On 05/08/2013 12:16 AM, Paolo Bonzini wrote: > From: Avi Kivity <avi.kiv...@gmail.com> > > Use the new iommu support in the memory core for iommu support. The only > user, spapr, is also converted, but it still provides a DMAContext > interface until the non-PCI bits switch to AddressSpace. > > Cc: Michael S. Tsirkin <m...@redhat.com> > Signed-off-by: Avi Kivity <avi.kiv...@gmail.com> > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> > --- > hw/pci/pci.c | 53 > ++++++++++++++++++++++++++-------------------- > hw/ppc/spapr_pci.c | 12 +++++++--- > include/hw/pci/pci.h | 7 ++++- > include/hw/pci/pci_bus.h | 5 ++- > 4 files changed, 46 insertions(+), 31 deletions(-) > > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > index 16ed118..3eb397c 100644 > --- a/hw/pci/pci.c > +++ b/hw/pci/pci.c > @@ -279,6 +279,16 @@ int pci_find_domain(const PCIBus *bus) > return -1; > } > > +static MemoryRegion *pci_default_iommu(PCIBus *bus, void *opaque, int devfn) > +{ > + /* FIXME: inherit memory region from bus creator */ > + return get_system_memory(); > +} > + > +static void pci_default_iommu_dtor(MemoryRegion *mr) > +{ > +} > + > static void pci_bus_init(PCIBus *bus, DeviceState *parent, > const char *name, > MemoryRegion *address_space_mem, > @@ -289,6 +299,7 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent, > bus->devfn_min = devfn_min; > bus->address_space_mem = address_space_mem; > bus->address_space_io = address_space_io; > + pci_setup_iommu(bus, pci_default_iommu, NULL, NULL); > > /* host bridge */ > QLIST_INIT(&bus->child); > @@ -801,21 +812,15 @@ static PCIDevice *do_pci_register_device(PCIDevice > *pci_dev, PCIBus *bus, > PCI_SLOT(devfn), PCI_FUNC(devfn), name, > bus->devices[devfn]->name); > return NULL; > } > + > pci_dev->bus = bus; > - if (bus->dma_context_fn) { > - pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, > devfn); > - } else { > - /* FIXME: Make dma_context_fn use MemoryRegions instead, so this > path is > - * taken unconditionally */ > - /* FIXME: inherit memory region from bus creator */ > - memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus > master", > - get_system_memory(), 0, > - memory_region_size(get_system_memory())); > - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); > - address_space_init(&pci_dev->bus_master_as, > &pci_dev->bus_master_enable_region); > - pci_dev->dma = g_new(DMAContext, 1); > - dma_context_init(pci_dev->dma, &pci_dev->bus_master_as); > - } > + pci_dev->iommu = bus->iommu_fn(bus, bus->iommu_opaque, devfn);
I tried to create a PCI bus on the default PHB and put e1000 onto it like this: -device pci-bridge,chassis_nr=1 -device e1000,bus=pci.0,addr=1.0 And I got a crash as bus->iommu_fn==NULL. Is it because we need this bridge to use parent's iommu_fn/iommu or pci-bridge is not supposed to be created this way or ...? I made small patch just to get one step further, the info qree is below. Now our system firmware fails (enters infinite loop) but this is a different story. diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 64a983c..a156053 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -811,7 +811,11 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, } pci_dev->bus = bus; - pci_dev->iommu = bus->iommu_fn(bus, bus->iommu_opaque, devfn); + if (bus->iommu_fn) + pci_dev->iommu = bus->iommu_fn(bus, bus->iommu_opaque, devfn); + else + pci_dev->iommu = bus->parent_dev->iommu; + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", pci_dev->iommu, 0, memory_region_size(pci_dev->iommu)); memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); dev: spapr-pci-host-bridge, id "" index = 0 buid = 0x800000020000000 liobn = 0x80000000 mem_win_addr = 0x100a0000000 mem_win_size = 0x20000000 io_win_addr = 0x10080000000 io_win_size = 0x10000 msi_win_addr = 0x10090000000 irq 0 bus: pci type PCI dev: pci-bridge, id "" chassis_nr = 1 msi = on addr = 00.0 romfile = <null> rombar = 1 multifunction = off command_serr_enable = on class PCI bridge, addr 00:00.0, pci id 1b36:0001 (sub 0000:0000) bar 0: mem at 0xffffffffffffffff [0xfe] bus: pci.0 type PCI dev: e1000, id "" mac = 52:54:00:12:34:57 vlan = <null> netdev = <null> bootindex = -1 autonegotiation = on addr = 01.0 romfile = "efi-e1000.rom" rombar = 1 multifunction = off command_serr_enable = on class Ethernet controller, addr 00:01.0, pci id 8086:100e (sub 1af4:1100) bar 0: mem at 0xffffffffffffffff [0x1fffe] bar 1: i/o at 0xffffffffffffffff [0x3e] > + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus > master", > + pci_dev->iommu, 0, > memory_region_size(pci_dev->iommu)); > + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); > + address_space_init(&pci_dev->bus_master_as, > &pci_dev->bus_master_enable_region); > + pci_dev->dma = g_new(DMAContext, 1); > + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as); > > pci_dev->devfn = devfn; > pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); > @@ -870,12 +875,12 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) > pci_dev->bus->devices[pci_dev->devfn] = NULL; > pci_config_free(pci_dev); > > - if (!pci_dev->bus->dma_context_fn) { > - address_space_destroy(&pci_dev->bus_master_as); > - memory_region_destroy(&pci_dev->bus_master_enable_region); > - g_free(pci_dev->dma); > - pci_dev->dma = NULL; > - } > + address_space_destroy(&pci_dev->bus_master_as); > + memory_region_del_subregion(&pci_dev->bus_master_enable_region, > pci_dev->iommu); > + pci_dev->bus->iommu_dtor_fn(pci_dev->iommu); > + memory_region_destroy(&pci_dev->bus_master_enable_region); > + g_free(pci_dev->dma); > + pci_dev->dma = NULL; > } > > static void pci_unregister_io_regions(PCIDevice *pci_dev) > @@ -2234,10 +2239,12 @@ static void pci_device_class_init(ObjectClass *klass, > void *data) > k->props = pci_props; > } > > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) > +void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, PCIIOMMUDestructorFunc > dtor, > + void *opaque) > { > - bus->dma_context_fn = fn; > - bus->dma_context_opaque = opaque; > + bus->iommu_fn = fn; > + bus->iommu_dtor_fn = dtor ? dtor : pci_default_iommu_dtor; > + bus->iommu_opaque = opaque; > } > > static const TypeInfo pci_device_type_info = { > diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c > index eb64a8f..ffbb45e 100644 > --- a/hw/ppc/spapr_pci.c > +++ b/hw/ppc/spapr_pci.c > @@ -506,12 +506,11 @@ static const MemoryRegionOps spapr_msi_ops = { > /* > * PHB PCI device > */ > -static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque, > - int devfn) > +static MemoryRegion *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int > devfn) > { > sPAPRPHBState *phb = opaque; > > - return spapr_tce_get_dma(phb->tcet); > + return spapr_tce_get_iommu(phb->tcet); > } > > static int spapr_phb_init(SysBusDevice *s) > @@ -651,7 +655,7 @@ static int spapr_phb_init(SysBusDevice *s) > fprintf(stderr, "Unable to create TCE table for %s\n", > sphb->dtbusname); > return -1; > } > - pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb); > + pci_setup_iommu(bus, spapr_pci_dma_iommu, NULL, sphb); > > QLIST_INSERT_HEAD(&spapr->phbs, sphb, list); > > diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h > index 8d075ab..7e7b0f4 100644 > --- a/include/hw/pci/pci.h > +++ b/include/hw/pci/pci.h > @@ -242,6 +242,7 @@ struct PCIDevice { > PCIIORegion io_regions[PCI_NUM_REGIONS]; > AddressSpace bus_master_as; > MemoryRegion bus_master_enable_region; > + MemoryRegion *iommu; > DMAContext *dma; > > /* do not access the following fields */ > @@ -401,9 +402,11 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int > *domp, int *busp, > > void pci_device_deassert_intx(PCIDevice *dev); > > -typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int); > +typedef MemoryRegion *(*PCIIOMMUFunc)(PCIBus *, void *, int); > +typedef void (*PCIIOMMUDestructorFunc)(MemoryRegion *mr); > > -void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque); > +void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, PCIIOMMUDestructorFunc > dtor, > + void *opaque); > > static inline void > pci_set_byte(uint8_t *config, uint8_t val) > diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h > index 6ee443c..fada8f5 100644 > --- a/include/hw/pci/pci_bus.h > +++ b/include/hw/pci/pci_bus.h > @@ -10,8 +10,9 @@ > > struct PCIBus { > BusState qbus; > - PCIDMAContextFunc dma_context_fn; > - void *dma_context_opaque; > + PCIIOMMUFunc iommu_fn; > + PCIIOMMUDestructorFunc iommu_dtor_fn; > + void *iommu_opaque; > uint8_t devfn_min; > pci_set_irq_fn set_irq; > pci_map_irq_fn map_irq; > -- Alexey