Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 145907
b: refs/heads/master
c: c323956
h: refs/heads/master
i:
  145905: ea27408
  145903: 8e98581
v: v3
  • Loading branch information
Joerg Roedel committed May 28, 2009
1 parent 8aed08b commit 5797166
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 149 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 736501ee000757082a4f0832826ae1eda7ea106e
refs/heads/master: c3239567a20e90e3026ac5453d5267506ef7b030
2 changes: 0 additions & 2 deletions trunk/arch/x86/include/asm/amd_iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ extern int amd_iommu_init(void);
extern int amd_iommu_init_dma_ops(void);
extern void amd_iommu_detect(void);
extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
extern void amd_iommu_flush_all_domains(void);
extern void amd_iommu_flush_all_devices(void);
#else
static inline int amd_iommu_init(void) { return -ENODEV; }
static inline void amd_iommu_detect(void) { }
Expand Down
38 changes: 21 additions & 17 deletions trunk/arch/x86/include/asm/amd_iommu_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,7 @@
#define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops
domain for an IOMMU */

/*
* Make iterating over all IOMMUs easier
*/
#define for_each_iommu(iommu) \
list_for_each_entry((iommu), &amd_iommu_list, list)
#define for_each_iommu_safe(iommu, next) \
list_for_each_entry_safe((iommu), (next), &amd_iommu_list, list)
#define APERTURE_RANGE_SIZE (128 * 1024 * 1024)

/*
* This structure contains generic data for IOMMU protection domains
Expand All @@ -217,6 +211,24 @@ struct protection_domain {
void *priv; /* private data */
};

/*
* 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
*/
Expand All @@ -232,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;
Expand Down
83 changes: 25 additions & 58 deletions trunk/arch/x86/kernel/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
{
struct amd_iommu *iommu;

for_each_iommu(iommu)
list_for_each_entry(iommu, &amd_iommu_list, list)
iommu_poll_events(iommu);

return IRQ_HANDLED;
Expand Down Expand Up @@ -440,7 +440,7 @@ static void iommu_flush_domain(u16 domid)
__iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
domid, 1, 1);

for_each_iommu(iommu) {
list_for_each_entry(iommu, &amd_iommu_list, list) {
spin_lock_irqsave(&iommu->lock, flags);
__iommu_queue_command(iommu, &cmd);
__iommu_completion_wait(iommu);
Expand All @@ -449,35 +449,6 @@ static void iommu_flush_domain(u16 domid)
}
}

void amd_iommu_flush_all_domains(void)
{
int i;

for (i = 1; i < MAX_DOMAIN_ID; ++i) {
if (!test_bit(i, amd_iommu_pd_alloc_bitmap))
continue;
iommu_flush_domain(i);
}
}

void amd_iommu_flush_all_devices(void)
{
struct amd_iommu *iommu;
int i;

for (i = 0; i <= amd_iommu_last_bdf; ++i) {
if (amd_iommu_pd_table[i] == NULL)
continue;

iommu = amd_iommu_rlookup_table[i];
if (!iommu)
continue;

iommu_queue_inv_dev_entry(iommu, i);
iommu_completion_wait(iommu);
}
}

/****************************************************************************
*
* The functions below are used the create the page table mappings for
Expand Down Expand Up @@ -624,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;
Expand Down Expand Up @@ -685,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;
}

Expand All @@ -714,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;
Expand Down Expand Up @@ -770,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)
Expand Down Expand Up @@ -814,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);
}
Expand Down Expand Up @@ -855,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;
Expand All @@ -883,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)
Expand All @@ -898,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);
}

Expand Down Expand Up @@ -1188,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;
Expand Down Expand Up @@ -1221,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);
Expand Down Expand Up @@ -1701,7 +1668,7 @@ int __init amd_iommu_init_dma_ops(void)
* found in the system. Devices not assigned to any other
* protection domain will be assigned to the default one.
*/
for_each_iommu(iommu) {
list_for_each_entry(iommu, &amd_iommu_list, list) {
iommu->default_dom = dma_ops_domain_alloc(iommu, order);
if (iommu->default_dom == NULL)
return -ENOMEM;
Expand Down Expand Up @@ -1739,7 +1706,7 @@ int __init amd_iommu_init_dma_ops(void)

free_domains:

for_each_iommu(iommu) {
list_for_each_entry(iommu, &amd_iommu_list, list) {
if (iommu->default_dom)
dma_ops_domain_free(iommu->default_dom);
}
Expand Down
Loading

0 comments on commit 5797166

Please sign in to comment.