diff options
| -rw-r--r-- | drivers/iommu/amd_iommu_v2.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index d4daa05efe60..499b4366a98d 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c | |||
| @@ -45,7 +45,7 @@ struct pri_queue { | |||
| 45 | struct pasid_state { | 45 | struct pasid_state { |
| 46 | struct list_head list; /* For global state-list */ | 46 | struct list_head list; /* For global state-list */ |
| 47 | atomic_t count; /* Reference count */ | 47 | atomic_t count; /* Reference count */ |
| 48 | atomic_t mmu_notifier_count; /* Counting nested mmu_notifier | 48 | unsigned mmu_notifier_count; /* Counting nested mmu_notifier |
| 49 | calls */ | 49 | calls */ |
| 50 | struct task_struct *task; /* Task bound to this PASID */ | 50 | struct task_struct *task; /* Task bound to this PASID */ |
| 51 | struct mm_struct *mm; /* mm_struct for the faults */ | 51 | struct mm_struct *mm; /* mm_struct for the faults */ |
| @@ -53,7 +53,8 @@ struct pasid_state { | |||
| 53 | struct pri_queue pri[PRI_QUEUE_SIZE]; /* PRI tag states */ | 53 | struct pri_queue pri[PRI_QUEUE_SIZE]; /* PRI tag states */ |
| 54 | struct device_state *device_state; /* Link to our device_state */ | 54 | struct device_state *device_state; /* Link to our device_state */ |
| 55 | int pasid; /* PASID index */ | 55 | int pasid; /* PASID index */ |
| 56 | spinlock_t lock; /* Protect pri_queues */ | 56 | spinlock_t lock; /* Protect pri_queues and |
| 57 | mmu_notifer_count */ | ||
| 57 | wait_queue_head_t wq; /* To wait for count == 0 */ | 58 | wait_queue_head_t wq; /* To wait for count == 0 */ |
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| @@ -431,15 +432,19 @@ static void mn_invalidate_range_start(struct mmu_notifier *mn, | |||
| 431 | { | 432 | { |
| 432 | struct pasid_state *pasid_state; | 433 | struct pasid_state *pasid_state; |
| 433 | struct device_state *dev_state; | 434 | struct device_state *dev_state; |
| 435 | unsigned long flags; | ||
| 434 | 436 | ||
| 435 | pasid_state = mn_to_state(mn); | 437 | pasid_state = mn_to_state(mn); |
| 436 | dev_state = pasid_state->device_state; | 438 | dev_state = pasid_state->device_state; |
| 437 | 439 | ||
| 438 | if (atomic_add_return(1, &pasid_state->mmu_notifier_count) == 1) { | 440 | spin_lock_irqsave(&pasid_state->lock, flags); |
| 441 | if (pasid_state->mmu_notifier_count == 0) { | ||
| 439 | amd_iommu_domain_set_gcr3(dev_state->domain, | 442 | amd_iommu_domain_set_gcr3(dev_state->domain, |
| 440 | pasid_state->pasid, | 443 | pasid_state->pasid, |
| 441 | __pa(empty_page_table)); | 444 | __pa(empty_page_table)); |
| 442 | } | 445 | } |
| 446 | pasid_state->mmu_notifier_count += 1; | ||
| 447 | spin_unlock_irqrestore(&pasid_state->lock, flags); | ||
| 443 | } | 448 | } |
| 444 | 449 | ||
| 445 | static void mn_invalidate_range_end(struct mmu_notifier *mn, | 450 | static void mn_invalidate_range_end(struct mmu_notifier *mn, |
| @@ -448,15 +453,19 @@ static void mn_invalidate_range_end(struct mmu_notifier *mn, | |||
| 448 | { | 453 | { |
| 449 | struct pasid_state *pasid_state; | 454 | struct pasid_state *pasid_state; |
| 450 | struct device_state *dev_state; | 455 | struct device_state *dev_state; |
| 456 | unsigned long flags; | ||
| 451 | 457 | ||
| 452 | pasid_state = mn_to_state(mn); | 458 | pasid_state = mn_to_state(mn); |
| 453 | dev_state = pasid_state->device_state; | 459 | dev_state = pasid_state->device_state; |
| 454 | 460 | ||
| 455 | if (atomic_dec_and_test(&pasid_state->mmu_notifier_count)) { | 461 | spin_lock_irqsave(&pasid_state->lock, flags); |
| 462 | pasid_state->mmu_notifier_count -= 1; | ||
| 463 | if (pasid_state->mmu_notifier_count == 0) { | ||
| 456 | amd_iommu_domain_set_gcr3(dev_state->domain, | 464 | amd_iommu_domain_set_gcr3(dev_state->domain, |
| 457 | pasid_state->pasid, | 465 | pasid_state->pasid, |
| 458 | __pa(pasid_state->mm->pgd)); | 466 | __pa(pasid_state->mm->pgd)); |
| 459 | } | 467 | } |
| 468 | spin_unlock_irqrestore(&pasid_state->lock, flags); | ||
| 460 | } | 469 | } |
| 461 | 470 | ||
| 462 | static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm) | 471 | static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm) |
| @@ -650,7 +659,6 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid, | |||
| 650 | goto out; | 659 | goto out; |
| 651 | 660 | ||
| 652 | atomic_set(&pasid_state->count, 1); | 661 | atomic_set(&pasid_state->count, 1); |
| 653 | atomic_set(&pasid_state->mmu_notifier_count, 0); | ||
| 654 | init_waitqueue_head(&pasid_state->wq); | 662 | init_waitqueue_head(&pasid_state->wq); |
| 655 | spin_lock_init(&pasid_state->lock); | 663 | spin_lock_init(&pasid_state->lock); |
| 656 | 664 | ||
