From 3b961124bf8a0b490e4fc3a6a39e004500ae6967 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Sat, 30 Mar 2013 06:40:49 +0000 Subject: PPC: e500: advertise 4.2 MPIC only if KVM supports EPR Older KVM versions don't support EPR which breaks guests when we announce MPIC variants that support EPR. Catch that case and expose only MPIC version 2.0 which tells the guest that we don't support the EPR capability yet. Signed-off-by: Stuart Yoder [agraf: Add comment, route cap check through kvm_ppc.c] Signed-off-by: Alexander Graf --- hw/ppc/e500plat.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'hw') diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 7292ce1290..c85299588c 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -16,6 +16,7 @@ #include "sysemu/device_tree.h" #include "hw/pci/pci.h" #include "hw/ppc/openpic.h" +#include "kvm_ppc.h" static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) { @@ -48,6 +49,12 @@ static void e500plat_init(QEMUMachineInitArgs *args) .mpic_version = OPENPIC_MODEL_FSL_MPIC_42, }; + /* Older KVM versions don't support EPR which breaks guests when we announce + MPIC variants that support EPR. Revert to an older one for those */ + if (kvm_enabled() && !kvmppc_has_cap_epr()) { + params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20; + } + ppce500_init(¶ms); } -- cgit v1.2.1 From 2cf3eb6df552cee74b52de9989e270b74e42847e Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Fri, 29 Mar 2013 02:06:27 +0000 Subject: PPC: Remove env->hreset_excp_prefix This value is not needed if we use correctly the MSR[IP] bit. excp_prefix is always 0x00000000, except when the MSR[IP] bit is implemented and set to 1, in that case excp_prefix is 0xfff00000. The handling of MSR[IP] was already implemented but not used at reset because the value of env->msr was changed "manually". The patch uses the function hreg_store_msr() to set env->msr, this ensures a good handling of MSR[IP] at reset, and therefore a good value for excp_prefix. Signed-off-by: Fabien Chouteau Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7a425011da..e35c26f577 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -801,8 +801,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); - /* PAPR always has exception vectors in RAM not ROM */ - env->hreset_excp_prefix = 0; + /* PAPR always has exception vectors in RAM not ROM. To ensure this, + * MSR[IP] should never be set. + */ + env->msr_mask &= ~(1 << 6); /* Tell KVM that we're in PAPR mode */ if (kvm_enabled()) { -- cgit v1.2.1 From 31f2cb8ff415e376b05335dcf63ba38c00f29e5e Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Sun, 24 Feb 2013 18:16:21 +0000 Subject: Enable kvm emulated watchdog Enable the KVM emulated watchdog if KVM supports (use the capability enablement in watchdog handler). Also watchdog exit (KVM_EXIT_WATCHDOG) handling is added. Watchdog state machine is cleared whenever VM state changes to running. This is to handle the cases like return from debug halt etc. Signed-off-by: Bharat Bhushan [agraf: rebase to current code base, fix non-kvm cases] Signed-off-by: Alexander Graf --- hw/ppc/ppc_booke.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index 585f53b912..e41b036b8e 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -28,6 +28,7 @@ #include "hw/timer/m48t59.h" #include "qemu/log.h" #include "hw/loader.h" +#include "kvm_ppc.h" /* Timer Control Register */ @@ -211,6 +212,7 @@ void store_booke_tsr(CPUPPCState *env, target_ulong val) PowerPCCPU *cpu = ppc_env_get_cpu(env); env->spr[SPR_BOOKE_TSR] &= ~val; + kvmppc_clear_tsr_bits(cpu, val); booke_update_irq(cpu); } @@ -222,6 +224,7 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) tb_env = env->tb_env; env->spr[SPR_BOOKE_TCR] = val; + kvmppc_set_tcr(cpu); booke_update_irq(cpu); @@ -234,7 +237,6 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) booke_get_wdt_target(env, tb_env), &booke_timer->wdt_next, booke_timer->wdt_timer); - } static void ppc_booke_timer_reset_handle(void *opaque) @@ -242,16 +244,39 @@ static void ppc_booke_timer_reset_handle(void *opaque) PowerPCCPU *cpu = opaque; CPUPPCState *env = &cpu->env; - env->spr[SPR_BOOKE_TSR] = 0; - env->spr[SPR_BOOKE_TCR] = 0; + store_booke_tcr(env, 0); + store_booke_tsr(env, -1); +} - booke_update_irq(cpu); +/* + * This function will be called whenever the CPU state changes. + * CPU states are defined "typedef enum RunState". + * Regarding timer, When CPU state changes to running after debug halt + * or similar cases which takes time then in between final watchdog + * expiry happenes. This will cause exit to QEMU and configured watchdog + * action will be taken. To avoid this we always clear the watchdog state when + * state changes to running. + */ +static void cpu_state_change_handler(void *opaque, int running, RunState state) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + if (!running) { + return; + } + + /* + * Clear watchdog interrupt condition by clearing TSR. + */ + store_booke_tsr(env, TSR_ENW | TSR_WIS | TSR_WRS_MASK); } void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { ppc_tb_t *tb_env; booke_timer_t *booke_timer; + int ret = 0; tb_env = g_malloc0(sizeof(ppc_tb_t)); booke_timer = g_malloc0(sizeof(booke_timer_t)); @@ -269,5 +294,17 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) booke_timer->wdt_timer = qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); + ret = kvmppc_booke_watchdog_enable(cpu); + + if (ret) { + /* TODO: Start the QEMU emulated watchdog if not running on KVM. + * Also start the QEMU emulated watchdog if KVM does not support + * emulated watchdog or somehow it is not enabled (supported but + * not enabled is though some bug and requires debugging :)). + */ + } + + qemu_add_vm_change_state_handler(cpu_state_change_handler, cpu); + qemu_register_reset(ppc_booke_timer_reset_handle, cpu); } -- cgit v1.2.1 From 20f649dd22dae13301c906c27a8768a318591ae8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 4 Apr 2013 18:45:07 +0200 Subject: PPC: mac newworld: fix cpu NIP reset value On -M mac99, we can run 970 CPUs. However, these CPUs define the initial instruction pointer they start execution at as part of their bootup protocol, so effectively it's up to the board to decide where they start. This went unnoticed, because they used to boot at the same location our flash was mapped to, but due to the recent reset changes our 970 CPUs want to reset to 0x100 now, which is always a 0 instruction. Set the initial IP to something reasonable for -M mac99. Signed-off-by: Alexander Graf Reviewed-by: Fabien Chouteau --- hw/ppc/mac_newworld.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 4a9b8837e3..ce44e95d53 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -126,6 +126,8 @@ static void ppc_core99_reset(void *opaque) PowerPCCPU *cpu = opaque; cpu_reset(CPU(cpu)); + /* 970 CPUs want to get their initial IP as part of their boot protocol */ + cpu->env.nip = PROM_ADDR + 0x100; } /* PowerPC Mac99 hardware initialisation */ -- cgit v1.2.1 From 0cbad81f70546b58f08de3225f1eca7a8b869b09 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 7 Apr 2013 19:08:19 +0000 Subject: pseries: Fixes and enhancements to L1 cache properties PAPR requires that the device tree's CPU nodes have several properties with information about the L1 cache. We already create two of these properties, but with incorrect names - "[id]cache-block-size" instead of "[id]-cache-block-size" (note the extra hyphen). We were also missing some of the required cache properties. This patch adds the [id]-cache-line-size properties (which have the same values as the block size properties in all current cases). We also add the [id]-cache-size properties. Adding the cache sizes requires some extra infrastructure in the general target-ppc code to (optionally) set the cache sizes for various CPUs. The CPU family descriptions in translate_init.c can set these sizes - this patch adds correct information for POWER7, I'm leaving other CPU types to people who have a physical example to verify against. In addition, for -cpu host we take the values advertised by the host (if available) and use those to override the information based on PVR. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e35c26f577..c96ac8131f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -308,6 +308,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, for (env = first_cpu; env != NULL; env = env->next_cpu) { CPUState *cpu = CPU(ppc_env_get_cpu(env)); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); int index = cpu->cpu_index; uint32_t servers_prop[smp_threads]; uint32_t gservers_prop[smp_threads * 2]; @@ -333,10 +334,26 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_string(fdt, "device_type", "cpu"))); _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); - _FDT((fdt_property_cell(fdt, "dcache-block-size", + _FDT((fdt_property_cell(fdt, "d-cache-block-size", env->dcache_line_size))); - _FDT((fdt_property_cell(fdt, "icache-block-size", + _FDT((fdt_property_cell(fdt, "d-cache-line-size", + env->dcache_line_size))); + _FDT((fdt_property_cell(fdt, "i-cache-block-size", + env->icache_line_size))); + _FDT((fdt_property_cell(fdt, "i-cache-line-size", env->icache_line_size))); + + if (pcc->l1_dcache_size) { + _FDT((fdt_property_cell(fdt, "d-cache-size", pcc->l1_dcache_size))); + } else { + fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n"); + } + if (pcc->l1_icache_size) { + _FDT((fdt_property_cell(fdt, "i-cache-size", pcc->l1_icache_size))); + } else { + fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n"); + } + _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); -- cgit v1.2.1 From e03c902cb617414dae49d77a810f6957ff7affac Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 7 Apr 2013 19:08:21 +0000 Subject: pseries: Fix some small errors in XICS logic Under certain circumstances the emulation for the pseries "XICS" interrupt controller was clearing a pending interrupt from the XISR register, without also clearing the corresponding priority variable. This will cause problems later when can trigger sanity checks in the under-development in-kernel XICS implementation. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/xics.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/ppc/xics.c b/hw/ppc/xics.c index 8e1e85edfd..1b25075d14 100644 --- a/hw/ppc/xics.c +++ b/hw/ppc/xics.c @@ -101,6 +101,7 @@ static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) if (XISR(ss) && (cppr <= ss->pending_priority)) { old_xisr = XISR(ss); ss->xirr &= ~XISR_MASK; /* Clear XISR */ + ss->pending_priority = 0xff; qemu_irq_lower(ss->output); ics_reject(icp->ics, old_xisr); } @@ -127,6 +128,7 @@ static uint32_t icp_accept(struct icp_server_state *ss) qemu_irq_lower(ss->output); ss->xirr = ss->pending_priority << 24; + ss->pending_priority = 0xff; trace_xics_icp_accept(xirr, ss->xirr); -- cgit v1.2.1 From fd506b4f61cd22793f8c54a9adf5c69345792501 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 7 Apr 2013 19:08:16 +0000 Subject: pseries: Convert VIO code to QOM style type safe(ish) casts Curerntly the pseries VIO device code contains quite a few explicit uses of DO_UPCAST and plain C casts. This is (obviously) type unsafe, and not the conventional way of doing things in the QOM model. This patch converts the code to use the QOM convention of per-type macros to do verified casts with OBJECT_CHECK(). Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/char/spapr_vty.c | 18 +++++++++++------- hw/net/spapr_llan.c | 24 ++++++++++++++---------- hw/nvram/spapr_nvram.c | 10 +++++++--- hw/ppc/spapr_vio.c | 4 ++-- hw/scsi/spapr_vscsi.c | 15 +++++++++------ 5 files changed, 43 insertions(+), 28 deletions(-) (limited to 'hw') diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index afcec1f182..2993848889 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -12,16 +12,20 @@ typedef struct VIOsPAPRVTYDevice { uint8_t buf[VTERM_BUFSIZE]; } VIOsPAPRVTYDevice; +#define TYPE_VIO_SPAPR_VTY_DEVICE "spapr-vty" +#define VIO_SPAPR_VTY_DEVICE(obj) \ + OBJECT_CHECK(VIOsPAPRVTYDevice, (obj), TYPE_VIO_SPAPR_VTY_DEVICE) + static int vty_can_receive(void *opaque) { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; + VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque); return (dev->in - dev->out) < VTERM_BUFSIZE; } static void vty_receive(void *opaque, const uint8_t *buf, int size) { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; + VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque); int i; if ((dev->in == dev->out) && size) { @@ -36,7 +40,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size) static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); int n = 0; while ((n < max) && (dev->out != dev->in)) { @@ -48,7 +52,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); /* FIXME: should check the qemu_chr_fe_write() return value */ qemu_chr_fe_write(dev->chardev, buf, len); @@ -56,7 +60,7 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) static int spapr_vty_init(VIOsPAPRDevice *sdev) { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); if (!dev->chardev) { fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n"); @@ -151,7 +155,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data) } static const TypeInfo spapr_vty_info = { - .name = "spapr-vty", + .name = TYPE_VIO_SPAPR_VTY_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VIOsPAPRVTYDevice), .class_init = spapr_vty_class_init, @@ -177,7 +181,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) continue; } - sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter); + sdev = VIO_SPAPR_DEVICE(iter); /* First VTY we've found, so it is selected for now */ if (!selected) { diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 34332f2452..3150add3c1 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -73,6 +73,10 @@ typedef uint64_t vlan_bd_t; #define VLAN_RX_BDS_OFF 16 #define VLAN_MAX_BUFS ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8) +#define TYPE_VIO_SPAPR_VLAN_DEVICE "spapr-vlan" +#define VIO_SPAPR_VLAN_DEVICE(obj) \ + OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE) + typedef struct VIOsPAPRVLANDevice { VIOsPAPRDevice sdev; NICConf nicconf; @@ -93,8 +97,8 @@ static int spapr_vlan_can_receive(NetClientState *nc) static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc); - VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc); + VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev); vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF); vlan_bd_t bd; int buf_ptr = dev->use_buf_ptr; @@ -192,7 +196,7 @@ static NetClientInfo net_spapr_vlan_info = { static void spapr_vlan_reset(VIOsPAPRDevice *sdev) { - VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev); + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); dev->buf_list = 0; dev->rx_bufs = 0; @@ -201,7 +205,7 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev) static int spapr_vlan_init(VIOsPAPRDevice *sdev) { - VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); qemu_macaddr_default_if_unset(&dev->nicconf.macaddr); @@ -225,7 +229,7 @@ void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd) static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) { - VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev; + VIOsPAPRVLANDevice *vdev = VIO_SPAPR_VLAN_DEVICE(dev); uint8_t padded_mac[8] = {0, 0}; int ret; @@ -282,7 +286,7 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu, target_ulong rec_queue = args[2]; target_ulong filter_list = args[3]; VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); vlan_bd_t filter_list_bd; if (!dev) { @@ -341,7 +345,7 @@ static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, { target_ulong reg = args[0]; VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); if (!dev) { return H_PARAMETER; @@ -365,7 +369,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, target_ulong reg = args[0]; target_ulong buf = args[1]; VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); vlan_bd_t bd; dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx @@ -413,7 +417,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong *bufs = args + 1; target_ulong continue_token = args[7]; VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); unsigned total_len; uint8_t *lbuf, *p; int i, nbufs; @@ -511,7 +515,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) } static const TypeInfo spapr_vlan_info = { - .name = "spapr-vlan", + .name = TYPE_VIO_SPAPR_VLAN_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VIOsPAPRVLANDevice), .class_init = spapr_vlan_class_init, diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 0cc6cba0e3..1eb05c9075 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -36,6 +36,10 @@ typedef struct sPAPRNVRAM { BlockDriverState *drive; } sPAPRNVRAM; +#define TYPE_VIO_SPAPR_NVRAM "spapr-nvram" +#define VIO_SPAPR_NVRAM(obj) \ + OBJECT_CHECK(sPAPRNVRAM, (obj), TYPE_VIO_SPAPR_NVRAM) + #define MIN_NVRAM_SIZE 8192 #define DEFAULT_NVRAM_SIZE 65536 #define MAX_NVRAM_SIZE (UINT16_MAX * 16) @@ -134,7 +138,7 @@ static void rtas_nvram_store(sPAPREnvironment *spapr, static int spapr_nvram_init(VIOsPAPRDevice *dev) { - sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev; + sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev); if (nvram->drive) { nvram->size = bdrv_getlength(nvram->drive); @@ -157,7 +161,7 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev) static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) { - sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev; + sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev); return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size); } @@ -182,7 +186,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data) } static const TypeInfo spapr_nvram_type_info = { - .name = "spapr-nvram", + .name = TYPE_VIO_SPAPR_NVRAM, .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(sPAPRNVRAM), .class_init = spapr_nvram_class_init, diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 4dbc31541b..ccc794da7f 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -379,7 +379,7 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) * the given dev might already be in the list. */ QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child); + other = VIO_SPAPR_DEVICE(kid->child); if (other != dev && other->reg == dev->reg) { return other; @@ -391,7 +391,7 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) static void spapr_vio_busdev_reset(DeviceState *qdev) { - VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev); VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); /* Shut down the request queue and TCEs if necessary */ diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 999a463a84..3d322d5d1e 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -91,6 +91,9 @@ typedef struct vscsi_req { int total_desc; } vscsi_req; +#define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi" +#define VIO_SPAPR_VSCSI_DEVICE(obj) \ + OBJECT_CHECK(VSCSIState, (obj), TYPE_VIO_SPAPR_VSCSI_DEVICE) typedef struct { VIOsPAPRDevice vdev; @@ -461,7 +464,7 @@ static int vscsi_preprocess_desc(vscsi_req *req) /* Callback to indicate that the SCSI layer has completed a transfer. */ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent); vscsi_req *req = sreq->hba_private; uint8_t *buf; int rc = 0; @@ -492,7 +495,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) /* Callback to indicate that the SCSI layer has completed a transfer. */ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent); vscsi_req *req = sreq->hba_private; int32_t res_in = 0, res_out = 0; @@ -827,7 +830,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev); vscsi_crq crq; memcpy(crq.raw, crq_data, 16); @@ -897,7 +900,7 @@ static const struct SCSIBusInfo vscsi_scsi_info = { static void spapr_vscsi_reset(VIOsPAPRDevice *dev) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev); int i; memset(s->reqs, 0, sizeof(s->reqs)); @@ -908,7 +911,7 @@ static void spapr_vscsi_reset(VIOsPAPRDevice *dev) static int spapr_vscsi_init(VIOsPAPRDevice *dev) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev); dev->crq.SendFunc = vscsi_do_crq; @@ -968,7 +971,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) } static const TypeInfo spapr_vscsi_info = { - .name = "spapr-vscsi", + .name = TYPE_VIO_SPAPR_VSCSI_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VSCSIState), .class_init = spapr_vscsi_class_init, -- cgit v1.2.1 From c4eda5b7234265313b09c2c9f9fdd3a960db97db Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 7 Apr 2013 19:08:17 +0000 Subject: pseries: Generate device paths for VIO devices This patch implements a get_dev_path qdev hook for the pseries paravirtual VIO bus. With upcoming savevm support, this will become very important for scsi disks hanging of VIO virtual SCSI adapters. scsibus_get_dev_path uses the get_dev_path of the parent adapter if available, but otherwise just uses a local channel/target/lun number to identify the device. So if two disks are present in the system having the same target and lun on seperate VIO scsi adapters, savevm cannot distinguish them. Since the conventional way of using VSCSI adapters is to have just one disk per adapter, such a conflict is very likely. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/ppc/spapr_vio.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index ccc794da7f..1405c3202c 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -53,9 +53,29 @@ static Property spapr_vio_props[] = { DEFINE_PROP_END_OF_LIST(), }; +static char *spapr_vio_get_dev_name(DeviceState *qdev) +{ + VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev); + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + char *name; + + /* Device tree style name device@reg */ + name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg); + + return name; +} + +static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->get_dev_path = spapr_vio_get_dev_name; +} + static const TypeInfo spapr_vio_bus_info = { .name = TYPE_SPAPR_VIO_BUS, .parent = TYPE_BUS, + .class_init = spapr_vio_bus_class_init, .instance_size = sizeof(VIOsPAPRBus), }; @@ -74,17 +94,6 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) return NULL; } -static char *vio_format_dev_name(VIOsPAPRDevice *dev) -{ - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - char *name; - - /* Device tree style name device@reg */ - name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg); - - return name; -} - #ifdef CONFIG_FDT static int vio_make_devnode(VIOsPAPRDevice *dev, void *fdt) @@ -98,7 +107,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, return vdevice_off; } - dt_name = vio_format_dev_name(dev); + dt_name = spapr_vio_get_dev_name(DEVICE(dev)); node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); g_free(dt_name); if (node_off < 0) { @@ -437,7 +446,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev) /* Don't overwrite ids assigned on the command line */ if (!dev->qdev.id) { - id = vio_format_dev_name(dev); + id = spapr_vio_get_dev_name(DEVICE(dev)); dev->qdev.id = id; } @@ -636,7 +645,7 @@ int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) return offset; } - name = vio_format_dev_name(dev); + name = spapr_vio_get_dev_name(DEVICE(dev)); path = g_strdup_printf("/vdevice/%s", name); ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); -- cgit v1.2.1