diff options
Diffstat (limited to 'drivers/hwqueue/hwqueue_core.c')
-rw-r--r-- | drivers/hwqueue/hwqueue_core.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/drivers/hwqueue/hwqueue_core.c b/drivers/hwqueue/hwqueue_core.c index c6d3d54e31e..204c8391d4d 100644 --- a/drivers/hwqueue/hwqueue_core.c +++ b/drivers/hwqueue/hwqueue_core.c | |||
@@ -134,6 +134,7 @@ int hwqueue_device_register(struct hwqueue_device *hdev) | |||
134 | setup_timer(&inst->poll_timer, __hwqueue_poll, | 134 | setup_timer(&inst->poll_timer, __hwqueue_poll, |
135 | (unsigned long)inst); | 135 | (unsigned long)inst); |
136 | init_waitqueue_head(&inst->wait); | 136 | init_waitqueue_head(&inst->wait); |
137 | spin_lock_init(&inst->lock); | ||
137 | } | 138 | } |
138 | 139 | ||
139 | list_add(&hdev->list, &hwqueue_devices); | 140 | list_add(&hdev->list, &hwqueue_devices); |
@@ -492,6 +493,7 @@ int hwqueue_enable_notifier(struct hwqueue *qh) | |||
492 | struct hwqueue_instance *inst = qh->inst; | 493 | struct hwqueue_instance *inst = qh->inst; |
493 | struct hwqueue_device *hdev = inst->hdev; | 494 | struct hwqueue_device *hdev = inst->hdev; |
494 | bool first; | 495 | bool first; |
496 | unsigned long flags; | ||
495 | 497 | ||
496 | if (!hwqueue_is_readable(qh)) | 498 | if (!hwqueue_is_readable(qh)) |
497 | return -EINVAL; | 499 | return -EINVAL; |
@@ -499,16 +501,21 @@ int hwqueue_enable_notifier(struct hwqueue *qh) | |||
499 | if (WARN_ON(!qh->notifier_fn)) | 501 | if (WARN_ON(!qh->notifier_fn)) |
500 | return -EINVAL; | 502 | return -EINVAL; |
501 | 503 | ||
504 | /* Protect against interrupt delivery */ | ||
505 | spin_lock_irqsave(&inst->lock, flags); | ||
506 | |||
502 | /* Adjust the per handle notifier count */ | 507 | /* Adjust the per handle notifier count */ |
503 | first = (atomic_inc_return(&qh->notifier_enabled) == 1); | 508 | first = (atomic_inc_return(&qh->notifier_enabled) == 1); |
504 | if (!first) | 509 | if (!first) |
505 | return 0; /* nothing to do */ | 510 | goto unlock; /* nothing to do */ |
506 | 511 | ||
507 | /* Now adjust the per instance notifier count */ | 512 | /* Now adjust the per instance notifier count */ |
508 | first = (atomic_inc_return(&inst->num_notifiers) == 1); | 513 | first = (atomic_inc_return(&inst->num_notifiers) == 1); |
509 | if (first) | 514 | if (first) |
510 | hdev->ops->set_notify(inst, true); | 515 | hdev->ops->set_notify(inst, true); |
511 | 516 | ||
517 | unlock: | ||
518 | spin_unlock_irqrestore(&inst->lock, flags); | ||
512 | return 0; | 519 | return 0; |
513 | } | 520 | } |
514 | EXPORT_SYMBOL(hwqueue_enable_notifier); | 521 | EXPORT_SYMBOL(hwqueue_enable_notifier); |
@@ -524,18 +531,24 @@ int hwqueue_disable_notifier(struct hwqueue *qh) | |||
524 | struct hwqueue_instance *inst = qh->inst; | 531 | struct hwqueue_instance *inst = qh->inst; |
525 | struct hwqueue_device *hdev = inst->hdev; | 532 | struct hwqueue_device *hdev = inst->hdev; |
526 | bool last; | 533 | bool last; |
534 | unsigned long flags; | ||
527 | 535 | ||
528 | if (!hwqueue_is_readable(qh)) | 536 | if (!hwqueue_is_readable(qh)) |
529 | return -EINVAL; | 537 | return -EINVAL; |
530 | 538 | ||
539 | /* Protect against interrupt delivery */ | ||
540 | spin_lock_irqsave(&inst->lock, flags); | ||
541 | |||
531 | last = (atomic_dec_return(&qh->notifier_enabled) == 0); | 542 | last = (atomic_dec_return(&qh->notifier_enabled) == 0); |
532 | if (!last) | 543 | if (!last) |
533 | return 0; /* nothing to do */ | 544 | goto unlock; /* nothing to do */ |
534 | 545 | ||
535 | last = (atomic_dec_return(&inst->num_notifiers) == 0); | 546 | last = (atomic_dec_return(&inst->num_notifiers) == 0); |
536 | if (last) | 547 | if (last) |
537 | hdev->ops->set_notify(inst, false); | 548 | hdev->ops->set_notify(inst, false); |
538 | 549 | ||
550 | unlock: | ||
551 | spin_unlock_irqrestore(&inst->lock, flags); | ||
539 | return 0; | 552 | return 0; |
540 | } | 553 | } |
541 | EXPORT_SYMBOL(hwqueue_disable_notifier); | 554 | EXPORT_SYMBOL(hwqueue_disable_notifier); |
@@ -619,11 +632,18 @@ EXPORT_SYMBOL(__hwqueue_pop_slow); | |||
619 | void hwqueue_notify(struct hwqueue_instance *inst) | 632 | void hwqueue_notify(struct hwqueue_instance *inst) |
620 | { | 633 | { |
621 | struct hwqueue *qh; | 634 | struct hwqueue *qh; |
635 | unsigned long flags; | ||
636 | bool enabled; | ||
622 | 637 | ||
623 | rcu_read_lock(); | 638 | rcu_read_lock(); |
624 | 639 | ||
625 | for_each_handle_rcu(qh, inst) { | 640 | for_each_handle_rcu(qh, inst) { |
626 | if (atomic_read(&qh->notifier_enabled) <= 0) | 641 | /* Synchronize against enable/disable notifier */ |
642 | spin_lock_irqsave(&inst->lock, flags); | ||
643 | enabled = atomic_read(&qh->notifier_enabled) > 0; | ||
644 | spin_unlock_irqrestore(&inst->lock, flags); | ||
645 | |||
646 | if (!enabled) | ||
627 | continue; | 647 | continue; |
628 | if (WARN_ON(!qh->notifier_fn)) | 648 | if (WARN_ON(!qh->notifier_fn)) |
629 | continue; | 649 | continue; |