hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation
Allow cold-plugging of an SMMUv3 device on the virt machine when no global (legacy) SMMUv3 is present or when a virtio-iommu is specified. This user-created SMMUv3 device is tied to a specific PCI bus provided by the user, so ensure the IOMMU ops are configured accordingly. Due to current limitations in QEMU’s device tree support, specifically its inability to properly present pxb-pcie based root complexes and their devices, the device tree support for the new SMMUv3 device is limited to cases where it is attached to the default pcie.0 root complex. Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Tested-by: Nathan Chen <nathanc@nvidia.com> Tested-by: Eric Auger <eric.auger@redhat.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Reviewed-by: Donald Dutile <ddutile@redhat.com> Reviewed-by: Nicolin Chen <nicolinc@nvidia.com> Message-id: 20250829082543.7680-8-skolothumtho@nvidia.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
951bc76fb6
commit
66d2f665e1
5 changed files with 64 additions and 1 deletions
|
|
@ -961,7 +961,12 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
|
|||
goto out_err;
|
||||
}
|
||||
}
|
||||
pci_setup_iommu(pci_bus, &smmu_ops, s);
|
||||
|
||||
if (s->smmu_per_bus) {
|
||||
pci_setup_iommu_per_bus(pci_bus, &smmu_ops, s);
|
||||
} else {
|
||||
pci_setup_iommu(pci_bus, &smmu_ops, s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
out_err:
|
||||
|
|
@ -986,6 +991,7 @@ static void smmu_base_reset_exit(Object *obj, ResetType type)
|
|||
|
||||
static const Property smmu_dev_properties[] = {
|
||||
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
|
||||
DEFINE_PROP_BOOL("smmu_per_bus", SMMUState, smmu_per_bus, false),
|
||||
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
|
||||
TYPE_PCI_BUS, PCIBus *),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1996,6 +1996,8 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
|
|||
device_class_set_parent_realize(dc, smmu_realize,
|
||||
&c->parent_realize);
|
||||
device_class_set_props(dc, smmuv3_properties);
|
||||
dc->hotpluggable = false;
|
||||
dc->user_creatable = true;
|
||||
}
|
||||
|
||||
static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/pci-bridge/pci_expander_bridge.h"
|
||||
#include "hw/virtio/virtio-pci.h"
|
||||
|
|
@ -1475,6 +1476,29 @@ static void create_smmuv3_dt_bindings(const VirtMachineState *vms, hwaddr base,
|
|||
g_free(node);
|
||||
}
|
||||
|
||||
static void create_smmuv3_dev_dtb(VirtMachineState *vms,
|
||||
DeviceState *dev, PCIBus *bus)
|
||||
{
|
||||
PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
|
||||
SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
|
||||
int irq = platform_bus_get_irqn(pbus, sbdev, 0);
|
||||
hwaddr base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
if (!(vms->bootinfo.firmware_loaded && virt_is_acpi_enabled(vms)) &&
|
||||
strcmp("pcie.0", bus->qbus.name)) {
|
||||
warn_report("SMMUv3 device only supported with pcie.0 for DT");
|
||||
return;
|
||||
}
|
||||
base += vms->memmap[VIRT_PLATFORM_BUS].base;
|
||||
irq += vms->irqmap[VIRT_PLATFORM_BUS];
|
||||
|
||||
vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
create_smmuv3_dt_bindings(vms, base, SMMU_IO_LEN, irq);
|
||||
qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, 0x10000);
|
||||
}
|
||||
|
||||
static void create_smmu(const VirtMachineState *vms,
|
||||
PCIBus *bus)
|
||||
{
|
||||
|
|
@ -3006,6 +3030,16 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
|||
qlist_append_str(reserved_regions, resv_prop_str);
|
||||
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
|
||||
g_free(resv_prop_str);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
|
||||
if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
|
||||
error_setg(errp, "virt machine already has %s set. "
|
||||
"Doesn't support incompatible iommus",
|
||||
(vms->legacy_smmuv3_present) ?
|
||||
"iommu=smmuv3" : "virtio-iommu");
|
||||
} else if (vms->iommu == VIRT_IOMMU_NONE) {
|
||||
/* The new SMMUv3 device is specific to the PCI bus */
|
||||
object_property_set_bool(OBJECT(dev), "smmu_per_bus", true, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3029,6 +3063,22 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
|||
virtio_md_pci_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
|
||||
if (!vms->legacy_smmuv3_present && vms->platform_bus_dev) {
|
||||
PCIBus *bus;
|
||||
|
||||
bus = PCI_BUS(object_property_get_link(OBJECT(dev), "primary-bus",
|
||||
&error_abort));
|
||||
if (pci_bus_bypass_iommu(bus)) {
|
||||
error_setg(errp, "Bypass option cannot be set for SMMUv3 "
|
||||
"associated PCIe RC");
|
||||
return;
|
||||
}
|
||||
|
||||
create_smmuv3_dev_dtb(vms, dev, bus);
|
||||
}
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
||||
PCIDevice *pdev = PCI_DEVICE(dev);
|
||||
|
||||
|
|
@ -3231,6 +3281,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
|
|||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_ARM_SMMUV3);
|
||||
#ifdef CONFIG_TPM
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "qemu/error-report.h"
|
||||
#include "system/device_tree.h"
|
||||
#include "system/tpm.h"
|
||||
#include "hw/arm/smmuv3.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "hw/vfio/vfio-platform.h"
|
||||
#include "hw/vfio/vfio-calxeda-xgmac.h"
|
||||
|
|
@ -518,6 +519,8 @@ static const BindingEntry bindings[] = {
|
|||
#ifdef CONFIG_TPM
|
||||
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
|
||||
#endif
|
||||
/* No generic DT support for smmuv3 dev. Support added for arm virt only */
|
||||
TYPE_BINDING(TYPE_ARM_SMMUV3, no_fdt_node),
|
||||
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
|
||||
TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
|
||||
TYPE_BINDING("", NULL), /* last element */
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ struct SMMUState {
|
|||
QLIST_HEAD(, SMMUDevice) devices_with_notifiers;
|
||||
uint8_t bus_num;
|
||||
PCIBus *primary_bus;
|
||||
bool smmu_per_bus; /* SMMU is specific to the primary_bus */
|
||||
};
|
||||
|
||||
struct SMMUBaseClass {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue