diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ea5d0e66f8..ddb7438434 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2375,31 +2375,38 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, hwaddr *mmio32, hwaddr *mmio64, unsigned n_dma, uint32_t *liobns, Error **errp) { + /* + * New-style PHB window placement. + * + * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window + * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO + * windows. + * + * Some guest kernels can't work with MMIO windows above 1<<46 + * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB + * + * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each + * PHB stacked together. (32TiB+2GiB)..(32TiB+64GiB) contains the + * 2GiB 32-bit MMIO windows for each PHB. Then 33..64TiB has the + * 1TiB 64-bit MMIO windows for each PHB. + */ const uint64_t base_buid = 0x800000020000000ULL; - const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */ - const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */ - const hwaddr pio_offset = 0x80000000; /* 2 GiB */ - const uint32_t max_index = 255; - const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */ - - uint64_t ram_top = MACHINE(spapr)->ram_size; - hwaddr phb0_base, phb_base; + const int max_phbs = + (SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / SPAPR_PCI_MEM64_WIN_SIZE - 1; int i; - /* Do we have hotpluggable memory? */ - if (MACHINE(spapr)->maxram_size > ram_top) { - /* Can't just use maxram_size, because there may be an - * alignment gap between normal and hotpluggable memory - * regions */ - ram_top = spapr->hotplug_memory.base + - memory_region_size(&spapr->hotplug_memory.mr); - } + /* Sanity check natural alignments */ + QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0); + QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0); + QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0); + QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0); + /* Sanity check bounds */ + QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_IO_WIN_SIZE) > SPAPR_PCI_MEM32_WIN_SIZE); + QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_MEM32_WIN_SIZE) > SPAPR_PCI_MEM64_WIN_SIZE); - phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment); - - if (index > max_index) { + if (index >= max_phbs) { error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", - max_index); + max_phbs - 1); return; } @@ -2408,14 +2415,9 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, liobns[i] = SPAPR_PCI_LIOBN(index, i); } - phb_base = phb0_base + index * phb_spacing; - *pio = phb_base + pio_offset; - *mmio32 = phb_base + mmio_offset; - /* - * We don't set the 64-bit MMIO window, relying on the PHB's - * fallback behaviour of automatically splitting a large "32-bit" - * window into contiguous 32-bit and 64-bit windows - */ + *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE; + *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE; + *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE; } static void spapr_machine_class_init(ObjectClass *oc, void *data) @@ -2519,8 +2521,67 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", true); /* * pseries-2.7 */ -#define SPAPR_COMPAT_2_7 \ - HW_COMPAT_2_7 \ +#define SPAPR_COMPAT_2_7 \ + HW_COMPAT_2_7 \ + { \ + .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ + .property = "mem_win_size", \ + .value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\ + }, \ + { \ + .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ + .property = "mem64_win_size", \ + .value = "0", \ + }, + +static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, + unsigned n_dma, uint32_t *liobns, Error **errp) +{ + /* Legacy PHB placement for pseries-2.7 and earlier machine types */ + const uint64_t base_buid = 0x800000020000000ULL; + const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */ + const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */ + const hwaddr pio_offset = 0x80000000; /* 2 GiB */ + const uint32_t max_index = 255; + const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */ + + uint64_t ram_top = MACHINE(spapr)->ram_size; + hwaddr phb0_base, phb_base; + int i; + + /* Do we have hotpluggable memory? */ + if (MACHINE(spapr)->maxram_size > ram_top) { + /* Can't just use maxram_size, because there may be an + * alignment gap between normal and hotpluggable memory + * regions */ + ram_top = spapr->hotplug_memory.base + + memory_region_size(&spapr->hotplug_memory.mr); + } + + phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment); + + if (index > max_index) { + error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", + max_index); + return; + } + + *buid = base_buid + index; + for (i = 0; i < n_dma; ++i) { + liobns[i] = SPAPR_PCI_LIOBN(index, i); + } + + phb_base = phb0_base + index * phb_spacing; + *pio = phb_base + pio_offset; + *mmio32 = phb_base + mmio_offset; + /* + * We don't set the 64-bit MMIO window, relying on the PHB's + * fallback behaviour of automatically splitting a large "32-bit" + * window into contiguous 32-bit and 64-bit windows + */ +} static void spapr_machine_2_7_instance_options(MachineState *machine) { @@ -2534,6 +2595,7 @@ static void spapr_machine_2_7_class_options(MachineClass *mc) spapr_machine_2_8_class_options(mc); smc->tcg_default_cpu = "POWER7"; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); + smc->phb_placement = phb_placement_2_7; } DEFINE_SPAPR_MACHINE(2_7, "2.7", false); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 10d5de2d70..2a1ccf59ea 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1564,9 +1564,10 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_UINT32("liobn64", sPAPRPHBState, dma_liobn[1], -1), DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size, - SPAPR_PCI_MMIO_WIN_SIZE), + SPAPR_PCI_MEM32_WIN_SIZE), DEFINE_PROP_UINT64("mem64_win_addr", sPAPRPHBState, mem64_win_addr, -1), - DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size, 0), + DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size, + SPAPR_PCI_MEM64_WIN_SIZE), DEFINE_PROP_UINT64("mem64_win_pciaddr", sPAPRPHBState, mem64_win_pciaddr, -1), DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1), diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 23dfb09d36..b92c1b59f1 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -84,8 +84,14 @@ struct sPAPRPHBState { #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL #define SPAPR_PCI_MEM32_WIN_SIZE \ ((1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_MEM64_WIN_SIZE 0x10000000000ULL /* 1 TiB */ -#define SPAPR_PCI_MMIO_WIN_SIZE 0xf80000000 +/* Without manual configuration, all PCI outbound windows will be + * within this range */ +#define SPAPR_PCI_BASE (1ULL << 45) /* 32 TiB */ +#define SPAPR_PCI_LIMIT (1ULL << 46) /* 64 TiB */ + +#define SPAPR_PCI_2_7_MMIO_WIN_SIZE 0xf80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 #define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL diff --git a/tests/endianness-test.c b/tests/endianness-test.c index b7a120e0a4..cf8d41b7b4 100644 --- a/tests/endianness-test.c +++ b/tests/endianness-test.c @@ -38,7 +38,8 @@ static const TestCase test_cases[] = { { "ppc", "prep", 0x80000000, .bswap = true }, { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" }, { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" }, - { "ppc64", "pseries", 0x10080000000ULL, + { "ppc64", "pseries", (1ULL << 45), .bswap = true, .superio = "i82378" }, + { "ppc64", "pseries-2.7", 0x10080000000ULL, .bswap = true, .superio = "i82378" }, { "sh4", "r2d", 0xfe240000, .superio = "i82378" }, { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" }, diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 558dfc3bdc..2eaaf9159a 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -235,10 +235,9 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_MMIO32_WIN_OFF 0xA0000000 +#define SPAPR_PCI_BASE (1ULL << 45) + #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ -#define SPAPR_PCI_IO_WIN_OFF 0x80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) @@ -273,12 +272,12 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) * get the window locations */ ret->buid = 0x800000020000000ULL; - ret->pio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_IO_WIN_OFF; + ret->pio_cpu_base = SPAPR_PCI_BASE; ret->pio.pci_base = 0; ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ - ret->mmio32_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO32_WIN_OFF; + ret->mmio32_cpu_base = SPAPR_PCI_BASE + SPAPR_PCI_MMIO32_WIN_SIZE; ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c index 21004a76ec..d3522ea093 100644 --- a/tests/spapr-phb-test.c +++ b/tests/spapr-phb-test.c @@ -25,7 +25,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); qtest_add_func("/spapr-phb/device", test_phb_device); - qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=100"); + qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=30"); ret = g_test_run();