diff options
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/mac_newworld.c | 15 | ||||
-rw-r--r-- | hw/ppc/pnv.c | 6 | ||||
-rw-r--r-- | hw/ppc/ppc.c | 16 | ||||
-rw-r--r-- | hw/ppc/ppc405_uc.c | 6 | ||||
-rw-r--r-- | hw/ppc/ppc4xx_pci.c | 13 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 507 | ||||
-rw-r--r-- | hw/ppc/spapr_cpu_core.c | 187 | ||||
-rw-r--r-- | hw/ppc/spapr_drc.c | 5 | ||||
-rw-r--r-- | hw/ppc/spapr_events.c | 10 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 89 | ||||
-rw-r--r-- | hw/ppc/spapr_ovec.c | 19 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 316 | ||||
-rw-r--r-- | hw/ppc/spapr_vio.c | 2 | ||||
-rw-r--r-- | hw/ppc/trace-events | 12 |
14 files changed, 862 insertions, 341 deletions
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 716aea6852..68aaedc06d 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -72,6 +72,7 @@ #include "exec/address-spaces.h" #include "hw/sysbus.h" #include "qemu/cutils.h" +#include "trace.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 @@ -79,21 +80,11 @@ #define CLOCKFREQ (266UL * 1000UL * 1000UL) #define BUSFREQ (100UL * 1000UL * 1000UL) -/* debug UniNorth */ -//#define DEBUG_UNIN - -#ifdef DEBUG_UNIN -#define UNIN_DPRINTF(fmt, ...) \ - do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0) -#else -#define UNIN_DPRINTF(fmt, ...) -#endif - /* UniN device */ static void unin_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - UNIN_DPRINTF("write addr " TARGET_FMT_plx " val %"PRIx64"\n", addr, value); + trace_mac99_uninorth_write(addr, value); if (addr == 0x0) { *(int*)opaque = value; } @@ -109,7 +100,7 @@ static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size) value = *(int*)opaque; } - UNIN_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", addr, value); + trace_mac99_uninorth_read(addr, value); return value; } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 4fab5c0ae7..09f0d22def 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -381,7 +381,7 @@ static void ppc_powernv_init(MachineState *machine) fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); if (fw_size < 0) { - error_report("qemu: could not load OPAL '%s'", fw_filename); + error_report("Could not load OPAL '%s'", fw_filename); exit(1); } g_free(fw_filename); @@ -393,7 +393,7 @@ static void ppc_powernv_init(MachineState *machine) kernel_size = load_image_targphys(machine->kernel_filename, KERNEL_LOAD_ADDR, 0x2000000); if (kernel_size < 0) { - error_report("qemu: could not load kernel'%s'", + error_report("Could not load kernel '%s'", machine->kernel_filename); exit(1); } @@ -405,7 +405,7 @@ static void ppc_powernv_init(MachineState *machine) pnv->initrd_size = load_image_targphys(machine->initrd_filename, pnv->initrd_base, 0x10000000); /* 128MB max */ if (pnv->initrd_size < 0) { - error_report("qemu: could not load initial ram disk '%s'", + error_report("Could not load initial ram disk '%s'", machine->initrd_filename); exit(1); } diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index d171e60b5c..5f93083d4a 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -62,7 +62,16 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - unsigned int old_pending = env->pending_interrupts; + unsigned int old_pending; + bool locked = false; + + /* We may already have the BQL if coming from the reset path */ + if (!qemu_mutex_iothread_locked()) { + locked = true; + qemu_mutex_lock_iothread(); + } + + old_pending = env->pending_interrupts; if (level) { env->pending_interrupts |= 1 << n_IRQ; @@ -80,9 +89,14 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) #endif } + LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 "req %08x\n", __func__, env, n_IRQ, level, env->pending_interrupts, CPU(cpu)->interrupt_request); + + if (locked) { + qemu_mutex_unlock_iothread(); + } } /* PowerPC 6xx / 7xx internal IRQ controller */ diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index d6d3fc2c4a..d5df94aa6e 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -1881,7 +1881,7 @@ static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc) D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */ D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */ M = D0 * D1 * D2; - VCO_out = cpc->sysclk * M; + VCO_out = (uint64_t)cpc->sysclk * M; if (VCO_out < 400000000 || VCO_out > 800000000) { /* PLL cannot lock */ cpc->pllmr &= ~0x80000000; @@ -1892,7 +1892,7 @@ static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc) /* Bypass PLL */ bypass_pll: M = D0; - PLL_out = cpc->sysclk * M; + PLL_out = (uint64_t)cpc->sysclk * M; } CPU_clk = PLL_out; if (cpc->cr1 & 0x00800000) @@ -2242,7 +2242,7 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) #ifdef DEBUG_CLOCKS_LL printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D); #endif - VCO_out = cpc->sysclk * M * D; + VCO_out = (uint64_t)cpc->sysclk * M * D; if (VCO_out < 500000000UL || VCO_out > 1000000000UL) { /* Error - unlock the PLL */ printf("VCO out of range %" PRIu64 "\n", VCO_out); diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c index 683218e5c5..dc19682970 100644 --- a/hw/ppc/ppc4xx_pci.c +++ b/hw/ppc/ppc4xx_pci.c @@ -26,13 +26,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" #include "exec/address-spaces.h" - -#undef DEBUG -#ifdef DEBUG -#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif /* DEBUG */ +#include "trace.h" struct PCIMasterMap { uint32_t la; @@ -249,8 +243,7 @@ static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) { int slot = pci_dev->devfn >> 3; - DPRINTF("%s: devfn %x irq %d -> %d\n", __func__, - pci_dev->devfn, irq_num, slot); + trace_ppc4xx_pci_map_irq(pci_dev->devfn, irq_num, slot); return slot - 1; } @@ -259,7 +252,7 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level) { qemu_irq *pci_irqs = opaque; - DPRINTF("%s: PCI irq %d\n", __func__, irq_num); + trace_ppc4xx_pci_set_irq(irq_num); if (irq_num < 0) { fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num); return; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e465d7ac98..c3bb991605 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -63,6 +63,7 @@ #include "qemu/error-report.h" #include "trace.h" #include "hw/nmi.h" +#include "hw/intc/intc.h" #include "hw/compat.h" #include "qemu/cutils.h" @@ -95,37 +96,66 @@ #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) -static XICSState *try_create_xics(const char *type, int nr_servers, - int nr_irqs, Error **errp) +static int try_create_xics(sPAPRMachineState *spapr, const char *type_ics, + const char *type_icp, int nr_servers, + int nr_irqs, Error **errp) { - Error *err = NULL; - DeviceState *dev; + XICSFabric *xi = XICS_FABRIC(spapr); + Error *err = NULL, *local_err = NULL; + ICSState *ics = NULL; + int i; - dev = qdev_create(NULL, type); - qdev_prop_set_uint32(dev, "nr_servers", nr_servers); - qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs); - object_property_set_bool(OBJECT(dev), true, "realized", &err); + ics = ICS_SIMPLE(object_new(type_ics)); + object_property_add_child(OBJECT(spapr), "ics", OBJECT(ics), NULL); + object_property_set_int(OBJECT(ics), nr_irqs, "nr-irqs", &err); + object_property_add_const_link(OBJECT(ics), "xics", OBJECT(xi), NULL); + object_property_set_bool(OBJECT(ics), true, "realized", &local_err); + error_propagate(&err, local_err); if (err) { - error_propagate(errp, err); - object_unparent(OBJECT(dev)); - return NULL; + goto error; + } + + spapr->icps = g_malloc0(nr_servers * sizeof(ICPState)); + spapr->nr_servers = nr_servers; + + for (i = 0; i < nr_servers; i++) { + ICPState *icp = &spapr->icps[i]; + + object_initialize(icp, sizeof(*icp), type_icp); + object_property_add_child(OBJECT(spapr), "icp[*]", OBJECT(icp), NULL); + object_property_add_const_link(OBJECT(icp), "xics", OBJECT(xi), NULL); + object_property_set_bool(OBJECT(icp), true, "realized", &err); + if (err) { + goto error; + } + object_unref(OBJECT(icp)); } - return XICS_COMMON(dev); + + spapr->ics = ics; + return 0; + +error: + error_propagate(errp, err); + if (ics) { + object_unparent(OBJECT(ics)); + } + return -1; } -static XICSState *xics_system_init(MachineState *machine, - int nr_servers, int nr_irqs, Error **errp) +static int xics_system_init(MachineState *machine, + int nr_servers, int nr_irqs, Error **errp) { - XICSState *xics = NULL; + int rc = -1; if (kvm_enabled()) { Error *err = NULL; - if (machine_kernel_irqchip_allowed(machine)) { - xics = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs, - &err); + if (machine_kernel_irqchip_allowed(machine) && + !xics_kvm_init(SPAPR_MACHINE(machine), errp)) { + rc = try_create_xics(SPAPR_MACHINE(machine), TYPE_ICS_KVM, + TYPE_KVM_ICP, nr_servers, nr_irqs, &err); } - if (machine_kernel_irqchip_required(machine) && !xics) { + if (machine_kernel_irqchip_required(machine) && rc < 0) { error_reportf_err(err, "kernel_irqchip requested but unavailable: "); } else { @@ -133,11 +163,13 @@ static XICSState *xics_system_init(MachineState *machine, } } - if (!xics) { - xics = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp); + if (rc < 0) { + xics_spapr_init(SPAPR_MACHINE(machine), errp); + rc = try_create_xics(SPAPR_MACHINE(machine), TYPE_ICS_SIMPLE, + TYPE_ICP, nr_servers, nr_irqs, errp); } - return xics; + return rc; } static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, @@ -356,20 +388,36 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; + /* Currently we don't advertise any of the "new" ISAv3.00 functionality */ + uint8_t pa_features_300[] = { 64, 0, + 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, /* 0 - 5 */ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 - 11 */ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */ + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24 - 29 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 - 35 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 36 - 41 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 - 47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 - 53 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 54 - 59 */ + 0x00, 0x00, 0x00, 0x00 }; /* 60 - 63 */ + uint8_t *pa_features; size_t pa_size; - switch (env->mmu_model) { - case POWERPC_MMU_2_06: - case POWERPC_MMU_2_06a: + switch (POWERPC_MMU_VER(env->mmu_model)) { + case POWERPC_MMU_VER_2_06: pa_features = pa_features_206; pa_size = sizeof(pa_features_206); break; - case POWERPC_MMU_2_07: - case POWERPC_MMU_2_07a: + case POWERPC_MMU_VER_2_07: pa_features = pa_features_207; pa_size = sizeof(pa_features_207); break; + case POWERPC_MMU_VER_3_00: + pa_features = pa_features_300; + pa_size = sizeof(pa_features_300); + break; default: return; } @@ -924,7 +972,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2)); /* /interrupt controller */ - spapr_dt_xics(spapr->xics, fdt, PHANDLE_XICP); + spapr_dt_xics(spapr->nr_servers, fdt, PHANDLE_XICP); ret = spapr_populate_memory(spapr, fdt); if (ret < 0) { @@ -958,7 +1006,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB)); } - if (mc->query_hotpluggable_cpus) { + if (mc->has_hotpluggable_cpus) { int offset = fdt_path_offset(fdt, "/cpus"); ret = spapr_drc_populate_dt(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU); @@ -1010,6 +1058,9 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, { CPUPPCState *env = &cpu->env; + /* The TCG path should also be holding the BQL at this point */ + g_assert(qemu_mutex_iothread_locked()); + if (msr_pr) { hcall_dprintf("Hypercall made with MSR[PR]=1\n"); env->gpr[3] = H_PRIVILEGE; @@ -1018,6 +1069,13 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, } } +static uint64_t spapr_get_patbe(PPCVirtualHypervisor *vhyp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); + + return spapr->patb_entry; +} + #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) @@ -1050,6 +1108,62 @@ static void close_htab_fd(sPAPRMachineState *spapr) spapr->htab_fd = -1; } +static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); + + return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1; +} + +static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp, + hwaddr ptex, int n) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); + hwaddr pte_offset = ptex * HASH_PTE_SIZE_64; + + if (!spapr->htab) { + /* + * HTAB is controlled by KVM. Fetch into temporary buffer + */ + ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64); + kvmppc_read_hptes(hptes, ptex, n); + return hptes; + } + + /* + * HTAB is controlled by QEMU. Just point to the internally + * accessible PTEG. + */ + return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset); +} + +static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp, + const ppc_hash_pte64_t *hptes, + hwaddr ptex, int n) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); + + if (!spapr->htab) { + g_free((void *)hptes); + } + + /* Nothing to do for qemu managed HPT */ +} + +static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex, + uint64_t pte0, uint64_t pte1) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); + hwaddr offset = ptex * HASH_PTE_SIZE_64; + + if (!spapr->htab) { + kvmppc_write_hpte(ptex, pte0, pte1); + } else { + stq_p(spapr->htab + offset, pte0); + stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1); + } +} + static int spapr_hpt_shift_for_ramsize(uint64_t ramsize) { int shift; @@ -1141,6 +1255,8 @@ static void ppc_spapr_reset(void) /* Check for unknown sysbus devices */ foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); + spapr->patb_entry = 0; + /* Allocate and/or reset the hash page table */ spapr_reallocate_hpt(spapr, spapr_hpt_shift_for_ramsize(machine->maxram_size), @@ -1249,6 +1365,13 @@ static int spapr_post_load(void *opaque, int version_id) sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; int err = 0; + if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) { + int i; + for (i = 0; i < spapr->nr_servers; i++) { + icp_resend(&spapr->icps[i]); + } + } + /* In earlier versions, there was no separate qdev for the PAPR * RTC, so the RTC offset was stored directly in sPAPREnvironment. * So when migrating from those versions, poke the incoming offset @@ -1327,6 +1450,24 @@ static const VMStateDescription vmstate_spapr_ov5_cas = { }, }; +static bool spapr_patb_entry_needed(void *opaque) +{ + sPAPRMachineState *spapr = opaque; + + return !!spapr->patb_entry; +} + +static const VMStateDescription vmstate_spapr_patb_entry = { + .name = "spapr_patb_entry", + .version_id = 1, + .minimum_version_id = 1, + .needed = spapr_patb_entry_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(patb_entry, sPAPRMachineState), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_spapr = { .name = "spapr", .version_id = 3, @@ -1344,6 +1485,7 @@ static const VMStateDescription vmstate_spapr = { }, .subsections = (const VMStateDescription*[]) { &vmstate_spapr_ov5_cas, + &vmstate_spapr_patb_entry, NULL } }; @@ -1751,13 +1893,28 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp) } } +/* find cpu slot in machine->possible_cpus by core_id */ +static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) +{ + int index = id / smp_threads; + + if (index >= ms->possible_cpus->len) { + return NULL; + } + if (idx) { + *idx = index; + } + return &ms->possible_cpus->cpus[index]; +} + static void spapr_init_cpus(sPAPRMachineState *spapr) { MachineState *machine = MACHINE(spapr); MachineClass *mc = MACHINE_GET_CLASS(machine); char *type = spapr_get_cpu_core_type(machine->cpu_model); int smt = kvmppc_smt_threads(); - int spapr_max_cores, spapr_cores; + const CPUArchIdList *possible_cpus; + int boot_cores_nr = smp_cpus / smp_threads; int i; if (!type) { @@ -1765,7 +1922,8 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) exit(1); } - if (mc->query_hotpluggable_cpus) { + possible_cpus = mc->possible_cpu_arch_ids(machine); + if (mc->has_hotpluggable_cpus) { if (smp_cpus % smp_threads) { error_report("smp_cpus (%u) must be multiple of threads (%u)", smp_cpus, smp_threads); @@ -1776,24 +1934,18 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) max_cpus, smp_threads); exit(1); } - - spapr_max_cores = max_cpus / smp_threads; - spapr_cores = smp_cpus / smp_threads; } else { if (max_cpus != smp_cpus) { error_report("This machine version does not support CPU hotplug"); exit(1); } - - spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads; - spapr_cores = spapr_max_cores; + boot_cores_nr = possible_cpus->len; } - spapr->cores = g_new0(Object *, spapr_max_cores); - for (i = 0; i < spapr_max_cores; i++) { + for (i = 0; i < possible_cpus->len; i++) { int core_id = i * smp_threads; - if (mc->query_hotpluggable_cpus) { + if (mc->has_hotpluggable_cpus) { sPAPRDRConnector *drc = spapr_dr_connector_new(OBJECT(spapr), SPAPR_DR_CONNECTOR_TYPE_CPU, @@ -1802,7 +1954,7 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) qemu_register_reset(spapr_drc_reset, drc); } - if (i < spapr_cores) { + if (i < boot_cores_nr) { Object *core = object_new(type); int nr_threads = smp_threads; @@ -1889,9 +2041,8 @@ static void ppc_spapr_init(MachineState *machine) load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; /* Set up Interrupt Controller before we create the VCPUs */ - spapr->xics = xics_system_init(machine, - DIV_ROUND_UP(max_cpus * smt, smp_threads), - XICS_IRQS_SPAPR, &error_fatal); + xics_system_init(machine, DIV_ROUND_UP(max_cpus * smt, smp_threads), + XICS_IRQS_SPAPR, &error_fatal); /* Set up containers for ibm,client-set-architecture negotiated options */ spapr->ov5 = spapr_ovec_new(); @@ -2357,6 +2508,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, uint64_t align = memory_region_get_alignment(mr); uint64_t size = memory_region_size(mr); uint64_t addr; + char *mem_dev; if (size % SPAPR_MEMORY_BLOCK_SIZE) { error_setg(&local_err, "Hotplugged memory size must be a multiple of " @@ -2364,6 +2516,13 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, goto out; } + mem_dev = object_property_get_str(OBJECT(dimm), PC_DIMM_MEMDEV_PROP, NULL); + if (mem_dev && !kvmppc_is_mem_backend_page_size_ok(mem_dev)) { + error_setg(&local_err, "Memory backend has bad page size. " + "Use 'memory-backend-file' with correct mem-path."); + goto out; + } + pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err); if (local_err) { goto out; @@ -2488,6 +2647,165 @@ void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, return fdt; } +static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + CPUCore *cc = CPU_CORE(dev); + CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL); + + core_slot->cpu = NULL; + object_unparent(OBJECT(dev)); +} + +static void spapr_core_release(DeviceState *dev, void *opaque) +{ + HotplugHandler *hotplug_ctrl; + + hotplug_ctrl = qdev_get_hotplug_handler(dev); + hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort); +} + +static +void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + int index; + sPAPRDRConnector *drc; + sPAPRDRConnectorClass *drck; + Error *local_err = NULL; + CPUCore *cc = CPU_CORE(dev); + int smt = kvmppc_smt_threads(); + + if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) { + error_setg(errp, "Unable to find CPU core with core-id: %d", + cc->core_id); + return; + } + if (index == 0) { + error_setg(errp, "Boot CPU core may not be unplugged"); + return; + } + + drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt); + g_assert(drc); + + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + drck->detach(drc, dev, spapr_core_release, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr_hotplug_req_remove_by_index(drc); +} + +static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + MachineClass *mc = MACHINE_GET_CLASS(spapr); + sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); + CPUCore *cc = CPU_CORE(dev); + CPUState *cs = CPU(core->threads); + sPAPRDRConnector *drc; + Error *local_err = NULL; + void *fdt = NULL; + int fdt_offset = 0; + int smt = kvmppc_smt_threads(); + CPUArchId *core_slot; + int index; + + core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); + if (!core_slot) { + error_setg(errp, "Unable to find CPU core with core-id: %d", + cc->core_id); + return; + } + drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt); + + g_assert(drc || !mc->has_hotpluggable_cpus); + + /* + * Setup CPU DT entries only for hotplugged CPUs. For boot time or + * coldplugged CPUs DT entries are setup in spapr_build_fdt(). + */ + if (dev->hotplugged) { + fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); + } + + if (drc) { + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err); + if (local_err) { + g_free(fdt); + error_propagate(errp, local_err); + return; + } + } + + if (dev->hotplugged) { + /* + * Send hotplug notification interrupt to the guest only in case + * of hotplugged CPUs. + */ + spapr_hotplug_req_add_by_index(drc); + } else { + /* + * Set the right DRC states for cold plugged CPU. + */ + if (drc) { + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE); + drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED); + } + } + core_slot->cpu = OBJECT(dev); +} + +static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + MachineState *machine = MACHINE(OBJECT(hotplug_dev)); + MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); + Error *local_err = NULL; + CPUCore *cc = CPU_CORE(dev); + char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model); + const char *type = object_get_typename(OBJECT(dev)); + CPUArchId *core_slot; + int index; + + if (dev->hotplugged && !mc->has_hotpluggable_cpus) { + error_setg(&local_err, "CPU hotplug not supported for this machine"); + goto out; + } + + if (strcmp(base_core_type, type)) { + error_setg(&local_err, "CPU core type should be %s", base_core_type); + goto out; + } + + if (cc->core_id % smp_threads) { + error_setg(&local_err, "invalid core id %d", cc->core_id); + goto out; + } + + core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); + if (!core_slot) { + error_setg(&local_err, "core id %d out of range", cc->core_id); + goto out; + } + + if (core_slot->cpu) { + error_setg(&local_err, "core %d already populated", cc->core_id); + goto out; + } + +out: + g_free(base_core_type); + error_propagate(errp, local_err); +} + static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -2550,7 +2868,7 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, error_setg(errp, "Memory hot unplug not supported for this guest"); } } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { - if (!mc->query_hotpluggable_cpus) { + if (!mc->has_hotpluggable_cpus) { error_setg(errp, "CPU hot unplug not supported on this machine"); return; } @@ -2577,11 +2895,11 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev, error_setg(errp, "Memory hot unplug not supported for this guest"); } } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { - if (!mc->query_hotpluggable_cpus) { + if (!mc->has_hotpluggable_cpus) { error_setg(errp, "CPU hot unplug not supported on this machine"); return; } - spapr_core_unplug(hotplug_dev, dev, errp); + spapr_core_unplug_request(hotplug_dev, dev, errp); } } @@ -2610,35 +2928,34 @@ static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index) return cpu_index / smp_threads / smp_cores; } -static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine) +static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine) { int i; - HotpluggableCPUList *head = NULL; - sPAPRMachineState *spapr = SPAPR_MACHINE(machine); int spapr_max_cores = max_cpus / smp_threads; + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (!mc->has_hotpluggable_cpus) { + spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads; + } + if (machine->possible_cpus) { + assert(machine->possible_cpus->len == spapr_max_cores); + return machine->possible_cpus; + } - for (i = 0; i < spapr_max_cores; i++) { - HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1); - HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1); - CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1); + machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * spapr_max_cores); + machine->possible_cpus->len = spapr_max_cores; + for (i = 0; i < machine->possible_cpus->len; i++) { + int core_id = i * smp_threads; - cpu_item->type = spapr_get_cpu_core_type(machine->cpu_model); - cpu_item->vcpus_count = smp_threads; - cpu_props->has_core_id = true; - cpu_props->core_id = i * smp_threads; + machine->possible_cpus->cpus[i].vcpus_count = smp_threads; + machine->possible_cpus->cpus[i].arch_id = core_id; + machine->possible_cpus->cpus[i].props.has_core_id = true; + machine->possible_cpus->cpus[i].props.core_id = core_id; /* TODO: add 'has_node/node' here to describe to which node core belongs */ - - cpu_item->props = cpu_props; - if (spapr->cores[i]) { - cpu_item->has_qom_path = true; - cpu_item->qom_path = object_get_canonical_path(spapr->cores[i]); - } - list_item->value = cpu_item; - list_item->next = head; - head = list_item; } - return head; + return machine->possible_cpus; } static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, @@ -2693,6 +3010,40 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE; } +static ICSState *spapr_ics_get(XICSFabric *dev, int irq) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(dev); + + return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL; +} + +static void spapr_ics_resend(XICSFabric *dev) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(dev); + + ics_resend(spapr->ics); +} + +static ICPState *spapr_icp_get(XICSFabric *xi, int server) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(xi); + + return (server < spapr->nr_servers) ? &spapr->icps[server] : NULL; +} + +static void spapr_pic_print_info(InterruptStatsProvider *obj, + Monitor *mon) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + int i; + + for (i = 0; i < spapr->nr_servers; i++) { + icp_pic_print_info(&spapr->icps[i], mon); + } + + ics_pic_print_info(spapr->ics, mon); +} + static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -2701,6 +3052,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) NMIClass *nc = NMI_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc); + XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); + InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); mc->desc = "pSeries Logical Partition (PAPR compliant)"; @@ -2712,7 +3065,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->init = ppc_spapr_init; mc->reset = ppc_spapr_reset; mc->block_default_type = IF_SCSI; - mc->max_cpus = 255; + mc->max_cpus = 1024; mc->no_parallel = 1; mc->default_boot_order = ""; mc->default_ram_size = 512 * M_BYTE; @@ -2724,15 +3077,25 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) hc->plug = spapr_machine_device_plug; hc->unplug = spapr_machine_device_unplug; mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; + mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids; hc->unplug_request = spapr_machine_device_unplug_request; smc->dr_lmb_enabled = true; smc->tcg_default_cpu = "POWER8"; - mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; + mc->has_hotpluggable_cpus = true; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; smc->phb_placement = spapr_phb_placement; vhc->hypercall = emulate_spapr_hypercall; + vhc->hpt_mask = spapr_hpt_mask; + vhc->map_hptes = spapr_map_hptes; + vhc->unmap_hptes = spapr_unmap_hptes; + vhc->store_hpte = spapr_store_hpte; + vhc->get_patbe = spapr_get_patbe; + xic->ics_get = spapr_ics_get; + xic->ics_resend = spapr_ics_resend; + xic->icp_get = spapr_icp_get; + ispc->print_info = spapr_pic_print_info; } static const TypeInfo spapr_machine_info = { @@ -2749,6 +3112,8 @@ static const TypeInfo spapr_machine_info = { { TYPE_NMI }, { TYPE_HOTPLUG_HANDLER }, { TYPE_PPC_VIRTUAL_HYPERVISOR }, + { TYPE_XICS_FABRIC }, + { TYPE_INTERRUPT_STATS_PROVIDER }, { } }, }; @@ -2928,7 +3293,7 @@ static void spapr_machine_2_6_instance_options(MachineState *machine) static void spapr_machine_2_6_class_options(MachineClass *mc) { spapr_machine_2_7_class_options(mc); - mc->query_hotpluggable_cpus = NULL; + mc->has_hotpluggable_cpus = false; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6); } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 9dddaeb3fa..6883f0991a 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -13,10 +13,12 @@ #include "hw/boards.h" #include "qapi/error.h" #include "sysemu/cpus.h" +#include "sysemu/kvm.h" #include "target/ppc/kvm_ppc.h" #include "hw/ppc/ppc.h" #include "target/ppc/mmu-hash64.h" #include "sysemu/numa.h" +#include "qemu/error-report.h" static void spapr_cpu_reset(void *opaque) { @@ -34,15 +36,26 @@ static void spapr_cpu_reset(void *opaque) env->spr[SPR_HIOR] = 0; - ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift, - &error_fatal); + /* + * This is a hack for the benefit of KVM PR - it abuses the SDR1 + * slot in kvm_sregs to communicate the userspace address of the + * HPT + */ + if (kvm_enabled()) { + env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab + | (spapr->htab_shift - 18); + if (kvmppc_put_books_sregs(cpu) < 0) { + error_report("Unable to update SDR1 in KVM"); + exit(1); + } + } } static void spapr_cpu_destroy(PowerPCCPU *cpu) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - xics_cpu_destroy(spapr->xics, cpu); + xics_cpu_destroy(XICS_FABRIC(spapr), cpu); qemu_unregister_reset(spapr_cpu_reset, cpu); } @@ -50,15 +63,12 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) { CPUPPCState *env = &cpu->env; - CPUState *cs = CPU(cpu); - int i; /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); /* Enable PAPR mode in TCG or KVM */ - cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); - cpu_ppc_set_papr(cpu); + cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); if (cpu->max_compat) { Error *local_err = NULL; @@ -70,13 +80,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, } } - /* Set NUMA node for the added CPUs */ - i = numa_get_node_for_cpu(cs->cpu_index); - if (i < nb_numa_nodes) { - cs->numa_node = i; - } - - xics_cpu_setup(spapr->xics, cpu); + xics_cpu_setup(XICS_FABRIC(spapr), cpu); qemu_register_reset(spapr_cpu_reset, cpu); spapr_cpu_reset(cpu); @@ -109,13 +113,12 @@ char *spapr_get_cpu_core_type(const char *model) return core_type; } -static void spapr_core_release(DeviceState *dev, void *opaque) +static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); const char *typename = object_class_get_name(scc->cpu_class); size_t size = object_type_get_instance_size(typename); - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); CPUCore *cc = CPU_CORE(dev); int i; @@ -129,140 +132,7 @@ static void spapr_core_release(DeviceState *dev, void *opaque) cpu_remove_sync(cs); object_unparent(obj); } - - spapr->cores[cc->core_id / smp_threads] = NULL; - g_free(sc->threads); - object_unparent(OBJECT(dev)); -} - -void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - CPUCore *cc = CPU_CORE(dev); - int smt = kvmppc_smt_threads(); - int index = cc->core_id / smp_threads; - sPAPRDRConnector *drc = - spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt); - sPAPRDRConnectorClass *drck; - Error *local_err = NULL; - - if (index == 0) { - error_setg(errp, "Boot CPU core may not be unplugged"); - return; - } - - g_assert(drc); - - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->detach(drc, dev, spapr_core_release, NULL, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_hotplug_req_remove_by_index(drc); -} - -void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); - MachineClass *mc = MACHINE_GET_CLASS(spapr); - sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); - CPUCore *cc = CPU_CORE(dev); - CPUState *cs = CPU(core->threads); - sPAPRDRConnector *drc; - Error *local_err = NULL; - void *fdt = NULL; - int fdt_offset = 0; - int index = cc->core_id / smp_threads; - int smt = kvmppc_smt_threads(); - - drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt); - spapr->cores[index] = OBJECT(dev); - - g_assert(drc || !mc->query_hotpluggable_cpus); - - /* - * Setup CPU DT entries only for hotplugged CPUs. For boot time or - * coldplugged CPUs DT entries are setup in spapr_build_fdt(). - */ - if (dev->hotplugged) { - fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); - } - - if (drc) { - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err); - if (local_err) { - g_free(fdt); - spapr->cores[index] = NULL; - error_propagate(errp, local_err); - return; - } - } - - if (dev->hotplugged) { - /* - * Send hotplug notification interrupt to the guest only in case - * of hotplugged CPUs. - */ - spapr_hotplug_req_add_by_index(drc); - } else { - /* - * Set the right DRC states for cold plugged CPU. - */ - if (drc) { - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE); - drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED); - } - } -} - -void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - MachineState *machine = MACHINE(OBJECT(hotplug_dev)); - MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); - sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); - int spapr_max_cores = max_cpus / smp_threads; - int index; - Error *local_err = NULL; - CPUCore *cc = CPU_CORE(dev); - char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model); - const char *type = object_get_typename(OBJECT(dev)); - - if (dev->hotplugged && !mc->query_hotpluggable_cpus) { - error_setg(&local_err, "CPU hotplug not supported for this machine"); - goto out; - } - - if (strcmp(base_core_type, type)) { - error_setg(&local_err, "CPU core type should be %s", base_core_type); - goto out; - } - - if (cc->core_id % smp_threads) { - error_setg(&local_err, "invalid core id %d", cc->core_id); - goto out; - } - - index = cc->core_id / smp_threads; - if (index < 0 || index >= spapr_max_cores) { - error_setg(&local_err, "core id %d out of range", cc->core_id); - goto out; - } - - if (spapr->cores[index]) { - error_setg(&local_err, "core %d already populated", cc->core_id); - goto out; - } - -out: - g_free(base_core_type); - error_propagate(errp, local_err); } static void spapr_cpu_core_realize_child(Object *child, Error **errp) @@ -293,11 +163,13 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) const char *typename = object_class_get_name(scc->cpu_class); size_t size = object_type_get_instance_size(typename); Error *local_err = NULL; + int core_node_id = numa_get_node_for_cpu(cc->core_id);; void *obj; int i, j; sc->threads = g_malloc0(size * cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { + int node_id; char id[32]; CPUState *cs; @@ -306,6 +178,19 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) object_initialize(obj, size, typename); cs = CPU(obj); cs->cpu_index = cc->core_id + i; + + /* Set NUMA node for the added CPUs */ + node_id = numa_get_node_for_cpu(cs->cpu_index); + if (node_id != core_node_id) { + error_setg(&local_err, "Invalid node-id=%d of thread[cpu-index: %d]" + " on CPU[core-id: %d, node-id: %d], node-id must be the same", + node_id, cs->cpu_index, cc->core_id, core_node_id); + goto err; + } + if (node_id < nb_numa_nodes) { + cs->numa_node = node_id; + } + snprintf(id, sizeof(id), "thread[%d]", i); object_property_add_child(OBJECT(sc), id, obj, &local_err); if (local_err) { @@ -360,6 +245,9 @@ static const char *spapr_core_models[] = { /* POWER8NVL */ "POWER8NVL_v1.0", + + /* POWER9 */ + "POWER9_v1.0", }; void spapr_cpu_core_class_init(ObjectClass *oc, void *data) @@ -368,6 +256,7 @@ void spapr_cpu_core_class_init(ObjectClass *oc, void *data) sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); dc->realize = spapr_cpu_core_realize; + dc->unrealize = spapr_cpu_core_unrealizefn; scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); g_assert(scc->cpu_class); } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 2de6377cca..150f6bf2c7 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -326,7 +326,12 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, return; } } + visit_check_list(v, &err); visit_end_list(v, NULL); + if (err) { + error_propagate(errp, err); + return; + } break; } default: diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index f85a9c32a7..24a5758e62 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -481,7 +481,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true); - qemu_irq_pulse(xics_get_qirq(spapr->xics, + qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_EPOW))); } @@ -574,7 +574,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true); - qemu_irq_pulse(xics_get_qirq(spapr->xics, + qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_HOTPLUG))); } @@ -695,7 +695,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, spapr_event_sources_get_source(spapr->event_sources, i); g_assert(source->enabled); - qemu_irq_pulse(xics_get_qirq(spapr->xics, source->irq)); + qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), source->irq)); } } @@ -752,7 +752,7 @@ void spapr_events_init(sPAPRMachineState *spapr) spapr->event_sources = spapr_event_sources_new(); spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW, - xics_spapr_alloc(spapr->xics, 0, false, + spapr_ics_alloc(spapr->ics, 0, false, &error_fatal)); /* NOTE: if machine supports modern/dedicated hotplug event source, @@ -765,7 +765,7 @@ void spapr_events_init(sPAPRMachineState *spapr) */ if (spapr->use_hotplug_event_source) { spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG, - xics_spapr_alloc(spapr->xics, 0, false, + spapr_ics_alloc(spapr->ics, 0, false, &error_fatal)); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 42d20e0b92..f05a90ed2c 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -47,12 +47,12 @@ static bool has_spr(PowerPCCPU *cpu, int spr) return cpu->env.spr_cb[spr].name != NULL; } -static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index) +static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) { /* - * hash value/pteg group index is normalized by htab_mask + * hash value/pteg group index is normalized by HPT mask */ - if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) { + if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { return false; } return true; @@ -77,15 +77,14 @@ static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr) static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; - target_ulong pte_index = args[1]; + target_ulong ptex = args[1]; target_ulong pteh = args[2]; target_ulong ptel = args[3]; unsigned apshift; target_ulong raddr; - target_ulong index; - uint64_t token; + target_ulong slot; + const ppc_hash_pte64_t *hptes; apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); if (!apshift) { @@ -116,36 +115,36 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr, pteh &= ~0x60ULL; - if (!valid_pte_index(env, pte_index)) { + if (!valid_ptex(cpu, ptex)) { return H_PARAMETER; } - index = 0; + slot = ptex & 7ULL; + ptex = ptex & ~7ULL; + if (likely((flags & H_EXACT) == 0)) { - pte_index &= ~7ULL; - token = ppc_hash64_start_access(cpu, pte_index); - for (; index < 8; index++) { - if (!(ppc_hash64_load_hpte0(cpu, token, index) & HPTE64_V_VALID)) { + hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); + for (slot = 0; slot < 8; slot++) { + if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { break; } } - ppc_hash64_stop_access(cpu, token); - if (index == 8) { + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + if (slot == 8) { return H_PTEG_FULL; } } else { - token = ppc_hash64_start_access(cpu, pte_index); - if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) { - ppc_hash64_stop_access(cpu, token); + hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); + if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { + ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); return H_PTEG_FULL; } - ppc_hash64_stop_access(cpu, token); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); } - ppc_hash64_store_hpte(cpu, pte_index + index, - pteh | HPTE64_V_HPTE_DIRTY, ptel); + ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); - args[0] = pte_index + index; + args[0] = ptex + slot; return H_SUCCESS; } @@ -161,18 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex, target_ulong flags, target_ulong *vp, target_ulong *rp) { - CPUPPCState *env = &cpu->env; - uint64_t token; + const ppc_hash_pte64_t *hptes; target_ulong v, r; - if (!valid_pte_index(env, ptex)) { + if (!valid_ptex(cpu, ptex)) { return REMOVE_PARM; } - token = ppc_hash64_start_access(cpu, ptex); - v = ppc_hash64_load_hpte0(cpu, token, 0); - r = ppc_hash64_load_hpte1(cpu, token, 0); - ppc_hash64_stop_access(cpu, token); + hptes = ppc_hash64_map_hptes(cpu, ptex, 1); + v = ppc_hash64_hpte0(cpu, hptes, 0); + r = ppc_hash64_hpte1(cpu, hptes, 0); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); if ((v & HPTE64_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || @@ -191,11 +189,11 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, { CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; - target_ulong pte_index = args[1]; + target_ulong ptex = args[1]; target_ulong avpn = args[2]; RemoveResult ret; - ret = remove_hpte(cpu, pte_index, avpn, flags, + ret = remove_hpte(cpu, ptex, avpn, flags, &args[0], &args[1]); switch (ret) { @@ -291,19 +289,19 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr, { CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; - target_ulong pte_index = args[1]; + target_ulong ptex = args[1]; target_ulong avpn = args[2]; - uint64_t token; + const ppc_hash_pte64_t *hptes; target_ulong v, r; - if (!valid_pte_index(env, pte_index)) { + if (!valid_ptex(cpu, ptex)) { return H_PARAMETER; } - token = ppc_hash64_start_access(cpu, pte_index); - v = ppc_hash64_load_hpte0(cpu, token, 0); - r = ppc_hash64_load_hpte1(cpu, token, 0); - ppc_hash64_stop_access(cpu, token); + hptes = ppc_hash64_map_hptes(cpu, ptex, 1); + v = ppc_hash64_hpte0(cpu, hptes, 0); + r = ppc_hash64_hpte1(cpu, hptes, 0); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); if ((v & HPTE64_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { @@ -315,36 +313,35 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr, r |= (flags << 55) & HPTE64_R_PP0; r |= (flags << 48) & HPTE64_R_KEY_HI; r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); - ppc_hash64_store_hpte(cpu, pte_index, + ppc_hash64_store_hpte(cpu, ptex, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); - ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r); + ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); /* Flush the tlb */ check_tlb_flush(env, true); /* Don't need a memory barrier, due to qemu's global lock */ - ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY, r); + ppc_hash64_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); return H_SUCCESS; } static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; - target_ulong pte_index = args[1]; + target_ulong ptex = args[1]; uint8_t *hpte; int i, ridx, n_entries = 1; - if (!valid_pte_index(env, pte_index)) { + if (!valid_ptex(cpu, ptex)) { return H_PARAMETER; } if (flags & H_READ_4) { /* Clear the two low order bits */ - pte_index &= ~(3ULL); + ptex &= ~(3ULL); n_entries = 4; } - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + hpte = spapr->htab + (ptex * HASH_PTE_SIZE_64); for (i = 0, ridx = 0; i < n_entries; i++) { args[ridx++] = ldq_p(hpte); diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c index 3eb1d5976f..41df4c35ba 100644 --- a/hw/ppc/spapr_ovec.c +++ b/hw/ppc/spapr_ovec.c @@ -16,18 +16,9 @@ #include "qemu/bitmap.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" +#include "trace.h" #include <libfdt.h> -/* #define DEBUG_SPAPR_OVEC */ - -#ifdef DEBUG_SPAPR_OVEC -#define DPRINTFN(fmt, ...) \ - do { fprintf(stderr, fmt "\n", ## __VA_ARGS__); } while (0) -#else -#define DPRINTFN(fmt, ...) \ - do { } while (0) -#endif - #define OV_MAXBYTES 256 /* not including length byte */ #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE) @@ -210,8 +201,7 @@ sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector) for (i = 0; i < vector_len; i++) { uint8_t entry = ldub_phys(&address_space_memory, addr + i); if (entry) { - DPRINTFN("read guest vector %2d, byte %3d / %3d: 0x%.2x", - vector, i + 1, vector_len, entry); + trace_spapr_ovec_parse_vector(vector, i + 1, vector_len, entry); guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE); } } @@ -245,10 +235,9 @@ int spapr_ovec_populate_dt(void *fdt, int fdt_offset, for (i = 1; i < vec_len + 1; i++) { vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE); if (vec[i]) { - DPRINTFN("encoding guest vector byte %3d / %3d: 0x%.2x", - i, vec_len, vec[i]); + trace_spapr_ovec_populate_dt(i, vec_len, vec[i]); } } - return fdt_setprop(fdt, fdt_offset, name, vec, vec_len); + return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1); } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index fd6fc1d953..919d3c2c59 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -43,6 +43,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" +#include "hw/pci/pci_ids.h" #include "hw/ppc/spapr_drc.h" #include "sysemu/device_tree.h" #include "sysemu/kvm.h" @@ -325,7 +326,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - xics_spapr_free(spapr->xics, msi->first_irq, msi->num); + spapr_ics_free(spapr->ics, msi->first_irq, msi->num); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -363,7 +364,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, } /* Allocate MSIs */ - irq = xics_spapr_alloc_block(spapr->xics, req_num, false, + irq = spapr_ics_alloc_block(spapr->ics, req_num, false, ret_intr_type == RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", @@ -374,7 +375,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* Release previous MSIs */ if (msi) { - xics_spapr_free(spapr->xics, msi->first_irq, msi->num); + spapr_ics_free(spapr->ics, msi->first_irq, msi->num); g_hash_table_remove(phb->msi, &config_addr); } @@ -736,7 +737,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr, trace_spapr_pci_msi_write(addr, data, irq); - qemu_irq_pulse(xics_get_qirq(spapr->xics, irq)); + qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), irq)); } static const MemoryRegionOps spapr_msi_ops = { @@ -946,6 +947,274 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp) rp->assigned_len = assigned_idx * sizeof(ResourceFields); } +typedef struct PCIClass PCIClass; +typedef struct PCISubClass PCISubClass; +typedef struct PCIIFace PCIIFace; + +struct PCIIFace { + int iface; + const char *name; +}; + +struct PCISubClass { + int subclass; + const char *name; + const PCIIFace *iface; +}; + +struct PCIClass { + const char *name; + const PCISubClass *subc; +}; + +static const PCISubClass undef_subclass[] = { + { PCI_CLASS_NOT_DEFINED_VGA, "display", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass mass_subclass[] = { + { PCI_CLASS_STORAGE_SCSI, "scsi", NULL }, + { PCI_CLASS_STORAGE_IDE, "ide", NULL }, + { PCI_CLASS_STORAGE_FLOPPY, "fdc", NULL }, + { PCI_CLASS_STORAGE_IPI, "ipi", NULL }, + { PCI_CLASS_STORAGE_RAID, "raid", NULL }, + { PCI_CLASS_STORAGE_ATA, "ata", NULL }, + { PCI_CLASS_STORAGE_SATA, "sata", NULL }, + { PCI_CLASS_STORAGE_SAS, "sas", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass net_subclass[] = { + { PCI_CLASS_NETWORK_ETHERNET, "ethernet", NULL }, + { PCI_CLASS_NETWORK_TOKEN_RING, "token-ring", NULL }, + { PCI_CLASS_NETWORK_FDDI, "fddi", NULL }, + { PCI_CLASS_NETWORK_ATM, "atm", NULL }, + { PCI_CLASS_NETWORK_ISDN, "isdn", NULL }, + { PCI_CLASS_NETWORK_WORLDFIP, "worldfip", NULL }, + { PCI_CLASS_NETWORK_PICMG214, "picmg", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass displ_subclass[] = { + { PCI_CLASS_DISPLAY_VGA, "vga", NULL }, + { PCI_CLASS_DISPLAY_XGA, "xga", NULL }, + { PCI_CLASS_DISPLAY_3D, "3d-controller", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass media_subclass[] = { + { PCI_CLASS_MULTIMEDIA_VIDEO, "video", NULL }, + { PCI_CLASS_MULTIMEDIA_AUDIO, "sound", NULL }, + { PCI_CLASS_MULTIMEDIA_PHONE, "telephony", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass mem_subclass[] = { + { PCI_CLASS_MEMORY_RAM, "memory", NULL }, + { PCI_CLASS_MEMORY_FLASH, "flash", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass bridg_subclass[] = { + { PCI_CLASS_BRIDGE_HOST, "host", NULL }, + { PCI_CLASS_BRIDGE_ISA, "isa", NULL }, + { PCI_CLASS_BRIDGE_EISA, "eisa", NULL }, + { PCI_CLASS_BRIDGE_MC, "mca", NULL }, + { PCI_CLASS_BRIDGE_PCI, "pci", NULL }, + { PCI_CLASS_BRIDGE_PCMCIA, "pcmcia", NULL }, + { PCI_CLASS_BRIDGE_NUBUS, "nubus", NULL }, + { PCI_CLASS_BRIDGE_CARDBUS, "cardbus", NULL }, + { PCI_CLASS_BRIDGE_RACEWAY, "raceway", NULL }, + { PCI_CLASS_BRIDGE_PCI_SEMITP, "semi-transparent-pci", NULL }, + { PCI_CLASS_BRIDGE_IB_PCI, "infiniband", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass comm_subclass[] = { + { PCI_CLASS_COMMUNICATION_SERIAL, "serial", NULL }, + { PCI_CLASS_COMMUNICATION_PARALLEL, "parallel", NULL }, + { PCI_CLASS_COMMUNICATION_MULTISERIAL, "multiport-serial", NULL }, + { PCI_CLASS_COMMUNICATION_MODEM, "modem", NULL }, + { PCI_CLASS_COMMUNICATION_GPIB, "gpib", NULL }, + { PCI_CLASS_COMMUNICATION_SC, "smart-card", NULL }, + { 0xFF, NULL, NULL, }, +}; + +static const PCIIFace pic_iface[] = { + { PCI_CLASS_SYSTEM_PIC_IOAPIC, "io-apic" }, + { PCI_CLASS_SYSTEM_PIC_IOXAPIC, "io-xapic" }, + { 0xFF, NULL }, +}; + +static const PCISubClass sys_subclass[] = { + { PCI_CLASS_SYSTEM_PIC, "interrupt-controller", pic_iface }, + { PCI_CLASS_SYSTEM_DMA, "dma-controller", NULL }, + { PCI_CLASS_SYSTEM_TIMER, "timer", NULL }, + { PCI_CLASS_SYSTEM_RTC, "rtc", NULL }, + { PCI_CLASS_SYSTEM_PCI_HOTPLUG, "hot-plug-controller", NULL }, + { PCI_CLASS_SYSTEM_SDHCI, "sd-host-controller", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass inp_subclass[] = { + { PCI_CLASS_INPUT_KEYBOARD, "keyboard", NULL }, + { PCI_CLASS_INPUT_PEN, "pen", NULL }, + { PCI_CLASS_INPUT_MOUSE, "mouse", NULL }, + { PCI_CLASS_INPUT_SCANNER, "scanner", NULL }, + { PCI_CLASS_INPUT_GAMEPORT, "gameport", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass dock_subclass[] = { + { PCI_CLASS_DOCKING_GENERIC, "dock", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass cpu_subclass[] = { + { PCI_CLASS_PROCESSOR_PENTIUM, "pentium", NULL }, + { PCI_CLASS_PROCESSOR_POWERPC, "powerpc", NULL }, + { PCI_CLASS_PROCESSOR_MIPS, "mips", NULL }, + { PCI_CLASS_PROCESSOR_CO, "co-processor", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCIIFace usb_iface[] = { + { PCI_CLASS_SERIAL_USB_UHCI, "usb-uhci" }, + { PCI_CLASS_SERIAL_USB_OHCI, "usb-ohci", }, + { PCI_CLASS_SERIAL_USB_EHCI, "usb-ehci" }, + { PCI_CLASS_SERIAL_USB_XHCI, "usb-xhci" }, + { PCI_CLASS_SERIAL_USB_UNKNOWN, "usb-unknown" }, + { PCI_CLASS_SERIAL_USB_DEVICE, "usb-device" }, + { 0xFF, NULL }, +}; + +static const PCISubClass ser_subclass[] = { + { PCI_CLASS_SERIAL_FIREWIRE, "firewire", NULL }, + { PCI_CLASS_SERIAL_ACCESS, "access-bus", NULL }, + { PCI_CLASS_SERIAL_SSA, "ssa", NULL }, + { PCI_CLASS_SERIAL_USB, "usb", usb_iface }, + { PCI_CLASS_SERIAL_FIBER, "fibre-channel", NULL }, + { PCI_CLASS_SERIAL_SMBUS, "smb", NULL }, + { PCI_CLASS_SERIAL_IB, "infiniband", NULL }, + { PCI_CLASS_SERIAL_IPMI, "ipmi", NULL }, + { PCI_CLASS_SERIAL_SERCOS, "sercos", NULL }, + { PCI_CLASS_SERIAL_CANBUS, "canbus", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass wrl_subclass[] = { + { PCI_CLASS_WIRELESS_IRDA, "irda", NULL }, + { PCI_CLASS_WIRELESS_CIR, "consumer-ir", NULL }, + { PCI_CLASS_WIRELESS_RF_CONTROLLER, "rf-controller", NULL }, + { PCI_CLASS_WIRELESS_BLUETOOTH, "bluetooth", NULL }, + { PCI_CLASS_WIRELESS_BROADBAND, "broadband", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass sat_subclass[] = { + { PCI_CLASS_SATELLITE_TV, "satellite-tv", NULL }, + { PCI_CLASS_SATELLITE_AUDIO, "satellite-audio", NULL }, + { PCI_CLASS_SATELLITE_VOICE, "satellite-voice", NULL }, + { PCI_CLASS_SATELLITE_DATA, "satellite-data", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass crypt_subclass[] = { + { PCI_CLASS_CRYPT_NETWORK, "network-encryption", NULL }, + { PCI_CLASS_CRYPT_ENTERTAINMENT, + "entertainment-encryption", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCISubClass spc_subclass[] = { + { PCI_CLASS_SP_DPIO, "dpio", NULL }, + { PCI_CLASS_SP_PERF, "counter", NULL }, + { PCI_CLASS_SP_SYNCH, "measurement", NULL }, + { PCI_CLASS_SP_MANAGEMENT, "management-card", NULL }, + { 0xFF, NULL, NULL }, +}; + +static const PCIClass pci_classes[] = { + { "legacy-device", undef_subclass }, + { "mass-storage", mass_subclass }, + { "network", net_subclass }, + { "display", displ_subclass, }, + { "multimedia-device", media_subclass }, + { "memory-controller", mem_subclass }, + { "unknown-bridge", bridg_subclass }, + { "communication-controller", comm_subclass}, + { "system-peripheral", sys_subclass }, + { "input-controller", inp_subclass }, + { "docking-station", dock_subclass }, + { "cpu", cpu_subclass }, + { "serial-bus", ser_subclass }, + { "wireless-controller", wrl_subclass }, + { "intelligent-io", NULL }, + { "satellite-device", sat_subclass }, + { "encryption", crypt_subclass }, + { "data-processing-controller", spc_subclass }, +}; + +static const char *pci_find_device_name(uint8_t class, uint8_t subclass, + uint8_t iface) +{ + const PCIClass *pclass; + const PCISubClass *psubclass; + const PCIIFace *piface; + const char *name; + + if (class >= ARRAY_SIZE(pci_classes)) { + return "pci"; + } + + pclass = pci_classes + class; + name = pclass->name; + + if (pclass->subc == NULL) { + return name; + } + + psubclass = pclass->subc; + while ((psubclass->subclass & 0xff) != 0xff) { + if ((psubclass->subclass & 0xff) == subclass) { + name = psubclass->name; + break; + } + psubclass++; + } + + piface = psubclass->iface; + if (piface == NULL) { + return name; + } + while ((piface->iface & 0xff) != 0xff) { + if ((piface->iface & 0xff) == iface) { + name = piface->name; + break; + } + piface++; + } + + return name; +} + +static void pci_get_node_name(char *nodename, int len, PCIDevice *dev) +{ + int slot = PCI_SLOT(dev->devfn); + int func = PCI_FUNC(dev->devfn); + uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3); + const char *name; + + name = pci_find_device_name((ccode >> 16) & 0xff, (ccode >> 8) & 0xff, + ccode & 0xff); + + if (func != 0) { + snprintf(nodename, len, "%s@%x,%x", name, slot, func); + } else { + snprintf(nodename, len, "%s@%x", name, slot); + } +} + static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb, PCIDevice *pdev); @@ -957,6 +1226,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset, int pci_status, err; char *buf = NULL; uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev); + uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3); uint32_t max_msi, max_msix; if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) == @@ -971,8 +1241,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset, pci_default_read_config(dev, PCI_DEVICE_ID, 2))); _FDT(fdt_setprop_cell(fdt, offset, "revision-id", pci_default_read_config(dev, PCI_REVISION_ID, 1))); - _FDT(fdt_setprop_cell(fdt, offset, "class-code", - pci_default_read_config(dev, PCI_CLASS_PROG, 3))); + _FDT(fdt_setprop_cell(fdt, offset, "class-code", ccode)); if (pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)) { _FDT(fdt_setprop_cell(fdt, offset, "interrupts", pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1))); @@ -1013,11 +1282,10 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset, _FDT(fdt_setprop(fdt, offset, "udf-supported", NULL, 0)); } - /* NOTE: this is normally generated by firmware via path/unit name, - * but in our case we must set it manually since it does not get - * processed by OF beforehand - */ - _FDT(fdt_setprop_string(fdt, offset, "name", "pci")); + _FDT(fdt_setprop_string(fdt, offset, "name", + pci_find_device_name((ccode >> 16) & 0xff, + (ccode >> 8) & 0xff, + ccode & 0xff))); buf = spapr_phb_get_loc_code(sphb, dev); if (!buf) { error_report("Failed setting the ibm,loc-code"); @@ -1053,6 +1321,10 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset, _FDT(fdt_setprop(fdt, offset, "assigned-addresses", (uint8_t *)rp.assigned, rp.assigned_len)); + if (pci_is_express(dev)) { + _FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1)); + } + return 0; } @@ -1061,15 +1333,9 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev, void *fdt, int node_offset) { int offset, ret; - int slot = PCI_SLOT(dev->devfn); - int func = PCI_FUNC(dev->devfn); char nodename[FDT_NAME_MAX]; - if (func != 0) { - snprintf(nodename, FDT_NAME_MAX, "pci@%x,%x", slot, func); - } else { - snprintf(nodename, FDT_NAME_MAX, "pci@%x", slot); - } + pci_get_node_name(nodename, FDT_NAME_MAX, dev); offset = fdt_add_subnode(fdt, node_offset, nodename); ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb); @@ -1485,7 +1751,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint32_t irq; Error *local_err = NULL; - irq = xics_spapr_alloc_block(spapr->xics, 1, true, false, &local_err); + irq = spapr_ics_alloc_block(spapr->ics, 1, true, false, &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); @@ -1782,9 +2048,9 @@ static void spapr_populate_pci_devices_dt(PCIBus *bus, PCIDevice *pdev, s_fdt.fdt = p->fdt; s_fdt.node_off = offset; s_fdt.sphb = p->sphb; - pci_for_each_device(sec_bus, pci_bus_num(sec_bus), - spapr_populate_pci_devices_dt, - &s_fdt); + pci_for_each_device_reverse(sec_bus, pci_bus_num(sec_bus), + spapr_populate_pci_devices_dt, + &s_fdt); } static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev, @@ -1953,9 +2219,9 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, s_fdt.fdt = fdt; s_fdt.node_off = bus_off; s_fdt.sphb = phb; - pci_for_each_device(bus, pci_bus_num(bus), - spapr_populate_pci_devices_dt, - &s_fdt); + pci_for_each_device_reverse(bus, pci_bus_num(bus), + spapr_populate_pci_devices_dt, + &s_fdt); ret = spapr_drc_populate_dt(fdt, bus_off, OBJECT(phb), SPAPR_DR_CONNECTOR_TYPE_PCI); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 8bfc5f971f..a0ee4fd265 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -454,7 +454,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq = xics_spapr_alloc(spapr->xics, dev->irq, false, &local_err); + dev->irq = spapr_ics_alloc(spapr->ics, dev->irq, false, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index f46995cdb2..43d265f351 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -56,6 +56,10 @@ spapr_drc_realize_child(uint32_t index, char *childname) "drc: 0x%"PRIx32", chil spapr_drc_realize_complete(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_unrealize(uint32_t index) "drc: 0x%"PRIx32 +# hw/ppc/spapr_ovec.c +spapr_ovec_parse_vector(int vector, int byte, uint16_t vec_len, uint8_t entry) "read guest vector %2d, byte %3d / %3d: 0x%.2x" +spapr_ovec_populate_dt(int byte, uint16_t vec_len, uint8_t entry) "encoding guest vector byte %3d / %3d: 0x%.2x" + # hw/ppc/spapr_rtas.c spapr_rtas_set_indicator_invalid(uint32_t index) "sensor index: 0x%"PRIx32 spapr_rtas_set_indicator_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 @@ -85,3 +89,11 @@ rs6000mc_presence_read(uint32_t addr, uint32_t val) "read addr=%x val=%x" rs6000mc_size_read(uint32_t addr, uint32_t val) "read addr=%x val=%x" rs6000mc_size_write(uint32_t addr, uint32_t val) "write addr=%x val=%x" rs6000mc_parity_read(uint32_t addr, uint32_t val) "read addr=%x val=%x" + +# hw/ppc/mac_newworld.c +mac99_uninorth_write(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 +mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 + +# hw/ppc/ppc4xx_pci.c +ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn %x irq %d -> %d" +ppc4xx_pci_set_irq(int irq_num) "PCI irq %d" |