aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwtracing/intel_th
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2016-06-22 06:48:21 -0400
committerAlexander Shishkin <alexander.shishkin@linux.intel.com>2016-07-01 04:01:01 -0400
commit142dfeb20209607659ca85f15e7a3dd592a6dd20 (patch)
tree45cbdde394ba1823df99bc386ac2798ad3a56cd3 /drivers/hwtracing/intel_th
parent8e0469a4f3e647059c0ef8db961140ee25246fbd (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.c54
-rw-r--r--drivers/hwtracing/intel_th/gth.c16
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
90out:
91 if (ret)
92 thdrv->remove(thdev);
93
94out_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
203static void intel_th_output_deactivate(struct intel_th_device *thdev) 227static 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
637err_chrdev: 666err_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(&gth->gth_lock); 337 spin_lock(&gth->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(&gth->gth_lock); 340 spin_unlock(&gth->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(&gth->gth_lock); 361 spin_lock(&gth->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(&gth->gth_lock); 363 spin_unlock(&gth->gth_lock);
352 364
365 pm_runtime_put(dev);
366
353 return count; 367 return count;
354} 368}
355 369