Commit 81716c3f authored by Robin Murphy's avatar Robin Murphy
Browse files

iommu/dma: Extended DMA domain debug info



Keep track of the allocation details too.

Signed-off-by: Robin Murphy's avatarRobin Murphy <robin.murphy@arm.com>
parent 30a5c547
......@@ -87,29 +87,54 @@ static int iommu_dma_debug_show(struct seq_file *m, void *p)
struct iommu_dma_cookie *cookie = dom->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
unsigned long shift = iova_shift(iovad);
unsigned long pfn_hi = iovad->dma_32bit_pfn + 1;
struct rb_node *node;
seq_puts(m, "--------------------------\n");
seq_printf(m, " %px\n", dom);
seq_puts(m, "--------------------------\n");
for (node = rb_last(&iovad->rbroot); node; node = rb_prev(node)) {
for (node = rb_last(&iovad->rbroot); ; node = rb_prev(node)) {
struct iova *iova = container_of(node, struct iova, node);
unsigned long pfn_lo = iova->pfn_lo;
unsigned long pfn_hi = iova->pfn_hi + 1;
phys_addr_t phys = iommu_iova_to_phys(dom, pfn_lo << shift);
unsigned long prot, pfn_lo;
if (phys) {
seq_printf(m, "%08lx - %08lx (%lx): %pap\n",
pfn_lo = node ? iova->pfn_hi + 1 : iovad->start_pfn;
if (pfn_hi > pfn_lo)
seq_printf(m, "%08lx - %08lx unallocated\n",
pfn_lo << shift,
(pfn_hi << shift) - 1);
if (!node)
break;
pfn_hi = pfn_lo;
pfn_lo = iova->pfn_lo;
prot = iova->prot;
if (iova->client) {
phys_addr_t phys = iommu_iova_to_phys(dom, pfn_lo << shift);
seq_printf(m, "%08lx - %08lx (%lx): %pap %c%c%c %c%c%c (%s)\n",
pfn_lo << shift,
(pfn_hi << shift) - 1,
(pfn_hi - pfn_lo) << shift,
&phys);
&phys,
(prot & IOMMU_READ) ? 'R' : 'r',
(prot & IOMMU_WRITE) ? 'W' : 'w',
(prot & IOMMU_NOEXEC) ? 'x' : 'X',
(prot & IOMMU_CACHE) ? 'C' : 'c',
(prot & IOMMU_MMIO) ? 'M' : 'm',
(prot & IOMMU_PRIV) ? 'P' : 'p',
dev_name(iova->client));
} else if (prot) {
seq_printf(m, "%08lx - %08lx (%lx): cached\n",
pfn_lo << shift,
(pfn_hi << shift) - 1,
(pfn_hi - pfn_lo) << shift);
} else {
seq_printf(m, "%08lx - %08lx reserved\n",
pfn_lo << shift,
(pfn_hi << shift) - 1);
}
pfn_hi = min(pfn_lo, iovad->dma_32bit_pfn + 1);
}
return 0;
......@@ -407,7 +432,8 @@ int dma_info_to_prot(enum dma_data_direction dir, bool coherent,
}
static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
size_t size, dma_addr_t dma_limit, struct device *dev)
size_t size, dma_addr_t dma_limit, struct device *dev,
unsigned long prot)
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
......@@ -441,6 +467,12 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift,
true);
if (iova) {
struct iova *i = find_iova(iovad, iova);
i->client = dev;
i->prot = prot;
}
return (dma_addr_t)iova << shift;
}
......@@ -452,9 +484,13 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
/* The MSI case is only ever cleaning up its most recent allocation */
if (cookie->type == IOMMU_DMA_MSI_COOKIE)
cookie->msi_iova -= size;
else
free_iova_fast(iovad, iova_pfn(iovad, iova),
size >> iova_shift(iovad));
else {
unsigned long shift = iova_shift(iovad);
struct iova *i = find_iova(iovad, iova >> shift);
i->client = 0;
i->prot = ~0UL;
free_iova_fast(iovad, iova >> shift, size >> shift);
}
}
static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
......@@ -603,7 +639,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
return NULL;
size = iova_align(iovad, size);
iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev);
iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev, prot);
if (!iova)
goto out_free_pages;
......@@ -677,7 +713,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
size = iova_align(&cookie->iovad, size + iova_off);
}
iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev, prot);
if (!iova)
return IOMMU_MAPPING_ERROR;
......@@ -833,7 +869,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
prev = s;
}
iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev);
iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev, prot);
if (!iova)
goto out_restore_sg;
......
......@@ -225,7 +225,7 @@ static DEFINE_MUTEX(iova_cache_mutex);
struct iova *alloc_iova_mem(void)
{
return kmem_cache_alloc(iova_cache, GFP_ATOMIC);
return kmem_cache_zalloc(iova_cache, GFP_ATOMIC);
}
EXPORT_SYMBOL(alloc_iova_mem);
......
......@@ -22,6 +22,8 @@ struct iova {
struct rb_node node;
unsigned long pfn_hi; /* Highest allocated pfn */
unsigned long pfn_lo; /* Lowest allocated pfn */
struct device *client;
unsigned long prot;
};
struct iova_magazine;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment