diff options
Diffstat (limited to 'drivers/hwtracing/intel_th/msu.c')
| -rw-r--r-- | drivers/hwtracing/intel_th/msu.c | 116 |
1 files changed, 68 insertions, 48 deletions
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); | 279 | unlock: |
| 280 | mutex_unlock(&msc->buf_mutex); | ||
| 268 | 281 | ||
| 269 | return iter; | 282 | return iter; |
| 270 | } | 283 | } |
| 271 | 284 | ||
| 272 | static void msc_iter_remove(struct msc_iter *iter, struct msc *msc) | 285 | static 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 | */ |
| 479 | static int msc_configure(struct msc *msc) | 491 | static 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 | */ |
| 526 | static void msc_disable(struct msc *msc) | 538 | static 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) | |||
| 569 | static int intel_th_msc_activate(struct intel_th_device *thdev) | 580 | static 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 | ||
| 592 | static void intel_th_msc_deactivate(struct intel_th_device *thdev) | 602 | static 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 | ||
| 1250 | static int intel_th_msc_init(struct msc *msc) | 1259 | static 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 | ||
| 1485 | static void intel_th_msc_remove(struct intel_th_device *thdev) | 1493 | static 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 | ||
| 1490 | static struct intel_th_driver intel_th_msc_driver = { | 1509 | static 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, |
