aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2014-05-20 17:18:24 -0400
committerJoerg Roedel <jroedel@suse.de>2014-05-26 05:28:13 -0400
commita40d4c67d7dec4e9b04e2fe1105072a843fda5a9 (patch)
tree1a1d7a9cc86058fb85eaa865d3032116a69e11b0 /drivers/iommu
parent741669c765c45cace9bd630f7c8c8047c8b33567 (diff)
iommu/amd: Implement mmu_notifier_release call-back
Since mmu_notifier call-backs can sleep (because they use SRCU now) we can use them to tear down PASID mappings. This allows us to finally remove the hack to use the task_exit notifier from oprofile to get notified when a process dies. Signed-off-by: Joerg Roedel <jroedel@suse.de> Tested-by: Jay Cornwall <Jay.Cornwall@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/amd_iommu_v2.c91
1 files changed, 35 insertions, 56 deletions
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index 569b6a0b6f56..09d342bf0f47 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -101,7 +101,6 @@ static u64 *empty_page_table;
101 101
102static void free_pasid_states(struct device_state *dev_state); 102static void free_pasid_states(struct device_state *dev_state);
103static void unbind_pasid(struct device_state *dev_state, int pasid); 103static void unbind_pasid(struct device_state *dev_state, int pasid);
104static int task_exit(struct notifier_block *nb, unsigned long e, void *data);
105 104
106static u16 device_id(struct pci_dev *pdev) 105static u16 device_id(struct pci_dev *pdev)
107{ 106{
@@ -172,10 +171,6 @@ static void put_device_state_wait(struct device_state *dev_state)
172 free_device_state(dev_state); 171 free_device_state(dev_state);
173} 172}
174 173
175static struct notifier_block profile_nb = {
176 .notifier_call = task_exit,
177};
178
179static void link_pasid_state(struct pasid_state *pasid_state) 174static void link_pasid_state(struct pasid_state *pasid_state)
180{ 175{
181 spin_lock(&ps_lock); 176 spin_lock(&ps_lock);
@@ -393,7 +388,12 @@ static void free_pasid_states(struct device_state *dev_state)
393 continue; 388 continue;
394 389
395 put_pasid_state(pasid_state); 390 put_pasid_state(pasid_state);
396 unbind_pasid(dev_state, i); 391
392 /*
393 * This will call the mn_release function and
394 * unbind the PASID
395 */
396 mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm);
397 } 397 }
398 398
399 if (dev_state->pasid_levels == 2) 399 if (dev_state->pasid_levels == 2)
@@ -475,7 +475,24 @@ static void mn_invalidate_range_end(struct mmu_notifier *mn,
475 __pa(pasid_state->mm->pgd)); 475 __pa(pasid_state->mm->pgd));
476} 476}
477 477
478static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
479{
480 struct pasid_state *pasid_state;
481 struct device_state *dev_state;
482
483 might_sleep();
484
485 pasid_state = mn_to_state(mn);
486 dev_state = pasid_state->device_state;
487
488 if (pasid_state->device_state->inv_ctx_cb)
489 dev_state->inv_ctx_cb(dev_state->pdev, pasid_state->pasid);
490
491 unbind_pasid(dev_state, pasid_state->pasid);
492}
493
478static struct mmu_notifier_ops iommu_mn = { 494static struct mmu_notifier_ops iommu_mn = {
495 .release = mn_release,
479 .clear_flush_young = mn_clear_flush_young, 496 .clear_flush_young = mn_clear_flush_young,
480 .change_pte = mn_change_pte, 497 .change_pte = mn_change_pte,
481 .invalidate_page = mn_invalidate_page, 498 .invalidate_page = mn_invalidate_page,
@@ -620,53 +637,6 @@ static struct notifier_block ppr_nb = {
620 .notifier_call = ppr_notifier, 637 .notifier_call = ppr_notifier,
621}; 638};
622 639
623static int task_exit(struct notifier_block *nb, unsigned long e, void *data)
624{
625 struct pasid_state *pasid_state;
626 struct task_struct *task;
627
628 task = data;
629
630 /*
631 * Using this notifier is a hack - but there is no other choice
632 * at the moment. What I really want is a sleeping notifier that
633 * is called when an MM goes down. But such a notifier doesn't
634 * exist yet. The notifier needs to sleep because it has to make
635 * sure that the device does not use the PASID and the address
636 * space anymore before it is destroyed. This includes waiting
637 * for pending PRI requests to pass the workqueue. The
638 * MMU-Notifiers would be a good fit, but they use RCU and so
639 * they are not allowed to sleep. Lets see how we can solve this
640 * in a more intelligent way in the future.
641 */
642again:
643 spin_lock(&ps_lock);
644 list_for_each_entry(pasid_state, &pasid_state_list, list) {
645 struct device_state *dev_state;
646 int pasid;
647
648 if (pasid_state->task != task)
649 continue;
650
651 /* Drop Lock and unbind */
652 spin_unlock(&ps_lock);
653
654 dev_state = pasid_state->device_state;
655 pasid = pasid_state->pasid;
656
657 if (pasid_state->device_state->inv_ctx_cb)
658 dev_state->inv_ctx_cb(dev_state->pdev, pasid);
659
660 unbind_pasid(dev_state, pasid);
661
662 /* Task may be in the list multiple times */
663 goto again;
664 }
665 spin_unlock(&ps_lock);
666
667 return NOTIFY_OK;
668}
669
670int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid, 640int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
671 struct task_struct *task) 641 struct task_struct *task)
672{ 642{
@@ -741,6 +711,7 @@ EXPORT_SYMBOL(amd_iommu_bind_pasid);
741 711
742void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid) 712void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid)
743{ 713{
714 struct pasid_state *pasid_state;
744 struct device_state *dev_state; 715 struct device_state *dev_state;
745 u16 devid; 716 u16 devid;
746 717
@@ -757,7 +728,17 @@ void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid)
757 if (pasid < 0 || pasid >= dev_state->max_pasids) 728 if (pasid < 0 || pasid >= dev_state->max_pasids)
758 goto out; 729 goto out;
759 730
760 unbind_pasid(dev_state, pasid); 731 pasid_state = get_pasid_state(dev_state, pasid);
732 if (pasid_state == NULL)
733 goto out;
734 /*
735 * Drop reference taken here. We are safe because we still hold
736 * the reference taken in the amd_iommu_bind_pasid function.
737 */
738 put_pasid_state(pasid_state);
739
740 /* This will call the mn_release function and unbind the PASID */
741 mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm);
761 742
762out: 743out:
763 put_device_state(dev_state); 744 put_device_state(dev_state);
@@ -963,7 +944,6 @@ static int __init amd_iommu_v2_init(void)
963 goto out_destroy_wq; 944 goto out_destroy_wq;
964 945
965 amd_iommu_register_ppr_notifier(&ppr_nb); 946 amd_iommu_register_ppr_notifier(&ppr_nb);
966 profile_event_register(PROFILE_TASK_EXIT, &profile_nb);
967 947
968 return 0; 948 return 0;
969 949
@@ -982,7 +962,6 @@ static void __exit amd_iommu_v2_exit(void)
982 if (!amd_iommu_v2_supported()) 962 if (!amd_iommu_v2_supported())
983 return; 963 return;
984 964
985 profile_event_unregister(PROFILE_TASK_EXIT, &profile_nb);
986 amd_iommu_unregister_ppr_notifier(&ppr_nb); 965 amd_iommu_unregister_ppr_notifier(&ppr_nb);
987 966
988 flush_workqueue(iommu_wq); 967 flush_workqueue(iommu_wq);