* [PATCH 01/12] amd-iommu: introduce aperture_range structure
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 02/12] amd-iommu: move page table allocation code to seperate function Joerg Roedel
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: preperation for extended address allocator ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/amd_iommu_types.h | 32 +++++++++++++++-------
arch/x86/kernel/amd_iommu.c | 46 ++++++++++++++-----------------
2 files changed, 43 insertions(+), 35 deletions(-)
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index 95c8cd9..4c64c9b 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -195,6 +195,8 @@
#define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops
domain for an IOMMU */
+#define APERTURE_RANGE_SIZE (128 * 1024 * 1024)
+
/*
* This structure contains generic data for IOMMU protection domains
* independent of their use.
@@ -210,6 +212,24 @@ struct protection_domain {
};
/*
+ * For dynamic growth the aperture size is split into ranges of 128MB of
+ * DMA address space each. This struct represents one such range.
+ */
+struct aperture_range {
+
+ /* address allocation bitmap */
+ unsigned long *bitmap;
+
+ /*
+ * Array of PTE pages for the aperture. In this array we save all the
+ * leaf pages of the domain page table used for the aperture. This way
+ * we don't need to walk the page table to find a specific PTE. We can
+ * just calculate its address in constant time.
+ */
+ u64 *pte_pages[64];
+};
+
+/*
* Data container for a dma_ops specific protection domain
*/
struct dma_ops_domain {
@@ -224,16 +244,8 @@ struct dma_ops_domain {
/* address we start to search for free addresses */
unsigned long next_bit;
- /* address allocation bitmap */
- unsigned long *bitmap;
-
- /*
- * Array of PTE pages for the aperture. In this array we save all the
- * leaf pages of the domain page table used for the aperture. This way
- * we don't need to walk the page table to find a specific PTE. We can
- * just calculate its address in constant time.
- */
- u64 **pte_pages;
+ /* address space relevant data */
+ struct aperture_range aperture;
/* This will be set to true when TLB needs to be flushed */
bool need_flush;
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index a97db99..62acd09 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -595,7 +595,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
* as allocated in the aperture
*/
if (addr < dma_dom->aperture_size)
- __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap);
+ __set_bit(addr >> PAGE_SHIFT,
+ dma_dom->aperture.bitmap);
}
return 0;
@@ -656,11 +657,12 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev,
dom->need_flush = true;
}
- address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
- 0 , boundary_size, align_mask);
+ address = iommu_area_alloc(dom->aperture.bitmap, limit, dom->next_bit,
+ pages, 0 , boundary_size, align_mask);
if (address == -1) {
- address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
- 0, boundary_size, align_mask);
+ address = iommu_area_alloc(dom->aperture.bitmap, limit, 0,
+ pages, 0, boundary_size,
+ align_mask);
dom->need_flush = true;
}
@@ -685,7 +687,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
unsigned int pages)
{
address >>= PAGE_SHIFT;
- iommu_area_free(dom->bitmap, address, pages);
+ iommu_area_free(dom->aperture.bitmap, address, pages);
if (address >= dom->next_bit)
dom->need_flush = true;
@@ -741,7 +743,7 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
if (start_page + pages > last_page)
pages = last_page - start_page;
- iommu_area_reserve(dom->bitmap, start_page, pages);
+ iommu_area_reserve(dom->aperture.bitmap, start_page, pages);
}
static void free_pagetable(struct protection_domain *domain)
@@ -785,9 +787,7 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
free_pagetable(&dom->domain);
- kfree(dom->pte_pages);
-
- kfree(dom->bitmap);
+ free_page((unsigned long)dom->aperture.bitmap);
kfree(dom);
}
@@ -826,16 +826,15 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->domain.priv = dma_dom;
if (!dma_dom->domain.pt_root)
goto free_dma_dom;
- dma_dom->aperture_size = (1ULL << order);
- dma_dom->bitmap = kzalloc(dma_dom->aperture_size / (PAGE_SIZE * 8),
- GFP_KERNEL);
- if (!dma_dom->bitmap)
+ dma_dom->aperture_size = APERTURE_RANGE_SIZE;
+ dma_dom->aperture.bitmap = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!dma_dom->aperture.bitmap)
goto free_dma_dom;
/*
* mark the first page as allocated so we never return 0 as
* a valid dma-address. So we can use 0 as error value
*/
- dma_dom->bitmap[0] = 1;
+ dma_dom->aperture.bitmap[0] = 1;
dma_dom->next_bit = 0;
dma_dom->need_flush = false;
@@ -854,13 +853,9 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
/*
* At the last step, build the page tables so we don't need to
* allocate page table pages in the dma_ops mapping/unmapping
- * path.
+ * path for the first 128MB of dma address space.
*/
num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512);
- dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *),
- GFP_KERNEL);
- if (!dma_dom->pte_pages)
- goto free_dma_dom;
l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL);
if (l2_pde == NULL)
@@ -869,10 +864,11 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
for (i = 0; i < num_pte_pages; ++i) {
- dma_dom->pte_pages[i] = (u64 *)get_zeroed_page(GFP_KERNEL);
- if (!dma_dom->pte_pages[i])
+ u64 **pte_page = &dma_dom->aperture.pte_pages[i];
+ *pte_page = (u64 *)get_zeroed_page(GFP_KERNEL);
+ if (!*pte_page)
goto free_dma_dom;
- address = virt_to_phys(dma_dom->pte_pages[i]);
+ address = virt_to_phys(*pte_page);
l2_pde[i] = IOMMU_L1_PDE(address);
}
@@ -1159,7 +1155,7 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
paddr &= PAGE_MASK;
- pte = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+ pte = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
pte += IOMMU_PTE_L0_INDEX(address);
__pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
@@ -1192,7 +1188,7 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu,
WARN_ON(address & ~PAGE_MASK || address >= dom->aperture_size);
- pte = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+ pte = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
pte += IOMMU_PTE_L0_INDEX(address);
WARN_ON(!*pte);
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 02/12] amd-iommu: move page table allocation code to seperate function
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
2009-05-22 12:21 ` [PATCH 01/12] amd-iommu: introduce aperture_range structure Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 03/12] amd-iommu: handle page table allocation failures in dma_ops code Joerg Roedel
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: make page table allocation usable for dma_ops code ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 86 ++++++++++++++++++++++++++++++------------
1 files changed, 61 insertions(+), 25 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 62acd09..ded79f7 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -55,7 +55,9 @@ struct iommu_cmd {
static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
struct unity_map_entry *e);
static struct dma_ops_domain *find_protection_domain(u16 devid);
-
+static u64* alloc_pte(struct protection_domain *dom,
+ unsigned long address, u64
+ **pte_page, gfp_t gfp);
#ifdef CONFIG_AMD_IOMMU_STATS
@@ -468,7 +470,7 @@ static int iommu_map_page(struct protection_domain *dom,
unsigned long phys_addr,
int prot)
{
- u64 __pte, *pte, *page;
+ u64 __pte, *pte;
bus_addr = PAGE_ALIGN(bus_addr);
phys_addr = PAGE_ALIGN(phys_addr);
@@ -477,27 +479,7 @@ static int iommu_map_page(struct protection_domain *dom,
if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK))
return -EINVAL;
- pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)];
-
- if (!IOMMU_PTE_PRESENT(*pte)) {
- page = (u64 *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- *pte = IOMMU_L2_PDE(virt_to_phys(page));
- }
-
- pte = IOMMU_PTE_PAGE(*pte);
- pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)];
-
- if (!IOMMU_PTE_PRESENT(*pte)) {
- page = (u64 *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- *pte = IOMMU_L1_PDE(virt_to_phys(page));
- }
-
- pte = IOMMU_PTE_PAGE(*pte);
- pte = &pte[IOMMU_PTE_L0_INDEX(bus_addr)];
+ pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL);
if (IOMMU_PTE_PRESENT(*pte))
return -EBUSY;
@@ -1140,6 +1122,61 @@ static int get_device_resources(struct device *dev,
}
/*
+ * If the pte_page is not yet allocated this function is called
+ */
+static u64* alloc_pte(struct protection_domain *dom,
+ unsigned long address, u64 **pte_page, gfp_t gfp)
+{
+ u64 *pte, *page;
+
+ pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+ if (!IOMMU_PTE_PRESENT(*pte)) {
+ page = (u64 *)get_zeroed_page(gfp);
+ if (!page)
+ return NULL;
+ *pte = IOMMU_L2_PDE(virt_to_phys(page));
+ }
+
+ pte = IOMMU_PTE_PAGE(*pte);
+ pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+ if (!IOMMU_PTE_PRESENT(*pte)) {
+ page = (u64 *)get_zeroed_page(gfp);
+ if (!page)
+ return NULL;
+ *pte = IOMMU_L1_PDE(virt_to_phys(page));
+ }
+
+ pte = IOMMU_PTE_PAGE(*pte);
+
+ if (pte_page)
+ *pte_page = pte;
+
+ pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+ return pte;
+}
+
+/*
+ * This function fetches the PTE for a given address in the aperture
+ */
+static u64* dma_ops_get_pte(struct dma_ops_domain *dom,
+ unsigned long address)
+{
+ struct aperture_range *aperture = &dom->aperture;
+ u64 *pte, *pte_page;
+
+ pte = aperture->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+ if (!pte) {
+ pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC);
+ aperture->pte_pages[IOMMU_PTE_L1_INDEX(address)] = pte_page;
+ }
+
+ return pte;
+}
+
+/*
* This is the generic map function. It maps one 4kb page at paddr to
* the given address in the DMA address space for the domain.
*/
@@ -1155,8 +1192,7 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
paddr &= PAGE_MASK;
- pte = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
- pte += IOMMU_PTE_L0_INDEX(address);
+ pte = dma_ops_get_pte(dom, address);
__pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 03/12] amd-iommu: handle page table allocation failures in dma_ops code
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
2009-05-22 12:21 ` [PATCH 01/12] amd-iommu: introduce aperture_range structure Joerg Roedel
2009-05-22 12:21 ` [PATCH 02/12] amd-iommu: move page table allocation code to seperate function Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 04/12] amd-iommu: make address allocator aware of multiple aperture ranges Joerg Roedel
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: preperation for extended address allocator ]
The code will be required when the aperture size increases dynamically.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 20 ++++++++++++++++++--
1 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index ded79f7..a467add 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1193,6 +1193,8 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
paddr &= PAGE_MASK;
pte = dma_ops_get_pte(dom, address);
+ if (!pte)
+ return bad_dma_address;
__pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
@@ -1248,7 +1250,7 @@ static dma_addr_t __map_single(struct device *dev,
u64 dma_mask)
{
dma_addr_t offset = paddr & ~PAGE_MASK;
- dma_addr_t address, start;
+ dma_addr_t address, start, ret;
unsigned int pages;
unsigned long align_mask = 0;
int i;
@@ -1271,7 +1273,10 @@ static dma_addr_t __map_single(struct device *dev,
start = address;
for (i = 0; i < pages; ++i) {
- dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+ ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+ if (ret == bad_dma_address)
+ goto out_unmap;
+
paddr += PAGE_SIZE;
start += PAGE_SIZE;
}
@@ -1287,6 +1292,17 @@ static dma_addr_t __map_single(struct device *dev,
out:
return address;
+
+out_unmap:
+
+ for (--i; i >= 0; --i) {
+ start -= PAGE_SIZE;
+ dma_ops_domain_unmap(iommu, dma_dom, start);
+ }
+
+ dma_ops_free_addresses(dma_dom, address, pages);
+
+ return bad_dma_address;
}
/*
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 04/12] amd-iommu: make address allocator aware of multiple aperture ranges
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (2 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 03/12] amd-iommu: handle page table allocation failures in dma_ops code Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 05/12] amd-iommu: change dma_dom->next_bit to dma_dom->next_address Joerg Roedel
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: prepare to increase maximum aperture size to 4GB ]
This patch changes the AMD IOMMU address allocator to allow up to 32
aperture ranges per dma_ops domain.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/amd_iommu_types.h | 11 ++-
arch/x86/kernel/amd_iommu.c | 138 +++++++++++++++++++++++---------
2 files changed, 110 insertions(+), 39 deletions(-)
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index 4c64c9b..eca9129 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -195,7 +195,12 @@
#define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops
domain for an IOMMU */
-#define APERTURE_RANGE_SIZE (128 * 1024 * 1024)
+#define APERTURE_RANGE_SHIFT 27 /* 128 MB */
+#define APERTURE_RANGE_SIZE (1ULL << APERTURE_RANGE_SHIFT)
+#define APERTURE_RANGE_PAGES (APERTURE_RANGE_SIZE >> PAGE_SHIFT)
+#define APERTURE_MAX_RANGES 32 /* allows 4GB of DMA address space */
+#define APERTURE_RANGE_INDEX(a) ((a) >> APERTURE_RANGE_SHIFT)
+#define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL)
/*
* This structure contains generic data for IOMMU protection domains
@@ -227,6 +232,8 @@ struct aperture_range {
* just calculate its address in constant time.
*/
u64 *pte_pages[64];
+
+ unsigned long offset;
};
/*
@@ -245,7 +252,7 @@ struct dma_ops_domain {
unsigned long next_bit;
/* address space relevant data */
- struct aperture_range aperture;
+ struct aperture_range *aperture[APERTURE_MAX_RANGES];
/* This will be set to true when TLB needs to be flushed */
bool need_flush;
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index a467add..794163a 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -578,7 +578,7 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
*/
if (addr < dma_dom->aperture_size)
__set_bit(addr >> PAGE_SHIFT,
- dma_dom->aperture.bitmap);
+ dma_dom->aperture[0]->bitmap);
}
return 0;
@@ -615,43 +615,74 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom,
****************************************************************************/
/*
- * The address allocator core function.
+ * The address allocator core functions.
*
* called with domain->lock held
*/
+
+static unsigned long dma_ops_area_alloc(struct device *dev,
+ struct dma_ops_domain *dom,
+ unsigned int pages,
+ unsigned long align_mask,
+ u64 dma_mask,
+ unsigned long start)
+{
+ unsigned long next_bit = dom->next_bit % APERTURE_RANGE_PAGES;
+ int max_index = dom->aperture_size >> APERTURE_RANGE_SHIFT;
+ int i = start >> APERTURE_RANGE_SHIFT;
+ unsigned long boundary_size;
+ unsigned long address = -1;
+ unsigned long limit;
+
+ boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+ PAGE_SIZE) >> PAGE_SHIFT;
+
+ for (;i < max_index; ++i) {
+ unsigned long offset = dom->aperture[i]->offset >> PAGE_SHIFT;
+
+ if (dom->aperture[i]->offset >= dma_mask)
+ break;
+
+ limit = iommu_device_max_index(APERTURE_RANGE_PAGES, offset,
+ dma_mask >> PAGE_SHIFT);
+
+ address = iommu_area_alloc(dom->aperture[i]->bitmap,
+ limit, next_bit, pages, 0,
+ boundary_size, align_mask);
+ if (address != -1) {
+ address = dom->aperture[i]->offset +
+ (address << PAGE_SHIFT);
+ dom->next_bit = (address >> PAGE_SHIFT) + pages;
+ break;
+ }
+
+ next_bit = 0;
+ }
+
+ return address;
+}
+
static unsigned long dma_ops_alloc_addresses(struct device *dev,
struct dma_ops_domain *dom,
unsigned int pages,
unsigned long align_mask,
u64 dma_mask)
{
- unsigned long limit;
unsigned long address;
- unsigned long boundary_size;
+ unsigned long start = dom->next_bit << PAGE_SHIFT;
- boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
- PAGE_SIZE) >> PAGE_SHIFT;
- limit = iommu_device_max_index(dom->aperture_size >> PAGE_SHIFT, 0,
- dma_mask >> PAGE_SHIFT);
- if (dom->next_bit >= limit) {
- dom->next_bit = 0;
- dom->need_flush = true;
- }
+ address = dma_ops_area_alloc(dev, dom, pages, align_mask,
+ dma_mask, start);
- address = iommu_area_alloc(dom->aperture.bitmap, limit, dom->next_bit,
- pages, 0 , boundary_size, align_mask);
if (address == -1) {
- address = iommu_area_alloc(dom->aperture.bitmap, limit, 0,
- pages, 0, boundary_size,
- align_mask);
+ dom->next_bit = 0;
+ address = dma_ops_area_alloc(dev, dom, pages, align_mask,
+ dma_mask, 0);
dom->need_flush = true;
}
- if (likely(address != -1)) {
- dom->next_bit = address + pages;
- address <<= PAGE_SHIFT;
- } else
+ if (unlikely(address == -1))
address = bad_dma_address;
WARN_ON((address + (PAGE_SIZE*pages)) > dom->aperture_size);
@@ -668,11 +699,17 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
unsigned long address,
unsigned int pages)
{
- address >>= PAGE_SHIFT;
- iommu_area_free(dom->aperture.bitmap, address, pages);
+ unsigned i = address >> APERTURE_RANGE_SHIFT;
+ struct aperture_range *range = dom->aperture[i];
+
+ BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL);
- if (address >= dom->next_bit)
+ if ((address >> PAGE_SHIFT) >= dom->next_bit)
dom->need_flush = true;
+
+ address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
+ iommu_area_free(range->bitmap, address, pages);
+
}
/****************************************************************************
@@ -720,12 +757,16 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
unsigned long start_page,
unsigned int pages)
{
- unsigned int last_page = dom->aperture_size >> PAGE_SHIFT;
+ unsigned int i, last_page = dom->aperture_size >> PAGE_SHIFT;
if (start_page + pages > last_page)
pages = last_page - start_page;
- iommu_area_reserve(dom->aperture.bitmap, start_page, pages);
+ for (i = start_page; i < start_page + pages; ++i) {
+ int index = i / APERTURE_RANGE_PAGES;
+ int page = i % APERTURE_RANGE_PAGES;
+ __set_bit(page, dom->aperture[index]->bitmap);
+ }
}
static void free_pagetable(struct protection_domain *domain)
@@ -764,12 +805,19 @@ static void free_pagetable(struct protection_domain *domain)
*/
static void dma_ops_domain_free(struct dma_ops_domain *dom)
{
+ int i;
+
if (!dom)
return;
free_pagetable(&dom->domain);
- free_page((unsigned long)dom->aperture.bitmap);
+ for (i = 0; i < APERTURE_MAX_RANGES; ++i) {
+ if (!dom->aperture[i])
+ continue;
+ free_page((unsigned long)dom->aperture[i]->bitmap);
+ kfree(dom->aperture[i]);
+ }
kfree(dom);
}
@@ -797,6 +845,11 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
if (!dma_dom)
return NULL;
+ dma_dom->aperture[0] = kzalloc(sizeof(struct aperture_range),
+ GFP_KERNEL);
+ if (!dma_dom->aperture[0])
+ goto free_dma_dom;
+
spin_lock_init(&dma_dom->domain.lock);
dma_dom->domain.id = domain_id_alloc();
@@ -809,14 +862,14 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
if (!dma_dom->domain.pt_root)
goto free_dma_dom;
dma_dom->aperture_size = APERTURE_RANGE_SIZE;
- dma_dom->aperture.bitmap = (void *)get_zeroed_page(GFP_KERNEL);
- if (!dma_dom->aperture.bitmap)
+ dma_dom->aperture[0]->bitmap = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!dma_dom->aperture[0]->bitmap)
goto free_dma_dom;
/*
* mark the first page as allocated so we never return 0 as
* a valid dma-address. So we can use 0 as error value
*/
- dma_dom->aperture.bitmap[0] = 1;
+ dma_dom->aperture[0]->bitmap[0] = 1;
dma_dom->next_bit = 0;
dma_dom->need_flush = false;
@@ -846,7 +899,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
for (i = 0; i < num_pte_pages; ++i) {
- u64 **pte_page = &dma_dom->aperture.pte_pages[i];
+ u64 **pte_page = &dma_dom->aperture[0]->pte_pages[i];
*pte_page = (u64 *)get_zeroed_page(GFP_KERNEL);
if (!*pte_page)
goto free_dma_dom;
@@ -1164,14 +1217,19 @@ static u64* alloc_pte(struct protection_domain *dom,
static u64* dma_ops_get_pte(struct dma_ops_domain *dom,
unsigned long address)
{
- struct aperture_range *aperture = &dom->aperture;
+ struct aperture_range *aperture;
u64 *pte, *pte_page;
- pte = aperture->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+ aperture = dom->aperture[APERTURE_RANGE_INDEX(address)];
+ if (!aperture)
+ return NULL;
+
+ pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)];
if (!pte) {
pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC);
- aperture->pte_pages[IOMMU_PTE_L1_INDEX(address)] = pte_page;
- }
+ aperture->pte_pages[APERTURE_PAGE_INDEX(address)] = pte_page;
+ } else
+ pte += IOMMU_PTE_L0_INDEX(address);
return pte;
}
@@ -1219,14 +1277,20 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu,
struct dma_ops_domain *dom,
unsigned long address)
{
+ struct aperture_range *aperture;
u64 *pte;
if (address >= dom->aperture_size)
return;
- WARN_ON(address & ~PAGE_MASK || address >= dom->aperture_size);
+ aperture = dom->aperture[APERTURE_RANGE_INDEX(address)];
+ if (!aperture)
+ return;
+
+ pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)];
+ if (!pte)
+ return;
- pte = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
pte += IOMMU_PTE_L0_INDEX(address);
WARN_ON(!*pte);
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 05/12] amd-iommu: change dma_dom->next_bit to dma_dom->next_address
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (3 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 04/12] amd-iommu: make address allocator aware of multiple aperture ranges Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 06/12] amd-iommu: move aperture_range allocation code to seperate function Joerg Roedel
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: code simplification ]
Simplify the code a little bit by using the same unit for all address
space related state in the dma_ops domain structure.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/amd_iommu_types.h | 2 +-
arch/x86/kernel/amd_iommu.c | 17 +++++++++--------
2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index eca9129..4ff4cf1 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -249,7 +249,7 @@ struct dma_ops_domain {
unsigned long aperture_size;
/* address we start to search for free addresses */
- unsigned long next_bit;
+ unsigned long next_address;
/* address space relevant data */
struct aperture_range *aperture[APERTURE_MAX_RANGES];
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 794163a..c1a08b9 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -627,13 +627,15 @@ static unsigned long dma_ops_area_alloc(struct device *dev,
u64 dma_mask,
unsigned long start)
{
- unsigned long next_bit = dom->next_bit % APERTURE_RANGE_PAGES;
+ unsigned long next_bit = dom->next_address % APERTURE_RANGE_SIZE;
int max_index = dom->aperture_size >> APERTURE_RANGE_SHIFT;
int i = start >> APERTURE_RANGE_SHIFT;
unsigned long boundary_size;
unsigned long address = -1;
unsigned long limit;
+ next_bit >>= PAGE_SHIFT;
+
boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
PAGE_SIZE) >> PAGE_SHIFT;
@@ -652,7 +654,7 @@ static unsigned long dma_ops_area_alloc(struct device *dev,
if (address != -1) {
address = dom->aperture[i]->offset +
(address << PAGE_SHIFT);
- dom->next_bit = (address >> PAGE_SHIFT) + pages;
+ dom->next_address = address + (pages << PAGE_SHIFT);
break;
}
@@ -669,14 +671,12 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev,
u64 dma_mask)
{
unsigned long address;
- unsigned long start = dom->next_bit << PAGE_SHIFT;
-
address = dma_ops_area_alloc(dev, dom, pages, align_mask,
- dma_mask, start);
+ dma_mask, dom->next_address);
if (address == -1) {
- dom->next_bit = 0;
+ dom->next_address = 0;
address = dma_ops_area_alloc(dev, dom, pages, align_mask,
dma_mask, 0);
dom->need_flush = true;
@@ -704,10 +704,11 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL);
- if ((address >> PAGE_SHIFT) >= dom->next_bit)
+ if (address >= dom->next_address)
dom->need_flush = true;
address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
+
iommu_area_free(range->bitmap, address, pages);
}
@@ -870,7 +871,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
* a valid dma-address. So we can use 0 as error value
*/
dma_dom->aperture[0]->bitmap[0] = 1;
- dma_dom->next_bit = 0;
+ dma_dom->next_address = 0;
dma_dom->need_flush = false;
dma_dom->target_dev = 0xffff;
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 06/12] amd-iommu: move aperture_range allocation code to seperate function
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (4 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 05/12] amd-iommu: change dma_dom->next_bit to dma_dom->next_address Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 07/12] amd-iommu: handle exlusion ranges and unity mappings in alloc_new_range Joerg Roedel
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: prepare dynamic increasement of apertures ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 95 ++++++++++++++++++++++++++----------------
1 files changed, 59 insertions(+), 36 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index c1a08b9..8ff02ee 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -620,6 +620,59 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom,
* called with domain->lock held
*/
+/*
+ * This function is used to add a new aperture range to an existing
+ * aperture in case of dma_ops domain allocation or address allocation
+ * failure.
+ */
+static int alloc_new_range(struct dma_ops_domain *dma_dom,
+ bool populate, gfp_t gfp)
+{
+ int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
+
+ if (index >= APERTURE_MAX_RANGES)
+ return -ENOMEM;
+
+ dma_dom->aperture[index] = kzalloc(sizeof(struct aperture_range), gfp);
+ if (!dma_dom->aperture[index])
+ return -ENOMEM;
+
+ dma_dom->aperture[index]->bitmap = (void *)get_zeroed_page(gfp);
+ if (!dma_dom->aperture[index]->bitmap)
+ goto out_free;
+
+ dma_dom->aperture[index]->offset = dma_dom->aperture_size;
+
+ if (populate) {
+ unsigned long address = dma_dom->aperture_size;
+ int i, num_ptes = APERTURE_RANGE_PAGES / 512;
+ u64 *pte, *pte_page;
+
+ for (i = 0; i < num_ptes; ++i) {
+ pte = alloc_pte(&dma_dom->domain, address,
+ &pte_page, gfp);
+ if (!pte)
+ goto out_free;
+
+ dma_dom->aperture[index]->pte_pages[i] = pte_page;
+
+ address += APERTURE_RANGE_SIZE / 64;
+ }
+ }
+
+ dma_dom->aperture_size += APERTURE_RANGE_SIZE;
+
+ return 0;
+
+out_free:
+ free_page((unsigned long)dma_dom->aperture[index]->bitmap);
+
+ kfree(dma_dom->aperture[index]);
+ dma_dom->aperture[index] = NULL;
+
+ return -ENOMEM;
+}
+
static unsigned long dma_ops_area_alloc(struct device *dev,
struct dma_ops_domain *dom,
unsigned int pages,
@@ -832,9 +885,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
unsigned order)
{
struct dma_ops_domain *dma_dom;
- unsigned i, num_pte_pages;
- u64 *l2_pde;
- u64 address;
/*
* Currently the DMA aperture must be between 32 MB and 1GB in size
@@ -846,11 +896,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
if (!dma_dom)
return NULL;
- dma_dom->aperture[0] = kzalloc(sizeof(struct aperture_range),
- GFP_KERNEL);
- if (!dma_dom->aperture[0])
- goto free_dma_dom;
-
spin_lock_init(&dma_dom->domain.lock);
dma_dom->domain.id = domain_id_alloc();
@@ -862,10 +907,13 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->domain.priv = dma_dom;
if (!dma_dom->domain.pt_root)
goto free_dma_dom;
- dma_dom->aperture_size = APERTURE_RANGE_SIZE;
- dma_dom->aperture[0]->bitmap = (void *)get_zeroed_page(GFP_KERNEL);
- if (!dma_dom->aperture[0]->bitmap)
+
+ dma_dom->need_flush = false;
+ dma_dom->target_dev = 0xffff;
+
+ if (alloc_new_range(dma_dom, true, GFP_KERNEL))
goto free_dma_dom;
+
/*
* mark the first page as allocated so we never return 0 as
* a valid dma-address. So we can use 0 as error value
@@ -873,9 +921,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->aperture[0]->bitmap[0] = 1;
dma_dom->next_address = 0;
- dma_dom->need_flush = false;
- dma_dom->target_dev = 0xffff;
-
/* Intialize the exclusion range if necessary */
if (iommu->exclusion_start &&
iommu->exclusion_start < dma_dom->aperture_size) {
@@ -886,28 +931,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_ops_reserve_addresses(dma_dom, startpage, pages);
}
- /*
- * At the last step, build the page tables so we don't need to
- * allocate page table pages in the dma_ops mapping/unmapping
- * path for the first 128MB of dma address space.
- */
- num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512);
-
- l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL);
- if (l2_pde == NULL)
- goto free_dma_dom;
-
- dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
-
- for (i = 0; i < num_pte_pages; ++i) {
- u64 **pte_page = &dma_dom->aperture[0]->pte_pages[i];
- *pte_page = (u64 *)get_zeroed_page(GFP_KERNEL);
- if (!*pte_page)
- goto free_dma_dom;
- address = virt_to_phys(*pte_page);
- l2_pde[i] = IOMMU_L1_PDE(address);
- }
-
return dma_dom;
free_dma_dom:
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 07/12] amd-iommu: handle exlusion ranges and unity mappings in alloc_new_range
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (5 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 06/12] amd-iommu: move aperture_range allocation code to seperate function Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 08/12] amd-iommu: enlarge the aperture dynamically Joerg Roedel
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: make sure no reserved addresses are allocated ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 71 ++++++++++++++++++++++++++++++++++++-------
1 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 8ff02ee..59ee1b9 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -58,6 +58,9 @@ static struct dma_ops_domain *find_protection_domain(u16 devid);
static u64* alloc_pte(struct protection_domain *dom,
unsigned long address, u64
**pte_page, gfp_t gfp);
+static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
+ unsigned long start_page,
+ unsigned int pages);
#ifdef CONFIG_AMD_IOMMU_STATS
@@ -621,14 +624,42 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom,
*/
/*
+ * This function checks if there is a PTE for a given dma address. If
+ * there is one, it returns the pointer to it.
+ */
+static u64* fetch_pte(struct protection_domain *domain,
+ unsigned long address)
+{
+ u64 *pte;
+
+ pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+ if (!IOMMU_PTE_PRESENT(*pte))
+ return NULL;
+
+ pte = IOMMU_PTE_PAGE(*pte);
+ pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+ if (!IOMMU_PTE_PRESENT(*pte))
+ return NULL;
+
+ pte = IOMMU_PTE_PAGE(*pte);
+ pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+ return pte;
+}
+
+/*
* This function is used to add a new aperture range to an existing
* aperture in case of dma_ops domain allocation or address allocation
* failure.
*/
-static int alloc_new_range(struct dma_ops_domain *dma_dom,
+static int alloc_new_range(struct amd_iommu *iommu,
+ struct dma_ops_domain *dma_dom,
bool populate, gfp_t gfp)
{
int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
+ int i;
if (index >= APERTURE_MAX_RANGES)
return -ENOMEM;
@@ -662,6 +693,33 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
dma_dom->aperture_size += APERTURE_RANGE_SIZE;
+ /* Intialize the exclusion range if necessary */
+ if (iommu->exclusion_start &&
+ iommu->exclusion_start >= dma_dom->aperture[index]->offset &&
+ iommu->exclusion_start < dma_dom->aperture_size) {
+ unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
+ int pages = iommu_num_pages(iommu->exclusion_start,
+ iommu->exclusion_length,
+ PAGE_SIZE);
+ dma_ops_reserve_addresses(dma_dom, startpage, pages);
+ }
+
+ /*
+ * Check for areas already mapped as present in the new aperture
+ * range and mark those pages as reserved in the allocator. Such
+ * mappings may already exist as a result of requested unity
+ * mappings for devices.
+ */
+ for (i = dma_dom->aperture[index]->offset;
+ i < dma_dom->aperture_size;
+ i += PAGE_SIZE) {
+ u64 *pte = fetch_pte(&dma_dom->domain, i);
+ if (!pte || !IOMMU_PTE_PRESENT(*pte))
+ continue;
+
+ dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
+ }
+
return 0;
out_free:
@@ -911,7 +969,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->need_flush = false;
dma_dom->target_dev = 0xffff;
- if (alloc_new_range(dma_dom, true, GFP_KERNEL))
+ if (alloc_new_range(iommu, dma_dom, true, GFP_KERNEL))
goto free_dma_dom;
/*
@@ -921,15 +979,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
dma_dom->aperture[0]->bitmap[0] = 1;
dma_dom->next_address = 0;
- /* Intialize the exclusion range if necessary */
- if (iommu->exclusion_start &&
- iommu->exclusion_start < dma_dom->aperture_size) {
- unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
- int pages = iommu_num_pages(iommu->exclusion_start,
- iommu->exclusion_length,
- PAGE_SIZE);
- dma_ops_reserve_addresses(dma_dom, startpage, pages);
- }
return dma_dom;
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 08/12] amd-iommu: enlarge the aperture dynamically
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (6 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 07/12] amd-iommu: handle exlusion ranges and unity mappings in alloc_new_range Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 09/12] amd-iommu: remove amd_iommu_size kernel parameter Joerg Roedel
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: enable the new extended dma address allocator ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 20 ++++++++++++++++++--
1 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 59ee1b9..d129d8f 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1403,10 +1403,26 @@ static dma_addr_t __map_single(struct device *dev,
if (align)
align_mask = (1UL << get_order(size)) - 1;
+retry:
address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask,
dma_mask);
- if (unlikely(address == bad_dma_address))
- goto out;
+ if (unlikely(address == bad_dma_address)) {
+ /*
+ * setting next_address here will let the address
+ * allocator only scan the new allocated range in the
+ * first run. This is a small optimization.
+ */
+ dma_dom->next_address = dma_dom->aperture_size;
+
+ if (alloc_new_range(iommu, dma_dom, false, GFP_ATOMIC))
+ goto out;
+
+ /*
+ * aperture was sucessfully enlarged by 128 MB, try
+ * allocation again
+ */
+ goto retry;
+ }
start = address;
for (i = 0; i < pages; ++i) {
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 09/12] amd-iommu: remove amd_iommu_size kernel parameter
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (7 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 08/12] amd-iommu: enlarge the aperture dynamically Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 10/12] amd-iommu: disable round-robin allocator for CONFIG_IOMMU_STRESS Joerg Roedel
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: parameter not longer necessary when aperture increases dynamically ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
Documentation/kernel-parameters.txt | 5 -----
arch/x86/kernel/amd_iommu.c | 18 ++++--------------
arch/x86/kernel/amd_iommu_init.c | 15 ---------------
3 files changed, 4 insertions(+), 34 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e87bdbf..5b776c6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -329,11 +329,6 @@ and is between 256 and 4096 characters. It is defined in the file
flushed before they will be reused, which
is a lot of faster
- amd_iommu_size= [HW,X86-64]
- Define the size of the aperture for the AMD IOMMU
- driver. Possible values are:
- '32M', '64M' (default), '128M', '256M', '512M', '1G'
-
amijoy.map= [HW,JOY] Amiga joystick support
Map of devices attached to JOY0DAT and JOY1DAT
Format: <a>,<b>
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index d129d8f..31d56c3 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -939,17 +939,10 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
* It also intializes the page table and the address allocator data
* structures required for the dma_ops interface
*/
-static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
- unsigned order)
+static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu)
{
struct dma_ops_domain *dma_dom;
- /*
- * Currently the DMA aperture must be between 32 MB and 1GB in size
- */
- if ((order < 25) || (order > 30))
- return NULL;
-
dma_dom = kzalloc(sizeof(struct dma_ops_domain), GFP_KERNEL);
if (!dma_dom)
return NULL;
@@ -1087,7 +1080,6 @@ static int device_change_notifier(struct notifier_block *nb,
struct protection_domain *domain;
struct dma_ops_domain *dma_domain;
struct amd_iommu *iommu;
- int order = amd_iommu_aperture_order;
unsigned long flags;
if (devid > amd_iommu_last_bdf)
@@ -1126,7 +1118,7 @@ static int device_change_notifier(struct notifier_block *nb,
dma_domain = find_protection_domain(devid);
if (dma_domain)
goto out;
- dma_domain = dma_ops_domain_alloc(iommu, order);
+ dma_domain = dma_ops_domain_alloc(iommu);
if (!dma_domain)
goto out;
dma_domain->target_dev = devid;
@@ -1826,7 +1818,6 @@ static void prealloc_protection_domains(void)
struct pci_dev *dev = NULL;
struct dma_ops_domain *dma_dom;
struct amd_iommu *iommu;
- int order = amd_iommu_aperture_order;
u16 devid;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
@@ -1839,7 +1830,7 @@ static void prealloc_protection_domains(void)
iommu = amd_iommu_rlookup_table[devid];
if (!iommu)
continue;
- dma_dom = dma_ops_domain_alloc(iommu, order);
+ dma_dom = dma_ops_domain_alloc(iommu);
if (!dma_dom)
continue;
init_unity_mappings_for_device(dma_dom, devid);
@@ -1865,7 +1856,6 @@ static struct dma_map_ops amd_iommu_dma_ops = {
int __init amd_iommu_init_dma_ops(void)
{
struct amd_iommu *iommu;
- int order = amd_iommu_aperture_order;
int ret;
/*
@@ -1874,7 +1864,7 @@ int __init amd_iommu_init_dma_ops(void)
* protection domain will be assigned to the default one.
*/
list_for_each_entry(iommu, &amd_iommu_list, list) {
- iommu->default_dom = dma_ops_domain_alloc(iommu, order);
+ iommu->default_dom = dma_ops_domain_alloc(iommu);
if (iommu->default_dom == NULL)
return -ENOMEM;
iommu->default_dom->domain.flags |= PD_DEFAULT_MASK;
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 8c0be09..762a4ee 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -121,7 +121,6 @@ u16 amd_iommu_last_bdf; /* largest PCI device id we have
to handle */
LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings
we find in ACPI */
-unsigned amd_iommu_aperture_order = 26; /* size of aperture in power of 2 */
bool amd_iommu_isolate = true; /* if true, device isolation is
enabled */
bool amd_iommu_unmap_flush; /* if true, flush on every unmap */
@@ -1137,9 +1136,6 @@ int __init amd_iommu_init(void)
enable_iommus();
- printk(KERN_INFO "AMD IOMMU: aperture size is %d MB\n",
- (1 << (amd_iommu_aperture_order-20)));
-
printk(KERN_INFO "AMD IOMMU: device isolation ");
if (amd_iommu_isolate)
printk("enabled\n");
@@ -1225,15 +1221,4 @@ static int __init parse_amd_iommu_options(char *str)
return 1;
}
-static int __init parse_amd_iommu_size_options(char *str)
-{
- unsigned order = PAGE_SHIFT + get_order(memparse(str, &str));
-
- if ((order > 24) && (order < 31))
- amd_iommu_aperture_order = order;
-
- return 1;
-}
-
__setup("amd_iommu=", parse_amd_iommu_options);
-__setup("amd_iommu_size=", parse_amd_iommu_size_options);
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 10/12] amd-iommu: disable round-robin allocator for CONFIG_IOMMU_STRESS
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (8 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 09/12] amd-iommu: remove amd_iommu_size kernel parameter Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 11/12] amd-iommu: don't preallocate page tables with CONFIG_IOMMU_STRESS Joerg Roedel
2009-05-22 12:21 ` [PATCH 12/12] amd-iommu: don't free dma adresses below 512MB " Joerg Roedel
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: put high load on iommu tlb to find stale entry bugs ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 31d56c3..543822b 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -783,6 +783,11 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev,
{
unsigned long address;
+#ifdef CONFIG_IOMMU_STRESS
+ dom->next_address = 0;
+ dom->need_flush = true;
+#endif
+
address = dma_ops_area_alloc(dev, dom, pages, align_mask,
dma_mask, dom->next_address);
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 11/12] amd-iommu: don't preallocate page tables with CONFIG_IOMMU_STRESS
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (9 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 10/12] amd-iommu: disable round-robin allocator for CONFIG_IOMMU_STRESS Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
2009-05-22 12:21 ` [PATCH 12/12] amd-iommu: don't free dma adresses below 512MB " Joerg Roedel
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: force testing of on-demand page table allocation code ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 543822b..33434c4 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -661,6 +661,10 @@ static int alloc_new_range(struct amd_iommu *iommu,
int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT;
int i;
+#ifdef CONFIG_IOMMU_STRESS
+ populate = false;
+#endif
+
if (index >= APERTURE_MAX_RANGES)
return -ENOMEM;
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 12/12] amd-iommu: don't free dma adresses below 512MB with CONFIG_IOMMU_STRESS
2009-05-22 12:21 [PATCH 0/12] extended allocator for amd iommu Joerg Roedel
` (10 preceding siblings ...)
2009-05-22 12:21 ` [PATCH 11/12] amd-iommu: don't preallocate page tables with CONFIG_IOMMU_STRESS Joerg Roedel
@ 2009-05-22 12:21 ` Joerg Roedel
11 siblings, 0 replies; 13+ messages in thread
From: Joerg Roedel @ 2009-05-22 12:21 UTC (permalink / raw)
To: iommu, linux-kernel; +Cc: Joerg Roedel
[ impact: stress test automatic aperture enlargement code ]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kernel/amd_iommu.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 33434c4..04ff5ec 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -824,6 +824,11 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL);
+#ifdef CONFIG_IOMMU_STRESS
+ if (i < 4)
+ return;
+#endif
+
if (address >= dom->next_address)
dom->need_flush = true;
--
1.6.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread