Skip to content

Commit

Permalink
AMD IOMMU: don't assign preallocated protection domains to devices
Browse files Browse the repository at this point in the history
In isolation mode the protection domains for the devices are
preallocated and preassigned. This is bad if a device should be passed
to a virtualization guest because the IOMMU code does not know if it is
in use by a driver. This patch changes the code to assign the device to
the preallocated domain only if there are dma mapping requests for it.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Joerg Roedel authored and Ingo Molnar committed Sep 19, 2008
1 parent b39ba6a commit bd60b73
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
43 changes: 38 additions & 5 deletions arch/x86/kernel/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@

static DEFINE_RWLOCK(amd_iommu_devtable_lock);

/* A list of preallocated protection domains */
static LIST_HEAD(iommu_pd_list);
static DEFINE_SPINLOCK(iommu_pd_list_lock);

/*
* general struct to manage commands send to an IOMMU
*/
Expand Down Expand Up @@ -663,6 +667,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->next_bit = 0;

dma_dom->need_flush = false;
dma_dom->target_dev = 0xffff;

/* Intialize the exclusion range if necessary */
if (iommu->exclusion_start &&
Expand Down Expand Up @@ -768,6 +773,33 @@ static bool check_device(struct device *dev)
return true;
}

/*
* In this function the list of preallocated protection domains is traversed to
* find the domain for a specific device
*/
static struct dma_ops_domain *find_protection_domain(u16 devid)
{
struct dma_ops_domain *entry, *ret = NULL;
unsigned long flags;

if (list_empty(&iommu_pd_list))
return NULL;

spin_lock_irqsave(&iommu_pd_list_lock, flags);

list_for_each_entry(entry, &iommu_pd_list, list) {
if (entry->target_dev == devid) {
ret = entry;
list_del(&ret->list);
break;
}
}

spin_unlock_irqrestore(&iommu_pd_list_lock, flags);

return ret;
}

/*
* In the dma_ops path we only have the struct device. This function
* finds the corresponding IOMMU, the protection domain and the
Expand Down Expand Up @@ -803,9 +835,11 @@ static int get_device_resources(struct device *dev,
*iommu = amd_iommu_rlookup_table[*bdf];
if (*iommu == NULL)
return 0;
dma_dom = (*iommu)->default_dom;
*domain = domain_for_device(*bdf);
if (*domain == NULL) {
dma_dom = find_protection_domain(*bdf);
if (!dma_dom)
dma_dom = (*iommu)->default_dom;
*domain = &dma_dom->domain;
set_device_domain(*iommu, *domain, *bdf);
printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
Expand Down Expand Up @@ -1257,10 +1291,9 @@ void prealloc_protection_domains(void)
if (!dma_dom)
continue;
init_unity_mappings_for_device(dma_dom, devid);
set_device_domain(iommu, &dma_dom->domain, devid);
printk(KERN_INFO "AMD IOMMU: Allocated domain %d for device ",
dma_dom->domain.id);
print_devid(devid, 1);
dma_dom->target_dev = devid;

list_add_tail(&dma_dom->list, &iommu_pd_list);
}
}

Expand Down
6 changes: 6 additions & 0 deletions include/asm-x86/amd_iommu_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ struct dma_ops_domain {

/* This will be set to true when TLB needs to be flushed */
bool need_flush;

/*
* if this is a preallocated domain, keep the device for which it was
* preallocated in this variable
*/
u16 target_dev;
};

/*
Expand Down

0 comments on commit bd60b73

Please sign in to comment.