Skip to content

Commit 3bff9ed

Browse files
iommu: bcm2712-iommu: Map and unmap multiple pages in a single call
For efficiency, the map_pages() and unmap_pages() calls now pay attention to their "count" argument. Remove a special case for a "pass-through" address range, which the DMA/IOMMU subsystem isn't told exists and should never use. Fix a bug where we omitted to set *mapped to 0 in error cases. Minor style fixes and tidying. Signed-off-by: Nick Hollinghurst <[email protected]>
1 parent abb8043 commit 3bff9ed

File tree

1 file changed

+67
-58
lines changed

1 file changed

+67
-58
lines changed

drivers/iommu/bcm2712-iommu.c

Lines changed: 67 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -241,42 +241,48 @@ static int bcm2712_iommu_map(struct iommu_domain *domain, unsigned long iova,
241241
int prot, gfp_t gfp, size_t *mapped)
242242
{
243243
struct bcm2712_iommu *mmu = domain_to_mmu(domain);
244-
245-
(void)gfp;
246-
iova -= mmu->dma_iova_offset;
247-
if (iova >= APERTURE_BASE && iova + bytes <= APERTURE_TOP) {
248-
unsigned int p;
249-
u32 entry = MMMU_PTE_VALID | (pa >> MMU_PAGE_SHIFT);
250-
u32 align = (u32)(iova | pa | bytes);
251-
252-
/* large page and write enable flags */
253-
if (!(align & ((1 << HUGEPAGE_SHIFT) - 1)))
254-
entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 3);
255-
else if (!(align & mmu->superpage_mask) && mmu->superpage_mask)
256-
entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 2);
257-
else if (!(align & mmu->bigpage_mask) && mmu->bigpage_mask)
258-
entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 1);
259-
if (prot & IOMMU_WRITE)
260-
entry |= MMMU_PTE_WRITEABLE;
261-
262-
/* Ensure tables are cache-coherent with CPU */
263-
if (!mmu->dirty) {
264-
dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE);
265-
mmu->dirty = true;
266-
}
267-
268-
iova -= APERTURE_BASE;
269-
for (p = iova >> MMU_PAGE_SHIFT;
270-
p < (iova + bytes) >> MMU_PAGE_SHIFT; p++) {
271-
mmu->nmapped_pages += !(mmu->tables[p]);
272-
mmu->tables[p] = entry++;
273-
}
274-
} else if (iova + bytes > APERTURE_BASE || iova != pa) {
275-
dev_warn(mmu->dev, "%s: iova=0x%lx pa=0x%llx size=0x%llx OUT OF RANGE!\n",
244+
u32 entry = MMMU_PTE_VALID | (pa >> MMU_PAGE_SHIFT);
245+
u32 align = (u32)(iova | pa | bytes);
246+
unsigned int p;
247+
248+
/* Reject if at least the first page is not within our aperture */
249+
if (iova < mmu->dma_iova_offset + APERTURE_BASE ||
250+
iova + bytes > mmu->dma_iova_offset + APERTURE_TOP) {
251+
dev_warn(mmu->dev, "%s: iova=0x%lx pa=0x%llx bytes=0x%lx OUT OF RANGE\n",
276252
__func__, iova,
277-
(unsigned long long)pa, (unsigned long long)bytes);
253+
(unsigned long long)pa, (unsigned long)bytes);
254+
*mapped = 0;
255+
278256
return -EINVAL;
279257
}
258+
259+
/* large page and write enable flags */
260+
if (!(align & ((1 << HUGEPAGE_SHIFT) - 1)))
261+
entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 3);
262+
else if (!(align & mmu->superpage_mask) && mmu->superpage_mask)
263+
entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 2);
264+
else if (!(align & mmu->bigpage_mask) && mmu->bigpage_mask)
265+
entry |= FIELD_PREP(MMMU_PTE_PAGESIZE_MASK, 1);
266+
if (prot & IOMMU_WRITE)
267+
entry |= MMMU_PTE_WRITEABLE;
268+
269+
/* Ensure tables are cache-coherent with CPU */
270+
if (!mmu->dirty) {
271+
dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE);
272+
mmu->dirty = true;
273+
}
274+
275+
/* Make iova relative to table base; amalgamate count pages */
276+
iova -= (mmu->dma_iova_offset + APERTURE_BASE);
277+
bytes = min(APERTURE_SIZE - iova, count * bytes);
278+
279+
/* Iterate over table by smallest native IOMMU page size */
280+
for (p = iova >> MMU_PAGE_SHIFT;
281+
p < (iova + bytes) >> MMU_PAGE_SHIFT; p++) {
282+
mmu->nmapped_pages += !(mmu->tables[p]);
283+
mmu->tables[p] = entry++;
284+
}
285+
280286
*mapped = bytes;
281287

282288
return 0;
@@ -287,42 +293,45 @@ static size_t bcm2712_iommu_unmap(struct iommu_domain *domain, unsigned long iov
287293
struct iommu_iotlb_gather *gather)
288294
{
289295
struct bcm2712_iommu *mmu = domain_to_mmu(domain);
296+
unsigned int p;
290297

291-
if (iova >= mmu->dma_iova_offset + APERTURE_BASE &&
292-
iova + bytes <= mmu->dma_iova_offset + APERTURE_TOP) {
293-
unsigned int p;
298+
if (iova < mmu->dma_iova_offset + APERTURE_BASE ||
299+
iova + bytes > mmu->dma_iova_offset + APERTURE_TOP)
300+
return 0;
294301

295-
/* Record just the lower and upper bounds in "gather" */
296-
if (gather) {
297-
bool empty = (gather->end <= gather->start);
302+
/* Record just the lower and upper bounds in "gather" */
303+
if (gather) {
304+
bool empty = (gather->end <= gather->start);
298305

299-
if (empty || gather->start < iova)
300-
gather->start = iova;
301-
if (empty || gather->end < iova + bytes)
302-
gather->end = iova + bytes;
303-
}
306+
if (empty || gather->start < iova)
307+
gather->start = iova;
308+
if (empty || gather->end < iova + bytes)
309+
gather->end = iova + bytes;
310+
}
304311

305-
/* Ensure tables are cache-coherent with CPU */
306-
if (!mmu->dirty) {
307-
dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE);
308-
mmu->dirty = true;
309-
}
312+
/* Ensure tables are cache-coherent with CPU */
313+
if (!mmu->dirty) {
314+
dma_sync_sgtable_for_cpu(mmu->dev, mmu->sgt, DMA_TO_DEVICE);
315+
mmu->dirty = true;
316+
}
310317

311-
/* Clear table entries, this marks the addresses as illegal */
312-
iova -= (mmu->dma_iova_offset + APERTURE_BASE);
313-
for (p = iova >> MMU_PAGE_SHIFT;
314-
p < (iova + bytes) >> MMU_PAGE_SHIFT;
315-
p++) {
316-
mmu->nmapped_pages -= !!(mmu->tables[p]);
317-
mmu->tables[p] = 0;
318-
}
318+
/* Make iova relative to table base; amalgamate count pages */
319+
iova -= (mmu->dma_iova_offset + APERTURE_BASE);
320+
bytes = min(APERTURE_SIZE - iova, count * bytes);
321+
322+
/* Clear table entries, this marks the addresses as illegal */
323+
for (p = iova >> MMU_PAGE_SHIFT;
324+
p < (iova + bytes) >> MMU_PAGE_SHIFT;
325+
p++) {
326+
mmu->nmapped_pages -= !!(mmu->tables[p]);
327+
mmu->tables[p] = 0;
319328
}
320329

321330
return bytes;
322331
}
323332

324333
static int bcm2712_iommu_sync_range(struct iommu_domain *domain,
325-
unsigned long iova, size_t size)
334+
unsigned long iova, size_t size)
326335
{
327336
struct bcm2712_iommu *mmu = domain_to_mmu(domain);
328337
unsigned long iova_end;

0 commit comments

Comments
 (0)