aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/cpu.c1
-rw-r--r--drivers/base/power/clock_ops.c13
-rw-r--r--drivers/base/power/main.c11
-rw-r--r--drivers/base/power/runtime.c70
-rw-r--r--drivers/base/power/sysfs.c17
-rw-r--r--drivers/gpu/drm/i915/i915_pmu.c16
-rw-r--r--drivers/gpu/drm/i915/i915_pmu.h4
-rw-r--r--include/linux/device.h10
-rw-r--r--include/linux/pm.h7
-rw-r--r--include/linux/pm_runtime.h2
10 files changed, 108 insertions, 43 deletions
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index eb9443d5bae1..6ce93a52bf3f 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -427,6 +427,7 @@ __cpu_device_create(struct device *parent, void *drvdata,
427 dev->parent = parent; 427 dev->parent = parent;
428 dev->groups = groups; 428 dev->groups = groups;
429 dev->release = device_create_release; 429 dev->release = device_create_release;
430 device_set_pm_not_required(dev);
430 dev_set_drvdata(dev, drvdata); 431 dev_set_drvdata(dev, drvdata);
431 432
432 retval = kobject_set_name_vargs(&dev->kobj, fmt, args); 433 retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 5a42ae4078c2..365ad751ce0f 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -65,10 +65,15 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
65 if (IS_ERR(ce->clk)) { 65 if (IS_ERR(ce->clk)) {
66 ce->status = PCE_STATUS_ERROR; 66 ce->status = PCE_STATUS_ERROR;
67 } else { 67 } else {
68 clk_prepare(ce->clk); 68 if (clk_prepare(ce->clk)) {
69 ce->status = PCE_STATUS_ACQUIRED; 69 ce->status = PCE_STATUS_ERROR;
70 dev_dbg(dev, "Clock %pC con_id %s managed by runtime PM.\n", 70 dev_err(dev, "clk_prepare() failed\n");
71 ce->clk, ce->con_id); 71 } else {
72 ce->status = PCE_STATUS_ACQUIRED;
73 dev_dbg(dev,
74 "Clock %pC con_id %s managed by runtime PM.\n",
75 ce->clk, ce->con_id);
76 }
72 } 77 }
73} 78}
74 79
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 0992e67e862b..893ae464bfd6 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -124,6 +124,10 @@ void device_pm_unlock(void)
124 */ 124 */
125void device_pm_add(struct device *dev) 125void device_pm_add(struct device *dev)
126{ 126{
127 /* Skip PM setup/initialization. */
128 if (device_pm_not_required(dev))
129 return;
130
127 pr_debug("PM: Adding info for %s:%s\n", 131 pr_debug("PM: Adding info for %s:%s\n",
128 dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); 132 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
129 device_pm_check_callbacks(dev); 133 device_pm_check_callbacks(dev);
@@ -142,6 +146,9 @@ void device_pm_add(struct device *dev)
142 */ 146 */
143void device_pm_remove(struct device *dev) 147void device_pm_remove(struct device *dev)
144{ 148{
149 if (device_pm_not_required(dev))
150 return;
151
145 pr_debug("PM: Removing info for %s:%s\n", 152 pr_debug("PM: Removing info for %s:%s\n",
146 dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); 153 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
147 complete_all(&dev->power.completion); 154 complete_all(&dev->power.completion);
@@ -1741,8 +1748,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1741 if (dev->power.direct_complete) { 1748 if (dev->power.direct_complete) {
1742 if (pm_runtime_status_suspended(dev)) { 1749 if (pm_runtime_status_suspended(dev)) {
1743 pm_runtime_disable(dev); 1750 pm_runtime_disable(dev);
1744 if (pm_runtime_status_suspended(dev)) 1751 if (pm_runtime_status_suspended(dev)) {
1752 pm_dev_dbg(dev, state, "direct-complete ");
1745 goto Complete; 1753 goto Complete;
1754 }
1746 1755
1747 pm_runtime_enable(dev); 1756 pm_runtime_enable(dev);
1748 } 1757 }
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index ccd296dbb95c..78937c45278c 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -66,20 +66,30 @@ static int rpm_suspend(struct device *dev, int rpmflags);
66 */ 66 */
67void update_pm_runtime_accounting(struct device *dev) 67void update_pm_runtime_accounting(struct device *dev)
68{ 68{
69 unsigned long now = jiffies; 69 u64 now, last, delta;
70 unsigned long delta;
71 70
72 delta = now - dev->power.accounting_timestamp; 71 if (dev->power.disable_depth > 0)
72 return;
73
74 last = dev->power.accounting_timestamp;
73 75
76 now = ktime_get_mono_fast_ns();
74 dev->power.accounting_timestamp = now; 77 dev->power.accounting_timestamp = now;
75 78
76 if (dev->power.disable_depth > 0) 79 /*
80 * Because ktime_get_mono_fast_ns() is not monotonic during
81 * timekeeping updates, ensure that 'now' is after the last saved
82 * timesptamp.
83 */
84 if (now < last)
77 return; 85 return;
78 86
87 delta = now - last;
88
79 if (dev->power.runtime_status == RPM_SUSPENDED) 89 if (dev->power.runtime_status == RPM_SUSPENDED)
80 dev->power.suspended_jiffies += delta; 90 dev->power.suspended_time += delta;
81 else 91 else
82 dev->power.active_jiffies += delta; 92 dev->power.active_time += delta;
83} 93}
84 94
85static void __update_runtime_status(struct device *dev, enum rpm_status status) 95static void __update_runtime_status(struct device *dev, enum rpm_status status)
@@ -88,6 +98,22 @@ static void __update_runtime_status(struct device *dev, enum rpm_status status)
88 dev->power.runtime_status = status; 98 dev->power.runtime_status = status;
89} 99}
90 100
101u64 pm_runtime_suspended_time(struct device *dev)
102{
103 u64 time;
104 unsigned long flags;
105
106 spin_lock_irqsave(&dev->power.lock, flags);
107
108 update_pm_runtime_accounting(dev);
109 time = dev->power.suspended_time;
110
111 spin_unlock_irqrestore(&dev->power.lock, flags);
112
113 return time;
114}
115EXPORT_SYMBOL_GPL(pm_runtime_suspended_time);
116
91/** 117/**
92 * pm_runtime_deactivate_timer - Deactivate given device's suspend timer. 118 * pm_runtime_deactivate_timer - Deactivate given device's suspend timer.
93 * @dev: Device to handle. 119 * @dev: Device to handle.
@@ -129,24 +155,21 @@ static void pm_runtime_cancel_pending(struct device *dev)
129u64 pm_runtime_autosuspend_expiration(struct device *dev) 155u64 pm_runtime_autosuspend_expiration(struct device *dev)
130{ 156{
131 int autosuspend_delay; 157 int autosuspend_delay;
132 u64 last_busy, expires = 0; 158 u64 expires;
133 u64 now = ktime_get_mono_fast_ns();
134 159
135 if (!dev->power.use_autosuspend) 160 if (!dev->power.use_autosuspend)
136 goto out; 161 return 0;
137 162
138 autosuspend_delay = READ_ONCE(dev->power.autosuspend_delay); 163 autosuspend_delay = READ_ONCE(dev->power.autosuspend_delay);
139 if (autosuspend_delay < 0) 164 if (autosuspend_delay < 0)
140 goto out; 165 return 0;
141
142 last_busy = READ_ONCE(dev->power.last_busy);
143 166
144 expires = last_busy + (u64)autosuspend_delay * NSEC_PER_MSEC; 167 expires = READ_ONCE(dev->power.last_busy);
145 if (expires <= now) 168 expires += (u64)autosuspend_delay * NSEC_PER_MSEC;
146 expires = 0; /* Already expired. */ 169 if (expires > ktime_get_mono_fast_ns())
170 return expires; /* Expires in the future */
147 171
148 out: 172 return 0;
149 return expires;
150} 173}
151EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration); 174EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);
152 175
@@ -1276,6 +1299,9 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
1276 pm_runtime_put_noidle(dev); 1299 pm_runtime_put_noidle(dev);
1277 } 1300 }
1278 1301
1302 /* Update time accounting before disabling PM-runtime. */
1303 update_pm_runtime_accounting(dev);
1304
1279 if (!dev->power.disable_depth++) 1305 if (!dev->power.disable_depth++)
1280 __pm_runtime_barrier(dev); 1306 __pm_runtime_barrier(dev);
1281 1307
@@ -1294,10 +1320,15 @@ void pm_runtime_enable(struct device *dev)
1294 1320
1295 spin_lock_irqsave(&dev->power.lock, flags); 1321 spin_lock_irqsave(&dev->power.lock, flags);
1296 1322
1297 if (dev->power.disable_depth > 0) 1323 if (dev->power.disable_depth > 0) {
1298 dev->power.disable_depth--; 1324 dev->power.disable_depth--;
1299 else 1325
1326 /* About to enable runtime pm, set accounting_timestamp to now */
1327 if (!dev->power.disable_depth)
1328 dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
1329 } else {
1300 dev_warn(dev, "Unbalanced %s!\n", __func__); 1330 dev_warn(dev, "Unbalanced %s!\n", __func__);
1331 }
1301 1332
1302 WARN(!dev->power.disable_depth && 1333 WARN(!dev->power.disable_depth &&
1303 dev->power.runtime_status == RPM_SUSPENDED && 1334 dev->power.runtime_status == RPM_SUSPENDED &&
@@ -1494,7 +1525,6 @@ void pm_runtime_init(struct device *dev)
1494 dev->power.request_pending = false; 1525 dev->power.request_pending = false;
1495 dev->power.request = RPM_REQ_NONE; 1526 dev->power.request = RPM_REQ_NONE;
1496 dev->power.deferred_resume = false; 1527 dev->power.deferred_resume = false;
1497 dev->power.accounting_timestamp = jiffies;
1498 INIT_WORK(&dev->power.work, pm_runtime_work); 1528 INIT_WORK(&dev->power.work, pm_runtime_work);
1499 1529
1500 dev->power.timer_expires = 0; 1530 dev->power.timer_expires = 0;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index d713738ce796..c6bf76124184 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -125,9 +125,12 @@ static ssize_t runtime_active_time_show(struct device *dev,
125 struct device_attribute *attr, char *buf) 125 struct device_attribute *attr, char *buf)
126{ 126{
127 int ret; 127 int ret;
128 u64 tmp;
128 spin_lock_irq(&dev->power.lock); 129 spin_lock_irq(&dev->power.lock);
129 update_pm_runtime_accounting(dev); 130 update_pm_runtime_accounting(dev);
130 ret = sprintf(buf, "%i\n", jiffies_to_msecs(dev->power.active_jiffies)); 131 tmp = dev->power.active_time;
132 do_div(tmp, NSEC_PER_MSEC);
133 ret = sprintf(buf, "%llu\n", tmp);
131 spin_unlock_irq(&dev->power.lock); 134 spin_unlock_irq(&dev->power.lock);
132 return ret; 135 return ret;
133} 136}
@@ -138,10 +141,12 @@ static ssize_t runtime_suspended_time_show(struct device *dev,
138 struct device_attribute *attr, char *buf) 141 struct device_attribute *attr, char *buf)
139{ 142{
140 int ret; 143 int ret;
144 u64 tmp;
141 spin_lock_irq(&dev->power.lock); 145 spin_lock_irq(&dev->power.lock);
142 update_pm_runtime_accounting(dev); 146 update_pm_runtime_accounting(dev);
143 ret = sprintf(buf, "%i\n", 147 tmp = dev->power.suspended_time;
144 jiffies_to_msecs(dev->power.suspended_jiffies)); 148 do_div(tmp, NSEC_PER_MSEC);
149 ret = sprintf(buf, "%llu\n", tmp);
145 spin_unlock_irq(&dev->power.lock); 150 spin_unlock_irq(&dev->power.lock);
146 return ret; 151 return ret;
147} 152}
@@ -648,6 +653,10 @@ int dpm_sysfs_add(struct device *dev)
648{ 653{
649 int rc; 654 int rc;
650 655
656 /* No need to create PM sysfs if explicitly disabled. */
657 if (device_pm_not_required(dev))
658 return 0;
659
651 rc = sysfs_create_group(&dev->kobj, &pm_attr_group); 660 rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
652 if (rc) 661 if (rc)
653 return rc; 662 return rc;
@@ -727,6 +736,8 @@ void rpm_sysfs_remove(struct device *dev)
727 736
728void dpm_sysfs_remove(struct device *dev) 737void dpm_sysfs_remove(struct device *dev)
729{ 738{
739 if (device_pm_not_required(dev))
740 return;
730 sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group); 741 sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
731 dev_pm_qos_constraints_destroy(dev); 742 dev_pm_qos_constraints_destroy(dev);
732 rpm_sysfs_remove(dev); 743 rpm_sysfs_remove(dev);
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 017fc602a10e..cf7c66bb3ed9 100644
--- a/drivers/gpu/drm/i915/i915_pmu.c
+++ b/drivers/gpu/drm/i915/i915_pmu.c
@@ -5,6 +5,7 @@
5 */ 5 */
6 6
7#include <linux/irq.h> 7#include <linux/irq.h>
8#include <linux/pm_runtime.h>
8#include "i915_pmu.h" 9#include "i915_pmu.h"
9#include "intel_ringbuffer.h" 10#include "intel_ringbuffer.h"
10#include "i915_drv.h" 11#include "i915_drv.h"
@@ -478,7 +479,6 @@ static u64 get_rc6(struct drm_i915_private *i915)
478 * counter value. 479 * counter value.
479 */ 480 */
480 spin_lock_irqsave(&i915->pmu.lock, flags); 481 spin_lock_irqsave(&i915->pmu.lock, flags);
481 spin_lock(&kdev->power.lock);
482 482
483 /* 483 /*
484 * After the above branch intel_runtime_pm_get_if_in_use failed 484 * After the above branch intel_runtime_pm_get_if_in_use failed
@@ -491,16 +491,13 @@ static u64 get_rc6(struct drm_i915_private *i915)
491 * suspended and if not we cannot do better than report the last 491 * suspended and if not we cannot do better than report the last
492 * known RC6 value. 492 * known RC6 value.
493 */ 493 */
494 if (kdev->power.runtime_status == RPM_SUSPENDED) { 494 if (pm_runtime_status_suspended(kdev)) {
495 if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) 495 val = pm_runtime_suspended_time(kdev);
496 i915->pmu.suspended_jiffies_last =
497 kdev->power.suspended_jiffies;
498 496
499 val = kdev->power.suspended_jiffies - 497 if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur)
500 i915->pmu.suspended_jiffies_last; 498 i915->pmu.suspended_time_last = val;
501 val += jiffies - kdev->power.accounting_timestamp;
502 499
503 val = jiffies_to_nsecs(val); 500 val -= i915->pmu.suspended_time_last;
504 val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; 501 val += i915->pmu.sample[__I915_SAMPLE_RC6].cur;
505 502
506 i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; 503 i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val;
@@ -510,7 +507,6 @@ static u64 get_rc6(struct drm_i915_private *i915)
510 val = i915->pmu.sample[__I915_SAMPLE_RC6].cur; 507 val = i915->pmu.sample[__I915_SAMPLE_RC6].cur;
511 } 508 }
512 509
513 spin_unlock(&kdev->power.lock);
514 spin_unlock_irqrestore(&i915->pmu.lock, flags); 510 spin_unlock_irqrestore(&i915->pmu.lock, flags);
515 } 511 }
516 512
diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h
index b3728c5f13e7..4fc4f2478301 100644
--- a/drivers/gpu/drm/i915/i915_pmu.h
+++ b/drivers/gpu/drm/i915/i915_pmu.h
@@ -97,9 +97,9 @@ struct i915_pmu {
97 */ 97 */
98 struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS]; 98 struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS];
99 /** 99 /**
100 * @suspended_jiffies_last: Cached suspend time from PM core. 100 * @suspended_time_last: Cached suspend time from PM core.
101 */ 101 */
102 unsigned long suspended_jiffies_last; 102 u64 suspended_time_last;
103 /** 103 /**
104 * @i915_attr: Memory block holding device attributes. 104 * @i915_attr: Memory block holding device attributes.
105 */ 105 */
diff --git a/include/linux/device.h b/include/linux/device.h
index 6cb4640b6160..53028636fe39 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1165,6 +1165,16 @@ static inline bool device_async_suspend_enabled(struct device *dev)
1165 return !!dev->power.async_suspend; 1165 return !!dev->power.async_suspend;
1166} 1166}
1167 1167
1168static inline bool device_pm_not_required(struct device *dev)
1169{
1170 return dev->power.no_pm;
1171}
1172
1173static inline void device_set_pm_not_required(struct device *dev)
1174{
1175 dev->power.no_pm = true;
1176}
1177
1168static inline void dev_pm_syscore_device(struct device *dev, bool val) 1178static inline void dev_pm_syscore_device(struct device *dev, bool val)
1169{ 1179{
1170#ifdef CONFIG_PM_SLEEP 1180#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 0bd9de116826..06f7ed893928 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -592,6 +592,7 @@ struct dev_pm_info {
592 bool is_suspended:1; /* Ditto */ 592 bool is_suspended:1; /* Ditto */
593 bool is_noirq_suspended:1; 593 bool is_noirq_suspended:1;
594 bool is_late_suspended:1; 594 bool is_late_suspended:1;
595 bool no_pm:1;
595 bool early_init:1; /* Owned by the PM core */ 596 bool early_init:1; /* Owned by the PM core */
596 bool direct_complete:1; /* Owned by the PM core */ 597 bool direct_complete:1; /* Owned by the PM core */
597 u32 driver_flags; 598 u32 driver_flags;
@@ -633,9 +634,9 @@ struct dev_pm_info {
633 int runtime_error; 634 int runtime_error;
634 int autosuspend_delay; 635 int autosuspend_delay;
635 u64 last_busy; 636 u64 last_busy;
636 unsigned long active_jiffies; 637 u64 active_time;
637 unsigned long suspended_jiffies; 638 u64 suspended_time;
638 unsigned long accounting_timestamp; 639 u64 accounting_timestamp;
639#endif 640#endif
640 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ 641 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
641 void (*set_latency_tolerance)(struct device *, s32); 642 void (*set_latency_tolerance)(struct device *, s32);
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index fed5be706bc9..9dc6eebf62d2 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -113,6 +113,8 @@ static inline bool pm_runtime_is_irq_safe(struct device *dev)
113 return dev->power.irq_safe; 113 return dev->power.irq_safe;
114} 114}
115 115
116extern u64 pm_runtime_suspended_time(struct device *dev);
117
116#else /* !CONFIG_PM */ 118#else /* !CONFIG_PM */
117 119
118static inline bool queue_pm_work(struct work_struct *work) { return false; } 120static inline bool queue_pm_work(struct work_struct *work) { return false; }