forked from Minki/linux
iommu/io-pgtable-arm-v7s: Refactor split_blk_unmap
Whilst the short-descriptor format's split_blk_unmap implementation has no need to be recursive, it followed the pattern of the LPAE version anyway for the sake of consistency. With the latter now reworked for both efficiency and future scalability improvements, tweak the former similarly, not least to make it less obtuse. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
parent
fb3a95795d
commit
b9f1ef30ac
@ -281,6 +281,13 @@ static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl,
|
||||
else if (prot & IOMMU_CACHE)
|
||||
pte |= ARM_V7S_ATTR_B | ARM_V7S_ATTR_C;
|
||||
|
||||
pte |= ARM_V7S_PTE_TYPE_PAGE;
|
||||
if (lvl == 1 && (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS))
|
||||
pte |= ARM_V7S_ATTR_NS_SECTION;
|
||||
|
||||
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB)
|
||||
pte |= ARM_V7S_ATTR_MTK_4GB;
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
@ -353,7 +360,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
|
||||
int lvl, int num_entries, arm_v7s_iopte *ptep)
|
||||
{
|
||||
struct io_pgtable_cfg *cfg = &data->iop.cfg;
|
||||
arm_v7s_iopte pte = arm_v7s_prot_to_pte(prot, lvl, cfg);
|
||||
arm_v7s_iopte pte;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_entries; i++)
|
||||
@ -375,13 +382,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
pte |= ARM_V7S_PTE_TYPE_PAGE;
|
||||
if (lvl == 1 && (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS))
|
||||
pte |= ARM_V7S_ATTR_NS_SECTION;
|
||||
|
||||
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB)
|
||||
pte |= ARM_V7S_ATTR_MTK_4GB;
|
||||
|
||||
pte = arm_v7s_prot_to_pte(prot, lvl, cfg);
|
||||
if (num_entries > 1)
|
||||
pte = arm_v7s_pte_to_cont(pte, lvl);
|
||||
|
||||
@ -391,6 +392,20 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static arm_v7s_iopte arm_v7s_install_table(arm_v7s_iopte *table,
|
||||
arm_v7s_iopte *ptep,
|
||||
struct io_pgtable_cfg *cfg)
|
||||
{
|
||||
arm_v7s_iopte new;
|
||||
|
||||
new = virt_to_phys(table) | ARM_V7S_PTE_TYPE_TABLE;
|
||||
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
|
||||
new |= ARM_V7S_ATTR_NS_TABLE;
|
||||
|
||||
__arm_v7s_set_pte(ptep, new, 1, cfg);
|
||||
return new;
|
||||
}
|
||||
|
||||
static int __arm_v7s_map(struct arm_v7s_io_pgtable *data, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot,
|
||||
int lvl, arm_v7s_iopte *ptep)
|
||||
@ -418,11 +433,7 @@ static int __arm_v7s_map(struct arm_v7s_io_pgtable *data, unsigned long iova,
|
||||
if (!cptep)
|
||||
return -ENOMEM;
|
||||
|
||||
pte = virt_to_phys(cptep) | ARM_V7S_PTE_TYPE_TABLE;
|
||||
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
|
||||
pte |= ARM_V7S_ATTR_NS_TABLE;
|
||||
|
||||
__arm_v7s_set_pte(ptep, pte, 1, cfg);
|
||||
arm_v7s_install_table(cptep, ptep, cfg);
|
||||
} else if (ARM_V7S_PTE_IS_TABLE(pte, lvl)) {
|
||||
cptep = iopte_deref(pte, lvl);
|
||||
} else {
|
||||
@ -503,41 +514,35 @@ static void arm_v7s_split_cont(struct arm_v7s_io_pgtable *data,
|
||||
|
||||
static int arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
|
||||
unsigned long iova, size_t size,
|
||||
arm_v7s_iopte *ptep)
|
||||
arm_v7s_iopte blk_pte, arm_v7s_iopte *ptep)
|
||||
{
|
||||
unsigned long blk_start, blk_end, blk_size;
|
||||
phys_addr_t blk_paddr;
|
||||
arm_v7s_iopte table = 0;
|
||||
int prot = arm_v7s_pte_to_prot(*ptep, 1);
|
||||
struct io_pgtable_cfg *cfg = &data->iop.cfg;
|
||||
arm_v7s_iopte pte, *tablep;
|
||||
int i, unmap_idx, num_entries, num_ptes;
|
||||
|
||||
blk_size = ARM_V7S_BLOCK_SIZE(1);
|
||||
blk_start = iova & ARM_V7S_LVL_MASK(1);
|
||||
blk_end = blk_start + ARM_V7S_BLOCK_SIZE(1);
|
||||
blk_paddr = *ptep & ARM_V7S_LVL_MASK(1);
|
||||
tablep = __arm_v7s_alloc_table(2, GFP_ATOMIC, data);
|
||||
if (!tablep)
|
||||
return 0; /* Bytes unmapped */
|
||||
|
||||
for (; blk_start < blk_end; blk_start += size, blk_paddr += size) {
|
||||
arm_v7s_iopte *tablep;
|
||||
num_ptes = ARM_V7S_PTES_PER_LVL(2);
|
||||
num_entries = size >> ARM_V7S_LVL_SHIFT(2);
|
||||
unmap_idx = ARM_V7S_LVL_IDX(iova, 2);
|
||||
|
||||
pte = arm_v7s_prot_to_pte(arm_v7s_pte_to_prot(blk_pte, 1), 2, cfg);
|
||||
if (num_entries > 1)
|
||||
pte = arm_v7s_pte_to_cont(pte, 2);
|
||||
|
||||
for (i = 0; i < num_ptes; i += num_entries, pte += size) {
|
||||
/* Unmap! */
|
||||
if (blk_start == iova)
|
||||
if (i == unmap_idx)
|
||||
continue;
|
||||
|
||||
/* __arm_v7s_map expects a pointer to the start of the table */
|
||||
tablep = &table - ARM_V7S_LVL_IDX(blk_start, 1);
|
||||
if (__arm_v7s_map(data, blk_start, blk_paddr, size, prot, 1,
|
||||
tablep) < 0) {
|
||||
if (table) {
|
||||
/* Free the table we allocated */
|
||||
tablep = iopte_deref(table, 1);
|
||||
__arm_v7s_free_table(tablep, 2, data);
|
||||
}
|
||||
return 0; /* Bytes unmapped */
|
||||
}
|
||||
__arm_v7s_set_pte(&tablep[i], pte, num_entries, cfg);
|
||||
}
|
||||
|
||||
__arm_v7s_set_pte(ptep, table, 1, &data->iop.cfg);
|
||||
iova &= ~(blk_size - 1);
|
||||
io_pgtable_tlb_add_flush(&data->iop, iova, blk_size, blk_size, true);
|
||||
arm_v7s_install_table(tablep, ptep, cfg);
|
||||
|
||||
io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true);
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -594,7 +599,7 @@ static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
|
||||
* Insert a table at the next level to map the old region,
|
||||
* minus the part we want to unmap
|
||||
*/
|
||||
return arm_v7s_split_blk_unmap(data, iova, size, ptep);
|
||||
return arm_v7s_split_blk_unmap(data, iova, size, pte[0], ptep);
|
||||
}
|
||||
|
||||
/* Keep on walkin' */
|
||||
|
Loading…
Reference in New Issue
Block a user