From 4e9200a0a0f89ad2b26f6aa42e1fca16b364a8c8 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Tue, 1 Nov 2011 09:57:52 +0000 Subject: [PATCH 01/10] PPC: monitor: add ability to dump SLB entries When run with a PPC Book3S (server) CPU Currently 'info tlb' in the qemu monitor reports "dump_mmu: unimplemented". However, during bringup work, it can be quite handy to have the SLB entries, which are available in the CPUPPCState. This patch adds an implementation of info tlb for book3s, which dumps the SLB. Signed-off-by: Nishanth Aravamudan Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/helper.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 137a494201..58474536c0 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1545,12 +1545,40 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, } } +#if defined(TARGET_PPC64) +static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf, + CPUState *env) +{ + int i; + uint64_t slbe, slbv; + + cpu_synchronize_state(env); + + cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n"); + for (i = 0; i < env->slb_nr; i++) { + slbe = env->slb[i].esid; + slbv = env->slb[i].vsid; + if (slbe == 0 && slbv == 0) { + continue; + } + cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", + i, slbe, slbv); + } +} +#endif + void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) { switch (env->mmu_model) { case POWERPC_MMU_BOOKE206: mmubooke206_dump_mmu(f, cpu_fprintf, env); break; +#if defined(TARGET_PPC64) + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: + mmubooks_dump_mmu(f, cpu_fprintf, env); + break; +#endif default: cpu_fprintf(f, "%s: unimplemented\n", __func__); } From 33bcd98c4e9fe0866807bef6253a057c82087539 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Nov 2011 16:41:59 +0100 Subject: [PATCH 02/10] console: Fix segfault on screendump without VGA adapter When trying to create a screen dump without having any VGA adapter inside the guest, QEMU segfaults. This is because it's trying to switch back to the "previous" screen it was on before dumping the VGA screen. Unfortunately, in my case there simply is no previous screen so it accesses a NULL pointer. Fix it by checking if previous_active_console is actually available. This is 1.0 material. Signed-off-by: Alexander Graf --- console.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/console.c b/console.c index 223f8fd9a4..135394f6f6 100644 --- a/console.c +++ b/console.c @@ -186,7 +186,9 @@ void vga_hw_screen_dump(const char *filename) consoles[0]->hw_screen_dump(consoles[0]->hw, filename); } - console_select(previous_active_console->index); + if (previous_active_console) { + console_select(previous_active_console->index); + } } void vga_hw_text_update(console_ch_t *chardata) From 157feeadbaec09fe4dca539a24f6f6d327d6eeb6 Mon Sep 17 00:00:00 2001 From: Liu Yu-B13201 Date: Mon, 28 Nov 2011 20:41:18 +0000 Subject: [PATCH 03/10] kvm-ppc: halt secondary cpus when guest reset When guest reset, we need to halt secondary cpus until guest kick them. This already works for tcg. The patch add the support for kvm. Signed-off-by: Liu Yu Signed-off-by: Alexander Graf [agraf: remove in-kernel irqchip code] --- hw/ppce500_spin.c | 1 + target-ppc/kvm.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index df74953874..e7b1453855 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -112,6 +112,7 @@ static void spin_kick(void *data) env->halted = 0; env->exception_index = -1; + env->stopped = 0; qemu_cpu_kick(env); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 429349fb94..9b2e605b67 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -504,7 +504,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run) int kvm_arch_process_async_events(CPUState *env) { - return 0; + return env->halted; } static int kvmppc_handle_halt(CPUState *env) From 1fc02533e73ad66f756f07efdf80fa9bef5afbc8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Dec 2011 18:24:28 +0000 Subject: [PATCH 04/10] pseries: Remove hcalls callback For forgotten historical reasons, PAPR hypercalls for specific virtual IO devices (oh which there are quite a number) are registered via a callback in the VIOsPAPRDeviceInfo structure. This is kind of ugly, so this patch instead registers hypercalls from device_init() functions for each device type. This works just as well, and is cleaner. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_llan.c | 17 ++++++----------- hw/spapr_vio.c | 13 ------------- hw/spapr_vio.h | 1 - hw/spapr_vty.c | 9 ++------- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index abe12973e6..45674c4cb9 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -474,16 +474,6 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -static void vlan_hcalls(VIOsPAPRBus *bus) -{ - spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan); - spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan); - spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan); - spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER, - h_add_logical_lan_buffer); - spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl); -} - static VIOsPAPRDeviceInfo spapr_vlan = { .init = spapr_vlan_init, .devnode = spapr_vlan_devnode, @@ -491,7 +481,6 @@ static VIOsPAPRDeviceInfo spapr_vlan = { .dt_type = "network", .dt_compatible = "IBM,l-lan", .signal_mask = 0x1, - .hcalls = vlan_hcalls, .qdev.name = "spapr-vlan", .qdev.size = sizeof(VIOsPAPRVLANDevice), .qdev.props = (Property[]) { @@ -504,5 +493,11 @@ static VIOsPAPRDeviceInfo spapr_vlan = { static void spapr_vlan_register(void) { spapr_vio_bus_register_withprop(&spapr_vlan); + spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan); + spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan); + spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan); + spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER, + h_add_logical_lan_buffer); + spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl); } device_init(spapr_vlan_register); diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 2dcc0361ed..5a35541837 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -684,7 +684,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void) VIOsPAPRBus *bus; BusState *qbus; DeviceState *dev; - DeviceInfo *qinfo; /* Create bridge device */ dev = qdev_create(NULL, "spapr-vio-bridge"); @@ -711,18 +710,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void) spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass); spapr_rtas_register("quiesce", rtas_quiesce); - for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { - VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; - - if (qinfo->bus_info != &spapr_vio_bus_info) { - continue; - } - - if (info->hcalls) { - info->hcalls(bus); - } - } - return bus; } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index a325a5f4b3..2430d45bdb 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -75,7 +75,6 @@ typedef struct { const char *dt_name, *dt_type, *dt_compatible; target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); - void (*hcalls)(VIOsPAPRBus *bus); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); } VIOsPAPRDeviceInfo; diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index f23cc36231..e2173142d8 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -135,18 +135,11 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev) qdev_init_nofail(dev); } -static void vty_hcalls(VIOsPAPRBus *bus) -{ - spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); - spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); -} - static VIOsPAPRDeviceInfo spapr_vty = { .init = spapr_vty_init, .dt_name = "vty", .dt_type = "serial", .dt_compatible = "hvterm1", - .hcalls = vty_hcalls, .qdev.name = "spapr-vty", .qdev.size = sizeof(VIOsPAPRVTYDevice), .qdev.props = (Property[]) { @@ -182,5 +175,7 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) static void spapr_vty_register(void) { spapr_vio_bus_register_withprop(&spapr_vty); + spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); + spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); } device_init(spapr_vty_register); From 6e806cc38bb1a79ec52d7d86da4aca11cdc302c8 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Mon, 12 Dec 2011 18:24:30 +0000 Subject: [PATCH 05/10] pseries: FDT NUMA extensions to support multi-node guests Add NUMA specific properties to guest's device tree to boot a multi-node guests. This patch adds the following properties: ibm,associativity ibm,architecture-vec-5 ibm,associativity-reference-points With this, it becomes possible to use -numa option on pseries targets. Signed-off-by: Bharata B Rao Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++------ hw/spapr.h | 1 + 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 2b901f105e..18832709a3 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -97,6 +97,44 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num) return qirq; } +static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) +{ + int ret = 0, offset; + CPUState *env; + char cpu_model[32]; + int smt = kvmppc_smt_threads(); + + assert(spapr->cpu_model); + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + uint32_t associativity[] = {cpu_to_be32(0x5), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(env->numa_node), + cpu_to_be32(env->cpu_index)}; + + if ((env->cpu_index % smt) != 0) { + continue; + } + + snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, + env->cpu_index); + + offset = fdt_path_offset(fdt, cpu_model); + if (offset < 0) { + return offset; + } + + ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, + sizeof(associativity)); + if (ret < 0) { + return ret; + } + } + return ret; +} + static void *spapr_create_fdt_skel(const char *cpu_model, target_phys_addr_t rma_size, target_phys_addr_t initrd_base, @@ -107,9 +145,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, { void *fdt; CPUState *env; - uint64_t mem_reg_property_rma[] = { 0, cpu_to_be64(rma_size) }; - uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size), - cpu_to_be64(ram_size - rma_size) }; + uint64_t mem_reg_property[2]; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; @@ -119,6 +155,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model, int i; char *modelname; int smt = kvmppc_smt_threads(); + unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; + uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; + uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0)}; + char mem_name[32]; + target_phys_addr_t node0_size, mem_start; #define _FDT(exp) \ do { \ @@ -146,6 +189,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, /* /chosen */ _FDT((fdt_begin_node(fdt, "chosen"))); + /* Set Form1_affinity */ + _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5)))); + _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline))); _FDT((fdt_property(fdt, "linux,initrd-start", &start_prop, sizeof(start_prop)))); @@ -164,24 +210,54 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); /* memory node(s) */ - _FDT((fdt_begin_node(fdt, "memory@0"))); + node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + if (rma_size > node0_size) { + rma_size = node0_size; + } + /* RMA */ + mem_reg_property[0] = 0; + mem_reg_property[1] = cpu_to_be64(rma_size); + _FDT((fdt_begin_node(fdt, "memory@0"))); _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property_rma, - sizeof(mem_reg_property_rma)))); + _FDT((fdt_property(fdt, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_property(fdt, "ibm,associativity", associativity, + sizeof(associativity)))); _FDT((fdt_end_node(fdt))); - if (ram_size > rma_size) { - char mem_name[32]; + /* RAM: Node 0 */ + if (node0_size > rma_size) { + mem_reg_property[0] = cpu_to_be64(rma_size); + mem_reg_property[1] = cpu_to_be64(node0_size - rma_size); - sprintf(mem_name, "memory@%" PRIx64, (uint64_t)rma_size); + sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size); _FDT((fdt_begin_node(fdt, mem_name))); _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma, - sizeof(mem_reg_property_nonrma)))); + _FDT((fdt_property(fdt, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_property(fdt, "ibm,associativity", associativity, + sizeof(associativity)))); _FDT((fdt_end_node(fdt))); } + /* RAM: Node 1 and beyond */ + mem_start = node0_size; + for (i = 1; i < nb_numa_nodes; i++) { + mem_reg_property[0] = cpu_to_be64(mem_start); + mem_reg_property[1] = cpu_to_be64(node_mem[i]); + associativity[3] = associativity[4] = cpu_to_be32(i); + sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); + _FDT((fdt_begin_node(fdt, mem_name))); + _FDT((fdt_property_string(fdt, "device_type", "memory"))); + _FDT((fdt_property(fdt, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_property(fdt, "ibm,associativity", associativity, + sizeof(associativity)))); + _FDT((fdt_end_node(fdt))); + mem_start += node_mem[i]; + } + /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -194,6 +270,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, modelname[i] = toupper(modelname[i]); } + /* This is needed during FDT finalization */ + spapr->cpu_model = g_strdup(modelname); + for (env = first_cpu; env != NULL; env = env->next_cpu) { int index = env->cpu_index; uint32_t servers_prop[smp_threads]; @@ -280,6 +359,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, sizeof(hypertas_prop)))); + _FDT((fdt_property(fdt, "ibm,associativity-reference-points", + refpoints, sizeof(refpoints)))); + _FDT((fdt_end_node(fdt))); /* interrupt controller */ @@ -351,6 +433,14 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); } + /* Advertise NUMA via ibm,associativity */ + if (nb_numa_nodes > 1) { + ret = spapr_set_associativity(fdt, spapr); + if (ret < 0) { + fprintf(stderr, "Couldn't set up NUMA device tree properties\n"); + } + } + _FDT((fdt_pack(fdt))); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); diff --git a/hw/spapr.h b/hw/spapr.h index d624841362..e946a3433e 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -21,6 +21,7 @@ typedef struct sPAPREnvironment { target_ulong entry_point; int next_irq; int rtc_offset; + char *cpu_model; } sPAPREnvironment; #define H_SUCCESS 0 From 05c194384f836240ea4c2da5fa3be43a54bff021 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Dec 2011 18:24:32 +0000 Subject: [PATCH 06/10] pseries: Emit device tree nodes in reg order Although in theory the device tree has no inherent ordering, in practice the order of nodes in the device tree does effect the order that devices are detected by software. Currently the ordering is determined by the order the devices appear on the QEMU command line. Although that does give the user control over the ordering, it is fragile, especially when the user does not generate the command line manually - eg. when using libvirt etc. So order the device tree based on the reg value, ie. the address of on the VIO bus of the devices. This gives us a sane and stable ordering. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf [agraf] add braces --- hw/spapr_vio.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 5a35541837..2cce421a8c 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -736,21 +736,61 @@ static void spapr_vio_register_devices(void) device_init(spapr_vio_register_devices) #ifdef CONFIG_FDT +static int compare_reg(const void *p1, const void *p2) +{ + VIOsPAPRDevice const *dev1, *dev2; + + dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1; + dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2; + + if (dev1->reg < dev2->reg) { + return -1; + } + if (dev1->reg == dev2->reg) { + return 0; + } + + /* dev1->reg > dev2->reg */ + return 1; +} + int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt) { - DeviceState *qdev; - int ret = 0; + DeviceState *qdev, **qdevs; + int i, num, ret = 0; + /* Count qdevs on the bus list */ + num = 0; QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { - VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; + num++; + } + + /* Copy out into an array of pointers */ + qdevs = g_malloc(sizeof(qdev) * num); + num = 0; + QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { + qdevs[num++] = qdev; + } + + /* Sort the array */ + qsort(qdevs, num, sizeof(qdev), compare_reg); + + /* Hack alert. Give the devices to libfdt in reverse order, we happen + * to know that will mean they are in forward order in the tree. */ + for (i = num - 1; i >= 0; i--) { + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]); ret = vio_make_devnode(dev, fdt); if (ret < 0) { - return ret; + goto out; } } - return 0; + ret = 0; +out: + free(qdevs); + + return ret; } #endif /* CONFIG_FDT */ From 98331f8ad6a3e2cfbb402d72e6be47eac7706251 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Dec 2011 18:24:33 +0000 Subject: [PATCH 07/10] pseries: Add a routine to find a stable "default" vty and use it In vty_lookup() we have a special case for supporting early debug in the kernel. This accepts reg == 0 as a special case to mean "any vty". We implement this by searching the vtys on the bus and returning the first we find. This means that the vty we chose depends on the order the vtys are specified on the QEMU command line - because that determines the order of the vtys on the bus. We'd rather the command line order was irrelevant, so instead return the vty with the lowest reg value. This is still a guess as to what the user really means, but it is at least stable WRT command line ordering. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf [agraf] fix braces --- hw/spapr_vty.c | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index e2173142d8..2923ca709d 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -149,24 +149,53 @@ static VIOsPAPRDeviceInfo spapr_vty = { }, }; +static VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) +{ + VIOsPAPRDevice *sdev, *selected; + DeviceState *iter; + + /* + * To avoid the console bouncing around we want one VTY to be + * the "default". We haven't really got anything to go on, so + * arbitrarily choose the one with the lowest reg value. + */ + + selected = NULL; + QTAILQ_FOREACH(iter, &bus->bus.children, sibling) { + /* Only look at VTY devices */ + if (iter->info != &spapr_vty.qdev) { + continue; + } + + sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter); + + /* First VTY we've found, so it is selected for now */ + if (!selected) { + selected = sdev; + continue; + } + + /* Choose VTY with lowest reg value */ + if (sdev->reg < selected->reg) { + selected = sdev; + } + } + + return selected; +} + static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) { VIOsPAPRDevice *sdev; sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!sdev && reg == 0) { - DeviceState *qdev; - /* Hack for kernel early debug, which always specifies reg==0. - * We search all VIO devices, and grab the first available vty - * device. This attempts to mimic existing PowerVM behaviour + * We search all VIO devices, and grab the vty with the lowest + * reg. This attempts to mimic existing PowerVM behaviour * (early debug does work there, despite having no vty with * reg==0. */ - QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) { - if (qdev->info == &spapr_vty.qdev) { - return DO_UPCAST(VIOsPAPRDevice, qdev, qdev); - } - } + return spapr_vty_get_default(spapr->vio_bus); } return sdev; From 68f3a94c64bbaaf8c7f2daa70de1b5d87a432f86 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 13 Dec 2011 15:24:34 +1100 Subject: [PATCH 08/10] pseries: Populate "/chosen/linux,stdout-path" in the FDT There is a device tree property "/chosen/linux,stdout-path" which indicates which device should be used as stdout - ie. "the console". Currently we don't specify anything, which means both firmware and Linux choose something arbitrarily. Use the routine we added in the last patch to pick a default vty and specify it as stdout. Currently SLOF doesn't use the property, but we are hoping to update it to do so. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 2 ++ hw/spapr_vio.c | 34 ++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 3 +++ hw/spapr_vty.c | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index 18832709a3..6a543de651 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -441,6 +441,8 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, } } + spapr_populate_chosen_stdout(fdt, spapr->vio_bus); + _FDT((fdt_pack(fdt))); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 2cce421a8c..cd03416958 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -793,4 +793,38 @@ out: return ret; } + +int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) +{ + VIOsPAPRDevice *dev; + char *name, *path; + int ret, offset; + + dev = spapr_vty_get_default(bus); + if (!dev) + return 0; + + offset = fdt_path_offset(fdt, "/chosen"); + if (offset < 0) { + return offset; + } + + name = vio_format_dev_name(dev); + if (!name) { + return -ENOMEM; + } + + if (asprintf(&path, "/vdevice/%s", name) < 0) { + path = NULL; + ret = -ENOMEM; + goto out; + } + + ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); +out: + free(name); + free(path); + + return ret; +} #endif /* CONFIG_FDT */ diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 2430d45bdb..0984d559db 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -82,6 +82,7 @@ extern VIOsPAPRBus *spapr_vio_bus_init(void); extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info); extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); +extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus); extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); @@ -107,6 +108,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev); void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd); void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg); +VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); + int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); void spapr_vio_quiesce(void); diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 2923ca709d..c5fb0968ed 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -149,7 +149,7 @@ static VIOsPAPRDeviceInfo spapr_vty = { }, }; -static VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) +VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) { VIOsPAPRDevice *sdev, *selected; DeviceState *iter; From 9fc380d3ed1cfac7d87dbe2a140e465cac58ed7b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 12 Dec 2011 18:24:35 +0000 Subject: [PATCH 09/10] pseries: Check for duplicate addresses on the spapr-vio bus Check that devices on the spapr vio bus aren't given duplicate addresses. Currently we will not run with duplicate devices, the fdt code will spot it, but the error reporting is not great. With this patch we can report the error nicely in terms of the device names given by the user. Signed-off-by: Michael Ellerman Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vio.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index cd03416958..7a86dc8d2c 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -621,11 +621,43 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); } +static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info) +{ + VIOsPAPRDevice *other_sdev; + DeviceState *qdev; + VIOsPAPRBus *sbus; + + sbus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus); + + /* + * Check two device aren't given clashing addresses by the user (or some + * other mechanism). We have to open code this because we have to check + * for matches with devices other than us. + */ + QTAILQ_FOREACH(qdev, &sbus->bus.children, sibling) { + other_sdev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + + if (other_sdev != sdev && other_sdev->reg == sdev->reg) { + fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n", + info->qdev.name, other_sdev->qdev.info->name, sdev->reg); + return -EEXIST; + } + } + + return 0; +} + static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; char *id; + int ret; + + ret = spapr_vio_check_reg(dev, info); + if (ret) { + return ret; + } /* Don't overwrite ids assigned on the command line */ if (!dev->qdev.id) { From f7aa558396dd0f6b7a2b22c05cb503c655854102 Mon Sep 17 00:00:00 2001 From: Varun Sethi Date: Thu, 22 Dec 2011 12:26:17 +0000 Subject: [PATCH 10/10] PPC: Add description for the Freescale e500mc core. This core is found on chips such as p4080, p3041, p2040, and p5020. More needs to be done to make this viable for TCG (such as missing SPRs and instructions), but this suffices to get KVM running with appropriate kernel support. Signed-off-by: Varun Sethi [scottwood@freescale.com: tweak some flags] Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 56 +++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8a7233fc82..47d73a6bf9 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2,6 +2,7 @@ * PowerPC CPU initialization for qemu. * * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright 2011 Freescale Semiconductor, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -4399,6 +4400,33 @@ static void init_proc_e300 (CPUPPCState *env) #define check_pow_e500v2 check_pow_hid0 #define init_proc_e500v2 init_proc_e500v2 +/* e500mc core */ +#define POWERPC_INSNS_e500mc (PPC_INSNS_BASE | PPC_ISEL | \ + PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \ + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_FLOAT | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ + PPC_FLOAT_STFIWX | PPC_WAIT | \ + PPC_MEM_TLBSYNC | PPC_TLBIVAX) +#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206) +#define POWERPC_MSRM_e500mc (0x000000001402FB36ULL) +#define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206) +#define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_e500mc (PPC_FLAGS_INPUT_BookE) +/* Fixme: figure out the correct flag for e500mc */ +#define POWERPC_BFDM_e500mc (bfd_mach_ppc_e500) +#define POWERPC_FLAG_e500mc (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_e500mc check_pow_none +#define init_proc_e500mc init_proc_e500mc + +enum fsl_e500_version { + fsl_e500v1, + fsl_e500v2, + fsl_e500mc, +}; + static void init_proc_e500 (CPUPPCState *env, int version) { uint32_t tlbncfg[2]; @@ -4430,15 +4458,26 @@ static void init_proc_e500 (CPUPPCState *env, int version) env->nb_ways = 2; env->id_tlbs = 0; switch (version) { - case 1: + case fsl_e500v1: /* e500v1 */ tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256); tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); + env->dcache_line_size = 32; + env->icache_line_size = 32; break; - case 2: + case fsl_e500v2: /* e500v2 */ tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); + env->dcache_line_size = 32; + env->icache_line_size = 32; + break; + case fsl_e500mc: + /* e500mc */ + tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); + tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); + env->dcache_line_size = 64; + env->icache_line_size = 64; break; default: cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); @@ -4522,20 +4561,23 @@ static void init_proc_e500 (CPUPPCState *env, int version) #endif init_excp_e200(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppce500_irq_init(env); } static void init_proc_e500v1(CPUPPCState *env) { - init_proc_e500(env, 1); + init_proc_e500(env, fsl_e500v1); } static void init_proc_e500v2(CPUPPCState *env) { - init_proc_e500(env, 2); + init_proc_e500(env, fsl_e500v2); +} + +static void init_proc_e500mc(CPUPPCState *env) +{ + init_proc_e500(env, fsl_e500mc); } /* Non-embedded PowerPC */ @@ -7070,6 +7112,7 @@ enum { CPU_POWERPC_e500v2_v21 = 0x80210021, CPU_POWERPC_e500v2_v22 = 0x80210022, CPU_POWERPC_e500v2_v30 = 0x80210030, + CPU_POWERPC_e500mc = 0x80230020, /* MPC85xx microcontrollers */ #define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11 #define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 @@ -8471,6 +8514,7 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2), /* PowerPC e500v2 v3.0 core */ POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2), + POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc), /* PowerPC e500 microcontrollers */ /* MPC8533 */ POWERPC_DEF_SVR("MPC8533",