diff options
author | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2016-06-22 06:48:21 -0400 |
---|---|---|
committer | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2016-07-01 04:01:01 -0400 |
commit | 142dfeb20209607659ca85f15e7a3dd592a6dd20 (patch) | |
tree | 45cbdde394ba1823df99bc386ac2798ad3a56cd3 /drivers/hwtracing/intel_th | |
parent | 8e0469a4f3e647059c0ef8db961140ee25246fbd (diff) |
intel_th: Add runtime power management handling
Currently, an Intel TH (pci) device will be always active, because the
devices on the 'intel_th' bus don't implement runtime pm to track their
usage.
To address this, this patch adds runtime pm support to the 'intel_th'
bus and some additional bits for the hub. The 'output' type device is
in use while a capture is active; the 'source' type device (STH) relies
on its child stm class device for runtime pm tracking.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Diffstat (limited to 'drivers/hwtracing/intel_th')
-rw-r--r-- | drivers/hwtracing/intel_th/core.c | 54 | ||||
-rw-r--r-- | drivers/hwtracing/intel_th/gth.c | 16 |
2 files changed, 60 insertions, 10 deletions
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 1be543e8e42f..fdd17636d109 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/debugfs.h> | 23 | #include <linux/debugfs.h> |
24 | #include <linux/idr.h> | 24 | #include <linux/idr.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/dma-mapping.h> | 27 | #include <linux/dma-mapping.h> |
27 | 28 | ||
28 | #include "intel_th.h" | 29 | #include "intel_th.h" |
@@ -67,23 +68,33 @@ static int intel_th_probe(struct device *dev) | |||
67 | 68 | ||
68 | hubdrv = to_intel_th_driver(hub->dev.driver); | 69 | hubdrv = to_intel_th_driver(hub->dev.driver); |
69 | 70 | ||
71 | pm_runtime_set_active(dev); | ||
72 | pm_runtime_no_callbacks(dev); | ||
73 | pm_runtime_enable(dev); | ||
74 | |||
70 | ret = thdrv->probe(to_intel_th_device(dev)); | 75 | ret = thdrv->probe(to_intel_th_device(dev)); |
71 | if (ret) | 76 | if (ret) |
72 | return ret; | 77 | goto out_pm; |
73 | 78 | ||
74 | if (thdrv->attr_group) { | 79 | if (thdrv->attr_group) { |
75 | ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group); | 80 | ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group); |
76 | if (ret) { | 81 | if (ret) |
77 | thdrv->remove(thdev); | 82 | goto out; |
78 | |||
79 | return ret; | ||
80 | } | ||
81 | } | 83 | } |
82 | 84 | ||
83 | if (thdev->type == INTEL_TH_OUTPUT && | 85 | if (thdev->type == INTEL_TH_OUTPUT && |
84 | !intel_th_output_assigned(thdev)) | 86 | !intel_th_output_assigned(thdev)) |
87 | /* does not talk to hardware */ | ||
85 | ret = hubdrv->assign(hub, thdev); | 88 | ret = hubdrv->assign(hub, thdev); |
86 | 89 | ||
90 | out: | ||
91 | if (ret) | ||
92 | thdrv->remove(thdev); | ||
93 | |||
94 | out_pm: | ||
95 | if (ret) | ||
96 | pm_runtime_disable(dev); | ||
97 | |||
87 | return ret; | 98 | return ret; |
88 | } | 99 | } |
89 | 100 | ||
@@ -103,6 +114,8 @@ static int intel_th_remove(struct device *dev) | |||
103 | if (thdrv->attr_group) | 114 | if (thdrv->attr_group) |
104 | sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group); | 115 | sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group); |
105 | 116 | ||
117 | pm_runtime_get_sync(dev); | ||
118 | |||
106 | thdrv->remove(thdev); | 119 | thdrv->remove(thdev); |
107 | 120 | ||
108 | if (intel_th_output_assigned(thdev)) { | 121 | if (intel_th_output_assigned(thdev)) { |
@@ -110,9 +123,14 @@ static int intel_th_remove(struct device *dev) | |||
110 | to_intel_th_driver(dev->parent->driver); | 123 | to_intel_th_driver(dev->parent->driver); |
111 | 124 | ||
112 | if (hub->dev.driver) | 125 | if (hub->dev.driver) |
126 | /* does not talk to hardware */ | ||
113 | hubdrv->unassign(hub, thdev); | 127 | hubdrv->unassign(hub, thdev); |
114 | } | 128 | } |
115 | 129 | ||
130 | pm_runtime_disable(dev); | ||
131 | pm_runtime_set_active(dev); | ||
132 | pm_runtime_enable(dev); | ||
133 | |||
116 | return 0; | 134 | return 0; |
117 | } | 135 | } |
118 | 136 | ||
@@ -185,6 +203,7 @@ static int intel_th_output_activate(struct intel_th_device *thdev) | |||
185 | { | 203 | { |
186 | struct intel_th_driver *thdrv = | 204 | struct intel_th_driver *thdrv = |
187 | to_intel_th_driver_or_null(thdev->dev.driver); | 205 | to_intel_th_driver_or_null(thdev->dev.driver); |
206 | int ret = 0; | ||
188 | 207 | ||
189 | if (!thdrv) | 208 | if (!thdrv) |
190 | return -ENODEV; | 209 | return -ENODEV; |
@@ -192,12 +211,17 @@ static int intel_th_output_activate(struct intel_th_device *thdev) | |||
192 | if (!try_module_get(thdrv->driver.owner)) | 211 | if (!try_module_get(thdrv->driver.owner)) |
193 | return -ENODEV; | 212 | return -ENODEV; |
194 | 213 | ||
214 | pm_runtime_get_sync(&thdev->dev); | ||
215 | |||
195 | if (thdrv->activate) | 216 | if (thdrv->activate) |
196 | return thdrv->activate(thdev); | 217 | ret = thdrv->activate(thdev); |
218 | else | ||
219 | intel_th_trace_enable(thdev); | ||
197 | 220 | ||
198 | intel_th_trace_enable(thdev); | 221 | if (ret) |
222 | pm_runtime_put(&thdev->dev); | ||
199 | 223 | ||
200 | return 0; | 224 | return ret; |
201 | } | 225 | } |
202 | 226 | ||
203 | static void intel_th_output_deactivate(struct intel_th_device *thdev) | 227 | static void intel_th_output_deactivate(struct intel_th_device *thdev) |
@@ -213,6 +237,7 @@ static void intel_th_output_deactivate(struct intel_th_device *thdev) | |||
213 | else | 237 | else |
214 | intel_th_trace_disable(thdev); | 238 | intel_th_trace_disable(thdev); |
215 | 239 | ||
240 | pm_runtime_put(&thdev->dev); | ||
216 | module_put(thdrv->driver.owner); | 241 | module_put(thdrv->driver.owner); |
217 | } | 242 | } |
218 | 243 | ||
@@ -628,6 +653,10 @@ intel_th_alloc(struct device *dev, struct resource *devres, | |||
628 | 653 | ||
629 | dev_set_drvdata(dev, th); | 654 | dev_set_drvdata(dev, th); |
630 | 655 | ||
656 | pm_runtime_no_callbacks(dev); | ||
657 | pm_runtime_put(dev); | ||
658 | pm_runtime_allow(dev); | ||
659 | |||
631 | err = intel_th_populate(th, devres, ndevres, irq); | 660 | err = intel_th_populate(th, devres, ndevres, irq); |
632 | if (err) | 661 | if (err) |
633 | goto err_chrdev; | 662 | goto err_chrdev; |
@@ -635,6 +664,8 @@ intel_th_alloc(struct device *dev, struct resource *devres, | |||
635 | return th; | 664 | return th; |
636 | 665 | ||
637 | err_chrdev: | 666 | err_chrdev: |
667 | pm_runtime_forbid(dev); | ||
668 | |||
638 | __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, | 669 | __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, |
639 | "intel_th/output"); | 670 | "intel_th/output"); |
640 | 671 | ||
@@ -658,6 +689,9 @@ void intel_th_free(struct intel_th *th) | |||
658 | 689 | ||
659 | intel_th_device_remove(th->hub); | 690 | intel_th_device_remove(th->hub); |
660 | 691 | ||
692 | pm_runtime_get_sync(th->dev); | ||
693 | pm_runtime_forbid(th->dev); | ||
694 | |||
661 | __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, | 695 | __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, |
662 | "intel_th/output"); | 696 | "intel_th/output"); |
663 | 697 | ||
@@ -682,6 +716,7 @@ int intel_th_trace_enable(struct intel_th_device *thdev) | |||
682 | if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT)) | 716 | if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT)) |
683 | return -EINVAL; | 717 | return -EINVAL; |
684 | 718 | ||
719 | pm_runtime_get_sync(&thdev->dev); | ||
685 | hubdrv->enable(hub, &thdev->output); | 720 | hubdrv->enable(hub, &thdev->output); |
686 | 721 | ||
687 | return 0; | 722 | return 0; |
@@ -702,6 +737,7 @@ int intel_th_trace_disable(struct intel_th_device *thdev) | |||
702 | return -EINVAL; | 737 | return -EINVAL; |
703 | 738 | ||
704 | hubdrv->disable(hub, &thdev->output); | 739 | hubdrv->disable(hub, &thdev->output); |
740 | pm_runtime_put(&thdev->dev); | ||
705 | 741 | ||
706 | return 0; | 742 | return 0; |
707 | } | 743 | } |
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c index 9beea0b54231..4106eaf13123 100644 --- a/drivers/hwtracing/intel_th/gth.c +++ b/drivers/hwtracing/intel_th/gth.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/bitmap.h> | 24 | #include <linux/bitmap.h> |
25 | #include <linux/pm_runtime.h> | ||
25 | 26 | ||
26 | #include "intel_th.h" | 27 | #include "intel_th.h" |
27 | #include "gth.h" | 28 | #include "gth.h" |
@@ -190,6 +191,11 @@ static ssize_t master_attr_store(struct device *dev, | |||
190 | if (old_port >= 0) { | 191 | if (old_port >= 0) { |
191 | gth->master[ma->master] = -1; | 192 | gth->master[ma->master] = -1; |
192 | clear_bit(ma->master, gth->output[old_port].master); | 193 | clear_bit(ma->master, gth->output[old_port].master); |
194 | |||
195 | /* | ||
196 | * if the port is active, program this setting, | ||
197 | * implies that runtime PM is on | ||
198 | */ | ||
193 | if (gth->output[old_port].output->active) | 199 | if (gth->output[old_port].output->active) |
194 | gth_master_set(gth, ma->master, -1); | 200 | gth_master_set(gth, ma->master, -1); |
195 | } | 201 | } |
@@ -204,7 +210,7 @@ static ssize_t master_attr_store(struct device *dev, | |||
204 | 210 | ||
205 | set_bit(ma->master, gth->output[port].master); | 211 | set_bit(ma->master, gth->output[port].master); |
206 | 212 | ||
207 | /* if the port is active, program this setting */ | 213 | /* if the port is active, program this setting, see above */ |
208 | if (gth->output[port].output->active) | 214 | if (gth->output[port].output->active) |
209 | gth_master_set(gth, ma->master, port); | 215 | gth_master_set(gth, ma->master, port); |
210 | } | 216 | } |
@@ -326,11 +332,15 @@ static ssize_t output_attr_show(struct device *dev, | |||
326 | struct gth_device *gth = oa->gth; | 332 | struct gth_device *gth = oa->gth; |
327 | size_t count; | 333 | size_t count; |
328 | 334 | ||
335 | pm_runtime_get_sync(dev); | ||
336 | |||
329 | spin_lock(>h->gth_lock); | 337 | spin_lock(>h->gth_lock); |
330 | count = snprintf(buf, PAGE_SIZE, "%x\n", | 338 | count = snprintf(buf, PAGE_SIZE, "%x\n", |
331 | gth_output_parm_get(gth, oa->port, oa->parm)); | 339 | gth_output_parm_get(gth, oa->port, oa->parm)); |
332 | spin_unlock(>h->gth_lock); | 340 | spin_unlock(>h->gth_lock); |
333 | 341 | ||
342 | pm_runtime_put(dev); | ||
343 | |||
334 | return count; | 344 | return count; |
335 | } | 345 | } |
336 | 346 | ||
@@ -346,10 +356,14 @@ static ssize_t output_attr_store(struct device *dev, | |||
346 | if (kstrtouint(buf, 16, &config) < 0) | 356 | if (kstrtouint(buf, 16, &config) < 0) |
347 | return -EINVAL; | 357 | return -EINVAL; |
348 | 358 | ||
359 | pm_runtime_get_sync(dev); | ||
360 | |||
349 | spin_lock(>h->gth_lock); | 361 | spin_lock(>h->gth_lock); |
350 | gth_output_parm_set(gth, oa->port, oa->parm, config); | 362 | gth_output_parm_set(gth, oa->port, oa->parm, config); |
351 | spin_unlock(>h->gth_lock); | 363 | spin_unlock(>h->gth_lock); |
352 | 364 | ||
365 | pm_runtime_put(dev); | ||
366 | |||
353 | return count; | 367 | return count; |
354 | } | 368 | } |
355 | 369 | ||