1
0
Fork 0

iommu/amd: Initialize new aperture range before making it visible

Make sure the aperture range is fully initialized before it
is visible to the address allocator.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
hifive-unleashed-5.1
Joerg Roedel 2015-12-21 19:25:56 +01:00
parent 7bfa5bd270
commit a73c156665
1 changed files with 20 additions and 13 deletions

View File

@ -1425,8 +1425,10 @@ 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;
struct amd_iommu *iommu;
unsigned long i, old_size, pte_pgsize;
struct aperture_range *range;
struct amd_iommu *iommu;
unsigned long flags;
#ifdef CONFIG_IOMMU_STRESS
populate = false;
@ -1435,17 +1437,17 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
if (index >= APERTURE_MAX_RANGES)
return -ENOMEM;
dma_dom->aperture[index] = kzalloc(sizeof(struct aperture_range), gfp);
if (!dma_dom->aperture[index])
range = kzalloc(sizeof(struct aperture_range), gfp);
if (!range)
return -ENOMEM;
dma_dom->aperture[index]->bitmap = (void *)get_zeroed_page(gfp);
if (!dma_dom->aperture[index]->bitmap)
range->bitmap = (void *)get_zeroed_page(gfp);
if (!range->bitmap)
goto out_free;
dma_dom->aperture[index]->offset = dma_dom->aperture_size;
range->offset = dma_dom->aperture_size;
spin_lock_init(&dma_dom->aperture[index]->bitmap_lock);
spin_lock_init(&range->bitmap_lock);
if (populate) {
unsigned long address = dma_dom->aperture_size;
@ -1458,14 +1460,18 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
if (!pte)
goto out_free;
dma_dom->aperture[index]->pte_pages[i] = pte_page;
range->pte_pages[i] = pte_page;
address += APERTURE_RANGE_SIZE / 64;
}
}
old_size = dma_dom->aperture_size;
dma_dom->aperture_size += APERTURE_RANGE_SIZE;
/* First take the bitmap_lock and then publish the range */
spin_lock_irqsave(&range->bitmap_lock, flags);
old_size = dma_dom->aperture_size;
dma_dom->aperture[index] = range;
dma_dom->aperture_size += APERTURE_RANGE_SIZE;
/* Reserve address range used for MSI messages */
if (old_size < MSI_ADDR_BASE_LO &&
@ -1512,15 +1518,16 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom,
update_domain(&dma_dom->domain);
spin_unlock_irqrestore(&range->bitmap_lock, flags);
return 0;
out_free:
update_domain(&dma_dom->domain);
free_page((unsigned long)dma_dom->aperture[index]->bitmap);
free_page((unsigned long)range->bitmap);
kfree(dma_dom->aperture[index]);
dma_dom->aperture[index] = NULL;
kfree(range);
return -ENOMEM;
}