aboutsummaryrefslogtreecommitdiff
path: root/hw/spapr_pci.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-01-11 19:46:28 +0000
committerAlexander Graf <agraf@suse.de>2012-01-21 05:17:02 +0100
commit4d8d5467cd6e324fb49ae97b9d5dcee3973d9a19 (patch)
tree9e7a863dc3bd53e1aa58b72f9f789714cd103dca /hw/spapr_pci.c
parentc9c3c80af71dd2b7813d1ada9b14cb51df584221 (diff)
pseries: SLOF PCI flag day
Currently on the pseries machine the SLOF firmware is used normally, but we bypass it when -kernel is specified. Having these two different boot paths can cause some confusion. In particular at present we need to "probe" the (emulated) PCI bus and produce device tree nodes for the PCI devices in qemu, for the -kernel case. In the SLOF case, it takes the device tree from qemu adds some stuff to it then passes it on to the kernel. It's been decided that a better approach is to always boot through SLOF, even when using -kernel. WIth this approach we can leave PCI probing and device node creation to SLOF in all cases which removes a bunch of code in qemu, and avoids iterating the PCI devices from the machine specific init code which we're not supposed to do. This patch changes qemu to always boot through SLOF, and not to create PCI nodes. Simultaneously it updates the included version of SLOF (submodule and binary image) to one which supports (and requires) the new approach. The new SLOF version also includes a number of unrelated enhancements: support for booting from virtio-pci devices and e1000, greatly improved FCode support and many bugfixes. It also makes SLOF ready to be used even when specifying a kernel on the qemu command line. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/spapr_pci.c')
-rw-r--r--hw/spapr_pci.c134
1 files changed, 12 insertions, 122 deletions
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index f3f9246ee0..cf37628292 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -324,31 +324,13 @@ void spapr_create_phb(sPAPREnvironment *spapr,
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
-static uint32_t regtype_to_ss(uint8_t type)
-{
- if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- return 3;
- }
- if (type == PCI_BASE_ADDRESS_SPACE_IO) {
- return 1;
- }
- return 2;
-}
-
int spapr_populate_pci_devices(sPAPRPHBState *phb,
uint32_t xics_phandle,
void *fdt)
{
PCIBus *bus = phb->host_state.bus;
- int bus_off, node_off = 0, devid, fn, i, n, devices;
- DeviceState *qdev;
+ int bus_off, i;
char nodename[256];
- struct {
- uint32_t hi;
- uint64_t addr;
- uint64_t size;
- } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
- assigned_addresses[PCI_NUM_REGIONS];
uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
struct {
uint32_t hi;
@@ -369,7 +351,7 @@ 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(-1)), 0x0, 0x0, 0x0};
+ cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0};
uint32_t interrupt_map[bus->nirq][7];
/* Start populating the FDT */
@@ -397,118 +379,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
- _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
- &interrupt_map_mask, sizeof(interrupt_map_mask)));
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
- /* Populate PCI devices and allocate IRQs */
- devices = 0;
- QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- int irq_index = pci_spapr_map_irq(dev, 0);
- uint32_t *irqmap = interrupt_map[devices];
- uint8_t *config = dev->config;
-
- devid = dev->devfn >> 3;
- fn = dev->devfn & 7;
-
- sprintf(nodename, "pci@%u,%u", devid, fn);
-
- /* Allocate interrupt from the map */
- if (devid > bus->nirq) {
- printf("Unexpected behaviour in spapr_populate_pci_devices,"
- "wrong devid %u\n", devid);
- exit(-1);
- }
- irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+ /* Build the interrupt-map, this must matches what is done
+ * in pci_spapr_map_irq
+ */
+ _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[irq_index].dt_irq);
+ irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq);
irqmap[6] = cpu_to_be32(0x8);
-
- /* Add node to FDT */
- node_off = fdt_add_subnode(fdt, bus_off, nodename);
- if (node_off < 0) {
- return node_off;
- }
-
- _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
- pci_get_word(&config[PCI_VENDOR_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
- pci_get_word(&config[PCI_DEVICE_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
- pci_get_byte(&config[PCI_REVISION_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
- pci_get_long(&config[PCI_CLASS_REVISION]) >> 8));
- _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
- pci_get_word(&config[PCI_SUBSYSTEM_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
- pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID])));
-
- /* Config space region comes first */
- reg[0].hi = cpu_to_be32(
- b_n(0) |
- b_p(0) |
- b_t(0) |
- b_ss(0/*config*/) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn));
- reg[0].addr = 0;
- reg[0].size = 0;
-
- n = 0;
- for (i = 0; i < ARRAY_SIZE(bars); ++i) {
- if (0 == dev->io_regions[i].size) {
- continue;
- }
-
- reg[n+1].hi = cpu_to_be32(
- b_n(0) |
- b_p(0) |
- b_t(0) |
- b_ss(regtype_to_ss(dev->io_regions[i].type)) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn) |
- b_rrrrrrrr(bars[i]));
- reg[n+1].addr = 0;
- reg[n+1].size = cpu_to_be64(dev->io_regions[i].size);
-
- assigned_addresses[n].hi = cpu_to_be32(
- b_n(1) |
- b_p(0) |
- b_t(0) |
- b_ss(regtype_to_ss(dev->io_regions[i].type)) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn) |
- b_rrrrrrrr(bars[i]));
-
- /*
- * Writing zeroes to assigned_addresses causes the guest kernel to
- * reassign BARs
- */
- assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr);
- assigned_addresses[n].size = reg[n+1].size;
-
- ++n;
- }
- _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
- _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
- assigned_addresses,
- sizeof(assigned_addresses[0])*(n)));
- _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
- pci_get_byte(&config[PCI_INTERRUPT_PIN])));
-
- ++devices;
}
-
/* Write interrupt map */
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
- devices * sizeof(interrupt_map[0])));
+ 7 * sizeof(interrupt_map[0])));
return 0;
}