Skip to content

Commit 92266e1

Browse files
committed
Merge branches 'pm-pci' and 'pm-core'
* pm-pci: PCI / PM: Fix small typo in documentation PCI / PM: constify pci_platform_pm_ops structure * pm-core: PM / core: fix typo in documentation PM / runtime: Add new helper for conditional usage count incrementation MAINTAINERS: Add an entry for the PM core PM / runtime: Re-init runtime PM states at probe error and driver unbind PM / sleep: prohibit devices probing during suspend/hibernation
3 parents 4c170ed + 76fc35d + 4295733 commit 92266e1

File tree

13 files changed

+142
-13
lines changed

13 files changed

+142
-13
lines changed

Documentation/power/pci.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ from its probe routine to make runtime PM work for the device.
999999

10001000
It is important to remember that the driver's runtime_suspend() callback
10011001
may be executed right after the usage counter has been decremented, because
1002-
user space may already have cuased the pm_runtime_allow() helper function
1002+
user space may already have caused the pm_runtime_allow() helper function
10031003
unblocking the runtime PM of the device to run via sysfs, so the driver must
10041004
be prepared to cope with that.
10051005

Documentation/power/runtime_pm.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
371371
- increment the device's usage counter, run pm_runtime_resume(dev) and
372372
return its result
373373

374+
int pm_runtime_get_if_in_use(struct device *dev);
375+
- return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
376+
runtime PM status is RPM_ACTIVE and the runtime PM usage counter is
377+
nonzero, increment the counter and return 1; otherwise return 0 without
378+
changing the counter
379+
374380
void pm_runtime_put_noidle(struct device *dev);
375381
- decrement the device's usage counter
376382

MAINTAINERS

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8447,6 +8447,17 @@ F: fs/timerfd.c
84478447
F: include/linux/timer*
84488448
F: kernel/time/*timer*
84498449

8450+
POWER MANAGEMENT CORE
8451+
M: "Rafael J. Wysocki" <[email protected]>
8452+
8453+
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
8454+
S: Supported
8455+
F: drivers/base/power/
8456+
F: include/linux/pm.h
8457+
F: include/linux/pm_*
8458+
F: include/linux/powercap.h
8459+
F: drivers/powercap/
8460+
84508461
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
84518462
M: Sebastian Reichel <[email protected]>
84528463
M: Dmitry Eremin-Solenikov <[email protected]>

drivers/base/base.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
131131
extern char *make_class_name(const char *name, struct kobject *kobj);
132132

133133
extern int devres_release_all(struct device *dev);
134+
extern void device_block_probing(void);
135+
extern void device_unblock_probing(void);
134136

135137
/* /sys/devices directory */
136138
extern struct kset *devices_kset;

drivers/base/dd.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ static LIST_HEAD(deferred_probe_active_list);
5454
static struct workqueue_struct *deferred_wq;
5555
static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
5656

57+
/*
58+
* In some cases, like suspend to RAM or hibernation, It might be reasonable
59+
* to prohibit probing of devices as it could be unsafe.
60+
* Once defer_all_probes is true all drivers probes will be forcibly deferred.
61+
*/
62+
static bool defer_all_probes;
63+
5764
/*
5865
* deferred_probe_work_func() - Retry probing devices in the active list.
5966
*/
@@ -171,6 +178,30 @@ static void driver_deferred_probe_trigger(void)
171178
queue_work(deferred_wq, &deferred_probe_work);
172179
}
173180

181+
/**
182+
* device_block_probing() - Block/defere device's probes
183+
*
184+
* It will disable probing of devices and defer their probes instead.
185+
*/
186+
void device_block_probing(void)
187+
{
188+
defer_all_probes = true;
189+
/* sync with probes to avoid races. */
190+
wait_for_device_probe();
191+
}
192+
193+
/**
194+
* device_unblock_probing() - Unblock/enable device's probes
195+
*
196+
* It will restore normal behavior and trigger re-probing of deferred
197+
* devices.
198+
*/
199+
void device_unblock_probing(void)
200+
{
201+
defer_all_probes = false;
202+
driver_deferred_probe_trigger();
203+
}
204+
174205
/**
175206
* deferred_probe_initcall() - Enable probing of deferred devices
176207
*
@@ -280,9 +311,20 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
280311

281312
static int really_probe(struct device *dev, struct device_driver *drv)
282313
{
283-
int ret = 0;
314+
int ret = -EPROBE_DEFER;
284315
int local_trigger_count = atomic_read(&deferred_trigger_count);
285316

317+
if (defer_all_probes) {
318+
/*
319+
* Value of defer_all_probes can be set only by
320+
* device_defer_all_probes_enable() which, in turn, will call
321+
* wait_for_device_probe() right after that to avoid any races.
322+
*/
323+
dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
324+
driver_deferred_probe_add(dev);
325+
return ret;
326+
}
327+
286328
atomic_inc(&probe_count);
287329
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
288330
drv->bus->name, __func__, drv->name, dev_name(dev));
@@ -347,6 +389,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
347389
dev_set_drvdata(dev, NULL);
348390
if (dev->pm_domain && dev->pm_domain->dismiss)
349391
dev->pm_domain->dismiss(dev);
392+
pm_runtime_reinit(dev);
350393

351394
switch (ret) {
352395
case -EPROBE_DEFER:
@@ -400,6 +443,10 @@ int driver_probe_done(void)
400443
*/
401444
void wait_for_device_probe(void)
402445
{
446+
/* wait for the deferred probe workqueue to finish */
447+
if (driver_deferred_probe_enable)
448+
flush_workqueue(deferred_wq);
449+
403450
/* wait for the known devices to complete their probing */
404451
wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
405452
async_synchronize_full();
@@ -702,6 +749,7 @@ static void __device_release_driver(struct device *dev)
702749
dev_set_drvdata(dev, NULL);
703750
if (dev->pm_domain && dev->pm_domain->dismiss)
704751
dev->pm_domain->dismiss(dev);
752+
pm_runtime_reinit(dev);
705753

706754
klist_remove(&dev->p->knode_driver);
707755
if (dev->bus)

drivers/base/power/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ EXPORT_SYMBOL_GPL(dev_pm_domain_attach);
112112

113113
/**
114114
* dev_pm_domain_detach - Detach a device from its PM domain.
115-
* @dev: Device to attach.
115+
* @dev: Device to detach.
116116
* @power_off: Used to indicate whether we should power off the device.
117117
*
118118
* This functions will reverse the actions from dev_pm_domain_attach() and thus

drivers/base/power/main.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,9 @@ void dpm_complete(pm_message_t state)
963963
}
964964
list_splice(&list, &dpm_list);
965965
mutex_unlock(&dpm_list_mtx);
966+
967+
/* Allow device probing and trigger re-probing of deferred devices */
968+
device_unblock_probing();
966969
trace_suspend_resume(TPS("dpm_complete"), state.event, false);
967970
}
968971

@@ -1624,6 +1627,20 @@ int dpm_prepare(pm_message_t state)
16241627
trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
16251628
might_sleep();
16261629

1630+
/*
1631+
* Give a chance for the known devices to complete their probes, before
1632+
* disable probing of devices. This sync point is important at least
1633+
* at boot time + hibernation restore.
1634+
*/
1635+
wait_for_device_probe();
1636+
/*
1637+
* It is unsafe if probing of devices will happen during suspend or
1638+
* hibernation and system behavior will be unpredictable in this case.
1639+
* So, let's prohibit device's probing here and defer their probes
1640+
* instead. The normal behavior will be restored in dpm_complete().
1641+
*/
1642+
device_block_probing();
1643+
16271644
mutex_lock(&dpm_list_mtx);
16281645
while (!list_empty(&dpm_list)) {
16291646
struct device *dev = to_device(dpm_list.next);

drivers/base/power/power.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ static inline void pm_runtime_early_init(struct device *dev)
1818
}
1919

2020
extern void pm_runtime_init(struct device *dev);
21+
extern void pm_runtime_reinit(struct device *dev);
2122
extern void pm_runtime_remove(struct device *dev);
2223

2324
struct wake_irq {
@@ -84,6 +85,7 @@ static inline void pm_runtime_early_init(struct device *dev)
8485
}
8586

8687
static inline void pm_runtime_init(struct device *dev) {}
88+
static inline void pm_runtime_reinit(struct device *dev) {}
8789
static inline void pm_runtime_remove(struct device *dev) {}
8890

8991
static inline int dpm_sysfs_add(struct device *dev) { return 0; }

drivers/base/power/runtime.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,30 @@ int __pm_runtime_resume(struct device *dev, int rpmflags)
965965
}
966966
EXPORT_SYMBOL_GPL(__pm_runtime_resume);
967967

968+
/**
969+
* pm_runtime_get_if_in_use - Conditionally bump up the device's usage counter.
970+
* @dev: Device to handle.
971+
*
972+
* Return -EINVAL if runtime PM is disabled for the device.
973+
*
974+
* If that's not the case and if the device's runtime PM status is RPM_ACTIVE
975+
* and the runtime PM usage counter is nonzero, increment the counter and
976+
* return 1. Otherwise return 0 without changing the counter.
977+
*/
978+
int pm_runtime_get_if_in_use(struct device *dev)
979+
{
980+
unsigned long flags;
981+
int retval;
982+
983+
spin_lock_irqsave(&dev->power.lock, flags);
984+
retval = dev->power.disable_depth > 0 ? -EINVAL :
985+
dev->power.runtime_status == RPM_ACTIVE
986+
&& atomic_inc_not_zero(&dev->power.usage_count);
987+
spin_unlock_irqrestore(&dev->power.lock, flags);
988+
return retval;
989+
}
990+
EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
991+
968992
/**
969993
* __pm_runtime_set_status - Set runtime PM status of a device.
970994
* @dev: Device to handle.
@@ -1389,19 +1413,33 @@ void pm_runtime_init(struct device *dev)
13891413
init_waitqueue_head(&dev->power.wait_queue);
13901414
}
13911415

1416+
/**
1417+
* pm_runtime_reinit - Re-initialize runtime PM fields in given device object.
1418+
* @dev: Device object to re-initialize.
1419+
*/
1420+
void pm_runtime_reinit(struct device *dev)
1421+
{
1422+
if (!pm_runtime_enabled(dev)) {
1423+
if (dev->power.runtime_status == RPM_ACTIVE)
1424+
pm_runtime_set_suspended(dev);
1425+
if (dev->power.irq_safe) {
1426+
spin_lock_irq(&dev->power.lock);
1427+
dev->power.irq_safe = 0;
1428+
spin_unlock_irq(&dev->power.lock);
1429+
if (dev->parent)
1430+
pm_runtime_put(dev->parent);
1431+
}
1432+
}
1433+
}
1434+
13921435
/**
13931436
* pm_runtime_remove - Prepare for removing a device from device hierarchy.
13941437
* @dev: Device object being removed from device hierarchy.
13951438
*/
13961439
void pm_runtime_remove(struct device *dev)
13971440
{
13981441
__pm_runtime_disable(dev, false);
1399-
1400-
/* Change the status back to 'suspended' to match the initial status. */
1401-
if (dev->power.runtime_status == RPM_ACTIVE)
1402-
pm_runtime_set_suspended(dev);
1403-
if (dev->power.irq_safe && dev->parent)
1404-
pm_runtime_put(dev->parent);
1442+
pm_runtime_reinit(dev);
14051443
}
14061444

14071445
/**

drivers/pci/pci-acpi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ static bool acpi_pci_need_resume(struct pci_dev *dev)
529529
return !!adev->power.flags.dsw_present;
530530
}
531531

532-
static struct pci_platform_pm_ops acpi_pci_platform_pm = {
532+
static const struct pci_platform_pm_ops acpi_pci_platform_pm = {
533533
.is_manageable = acpi_pci_power_manageable,
534534
.set_state = acpi_pci_set_power_state,
535535
.choose_state = acpi_pci_choose_state,

drivers/pci/pci.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,9 +527,9 @@ static void pci_restore_bars(struct pci_dev *dev)
527527
pci_update_resource(dev, i);
528528
}
529529

530-
static struct pci_platform_pm_ops *pci_platform_pm;
530+
static const struct pci_platform_pm_ops *pci_platform_pm;
531531

532-
int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
532+
int pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
533533
{
534534
if (!ops->is_manageable || !ops->set_state || !ops->choose_state
535535
|| !ops->sleep_wake)

drivers/pci/pci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ struct pci_platform_pm_ops {
6868
bool (*need_resume)(struct pci_dev *dev);
6969
};
7070

71-
int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
71+
int pci_set_platform_pm(const struct pci_platform_pm_ops *ops);
7272
void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
7373
void pci_power_up(struct pci_dev *dev);
7474
void pci_disable_enabled_device(struct pci_dev *dev);

include/linux/pm_runtime.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern int pm_runtime_force_resume(struct device *dev);
3939
extern int __pm_runtime_idle(struct device *dev, int rpmflags);
4040
extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
4141
extern int __pm_runtime_resume(struct device *dev, int rpmflags);
42+
extern int pm_runtime_get_if_in_use(struct device *dev);
4243
extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
4344
extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
4445
extern int pm_runtime_barrier(struct device *dev);
@@ -143,6 +144,10 @@ static inline int pm_schedule_suspend(struct device *dev, unsigned int delay)
143144
{
144145
return -ENOSYS;
145146
}
147+
static inline int pm_runtime_get_if_in_use(struct device *dev)
148+
{
149+
return -EINVAL;
150+
}
146151
static inline int __pm_runtime_set_status(struct device *dev,
147152
unsigned int status) { return 0; }
148153
static inline int pm_runtime_barrier(struct device *dev) { return 0; }

0 commit comments

Comments
 (0)