diff options
Diffstat (limited to 'hw/pci-host/q35.c')
-rw-r--r-- | hw/pci-host/q35.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 37f228e77e..b20bad8373 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -347,6 +347,49 @@ static void mch_reset(DeviceState *qdev) mch_update(mch); } +static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) +{ + IntelIOMMUState *s = opaque; + VTDAddressSpace **pvtd_as; + int bus_num = pci_bus_num(bus); + + assert(0 <= bus_num && bus_num <= VTD_PCI_BUS_MAX); + assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX); + + pvtd_as = s->address_spaces[bus_num]; + if (!pvtd_as) { + /* No corresponding free() */ + pvtd_as = g_malloc0(sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX); + s->address_spaces[bus_num] = pvtd_as; + } + if (!pvtd_as[devfn]) { + pvtd_as[devfn] = g_malloc0(sizeof(VTDAddressSpace)); + + pvtd_as[devfn]->bus_num = (uint8_t)bus_num; + pvtd_as[devfn]->devfn = (uint8_t)devfn; + pvtd_as[devfn]->iommu_state = s; + pvtd_as[devfn]->context_cache_entry.context_cache_gen = 0; + memory_region_init_iommu(&pvtd_as[devfn]->iommu, OBJECT(s), + &s->iommu_ops, "intel_iommu", UINT64_MAX); + address_space_init(&pvtd_as[devfn]->as, + &pvtd_as[devfn]->iommu, "intel_iommu"); + } + return &pvtd_as[devfn]->as; +} + +static void mch_init_dmar(MCHPCIState *mch) +{ + PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); + + mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE)); + object_property_add_child(OBJECT(mch), "intel-iommu", + OBJECT(mch->iommu), NULL); + qdev_init_nofail(DEVICE(mch->iommu)); + sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); + + pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu); +} + static int mch_init(PCIDevice *d) { int i; @@ -363,12 +406,17 @@ static int mch_init(PCIDevice *d) memory_region_add_subregion_overlap(mch->system_memory, 0xa0000, &mch->smram_region, 1); memory_region_set_enabled(&mch->smram_region, false); - init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory, mch->pci_address_space, - &mch->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); + init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory, + mch->pci_address_space, &mch->pam_regions[0], + PAM_BIOS_BASE, PAM_BIOS_SIZE); for (i = 0; i < 12; ++i) { - init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory, mch->pci_address_space, - &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, - PAM_EXPAN_SIZE); + init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory, + mch->pci_address_space, &mch->pam_regions[i+1], + PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); + } + /* Intel IOMMU (VT-d) */ + if (qemu_opt_get_bool(qemu_get_machine_opts(), "iommu", false)) { + mch_init_dmar(mch); } return 0; } |