Commit 58c610bd authored by Sheng Yang's avatar Sheng Yang Committed by David Woodhouse

intel-iommu: Snooping control support

Snooping control enabled IOMMU to guarantee DMA cache coherency and thus reduce
software effort (VMM) in maintaining effective memory type.
Signed-off-by: default avatarSheng Yang <sheng@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent a1e4ee22
...@@ -231,6 +231,7 @@ struct dmar_domain { ...@@ -231,6 +231,7 @@ struct dmar_domain {
int flags; /* flags to find out type of domain */ int flags; /* flags to find out type of domain */
int iommu_coherency;/* indicate coherency of iommu access */ int iommu_coherency;/* indicate coherency of iommu access */
int iommu_snooping; /* indicate snooping control feature*/
int iommu_count; /* reference count of iommu */ int iommu_count; /* reference count of iommu */
spinlock_t iommu_lock; /* protect iommu set in domain */ spinlock_t iommu_lock; /* protect iommu set in domain */
u64 max_addr; /* maximum mapped address */ u64 max_addr; /* maximum mapped address */
...@@ -421,7 +422,6 @@ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) ...@@ -421,7 +422,6 @@ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
return g_iommus[iommu_id]; return g_iommus[iommu_id];
} }
/* "Coherency" capability may be different across iommus */
static void domain_update_iommu_coherency(struct dmar_domain *domain) static void domain_update_iommu_coherency(struct dmar_domain *domain)
{ {
int i; int i;
...@@ -438,6 +438,29 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain) ...@@ -438,6 +438,29 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
} }
} }
static void domain_update_iommu_snooping(struct dmar_domain *domain)
{
int i;
domain->iommu_snooping = 1;
i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
for (; i < g_num_of_iommus; ) {
if (!ecap_sc_support(g_iommus[i]->ecap)) {
domain->iommu_snooping = 0;
break;
}
i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
}
}
/* 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);
}
static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn) static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn)
{ {
struct dmar_drhd_unit *drhd = NULL; struct dmar_drhd_unit *drhd = NULL;
...@@ -1429,6 +1452,11 @@ static int domain_init(struct dmar_domain *domain, int guest_width) ...@@ -1429,6 +1452,11 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
else else
domain->iommu_coherency = 0; domain->iommu_coherency = 0;
if (ecap_sc_support(iommu->ecap))
domain->iommu_snooping = 1;
else
domain->iommu_snooping = 0;
domain->iommu_count = 1; domain->iommu_count = 1;
/* always allocate the top pgd */ /* always allocate the top pgd */
...@@ -1557,7 +1585,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, ...@@ -1557,7 +1585,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
spin_lock_irqsave(&domain->iommu_lock, flags); spin_lock_irqsave(&domain->iommu_lock, flags);
if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) { if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
domain->iommu_count++; domain->iommu_count++;
domain_update_iommu_coherency(domain); domain_update_iommu_cap(domain);
} }
spin_unlock_irqrestore(&domain->iommu_lock, flags); spin_unlock_irqrestore(&domain->iommu_lock, flags);
return 0; return 0;
...@@ -2820,7 +2848,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, ...@@ -2820,7 +2848,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain,
spin_lock_irqsave(&domain->iommu_lock, tmp_flags); spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
clear_bit(iommu->seq_id, &domain->iommu_bmp); clear_bit(iommu->seq_id, &domain->iommu_bmp);
domain->iommu_count--; domain->iommu_count--;
domain_update_iommu_coherency(domain); domain_update_iommu_cap(domain);
spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
} }
...@@ -2848,13 +2876,13 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain) ...@@ -2848,13 +2876,13 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
iommu_detach_dev(iommu, info->bus, info->devfn); iommu_detach_dev(iommu, info->bus, info->devfn);
/* clear this iommu in iommu_bmp, update iommu count /* clear this iommu in iommu_bmp, update iommu count
* and coherency * and capabilities
*/ */
spin_lock_irqsave(&domain->iommu_lock, flags2); spin_lock_irqsave(&domain->iommu_lock, flags2);
if (test_and_clear_bit(iommu->seq_id, if (test_and_clear_bit(iommu->seq_id,
&domain->iommu_bmp)) { &domain->iommu_bmp)) {
domain->iommu_count--; domain->iommu_count--;
domain_update_iommu_coherency(domain); domain_update_iommu_cap(domain);
} }
spin_unlock_irqrestore(&domain->iommu_lock, flags2); spin_unlock_irqrestore(&domain->iommu_lock, flags2);
......
...@@ -123,7 +123,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) ...@@ -123,7 +123,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define ecap_eim_support(e) ((e >> 4) & 0x1) #define ecap_eim_support(e) ((e >> 4) & 0x1)
#define ecap_ir_support(e) ((e >> 3) & 0x1) #define ecap_ir_support(e) ((e >> 3) & 0x1)
#define ecap_max_handle_mask(e) ((e >> 20) & 0xf) #define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
#define ecap_sc_support(e) ((e >> 7) & 0x1) /* Snooping Control */
/* IOTLB_REG */ /* IOTLB_REG */
#define DMA_TLB_FLUSH_GRANU_OFFSET 60 #define DMA_TLB_FLUSH_GRANU_OFFSET 60
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment