From: Alexander Graf <agraf@suse.de>
To: qemu-devel@nongnu.org
Cc: Blue Swirl <blauwirbel@gmail.com>, qemu-ppc@nongnu.org
Subject: [Qemu-devel] [PATCH 24/64] PPC: E500: Add PV spinning code
Date: Thu, 6 Oct 2011 10:05:26 +0200 [thread overview]
Message-ID: <1317888366-10509-25-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1317888366-10509-1-git-send-email-agraf@suse.de>
CPUs that are not the boot CPU need to run in spinning code to check if they
should run off to execute and if so where to jump to. This usually happens
by leaving secondary CPUs looping and checking if some variable in memory
changed.
In an environment like Qemu however we can be more clever. We can just export
the spin table the primary CPU modifies as MMIO region that would event based
wake up the respective secondary CPUs. That saves us quite some cycles while
the secondary CPUs are not up yet.
So this patch adds a PV device that simply exports the spinning table into the
guest and thus allows the primary CPU to wake up secondary ones.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
v1 -> v2:
- change into MMIO scheme
- map the secondary NIP instead of 0 1:1
- only map 64MB for TLB, same as u-boot
- prepare code for 64-bit spinnings
v2 -> v3:
- remove r6
- set MAS2_M
- map EA 0
- use second TLB1 entry
v3 -> v4:
- change to memoryops
v4 -> v5:
- fix endianness bugs
v5 -> v6:
- add header
---
Makefile.target | 2 +-
hw/ppce500_mpc8544ds.c | 33 +++++++-
hw/ppce500_spin.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 245 insertions(+), 5 deletions(-)
create mode 100644 hw/ppce500_spin.c
diff --git a/Makefile.target b/Makefile.target
index 8db9f37..ff3efa4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -247,7 +247,7 @@ endif
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-ppc-y += ppc440.o ppc440_bamboo.o
# PowerPC E500 boards
-obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o
+obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
# PowerPC 440 Xilinx ML507 reference board.
obj-ppc-y += virtex_ml507.o
obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 9379624..3b8b449 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -49,6 +49,7 @@
#define MPC8544_PCI_IO 0xE1000000
#define MPC8544_PCI_IOLEN 0x10000
#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
+#define MPC8544_SPIN_BASE 0xEF000000
struct boot_info
{
@@ -164,6 +165,18 @@ static void mmubooke_create_initial_mapping(CPUState *env,
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
}
+static void mpc8544ds_cpu_reset_sec(void *opaque)
+{
+ CPUState *env = opaque;
+
+ cpu_reset(env);
+
+ /* Secondary CPU starts in halted state for now. Needs to change when
+ implementing non-kernel boot. */
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+}
+
static void mpc8544ds_cpu_reset(void *opaque)
{
CPUState *env = opaque;
@@ -172,6 +185,7 @@ static void mpc8544ds_cpu_reset(void *opaque)
cpu_reset(env);
/* Set initial guest state. */
+ env->halted = 0;
env->gpr[1] = (16<<20) - 8;
env->gpr[3] = bi->dt_base;
env->nip = bi->entry;
@@ -199,7 +213,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
qemu_irq **irqs, *mpic;
DeviceState *dev;
- struct boot_info *boot_info;
CPUState *firstenv = NULL;
/* Setup CPUs */
@@ -234,9 +247,16 @@ static void mpc8544ds_init(ram_addr_t ram_size,
env->spr[SPR_40x_TCR] = 1 << 26;
/* Register reset handler */
- boot_info = g_malloc0(sizeof(struct boot_info));
- qemu_register_reset(mpc8544ds_cpu_reset, env);
- env->load_info = boot_info;
+ if (!i) {
+ /* Primary CPU */
+ struct boot_info *boot_info;
+ boot_info = g_malloc0(sizeof(struct boot_info));
+ qemu_register_reset(mpc8544ds_cpu_reset, env);
+ env->load_info = boot_info;
+ } else {
+ /* Secondary CPUs */
+ qemu_register_reset(mpc8544ds_cpu_reset_sec, env);
+ }
}
env = firstenv;
@@ -289,6 +309,9 @@ static void mpc8544ds_init(ram_addr_t ram_size,
}
}
+ /* Register spinning region */
+ sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
+
/* Load kernel. */
if (kernel_filename) {
kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
@@ -321,6 +344,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
/* If we're loading a kernel directly, we must load the device tree too. */
if (kernel_filename) {
+ struct boot_info *boot_info;
+
#ifndef CONFIG_FDT
cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
#endif
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
new file mode 100644
index 0000000..cccd940
--- /dev/null
+++ b/hw/ppce500_spin.c
@@ -0,0 +1,215 @@
+/*
+ * QEMU PowerPC e500v2 ePAPR spinning code
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This code is not really a device, but models an interface that usually
+ * firmware takes care of. It's used when QEMU plays the role of firmware.
+ *
+ * Specification:
+ *
+ * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "kvm.h"
+
+#define MAX_CPUS 32
+
+typedef struct spin_info {
+ uint64_t addr;
+ uint64_t r3;
+ uint32_t resv;
+ uint32_t pir;
+ uint64_t reserved;
+} __attribute__ ((packed)) SpinInfo;
+
+typedef struct spin_state {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ SpinInfo spin[MAX_CPUS];
+} SpinState;
+
+typedef struct spin_kick {
+ CPUState *env;
+ SpinInfo *spin;
+} SpinKick;
+
+static void spin_reset(void *opaque)
+{
+ SpinState *s = opaque;
+ int i;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ SpinInfo *info = &s->spin[i];
+
+ info->pir = i;
+ info->r3 = i;
+ info->addr = 1;
+ }
+}
+
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+ return (ffs(size >> 10) - 1) >> 1;
+}
+
+static void mmubooke_create_initial_mapping(CPUState *env,
+ target_ulong va,
+ target_phys_addr_t pa,
+ target_phys_addr_t len)
+{
+ ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
+ target_phys_addr_t size;
+
+ size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
+ tlb->mas1 = MAS1_VALID | size;
+ tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
+ tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+ tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
+static void spin_kick(void *data)
+{
+ SpinKick *kick = data;
+ CPUState *env = kick->env;
+ SpinInfo *curspin = kick->spin;
+ target_phys_addr_t map_size = 64 * 1024 * 1024;
+ target_phys_addr_t map_start;
+
+ cpu_synchronize_state(env);
+ stl_p(&curspin->pir, env->spr[SPR_PIR]);
+ env->nip = ldq_p(&curspin->addr) & (map_size - 1);
+ env->gpr[3] = ldq_p(&curspin->r3);
+ env->gpr[4] = 0;
+ env->gpr[5] = 0;
+ env->gpr[6] = 0;
+ env->gpr[7] = map_size;
+ env->gpr[8] = 0;
+ env->gpr[9] = 0;
+
+ map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
+ mmubooke_create_initial_mapping(env, 0, map_start, map_size);
+
+ env->halted = 0;
+ env->exception_index = -1;
+ qemu_cpu_kick(env);
+}
+
+static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+ unsigned len)
+{
+ SpinState *s = opaque;
+ int env_idx = addr / sizeof(SpinInfo);
+ CPUState *env;
+ SpinInfo *curspin = &s->spin[env_idx];
+ uint8_t *curspin_p = (uint8_t*)curspin;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ if (env->cpu_index == env_idx) {
+ break;
+ }
+ }
+
+ if (!env) {
+ /* Unknown CPU */
+ return;
+ }
+
+ if (!env->cpu_index) {
+ /* primary CPU doesn't spin */
+ return;
+ }
+
+ curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
+ switch (len) {
+ case 1:
+ stb_p(curspin_p, value);
+ break;
+ case 2:
+ stw_p(curspin_p, value);
+ break;
+ case 4:
+ stl_p(curspin_p, value);
+ break;
+ }
+
+ if (!(ldq_p(&curspin->addr) & 1)) {
+ /* run CPU */
+ SpinKick kick = {
+ .env = env,
+ .spin = curspin,
+ };
+
+ run_on_cpu(env, spin_kick, &kick);
+ }
+}
+
+static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len)
+{
+ SpinState *s = opaque;
+ uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
+
+ switch (len) {
+ case 1:
+ return ldub_p(spin_p);
+ case 2:
+ return lduw_p(spin_p);
+ case 4:
+ return ldl_p(spin_p);
+ default:
+ assert(0);
+ }
+}
+
+const MemoryRegionOps spin_rw_ops = {
+ .read = spin_read,
+ .write = spin_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int ppce500_spin_initfn(SysBusDevice *dev)
+{
+ SpinState *s;
+
+ s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev));
+
+ memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
+ sizeof(SpinInfo) * MAX_CPUS);
+ sysbus_init_mmio_region(dev, &s->iomem);
+
+ qemu_register_reset(spin_reset, s);
+
+ return 0;
+}
+
+static SysBusDeviceInfo ppce500_spin_info = {
+ .init = ppce500_spin_initfn,
+ .qdev.name = "e500-spin",
+ .qdev.size = sizeof(SpinState),
+};
+
+static void ppce500_spin_register(void)
+{
+ sysbus_register_withprop(&ppce500_spin_info);
+}
+device_init(ppce500_spin_register);
--
1.6.0.2
next prev parent reply other threads:[~2011-10-06 8:06 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-06 8:05 [Qemu-devel] [PULL 00/64] ppc patch queue 2011-10-06 Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 01/64] spapr: proper qdevification Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 02/64] spapr: prepare for qdevification of irq Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 03/64] spapr: make irq customizable via qdev Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 04/64] PPC: Move openpic to target specific code compilation Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 05/64] PPC: Add CPU local MMIO regions to MPIC Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 06/64] PPC: Extend MPIC MMIO range Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 07/64] PPC: Fix IPI support in MPIC Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 08/64] PPC: Set MPIC IDE for IPI to 0 Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 09/64] PPC: MPIC: Remove read functionality for WO registers Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 10/64] PPC: MPIC: Fix CI bit definitions Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 11/64] PPC: Bump MPIC up to 32 supported CPUs Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 12/64] PPC: E500: create multiple envs Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 13/64] PPC: E500: Generate IRQ lines for many CPUs Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 14/64] device tree: add nop_node Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 15/64] PPC: bamboo: Move host fdt copy to target Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 16/64] PPC: KVM: Add generic function to read host clockfreq Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 17/64] PPC: E500: Use generic kvm function for freq Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 18/64] PPC: E500: Remove mpc8544_copy_soc_cell Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 19/64] PPC: bamboo: Use kvm api for freq and clock frequencies Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 20/64] PPC: KVM: Remove kvmppc_read_host_property Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 21/64] PPC: KVM: Add stubs for kvm helper functions Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 22/64] PPC: E500: Update freqs for all CPUs Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 23/64] PPC: E500: Remove unneeded CPU nodes Alexander Graf
2011-10-06 8:05 ` Alexander Graf [this message]
2011-10-06 8:05 ` [Qemu-devel] [PATCH 25/64] PPC: E500: Update cpu-release-addr property in cpu nodes Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 26/64] device tree: add add_subnode command Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 27/64] device tree: dont fail operations Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 28/64] device tree: give dt more size Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 29/64] MPC8544DS: Remove CPU nodes Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 30/64] MPC8544DS: Generate CPU nodes on init Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 31/64] PPC: E500: Bump CPU count to 15 Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 32/64] PPC: Add new target config for pseries Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 33/64] KVM: update kernel headers Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 34/64] PPC: Enable to use PAPR with PR style KVM Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 35/64] PPC: SPAPR: Use KVM function for time info Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 36/64] pseries: Bugfixes for interrupt numbering in XICS code Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 37/64] pseries: Add a phandle to the xicp interrupt controller device tree node Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 38/64] pseries: interrupt controller should not have a 'reg' property Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 39/64] pseries: More complete WIMG validation in H_ENTER code Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 40/64] PPC: Fix sync instructions problem in SMP Alexander Graf
2011-10-06 8:24 ` Elie Richa
2011-10-06 8:05 ` [Qemu-devel] [PATCH 41/64] pseries: Add real mode debugging hcalls Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 42/64] pseries: use macro for firmware filename Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 43/64] KVM: Update kernel headers Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 44/64] kvm: ppc: booke206: use MMU API Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 45/64] ppc: booke206: add "info tlb" support Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 46/64] ppc: booke206: use MAV=2.0 TSIZE definition, fix 4G pages Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 47/64] Implement POWER7's CFAR in TCG Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 48/64] pseries: Implement hcall-bulk hypervisor interface Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 49/64] vscsi: send the CHECK_CONDITION status down together with autosense data Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 50/64] Gdbstub: handle read of fpscr Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 51/64] ppc405: use RAM_ADDR_FMT instead of %08lx Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 52/64] openpic: Unfold read_IRQreg Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 53/64] openpic: Unfold write_IRQreg Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 54/64] ppc: move ADB stuff from ppc_mac.h to adb.h Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 55/64] PPC: Fix via-cuda memory registration Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 56/64] PPC: Fix heathrow PIC to use little endian MMIO Alexander Graf
2011-10-06 8:05 ` [Qemu-devel] [PATCH 57/64] KVM: Update kernel headers Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 58/64] " Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 59/64] KVM: PPC: Use HIOR setting for -M pseries with PR KVM Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 60/64] PPC: booke timers Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 61/64] PPC: Clean up BookE timer code Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 62/64] pseries: Refactor spapr irq allocation Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 63/64] pseries: Implement set-time-of-day RTAS function Alexander Graf
2011-10-06 8:06 ` [Qemu-devel] [PATCH 64/64] ppc64: Fix linker script Alexander Graf
2011-10-08 10:17 ` [Qemu-devel] [PULL 00/64] ppc patch queue 2011-10-06 Blue Swirl
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1317888366-10509-25-git-send-email-agraf@suse.de \
--to=agraf@suse.de \
--cc=blauwirbel@gmail.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).