diff options
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/e500.c | 36 | ||||
-rw-r--r-- | hw/ppc/e500.h | 5 | ||||
-rw-r--r-- | hw/ppc/e500plat.c | 5 | ||||
-rw-r--r-- | hw/ppc/mpc8544ds.c | 11 | ||||
-rw-r--r-- | hw/ppc/ppc.c | 4 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 62 | ||||
-rw-r--r-- | hw/ppc/spapr_iommu.c | 6 |
7 files changed, 95 insertions, 34 deletions
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 2832fc0da4..7e17d180c6 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -51,21 +51,16 @@ #define RAM_SIZES_ALIGN (64UL << 20) /* TODO: parameterize */ -#define MPC8544_CCSRBAR_BASE 0xE0000000ULL #define MPC8544_CCSRBAR_SIZE 0x00100000ULL #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL #define MPC8544_MSI_REGS_OFFSET 0x41600ULL #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL #define MPC8544_PCI_REGS_OFFSET 0x8000ULL -#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \ - MPC8544_PCI_REGS_OFFSET) #define MPC8544_PCI_REGS_SIZE 0x1000ULL -#define MPC8544_PCI_IO 0xE1000000ULL #define MPC8544_UTIL_OFFSET 0xe0000ULL -#define MPC8544_SPIN_BASE 0xEF000000ULL #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL -#define MPC8XXX_GPIO_IRQ 43 +#define MPC8XXX_GPIO_IRQ 47 struct boot_info { @@ -293,12 +288,12 @@ static int ppce500_load_device_tree(MachineState *machine, int len; uint32_t pci_ranges[14] = { - 0x2000000, 0x0, 0xc0000000, - 0x0, 0xc0000000, + 0x2000000, 0x0, params->pci_mmio_bus_base, + params->pci_mmio_base >> 32, params->pci_mmio_base, 0x0, 0x20000000, 0x1000000, 0x0, 0x0, - 0x0, 0xe1000000, + params->pci_pio_base >> 32, params->pci_pio_base, 0x0, 0x10000, }; QemuOpts *machine_opts = qemu_get_machine_opts(); @@ -389,7 +384,7 @@ static int ppce500_load_device_tree(MachineState *machine, CPUState *cpu; PowerPCCPU *pcpu; char cpu_name[128]; - uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); + uint64_t cpu_release_addr = params->spin_base + (i * 0x20); cpu = qemu_get_cpu(i); if (cpu == NULL) { @@ -426,7 +421,7 @@ static int ppce500_load_device_tree(MachineState *machine, qemu_fdt_add_subnode(fdt, "/aliases"); /* XXX These should go into their respective devices' code */ - snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); + snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base); qemu_fdt_add_subnode(fdt, soc); qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, @@ -434,7 +429,7 @@ static int ppce500_load_device_tree(MachineState *machine, qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, - MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, + params->ccsrbar_base >> 32, params->ccsrbar_base, MPC8544_CCSRBAR_SIZE); /* XXX should contain a reasonable value */ qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); @@ -493,7 +488,8 @@ static int ppce500_load_device_tree(MachineState *machine, qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); - snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); + snprintf(pci, sizeof(pci), "/pci@%llx", + params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET); qemu_fdt_add_subnode(fdt, pci); qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); @@ -512,8 +508,10 @@ static int ppce500_load_device_tree(MachineState *machine, } qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); - qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, - MPC8544_PCI_REGS_BASE, 0, 0x1000); + qemu_fdt_setprop_cells(fdt, pci, "reg", + (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32, + (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET), + 0, 0x1000); qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); @@ -841,7 +839,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; - env->mpic_iack = MPC8544_CCSRBAR_BASE + + env->mpic_iack = params->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0; ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); @@ -875,7 +873,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) qdev_init_nofail(dev); ccsr = CCSR(dev); ccsr_addr_space = &ccsr->ccsr_space; - memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, + memory_region_add_subregion(address_space_mem, params->ccsrbar_base, ccsr_addr_space); mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); @@ -917,8 +915,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) if (!pci_bus) printf("couldn't create PCI controller!\n"); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO); - if (pci_bus) { /* Register network interfaces. */ for (i = 0; i < nb_nics; i++) { @@ -927,7 +923,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) } /* Register spinning region */ - sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); + sysbus_create_simple("e500-spin", params->spin_base, NULL); if (cur_base < (32 * 1024 * 1024)) { /* u-boot occupies memory up to 32MB, so load blobs above */ diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 9f61ab2b1c..ef224ea5e6 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -17,6 +17,11 @@ typedef struct PPCE500Params { hwaddr platform_bus_size; int platform_bus_first_irq; int platform_bus_num_irqs; + hwaddr ccsrbar_base; + hwaddr pci_pio_base; + hwaddr pci_mmio_base; + hwaddr pci_mmio_bus_base; + hwaddr spin_base; } PPCE500Params; void ppce500_init(MachineState *machine, PPCE500Params *params); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index d50ae000ee..14b14eaa7d 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -41,6 +41,11 @@ static void e500plat_init(MachineState *machine) .platform_bus_size = (128ULL * 1024 * 1024), .platform_bus_first_irq = 5, .platform_bus_num_irqs = 10, + .ccsrbar_base = 0xFE0000000ULL, + .pci_pio_base = 0xFE1000000ULL, + .pci_mmio_base = 0xC00000000ULL, + .pci_mmio_bus_base = 0xE0000000ULL, + .spin_base = 0xFEF000000ULL, }; /* Older KVM versions don't support EPR which breaks guests when we announce diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index b99f74af75..3a3b141e43 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -15,6 +15,7 @@ #include "hw/boards.h" #include "sysemu/device_tree.h" #include "hw/ppc/openpic.h" +#include "qemu/error-report.h" static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) { @@ -33,8 +34,18 @@ static void mpc8544ds_init(MachineState *machine) .pci_nr_slots = 2, .fixup_devtree = mpc8544ds_fixup_devtree, .mpic_version = OPENPIC_MODEL_FSL_MPIC_20, + .ccsrbar_base = 0xE0000000ULL, + .pci_mmio_base = 0xC0000000ULL, + .pci_mmio_bus_base = 0xC0000000ULL, + .pci_pio_base = 0xE1000000ULL, + .spin_base = 0xEF000000ULL, }; + if (machine->ram_size > 0xc0000000) { + error_report("The MPC8544DS board only supports up to 3GB of RAM"); + exit(1); + } + ppce500_init(machine, ¶ms); } diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index bec82cd7a9..5ce565d5ec 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -844,7 +844,7 @@ static void timebase_pre_save(void *opaque) return; } - tb->time_of_the_day_ns = get_clock_realtime(); + tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); /* * tb_offset is only expected to be changed by migration so * there is no need to update it from KVM here @@ -873,7 +873,7 @@ static int timebase_post_load(void *opaque, int version_id) * We try to adjust timebase by downtime if host clocks are not * too much out of sync (1 second for now). */ - host_ns = get_clock_realtime(); + host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns); migration_duration_ns = MIN(NSEC_PER_SEC, ns_diff); migration_duration_tb = muldiv64(migration_duration_ns, freq, NSEC_PER_SEC); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 53c4116ed3..b560459e83 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -819,9 +819,16 @@ static void emulate_spapr_hypercall(PowerPCCPU *cpu) } } +#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) +#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID) +#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY) +#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY)) +#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY)) + static void spapr_reset_htab(sPAPREnvironment *spapr) { long shift; + int index; /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest @@ -833,6 +840,11 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) /* Kernel handles htab, we don't need to allocate one */ spapr->htab_shift = shift; kvmppc_kern_htab = true; + + /* Tell readers to update their file descriptor */ + if (spapr->htab_fd >= 0) { + spapr->htab_fd_stale = true; + } } else { if (!spapr->htab) { /* Allocate an htab if we don't yet have one */ @@ -841,6 +853,10 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) /* And clear it */ memset(spapr->htab, 0, HTAB_SIZE(spapr)); + + for (index = 0; index < HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; index++) { + DIRTY_HPTE(HPTE(spapr->htab, index)); + } } /* Update the RMA size if necessary */ @@ -867,6 +883,28 @@ static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) return 0; } +/* + * A guest reset will cause spapr->htab_fd to become stale if being used. + * Reopen the file descriptor to make sure the whole HTAB is properly read. + */ +static int spapr_check_htab_fd(sPAPREnvironment *spapr) +{ + int rc = 0; + + if (spapr->htab_fd_stale) { + close(spapr->htab_fd); + spapr->htab_fd = kvmppc_get_htab_fd(false); + if (spapr->htab_fd < 0) { + error_report("Unable to open fd for reading hash table from KVM: " + "%s", strerror(errno)); + rc = -1; + } + spapr->htab_fd_stale = false; + } + + return rc; +} + static void ppc_spapr_reset(void) { PowerPCCPU *first_ppc_cpu; @@ -986,11 +1024,6 @@ static const VMStateDescription vmstate_spapr = { }, }; -#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) -#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID) -#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY) -#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY)) - static int htab_save_setup(QEMUFile *f, void *opaque) { sPAPREnvironment *spapr = opaque; @@ -1005,6 +1038,7 @@ static int htab_save_setup(QEMUFile *f, void *opaque) assert(kvm_enabled()); spapr->htab_fd = kvmppc_get_htab_fd(false); + spapr->htab_fd_stale = false; if (spapr->htab_fd < 0) { fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", strerror(errno)); @@ -1037,7 +1071,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, /* Consume valid HPTEs */ chunkstart = index; - while ((index < htabslots) + while ((index < htabslots) && (index - chunkstart < USHRT_MAX) && HPTE_VALID(HPTE(spapr->htab, index))) { index++; CLEAN_HPTE(HPTE(spapr->htab, index)); @@ -1089,7 +1123,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, chunkstart = index; /* Consume valid dirty HPTEs */ - while ((index < htabslots) + while ((index < htabslots) && (index - chunkstart < USHRT_MAX) && HPTE_DIRTY(HPTE(spapr->htab, index)) && HPTE_VALID(HPTE(spapr->htab, index))) { CLEAN_HPTE(HPTE(spapr->htab, index)); @@ -1099,7 +1133,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, invalidstart = index; /* Consume invalid dirty HPTEs */ - while ((index < htabslots) + while ((index < htabslots) && (index - invalidstart < USHRT_MAX) && HPTE_DIRTY(HPTE(spapr->htab, index)) && !HPTE_VALID(HPTE(spapr->htab, index))) { CLEAN_HPTE(HPTE(spapr->htab, index)); @@ -1157,6 +1191,11 @@ static int htab_save_iterate(QEMUFile *f, void *opaque) if (!spapr->htab) { assert(kvm_enabled()); + rc = spapr_check_htab_fd(spapr); + if (rc < 0) { + return rc; + } + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); if (rc < 0) { @@ -1188,6 +1227,11 @@ static int htab_save_complete(QEMUFile *f, void *opaque) assert(kvm_enabled()); + rc = spapr_check_htab_fd(spapr); + if (rc < 0) { + return rc; + } + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); if (rc < 0) { return rc; @@ -1438,7 +1482,7 @@ static void ppc_spapr_init(MachineState *machine) } if (spapr->rtas_size > RTAS_MAX_SIZE) { hw_error("RTAS too big ! 0x%zx bytes (max is 0x%x)\n", - spapr->rtas_size, RTAS_MAX_SIZE); + (size_t)spapr->rtas_size, RTAS_MAX_SIZE); exit(1); } g_free(filename); diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 6c91d8edd8..da474740c0 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -173,9 +173,9 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, return tcet; } -static void spapr_tce_table_finalize(Object *obj) +static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp) { - sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj); + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); QLIST_REMOVE(tcet, list); @@ -420,6 +420,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->init = spapr_tce_table_realize; dc->reset = spapr_tce_reset; + dc->unrealize = spapr_tce_table_unrealize; QLIST_INIT(&spapr_tce_tables); @@ -435,7 +436,6 @@ static TypeInfo spapr_tce_table_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(sPAPRTCETable), .class_init = spapr_tce_table_class_init, - .instance_finalize = spapr_tce_table_finalize, }; static void register_types(void) |