Skip to content

Commit

Permalink
Merge tag 'iommu-fixes-v3.16-rc1' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/joro/iommu

Pull IOMMU fixes from Joerg Roedel:

 - fix VT-d regression with handling multiple RMRR entries per device

 - fix a small race that was left in the mmu_notifier handling in the
   AMD IOMMUv2 driver

* tag 'iommu-fixes-v3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/amd: Fix small race between invalidate_range_end/start
  iommu/vt-d: fix bug in handling multiple RMRRs for the same PCI device
  • Loading branch information
Linus Torvalds committed Jun 28, 2014
2 parents d1fc98b + d73a6d7 commit 3e7b256
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 11 deletions.
18 changes: 13 additions & 5 deletions drivers/iommu/amd_iommu_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,16 @@ struct pri_queue {
struct pasid_state {
struct list_head list; /* For global state-list */
atomic_t count; /* Reference count */
atomic_t mmu_notifier_count; /* Counting nested mmu_notifier
unsigned mmu_notifier_count; /* Counting nested mmu_notifier
calls */
struct task_struct *task; /* Task bound to this PASID */
struct mm_struct *mm; /* mm_struct for the faults */
struct mmu_notifier mn; /* mmu_otifier handle */
struct pri_queue pri[PRI_QUEUE_SIZE]; /* PRI tag states */
struct device_state *device_state; /* Link to our device_state */
int pasid; /* PASID index */
spinlock_t lock; /* Protect pri_queues */
spinlock_t lock; /* Protect pri_queues and
mmu_notifer_count */
wait_queue_head_t wq; /* To wait for count == 0 */
};

Expand Down Expand Up @@ -431,15 +432,19 @@ static void mn_invalidate_range_start(struct mmu_notifier *mn,
{
struct pasid_state *pasid_state;
struct device_state *dev_state;
unsigned long flags;

pasid_state = mn_to_state(mn);
dev_state = pasid_state->device_state;

if (atomic_add_return(1, &pasid_state->mmu_notifier_count) == 1) {
spin_lock_irqsave(&pasid_state->lock, flags);
if (pasid_state->mmu_notifier_count == 0) {
amd_iommu_domain_set_gcr3(dev_state->domain,
pasid_state->pasid,
__pa(empty_page_table));
}
pasid_state->mmu_notifier_count += 1;
spin_unlock_irqrestore(&pasid_state->lock, flags);
}

static void mn_invalidate_range_end(struct mmu_notifier *mn,
Expand All @@ -448,15 +453,19 @@ static void mn_invalidate_range_end(struct mmu_notifier *mn,
{
struct pasid_state *pasid_state;
struct device_state *dev_state;
unsigned long flags;

pasid_state = mn_to_state(mn);
dev_state = pasid_state->device_state;

if (atomic_dec_and_test(&pasid_state->mmu_notifier_count)) {
spin_lock_irqsave(&pasid_state->lock, flags);
pasid_state->mmu_notifier_count -= 1;
if (pasid_state->mmu_notifier_count == 0) {
amd_iommu_domain_set_gcr3(dev_state->domain,
pasid_state->pasid,
__pa(pasid_state->mm->pgd));
}
spin_unlock_irqrestore(&pasid_state->lock, flags);
}

static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
Expand Down Expand Up @@ -650,7 +659,6 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
goto out;

atomic_set(&pasid_state->count, 1);
atomic_set(&pasid_state->mmu_notifier_count, 0);
init_waitqueue_head(&pasid_state->wq);
spin_lock_init(&pasid_state->lock);

Expand Down
9 changes: 3 additions & 6 deletions drivers/iommu/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3816,14 +3816,11 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
((void *)rmrr) + rmrr->header.length,
rmrr->segment, rmrru->devices,
rmrru->devices_cnt);
if (ret > 0)
break;
else if(ret < 0)
if(ret < 0)
return ret;
} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
if (dmar_remove_dev_scope(info, rmrr->segment,
rmrru->devices, rmrru->devices_cnt))
break;
dmar_remove_dev_scope(info, rmrr->segment,
rmrru->devices, rmrru->devices_cnt);
}
}

Expand Down

0 comments on commit 3e7b256

Please sign in to comment.