pci: Add pci_device_get_host_irq
PATCH 1/2 pci: Add pci_device_get_host_irq
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced: map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.
Will be used for KVM PCI device assignment.
--- hw/alpha_typhoon.c | 2 +- hw/apb_pci.c | 2 +- hw/bonito.c | 2 +- hw/grackle_pci.c | 1 + hw/gt64xxx.c | 2 +- hw/pci.c | 23 ++++++++++++++++++++--- hw/pci.h | 7 +++++-- hw/pci_internals.h | 1 + hw/piix_pci.c | 15 ++++++++++++--- hw/ppc4xx_pci.c | 2 +- hw/ppce500_pci.c | 2 +- hw/prep_pci.c | 2 +- hw/sh_pci.c | 2 +- hw/spapr_pci.c | 2 +- hw/unin_pci.c | 4 ++-- hw/versatile_pci.c | 2 +- 16 files changed, 51 insertions(+), 20 deletions(-)
hw/alpha_typhoon.c +1 -1
@@ -764,7 +764,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, &s->pchip.reg_io); b =pci_register_bus (&s->host.busdev.qdev,"pci" , - typhoon_set_irq, sys_map_irq, s, + typhoon_set_irq, sys_map_irq,NULL , s, &s->pchip.reg_mem, addr_space_io,0 ,64 ); s->host.bus = b;
hw/apb_pci.c +1 -1
@@ -366,7 +366,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,memory_region_add_subregion (get_system_memory (), mem_base, &d->pci_mmio); d->bus =pci_register_bus (&d->busdev.qdev,"pci" , - pci_apb_set_irq, pci_pbm_map_irq, d, + pci_apb_set_irq, pci_pbm_map_irq,NULL , d, &d->pci_mmio,get_system_io (),0 ,32 );
hw/bonito.c +1 -1
@@ -750,7 +750,7 @@ PCIBus *bonito_init(qemu_irq *pic) dev =qdev_create (NULL ,"Bonito-pcihost" ); pcihost =FROM_SYSBUS (BonitoState,sysbus_from_qdev (dev)); b =pci_register_bus (&pcihost->busdev.qdev,"pci" , pci_bonito_set_irq, - pci_bonito_map_irq, pic,get_system_memory (), + pci_bonito_map_irq,NULL , pic,get_system_memory (),get_system_io (),0x28 ,32 ); pcihost->bus = b;
hw/grackle_pci.c +1 -0
@@ -85,6 +85,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", pci_grackle_set_irq, pci_grackle_map_irq, + NULL, pic, &d->pci_mmio, address_space_io,
hw/gt64xxx.c +1 -1
@@ -1093,7 +1093,7 @@ PCIBus *gt64120_register(qemu_irq *pic) d =FROM_SYSBUS (GT64120State, s); d->pci.bus =pci_register_bus (&d->busdev.qdev,"pci" , gt64120_pci_set_irq, gt64120_pci_map_irq, - pic, +NULL , pic,get_system_memory (),get_system_io (),PCI_DEVFN (18 ,0 ),4 );
hw/pci.c +20 -3
@@ -298,10 +298,11 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, }void pci_bus_irqs (PCIBus *bus,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque,int nirq) +pci_map_host_irq_fn map_host_irq,void *irq_opaque,int nirq) { bus->set_irq = set_irq; bus->map_irq = map_irq; + bus->map_host_irq = map_host_irq; bus->irq_opaque = irq_opaque; bus->nirq = nirq; bus->irq_count =g_malloc0 (nirq *sizeof (bus->irq_count[0 ]));
@@ -316,7 +317,7 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)PCIBus *pci_register_bus (DeviceState *parent,const char *name,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque, +pci_map_host_irq_fn map_host_irq,void *irq_opaque,MemoryRegion *address_space_mem,MemoryRegion *address_space_io,uint8_t devfn_min,int nirq)
@@ -325,7 +326,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, bus =pci_bus_new (parent, name, address_space_mem, address_space_io, devfn_min); -pci_bus_irqs (bus, set_irq, map_irq, irq_opaque, nirq); +pci_bus_irqs (bus, set_irq, map_irq, map_host_irq, irq_opaque, nirq);return bus; }
@@ -1067,6 +1068,22 @@ static void pci_set_irq(void *opaque, int irq_num, int level)pci_change_irq_level (pci_dev, irq_num, change); } +int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num) +{ +PCIBus *bus; + +for (;;) { + bus = pci_dev->bus; + irq_num = bus->map_irq (pci_dev, irq_num); +if (bus->map_host_irq) { +break ; + } + pci_dev = bus->parent_dev; +assert (pci_dev); + } +return bus->map_host_irq (bus->irq_opaque, irq_num); +} +/***********************************************************/ /* monitor info on PCI */
hw/pci.h +5 -2
@@ -276,6 +276,7 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev);typedef void (*pci_set_irq_fn )(void *opaque,int irq_num,int level);typedef int (*pci_map_irq_fn )(PCIDevice *pci_dev,int irq_num); +typedef int (*pci_map_host_irq_fn )(void *opaque,int irq_num); typedef enum { PCI_HOTPLUG_DISABLED,
@@ -295,15 +296,17 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,MemoryRegion *address_space_io, uint8_t devfn_min);void pci_bus_irqs (PCIBus *bus,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque,int nirq); +pci_map_host_irq_fn map_host_irq,void *irq_opaque, +int nirq);int pci_bus_get_irq_level (PCIBus *bus,int irq_num);void pci_bus_hotplug (PCIBus *bus,pci_hotplug_fn hotplug,DeviceState *dev);PCIBus *pci_register_bus (DeviceState *parent,const char *name,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque, +pci_map_host_irq_fn map_host_irq,void *irq_opaque,MemoryRegion *address_space_mem,MemoryRegion *address_space_io,uint8_t devfn_min,int nirq); +int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num);void pci_device_reset (PCIDevice *dev);void pci_bus_reset (PCIBus *bus);
hw/pci_internals.h +1 -0
@@ -19,6 +19,7 @@ struct PCIBus {uint8_t devfn_min;pci_set_irq_fn set_irq;pci_map_irq_fn map_irq; +pci_map_host_irq_fn map_host_irq;pci_hotplug_fn hotplug;DeviceState *hotplug_qdev;void *irq_opaque;
hw/piix_pci.c +12 -3
@@ -89,6 +89,7 @@ struct PCII440FXState {#define I440FX_SMRAM 0x72static void piix3_set_irq (void *opaque,int pirq,int level); +static int piix3_map_host_irq (void *opaque,int pci_intx);static void piix3_write_config_xen (PCIDevice *dev,uint32_t address,uint32_t val,int len);
@@ -308,13 +309,13 @@ static PCIBus *i440fx_common_init(const char *device_name,if (xen_enabled ()) { piix3 =DO_UPCAST (PIIX3State, dev,pci_create_simple_multifunction (b,-1 , true,"PIIX3-xen" )); -pci_bus_irqs (b, xen_piix3_set_irq, xen_pci_slot_get_pirq, +pci_bus_irqs (b, xen_piix3_set_irq, xen_pci_slot_get_pirq,NULL , piix3,XEN_PIIX_NUM_PIRQS ); }else { piix3 =DO_UPCAST (PIIX3State, dev,pci_create_simple_multifunction (b,-1 , true,"PIIX3" )); -pci_bus_irqs (b, piix3_set_irq, pci_slot_get_pirq, piix3, -PIIX_NUM_PIRQS ); +pci_bus_irqs (b, piix3_set_irq, pci_slot_get_pirq, piix3_map_host_irq, + piix3,PIIX_NUM_PIRQS ); } piix3->pic = pic; *isa_bus = DO_UPCAST(ISABus, qbus,
@@ -386,6 +387,14 @@ static void piix3_set_irq(void *opaque, int pirq, int level)piix3_set_irq_level (piix3, pirq, level); } +static int piix3_map_host_irq (void *opaque,int pci_intx) +{ +PIIX3State *piix3 = opaque; +int host_irq = piix3->dev.config[PIIX_PIRQC + pci_intx]; + +return host_irq <PIIX_NUM_PIC_IRQS ? host_irq :-1 ; +} +/* irq routing is changed. so rebuild bitmap */ static void piix3_update_irq_levels (PIIX3State *piix3) {
hw/ppc4xx_pci.c +1 -1
@@ -343,7 +343,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) } b =pci_register_bus (&s->pci_state.busdev.qdev,NULL , ppc4xx_pci_set_irq, - ppc4xx_pci_map_irq, s->irq,get_system_memory (), + ppc4xx_pci_map_irq,NULL , s->irq,get_system_memory (),get_system_io (),0 ,4 ); s->pci_state.bus = b;
hw/ppce500_pci.c +1 -1
@@ -318,7 +318,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) } b =pci_register_bus (&s->pci_state.busdev.qdev,NULL , mpc85xx_pci_set_irq, - mpc85xx_pci_map_irq, s->irq, address_space_mem, + mpc85xx_pci_map_irq,NULL , s->irq, address_space_mem, address_space_io,PCI_DEVFN (0x11 ,0 ),4 ); s->pci_state.bus = b;
hw/prep_pci.c +1 -1
@@ -108,7 +108,7 @@ static int raven_pcihost_init(SysBusDevice *dev) } bus =pci_register_bus (&h->busdev.qdev,NULL , - prep_set_irq, prep_map_irq, s->irq, + prep_set_irq, prep_map_irq,NULL , s->irq, address_space_mem, address_space_io,0 ,4 ); h->bus = bus;
hw/sh_pci.c +1 -1
@@ -120,7 +120,7 @@ static int sh_pci_device_init(SysBusDevice *dev)sysbus_init_irq (dev, &s->irq[i]); } s->bus = pci_register_bus(&s->busdev.qdev, "pci", - sh_pci_set_irq, sh_pci_map_irq, + sh_pci_set_irq, sh_pci_map_irq, NULL, s->irq, get_system_memory(), get_system_io(),
hw/spapr_pci.c +1 -1
@@ -306,7 +306,7 @@ static int spapr_phb_init(SysBusDevice *s) bus =pci_register_bus (&phb->busdev.qdev, phb->busname ? phb->busname : phb->dtbusname, - pci_spapr_set_irq, pci_spapr_map_irq, phb, + pci_spapr_set_irq, pci_spapr_map_irq,NULL , phb, &phb->memspace, &phb->iospace,PCI_DEVFN (0 ,0 ),PCI_NUM_PINS ); phb->host_state.bus = bus;
hw/unin_pci.c +2 -2
@@ -227,7 +227,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, d->host_state.bus =pci_register_bus (dev,"pci" , pci_unin_set_irq, pci_unin_map_irq, - pic, +NULL , pic, &d->pci_mmio, address_space_io,PCI_DEVFN (11 ,0 ),4 );
@@ -293,7 +293,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, d->host_state.bus =pci_register_bus (dev,"pci" , pci_unin_set_irq, pci_unin_map_irq, - pic, +NULL , pic, &d->pci_mmio, address_space_io,PCI_DEVFN (11 ,0 ),4 );
hw/versatile_pci.c +1 -1
@@ -68,7 +68,7 @@ static int pci_vpb_init(SysBusDevice *dev)sysbus_init_irq (dev, &s->irq[i]); } bus =pci_register_bus (&dev->qdev,"pci" , - pci_vpb_set_irq, pci_vpb_map_irq, s->irq, + pci_vpb_set_irq, pci_vpb_map_irq,NULL , s->irq,get_system_memory (),get_system_io (),PCI_DEVFN (11 ,0 ),4 );
Signature · 1 line
1.7.3.4
PATCH 2/2 pci: Add INTx routing notifier
This per-device notifier shall be triggered by any interrupt router along the path of a device's legacy interrupt signal on routing changes. For simplicity reasons and as this is a slow path anyway, no further details on the routing changes are provided. Instead, the callback is expected to use pci_device_get_host_irq to check the effect of the change.
Will be used by KVM PCI device assignment.
--- hw/pci.c | 19 +++++++++++++++++++ hw/pci.h | 7 +++++++ hw/pci_bridge.c | 8 ++++++++ hw/piix_pci.c | 2 ++ 4 files changed, 36 insertions(+), 0 deletions(-)
hw/pci.c +19 -0
@@ -1084,6 +1084,25 @@ int pci_device_get_host_irq(PCIDevice *pci_dev, int irq_num)return bus->map_host_irq (bus->irq_opaque, irq_num); } +void pci_bus_fire_intx_routing_notifier (PCIBus *bus) +{ +PCIDevice *dev; +int i; + +for (i =0 ; i <ARRAY_SIZE (bus->devices); ++i) { + dev = bus->devices[i]; +if (dev && dev->intx_routing_notifier) { + dev->intx_routing_notifier (dev); + } + } +} + +void pci_device_set_intx_routing_notifier (PCIDevice *pci_dev, +INTxRoutingNotifier notifier) +{ + pci_dev->intx_routing_notifier = notifier; +} +/***********************************************************/ /* monitor info on PCI */
hw/pci.h +7 -0
@@ -173,6 +173,7 @@ typedef struct PCIDeviceClass {const char *romfile; } PCIDeviceClass; +typedef void (*INTxRoutingNotifier )(PCIDevice *dev);typedef int (*MSIVectorUseNotifier )(PCIDevice *dev,unsigned int vector,MSIMessage msg);typedef void (*MSIVectorReleaseNotifier )(PCIDevice *dev,unsigned int vector);
@@ -248,6 +249,9 @@ struct PCIDevice {MemoryRegion rom;uint32_t rom_bar; +/* INTx routing notifier */ +INTxRoutingNotifier intx_routing_notifier; +/* MSI-X notifiers */ MSIVectorUseNotifier msix_vector_use_notifier;MSIVectorReleaseNotifier msix_vector_release_notifier;
@@ -307,6 +311,9 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,MemoryRegion *address_space_io, uint8_t devfn_min, int nirq);int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num); +void pci_bus_fire_intx_routing_notifier (PCIBus *bus); +void pci_device_set_intx_routing_notifier (PCIDevice *pci_dev, +INTxRoutingNotifier notifier);void pci_device_reset (PCIDevice *dev);void pci_bus_reset (PCIBus *bus);
hw/pci_bridge.c +8 -0
@@ -292,6 +292,13 @@ void pci_bridge_reset(DeviceState *qdev)pci_set_word (conf +PCI_BRIDGE_CONTROL ,0 ); } +static void pci_bridge_intx_routing_update (PCIDevice *dev) +{ +PCIBridge *br =DO_UPCAST (PCIBridge, dev, dev); + +pci_bus_fire_intx_routing_notifier (&br->sec_bus); +} +/* default qdev initialization function for PCI-to-PCI bridge */ int pci_bridge_initfn (PCIDevice *dev) {
@@ -327,6 +334,7 @@ int pci_bridge_initfn(PCIDevice *dev) sec_bus->address_space_io = &br->address_space_io;memory_region_init (&br->address_space_io,"pci_bridge_io" ,65536 );pci_bridge_region_init (br); +pci_device_set_intx_routing_notifier (dev, pci_bridge_intx_routing_update);QLIST_INIT (&sec_bus->child);QLIST_INSERT_HEAD (&parent->child, sec_bus, sibling);return 0 ;
hw/piix_pci.c +2 -0
@@ -414,6 +414,8 @@ static void piix3_write_config(PCIDevice *dev,if (ranges_overlap (address, len,PIIX_PIRQC ,4 )) {PIIX3State *piix3 =DO_UPCAST (PIIX3State, dev, dev);int pic_irq; + +pci_bus_fire_intx_routing_notifier (piix3->dev.bus);piix3_update_irq_levels (piix3);for (pic_irq =0 ; pic_irq <PIIX_NUM_PIC_IRQS ; pic_irq++) {piix3_set_irq_pic (piix3, pic_irq);
Signature · 1 line
1.7.3.4
Re: [Qemu-devel] [PATCH 2/2] pci: Add INTx routing notifier
Quoted 8 lines · Jan Kiszka
This per-device notifier shall be triggered by any interrupt router along the path of a device's legacy interrupt signal on routing changes. For simplicity reasons and as this is a slow path anyway, no further details on the routing changes are provided. Instead, the callback is expected to use
pci_device_get_host_irqto check the effect of the change.Will be used by KVM PCI device assignment.
I think we could do this without inventing our out notifier mechanism, Notifier + NotifierList, but it's better than what we've got now. VFIO will use this too.
Quoted 110 lines
Signed-off-by Jan Kiszka <[email protected]>--- hw/pci.c | 19 +++++++++++++++++++ hw/pci.h | 7 +++++++ hw/pci_bridge.c | 8 ++++++++ hw/piix_pci.c | 2 ++ 4 files changed, 36 insertions(+), 0 deletions(-)hw/pci.c +19
-0@@ -1084,6 +1084,25 @@ int pci_device_get_host_irq(PCIDevice *pci_dev, int irq_num)return bus->map_host_irq (bus->irq_opaque, irq_num); } +void pci_bus_fire_intx_routing_notifier (PCIBus *bus) +{ +PCIDevice *dev; +int i; + +for (i =0 ; i <ARRAY_SIZE (bus->devices); ++i) { + dev = bus->devices[i]; +if (dev && dev->intx_routing_notifier) { + dev->intx_routing_notifier (dev); + } + } +} + +void pci_device_set_intx_routing_notifier (PCIDevice *pci_dev, +INTxRoutingNotifier notifier) +{ + pci_dev->intx_routing_notifier = notifier; +} +/***********************************************************/ /* monitor info on PCI */ hw/pci.h +7
-0@@ -173,6 +173,7 @@ typedef struct PCIDeviceClass {const char *romfile; } PCIDeviceClass; +typedef void (*INTxRoutingNotifier )(PCIDevice *dev);typedef int (*MSIVectorUseNotifier )(PCIDevice *dev,unsigned int vector,MSIMessage msg);typedef void (*MSIVectorReleaseNotifier )(PCIDevice *dev,unsigned int vector);@@ -248,6 +249,9 @@ struct PCIDevice {MemoryRegion rom;uint32_t rom_bar; +/* INTx routing notifier */ +INTxRoutingNotifier intx_routing_notifier; +/* MSI-X notifiers */ MSIVectorUseNotifier msix_vector_use_notifier;MSIVectorReleaseNotifier msix_vector_release_notifier;@@ -307,6 +311,9 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,MemoryRegion *address_space_io, uint8_t devfn_min, int nirq);int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num); +void pci_bus_fire_intx_routing_notifier (PCIBus *bus); +void pci_device_set_intx_routing_notifier (PCIDevice *pci_dev, +INTxRoutingNotifier notifier);void pci_device_reset (PCIDevice *dev);void pci_bus_reset (PCIBus *bus);hw/pci_bridge.c +8
-0@@ -292,6 +292,13 @@ void pci_bridge_reset(DeviceState *qdev)pci_set_word (conf +PCI_BRIDGE_CONTROL ,0 ); } +static void pci_bridge_intx_routing_update (PCIDevice *dev) +{ +PCIBridge *br =DO_UPCAST (PCIBridge, dev, dev); + +pci_bus_fire_intx_routing_notifier (&br->sec_bus); +} +/* default qdev initialization function for PCI-to-PCI bridge */ int pci_bridge_initfn (PCIDevice *dev) {@@ -327,6 +334,7 @@ int pci_bridge_initfn(PCIDevice *dev) sec_bus->address_space_io = &br->address_space_io;memory_region_init (&br->address_space_io,"pci_bridge_io" ,65536 );pci_bridge_region_init (br); +pci_device_set_intx_routing_notifier (dev, pci_bridge_intx_routing_update);QLIST_INIT (&sec_bus->child);QLIST_INSERT_HEAD (&parent->child, sec_bus, sibling);return 0 ;hw/piix_pci.c +2
-0@@ -414,6 +414,8 @@ static void piix3_write_config(PCIDevice *dev,if (ranges_overlap (address, len,PIIX_PIRQC ,4 )) {PIIX3State *piix3 =DO_UPCAST (PIIX3State, dev, dev);int pic_irq; + +pci_bus_fire_intx_routing_notifier (piix3->dev.bus);piix3_update_irq_levels (piix3);for (pic_irq =0 ; pic_irq <PIIX_NUM_PIC_IRQS ; pic_irq++) {piix3_set_irq_pic (piix3, pic_irq);
Quoted 8 lines · Jan Kiszka
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced:
map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.Will be used for KVM PCI device assignment.
And VFIO. Not so different from the get_irq function I added in the VFIO tree.
Quoted 330 lines
Signed-off-by Jan Kiszka <[email protected]>--- hw/alpha_typhoon.c | 2 +- hw/apb_pci.c | 2 +- hw/bonito.c | 2 +- hw/grackle_pci.c | 1 + hw/gt64xxx.c | 2 +- hw/pci.c | 23 ++++++++++++++++++++--- hw/pci.h | 7 +++++-- hw/pci_internals.h | 1 + hw/piix_pci.c | 15 ++++++++++++--- hw/ppc4xx_pci.c | 2 +- hw/ppce500_pci.c | 2 +- hw/prep_pci.c | 2 +- hw/sh_pci.c | 2 +- hw/spapr_pci.c | 2 +- hw/unin_pci.c | 4 ++-- hw/versatile_pci.c | 2 +- 16 files changed, 51 insertions(+), 20 deletions(-)hw/alpha_typhoon.c +1
-1@@ -764,7 +764,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, &s->pchip.reg_io); b =pci_register_bus (&s->host.busdev.qdev,"pci" , - typhoon_set_irq, sys_map_irq, s, + typhoon_set_irq, sys_map_irq,NULL , s, &s->pchip.reg_mem, addr_space_io,0 ,64 ); s->host.bus = b;hw/apb_pci.c +1
-1@@ -366,7 +366,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,memory_region_add_subregion (get_system_memory (), mem_base, &d->pci_mmio); d->bus =pci_register_bus (&d->busdev.qdev,"pci" , - pci_apb_set_irq, pci_pbm_map_irq, d, + pci_apb_set_irq, pci_pbm_map_irq,NULL , d, &d->pci_mmio,get_system_io (),0 ,32 );hw/bonito.c +1
-1@@ -750,7 +750,7 @@ PCIBus *bonito_init(qemu_irq *pic) dev =qdev_create (NULL ,"Bonito-pcihost" ); pcihost =FROM_SYSBUS (BonitoState,sysbus_from_qdev (dev)); b =pci_register_bus (&pcihost->busdev.qdev,"pci" , pci_bonito_set_irq, - pci_bonito_map_irq, pic,get_system_memory (), + pci_bonito_map_irq,NULL , pic,get_system_memory (),get_system_io (),0x28 ,32 ); pcihost->bus = b;hw/grackle_pci.c +1
-0@@ -85,6 +85,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", pci_grackle_set_irq, pci_grackle_map_irq, + NULL, pic, &d->pci_mmio, address_space_io,hw/gt64xxx.c +1
-1@@ -1093,7 +1093,7 @@ PCIBus *gt64120_register(qemu_irq *pic) d =FROM_SYSBUS (GT64120State, s); d->pci.bus =pci_register_bus (&d->busdev.qdev,"pci" , gt64120_pci_set_irq, gt64120_pci_map_irq, - pic, +NULL , pic,get_system_memory (),get_system_io (),PCI_DEVFN (18 ,0 ),4 );hw/pci.c +20
-3@@ -298,10 +298,11 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, }void pci_bus_irqs (PCIBus *bus,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque,int nirq) +pci_map_host_irq_fn map_host_irq,void *irq_opaque,int nirq) { bus->set_irq = set_irq; bus->map_irq = map_irq; + bus->map_host_irq = map_host_irq; bus->irq_opaque = irq_opaque; bus->nirq = nirq; bus->irq_count =g_malloc0 (nirq *sizeof (bus->irq_count[0 ]));@@ -316,7 +317,7 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)PCIBus *pci_register_bus (DeviceState *parent,const char *name,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque, +pci_map_host_irq_fn map_host_irq,void *irq_opaque,MemoryRegion *address_space_mem,MemoryRegion *address_space_io,uint8_t devfn_min,int nirq)@@ -325,7 +326,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, bus =pci_bus_new (parent, name, address_space_mem, address_space_io, devfn_min); -pci_bus_irqs (bus, set_irq, map_irq, irq_opaque, nirq); +pci_bus_irqs (bus, set_irq, map_irq, map_host_irq, irq_opaque, nirq);return bus; }@@ -1067,6 +1068,22 @@ static void pci_set_irq(void *opaque, int irq_num, int level)pci_change_irq_level (pci_dev, irq_num, change); } +int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num) +{ +PCIBus *bus; + +for (;;) { + bus = pci_dev->bus; + irq_num = bus->map_irq (pci_dev, irq_num); +if (bus->map_host_irq) { +break ; + } + pci_dev = bus->parent_dev; +assert (pci_dev); + } +return bus->map_host_irq (bus->irq_opaque, irq_num); +} +/***********************************************************/ /* monitor info on PCI */ hw/pci.h +5
-2@@ -276,6 +276,7 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev);typedef void (*pci_set_irq_fn )(void *opaque,int irq_num,int level);typedef int (*pci_map_irq_fn )(PCIDevice *pci_dev,int irq_num); +typedef int (*pci_map_host_irq_fn )(void *opaque,int irq_num); typedef enum { PCI_HOTPLUG_DISABLED,@@ -295,15 +296,17 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,MemoryRegion *address_space_io, uint8_t devfn_min);void pci_bus_irqs (PCIBus *bus,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque,int nirq); +pci_map_host_irq_fn map_host_irq,void *irq_opaque, +int nirq);int pci_bus_get_irq_level (PCIBus *bus,int irq_num);void pci_bus_hotplug (PCIBus *bus,pci_hotplug_fn hotplug,DeviceState *dev);PCIBus *pci_register_bus (DeviceState *parent,const char *name,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque, +pci_map_host_irq_fn map_host_irq,void *irq_opaque,MemoryRegion *address_space_mem,MemoryRegion *address_space_io,uint8_t devfn_min,int nirq); +int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num);void pci_device_reset (PCIDevice *dev);void pci_bus_reset (PCIBus *bus);hw/pci_internals.h +1
-0@@ -19,6 +19,7 @@ struct PCIBus {uint8_t devfn_min;pci_set_irq_fn set_irq;pci_map_irq_fn map_irq; +pci_map_host_irq_fn map_host_irq;pci_hotplug_fn hotplug;DeviceState *hotplug_qdev;void *irq_opaque;hw/piix_pci.c +12
-3@@ -89,6 +89,7 @@ struct PCII440FXState {#define I440FX_SMRAM 0x72static void piix3_set_irq (void *opaque,int pirq,int level); +static int piix3_map_host_irq (void *opaque,int pci_intx);static void piix3_write_config_xen (PCIDevice *dev,uint32_t address,uint32_t val,int len);@@ -308,13 +309,13 @@ static PCIBus *i440fx_common_init(const char *device_name,if (xen_enabled ()) { piix3 =DO_UPCAST (PIIX3State, dev,pci_create_simple_multifunction (b,-1 , true,"PIIX3-xen" )); -pci_bus_irqs (b, xen_piix3_set_irq, xen_pci_slot_get_pirq, +pci_bus_irqs (b, xen_piix3_set_irq, xen_pci_slot_get_pirq,NULL , piix3,XEN_PIIX_NUM_PIRQS ); }else { piix3 =DO_UPCAST (PIIX3State, dev,pci_create_simple_multifunction (b,-1 , true,"PIIX3" )); -pci_bus_irqs (b, piix3_set_irq, pci_slot_get_pirq, piix3, -PIIX_NUM_PIRQS ); +pci_bus_irqs (b, piix3_set_irq, pci_slot_get_pirq, piix3_map_host_irq, + piix3,PIIX_NUM_PIRQS ); } piix3->pic = pic; *isa_bus = DO_UPCAST(ISABus, qbus,@@ -386,6 +387,14 @@ static void piix3_set_irq(void *opaque, int pirq, int level)piix3_set_irq_level (piix3, pirq, level); } +static int piix3_map_host_irq (void *opaque,int pci_intx) +{ +PIIX3State *piix3 = opaque; +int host_irq = piix3->dev.config[PIIX_PIRQC + pci_intx]; + +return host_irq <PIIX_NUM_PIC_IRQS ? host_irq :-1 ; +} +/* irq routing is changed. so rebuild bitmap */ static void piix3_update_irq_levels (PIIX3State *piix3) {hw/ppc4xx_pci.c +1
-1@@ -343,7 +343,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) } b =pci_register_bus (&s->pci_state.busdev.qdev,NULL , ppc4xx_pci_set_irq, - ppc4xx_pci_map_irq, s->irq,get_system_memory (), + ppc4xx_pci_map_irq,NULL , s->irq,get_system_memory (),get_system_io (),0 ,4 ); s->pci_state.bus = b;hw/ppce500_pci.c +1
-1@@ -318,7 +318,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) } b =pci_register_bus (&s->pci_state.busdev.qdev,NULL , mpc85xx_pci_set_irq, - mpc85xx_pci_map_irq, s->irq, address_space_mem, + mpc85xx_pci_map_irq,NULL , s->irq, address_space_mem, address_space_io,PCI_DEVFN (0x11 ,0 ),4 ); s->pci_state.bus = b;hw/prep_pci.c +1
-1@@ -108,7 +108,7 @@ static int raven_pcihost_init(SysBusDevice *dev) } bus =pci_register_bus (&h->busdev.qdev,NULL , - prep_set_irq, prep_map_irq, s->irq, + prep_set_irq, prep_map_irq,NULL , s->irq, address_space_mem, address_space_io,0 ,4 ); h->bus = bus;hw/sh_pci.c +1
-1@@ -120,7 +120,7 @@ static int sh_pci_device_init(SysBusDevice *dev)sysbus_init_irq (dev, &s->irq[i]); } s->bus = pci_register_bus(&s->busdev.qdev, "pci", - sh_pci_set_irq, sh_pci_map_irq, + sh_pci_set_irq, sh_pci_map_irq, NULL, s->irq, get_system_memory(), get_system_io(),hw/spapr_pci.c +1
-1@@ -306,7 +306,7 @@ static int spapr_phb_init(SysBusDevice *s) bus =pci_register_bus (&phb->busdev.qdev, phb->busname ? phb->busname : phb->dtbusname, - pci_spapr_set_irq, pci_spapr_map_irq, phb, + pci_spapr_set_irq, pci_spapr_map_irq,NULL , phb, &phb->memspace, &phb->iospace,PCI_DEVFN (0 ,0 ),PCI_NUM_PINS ); phb->host_state.bus = bus;hw/unin_pci.c +2
-2@@ -227,7 +227,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, d->host_state.bus =pci_register_bus (dev,"pci" , pci_unin_set_irq, pci_unin_map_irq, - pic, +NULL , pic, &d->pci_mmio, address_space_io,PCI_DEVFN (11 ,0 ),4 );@@ -293,7 +293,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, d->host_state.bus =pci_register_bus (dev,"pci" , pci_unin_set_irq, pci_unin_map_irq, - pic, +NULL , pic, &d->pci_mmio, address_space_io,PCI_DEVFN (11 ,0 ),4 );hw/versatile_pci.c +1
-1@@ -68,7 +68,7 @@ static int pci_vpb_init(SysBusDevice *dev)sysbus_init_irq (dev, &s->irq[i]); } bus =pci_register_bus (&dev->qdev,"pci" , - pci_vpb_set_irq, pci_vpb_map_irq, s->irq, + pci_vpb_set_irq, pci_vpb_map_irq,NULL , s->irq,get_system_memory (),get_system_io (),PCI_DEVFN (11 ,0 ),4 );
Quoted 8 lines · Jan Kiszka
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced:
map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.Will be used for KVM PCI device assignment.
This is similar to the memory API, which converts a memory region hierarchy to a flat list and fires notifiers whenever it changes.
Quoted 6 lines
hw/pci.c +6
-0+int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num) +{ +PCIBus *bus; + +for (;;) { + bus = pci_dev->bus;
hw/pci.c static void pci_set_irq(void *opaque, int irq_num, int level) · line 1086
Quoted 10 lines
hw/pci.c +10
-0+ irq_num = bus->map_irq (pci_dev, irq_num); +if (bus->map_host_irq) { +break ; + } + pci_dev = bus->parent_dev; +assert (pci_dev); + } +return bus->map_host_irq (bus->irq_opaque, irq_num); +} +
My personal preference is to avoid infinite loops with breaks, I'd write this as a do/while (without the assert). Or maybe supply all buses with a default map_host_irq that recurses back into pci_device_get_host_irq(). But this is not an objection to the patch.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 8 lines · Avi Kivity
Quoted 7 lines · Jan Kiszka
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced:
map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.
Quoted 4 lines
Quoted 1 line
Will be used for KVM PCI device assignment.
This is similar to the memory API, which converts a memory region hierarchy to a flat list and fires notifiers whenever it changes.
In fact, this should become a generic thing one day, independent of PCI. But that's an exercise to be done while reworking the IRQ layer of QEMU (e.g. to support delivery feedback...).
Quoted 14 lines
Quoted 14 lines
hw/pci.c +13
-0+int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num) +{ +PCIBus *bus; + +for (;;) { + bus = pci_dev->bus; + irq_num = bus->map_irq (pci_dev, irq_num); +if (bus->map_host_irq) { +break ; + } + pci_dev = bus->parent_dev; +assert (pci_dev); + }
Quoted 8 lines
hw/pci.c static void pci_set_irq(void *opaque, int irq_num, int level) · line 1086
Quoted 3 lines
hw/pci.c +3
-0+return bus->map_host_irq (bus->irq_opaque, irq_num); +} +My personal preference is to avoid infinite loops with breaks, I'd write this as a do/while (without the assert). Or maybe supply all buses with a default
map_host_irqthat recurses back intopci_device_get_host_irq(). But this is not an objection to the patch.
I've modeled it after pci_change_irq_level. I would suggest to change both later on.
BTW, the assert catches host bridges that do not yet implement the required mapping service.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 10 lines · Jan Kiszka
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced:
map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.Will be used for KVM PCI device assignment.
Signed-off-by Jan Kiszka <[email protected]>
interrupt injection is data path even for emulated devices. So instead of special casing device assignment I would like to see all devices converted to an API that caches irqs.
This will likely mean that we can maintain the final irq as part of the pci device structure, and this api will simply return it.
Quoted 331 lines
--- hw/alpha_typhoon.c | 2 +- hw/apb_pci.c | 2 +- hw/bonito.c | 2 +- hw/grackle_pci.c | 1 + hw/gt64xxx.c | 2 +- hw/pci.c | 23 ++++++++++++++++++++--- hw/pci.h | 7 +++++-- hw/pci_internals.h | 1 + hw/piix_pci.c | 15 ++++++++++++--- hw/ppc4xx_pci.c | 2 +- hw/ppce500_pci.c | 2 +- hw/prep_pci.c | 2 +- hw/sh_pci.c | 2 +- hw/spapr_pci.c | 2 +- hw/unin_pci.c | 4 ++-- hw/versatile_pci.c | 2 +- 16 files changed, 51 insertions(+), 20 deletions(-)hw/alpha_typhoon.c +1
-1@@ -764,7 +764,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, &s->pchip.reg_io); b =pci_register_bus (&s->host.busdev.qdev,"pci" , - typhoon_set_irq, sys_map_irq, s, + typhoon_set_irq, sys_map_irq,NULL , s, &s->pchip.reg_mem, addr_space_io,0 ,64 ); s->host.bus = b;hw/apb_pci.c +1
-1@@ -366,7 +366,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,memory_region_add_subregion (get_system_memory (), mem_base, &d->pci_mmio); d->bus =pci_register_bus (&d->busdev.qdev,"pci" , - pci_apb_set_irq, pci_pbm_map_irq, d, + pci_apb_set_irq, pci_pbm_map_irq,NULL , d, &d->pci_mmio,get_system_io (),0 ,32 );hw/bonito.c +1
-1@@ -750,7 +750,7 @@ PCIBus *bonito_init(qemu_irq *pic) dev =qdev_create (NULL ,"Bonito-pcihost" ); pcihost =FROM_SYSBUS (BonitoState,sysbus_from_qdev (dev)); b =pci_register_bus (&pcihost->busdev.qdev,"pci" , pci_bonito_set_irq, - pci_bonito_map_irq, pic,get_system_memory (), + pci_bonito_map_irq,NULL , pic,get_system_memory (),get_system_io (),0x28 ,32 ); pcihost->bus = b;hw/grackle_pci.c +1
-0@@ -85,6 +85,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", pci_grackle_set_irq, pci_grackle_map_irq, + NULL, pic, &d->pci_mmio, address_space_io,hw/gt64xxx.c +1
-1@@ -1093,7 +1093,7 @@ PCIBus *gt64120_register(qemu_irq *pic) d =FROM_SYSBUS (GT64120State, s); d->pci.bus =pci_register_bus (&d->busdev.qdev,"pci" , gt64120_pci_set_irq, gt64120_pci_map_irq, - pic, +NULL , pic,get_system_memory (),get_system_io (),PCI_DEVFN (18 ,0 ),4 );hw/pci.c +20
-3@@ -298,10 +298,11 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, }void pci_bus_irqs (PCIBus *bus,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque,int nirq) +pci_map_host_irq_fn map_host_irq,void *irq_opaque,int nirq) { bus->set_irq = set_irq; bus->map_irq = map_irq; + bus->map_host_irq = map_host_irq; bus->irq_opaque = irq_opaque; bus->nirq = nirq; bus->irq_count =g_malloc0 (nirq *sizeof (bus->irq_count[0 ]));@@ -316,7 +317,7 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)PCIBus *pci_register_bus (DeviceState *parent,const char *name,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque, +pci_map_host_irq_fn map_host_irq,void *irq_opaque,MemoryRegion *address_space_mem,MemoryRegion *address_space_io,uint8_t devfn_min,int nirq)@@ -325,7 +326,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, bus =pci_bus_new (parent, name, address_space_mem, address_space_io, devfn_min); -pci_bus_irqs (bus, set_irq, map_irq, irq_opaque, nirq); +pci_bus_irqs (bus, set_irq, map_irq, map_host_irq, irq_opaque, nirq);return bus; }@@ -1067,6 +1068,22 @@ static void pci_set_irq(void *opaque, int irq_num, int level)pci_change_irq_level (pci_dev, irq_num, change); } +int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num) +{ +PCIBus *bus; + +for (;;) { + bus = pci_dev->bus; + irq_num = bus->map_irq (pci_dev, irq_num); +if (bus->map_host_irq) { +break ; + } + pci_dev = bus->parent_dev; +assert (pci_dev); + } +return bus->map_host_irq (bus->irq_opaque, irq_num); +} +/***********************************************************/ /* monitor info on PCI */ hw/pci.h +5
-2@@ -276,6 +276,7 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev);typedef void (*pci_set_irq_fn )(void *opaque,int irq_num,int level);typedef int (*pci_map_irq_fn )(PCIDevice *pci_dev,int irq_num); +typedef int (*pci_map_host_irq_fn )(void *opaque,int irq_num); typedef enum { PCI_HOTPLUG_DISABLED,@@ -295,15 +296,17 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,MemoryRegion *address_space_io, uint8_t devfn_min);void pci_bus_irqs (PCIBus *bus,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque,int nirq); +pci_map_host_irq_fn map_host_irq,void *irq_opaque, +int nirq);int pci_bus_get_irq_level (PCIBus *bus,int irq_num);void pci_bus_hotplug (PCIBus *bus,pci_hotplug_fn hotplug,DeviceState *dev);PCIBus *pci_register_bus (DeviceState *parent,const char *name,pci_set_irq_fn set_irq,pci_map_irq_fn map_irq, -void *irq_opaque, +pci_map_host_irq_fn map_host_irq,void *irq_opaque,MemoryRegion *address_space_mem,MemoryRegion *address_space_io,uint8_t devfn_min,int nirq); +int pci_device_get_host_irq (PCIDevice *pci_dev,int irq_num);void pci_device_reset (PCIDevice *dev);void pci_bus_reset (PCIBus *bus);hw/pci_internals.h +1
-0@@ -19,6 +19,7 @@ struct PCIBus {uint8_t devfn_min;pci_set_irq_fn set_irq;pci_map_irq_fn map_irq; +pci_map_host_irq_fn map_host_irq;pci_hotplug_fn hotplug;DeviceState *hotplug_qdev;void *irq_opaque;hw/piix_pci.c +12
-3@@ -89,6 +89,7 @@ struct PCII440FXState {#define I440FX_SMRAM 0x72static void piix3_set_irq (void *opaque,int pirq,int level); +static int piix3_map_host_irq (void *opaque,int pci_intx);static void piix3_write_config_xen (PCIDevice *dev,uint32_t address,uint32_t val,int len);@@ -308,13 +309,13 @@ static PCIBus *i440fx_common_init(const char *device_name,if (xen_enabled ()) { piix3 =DO_UPCAST (PIIX3State, dev,pci_create_simple_multifunction (b,-1 , true,"PIIX3-xen" )); -pci_bus_irqs (b, xen_piix3_set_irq, xen_pci_slot_get_pirq, +pci_bus_irqs (b, xen_piix3_set_irq, xen_pci_slot_get_pirq,NULL , piix3,XEN_PIIX_NUM_PIRQS ); }else { piix3 =DO_UPCAST (PIIX3State, dev,pci_create_simple_multifunction (b,-1 , true,"PIIX3" )); -pci_bus_irqs (b, piix3_set_irq, pci_slot_get_pirq, piix3, -PIIX_NUM_PIRQS ); +pci_bus_irqs (b, piix3_set_irq, pci_slot_get_pirq, piix3_map_host_irq, + piix3,PIIX_NUM_PIRQS ); } piix3->pic = pic; *isa_bus = DO_UPCAST(ISABus, qbus,@@ -386,6 +387,14 @@ static void piix3_set_irq(void *opaque, int pirq, int level)piix3_set_irq_level (piix3, pirq, level); } +static int piix3_map_host_irq (void *opaque,int pci_intx) +{ +PIIX3State *piix3 = opaque; +int host_irq = piix3->dev.config[PIIX_PIRQC + pci_intx]; + +return host_irq <PIIX_NUM_PIC_IRQS ? host_irq :-1 ; +} +/* irq routing is changed. so rebuild bitmap */ static void piix3_update_irq_levels (PIIX3State *piix3) {hw/ppc4xx_pci.c +1
-1@@ -343,7 +343,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) } b =pci_register_bus (&s->pci_state.busdev.qdev,NULL , ppc4xx_pci_set_irq, - ppc4xx_pci_map_irq, s->irq,get_system_memory (), + ppc4xx_pci_map_irq,NULL , s->irq,get_system_memory (),get_system_io (),0 ,4 ); s->pci_state.bus = b;hw/ppce500_pci.c +1
-1@@ -318,7 +318,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) } b =pci_register_bus (&s->pci_state.busdev.qdev,NULL , mpc85xx_pci_set_irq, - mpc85xx_pci_map_irq, s->irq, address_space_mem, + mpc85xx_pci_map_irq,NULL , s->irq, address_space_mem, address_space_io,PCI_DEVFN (0x11 ,0 ),4 ); s->pci_state.bus = b;hw/prep_pci.c +1
-1@@ -108,7 +108,7 @@ static int raven_pcihost_init(SysBusDevice *dev) } bus =pci_register_bus (&h->busdev.qdev,NULL , - prep_set_irq, prep_map_irq, s->irq, + prep_set_irq, prep_map_irq,NULL , s->irq, address_space_mem, address_space_io,0 ,4 ); h->bus = bus;hw/sh_pci.c +1
-1@@ -120,7 +120,7 @@ static int sh_pci_device_init(SysBusDevice *dev)sysbus_init_irq (dev, &s->irq[i]); } s->bus = pci_register_bus(&s->busdev.qdev, "pci", - sh_pci_set_irq, sh_pci_map_irq, + sh_pci_set_irq, sh_pci_map_irq, NULL, s->irq, get_system_memory(), get_system_io(),hw/spapr_pci.c +1
-1@@ -306,7 +306,7 @@ static int spapr_phb_init(SysBusDevice *s) bus =pci_register_bus (&phb->busdev.qdev, phb->busname ? phb->busname : phb->dtbusname, - pci_spapr_set_irq, pci_spapr_map_irq, phb, + pci_spapr_set_irq, pci_spapr_map_irq,NULL , phb, &phb->memspace, &phb->iospace,PCI_DEVFN (0 ,0 ),PCI_NUM_PINS ); phb->host_state.bus = bus;hw/unin_pci.c +2
-2@@ -227,7 +227,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, d->host_state.bus =pci_register_bus (dev,"pci" , pci_unin_set_irq, pci_unin_map_irq, - pic, +NULL , pic, &d->pci_mmio, address_space_io,PCI_DEVFN (11 ,0 ),4 );@@ -293,7 +293,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, d->host_state.bus =pci_register_bus (dev,"pci" , pci_unin_set_irq, pci_unin_map_irq, - pic, +NULL , pic, &d->pci_mmio, address_space_io,PCI_DEVFN (11 ,0 ),4 );hw/versatile_pci.c +1
-1@@ -68,7 +68,7 @@ static int pci_vpb_init(SysBusDevice *dev)sysbus_init_irq (dev, &s->irq[i]); } bus =pci_register_bus (&dev->qdev,"pci" , - pci_vpb_set_irq, pci_vpb_map_irq, s->irq, + pci_vpb_set_irq, pci_vpb_map_irq,NULL , s->irq,get_system_memory (),get_system_io (),PCI_DEVFN (11 ,0 ),4 );Signature · 1 line
1.7.3.4
Quoted 12 lines · Michael S. Tsirkin
Quoted 10 lines · Jan Kiszka
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced:
map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.Will be used for KVM PCI device assignment.
Signed-off-by Jan Kiszka <[email protected]>
Quoted 7 lines
interrupt injection is data path even for emulated devices. So instead of special casing device assignment I would like to see all devices converted to an API that caches irqs.
This will likely mean that we can maintain the final irq as part of the pci device structure, and this api will simply return it.
Yep, I definitely agree. It's just that such a design has to please even more users than PCI devices, thus will likely take longer to settle than the device assignment effort. Therefore I decided to rush forward with an intermediate approach first.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 21 lines · Jan Kiszka
Quoted 12 lines · Michael S. Tsirkin
Quoted 10 lines · Jan Kiszka
Add a PCI IRQ path discovery function that walks from a given device to the host bridge, returning the IRQ number that is reported to the attached interrupt controller. For this purpose, another PCI bridge callback function is introduced:
map_host_irq. It is so far only implemented by the PIIX3, other host bridges can be added later on as required.Will be used for KVM PCI device assignment.
Signed-off-by Jan Kiszka <[email protected]>Quoted 7 lines
interrupt injection is data path even for emulated devices. So instead of special casing device assignment I would like to see all devices converted to an API that caches irqs.
This will likely mean that we can maintain the final irq as part of the pci device structure, and this api will simply return it.
Quoted 6 lines
Yep, I definitely agree. It's just that such a design has to please even more users than PCI devices, thus will likely take longer to settle than the device assignment effort. Therefore I decided to rush forward with an intermediate approach first.
Jan
I think it's easy, will try to do it soon.
Quoted 3 lines
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 5 lines · Jan Kiszka
hw/piix_pci.c +1
-0@@ -386,6 +387,14 @@ static void piix3_set_irq(void *opaque, int pirq, int level)piix3_set_irq_level (piix3, pirq, level); } +static int piix3_map_host_irq (void *opaque,int pci_intx)
hw/piix_pci.c static void piix3_set_irq(void *opaque, int pirq, int level) · line 400
Quoted 10 lines
hw/piix_pci.c +7
-0+{ +PIIX3State *piix3 = opaque; +int host_irq = piix3->dev.config[PIIX_PIRQC + pci_intx]; + +return host_irq <PIIX_NUM_PIC_IRQS ? host_irq :-1 ; +} +/* irq routing is changed. so rebuild bitmap */ static void piix3_update_irq_levels (PIIX3State *piix3) {
So, instead of special API just for assignment, I would like to see map_irq in piix being reworked to take dev config into account.
I think piix is almost unique in this but need to check, if not fix other host buses that are programmable. PCI bridges are all fixed routing.
Then we can drop set_irq callback.
Finally all devices can cache the irq#,
and piix would scan devices behind it
and update the irq.
Assignment then just needs a notifier, since
it owns the device just a pointer in device is
enough.
Could you look at doing this please?
If no I can give it a stub.
Signature · 1 line
MST
Quoted 14 lines · Michael S. Tsirkin
Quoted 13 lines · Jan Kiszka
hw/piix_pci.c +8
-0@@ -386,6 +387,14 @@ static void piix3_set_irq(void *opaque, int pirq, int level)piix3_set_irq_level (piix3, pirq, level); } +static int piix3_map_host_irq (void *opaque,int pci_intx) +{ +PIIX3State *piix3 = opaque; +int host_irq = piix3->dev.config[PIIX_PIRQC + pci_intx]; + +return host_irq <PIIX_NUM_PIC_IRQS ? host_irq :-1 ; +} +/* irq routing is changed. so rebuild bitmap */
Quoted 8 lines
hw/piix_pci.c static void piix3_set_irq(void *opaque, int pirq, int level) · line 400
Quoted 2 lines
hw/piix_pci.c +0
-0static void piix3_update_irq_levels (PIIX3State *piix3) {So, instead of special API just for assignment, I would like to see
map_irqin piix being reworked to take dev config into account.
I think piix is almost unique in this but need to check,
Maybe it is the only host bridge with routing that we have in QEMU right now, but it is surely not unique (e.g. all later Intel chipsets support this).
Quoted 4 lines
if not fix other host buses that are programmable. PCI bridges are all fixed routing.
Then we can drop
set_irqcallback.
set_irq may do more than IRQ routing. It may also flip polarity (see bonito.c). I guess we need to analyze the requirements of all in-tree host bridges first.
Quoted 8 lines
Finally all devices can cache the irq#, and piix would scan devices behind it
and update the irq.Assignment then just needs a notifier, since it owns the device just a pointer in device is enough.
I cannot completely follow your ideas here yet. Do you want to pass the mapping information along the notifier, or why "just ... a notifier"?
Quoted 4 lines
Could you look at doing this please?
If no I can give it a stub.
Unless we can converge over a final API quickly, I would suggest to base these refactorings on top of what I propose here. We will have to touch all host bridges more invasively for this anyway. If you can explain to me how simple the refactoring can be (but I'm a bit skeptical ;) ), I could do this, otherwise I would prefer to focus on the device assignment topic which provide some more nuts.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 24 lines · Jan Kiszka
Quoted 14 lines · Michael S. Tsirkin
Quoted 13 lines · Jan Kiszka
hw/piix_pci.c +8
-0@@ -386,6 +387,14 @@ static void piix3_set_irq(void *opaque, int pirq, int level)piix3_set_irq_level (piix3, pirq, level); } +static int piix3_map_host_irq (void *opaque,int pci_intx) +{ +PIIX3State *piix3 = opaque; +int host_irq = piix3->dev.config[PIIX_PIRQC + pci_intx]; + +return host_irq <PIIX_NUM_PIC_IRQS ? host_irq :-1 ; +} +/* irq routing is changed. so rebuild bitmap */ Quoted 8 lines
hw/piix_pci.c static void piix3_set_irq(void *opaque, int pirq, int level) · line 400
Quoted 2 lines
hw/piix_pci.c +0
-0static void piix3_update_irq_levels (PIIX3State *piix3) {So, instead of special API just for assignment, I would like to see
map_irqin piix being reworked to take dev config into account.
I think piix is almost unique in this but need to check,
Quoted 3 lines
Maybe it is the only host bridge with routing that we have in QEMU right now, but it is surely not unique (e.g. all later Intel chipsets support this).
Yes. APIs for this should be in place. Just saying instead of failing we can easily just make it work if there are no remappings.
Quoted 7 lines
Quoted 4 lines
if not fix other host buses that are programmable. PCI bridges are all fixed routing.
Then we can drop
set_irqcallback.
set_irqmay do more than IRQ routing. It may also flip polarity (seebonito.c).
In that case host_map_irq is not a good API? Need to investigate.
Quoted 2 lines
I guess we need to analyze the requirements of all in-tree host bridges first.
Yes.
Quoted 11 lines
Quoted 8 lines
Finally all devices can cache the irq#, and piix would scan devices behind it
and update the irq.Assignment then just needs a notifier, since it owns the device just a pointer in device is enough.
I cannot completely follow your ideas here yet. Do you want to pass the mapping information along the notifier, or why "just ... a notifier"?
Each device would resolve IRQs that it uses.
Quoted 5 lines
Quoted 4 lines
Could you look at doing this please?
If no I can give it a stub.
Quoted 8 lines
Unless we can converge over a final API quickly, I would suggest to base these refactorings on top of what I propose here. We will have to touch all host bridges more invasively for this anyway. If you can explain to me how simple the refactoring can be (but I'm a bit skeptical ;) ), I could do this, otherwise I would prefer to focus on the device assignment topic which provide some more nuts.
Jan
Yes it's simple. I'll post in a couple of days (lots of meetings tomorrow). I think you'll
see it's easier and cleaner.
Quoted 3 lines
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux