aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwtracing/intel_th
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-05-21 00:20:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-21 00:20:31 -0400
commit5af2344013454640e0133bb62e8cf2e30190a472 (patch)
tree93495d1eb88d7498dac4747a3d28081c09a69a55 /drivers/hwtracing/intel_th
parent19e36ad292ab24980db64a5ff17973d3118a8fb9 (diff)
parent725d0123dfff3d7b666cf57f5d29c50addfc99d3 (diff)
Merge tag 'char-misc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc driver updates from Greg KH: "Here's the big char and misc driver update for 4.7-rc1. Lots of different tiny driver subsystems have updates here with new drivers and functionality. Details in the shortlog. All have been in linux-next with no reported issues for a while" * tag 'char-misc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (125 commits) mcb: Delete num_cells variable which is not required mcb: Fixed bar number assignment for the gdd mcb: Replace ioremap and request_region with the devm version mcb: Implement bus->dev.release callback mcb: export bus information via sysfs mcb: Correctly initialize the bus's device mei: bus: call mei_cl_read_start under device lock coresight: etb10: adjust read pointer only when needed coresight: configuring ETF in FIFO mode when acting as link coresight: tmc: implementing TMC-ETF AUX space API coresight: moving struct cs_buffers to header file coresight: tmc: keep track of memory width coresight: tmc: make sysFS and Perf mode mutually exclusive coresight: tmc: dump system memory content only when needed coresight: tmc: adding mode of operation for link/sinks coresight: tmc: getting rid of multiple read access coresight: tmc: allocating memory when needed coresight: tmc: making prepare/unprepare functions generic coresight: tmc: splitting driver in ETB/ETF and ETR components coresight: tmc: cleaning up header file ...
Diffstat (limited to 'drivers/hwtracing/intel_th')
-rw-r--r--drivers/hwtracing/intel_th/core.c29
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h6
-rw-r--r--drivers/hwtracing/intel_th/msu.c116
-rw-r--r--drivers/hwtracing/intel_th/pci.c5
-rw-r--r--drivers/hwtracing/intel_th/pti.c6
5 files changed, 107 insertions, 55 deletions
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 4272f2ce5f6e..1be543e8e42f 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -71,6 +71,15 @@ static int intel_th_probe(struct device *dev)
71 if (ret) 71 if (ret)
72 return ret; 72 return ret;
73 73
74 if (thdrv->attr_group) {
75 ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group);
76 if (ret) {
77 thdrv->remove(thdev);
78
79 return ret;
80 }
81 }
82
74 if (thdev->type == INTEL_TH_OUTPUT && 83 if (thdev->type == INTEL_TH_OUTPUT &&
75 !intel_th_output_assigned(thdev)) 84 !intel_th_output_assigned(thdev))
76 ret = hubdrv->assign(hub, thdev); 85 ret = hubdrv->assign(hub, thdev);
@@ -91,6 +100,9 @@ static int intel_th_remove(struct device *dev)
91 return err; 100 return err;
92 } 101 }
93 102
103 if (thdrv->attr_group)
104 sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group);
105
94 thdrv->remove(thdev); 106 thdrv->remove(thdev);
95 107
96 if (intel_th_output_assigned(thdev)) { 108 if (intel_th_output_assigned(thdev)) {
@@ -171,7 +183,14 @@ static DEVICE_ATTR_RO(port);
171 183
172static int intel_th_output_activate(struct intel_th_device *thdev) 184static int intel_th_output_activate(struct intel_th_device *thdev)
173{ 185{
174 struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver); 186 struct intel_th_driver *thdrv =
187 to_intel_th_driver_or_null(thdev->dev.driver);
188
189 if (!thdrv)
190 return -ENODEV;
191
192 if (!try_module_get(thdrv->driver.owner))
193 return -ENODEV;
175 194
176 if (thdrv->activate) 195 if (thdrv->activate)
177 return thdrv->activate(thdev); 196 return thdrv->activate(thdev);
@@ -183,12 +202,18 @@ static int intel_th_output_activate(struct intel_th_device *thdev)
183 202
184static void intel_th_output_deactivate(struct intel_th_device *thdev) 203static void intel_th_output_deactivate(struct intel_th_device *thdev)
185{ 204{
186 struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver); 205 struct intel_th_driver *thdrv =
206 to_intel_th_driver_or_null(thdev->dev.driver);
207
208 if (!thdrv)
209 return;
187 210
188 if (thdrv->deactivate) 211 if (thdrv->deactivate)
189 thdrv->deactivate(thdev); 212 thdrv->deactivate(thdev);
190 else 213 else
191 intel_th_trace_disable(thdev); 214 intel_th_trace_disable(thdev);
215
216 module_put(thdrv->driver.owner);
192} 217}
193 218
194static ssize_t active_show(struct device *dev, struct device_attribute *attr, 219static ssize_t active_show(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index eedd09332db6..0df22e30673d 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -115,6 +115,7 @@ intel_th_output_assigned(struct intel_th_device *thdev)
115 * @enable: enable tracing for a given output device 115 * @enable: enable tracing for a given output device
116 * @disable: disable tracing for a given output device 116 * @disable: disable tracing for a given output device
117 * @fops: file operations for device nodes 117 * @fops: file operations for device nodes
118 * @attr_group: attributes provided by the driver
118 * 119 *
119 * Callbacks @probe and @remove are required for all device types. 120 * Callbacks @probe and @remove are required for all device types.
120 * Switch device driver needs to fill in @assign, @enable and @disable 121 * Switch device driver needs to fill in @assign, @enable and @disable
@@ -139,6 +140,8 @@ struct intel_th_driver {
139 void (*deactivate)(struct intel_th_device *thdev); 140 void (*deactivate)(struct intel_th_device *thdev);
140 /* file_operations for those who want a device node */ 141 /* file_operations for those who want a device node */
141 const struct file_operations *fops; 142 const struct file_operations *fops;
143 /* optional attributes */
144 struct attribute_group *attr_group;
142 145
143 /* source ops */ 146 /* source ops */
144 int (*set_output)(struct intel_th_device *thdev, 147 int (*set_output)(struct intel_th_device *thdev,
@@ -148,6 +151,9 @@ struct intel_th_driver {
148#define to_intel_th_driver(_d) \ 151#define to_intel_th_driver(_d) \
149 container_of((_d), struct intel_th_driver, driver) 152 container_of((_d), struct intel_th_driver, driver)
150 153
154#define to_intel_th_driver_or_null(_d) \
155 ((_d) ? to_intel_th_driver(_d) : NULL)
156
151static inline struct intel_th_device * 157static inline struct intel_th_device *
152to_intel_th_hub(struct intel_th_device *thdev) 158to_intel_th_hub(struct intel_th_device *thdev)
153{ 159{
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index d2209147dc89..e8d55a153a65 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -122,7 +122,6 @@ struct msc {
122 atomic_t mmap_count; 122 atomic_t mmap_count;
123 struct mutex buf_mutex; 123 struct mutex buf_mutex;
124 124
125 struct mutex iter_mutex;
126 struct list_head iter_list; 125 struct list_head iter_list;
127 126
128 /* config */ 127 /* config */
@@ -257,23 +256,37 @@ static struct msc_iter *msc_iter_install(struct msc *msc)
257 256
258 iter = kzalloc(sizeof(*iter), GFP_KERNEL); 257 iter = kzalloc(sizeof(*iter), GFP_KERNEL);
259 if (!iter) 258 if (!iter)
260 return NULL; 259 return ERR_PTR(-ENOMEM);
260
261 mutex_lock(&msc->buf_mutex);
262
263 /*
264 * Reading and tracing are mutually exclusive; if msc is
265 * enabled, open() will fail; otherwise existing readers
266 * will prevent enabling the msc and the rest of fops don't
267 * need to worry about it.
268 */
269 if (msc->enabled) {
270 kfree(iter);
271 iter = ERR_PTR(-EBUSY);
272 goto unlock;
273 }
261 274
262 msc_iter_init(iter); 275 msc_iter_init(iter);
263 iter->msc = msc; 276 iter->msc = msc;
264 277
265 mutex_lock(&msc->iter_mutex);
266 list_add_tail(&iter->entry, &msc->iter_list); 278 list_add_tail(&iter->entry, &msc->iter_list);
267 mutex_unlock(&msc->iter_mutex); 279unlock:
280 mutex_unlock(&msc->buf_mutex);
268 281
269 return iter; 282 return iter;
270} 283}
271 284
272static void msc_iter_remove(struct msc_iter *iter, struct msc *msc) 285static void msc_iter_remove(struct msc_iter *iter, struct msc *msc)
273{ 286{
274 mutex_lock(&msc->iter_mutex); 287 mutex_lock(&msc->buf_mutex);
275 list_del(&iter->entry); 288 list_del(&iter->entry);
276 mutex_unlock(&msc->iter_mutex); 289 mutex_unlock(&msc->buf_mutex);
277 290
278 kfree(iter); 291 kfree(iter);
279} 292}
@@ -454,7 +467,6 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
454{ 467{
455 struct msc_window *win; 468 struct msc_window *win;
456 469
457 mutex_lock(&msc->buf_mutex);
458 list_for_each_entry(win, &msc->win_list, entry) { 470 list_for_each_entry(win, &msc->win_list, entry) {
459 unsigned int blk; 471 unsigned int blk;
460 size_t hw_sz = sizeof(struct msc_block_desc) - 472 size_t hw_sz = sizeof(struct msc_block_desc) -
@@ -466,7 +478,6 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
466 memset(&bdesc->hw_tag, 0, hw_sz); 478 memset(&bdesc->hw_tag, 0, hw_sz);
467 } 479 }
468 } 480 }
469 mutex_unlock(&msc->buf_mutex);
470} 481}
471 482
472/** 483/**
@@ -474,12 +485,15 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
474 * @msc: the MSC device to configure 485 * @msc: the MSC device to configure
475 * 486 *
476 * Program storage mode, wrapping, burst length and trace buffer address 487 * Program storage mode, wrapping, burst length and trace buffer address
477 * into a given MSC. If msc::enabled is set, enable the trace, too. 488 * into a given MSC. Then, enable tracing and set msc::enabled.
489 * The latter is serialized on msc::buf_mutex, so make sure to hold it.
478 */ 490 */
479static int msc_configure(struct msc *msc) 491static int msc_configure(struct msc *msc)
480{ 492{
481 u32 reg; 493 u32 reg;
482 494
495 lockdep_assert_held(&msc->buf_mutex);
496
483 if (msc->mode > MSC_MODE_MULTI) 497 if (msc->mode > MSC_MODE_MULTI)
484 return -ENOTSUPP; 498 return -ENOTSUPP;
485 499
@@ -497,21 +511,19 @@ static int msc_configure(struct msc *msc)
497 reg = ioread32(msc->reg_base + REG_MSU_MSC0CTL); 511 reg = ioread32(msc->reg_base + REG_MSU_MSC0CTL);
498 reg &= ~(MSC_MODE | MSC_WRAPEN | MSC_EN | MSC_RD_HDR_OVRD); 512 reg &= ~(MSC_MODE | MSC_WRAPEN | MSC_EN | MSC_RD_HDR_OVRD);
499 513
514 reg |= MSC_EN;
500 reg |= msc->mode << __ffs(MSC_MODE); 515 reg |= msc->mode << __ffs(MSC_MODE);
501 reg |= msc->burst_len << __ffs(MSC_LEN); 516 reg |= msc->burst_len << __ffs(MSC_LEN);
502 /*if (msc->mode == MSC_MODE_MULTI) 517
503 reg |= MSC_RD_HDR_OVRD; */
504 if (msc->wrap) 518 if (msc->wrap)
505 reg |= MSC_WRAPEN; 519 reg |= MSC_WRAPEN;
506 if (msc->enabled)
507 reg |= MSC_EN;
508 520
509 iowrite32(reg, msc->reg_base + REG_MSU_MSC0CTL); 521 iowrite32(reg, msc->reg_base + REG_MSU_MSC0CTL);
510 522
511 if (msc->enabled) { 523 msc->thdev->output.multiblock = msc->mode == MSC_MODE_MULTI;
512 msc->thdev->output.multiblock = msc->mode == MSC_MODE_MULTI; 524 intel_th_trace_enable(msc->thdev);
513 intel_th_trace_enable(msc->thdev); 525 msc->enabled = 1;
514 } 526
515 527
516 return 0; 528 return 0;
517} 529}
@@ -521,15 +533,14 @@ static int msc_configure(struct msc *msc)
521 * @msc: MSC device to disable 533 * @msc: MSC device to disable
522 * 534 *
523 * If @msc is enabled, disable tracing on the switch and then disable MSC 535 * If @msc is enabled, disable tracing on the switch and then disable MSC
524 * storage. 536 * storage. Caller must hold msc::buf_mutex.
525 */ 537 */
526static void msc_disable(struct msc *msc) 538static void msc_disable(struct msc *msc)
527{ 539{
528 unsigned long count; 540 unsigned long count;
529 u32 reg; 541 u32 reg;
530 542
531 if (!msc->enabled) 543 lockdep_assert_held(&msc->buf_mutex);
532 return;
533 544
534 intel_th_trace_disable(msc->thdev); 545 intel_th_trace_disable(msc->thdev);
535 546
@@ -569,33 +580,35 @@ static void msc_disable(struct msc *msc)
569static int intel_th_msc_activate(struct intel_th_device *thdev) 580static int intel_th_msc_activate(struct intel_th_device *thdev)
570{ 581{
571 struct msc *msc = dev_get_drvdata(&thdev->dev); 582 struct msc *msc = dev_get_drvdata(&thdev->dev);
572 int ret = 0; 583 int ret = -EBUSY;
573 584
574 if (!atomic_inc_unless_negative(&msc->user_count)) 585 if (!atomic_inc_unless_negative(&msc->user_count))
575 return -ENODEV; 586 return -ENODEV;
576 587
577 mutex_lock(&msc->iter_mutex); 588 mutex_lock(&msc->buf_mutex);
578 if (!list_empty(&msc->iter_list))
579 ret = -EBUSY;
580 mutex_unlock(&msc->iter_mutex);
581 589
582 if (ret) { 590 /* if there are readers, refuse */
583 atomic_dec(&msc->user_count); 591 if (list_empty(&msc->iter_list))
584 return ret; 592 ret = msc_configure(msc);
585 }
586 593
587 msc->enabled = 1; 594 mutex_unlock(&msc->buf_mutex);
595
596 if (ret)
597 atomic_dec(&msc->user_count);
588 598
589 return msc_configure(msc); 599 return ret;
590} 600}
591 601
592static void intel_th_msc_deactivate(struct intel_th_device *thdev) 602static void intel_th_msc_deactivate(struct intel_th_device *thdev)
593{ 603{
594 struct msc *msc = dev_get_drvdata(&thdev->dev); 604 struct msc *msc = dev_get_drvdata(&thdev->dev);
595 605
596 msc_disable(msc); 606 mutex_lock(&msc->buf_mutex);
597 607 if (msc->enabled) {
598 atomic_dec(&msc->user_count); 608 msc_disable(msc);
609 atomic_dec(&msc->user_count);
610 }
611 mutex_unlock(&msc->buf_mutex);
599} 612}
600 613
601/** 614/**
@@ -1035,8 +1048,8 @@ static int intel_th_msc_open(struct inode *inode, struct file *file)
1035 return -EPERM; 1048 return -EPERM;
1036 1049
1037 iter = msc_iter_install(msc); 1050 iter = msc_iter_install(msc);
1038 if (!iter) 1051 if (IS_ERR(iter))
1039 return -ENOMEM; 1052 return PTR_ERR(iter);
1040 1053
1041 file->private_data = iter; 1054 file->private_data = iter;
1042 1055
@@ -1101,11 +1114,6 @@ static ssize_t intel_th_msc_read(struct file *file, char __user *buf,
1101 if (!atomic_inc_unless_negative(&msc->user_count)) 1114 if (!atomic_inc_unless_negative(&msc->user_count))
1102 return 0; 1115 return 0;
1103 1116
1104 if (msc->enabled) {
1105 ret = -EBUSY;
1106 goto put_count;
1107 }
1108
1109 if (msc->mode == MSC_MODE_SINGLE && !msc->single_wrap) 1117 if (msc->mode == MSC_MODE_SINGLE && !msc->single_wrap)
1110 size = msc->single_sz; 1118 size = msc->single_sz;
1111 else 1119 else
@@ -1245,6 +1253,7 @@ static const struct file_operations intel_th_msc_fops = {
1245 .read = intel_th_msc_read, 1253 .read = intel_th_msc_read,
1246 .mmap = intel_th_msc_mmap, 1254 .mmap = intel_th_msc_mmap,
1247 .llseek = no_llseek, 1255 .llseek = no_llseek,
1256 .owner = THIS_MODULE,
1248}; 1257};
1249 1258
1250static int intel_th_msc_init(struct msc *msc) 1259static int intel_th_msc_init(struct msc *msc)
@@ -1254,8 +1263,6 @@ static int intel_th_msc_init(struct msc *msc)
1254 msc->mode = MSC_MODE_MULTI; 1263 msc->mode = MSC_MODE_MULTI;
1255 mutex_init(&msc->buf_mutex); 1264 mutex_init(&msc->buf_mutex);
1256 INIT_LIST_HEAD(&msc->win_list); 1265 INIT_LIST_HEAD(&msc->win_list);
1257
1258 mutex_init(&msc->iter_mutex);
1259 INIT_LIST_HEAD(&msc->iter_list); 1266 INIT_LIST_HEAD(&msc->iter_list);
1260 1267
1261 msc->burst_len = 1268 msc->burst_len =
@@ -1393,6 +1400,11 @@ nr_pages_store(struct device *dev, struct device_attribute *attr,
1393 do { 1400 do {
1394 end = memchr(p, ',', len); 1401 end = memchr(p, ',', len);
1395 s = kstrndup(p, end ? end - p : len, GFP_KERNEL); 1402 s = kstrndup(p, end ? end - p : len, GFP_KERNEL);
1403 if (!s) {
1404 ret = -ENOMEM;
1405 goto free_win;
1406 }
1407
1396 ret = kstrtoul(s, 10, &val); 1408 ret = kstrtoul(s, 10, &val);
1397 kfree(s); 1409 kfree(s);
1398 1410
@@ -1473,10 +1485,6 @@ static int intel_th_msc_probe(struct intel_th_device *thdev)
1473 if (err) 1485 if (err)
1474 return err; 1486 return err;
1475 1487
1476 err = sysfs_create_group(&dev->kobj, &msc_output_group);
1477 if (err)
1478 return err;
1479
1480 dev_set_drvdata(dev, msc); 1488 dev_set_drvdata(dev, msc);
1481 1489
1482 return 0; 1490 return 0;
@@ -1484,7 +1492,18 @@ static int intel_th_msc_probe(struct intel_th_device *thdev)
1484 1492
1485static void intel_th_msc_remove(struct intel_th_device *thdev) 1493static void intel_th_msc_remove(struct intel_th_device *thdev)
1486{ 1494{
1487 sysfs_remove_group(&thdev->dev.kobj, &msc_output_group); 1495 struct msc *msc = dev_get_drvdata(&thdev->dev);
1496 int ret;
1497
1498 intel_th_msc_deactivate(thdev);
1499
1500 /*
1501 * Buffers should not be used at this point except if the
1502 * output character device is still open and the parent
1503 * device gets detached from its bus, which is a FIXME.
1504 */
1505 ret = msc_buffer_free_unless_used(msc);
1506 WARN_ON_ONCE(ret);
1488} 1507}
1489 1508
1490static struct intel_th_driver intel_th_msc_driver = { 1509static struct intel_th_driver intel_th_msc_driver = {
@@ -1493,6 +1512,7 @@ static struct intel_th_driver intel_th_msc_driver = {
1493 .activate = intel_th_msc_activate, 1512 .activate = intel_th_msc_activate,
1494 .deactivate = intel_th_msc_deactivate, 1513 .deactivate = intel_th_msc_deactivate,
1495 .fops = &intel_th_msc_fops, 1514 .fops = &intel_th_msc_fops,
1515 .attr_group = &msc_output_group,
1496 .driver = { 1516 .driver = {
1497 .name = "msc", 1517 .name = "msc",
1498 .owner = THIS_MODULE, 1518 .owner = THIS_MODULE,
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index bca7a2ac00d6..5e25c7eb31d3 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -75,6 +75,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
75 PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80), 75 PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
76 .driver_data = (kernel_ulong_t)0, 76 .driver_data = (kernel_ulong_t)0,
77 }, 77 },
78 {
79 /* Broxton B-step */
80 PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e),
81 .driver_data = (kernel_ulong_t)0,
82 },
78 { 0 }, 83 { 0 },
79}; 84};
80 85
diff --git a/drivers/hwtracing/intel_th/pti.c b/drivers/hwtracing/intel_th/pti.c
index 57cbfdcc7ef0..35738b5bfccd 100644
--- a/drivers/hwtracing/intel_th/pti.c
+++ b/drivers/hwtracing/intel_th/pti.c
@@ -200,7 +200,6 @@ static int intel_th_pti_probe(struct intel_th_device *thdev)
200 struct resource *res; 200 struct resource *res;
201 struct pti_device *pti; 201 struct pti_device *pti;
202 void __iomem *base; 202 void __iomem *base;
203 int ret;
204 203
205 res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0); 204 res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
206 if (!res) 205 if (!res)
@@ -219,10 +218,6 @@ static int intel_th_pti_probe(struct intel_th_device *thdev)
219 218
220 read_hw_config(pti); 219 read_hw_config(pti);
221 220
222 ret = sysfs_create_group(&dev->kobj, &pti_output_group);
223 if (ret)
224 return ret;
225
226 dev_set_drvdata(dev, pti); 221 dev_set_drvdata(dev, pti);
227 222
228 return 0; 223 return 0;
@@ -237,6 +232,7 @@ static struct intel_th_driver intel_th_pti_driver = {
237 .remove = intel_th_pti_remove, 232 .remove = intel_th_pti_remove,
238 .activate = intel_th_pti_activate, 233 .activate = intel_th_pti_activate,
239 .deactivate = intel_th_pti_deactivate, 234 .deactivate = intel_th_pti_deactivate,
235 .attr_group = &pti_output_group,
240 .driver = { 236 .driver = {
241 .name = "pti", 237 .name = "pti",
242 .owner = THIS_MODULE, 238 .owner = THIS_MODULE,