On Mon, Jun 04, 2012 at 10:52:11AM +0200, Jan Kiszka wrote:
> Based on the original version by Michael Tsirkin: Instead of traversing
> the PCI bus hierarchy from a device to the host bridge, cache this path
> in PCIDevice and use it directly on interrupt delivery. This will
> specifically pay off with more complex topologies than the current
> single host bus.
> 
> Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>

OK, I applied this. I still think we should go the extra
mile and cache the final IRQ not just the root intx.
But that can be a patch on top.

> ---
>  hw/pci.c |   53 ++++++++++++++++++++++++++++++++++++++++++++---------
>  hw/pci.h |    4 ++++
>  2 files changed, 48 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/pci.c b/hw/pci.c
> index 33452ab..771fb39 100644
> --- a/hw/pci.c
> +++ b/hw/pci.c
> @@ -68,6 +68,8 @@ static void pci_update_mappings(PCIDevice *d);
>  static void pci_set_irq(void *opaque, int irq_num, int level);
>  static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
>  static void pci_del_option_rom(PCIDevice *pdev);
> +static void pci_for_each_device_under_bus(PCIBus *bus,
> +                                          void (*fn)(PCIBus *b, PCIDevice 
> *d));
>  
>  static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
>  static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
> @@ -112,18 +114,49 @@ static inline void pci_set_irq_state(PCIDevice *d, int 
> irq_num, int level)
>       d->irq_state |= level << irq_num;
>  }
>  
> -static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
> +static void pci_set_device_intx_routing(PCIBus *bus, PCIDevice *dev)
>  {
> -    PCIBus *bus;
> +    int pin, output_pin;
> +    PCIDevice *pci_dev;
> +
> +    /* We might be too early, i.e. before pci_bus_irqs was called.
> +     * We will be called again when this happened. */
> +    if (!bus->map_irq) {
> +        return;
> +    }
> +
> +    for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> +        pci_dev = dev;
> +        output_pin = pin;
> +        do {
> +            bus = pci_dev->bus;
> +            output_pin = bus->map_irq(pci_dev, output_pin);
> +            pci_dev = bus->parent_dev;
> +        } while (pci_dev);
> +
> +        dev->host_intx_pin[pin] = output_pin;
> +        dev->host_bus = bus;
> +    }
> +}
> +
> +static void pci_set_bus_intx_routing(PCIBus *bus)
> +{
> +    PCIBus *sec;
> +
> +    pci_for_each_device_under_bus(bus, pci_set_device_intx_routing);
>  
> -    do {
> -        bus = pci_dev->bus;
> -        irq_num = bus->map_irq(pci_dev, irq_num);
> -        pci_dev = bus->parent_dev;
> -    } while (pci_dev);
> +    QLIST_FOREACH(sec, &bus->child, sibling) {
> +        pci_set_bus_intx_routing(sec);
> +    }
> +}
> +
> +static void pci_change_irq_level(PCIDevice *dev, int pin, int change)
> +{
> +    PCIBus *bus = dev->host_bus;
> +    int output_pin = dev->host_intx_pin[pin];
>  
> -    bus->irq_count[irq_num] += change;
> -    bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
> +    bus->irq_count[output_pin] += change;
> +    bus->set_irq(bus->irq_opaque, output_pin, bus->irq_count[output_pin] != 
> 0);
>  }
>  
>  int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
> @@ -293,6 +326,7 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, 
> pci_map_irq_fn map_irq,
>      bus->irq_opaque = irq_opaque;
>      bus->nirq = nirq;
>      bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
> +    pci_set_bus_intx_routing(bus);
>  }
>  
>  void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
> @@ -798,6 +832,7 @@ static PCIDevice *do_pci_register_device(PCIDevice 
> *pci_dev, PCIBus *bus,
>      bus->devices[devfn] = pci_dev;
>      pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS);
>      pci_dev->version_id = 2; /* Current pci device vmstate version */
> +    pci_set_device_intx_routing(bus, pci_dev);
>      return pci_dev;
>  }
>  
> diff --git a/hw/pci.h b/hw/pci.h
> index 7eaf90b..c4fd863 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -211,6 +211,10 @@ struct PCIDevice {
>      /* Current IRQ levels.  Used internally by the generic PCI code.  */
>      uint8_t irq_state;
>  
> +    /* Used internally by PCI code to cache the interrupt routing */
> +    PCIBus *host_bus;
> +    int host_intx_pin[PCI_NUM_PINS];
> +

A better name would be root_XXXX: host is an overloaded term.
I applied such a patch.

>      /* Capability bits */
>      uint32_t cap_present;
>  
> -- 
> 1.7.3.4

Reply via email to