Skip to content

Commit

Permalink
iommu/vt-d: Fix issue in computing domain's iommu_snooping flag
Browse files Browse the repository at this point in the history
IOMMU units may dynamically attached to/detached from domains,
so we should scan all active IOMMU units when computing iommu_snooping
flag for a domain instead of only scanning IOMMU units associated
with the domain.

Also check snooping and superpage capabilities when hot-adding DMAR units.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
  • Loading branch information
Jiang Liu authored and Joerg Roedel committed Jul 23, 2014
1 parent a156ef9 commit 161f693
Showing 1 changed file with 24 additions and 18 deletions.
42 changes: 24 additions & 18 deletions drivers/iommu/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -633,50 +633,56 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
rcu_read_unlock();
}

static void domain_update_iommu_snooping(struct dmar_domain *domain)
static int domain_update_iommu_snooping(struct intel_iommu *skip)
{
int i;

domain->iommu_snooping = 1;
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
int ret = 1;

for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) {
if (!ecap_sc_support(g_iommus[i]->ecap)) {
domain->iommu_snooping = 0;
break;
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {
if (iommu != skip) {
if (!ecap_sc_support(iommu->ecap)) {
ret = 0;
break;
}
}
}
rcu_read_unlock();

return ret;
}

static void domain_update_iommu_superpage(struct dmar_domain *domain)
static int domain_update_iommu_superpage(struct intel_iommu *skip)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
struct intel_iommu *iommu;
int mask = 0xf;

if (!intel_iommu_superpage) {
domain->iommu_superpage = 0;
return;
return 0;
}

/* set iommu_superpage to the smallest common denominator */
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {
mask &= cap_super_page_val(iommu->cap);
if (!mask) {
break;
if (iommu != skip) {
mask &= cap_super_page_val(iommu->cap);
if (!mask)
break;
}
}
rcu_read_unlock();

domain->iommu_superpage = fls(mask);
return fls(mask);
}

/* Some capabilities may be different across iommus */
static void domain_update_iommu_cap(struct dmar_domain *domain)
{
domain_update_iommu_coherency(domain);
domain_update_iommu_snooping(domain);
domain_update_iommu_superpage(domain);
domain->iommu_snooping = domain_update_iommu_snooping(NULL);
domain->iommu_superpage = domain_update_iommu_superpage(NULL);
}

static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
Expand Down

0 comments on commit 161f693

Please sign in to comment.