diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index a564c007b4..25b400aa47 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -198,16 +198,20 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, finish_write_pci_config(spapr, 0, addr, size, val, rets); } +static int pci_spapr_swizzle(int slot, int pin) +{ + return (slot + pin) % PCI_NUM_PINS; +} + static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) { /* * Here we need to convert pci_dev + irq_num to some unique value - * which is less than number of IRQs on the specific bus (now it - * is 16). At the moment irq_num == device_id (number of the - * slot?) - * FIXME: we should swizzle in fn and irq_num + * which is less than number of IRQs on the specific bus (4). We + * use standard PCI swizzling, that is (slot number + pin number) + * % 4. */ - return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI; + return pci_spapr_swizzle(PCI_SLOT(pci_dev->devfn), irq_num); } static void pci_spapr_set_irq(void *opaque, int irq_num, int level) @@ -304,13 +308,13 @@ static int spapr_phb_init(SysBusDevice *s) phb->busname ? phb->busname : phb->dtbusname, pci_spapr_set_irq, pci_spapr_map_irq, phb, &phb->memspace, &phb->iospace, - PCI_DEVFN(0, 0), SPAPR_PCI_NUM_LSI); + PCI_DEVFN(0, 0), PCI_NUM_PINS); phb->host_state.bus = bus; QLIST_INSERT_HEAD(&spapr->phbs, phb, list); /* Initialize the LSI table */ - for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { qemu_irq qirq; uint32_t num; @@ -392,8 +396,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt) { - PCIBus *bus = phb->host_state.bus; - int bus_off, i; + int bus_off, i, j; char nodename[256]; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; struct { @@ -415,8 +418,8 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, }; uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; uint32_t interrupt_map_mask[] = { - cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0}; - uint32_t interrupt_map[bus->nirq][7]; + cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)}; + uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7]; /* Start populating the FDT */ sprintf(nodename, "pci@%" PRIx64, phb->buid); @@ -450,19 +453,23 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", &interrupt_map_mask, sizeof(interrupt_map_mask))); - for (i = 0; i < 7; i++) { - uint32_t *irqmap = interrupt_map[i]; - irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); - irqmap[1] = 0; - irqmap[2] = 0; - irqmap[3] = 0; - irqmap[4] = cpu_to_be32(xics_phandle); - irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq); - irqmap[6] = cpu_to_be32(0x8); + for (i = 0; i < PCI_SLOT_MAX; i++) { + for (j = 0; j < PCI_NUM_PINS; j++) { + uint32_t *irqmap = interrupt_map[i*PCI_NUM_PINS + j]; + int lsi_num = pci_spapr_swizzle(i, j); + + irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); + irqmap[1] = 0; + irqmap[2] = 0; + irqmap[3] = cpu_to_be32(j+1); + irqmap[4] = cpu_to_be32(xics_phandle); + irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].dt_irq); + irqmap[6] = cpu_to_be32(0x8); + } } /* Write interrupt map */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, - 7 * sizeof(interrupt_map[0]))); + sizeof(interrupt_map))); return 0; } diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 039f85bd4b..f54c2e8108 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -23,11 +23,10 @@ #if !defined(__HW_SPAPR_PCI_H__) #define __HW_SPAPR_PCI_H__ +#include "hw/pci.h" #include "hw/pci_host.h" #include "hw/xics.h" -#define SPAPR_PCI_NUM_LSI 16 - typedef struct sPAPRPHBState { SysBusDevice busdev; PCIHostState host_state; @@ -43,7 +42,7 @@ typedef struct sPAPRPHBState { struct { uint32_t dt_irq; qemu_irq qirq; - } lsi_table[SPAPR_PCI_NUM_LSI]; + } lsi_table[PCI_NUM_PINS]; QLIST_ENTRY(sPAPRPHBState) list; } sPAPRPHBState;