On Mon, 14 Jul 2025 16:59:40 +0100 Shameer Kolothum <shameerali.kolothum.th...@huawei.com> wrote:
> From: Nicolin Chen <nicol...@nvidia.com> > > Not all fields in the SMMU IDR registers are meaningful for userspace. > Only the following fields can be used: > > - IDR0: ST_LEVEL, TERM_MODEL, STALL_MODEL, TTENDIAN, CD2L, ASID16, TTF > - IDR1: SIDSIZE, SSIDSIZE > - IDR3: BBML, RIL > - IDR5: VAX, GRAN64K, GRAN16K, GRAN4K > > Use the relevant fields from these to check whether the host and emulated > SMMUv3 features are sufficiently aligned to enable accelerated SMMUv3 > support. > > To retrieve this information from the host, at least one vfio-pci device > must be assigned with "arm-smmuv3,accel=on" usage. Add a check to enforce > this. > > Note: > > ATS, PASID, and PRI features are currently not supported. Only devices > that do not require or make use of these features are expected to work. > > Also, requiring at least one vfio-pci device to be cold-plugged > complicates hot-unplug and replug scenarios. For example, if all devices > behind the vSMMUv3 are unplugged after the guest boots, and a new device > is later hot-plugged into the same PCI bus, there is no guarantee that > the underlying host SMMUv3 will expose the same feature set as the one > originally used when the vSMMU was initialized. > > Signed-off-by: Nicolin Chen <nicol...@nvidia.com> > Signed-off-by: Shameer Kolothum <shameerali.kolothum.th...@huawei.com> = > + > +void smmuv3_accel_init_regs(SMMUv3State *s) > +{ > + SMMUv3AccelState *s_accel = s->s_accel; > + SMMUv3AccelDevice *accel_dev; > + uint32_t data_type; > + uint32_t val; > + int ret; > + > + if (s_accel->info.idr[0]) { > + /* We already got this */ > + return; > + } > + > + if (!s_accel->viommu || QLIST_EMPTY(&s_accel->viommu->device_list)) { > + error_report("For arm-smmuv3,accel=on case, atleast one cold-plugged > " > + "vfio-pci dev needs to be assigned"); > + goto out_err; > + } > + > + accel_dev = QLIST_FIRST(&s_accel->viommu->device_list); > + ret = smmuv3_accel_host_hw_info(accel_dev, &data_type, > + sizeof(s_accel->info), &s_accel->info); > + if (ret) { > + error_report("Failed to get Host SMMU device info"); > + goto out_err; > + } > + > + if (data_type != IOMMU_HW_INFO_TYPE_ARM_SMMUV3) { > + error_report("Wrong data type (%d) for Host SMMU device info", > + data_type); > + goto out_err; > + } > + > + trace_smmuv3_accel_host_hw_info(s_accel->info.idr[0], > s_accel->info.idr[1], > + s_accel->info.idr[3], > s_accel->info.idr[5]); > + /* > + * QEMU SMMUv3 supports both linear and 2-level stream tables. If host > + * SMMUv3 supports only linear stream table, report that to Guest. > + */ > + val = FIELD_EX32(s_accel->info.idr[0], IDR0, STLEVEL); > + if (val < FIELD_EX32(s->idr[0], IDR0, STLEVEL)) { > + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STLEVEL, val); > + } > + > + /* > + * QEMU SMMUv3 supports little-endian support for translation table > walks. > + * If host SMMUv3 supports only big-endian, report error. > + */ > + val = FIELD_EX32(s_accel->info.idr[0], IDR0, TTENDIAN); > + if (val > FIELD_EX32(s->idr[0], IDR0, TTENDIAN)) { > + error_report("Host SUUMU device translation table walk endianess " > + "not supported"); > + goto out_err; > + } > + > + /* > + * QEMU SMMUv3 supports AArch64 Translation table format. > + * If host SMMUv3 supports only AArch32, report error. > + */ > + val = FIELD_EX32(s_accel->info.idr[0], IDR0, TTF); > + if (val < FIELD_EX32(s->idr[0], IDR0, TTF)) { > + error_report("Host SMMU device Translation table format not > supported"); > + goto out_err; > + } > + > + /* > + * QEMU SMMUv3 supports 4K/16K/64K translation granules. If host SMMUv3 > + * does't support any of these, report the supported ones only to Guest. > + */ > + val = FIELD_EX32(s_accel->info.idr[5], IDR5, GRAN4K); > + if (val < FIELD_EX32(s->idr[5], IDR5, GRAN4K)) { > + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, val); > + } > + val = FIELD_EX32(s_accel->info.idr[5], IDR5, GRAN16K); > + if (val < FIELD_EX32(s->idr[5], IDR5, GRAN16K)) { > + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, val); > + } > + val = FIELD_EX32(s_accel->info.idr[5], IDR5, GRAN64K); > + if (val < FIELD_EX32(s->idr[5], IDR5, GRAN64K)) { > + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, val); > + } > + return; > + > +out_err: > + exit(1); Maybe just do this at each error path rather than goto? Makes it clear that the result is brutal. > +} > + > static void > smmuv3_accel_dev_uninstall_nested_ste(SMMUv3AccelDevice *accel_dev, bool > abort) > { > diff --git a/hw/arm/trace-events b/hw/arm/trace-events > index 7d232ca17c..37ecab10a0 100644 > --- a/hw/arm/trace-events > +++ b/hw/arm/trace-events > @@ -70,7 +70,7 @@ smmu_reset_exit(void) "" > smmuv3_accel_set_iommu_device(int devfn, uint32_t sid) "devfn=0x%x > (sid=0x%x)" > smmuv3_accel_unset_iommu_device(int devfn, uint32_t sid) "devfn=0x%x > (sid=0x%x" > smmuv3_accel_install_nested_ste(uint32_t sid, uint64_t ste_1, uint64_t > ste_0) "sid=%d ste=%"PRIx64":%"PRIx64 > - Stray > +smmuv3_accel_host_hw_info(uint32_t idr0, uint32_t idr1, uint32_t idr3, > uint32_t idr5) "idr0=0x%x idr1=0x%x idr3=0x%x idr5=0x%x" > # strongarm.c > strongarm_uart_update_parameters(const char *label, int speed, char parity, > int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d" > strongarm_ssp_read_underrun(void) "SSP rx underrun"