From 56258174238eb25df629a53a96e1ac16a32dc7d4 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 30 Aug 2017 15:21:40 -0300 Subject: hw/ppc: clear pending_events on machine reset The sPAPR machine isn't clearing up the pending events QTAILQ on machine reboot. This allows for unprocessed hotplug/epow events to persist in the queue after reset and, when reasserting the IRQs in check_exception later on, these will be being processed by the OS. This patch implements a new function called 'spapr_clear_pending_events' that clears up the pending_events QTAILQ. This helper is then called inside ppc_spapr_reset to clear up the events queue, preventing old/deprecated events from persisting after a reset. Signed-off-by: Daniel Henrique Barboza Signed-off-by: David Gibson --- include/hw/ppc/spapr.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 2a303a705c..5d161ec580 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -662,6 +662,7 @@ void spapr_cpu_parse_features(sPAPRMachineState *spapr); int spapr_hpt_shift_for_ramsize(uint64_t ramsize); void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, Error **errp); +void spapr_clear_pending_events(sPAPRMachineState *spapr); /* CPU and LMB DRC release callbacks. */ void spapr_core_release(DeviceState *dev); -- cgit v1.2.3-55-g7522 From 10f12e6450407b18b4d5a6b50d3852dcfd7fff75 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 30 Aug 2017 15:21:41 -0300 Subject: hw/ppc: CAS reset on early device hotplug This patch is a follow up on the discussions made in patch "hw/ppc: disable hotplug before CAS is completed" that can be found at [1]. At this moment, we do not support CPU/memory hotplug in early boot stages, before CAS. When a hotplug occurs, the event is logged in an internal RTAS event log queue and an IRQ pulse is fired. In regular conditions, the guest handles the interrupt by executing check_exception, fetching the generated hotplug event and enabling the device for use. In early boot, this IRQ isn't caught (SLOF does not handle hotplug events), leaving the event in the rtas event log queue. If the guest executes check_exception due to another hotplug event, the re-assertion of the IRQ ends up de-queuing the first hotplug event as well. In short, a device hotplugged before CAS is considered coldplugged by SLOF. This leads to device misbehavior and, in some cases, guest kernel Ooops when trying to unplug the device. A proper fix would be to turn every device hotplugged before CAS as a colplugged device. This is not trivial to do with the current code base though - the FDT is written in the guest memory at ppc_spapr_reset and can't be retrieved without adding extra state (fdt_size for example) that will need to managed and migrated. Adding the hotplugged DT in the middle of CAS negotiation via the updated DT tree works with CPU devs, but panics the guest kernel at boot. Additional analysis would be necessary for LMBs and PCI devices. There are questions to be made in QEMU/SLOF/kernel level about how we can make this change in a sustainable way. With Linux guests, a fix would be the kernel executing check_exception at boot time, de-queueing the events that happened in early boot and processing them. However, even if/when the newer kernels start fetching these events at boot time, we need to take care of older kernels that won't be doing that. This patch works around the situation by issuing a CAS reset if a hotplugged device is detected during CAS: - the DRC conditions that warrant a CAS reset is the same as those that triggers a DRC migration - the DRC must have a device attached and the DRC state is not equal to its ready_state. With that in mind, this patch makes use of 'spapr_drc_needed' to determine if a CAS reset is needed. - In the middle of CAS negotiations, the function 'spapr_hotplugged_dev_before_cas' goes through all the DRCs to see if there are any DRC that requires a reset, using spapr_drc_needed. If that happens, returns '1' in 'spapr_h_cas_compose_response' which will set spapr->cas_reboot to true, causing the machine to reboot. No changes are made for coldplug devices. [1] http://lists.nongnu.org/archive/html/qemu-devel/2017-08/msg02855.html Signed-off-by: Daniel Henrique Barboza Signed-off-by: David Gibson --- hw/ppc/spapr.c | 26 +++++++++++++++++++++++++- hw/ppc/spapr_drc.c | 2 +- include/hw/ppc/spapr_drc.h | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 0e5f29d348..954fd1a747 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -790,6 +790,26 @@ out: return ret; } +static bool spapr_hotplugged_dev_before_cas(void) +{ + Object *drc_container, *obj; + ObjectProperty *prop; + ObjectPropertyIterator iter; + + drc_container = container_get(object_get_root(), "/dr-connector"); + object_property_iter_init(&iter, drc_container); + while ((prop = object_property_iter_next(&iter))) { + if (!strstart(prop->type, "link<", NULL)) { + continue; + } + obj = object_property_get_link(drc_container, prop->name, NULL); + if (spapr_drc_needed(obj)) { + return true; + } + } + return false; +} + int spapr_h_cas_compose_response(sPAPRMachineState *spapr, target_ulong addr, target_ulong size, sPAPROptionVector *ov5_updates) @@ -797,9 +817,13 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr, void *fdt, *fdt_skel; sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 }; + if (spapr_hotplugged_dev_before_cas()) { + return 1; + } + size -= sizeof(hdr); - /* Create sceleton */ + /* Create skeleton */ fdt_skel = g_malloc0(size); _FDT((fdt_create(fdt_skel, size))); _FDT((fdt_begin_node(fdt_skel, ""))); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 031ba7c387..85c999d9cb 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -460,7 +460,7 @@ static void drc_reset(void *opaque) spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque)); } -static bool spapr_drc_needed(void *opaque) +bool spapr_drc_needed(void *opaque) { sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque; sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h index a7958d0a8d..f8d9f5b231 100644 --- a/include/hw/ppc/spapr_drc.h +++ b/include/hw/ppc/spapr_drc.h @@ -257,6 +257,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, int fdt_start_offset, Error **errp); void spapr_drc_detach(sPAPRDRConnector *drc); +bool spapr_drc_needed(void *opaque); static inline bool spapr_drc_unplug_requested(sPAPRDRConnector *drc) { -- cgit v1.2.3-55-g7522 From 2e886fb39168942ab03b91062e715946e4af8436 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 9 Aug 2017 15:38:56 +1000 Subject: ppc: spapr: Make VCPU ID handling private to SPAPR The concept of a VCPU ID that differs from the CPU's index (cpu->cpu_index) exists only within SPAPR machines so, move the functions ppc_get_vcpu_id() and ppc_get_cpu_by_vcpu_id() into spapr.c and rename them appropriately. Signed-off-by: Sam Bobroff Signed-off-by: David Gibson --- hw/ppc/ppc.c | 21 --------------------- hw/ppc/spapr.c | 40 +++++++++++++++++++++++++++++++++------- hw/ppc/spapr_hcall.c | 4 ++-- hw/ppc/spapr_rtas.c | 4 ++-- include/hw/ppc/spapr.h | 3 +++ target/ppc/cpu.h | 18 ------------------ target/ppc/kvm.c | 2 +- 7 files changed, 41 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 4477d4ad89..f76886f4d3 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -1358,27 +1358,6 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) } } -/* CPU device-tree ID helpers */ -int ppc_get_vcpu_id(PowerPCCPU *cpu) -{ - return cpu->vcpu_id; -} - -PowerPCCPU *ppc_get_cpu_by_vcpu_id(int vcpu_id) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - - if (cpu->vcpu_id == vcpu_id) { - return cpu; - } - } - - return NULL; -} - void ppc_cpu_parse_features(const char *cpu_model) { CPUClass *cc; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f7a4c73e08..067f571416 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -208,7 +208,7 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, int i, ret = 0; uint32_t servers_prop[smt_threads]; uint32_t gservers_prop[smt_threads * 2]; - int index = ppc_get_vcpu_id(cpu); + int index = spapr_vcpu_id(cpu); if (cpu->compat_pvr) { ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr); @@ -237,7 +237,7 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu) { - int index = ppc_get_vcpu_id(cpu); + int index = spapr_vcpu_id(cpu); uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), @@ -341,7 +341,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; DeviceClass *dc = DEVICE_GET_CLASS(cs); - int index = ppc_get_vcpu_id(cpu); + int index = spapr_vcpu_id(cpu); int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); if ((index % smt) != 0) { @@ -493,7 +493,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); - int index = ppc_get_vcpu_id(cpu); + int index = spapr_vcpu_id(cpu); uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() @@ -626,7 +626,7 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr) */ CPU_FOREACH_REVERSE(cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); - int index = ppc_get_vcpu_id(cpu); + int index = spapr_vcpu_id(cpu); DeviceClass *dc = DEVICE_GET_CLASS(cs); int offset; @@ -3025,7 +3025,7 @@ static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, { PowerPCCPU *cpu = POWERPC_CPU(cs); DeviceClass *dc = DEVICE_GET_CLASS(cs); - int id = ppc_get_vcpu_id(cpu); + int id = spapr_vcpu_id(cpu); void *fdt; int offset, fdt_size; char *nodename; @@ -3435,7 +3435,7 @@ static void spapr_ics_resend(XICSFabric *dev) static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id) { - PowerPCCPU *cpu = ppc_get_cpu_by_vcpu_id(vcpu_id); + PowerPCCPU *cpu = spapr_find_cpu(vcpu_id); return cpu ? ICP(cpu->intc) : NULL; } @@ -3455,6 +3455,32 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, ics_pic_print_info(spapr->ics, mon); } +int spapr_vcpu_id(PowerPCCPU *cpu) +{ + CPUState *cs = CPU(cpu); + + if (kvm_enabled()) { + return kvm_arch_vcpu_id(cs); + } else { + return cs->cpu_index; + } +} + +PowerPCCPU *spapr_find_cpu(int vcpu_id) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + + if (spapr_vcpu_id(cpu) == vcpu_id) { + return cpu; + } + } + + return NULL; +} + static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 4ca233854a..7cf0993800 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -999,7 +999,7 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr, CPUPPCState *tenv; PowerPCCPU *tcpu; - tcpu = ppc_get_cpu_by_vcpu_id(procno); + tcpu = spapr_find_cpu(procno); if (!tcpu) { return H_PARAMETER; } @@ -1431,7 +1431,7 @@ static target_ulong h_signal_sys_reset(PowerPCCPU *cpu, } else { /* Unicast */ - cs = CPU(ppc_get_cpu_by_vcpu_id(target)); + cs = CPU(spapr_find_cpu(target)); if (cs) { run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL); return H_SUCCESS; diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 626c06b375..cdf0b607a0 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -104,7 +104,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, } id = rtas_ld(args, 0); - cpu = ppc_get_cpu_by_vcpu_id(id); + cpu = spapr_find_cpu(id); if (cpu != NULL) { if (CPU(cpu)->halted) { rtas_st(rets, 1, 0); @@ -158,7 +158,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, start = rtas_ld(args, 1); r3 = rtas_ld(args, 2); - cpu = ppc_get_cpu_by_vcpu_id(id); + cpu = spapr_find_cpu(id); if (cpu != NULL) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 5d161ec580..91617e3277 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -705,4 +705,7 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) +int spapr_vcpu_id(PowerPCCPU *cpu); +PowerPCCPU *spapr_find_cpu(int vcpu_id); + #endif /* HW_SPAPR_H */ diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 687e66acde..cf4ded7b8e 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2514,23 +2514,5 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx) void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); -/** - * ppc_get_vcpu_id: - * @cs: a PowerPCCPU struct. - * - * Returns a device-tree ID for a CPU. - */ -int ppc_get_vcpu_id(PowerPCCPU *cpu); - -/** - * ppc_get_cpu_by_vcpu_id: - * @vcpu_id: a VCPU ID - * - * Searches for a CPU by @vcpu_id. - * - * Returns: a PowerPCCPU struct - */ -PowerPCCPU *ppc_get_cpu_by_vcpu_id(int vcpu_id); - void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len); #endif /* PPC_CPU_H */ diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 1142d5c970..f1d54106ac 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -520,7 +520,7 @@ bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) unsigned long kvm_arch_vcpu_id(CPUState *cpu) { - return ppc_get_vcpu_id(POWERPC_CPU(cpu)); + return POWERPC_CPU(cpu)->vcpu_id; } /* e500 supports 2 h/w breakpoint and 2 watchpoint. -- cgit v1.2.3-55-g7522 From 517284a77171af6f5676678aea15030ea1887842 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 20 Aug 2017 19:23:05 +0200 Subject: ppc4xx: Move MAL from ppc405_uc to ppc4xx_devs This device appears in other SoCs as well not just in 405 ones Signed-off-by: BALATON Zoltan Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/ppc405_uc.c | 263 ----------------------------------------------- hw/ppc/ppc4xx_devs.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/ppc4xx.h | 2 + 3 files changed, 266 insertions(+), 263 deletions(-) (limited to 'include') diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index f6fe3e6f5e..3c744021d6 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -42,7 +42,6 @@ //#define DEBUG_OCM //#define DEBUG_I2C //#define DEBUG_GPT -//#define DEBUG_MAL //#define DEBUG_CLOCKS //#define DEBUG_CLOCKS_LL @@ -1512,268 +1511,6 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) qemu_register_reset(ppc4xx_gpt_reset, gpt); } -/*****************************************************************************/ -/* MAL */ -enum { - MAL0_CFG = 0x180, - MAL0_ESR = 0x181, - MAL0_IER = 0x182, - MAL0_TXCASR = 0x184, - MAL0_TXCARR = 0x185, - MAL0_TXEOBISR = 0x186, - MAL0_TXDEIR = 0x187, - MAL0_RXCASR = 0x190, - MAL0_RXCARR = 0x191, - MAL0_RXEOBISR = 0x192, - MAL0_RXDEIR = 0x193, - MAL0_TXCTP0R = 0x1A0, - MAL0_TXCTP1R = 0x1A1, - MAL0_TXCTP2R = 0x1A2, - MAL0_TXCTP3R = 0x1A3, - MAL0_RXCTP0R = 0x1C0, - MAL0_RXCTP1R = 0x1C1, - MAL0_RCBS0 = 0x1E0, - MAL0_RCBS1 = 0x1E1, -}; - -typedef struct ppc40x_mal_t ppc40x_mal_t; -struct ppc40x_mal_t { - qemu_irq irqs[4]; - uint32_t cfg; - uint32_t esr; - uint32_t ier; - uint32_t txcasr; - uint32_t txcarr; - uint32_t txeobisr; - uint32_t txdeir; - uint32_t rxcasr; - uint32_t rxcarr; - uint32_t rxeobisr; - uint32_t rxdeir; - uint32_t txctpr[4]; - uint32_t rxctpr[2]; - uint32_t rcbs[2]; -}; - -static void ppc40x_mal_reset (void *opaque); - -static uint32_t dcr_read_mal (void *opaque, int dcrn) -{ - ppc40x_mal_t *mal; - uint32_t ret; - - mal = opaque; - switch (dcrn) { - case MAL0_CFG: - ret = mal->cfg; - break; - case MAL0_ESR: - ret = mal->esr; - break; - case MAL0_IER: - ret = mal->ier; - break; - case MAL0_TXCASR: - ret = mal->txcasr; - break; - case MAL0_TXCARR: - ret = mal->txcarr; - break; - case MAL0_TXEOBISR: - ret = mal->txeobisr; - break; - case MAL0_TXDEIR: - ret = mal->txdeir; - break; - case MAL0_RXCASR: - ret = mal->rxcasr; - break; - case MAL0_RXCARR: - ret = mal->rxcarr; - break; - case MAL0_RXEOBISR: - ret = mal->rxeobisr; - break; - case MAL0_RXDEIR: - ret = mal->rxdeir; - break; - case MAL0_TXCTP0R: - ret = mal->txctpr[0]; - break; - case MAL0_TXCTP1R: - ret = mal->txctpr[1]; - break; - case MAL0_TXCTP2R: - ret = mal->txctpr[2]; - break; - case MAL0_TXCTP3R: - ret = mal->txctpr[3]; - break; - case MAL0_RXCTP0R: - ret = mal->rxctpr[0]; - break; - case MAL0_RXCTP1R: - ret = mal->rxctpr[1]; - break; - case MAL0_RCBS0: - ret = mal->rcbs[0]; - break; - case MAL0_RCBS1: - ret = mal->rcbs[1]; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_mal (void *opaque, int dcrn, uint32_t val) -{ - ppc40x_mal_t *mal; - int idx; - - mal = opaque; - switch (dcrn) { - case MAL0_CFG: - if (val & 0x80000000) - ppc40x_mal_reset(mal); - mal->cfg = val & 0x00FFC087; - break; - case MAL0_ESR: - /* Read/clear */ - mal->esr &= ~val; - break; - case MAL0_IER: - mal->ier = val & 0x0000001F; - break; - case MAL0_TXCASR: - mal->txcasr = val & 0xF0000000; - break; - case MAL0_TXCARR: - mal->txcarr = val & 0xF0000000; - break; - case MAL0_TXEOBISR: - /* Read/clear */ - mal->txeobisr &= ~val; - break; - case MAL0_TXDEIR: - /* Read/clear */ - mal->txdeir &= ~val; - break; - case MAL0_RXCASR: - mal->rxcasr = val & 0xC0000000; - break; - case MAL0_RXCARR: - mal->rxcarr = val & 0xC0000000; - break; - case MAL0_RXEOBISR: - /* Read/clear */ - mal->rxeobisr &= ~val; - break; - case MAL0_RXDEIR: - /* Read/clear */ - mal->rxdeir &= ~val; - break; - case MAL0_TXCTP0R: - idx = 0; - goto update_tx_ptr; - case MAL0_TXCTP1R: - idx = 1; - goto update_tx_ptr; - case MAL0_TXCTP2R: - idx = 2; - goto update_tx_ptr; - case MAL0_TXCTP3R: - idx = 3; - update_tx_ptr: - mal->txctpr[idx] = val; - break; - case MAL0_RXCTP0R: - idx = 0; - goto update_rx_ptr; - case MAL0_RXCTP1R: - idx = 1; - update_rx_ptr: - mal->rxctpr[idx] = val; - break; - case MAL0_RCBS0: - idx = 0; - goto update_rx_size; - case MAL0_RCBS1: - idx = 1; - update_rx_size: - mal->rcbs[idx] = val & 0x000000FF; - break; - } -} - -static void ppc40x_mal_reset (void *opaque) -{ - ppc40x_mal_t *mal; - - mal = opaque; - mal->cfg = 0x0007C000; - mal->esr = 0x00000000; - mal->ier = 0x00000000; - mal->rxcasr = 0x00000000; - mal->rxdeir = 0x00000000; - mal->rxeobisr = 0x00000000; - mal->txcasr = 0x00000000; - mal->txdeir = 0x00000000; - mal->txeobisr = 0x00000000; -} - -static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) -{ - ppc40x_mal_t *mal; - int i; - - mal = g_malloc0(sizeof(ppc40x_mal_t)); - for (i = 0; i < 4; i++) - mal->irqs[i] = irqs[i]; - qemu_register_reset(&ppc40x_mal_reset, mal); - ppc_dcr_register(env, MAL0_CFG, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_ESR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_IER, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCASR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCARR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXEOBISR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXDEIR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCASR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCARR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXEOBISR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXDEIR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP0R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP1R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP2R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP3R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCTP0R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCTP1R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RCBS0, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RCBS1, - mal, &dcr_read_mal, &dcr_write_mal); -} - /*****************************************************************************/ /* SPR */ void ppc40x_core_reset(PowerPCCPU *cpu) diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 6b38ed7bc7..b296ea66c2 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -734,3 +734,267 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, return ram_size; } + +/*****************************************************************************/ +/* MAL */ +enum { + MAL0_CFG = 0x180, + MAL0_ESR = 0x181, + MAL0_IER = 0x182, + MAL0_TXCASR = 0x184, + MAL0_TXCARR = 0x185, + MAL0_TXEOBISR = 0x186, + MAL0_TXDEIR = 0x187, + MAL0_RXCASR = 0x190, + MAL0_RXCARR = 0x191, + MAL0_RXEOBISR = 0x192, + MAL0_RXDEIR = 0x193, + MAL0_TXCTP0R = 0x1A0, + MAL0_TXCTP1R = 0x1A1, + MAL0_TXCTP2R = 0x1A2, + MAL0_TXCTP3R = 0x1A3, + MAL0_RXCTP0R = 0x1C0, + MAL0_RXCTP1R = 0x1C1, + MAL0_RCBS0 = 0x1E0, + MAL0_RCBS1 = 0x1E1, +}; + +typedef struct ppc40x_mal_t ppc40x_mal_t; +struct ppc40x_mal_t { + qemu_irq irqs[4]; + uint32_t cfg; + uint32_t esr; + uint32_t ier; + uint32_t txcasr; + uint32_t txcarr; + uint32_t txeobisr; + uint32_t txdeir; + uint32_t rxcasr; + uint32_t rxcarr; + uint32_t rxeobisr; + uint32_t rxdeir; + uint32_t txctpr[4]; + uint32_t rxctpr[2]; + uint32_t rcbs[2]; +}; + +static void ppc40x_mal_reset(void *opaque); + +static uint32_t dcr_read_mal(void *opaque, int dcrn) +{ + ppc40x_mal_t *mal; + uint32_t ret; + + mal = opaque; + switch (dcrn) { + case MAL0_CFG: + ret = mal->cfg; + break; + case MAL0_ESR: + ret = mal->esr; + break; + case MAL0_IER: + ret = mal->ier; + break; + case MAL0_TXCASR: + ret = mal->txcasr; + break; + case MAL0_TXCARR: + ret = mal->txcarr; + break; + case MAL0_TXEOBISR: + ret = mal->txeobisr; + break; + case MAL0_TXDEIR: + ret = mal->txdeir; + break; + case MAL0_RXCASR: + ret = mal->rxcasr; + break; + case MAL0_RXCARR: + ret = mal->rxcarr; + break; + case MAL0_RXEOBISR: + ret = mal->rxeobisr; + break; + case MAL0_RXDEIR: + ret = mal->rxdeir; + break; + case MAL0_TXCTP0R: + ret = mal->txctpr[0]; + break; + case MAL0_TXCTP1R: + ret = mal->txctpr[1]; + break; + case MAL0_TXCTP2R: + ret = mal->txctpr[2]; + break; + case MAL0_TXCTP3R: + ret = mal->txctpr[3]; + break; + case MAL0_RXCTP0R: + ret = mal->rxctpr[0]; + break; + case MAL0_RXCTP1R: + ret = mal->rxctpr[1]; + break; + case MAL0_RCBS0: + ret = mal->rcbs[0]; + break; + case MAL0_RCBS1: + ret = mal->rcbs[1]; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) +{ + ppc40x_mal_t *mal; + int idx; + + mal = opaque; + switch (dcrn) { + case MAL0_CFG: + if (val & 0x80000000) { + ppc40x_mal_reset(mal); + } + mal->cfg = val & 0x00FFC087; + break; + case MAL0_ESR: + /* Read/clear */ + mal->esr &= ~val; + break; + case MAL0_IER: + mal->ier = val & 0x0000001F; + break; + case MAL0_TXCASR: + mal->txcasr = val & 0xF0000000; + break; + case MAL0_TXCARR: + mal->txcarr = val & 0xF0000000; + break; + case MAL0_TXEOBISR: + /* Read/clear */ + mal->txeobisr &= ~val; + break; + case MAL0_TXDEIR: + /* Read/clear */ + mal->txdeir &= ~val; + break; + case MAL0_RXCASR: + mal->rxcasr = val & 0xC0000000; + break; + case MAL0_RXCARR: + mal->rxcarr = val & 0xC0000000; + break; + case MAL0_RXEOBISR: + /* Read/clear */ + mal->rxeobisr &= ~val; + break; + case MAL0_RXDEIR: + /* Read/clear */ + mal->rxdeir &= ~val; + break; + case MAL0_TXCTP0R: + idx = 0; + goto update_tx_ptr; + case MAL0_TXCTP1R: + idx = 1; + goto update_tx_ptr; + case MAL0_TXCTP2R: + idx = 2; + goto update_tx_ptr; + case MAL0_TXCTP3R: + idx = 3; + update_tx_ptr: + mal->txctpr[idx] = val; + break; + case MAL0_RXCTP0R: + idx = 0; + goto update_rx_ptr; + case MAL0_RXCTP1R: + idx = 1; + update_rx_ptr: + mal->rxctpr[idx] = val; + break; + case MAL0_RCBS0: + idx = 0; + goto update_rx_size; + case MAL0_RCBS1: + idx = 1; + update_rx_size: + mal->rcbs[idx] = val & 0x000000FF; + break; + } +} + +static void ppc40x_mal_reset(void *opaque) +{ + ppc40x_mal_t *mal; + + mal = opaque; + mal->cfg = 0x0007C000; + mal->esr = 0x00000000; + mal->ier = 0x00000000; + mal->rxcasr = 0x00000000; + mal->rxdeir = 0x00000000; + mal->rxeobisr = 0x00000000; + mal->txcasr = 0x00000000; + mal->txdeir = 0x00000000; + mal->txeobisr = 0x00000000; +} + +void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) +{ + ppc40x_mal_t *mal; + int i; + + mal = g_malloc0(sizeof(ppc40x_mal_t)); + for (i = 0; i < 4; i++) { + mal->irqs[i] = irqs[i]; + } + qemu_register_reset(&ppc40x_mal_reset, mal); + ppc_dcr_register(env, MAL0_CFG, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_ESR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_IER, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCASR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCARR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXEOBISR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXDEIR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCASR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCARR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXEOBISR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXDEIR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP0R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP1R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP2R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP3R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCTP0R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCTP1R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RCBS0, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RCBS1, + mal, &dcr_read_mal, &dcr_write_mal); +} diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index 66e57a5194..db50cfac02 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -53,6 +53,8 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, hwaddr *ram_sizes, int do_init); +void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]); + #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" #endif /* PPC4XX_H */ -- cgit v1.2.3-55-g7522 From 0453428047527ac778489a927b66d591ff3c450c Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 20 Aug 2017 19:23:05 +0200 Subject: ppc4xx: Make MAL emulation more generic Allow MAL with more RX and TX channels as found in newer versions. Signed-off-by: BALATON Zoltan Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/ppc405_uc.c | 2 +- hw/ppc/ppc4xx_devs.c | 171 +++++++++++++++++++----------------------------- include/hw/ppc/ppc4xx.h | 3 +- 3 files changed, 70 insertions(+), 106 deletions(-) (limited to 'include') diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 3c744021d6..03856d573f 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -2281,7 +2281,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, mal_irqs[1] = pic[12]; mal_irqs[2] = pic[13]; mal_irqs[3] = pic[14]; - ppc405_mal_init(env, mal_irqs); + ppc4xx_mal_init(env, 4, 2, mal_irqs); /* Ethernet */ /* Uses pic[9], pic[15], pic[17] */ /* CPU control */ diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index b296ea66c2..ec90f13295 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -737,6 +737,7 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, /*****************************************************************************/ /* MAL */ + enum { MAL0_CFG = 0x180, MAL0_ESR = 0x181, @@ -750,17 +751,13 @@ enum { MAL0_RXEOBISR = 0x192, MAL0_RXDEIR = 0x193, MAL0_TXCTP0R = 0x1A0, - MAL0_TXCTP1R = 0x1A1, - MAL0_TXCTP2R = 0x1A2, - MAL0_TXCTP3R = 0x1A3, MAL0_RXCTP0R = 0x1C0, - MAL0_RXCTP1R = 0x1C1, MAL0_RCBS0 = 0x1E0, MAL0_RCBS1 = 0x1E1, }; -typedef struct ppc40x_mal_t ppc40x_mal_t; -struct ppc40x_mal_t { +typedef struct ppc4xx_mal_t ppc4xx_mal_t; +struct ppc4xx_mal_t { qemu_irq irqs[4]; uint32_t cfg; uint32_t esr; @@ -773,16 +770,32 @@ struct ppc40x_mal_t { uint32_t rxcarr; uint32_t rxeobisr; uint32_t rxdeir; - uint32_t txctpr[4]; - uint32_t rxctpr[2]; - uint32_t rcbs[2]; + uint32_t *txctpr; + uint32_t *rxctpr; + uint32_t *rcbs; + uint8_t txcnum; + uint8_t rxcnum; }; -static void ppc40x_mal_reset(void *opaque); +static void ppc4xx_mal_reset(void *opaque) +{ + ppc4xx_mal_t *mal; + + mal = opaque; + mal->cfg = 0x0007C000; + mal->esr = 0x00000000; + mal->ier = 0x00000000; + mal->rxcasr = 0x00000000; + mal->rxdeir = 0x00000000; + mal->rxeobisr = 0x00000000; + mal->txcasr = 0x00000000; + mal->txdeir = 0x00000000; + mal->txeobisr = 0x00000000; +} static uint32_t dcr_read_mal(void *opaque, int dcrn) { - ppc40x_mal_t *mal; + ppc4xx_mal_t *mal; uint32_t ret; mal = opaque; @@ -820,48 +833,32 @@ static uint32_t dcr_read_mal(void *opaque, int dcrn) case MAL0_RXDEIR: ret = mal->rxdeir; break; - case MAL0_TXCTP0R: - ret = mal->txctpr[0]; - break; - case MAL0_TXCTP1R: - ret = mal->txctpr[1]; - break; - case MAL0_TXCTP2R: - ret = mal->txctpr[2]; - break; - case MAL0_TXCTP3R: - ret = mal->txctpr[3]; - break; - case MAL0_RXCTP0R: - ret = mal->rxctpr[0]; - break; - case MAL0_RXCTP1R: - ret = mal->rxctpr[1]; - break; - case MAL0_RCBS0: - ret = mal->rcbs[0]; - break; - case MAL0_RCBS1: - ret = mal->rcbs[1]; - break; default: ret = 0; break; } + if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { + ret = mal->txctpr[dcrn - MAL0_TXCTP0R]; + } + if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { + ret = mal->rxctpr[dcrn - MAL0_RXCTP0R]; + } + if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { + ret = mal->rcbs[dcrn - MAL0_RCBS0]; + } return ret; } static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) { - ppc40x_mal_t *mal; - int idx; + ppc4xx_mal_t *mal; mal = opaque; switch (dcrn) { case MAL0_CFG: if (val & 0x80000000) { - ppc40x_mal_reset(mal); + ppc4xx_mal_reset(mal); } mal->cfg = val & 0x00FFC087; break; @@ -900,65 +897,35 @@ static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) /* Read/clear */ mal->rxdeir &= ~val; break; - case MAL0_TXCTP0R: - idx = 0; - goto update_tx_ptr; - case MAL0_TXCTP1R: - idx = 1; - goto update_tx_ptr; - case MAL0_TXCTP2R: - idx = 2; - goto update_tx_ptr; - case MAL0_TXCTP3R: - idx = 3; - update_tx_ptr: - mal->txctpr[idx] = val; - break; - case MAL0_RXCTP0R: - idx = 0; - goto update_rx_ptr; - case MAL0_RXCTP1R: - idx = 1; - update_rx_ptr: - mal->rxctpr[idx] = val; - break; - case MAL0_RCBS0: - idx = 0; - goto update_rx_size; - case MAL0_RCBS1: - idx = 1; - update_rx_size: - mal->rcbs[idx] = val & 0x000000FF; - break; + } + if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { + mal->txctpr[dcrn - MAL0_TXCTP0R] = val; + } + if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { + mal->rxctpr[dcrn - MAL0_RXCTP0R] = val; + } + if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { + mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF; } } -static void ppc40x_mal_reset(void *opaque) -{ - ppc40x_mal_t *mal; - - mal = opaque; - mal->cfg = 0x0007C000; - mal->esr = 0x00000000; - mal->ier = 0x00000000; - mal->rxcasr = 0x00000000; - mal->rxdeir = 0x00000000; - mal->rxeobisr = 0x00000000; - mal->txcasr = 0x00000000; - mal->txdeir = 0x00000000; - mal->txeobisr = 0x00000000; -} - -void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) +void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, + qemu_irq irqs[4]) { - ppc40x_mal_t *mal; + ppc4xx_mal_t *mal; int i; - mal = g_malloc0(sizeof(ppc40x_mal_t)); + assert(txcnum <= 32 && rxcnum <= 32); + mal = g_malloc0(sizeof(*mal)); + mal->txcnum = txcnum; + mal->rxcnum = rxcnum; + mal->txctpr = g_new0(uint32_t, txcnum); + mal->rxctpr = g_new0(uint32_t, rxcnum); + mal->rcbs = g_new0(uint32_t, rxcnum); for (i = 0; i < 4; i++) { mal->irqs[i] = irqs[i]; } - qemu_register_reset(&ppc40x_mal_reset, mal); + qemu_register_reset(&ppc4xx_mal_reset, mal); ppc_dcr_register(env, MAL0_CFG, mal, &dcr_read_mal, &dcr_write_mal); ppc_dcr_register(env, MAL0_ESR, @@ -981,20 +948,16 @@ void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) mal, &dcr_read_mal, &dcr_write_mal); ppc_dcr_register(env, MAL0_RXDEIR, mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP0R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP1R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP2R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCTP3R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCTP0R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCTP1R, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RCBS0, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RCBS1, - mal, &dcr_read_mal, &dcr_write_mal); + for (i = 0; i < txcnum; i++) { + ppc_dcr_register(env, MAL0_TXCTP0R + i, + mal, &dcr_read_mal, &dcr_write_mal); + } + for (i = 0; i < rxcnum; i++) { + ppc_dcr_register(env, MAL0_RXCTP0R + i, + mal, &dcr_read_mal, &dcr_write_mal); + } + for (i = 0; i < rxcnum; i++) { + ppc_dcr_register(env, MAL0_RCBS0 + i, + mal, &dcr_read_mal, &dcr_write_mal); + } } diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index db50cfac02..cb0bb55cec 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -53,7 +53,8 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, hwaddr *ram_sizes, int do_init); -void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]); +void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, + qemu_irq irqs[4]); #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" -- cgit v1.2.3-55-g7522 From 3b09bb0fb9bc03f3897da4940ba2fb808c00c038 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 20 Aug 2017 19:23:05 +0200 Subject: ppc4xx_i2c: QOMify Signed-off-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/ppc/ppc405.h | 2 - hw/ppc/ppc405_uc.c | 5 +- hw/ppc/ppc4xx_i2c.c | 154 ++++++++++++++------------------------------ include/hw/i2c/ppc4xx_i2c.h | 61 ++++++++++++++++++ 4 files changed, 113 insertions(+), 109 deletions(-) create mode 100644 include/hw/i2c/ppc4xx_i2c.h (limited to 'include') diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index 61ec739ebf..a9ffc87f19 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -59,8 +59,6 @@ struct ppc4xx_bd_info_t { ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd, uint32_t flags); -void ppc405_i2c_init(hwaddr base, qemu_irq irq); - CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, MemoryRegion ram_memories[4], hwaddr ram_bases[4], diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 3925e4c60b..8f44cb46d0 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -28,6 +28,7 @@ #include "hw/hw.h" #include "hw/ppc/ppc.h" #include "hw/boards.h" +#include "hw/i2c/ppc4xx_i2c.h" #include "ppc405.h" #include "hw/char/serial.h" #include "qemu/timer.h" @@ -1663,7 +1664,7 @@ CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, DEVICE_BIG_ENDIAN); } /* IIC controller */ - ppc405_i2c_init(0xef600500, pic[2]); + sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]); /* GPIO */ ppc405_gpio_init(0xef600700); /* CPU control */ @@ -2010,7 +2011,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, dma_irqs[3] = pic[8]; ppc405_dma_init(env, dma_irqs); /* IIC controller */ - ppc405_i2c_init(0xef600500, pic[2]); + sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]); /* GPIO */ ppc405_gpio_init(0xef600700); /* Serial ports */ diff --git a/hw/ppc/ppc4xx_i2c.c b/hw/ppc/ppc4xx_i2c.c index 15f2dea69e..5a6bde951e 100644 --- a/hw/ppc/ppc4xx_i2c.c +++ b/hw/ppc/ppc4xx_i2c.c @@ -27,42 +27,20 @@ #include "qemu-common.h" #include "cpu.h" #include "hw/hw.h" -#include "exec/address-spaces.h" -#include "hw/ppc/ppc.h" -#include "ppc405.h" +#include "hw/i2c/ppc4xx_i2c.h" /*#define DEBUG_I2C*/ -typedef struct ppc4xx_i2c_t ppc4xx_i2c_t; -struct ppc4xx_i2c_t { - qemu_irq irq; - MemoryRegion iomem; - uint8_t mdata; - uint8_t lmadr; - uint8_t hmadr; - uint8_t cntl; - uint8_t mdcntl; - uint8_t sts; - uint8_t extsts; - uint8_t sdata; - uint8_t lsadr; - uint8_t hsadr; - uint8_t clkdiv; - uint8_t intrmsk; - uint8_t xfrcnt; - uint8_t xtcntlss; - uint8_t directcntl; -}; +#define PPC4xx_I2C_MEM_SIZE 0x11 -static uint32_t ppc4xx_i2c_readb(void *opaque, hwaddr addr) +static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size) { - ppc4xx_i2c_t *i2c; - uint32_t ret; + PPC4xxI2CState *i2c = PPC4xx_I2C(opaque); + uint64_t ret; #ifdef DEBUG_I2C printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); #endif - i2c = opaque; switch (addr) { case 0x00: /*i2c_readbyte(&i2c->mdata);*/ @@ -115,22 +93,20 @@ static uint32_t ppc4xx_i2c_readb(void *opaque, hwaddr addr) break; } #ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret); + printf("%s: addr " TARGET_FMT_plx " %02" PRIx64 "\n", __func__, addr, ret); #endif return ret; } -static void ppc4xx_i2c_writeb(void *opaque, - hwaddr addr, uint32_t value) +static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) { - ppc4xx_i2c_t *i2c; - + PPC4xxI2CState *i2c = opaque; #ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); + printf("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", + __func__, addr, value); #endif - i2c = opaque; switch (addr) { case 0x00: i2c->mdata = value; @@ -181,71 +157,20 @@ static void ppc4xx_i2c_writeb(void *opaque, } } -static uint32_t ppc4xx_i2c_readw(void *opaque, hwaddr addr) -{ - uint32_t ret; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - ret = ppc4xx_i2c_readb(opaque, addr) << 8; - ret |= ppc4xx_i2c_readb(opaque, addr + 1); - - return ret; -} - -static void ppc4xx_i2c_writew(void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - ppc4xx_i2c_writeb(opaque, addr, value >> 8); - ppc4xx_i2c_writeb(opaque, addr + 1, value); -} - -static uint32_t ppc4xx_i2c_readl(void *opaque, hwaddr addr) -{ - uint32_t ret; - -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif - ret = ppc4xx_i2c_readb(opaque, addr) << 24; - ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16; - ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8; - ret |= ppc4xx_i2c_readb(opaque, addr + 3); - - return ret; -} - -static void ppc4xx_i2c_writel(void *opaque, - hwaddr addr, uint32_t value) -{ -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, - value); -#endif - ppc4xx_i2c_writeb(opaque, addr, value >> 24); - ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16); - ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8); - ppc4xx_i2c_writeb(opaque, addr + 3, value); -} - -static const MemoryRegionOps i2c_ops = { - .old_mmio = { - .read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, }, - .write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, }, - }, +static const MemoryRegionOps ppc4xx_i2c_ops = { + .read = ppc4xx_i2c_readb, + .write = ppc4xx_i2c_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, .endianness = DEVICE_NATIVE_ENDIAN, }; -static void ppc4xx_i2c_reset(void *opaque) +static void ppc4xx_i2c_reset(DeviceState *s) { - ppc4xx_i2c_t *i2c; + PPC4xxI2CState *i2c = PPC4xx_I2C(s); - i2c = opaque; i2c->mdata = 0x00; i2c->sdata = 0x00; i2c->cntl = 0x00; @@ -257,16 +182,35 @@ static void ppc4xx_i2c_reset(void *opaque) i2c->directcntl = 0x0F; } -void ppc405_i2c_init(hwaddr base, qemu_irq irq) +static void ppc4xx_i2c_init(Object *o) { - ppc4xx_i2c_t *i2c; + PPC4xxI2CState *s = PPC4xx_I2C(o); - i2c = g_malloc0(sizeof(ppc4xx_i2c_t)); - i2c->irq = irq; -#ifdef DEBUG_I2C - printf("%s: offset " TARGET_FMT_plx "\n", __func__, base); -#endif - memory_region_init_io(&i2c->iomem, NULL, &i2c_ops, i2c, "i2c", 0x011); - memory_region_add_subregion(get_system_memory(), base, &i2c->iomem); - qemu_register_reset(ppc4xx_i2c_reset, i2c); + memory_region_init_io(&s->iomem, OBJECT(s), &ppc4xx_i2c_ops, s, + TYPE_PPC4xx_I2C, PPC4xx_I2C_MEM_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); + s->bus = i2c_init_bus(DEVICE(s), "i2c"); } + +static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = ppc4xx_i2c_reset; +} + +static const TypeInfo ppc4xx_i2c_type_info = { + .name = TYPE_PPC4xx_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PPC4xxI2CState), + .instance_init = ppc4xx_i2c_init, + .class_init = ppc4xx_i2c_class_init, +}; + +static void ppc4xx_i2c_register_types(void) +{ + type_register_static(&ppc4xx_i2c_type_info); +} + +type_init(ppc4xx_i2c_register_types) diff --git a/include/hw/i2c/ppc4xx_i2c.h b/include/hw/i2c/ppc4xx_i2c.h new file mode 100644 index 0000000000..e53042f6d4 --- /dev/null +++ b/include/hw/i2c/ppc4xx_i2c.h @@ -0,0 +1,61 @@ +/* + * PPC4xx I2C controller emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef PPC4XX_I2C_H +#define PPC4XX_I2C_H + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "hw/sysbus.h" +#include "hw/i2c/i2c.h" + +#define TYPE_PPC4xx_I2C "ppc4xx-i2c" +#define PPC4xx_I2C(obj) OBJECT_CHECK(PPC4xxI2CState, (obj), TYPE_PPC4xx_I2C) + +typedef struct PPC4xxI2CState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + I2CBus *bus; + qemu_irq irq; + MemoryRegion iomem; + uint8_t mdata; + uint8_t lmadr; + uint8_t hmadr; + uint8_t cntl; + uint8_t mdcntl; + uint8_t sts; + uint8_t extsts; + uint8_t sdata; + uint8_t lsadr; + uint8_t hsadr; + uint8_t clkdiv; + uint8_t intrmsk; + uint8_t xfrcnt; + uint8_t xtcntlss; + uint8_t directcntl; +} PPC4xxI2CState; + +#endif /* PPC4XX_I2C_H */ -- cgit v1.2.3-55-g7522 From fa98fbfcdfcb980b4a690b8bc93ab597935087b1 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Fri, 18 Aug 2017 15:50:22 +1000 Subject: PPC: KVM: Support machine option to set VSMT mode KVM now allows writing to KVM_CAP_PPC_SMT which has previously been read only. Doing so causes KVM to act, for that VM, as if the host's SMT mode was the given value. This is particularly important on Power 9 systems because their default value is 1, but they are able to support values up to 8. This patch introduces a way to control this capability via a new machine property called VSMT ("Virtual SMT"). If the value is not set on the command line a default is chosen that is, when possible, compatible with legacy systems. Note that the intialization of KVM_CAP_PPC_SMT has changed slightly because it has changed (in KVM) from a global capability to a VM-specific one. This won't cause a problem on older KVMs because VM capabilities fall back to global ones. Signed-off-by: Sam Bobroff Signed-off-by: David Gibson --- hw/ppc/spapr.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 1 + target/ppc/kvm.c | 39 ++++++++++++++++++++++- target/ppc/kvm_ppc.h | 12 ++++++++ target/ppc/translate_init.c | 14 --------- 5 files changed, 126 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 067f571416..caffa12763 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "sysemu/sysemu.h" #include "sysemu/numa.h" #include "hw/hw.h" @@ -2165,6 +2166,61 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) g_free(type); } +static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) +{ + Error *local_err = NULL; + bool vsmt_user = !!spapr->vsmt; + int kvm_smt = kvmppc_smt_threads(); + int ret; + + if (!kvm_enabled() && (smp_threads > 1)) { + error_setg(&local_err, "TCG cannot support more than 1 thread/core " + "on a pseries machine"); + goto out; + } + if (!is_power_of_2(smp_threads)) { + error_setg(&local_err, "Cannot support %d threads/core on a pseries " + "machine because it must be a power of 2", smp_threads); + goto out; + } + + /* Detemine the VSMT mode to use: */ + if (vsmt_user) { + if (spapr->vsmt < smp_threads) { + error_setg(&local_err, "Cannot support VSMT mode %d" + " because it must be >= threads/core (%d)", + spapr->vsmt, smp_threads); + goto out; + } + /* In this case, spapr->vsmt has been set by the command line */ + } else { + /* Choose a VSMT mode that may be higher than necessary but is + * likely to be compatible with hosts that don't have VSMT. */ + spapr->vsmt = MAX(kvm_smt, smp_threads); + } + + /* KVM: If necessary, set the SMT mode: */ + if (kvm_enabled() && (spapr->vsmt != kvm_smt)) { + ret = kvmppc_set_smt_threads(spapr->vsmt); + if (ret) { + error_setg(&local_err, + "Failed to set KVM's VSMT mode to %d (errno %d)", + spapr->vsmt, ret); + if (!vsmt_user) { + error_append_hint(&local_err, "On PPC, a VM with %d threads/" + "core on a host with %d threads/core requires " + " the use of VSMT mode %d.\n", + smp_threads, kvm_smt, spapr->vsmt); + } + kvmppc_hint_smt_possible(&local_err); + goto out; + } + } + /* else TCG: nothing to do currently */ +out: + error_propagate(errp, local_err); +} + /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(MachineState *machine) { @@ -2297,6 +2353,8 @@ static void ppc_spapr_init(MachineState *machine) spapr_cpu_parse_features(spapr); + spapr_set_vsmt_mode(spapr, &error_fatal); + spapr_init_cpus(spapr); if (kvm_enabled()) { @@ -2681,6 +2739,18 @@ static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp) } } +static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + +static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + visit_type_uint32(v, name, (uint32_t *)opaque, errp); +} + static void spapr_machine_initfn(Object *obj) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -2711,6 +2781,11 @@ static void spapr_machine_initfn(Object *obj) object_property_set_description(obj, "resize-hpt", "Resizing of the Hash Page Table (enabled, disabled, required)", NULL); + object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt, + spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort); + object_property_set_description(obj, "vsmt", + "Virtual SMT: KVM behaves as if this were" + " the host's SMT mode", &error_abort); } static void spapr_machine_finalizefn(Object *obj) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 91617e3277..c1b365f564 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -99,6 +99,7 @@ struct sPAPRMachineState { uint64_t rtc_offset; /* Now used only during incoming migration */ struct PPCTimebase tb; bool has_graphics; + uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */ Notifier epow_notifier; QTAILQ_HEAD(, sPAPREventLogEntry) pending_events; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index f1d54106ac..b6bd0fa7a6 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -74,6 +74,7 @@ static int cap_interrupt_level = false; static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; +static int cap_ppc_smt_possible; static int cap_ppc_rma; static int cap_spapr_tce; static int cap_spapr_tce_64; @@ -130,7 +131,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); - cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); + cap_ppc_smt_possible = kvm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64); @@ -144,6 +145,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) * only activated after this by kvmppc_set_papr() */ cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); + cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT); cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX); cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3); @@ -2134,6 +2136,41 @@ int kvmppc_smt_threads(void) return cap_ppc_smt ? cap_ppc_smt : 1; } +int kvmppc_set_smt_threads(int smt) +{ + int ret; + + ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_SMT, 0, smt, 0); + if (!ret) { + cap_ppc_smt = smt; + } + return ret; +} + +void kvmppc_hint_smt_possible(Error **errp) +{ + int i; + GString *g; + char *s; + + assert(kvm_enabled()); + if (cap_ppc_smt_possible) { + g = g_string_new("Available VSMT modes:"); + for (i = 63; i >= 0; i--) { + if ((1UL << i) & cap_ppc_smt_possible) { + g_string_append_printf(g, " %lu", (1UL << i)); + } + } + s = g_string_free(g, false); + error_append_hint(errp, "%s.\n", s); + g_free(s); + } else { + error_append_hint(errp, + "This KVM seems to be too old to support VSMT.\n"); + } +} + + #ifdef TARGET_PPC64 off_t kvmppc_alloc_rma(void **rma) { diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 381afe6240..e6711fc2b7 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -29,6 +29,8 @@ void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); int kvmppc_smt_threads(void); +void kvmppc_hint_smt_possible(Error **errp); +int kvmppc_set_smt_threads(int smt); int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits); int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits); int kvmppc_set_tcr(PowerPCCPU *cpu); @@ -148,6 +150,16 @@ static inline int kvmppc_smt_threads(void) return 1; } +static inline void kvmppc_hint_smt_possible(Error **errp) +{ + return; +} + +static inline int kvmppc_set_smt_threads(int smt) +{ + return 0; +} + static inline int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits) { return 0; diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 08ef74f064..703ea12f2a 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -9907,20 +9907,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) int max_smt = kvmppc_smt_threads(); #endif -#if !defined(CONFIG_USER_ONLY) - if (smp_threads > max_smt) { - error_setg(errp, "Cannot support more than %d threads on PPC with %s", - max_smt, kvm_enabled() ? "KVM" : "TCG"); - return; - } - if (!is_power_of_2(smp_threads)) { - error_setg(errp, "Cannot support %d threads on PPC with %s, " - "threads count must be a power of 2.", - smp_threads, kvm_enabled() ? "KVM" : "TCG"); - return; - } -#endif - cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); -- cgit v1.2.3-55-g7522