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. Update a stream_id to support two different interpretations: - for the SMMUv2, provide an explicit mask + ID. - for the SMMUv3, keep the current single ID. This commit updates the SMMUv2 / v3 --including configuration-- accordingly. Signed-off-by: Andrea Bastoni <[email protected]> --- configs/arm64/imx8qm-linux-demo.c | 7 ++- configs/arm64/imx8qm.c | 16 +++++-- configs/arm64/k3-j7200-evm-linux-demo.c | 2 +- configs/arm64/k3-j7200-evm.c | 2 +- configs/arm64/k3-j721e-evm-linux-demo.c | 2 +- configs/arm64/k3-j721e-evm.c | 2 +- configs/arm64/ultra96.c | 11 ++++- configs/arm64/zynqmp-zcu102.c | 15 +++++- hypervisor/arch/arm64/smmu-v3.c | 9 ++-- hypervisor/arch/arm64/smmu.c | 64 ++++++++++++++++--------- hypervisor/arch/arm64/ti-pvu.c | 21 ++++---- include/jailhouse/cell-config.h | 18 ++++--- 12 files changed, 114 insertions(+), 55 deletions(-) diff --git a/configs/arm64/imx8qm-linux-demo.c b/configs/arm64/imx8qm-linux-demo.c index f13ca7bc..e8e8b217 100644 --- a/configs/arm64/imx8qm-linux-demo.c +++ b/configs/arm64/imx8qm-linux-demo.c @@ -19,7 +19,7 @@ struct { struct jailhouse_memory mem_regions[18]; struct jailhouse_irqchip irqchips[4]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[1]; + union jailhouse_stream_id stream_ids[1]; } __attribute__((packed)) config = { .cell = { .signature = JAILHOUSE_CELL_DESC_SIGNATURE, @@ -194,6 +194,9 @@ struct { }, .stream_ids = { - 0x10, + { + .mmu500.mask = 0x7f8, + .mmu500.id = 0x10, + }, }, }; diff --git a/configs/arm64/imx8qm.c b/configs/arm64/imx8qm.c index d63c73cf..2ec4f4dd 100644 --- a/configs/arm64/imx8qm.c +++ b/configs/arm64/imx8qm.c @@ -20,7 +20,7 @@ struct { struct jailhouse_memory mem_regions[15]; struct jailhouse_irqchip irqchips[3]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[3]; + union jailhouse_stream_id stream_ids[3]; } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, @@ -54,7 +54,6 @@ struct { .type = JAILHOUSE_IOMMU_ARM_MMU500, .base = 0x51400000, .size = 0x40000, - .arm_mmu500.sid_mask = 0x7f80, }, }, @@ -209,6 +208,17 @@ struct { }, .stream_ids = { - 0x11, 0x12, 0x13, + { + .mmu500.mask = 0x7f8, + .mmu500.id = 0x11, + }, + { + .mmu500.mask = 0x7f8, + .mmu500.id = 0x12, + }, + { + .mmu500.mask = 0x7f8, + .mmu500.id = 0x13, + }, }, }; diff --git a/configs/arm64/k3-j7200-evm-linux-demo.c b/configs/arm64/k3-j7200-evm-linux-demo.c index 90a0ce4c..ace9cd3a 100644 --- a/configs/arm64/k3-j7200-evm-linux-demo.c +++ b/configs/arm64/k3-j7200-evm-linux-demo.c @@ -26,7 +26,7 @@ struct { struct jailhouse_memory mem_regions[19]; struct jailhouse_irqchip irqchips[3]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[1]; + union jailhouse_stream_id stream_ids[1]; } __attribute__((packed)) config = { .cell = { .signature = JAILHOUSE_CELL_DESC_SIGNATURE, diff --git a/configs/arm64/k3-j7200-evm.c b/configs/arm64/k3-j7200-evm.c index c3ac331d..d0c8aee3 100644 --- a/configs/arm64/k3-j7200-evm.c +++ b/configs/arm64/k3-j7200-evm.c @@ -21,7 +21,7 @@ struct { struct jailhouse_memory mem_regions[32]; struct jailhouse_irqchip irqchips[6]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[1]; + union jailhouse_stream_id stream_ids[1]; } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, diff --git a/configs/arm64/k3-j721e-evm-linux-demo.c b/configs/arm64/k3-j721e-evm-linux-demo.c index 5b6aa82e..1b8b3c4c 100644 --- a/configs/arm64/k3-j721e-evm-linux-demo.c +++ b/configs/arm64/k3-j721e-evm-linux-demo.c @@ -27,7 +27,7 @@ struct { struct jailhouse_memory mem_regions[22]; struct jailhouse_irqchip irqchips[4]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[2]; + union jailhouse_stream_id stream_ids[2]; } __attribute__((packed)) config = { .cell = { .signature = JAILHOUSE_CELL_DESC_SIGNATURE, diff --git a/configs/arm64/k3-j721e-evm.c b/configs/arm64/k3-j721e-evm.c index ab13fedd..aa5b47a9 100644 --- a/configs/arm64/k3-j721e-evm.c +++ b/configs/arm64/k3-j721e-evm.c @@ -22,7 +22,7 @@ struct { struct jailhouse_memory mem_regions[40]; struct jailhouse_irqchip irqchips[6]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[30]; + union jailhouse_stream_id stream_ids[30]; } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, diff --git a/configs/arm64/ultra96.c b/configs/arm64/ultra96.c index db65ae01..19be84ae 100644 --- a/configs/arm64/ultra96.c +++ b/configs/arm64/ultra96.c @@ -21,7 +21,7 @@ struct { struct jailhouse_memory mem_regions[11]; struct jailhouse_irqchip irqchips[1]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[2]; + union jailhouse_stream_id stream_ids[2]; } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, @@ -161,6 +161,13 @@ struct { }, .stream_ids = { - 0x870, 0x871 + { + .mmu500.mask = 0x0, + .mmu500.id = 0x870, + }, + { + .mmu500.mask = 0x0, + .mmu500.id = 0x871, + }, }, }; diff --git a/configs/arm64/zynqmp-zcu102.c b/configs/arm64/zynqmp-zcu102.c index bdcb04b3..1a5d29b3 100644 --- a/configs/arm64/zynqmp-zcu102.c +++ b/configs/arm64/zynqmp-zcu102.c @@ -23,7 +23,7 @@ struct { struct jailhouse_memory mem_regions[12]; struct jailhouse_irqchip irqchips[1]; struct jailhouse_pci_device pci_devices[2]; - __u32 stream_ids[8]; + union jailhouse_stream_id stream_ids[3]; } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, @@ -147,6 +147,17 @@ struct { }, .stream_ids = { - 0x860, 0x861, 0x870, 0x871, 0x874, 0x875, 0x876, 0x877 + { + .mmu500.mask = 0x0, + .mmu500.id = 0x860, + }, + { + .mmu500.mask = 0x0, + .mmu500.id = 0x861, + }, + { + .mmu500.mask = 0xf, + .mmu500.id = 0x870, + }, }, }; diff --git a/hypervisor/arch/arm64/smmu-v3.c b/hypervisor/arch/arm64/smmu-v3.c index d4b7529d..d306818e 100644 --- a/hypervisor/arch/arm64/smmu-v3.c +++ b/hypervisor/arch/arm64/smmu-v3.c @@ -1045,8 +1045,9 @@ static int arm_smmuv3_cell_init(struct cell *cell) struct arm_smmu_device *smmu = &smmu_devices[0]; struct jailhouse_iommu *iommu; struct arm_smmu_cmdq_ent cmd; - int ret, sid; + int ret; unsigned int n, s; + union jailhouse_stream_id sid; if (!iommu_count_units()) return 0; @@ -1057,7 +1058,7 @@ static int arm_smmuv3_cell_init(struct cell *cell) continue; for_each_stream_id(sid, cell->config, s) { - ret = arm_smmu_init_ste(smmu, sid, cell->config->id); + ret = arm_smmu_init_ste(smmu, sid.id, cell->config->id); if (ret) return ret; } @@ -1076,7 +1077,7 @@ static void arm_smmuv3_cell_exit(struct cell *cell) struct arm_smmu_device *smmu = &smmu_devices[0]; struct jailhouse_iommu *iommu; struct arm_smmu_cmdq_ent cmd; - int sid; + union jailhouse_stream_id sid; unsigned int n, s; if (!iommu_count_units()) @@ -1088,7 +1089,7 @@ static void arm_smmuv3_cell_exit(struct cell *cell) continue; for_each_stream_id(sid, cell->config, s) { - arm_smmu_uninit_ste(smmu, sid, cell->config->id); + arm_smmu_uninit_ste(smmu, sid.id, cell->config->id); } cmd.opcode = CMDQ_OP_TLBI_S12_VMALL; diff --git a/hypervisor/arch/arm64/smmu.c b/hypervisor/arch/arm64/smmu.c index df92fb7a..9c625c54 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; }; @@ -360,7 +363,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 +391,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 +400,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 +412,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 +426,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.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 +457,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_stream_id(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 +483,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 +493,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.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 +566,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/hypervisor/arch/arm64/ti-pvu.c b/hypervisor/arch/arm64/ti-pvu.c index 98c1fb5e..bbc633a0 100644 --- a/hypervisor/arch/arm64/ti-pvu.c +++ b/hypervisor/arch/arm64/ti-pvu.c @@ -444,7 +444,8 @@ int pvu_iommu_unmap_memory(struct cell *cell, void pvu_iommu_config_commit(struct cell *cell) { - unsigned int i, virtid; + unsigned int i; + union jailhouse_stream_id virtid; if (pvu_count == 0 || !cell) return; @@ -459,10 +460,10 @@ void pvu_iommu_config_commit(struct cell *cell) cell->arch.iommu_pvu.ent_count); for_each_stream_id(virtid, cell->config, i) { - if (virtid > MAX_VIRTID) + if (virtid.id > MAX_VIRTID) continue; - pvu_iommu_program_entries(cell, virtid); + pvu_iommu_program_entries(cell, virtid.id); } cell->arch.iommu_pvu.ent_count = 0; @@ -470,8 +471,9 @@ void pvu_iommu_config_commit(struct cell *cell) static int pvu_iommu_cell_init(struct cell *cell) { - unsigned int i, virtid; + unsigned int i; struct pvu_dev *dev; + union jailhouse_stream_id virtid; if (pvu_count == 0) return 0; @@ -484,10 +486,10 @@ static int pvu_iommu_cell_init(struct cell *cell) dev = &pvu_units[0]; for_each_stream_id(virtid, cell->config, i) { - if (virtid > MAX_VIRTID) + if (virtid.id > MAX_VIRTID) continue; - if (pvu_tlb_is_enabled(dev, virtid)) + if (pvu_tlb_is_enabled(dev, virtid.id)) return -EINVAL; } return 0; @@ -515,17 +517,18 @@ static int pvu_iommu_flush_context(u16 virtid) static void pvu_iommu_cell_exit(struct cell *cell) { - unsigned int i, virtid; + unsigned int i; + union jailhouse_stream_id virtid; if (pvu_count == 0) return; for_each_stream_id(virtid, cell->config, i) { - if (virtid > MAX_VIRTID) + if (virtid.id > MAX_VIRTID) continue; - pvu_iommu_flush_context(virtid); + pvu_iommu_flush_context(virtid.id); } cell->arch.iommu_pvu.ent_count = 0; diff --git a/include/jailhouse/cell-config.h b/include/jailhouse/cell-config.h index 472cb4bb..c94385b8 100644 --- a/include/jailhouse/cell-config.h +++ b/include/jailhouse/cell-config.h @@ -279,13 +279,18 @@ 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 { + __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; @@ -424,10 +429,11 @@ jailhouse_cell_pci_caps(const struct jailhouse_cell_desc *cell) cell->num_pci_devices * sizeof(struct jailhouse_pci_device)); } -static inline const __u32 * +static inline const union jailhouse_stream_id * jailhouse_cell_stream_ids(const struct jailhouse_cell_desc *cell) { - return (const __u32 *)((void *)jailhouse_cell_pci_caps(cell) + + return (const union jailhouse_stream_id *) + ((void *)jailhouse_cell_pci_caps(cell) + cell->num_pci_caps * sizeof(struct jailhouse_pci_capability)); } -- 2.29.2 -- 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/20201127114140.37179-1-andrea.bastoni%40tum.de.
