On boards such as the ZCU Ultrascale+, the master ID needed to identify the corresponding SMMU stream ID may be dependent on a specific AXI ID that is set by the PL (and could be IP specific).
One single fixed mask to pass to the SMR to compact multiple stream IDs before they "hit" the TBC is not flexible enough. The use-case is to compact similar PL-originating masters and have the SMMU behaving the same for them (e.g., they're assigned to the same inmate). At the same time, one needs a full stream_id to assign e.g., different GEM ethernets to different inmates. This patch encodes the mask and the ID of a stream directly into the stream_id of the configuration. The encoding is the same as the SMR encoding. Signed-off-by: Andrea Bastoni <[email protected]> --- hypervisor/arch/arm64/smmu.c | 54 ++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/hypervisor/arch/arm64/smmu.c b/hypervisor/arch/arm64/smmu.c index df92fb7a..191ff154 100644 --- a/hypervisor/arch/arm64/smmu.c +++ b/hypervisor/arch/arm64/smmu.c @@ -84,6 +84,11 @@ #define SMR_VALID (1 << 31) #define SMR_MASK_SHIFT 16 #define SMR_ID_SHIFT 0 +/* "Full" Stream IDs in the configuration are the combination of MASK + ID + * according to the bit split as defined by ARM SMMU architecture version 2.0. + */ +#define SMR_GET_ID(smr) GET_FIELD((smr), 14, 0) +#define SMR_GET_MASK(smr) GET_FIELD((smr), 30, 16) /* Stream-to-Context Register */ #define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) @@ -360,7 +365,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return 0; } -static int arm_smmu_find_sme(u16 id, struct arm_smmu_device *smmu) +static int arm_smmu_find_sme(u16 id, u16 mask, struct arm_smmu_device *smmu) { struct arm_smmu_smr *smrs = smmu->smrs; int free_idx = -EINVAL; @@ -388,7 +393,7 @@ static int arm_smmu_find_sme(u16 id, struct arm_smmu_device *smmu) * expect simply identical entries for this case, but there's * no harm in accommodating the generalisation. */ - if ((smmu->arm_sid_mask & smrs[n].mask) == smmu->arm_sid_mask && + if ((mask & smrs[n].mask) == mask && !((id ^ smrs[n].id) & ~smrs[n].mask)) { return n; } @@ -397,7 +402,7 @@ static int arm_smmu_find_sme(u16 id, struct arm_smmu_device *smmu) * though, then there always exists at least one stream ID * which would cause a conflict, and we can't allow that risk. */ - if (!((id ^ smrs[n].id) & ~(smrs[n].mask | smmu->arm_sid_mask))) + if (!((id ^ smrs[n].id) & ~(smrs[n].mask | mask))) return -EINVAL; } @@ -409,7 +414,9 @@ static int arm_smmu_cell_init(struct cell *cell) unsigned int vmid = cell->config->id; struct arm_smmu_device *smmu; struct arm_smmu_smr *smr; - unsigned int dev, n, sid; + unsigned int dev, n; + u16 sid, smask; + u32 fsid; int ret, idx; /* If no sids, ignore */ @@ -421,19 +428,22 @@ static int arm_smmu_cell_init(struct cell *cell) smr = smmu->smrs; - for_each_stream_id(sid, cell->config, n) { - ret = arm_smmu_find_sme(sid, smmu); + for_each_stream_id(fsid, cell->config, n) { + sid = SMR_GET_ID(fsid); + smask = SMR_GET_MASK(fsid); + + ret = arm_smmu_find_sme(sid, smask, smmu); if (ret < 0) return trace_error(ret); idx = ret; - printk("Assigning StreamID 0x%x to cell \"%s\"\n", - sid, cell->config->name); + printk("Assigning SID 0x%x, Mask 0x%x to cell \"%s\"\n", + sid, smask, cell->config->name); arm_smmu_write_s2cr(smmu, idx, S2CR_TYPE_TRANS, vmid); smr[idx].id = sid; - smr[idx].mask = smmu->arm_sid_mask; + smr[idx].mask = smask; smr[idx].valid = true; arm_smmu_write_smr(smmu, idx); @@ -449,14 +459,14 @@ static int arm_smmu_cell_init(struct cell *cell) } static bool arm_smmu_return_sid_to_root_cell(struct arm_smmu_device *smmu, - unsigned int sid, int idx) + unsigned int full_sid, int idx) { unsigned int root_sid, n; for_each_stream_id(root_sid, root_cell.config, n) { - if (sid == root_sid) { - printk("Assigning StreamID 0x%x to cell \"%s\"\n", - sid, root_cell.config->name); + if (full_sid == root_sid) { + printk("Assigning Full StreamID 0x%x to cell \"%s\"\n", + full_sid, root_cell.config->name); /* We just need to update S2CR, SMR can stay as is. */ arm_smmu_write_s2cr(smmu, idx, S2CR_TYPE_TRANS, @@ -471,7 +481,9 @@ static void arm_smmu_cell_exit(struct cell *cell) { int id = cell->config->id; struct arm_smmu_device *smmu; - unsigned int dev, n, sid; + unsigned int dev, n; + u16 sid, smask; + u32 fsid; int idx; /* If no sids, ignore */ @@ -479,10 +491,16 @@ static void arm_smmu_cell_exit(struct cell *cell) return; for_each_smmu(smmu, dev) { - for_each_stream_id(sid, cell->config, n) { - idx = arm_smmu_find_sme(sid, smmu); - if (idx < 0 || - arm_smmu_return_sid_to_root_cell(smmu, sid, idx)) + for_each_stream_id(fsid, cell->config, n) { + sid = SMR_GET_ID(fsid); + smask = SMR_GET_MASK(fsid); + + idx = arm_smmu_find_sme(sid, smask, smmu); + if (idx < 0) + continue; + + /* return full stream ids */ + if (arm_smmu_return_sid_to_root_cell(smmu, fsid, idx)) continue; if (smmu->smrs) { -- 2.28.0 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/jailhouse-dev/20201104153648.35076-2-andrea.bastoni%40tum.de.
