* [PATCH 01/13] iommu bitmap insteads of iommu pointer in dmar_domain
@ 2008-12-02 14:22 Han, Weidong
2008-12-04 17:12 ` Mark McLoughlin
0 siblings, 1 reply; 4+ messages in thread
From: Han, Weidong @ 2008-12-02 14:22 UTC (permalink / raw)
To: 'Avi Kivity', Woodhouse, David, 'Jesse Barnes'
Cc: 'Joerg Roedel', Kay, Allen M, Yu, Fenghua,
'kvm@vger.kernel.org',
'iommu@lists.linux-foundation.org'
[-- Attachment #1: Type: text/plain, Size: 13907 bytes --]
Support dmar_domain own multiple devices from different iommus, which are set in iommu bitmap. add function domain_get_iommu() to get the only one iommu of domain in native VT-d usage.
Signed-off-by: Weidong Han <weidong.han@intel.com>
---
drivers/pci/intel-iommu.c | 102 ++++++++++++++++++++++++++++------------
include/linux/dma_remapping.h | 2 +-
2 files changed, 72 insertions(+), 32 deletions(-)
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 5c8baa4..39c5e9d 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -64,6 +64,7 @@ struct deferred_flush_tables {
int next;
struct iova *iova[HIGH_WATER_MARK];
struct dmar_domain *domain[HIGH_WATER_MARK];
+ struct intel_iommu *iommu;
};
static struct deferred_flush_tables *deferred_flush;
@@ -184,6 +185,21 @@ void free_iova_mem(struct iova *iova)
kmem_cache_free(iommu_iova_cache, iova);
}
+/* in native case, each domain is related to only one iommu */
+static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
+{
+ struct dmar_drhd_unit *drhd;
+
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+ if (test_bit(drhd->iommu->seq_id, &domain->iommu_bmp))
+ return drhd->iommu;
+ }
+
+ return NULL;
+}
+
/* Gets context entry for a given bus and devfn */
static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
u8 bus, u8 devfn)
@@ -324,6 +340,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
int level = agaw_to_level(domain->agaw);
int offset;
unsigned long flags;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
BUG_ON(!domain->pgd);
@@ -347,7 +364,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
flags);
return NULL;
}
- __iommu_flush_cache(domain->iommu, tmp_page,
+ __iommu_flush_cache(iommu, tmp_page,
PAGE_SIZE);
dma_set_pte_addr(*pte, virt_to_phys(tmp_page));
/*
@@ -356,7 +373,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
*/
dma_set_pte_readable(*pte);
dma_set_pte_writable(*pte);
- __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ __iommu_flush_cache(iommu, pte, sizeof(*pte));
}
parent = phys_to_virt(dma_pte_addr(*pte));
level--;
@@ -393,13 +410,14 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
{
struct dma_pte *pte = NULL;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
/* get last level pte */
pte = dma_addr_level_pte(domain, addr, 1);
if (pte) {
dma_clear_pte(*pte);
- __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ __iommu_flush_cache(iommu, pte, sizeof(*pte));
}
}
@@ -428,6 +446,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
int addr_width = agaw_to_width(domain->agaw);
struct dma_pte *pte;
int total = agaw_to_level(domain->agaw);
+ struct intel_iommu *iommu = domain_get_iommu(domain);
int level;
u64 tmp;
@@ -447,7 +466,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
free_pgtable_page(
phys_to_virt(dma_pte_addr(*pte)));
dma_clear_pte(*pte);
- __iommu_flush_cache(domain->iommu,
+ __iommu_flush_cache(iommu,
pte, sizeof(*pte));
}
tmp += level_size(level);
@@ -1006,7 +1025,8 @@ static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
set_bit(num, iommu->domain_ids);
domain->id = num;
- domain->iommu = iommu;
+ memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
+ set_bit(iommu->seq_id, &domain->iommu_bmp);
iommu->domains[num] = domain;
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -1016,10 +1036,12 @@ static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
static void iommu_free_domain(struct dmar_domain *domain)
{
unsigned long flags;
+ struct intel_iommu *iommu;
- spin_lock_irqsave(&domain->iommu->lock, flags);
- clear_bit(domain->id, domain->iommu->domain_ids);
- spin_unlock_irqrestore(&domain->iommu->lock, flags);
+ iommu = domain_get_iommu(domain);
+ spin_lock_irqsave(&iommu->lock, flags);
+ clear_bit(domain->id, iommu->domain_ids);
+ spin_unlock_irqrestore(&iommu->lock, flags);
}
static struct iova_domain reserved_iova_list;
@@ -1098,7 +1120,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
domain_reserve_special_ranges(domain);
/* calculate AGAW */
- iommu = domain->iommu;
+ iommu = domain_get_iommu(domain);
if (guest_width > cap_mgaw(iommu->cap))
guest_width = cap_mgaw(iommu->cap);
domain->gaw = guest_width;
@@ -1151,7 +1173,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
u8 bus, u8 devfn)
{
struct context_entry *context;
- struct intel_iommu *iommu = domain->iommu;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
unsigned long flags;
pr_debug("Set context mapping for %02x:%02x.%d\n",
@@ -1223,8 +1245,9 @@ static int domain_context_mapped(struct dmar_domain *domain,
{
int ret;
struct pci_dev *tmp, *parent;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
- ret = device_context_mapped(domain->iommu,
+ ret = device_context_mapped(iommu,
pdev->bus->number, pdev->devfn);
if (!ret)
return ret;
@@ -1235,17 +1258,17 @@ static int domain_context_mapped(struct dmar_domain *domain,
/* Secondary interface's bus number and devfn 0 */
parent = pdev->bus->self;
while (parent != tmp) {
- ret = device_context_mapped(domain->iommu, parent->bus->number,
+ ret = device_context_mapped(iommu, parent->bus->number,
parent->devfn);
if (!ret)
return ret;
parent = parent->bus->self;
}
if (tmp->is_pcie)
- return device_context_mapped(domain->iommu,
+ return device_context_mapped(iommu,
tmp->subordinate->number, 0);
else
- return device_context_mapped(domain->iommu,
+ return device_context_mapped(iommu,
tmp->bus->number, tmp->devfn);
}
@@ -1257,6 +1280,7 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
struct dma_pte *pte;
int index;
int addr_width = agaw_to_width(domain->agaw);
+ struct intel_iommu *iommu = domain_get_iommu(domain);
hpa &= (((u64)1) << addr_width) - 1;
@@ -1276,7 +1300,7 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
BUG_ON(dma_pte_addr(*pte));
dma_set_pte_addr(*pte, start_pfn << VTD_PAGE_SHIFT);
dma_set_pte_prot(*pte, prot);
- __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ __iommu_flush_cache(iommu, pte, sizeof(*pte));
start_pfn++;
index++;
}
@@ -1285,10 +1309,12 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
static void detach_domain_for_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
{
- clear_context_table(domain->iommu, bus, devfn);
- domain->iommu->flush.flush_context(domain->iommu, 0, 0, 0,
+ struct intel_iommu *iommu = domain_get_iommu(domain);
+
+ clear_context_table(iommu, bus, devfn);
+ iommu->flush.flush_context(iommu, 0, 0, 0,
DMA_CCMD_GLOBAL_INVL, 0);
- domain->iommu->flush.flush_iotlb(domain->iommu, 0, 0, 0,
+ iommu->flush.flush_iotlb(iommu, 0, 0, 0,
DMA_TLB_GLOBAL_FLUSH, 0);
}
@@ -1827,6 +1853,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
struct iova *iova;
int prot = 0;
int ret;
+ struct intel_iommu *iommu;
BUG_ON(dir == DMA_NONE);
if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
@@ -1835,7 +1862,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
domain = get_valid_domain_for_dev(pdev);
if (!domain)
return 0;
-
+ iommu = domain_get_iommu(domain);
size = aligned_size((u64)paddr, size);
iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
@@ -1849,7 +1876,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
* mappings..
*/
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
- !cap_zlr(domain->iommu->cap))
+ !cap_zlr(iommu->cap))
prot |= DMA_PTE_READ;
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
prot |= DMA_PTE_WRITE;
@@ -1865,10 +1892,10 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
goto error;
/* it's a non-present to present mapping */
- ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
+ ret = iommu_flush_iotlb_psi(iommu, domain->id,
start_paddr, size >> VTD_PAGE_SHIFT, 1);
if (ret)
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
return start_paddr + ((u64)paddr & (~PAGE_MASK));
@@ -1897,7 +1924,7 @@ static void flush_unmaps(void)
for (i = 0; i < g_num_of_iommus; i++) {
if (deferred_flush[i].next) {
struct intel_iommu *iommu =
- deferred_flush[i].domain[0]->iommu;
+ deferred_flush[i].iommu;
iommu->flush.flush_iotlb(iommu, 0, 0, 0,
DMA_TLB_GLOBAL_FLUSH, 0);
@@ -1925,16 +1952,19 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
{
unsigned long flags;
int next, iommu_id;
+ struct intel_iommu *iommu;
spin_lock_irqsave(&async_umap_flush_lock, flags);
if (list_size == HIGH_WATER_MARK)
flush_unmaps();
- iommu_id = dom->iommu->seq_id;
+ iommu = domain_get_iommu(dom);
+ iommu_id = iommu->seq_id;
next = deferred_flush[iommu_id].next;
deferred_flush[iommu_id].domain[next] = dom;
deferred_flush[iommu_id].iova[next] = iova;
+ deferred_flush[iommu_id].iommu = iommu;
deferred_flush[iommu_id].next++;
if (!timer_on) {
@@ -1950,6 +1980,7 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dmar_domain *domain;
+ struct intel_iommu *iommu;
unsigned long start_addr;
struct iova *iova;
@@ -1958,6 +1989,8 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
domain = find_domain(pdev);
BUG_ON(!domain);
+ iommu = domain_get_iommu(domain);
+
iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
if (!iova)
return;
@@ -1973,9 +2006,9 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
/* free page tables */
dma_pte_free_pagetable(domain, start_addr, start_addr + size);
if (intel_iommu_strict) {
- if (iommu_flush_iotlb_psi(domain->iommu,
+ if (iommu_flush_iotlb_psi(iommu,
domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0))
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
/* free iova */
__free_iova(&domain->iovad, iova);
} else {
@@ -2031,6 +2064,7 @@ void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
+ struct intel_iommu *iommu;
unsigned long start_addr;
struct iova *iova;
size_t size = 0;
@@ -2045,6 +2079,9 @@ void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
if (!iova)
return;
+
+ iommu = domain_get_iommu(domain);
+
for_each_sg(sglist, sg, nelems, i) {
addr = SG_ENT_VIRT_ADDRESS(sg);
size += aligned_size((u64)addr, sg->length);
@@ -2057,9 +2094,9 @@ void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
/* free page tables */
dma_pte_free_pagetable(domain, start_addr, start_addr + size);
- if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
+ if (iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
size >> VTD_PAGE_SHIFT, 0))
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
/* free iova */
__free_iova(&domain->iovad, iova);
@@ -2086,6 +2123,7 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
+ struct intel_iommu *iommu;
size_t size = 0;
int prot = 0;
size_t offset = 0;
@@ -2102,6 +2140,8 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
if (!domain)
return 0;
+ iommu = domain_get_iommu(domain);
+
for_each_sg(sglist, sg, nelems, i) {
addr = SG_ENT_VIRT_ADDRESS(sg);
addr = (void *)virt_to_phys(addr);
@@ -2119,7 +2159,7 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
* mappings..
*/
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
- !cap_zlr(domain->iommu->cap))
+ !cap_zlr(iommu->cap))
prot |= DMA_PTE_READ;
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
prot |= DMA_PTE_WRITE;
@@ -2151,9 +2191,9 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
}
/* it's a non-present to present mapping */
- if (iommu_flush_iotlb_psi(domain->iommu, domain->id,
+ if (iommu_flush_iotlb_psi(iommu, domain->id,
start_addr, offset >> VTD_PAGE_SHIFT, 1))
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
return nelems;
}
diff --git a/include/linux/dma_remapping.h b/include/linux/dma_remapping.h
index 952df39..66f7887 100644
--- a/include/linux/dma_remapping.h
+++ b/include/linux/dma_remapping.h
@@ -115,7 +115,7 @@ struct intel_iommu;
struct dmar_domain {
int id; /* domain id */
- struct intel_iommu *iommu; /* back pointer to owning iommu */
+ unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
struct list_head devices; /* all devices' list */
struct iova_domain iovad; /* iova's that belong to this domain */
--
1.5.1
[-- Attachment #2: 0001-iommu-bitmap-insteads-of-iommu-pointer.patch --]
[-- Type: application/octet-stream, Size: 13555 bytes --]
From c029088744902dc57816ed8fdea86368efd03ed4 Mon Sep 17 00:00:00 2001
From: Weidong Han <weidong.han@intel.com>
Date: Tue, 2 Dec 2008 13:44:22 +0800
Subject: [PATCH] iommu bitmap insteads of iommu pointer in dmar_domain
Signed-off-by: Weidong Han <weidong.han@intel.com>
---
drivers/pci/intel-iommu.c | 102 ++++++++++++++++++++++++++++------------
include/linux/dma_remapping.h | 2 +-
2 files changed, 72 insertions(+), 32 deletions(-)
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 5c8baa4..39c5e9d 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -64,6 +64,7 @@ struct deferred_flush_tables {
int next;
struct iova *iova[HIGH_WATER_MARK];
struct dmar_domain *domain[HIGH_WATER_MARK];
+ struct intel_iommu *iommu;
};
static struct deferred_flush_tables *deferred_flush;
@@ -184,6 +185,21 @@ void free_iova_mem(struct iova *iova)
kmem_cache_free(iommu_iova_cache, iova);
}
+/* in native case, each domain is related to only one iommu */
+static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
+{
+ struct dmar_drhd_unit *drhd;
+
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+ if (test_bit(drhd->iommu->seq_id, &domain->iommu_bmp))
+ return drhd->iommu;
+ }
+
+ return NULL;
+}
+
/* Gets context entry for a given bus and devfn */
static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
u8 bus, u8 devfn)
@@ -324,6 +340,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
int level = agaw_to_level(domain->agaw);
int offset;
unsigned long flags;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
BUG_ON(!domain->pgd);
@@ -347,7 +364,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
flags);
return NULL;
}
- __iommu_flush_cache(domain->iommu, tmp_page,
+ __iommu_flush_cache(iommu, tmp_page,
PAGE_SIZE);
dma_set_pte_addr(*pte, virt_to_phys(tmp_page));
/*
@@ -356,7 +373,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
*/
dma_set_pte_readable(*pte);
dma_set_pte_writable(*pte);
- __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ __iommu_flush_cache(iommu, pte, sizeof(*pte));
}
parent = phys_to_virt(dma_pte_addr(*pte));
level--;
@@ -393,13 +410,14 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
{
struct dma_pte *pte = NULL;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
/* get last level pte */
pte = dma_addr_level_pte(domain, addr, 1);
if (pte) {
dma_clear_pte(*pte);
- __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ __iommu_flush_cache(iommu, pte, sizeof(*pte));
}
}
@@ -428,6 +446,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
int addr_width = agaw_to_width(domain->agaw);
struct dma_pte *pte;
int total = agaw_to_level(domain->agaw);
+ struct intel_iommu *iommu = domain_get_iommu(domain);
int level;
u64 tmp;
@@ -447,7 +466,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
free_pgtable_page(
phys_to_virt(dma_pte_addr(*pte)));
dma_clear_pte(*pte);
- __iommu_flush_cache(domain->iommu,
+ __iommu_flush_cache(iommu,
pte, sizeof(*pte));
}
tmp += level_size(level);
@@ -1006,7 +1025,8 @@ static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
set_bit(num, iommu->domain_ids);
domain->id = num;
- domain->iommu = iommu;
+ memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
+ set_bit(iommu->seq_id, &domain->iommu_bmp);
iommu->domains[num] = domain;
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -1016,10 +1036,12 @@ static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
static void iommu_free_domain(struct dmar_domain *domain)
{
unsigned long flags;
+ struct intel_iommu *iommu;
- spin_lock_irqsave(&domain->iommu->lock, flags);
- clear_bit(domain->id, domain->iommu->domain_ids);
- spin_unlock_irqrestore(&domain->iommu->lock, flags);
+ iommu = domain_get_iommu(domain);
+ spin_lock_irqsave(&iommu->lock, flags);
+ clear_bit(domain->id, iommu->domain_ids);
+ spin_unlock_irqrestore(&iommu->lock, flags);
}
static struct iova_domain reserved_iova_list;
@@ -1098,7 +1120,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
domain_reserve_special_ranges(domain);
/* calculate AGAW */
- iommu = domain->iommu;
+ iommu = domain_get_iommu(domain);
if (guest_width > cap_mgaw(iommu->cap))
guest_width = cap_mgaw(iommu->cap);
domain->gaw = guest_width;
@@ -1151,7 +1173,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
u8 bus, u8 devfn)
{
struct context_entry *context;
- struct intel_iommu *iommu = domain->iommu;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
unsigned long flags;
pr_debug("Set context mapping for %02x:%02x.%d\n",
@@ -1223,8 +1245,9 @@ static int domain_context_mapped(struct dmar_domain *domain,
{
int ret;
struct pci_dev *tmp, *parent;
+ struct intel_iommu *iommu = domain_get_iommu(domain);
- ret = device_context_mapped(domain->iommu,
+ ret = device_context_mapped(iommu,
pdev->bus->number, pdev->devfn);
if (!ret)
return ret;
@@ -1235,17 +1258,17 @@ static int domain_context_mapped(struct dmar_domain *domain,
/* Secondary interface's bus number and devfn 0 */
parent = pdev->bus->self;
while (parent != tmp) {
- ret = device_context_mapped(domain->iommu, parent->bus->number,
+ ret = device_context_mapped(iommu, parent->bus->number,
parent->devfn);
if (!ret)
return ret;
parent = parent->bus->self;
}
if (tmp->is_pcie)
- return device_context_mapped(domain->iommu,
+ return device_context_mapped(iommu,
tmp->subordinate->number, 0);
else
- return device_context_mapped(domain->iommu,
+ return device_context_mapped(iommu,
tmp->bus->number, tmp->devfn);
}
@@ -1257,6 +1280,7 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
struct dma_pte *pte;
int index;
int addr_width = agaw_to_width(domain->agaw);
+ struct intel_iommu *iommu = domain_get_iommu(domain);
hpa &= (((u64)1) << addr_width) - 1;
@@ -1276,7 +1300,7 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
BUG_ON(dma_pte_addr(*pte));
dma_set_pte_addr(*pte, start_pfn << VTD_PAGE_SHIFT);
dma_set_pte_prot(*pte, prot);
- __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ __iommu_flush_cache(iommu, pte, sizeof(*pte));
start_pfn++;
index++;
}
@@ -1285,10 +1309,12 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
static void detach_domain_for_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
{
- clear_context_table(domain->iommu, bus, devfn);
- domain->iommu->flush.flush_context(domain->iommu, 0, 0, 0,
+ struct intel_iommu *iommu = domain_get_iommu(domain);
+
+ clear_context_table(iommu, bus, devfn);
+ iommu->flush.flush_context(iommu, 0, 0, 0,
DMA_CCMD_GLOBAL_INVL, 0);
- domain->iommu->flush.flush_iotlb(domain->iommu, 0, 0, 0,
+ iommu->flush.flush_iotlb(iommu, 0, 0, 0,
DMA_TLB_GLOBAL_FLUSH, 0);
}
@@ -1827,6 +1853,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
struct iova *iova;
int prot = 0;
int ret;
+ struct intel_iommu *iommu;
BUG_ON(dir == DMA_NONE);
if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
@@ -1835,7 +1862,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
domain = get_valid_domain_for_dev(pdev);
if (!domain)
return 0;
-
+ iommu = domain_get_iommu(domain);
size = aligned_size((u64)paddr, size);
iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
@@ -1849,7 +1876,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
* mappings..
*/
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
- !cap_zlr(domain->iommu->cap))
+ !cap_zlr(iommu->cap))
prot |= DMA_PTE_READ;
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
prot |= DMA_PTE_WRITE;
@@ -1865,10 +1892,10 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
goto error;
/* it's a non-present to present mapping */
- ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
+ ret = iommu_flush_iotlb_psi(iommu, domain->id,
start_paddr, size >> VTD_PAGE_SHIFT, 1);
if (ret)
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
return start_paddr + ((u64)paddr & (~PAGE_MASK));
@@ -1897,7 +1924,7 @@ static void flush_unmaps(void)
for (i = 0; i < g_num_of_iommus; i++) {
if (deferred_flush[i].next) {
struct intel_iommu *iommu =
- deferred_flush[i].domain[0]->iommu;
+ deferred_flush[i].iommu;
iommu->flush.flush_iotlb(iommu, 0, 0, 0,
DMA_TLB_GLOBAL_FLUSH, 0);
@@ -1925,16 +1952,19 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
{
unsigned long flags;
int next, iommu_id;
+ struct intel_iommu *iommu;
spin_lock_irqsave(&async_umap_flush_lock, flags);
if (list_size == HIGH_WATER_MARK)
flush_unmaps();
- iommu_id = dom->iommu->seq_id;
+ iommu = domain_get_iommu(dom);
+ iommu_id = iommu->seq_id;
next = deferred_flush[iommu_id].next;
deferred_flush[iommu_id].domain[next] = dom;
deferred_flush[iommu_id].iova[next] = iova;
+ deferred_flush[iommu_id].iommu = iommu;
deferred_flush[iommu_id].next++;
if (!timer_on) {
@@ -1950,6 +1980,7 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dmar_domain *domain;
+ struct intel_iommu *iommu;
unsigned long start_addr;
struct iova *iova;
@@ -1958,6 +1989,8 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
domain = find_domain(pdev);
BUG_ON(!domain);
+ iommu = domain_get_iommu(domain);
+
iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
if (!iova)
return;
@@ -1973,9 +2006,9 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
/* free page tables */
dma_pte_free_pagetable(domain, start_addr, start_addr + size);
if (intel_iommu_strict) {
- if (iommu_flush_iotlb_psi(domain->iommu,
+ if (iommu_flush_iotlb_psi(iommu,
domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0))
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
/* free iova */
__free_iova(&domain->iovad, iova);
} else {
@@ -2031,6 +2064,7 @@ void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
+ struct intel_iommu *iommu;
unsigned long start_addr;
struct iova *iova;
size_t size = 0;
@@ -2045,6 +2079,9 @@ void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
if (!iova)
return;
+
+ iommu = domain_get_iommu(domain);
+
for_each_sg(sglist, sg, nelems, i) {
addr = SG_ENT_VIRT_ADDRESS(sg);
size += aligned_size((u64)addr, sg->length);
@@ -2057,9 +2094,9 @@ void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
/* free page tables */
dma_pte_free_pagetable(domain, start_addr, start_addr + size);
- if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
+ if (iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
size >> VTD_PAGE_SHIFT, 0))
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
/* free iova */
__free_iova(&domain->iovad, iova);
@@ -2086,6 +2123,7 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
+ struct intel_iommu *iommu;
size_t size = 0;
int prot = 0;
size_t offset = 0;
@@ -2102,6 +2140,8 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
if (!domain)
return 0;
+ iommu = domain_get_iommu(domain);
+
for_each_sg(sglist, sg, nelems, i) {
addr = SG_ENT_VIRT_ADDRESS(sg);
addr = (void *)virt_to_phys(addr);
@@ -2119,7 +2159,7 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
* mappings..
*/
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
- !cap_zlr(domain->iommu->cap))
+ !cap_zlr(iommu->cap))
prot |= DMA_PTE_READ;
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
prot |= DMA_PTE_WRITE;
@@ -2151,9 +2191,9 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
}
/* it's a non-present to present mapping */
- if (iommu_flush_iotlb_psi(domain->iommu, domain->id,
+ if (iommu_flush_iotlb_psi(iommu, domain->id,
start_addr, offset >> VTD_PAGE_SHIFT, 1))
- iommu_flush_write_buffer(domain->iommu);
+ iommu_flush_write_buffer(iommu);
return nelems;
}
diff --git a/include/linux/dma_remapping.h b/include/linux/dma_remapping.h
index 952df39..66f7887 100644
--- a/include/linux/dma_remapping.h
+++ b/include/linux/dma_remapping.h
@@ -115,7 +115,7 @@ struct intel_iommu;
struct dmar_domain {
int id; /* domain id */
- struct intel_iommu *iommu; /* back pointer to owning iommu */
+ unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
struct list_head devices; /* all devices' list */
struct iova_domain iovad; /* iova's that belong to this domain */
--
1.5.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 01/13] iommu bitmap insteads of iommu pointer in dmar_domain
2008-12-02 14:22 [PATCH 01/13] iommu bitmap insteads of iommu pointer in dmar_domain Han, Weidong
@ 2008-12-04 17:12 ` Mark McLoughlin
2008-12-05 0:52 ` Han, Weidong
2008-12-05 16:42 ` Avi Kivity
0 siblings, 2 replies; 4+ messages in thread
From: Mark McLoughlin @ 2008-12-04 17:12 UTC (permalink / raw)
To: Han, Weidong
Cc: 'Avi Kivity', Woodhouse, David, 'Jesse Barnes',
Yu, Fenghua, 'iommu@lists.linux-foundation.org',
'kvm@vger.kernel.org'
Hi Weidong,
On Tue, 2008-12-02 at 22:22 +0800, Han, Weidong wrote:
> Support dmar_domain own multiple devices from different iommus, which
> are set in iommu bitmap. add function domain_get_iommu() to get the
> only one iommu of domain in native VT-d usage.
A bitmap seems quite awkward. Why not a list?
Also, I wasn't sure at first what you meant by "native VT-d" ... you
mean DMA-API VT-d usage as opposed to KVM device assignment usage,
right? Perhaps we need a better term for that distinction.
> Signed-off-by: Weidong Han <weidong.han@intel.com>
> ---
> drivers/pci/intel-iommu.c | 102 ++++++++++++++++++++++++++++------------
> include/linux/dma_remapping.h | 2 +-
> 2 files changed, 72 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
> index 5c8baa4..39c5e9d 100644
> --- a/drivers/pci/intel-iommu.c
> +++ b/drivers/pci/intel-iommu.c
> @@ -184,6 +185,21 @@ void free_iova_mem(struct iova *iova)
> kmem_cache_free(iommu_iova_cache, iova);
> }
>
> +/* in native case, each domain is related to only one iommu */
> +static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
> +{
> + struct dmar_drhd_unit *drhd;
> +
> + for_each_drhd_unit(drhd) {
> + if (drhd->ignored)
> + continue;
> + if (test_bit(drhd->iommu->seq_id, &domain->iommu_bmp))
> + return drhd->iommu;
> + }
> +
> + return NULL;
> +}
So, basically, a lot of the code assumes that there is only one iommu
associated with a domain. That makes it seem like the abstractions here
could do with some re-working.
We should at least add:
ASSERT(!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE));
in the patch which adds that flag.
> @@ -1925,16 +1952,19 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
> {
> unsigned long flags;
> int next, iommu_id;
> + struct intel_iommu *iommu;
>
> spin_lock_irqsave(&async_umap_flush_lock, flags);
> if (list_size == HIGH_WATER_MARK)
> flush_unmaps();
>
> - iommu_id = dom->iommu->seq_id;
> + iommu = domain_get_iommu(dom);
> + iommu_id = iommu->seq_id;
>
> next = deferred_flush[iommu_id].next;
> deferred_flush[iommu_id].domain[next] = dom;
> deferred_flush[iommu_id].iova[next] = iova;
> + deferred_flush[iommu_id].iommu = iommu;
> deferred_flush[iommu_id].next++;
This deferred_flush->iommu change should be in it's own patch, IMHO.
Also, it's not quite right - there is a fixed mapping between iommu_id
and the iommu, so it makes no sense to update that mapping each time we
add a new iova.
In fact, it makes me wonder why we don't have the flush list in the
struct intel_iommu and have a global list of iommus.
Cheers,
Mark.
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [PATCH 01/13] iommu bitmap insteads of iommu pointer in dmar_domain
2008-12-04 17:12 ` Mark McLoughlin
@ 2008-12-05 0:52 ` Han, Weidong
2008-12-05 16:42 ` Avi Kivity
1 sibling, 0 replies; 4+ messages in thread
From: Han, Weidong @ 2008-12-05 0:52 UTC (permalink / raw)
To: 'Mark McLoughlin'
Cc: 'Avi Kivity', Woodhouse, David, 'Jesse Barnes',
Yu, Fenghua, 'iommu@lists.linux-foundation.org',
'kvm@vger.kernel.org'
Mark McLoughlin wrote:
> Hi Weidong,
>
> On Tue, 2008-12-02 at 22:22 +0800, Han, Weidong wrote:
>
>> Support dmar_domain own multiple devices from different iommus, which
>> are set in iommu bitmap. add function domain_get_iommu() to get the
>> only one iommu of domain in native VT-d usage.
>
> A bitmap seems quite awkward. Why not a list?
Yes, list may be direct. I will replace it.
>
> Also, I wasn't sure at first what you meant by "native VT-d" ... you
> mean DMA-API VT-d usage as opposed to KVM device assignment usage,
> right? Perhaps we need a better term for that distinction.
Yes. any proposal on the term?
>
>> Signed-off-by: Weidong Han <weidong.han@intel.com>
>> ---
>> drivers/pci/intel-iommu.c | 102
>> ++++++++++++++++++++++++++++------------
>> include/linux/dma_remapping.h | 2 +- 2 files changed, 72
>> insertions(+), 32 deletions(-)
>>
>> diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
>> index 5c8baa4..39c5e9d 100644
>> --- a/drivers/pci/intel-iommu.c
>> +++ b/drivers/pci/intel-iommu.c
>
>> @@ -184,6 +185,21 @@ void free_iova_mem(struct iova *iova)
>> kmem_cache_free(iommu_iova_cache, iova);
>> }
>>
>> +/* in native case, each domain is related to only one iommu */
>> +static struct intel_iommu *domain_get_iommu(struct dmar_domain
>> *domain) +{ + struct dmar_drhd_unit *drhd;
>> +
>> + for_each_drhd_unit(drhd) {
>> + if (drhd->ignored)
>> + continue;
>> + if (test_bit(drhd->iommu->seq_id, &domain->iommu_bmp)) + return
>> drhd->iommu; + }
>> +
>> + return NULL;
>> +}
>
> So, basically, a lot of the code assumes that there is only one iommu
> associated with a domain. That makes it seem like the abstractions
> here could do with some re-working.
>
> We should at least add:
>
> ASSERT(!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE));
>
> in the patch which adds that flag.
Okay, I will add ASSERT()s.
>
>> @@ -1925,16 +1952,19 @@ static void add_unmap(struct dmar_domain
>> *dom, struct iova *iova) { unsigned long flags;
>> int next, iommu_id;
>> + struct intel_iommu *iommu;
>>
>> spin_lock_irqsave(&async_umap_flush_lock, flags);
>> if (list_size == HIGH_WATER_MARK)
>> flush_unmaps();
>>
>> - iommu_id = dom->iommu->seq_id;
>> + iommu = domain_get_iommu(dom);
>> + iommu_id = iommu->seq_id;
>>
>> next = deferred_flush[iommu_id].next;
>> deferred_flush[iommu_id].domain[next] = dom;
>> deferred_flush[iommu_id].iova[next] = iova;
>> + deferred_flush[iommu_id].iommu = iommu;
>> deferred_flush[iommu_id].next++;
>
> This deferred_flush->iommu change should be in it's own patch, IMHO.
I will make a separate patch for it.
>
> Also, it's not quite right - there is a fixed mapping between iommu_id
> and the iommu, so it makes no sense to update that mapping each time
> we add a new iova.
>
> In fact, it makes me wonder why we don't have the flush list in the
> struct intel_iommu and have a global list of iommus.
I think a global list of iommus is useful. Because there is a fixed mapping between iommu_id and the iommu, iommu can be got directly from the global iommu list by iommu_id.
Regards,
Weidong
>
> Cheers,
> Mark.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 01/13] iommu bitmap insteads of iommu pointer in dmar_domain
2008-12-04 17:12 ` Mark McLoughlin
2008-12-05 0:52 ` Han, Weidong
@ 2008-12-05 16:42 ` Avi Kivity
1 sibling, 0 replies; 4+ messages in thread
From: Avi Kivity @ 2008-12-05 16:42 UTC (permalink / raw)
To: Mark McLoughlin
Cc: Han, Weidong, Woodhouse, David, 'Jesse Barnes',
Yu, Fenghua, 'iommu@lists.linux-foundation.org',
'kvm@vger.kernel.org'
Mark McLoughlin wrote:
> Also, I wasn't sure at first what you meant by "native VT-d" ... you
> mean DMA-API VT-d usage as opposed to KVM device assignment usage,
> right? Perhaps we need a better term for that distinction.
>
>
dma-api is request-oriented (the API is called to set up and tear down a
single dma request), while the kvm usage is address space oriented (the
API is called to set up, maintain, and tear down an address space, over
which many dma requests can run). Perhaps someone can come up with
names that reflect that.
--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-12-05 16:42 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-02 14:22 [PATCH 01/13] iommu bitmap insteads of iommu pointer in dmar_domain Han, Weidong
2008-12-04 17:12 ` Mark McLoughlin
2008-12-05 0:52 ` Han, Weidong
2008-12-05 16:42 ` Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).