Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
iommu/arm-smmu-v3: Add arm_smmu_strtab_l1/2_idx()
Browse files Browse the repository at this point in the history
Don't open code the calculations of the indexes for each level, provide
two functions to do that math and call them in all the places. Update all
the places computing indexes.

Calculate the L1 table size directly based on the max required index from
the cap. Remove STRTAB_L1_SZ_SHIFT in favour of STRTAB_NUM_L2_STES.

Use STRTAB_NUM_L2_STES to replace remaining open coded 1 << STRTAB_SPLIT.

Tested-by: Nicolin Chen <[email protected]>
Reviewed-by: Nicolin Chen <[email protected]>
Signed-off-by: Jason Gunthorpe <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Will Deacon <[email protected]>
  • Loading branch information
jgunthorpe authored and willdeacon committed Sep 9, 2024
1 parent 19eb465 commit ce41041
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 27 deletions.
45 changes: 19 additions & 26 deletions drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -1710,17 +1710,15 @@ static void arm_smmu_init_initial_stes(struct arm_smmu_ste *strtab,
static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
{
size_t size;
void *strtab;
dma_addr_t l2ptr_dma;
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
struct arm_smmu_strtab_l1_desc *desc;

desc = &cfg->l1_desc[arm_smmu_strtab_l1_idx(sid)];
if (desc->l2ptr)
return 0;

size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];

size = STRTAB_NUM_L2_STES * sizeof(struct arm_smmu_ste);
desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &l2ptr_dma,
GFP_KERNEL);
if (!desc->l2ptr) {
Expand All @@ -1730,8 +1728,9 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
return -ENOMEM;
}

arm_smmu_init_initial_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
arm_smmu_write_strtab_l1_desc(strtab, l2ptr_dma);
arm_smmu_init_initial_stes(desc->l2ptr, STRTAB_NUM_L2_STES);
arm_smmu_write_strtab_l1_desc(&cfg->strtab[arm_smmu_strtab_l1_idx(sid)],
l2ptr_dma);
return 0;
}

Expand Down Expand Up @@ -2486,12 +2485,9 @@ arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;

if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
unsigned int idx1, idx2;

/* Two-level walk */
idx1 = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
idx2 = sid & ((1 << STRTAB_SPLIT) - 1);
return &cfg->l1_desc[idx1].l2ptr[idx2];
return &cfg->l1_desc[arm_smmu_strtab_l1_idx(sid)]
.l2ptr[arm_smmu_strtab_l2_idx(sid)];
} else {
/* Simple linear lookup */
return (struct arm_smmu_ste *)&cfg
Expand Down Expand Up @@ -3195,12 +3191,9 @@ struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)

static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
{
unsigned long limit = smmu->strtab_cfg.num_l1_ents;

if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
limit *= 1UL << STRTAB_SPLIT;

return sid < limit;
return arm_smmu_strtab_l1_idx(sid) < smmu->strtab_cfg.num_l1_ents;
return sid < smmu->strtab_cfg.num_l1_ents;
}

static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
Expand Down Expand Up @@ -3637,19 +3630,18 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
{
void *strtab;
u64 reg;
u32 size, l1size;
u32 l1size;
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
unsigned int last_sid_idx =
arm_smmu_strtab_l1_idx((1 << smmu->sid_bits) - 1);

/* Calculate the L1 size, capped to the SIDSIZE. */
size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
size = min(size, smmu->sid_bits - STRTAB_SPLIT);
cfg->num_l1_ents = 1 << size;

size += STRTAB_SPLIT;
if (size < smmu->sid_bits)
cfg->num_l1_ents = min(last_sid_idx + 1, STRTAB_MAX_L1_ENTRIES);
if (cfg->num_l1_ents <= last_sid_idx)
dev_warn(smmu->dev,
"2-level strtab only covers %u/%u bits of SID\n",
size, smmu->sid_bits);
ilog2(cfg->num_l1_ents * STRTAB_NUM_L2_STES),
smmu->sid_bits);

l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
Expand All @@ -3664,7 +3656,8 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)

/* Configure strtab_base_cfg for 2 levels */
reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_2LVL);
reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, size);
reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE,
ilog2(cfg->num_l1_ents) + STRTAB_SPLIT);
reg |= FIELD_PREP(STRTAB_BASE_CFG_SPLIT, STRTAB_SPLIT);
cfg->strtab_base_cfg = reg;

Expand Down
14 changes: 13 additions & 1 deletion drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ struct arm_smmu_device;
* 2lvl: 128k L1 entries,
* 256 lazy entries per table (each table covers a PCI bus)
*/
#define STRTAB_L1_SZ_SHIFT 20
#define STRTAB_SPLIT 8

#define STRTAB_L1_DESC_DWORDS 1
Expand All @@ -217,6 +216,19 @@ struct arm_smmu_ste {
__le64 data[STRTAB_STE_DWORDS];
};

#define STRTAB_NUM_L2_STES (1 << STRTAB_SPLIT)
#define STRTAB_MAX_L1_ENTRIES (1 << 17)

static inline u32 arm_smmu_strtab_l1_idx(u32 sid)
{
return sid / STRTAB_NUM_L2_STES;
}

static inline u32 arm_smmu_strtab_l2_idx(u32 sid)
{
return sid % STRTAB_NUM_L2_STES;
}

#define STRTAB_STE_0_V (1UL << 0)
#define STRTAB_STE_0_CFG GENMASK_ULL(3, 1)
#define STRTAB_STE_0_CFG_ABORT 0
Expand Down

0 comments on commit ce41041

Please sign in to comment.