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.

Reply via email to