On 09.11.20 17:00, Andrea Bastoni wrote: > The SMMUv2 allows filtering bits when matching stream IDs before they're > passed to the TCU. In this way multiple streams legally get the same > translation. > > 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 TCU 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. > > For the MMU-500, provide an explicit mask + id in the configuration and > update the implementation accordingly. > > Signed-off-by: Andrea Bastoni <[email protected]> > --- > hypervisor/arch/arm64/smmu.c | 73 ++++++++++++++++++++++----------- > include/jailhouse/cell-config.h | 15 +++++-- > 2 files changed, 61 insertions(+), 27 deletions(-) > > diff --git a/hypervisor/arch/arm64/smmu.c b/hypervisor/arch/arm64/smmu.c > index df92fb7a..9b824782 100644 > --- a/hypervisor/arch/arm64/smmu.c > +++ b/hypervisor/arch/arm64/smmu.c > @@ -84,6 +84,10 @@ > #define SMR_VALID (1 << 31) > #define SMR_MASK_SHIFT 16 > #define SMR_ID_SHIFT 0 > +/* Ignore upper bit in ID and MASK */ > +#define SMR_GET_ID(smr) ((smr) & 0x7fff) > +/* Mask is already specified from bit 0 in the configuration */ > +#define SMR_GET_MASK(smr) ((smr) & 0x7fff) > > /* Stream-to-Context Register */ > #define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) > @@ -152,7 +156,6 @@ struct arm_smmu_device { > unsigned long pgshift; > u32 num_context_banks; > u32 num_mapping_groups; > - u16 arm_sid_mask; > struct arm_smmu_smr *smrs; > }; > > @@ -164,6 +167,15 @@ static unsigned int num_smmu_devices; > (counter) < num_smmu_devices; \ > (smmu)++, (counter)++) > > +#define for_each_mmu500_sid(sid, config, counter) \ > + u32 __stub_iter; \ > + for ((__stub_iter) = (jailhouse_cell_stream_ids(config)[0]), \ > + (counter) = 0, \ > + (sid) = (union jailhouse_stream_id)(__stub_iter); \ > + (counter) < (config)->num_stream_ids; \ > + (__stub_iter) = (jailhouse_cell_stream_ids(config)[++(counter)]), \ > + (sid) = (union jailhouse_stream_id)(__stub_iter)) > + > static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) > { > struct arm_smmu_smr *smr = smmu->smrs + idx; > @@ -360,7 +372,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 +400,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 +409,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 +421,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; > + union jailhouse_stream_id fsid; > int ret, idx; > > /* If no sids, ignore */ > @@ -421,19 +435,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_mmu500_sid(fsid, cell->config, n) { > + sid = SMR_GET_ID(fsid.mmu500.id); > + smask = SMR_GET_MASK(fsid.mmu500.mask); > + > + 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 +466,18 @@ 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) > + union jailhouse_stream_id fsid, > + int idx) > { > - unsigned int root_sid, n; > + unsigned int n; > + union jailhouse_stream_id rsid; > > - 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); > + for_each_mmu500_sid(rsid, root_cell.config, n) { > + if (fsid.id == rsid.id) { > + printk("Assigning SID 0x%x Mask: 0x%x to cell \"%s\"\n", > + SMR_GET_ID(fsid.mmu500.id), > + SMR_GET_MASK(fsid.mmu500.mask), > + 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 +492,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; > + union jailhouse_stream_id fsid; > int idx; > > /* If no sids, ignore */ > @@ -479,10 +502,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_mmu500_sid(fsid, cell->config, n) { > + sid = SMR_GET_ID(fsid.mmu500.id); > + smask = SMR_GET_MASK(fsid.mmu500.mask); > + > + 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) { > @@ -546,8 +575,6 @@ static int arm_smmu_init(void) > continue; > > smmu = &smmu_device[num_smmu_devices]; > - smmu->arm_sid_mask = iommu->arm_mmu500.sid_mask; > - > smmu->base = paging_map_device(iommu->base, iommu->size); > if (!smmu->base) { > err = -ENOMEM; > diff --git a/include/jailhouse/cell-config.h b/include/jailhouse/cell-config.h > index 472cb4bb..d7a15990 100644 > --- a/include/jailhouse/cell-config.h > +++ b/include/jailhouse/cell-config.h > @@ -279,13 +279,19 @@ struct jailhouse_iommu { > __u64 tlb_base; > __u32 tlb_size; > } __attribute__((packed)) tipvu; > - > - struct { > - __u32 sid_mask; > - } __attribute__((packed)) arm_mmu500; > }; > } __attribute__((packed)); > > +union jailhouse_stream_id { > + /* Note: keep first */ > + __u32 id; > + struct { > + /* Note: both mask and id are only 15 bits wide */ > + __u16 mask; > + __u16 id; > + } __attribute__((packed)) mmu500; > +} __attribute__((packed)); > + > struct jailhouse_pio { > __u16 base; > __u16 length; > @@ -427,6 +433,7 @@ jailhouse_cell_pci_caps(const struct jailhouse_cell_desc > *cell) > static inline const __u32 * > jailhouse_cell_stream_ids(const struct jailhouse_cell_desc *cell) > { > + /* Note: deliver the __u32 full id */ > return (const __u32 *)((void *)jailhouse_cell_pci_caps(cell) + > cell->num_pci_caps * sizeof(struct jailhouse_pci_capability)); > } >
Will require some changes, but if we already introduce union, we should return it, like with the other accessors. Maybe different for_each-iterators can catch that again. Jan -- Siemens AG, T RDA IOT Corporate Competence Center Embedded Linux -- 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/13b9ba70-ff2e-aebb-57ca-49572536cbe2%40siemens.com.
