1c68c4a56SPaolo Bonzini /*
2c68c4a56SPaolo Bonzini * QEMU PowerPC e500v2 ePAPR spinning code
3c68c4a56SPaolo Bonzini *
4c68c4a56SPaolo Bonzini * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
5c68c4a56SPaolo Bonzini *
6c68c4a56SPaolo Bonzini * Author: Alexander Graf, <agraf@suse.de>
7c68c4a56SPaolo Bonzini *
8c68c4a56SPaolo Bonzini * This library is free software; you can redistribute it and/or
9c68c4a56SPaolo Bonzini * modify it under the terms of the GNU Lesser General Public
10c68c4a56SPaolo Bonzini * License as published by the Free Software Foundation; either
116bd039cdSChetan Pant * version 2.1 of the License, or (at your option) any later version.
12c68c4a56SPaolo Bonzini *
13c68c4a56SPaolo Bonzini * This library is distributed in the hope that it will be useful,
14c68c4a56SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c68c4a56SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16c68c4a56SPaolo Bonzini * Lesser General Public License for more details.
17c68c4a56SPaolo Bonzini *
18c68c4a56SPaolo Bonzini * You should have received a copy of the GNU Lesser General Public
19c68c4a56SPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20c68c4a56SPaolo Bonzini *
21c68c4a56SPaolo Bonzini * This code is not really a device, but models an interface that usually
22c68c4a56SPaolo Bonzini * firmware takes care of. It's used when QEMU plays the role of firmware.
23c68c4a56SPaolo Bonzini *
24c68c4a56SPaolo Bonzini * Specification:
25c68c4a56SPaolo Bonzini *
26c68c4a56SPaolo Bonzini * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
27c68c4a56SPaolo Bonzini *
28c68c4a56SPaolo Bonzini */
29c68c4a56SPaolo Bonzini
300d75590dSPeter Maydell #include "qemu/osdep.h"
310b8fa32fSMarkus Armbruster #include "qemu/module.h"
32ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h"
33c68c4a56SPaolo Bonzini #include "hw/hw.h"
34c68c4a56SPaolo Bonzini #include "hw/sysbus.h"
35b3946626SVincent Palatin #include "sysemu/hw_accel.h"
36*779a30dfSBALATON Zoltan #include "hw/ppc/ppc.h"
37a36848ffSAaron Larson #include "e500.h"
38db1015e9SEduardo Habkost #include "qom/object.h"
39c68c4a56SPaolo Bonzini
40c68c4a56SPaolo Bonzini #define MAX_CPUS 32
41c68c4a56SPaolo Bonzini
42c68c4a56SPaolo Bonzini typedef struct spin_info {
43c68c4a56SPaolo Bonzini uint64_t addr;
44c68c4a56SPaolo Bonzini uint64_t r3;
45c68c4a56SPaolo Bonzini uint32_t resv;
46c68c4a56SPaolo Bonzini uint32_t pir;
47c68c4a56SPaolo Bonzini uint64_t reserved;
48c68c4a56SPaolo Bonzini } QEMU_PACKED SpinInfo;
49c68c4a56SPaolo Bonzini
50880fc798SAndreas Färber #define TYPE_E500_SPIN "e500-spin"
518063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SpinState, E500_SPIN)
52880fc798SAndreas Färber
53db1015e9SEduardo Habkost struct SpinState {
54880fc798SAndreas Färber SysBusDevice parent_obj;
55880fc798SAndreas Färber
56c68c4a56SPaolo Bonzini MemoryRegion iomem;
57c68c4a56SPaolo Bonzini SpinInfo spin[MAX_CPUS];
58db1015e9SEduardo Habkost };
59c68c4a56SPaolo Bonzini
spin_reset(DeviceState * dev)6009a7eb97Sxiaoqiang zhao static void spin_reset(DeviceState *dev)
61c68c4a56SPaolo Bonzini {
6209a7eb97Sxiaoqiang zhao SpinState *s = E500_SPIN(dev);
63c68c4a56SPaolo Bonzini int i;
64c68c4a56SPaolo Bonzini
65c68c4a56SPaolo Bonzini for (i = 0; i < MAX_CPUS; i++) {
66c68c4a56SPaolo Bonzini SpinInfo *info = &s->spin[i];
67c68c4a56SPaolo Bonzini
686a2b3d89SAlexander Graf stl_p(&info->pir, i);
696a2b3d89SAlexander Graf stq_p(&info->r3, i);
706a2b3d89SAlexander Graf stq_p(&info->addr, 1);
71c68c4a56SPaolo Bonzini }
72c68c4a56SPaolo Bonzini }
73c68c4a56SPaolo Bonzini
spin_kick(CPUState * cs,run_on_cpu_data data)7414e6fe12SPaolo Bonzini static void spin_kick(CPUState *cs, run_on_cpu_data data)
75c68c4a56SPaolo Bonzini {
76794511bcSPhilippe Mathieu-Daudé CPUPPCState *env = cpu_env(cs);
7714e6fe12SPaolo Bonzini SpinInfo *curspin = data.host_ptr;
78*779a30dfSBALATON Zoltan hwaddr map_start, map_size = 64 * MiB;
79*779a30dfSBALATON Zoltan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
80c68c4a56SPaolo Bonzini
81e0eeb4a2SAlex Bennée cpu_synchronize_state(cs);
826d18a7a1SAaron Larson stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]);
83c68c4a56SPaolo Bonzini env->nip = ldq_p(&curspin->addr) & (map_size - 1);
84c68c4a56SPaolo Bonzini env->gpr[3] = ldq_p(&curspin->r3);
85c68c4a56SPaolo Bonzini env->gpr[4] = 0;
86c68c4a56SPaolo Bonzini env->gpr[5] = 0;
87c68c4a56SPaolo Bonzini env->gpr[6] = 0;
88c68c4a56SPaolo Bonzini env->gpr[7] = map_size;
89c68c4a56SPaolo Bonzini env->gpr[8] = 0;
90c68c4a56SPaolo Bonzini env->gpr[9] = 0;
91c68c4a56SPaolo Bonzini
92c68c4a56SPaolo Bonzini map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
93*779a30dfSBALATON Zoltan /* create initial mapping */
94*779a30dfSBALATON Zoltan booke206_set_tlb(tlb, 0, map_start, map_size);
95*779a30dfSBALATON Zoltan tlb->mas2 |= MAS2_M;
96*779a30dfSBALATON Zoltan #ifdef CONFIG_KVM
97*779a30dfSBALATON Zoltan env->tlb_dirty = true;
98*779a30dfSBALATON Zoltan #endif
99c68c4a56SPaolo Bonzini
100e0eeb4a2SAlex Bennée cs->halted = 0;
101e0eeb4a2SAlex Bennée cs->exception_index = -1;
102e0eeb4a2SAlex Bennée cs->stopped = false;
103e0eeb4a2SAlex Bennée qemu_cpu_kick(cs);
104c68c4a56SPaolo Bonzini }
105c68c4a56SPaolo Bonzini
spin_write(void * opaque,hwaddr addr,uint64_t value,unsigned len)106c68c4a56SPaolo Bonzini static void spin_write(void *opaque, hwaddr addr, uint64_t value,
107c68c4a56SPaolo Bonzini unsigned len)
108c68c4a56SPaolo Bonzini {
109c68c4a56SPaolo Bonzini SpinState *s = opaque;
110c68c4a56SPaolo Bonzini int env_idx = addr / sizeof(SpinInfo);
111c68c4a56SPaolo Bonzini CPUState *cpu;
112c68c4a56SPaolo Bonzini SpinInfo *curspin = &s->spin[env_idx];
113c68c4a56SPaolo Bonzini uint8_t *curspin_p = (uint8_t*)curspin;
114c68c4a56SPaolo Bonzini
115c68c4a56SPaolo Bonzini cpu = qemu_get_cpu(env_idx);
116c68c4a56SPaolo Bonzini if (cpu == NULL) {
117c68c4a56SPaolo Bonzini /* Unknown CPU */
118c68c4a56SPaolo Bonzini return;
119c68c4a56SPaolo Bonzini }
120c68c4a56SPaolo Bonzini
121c68c4a56SPaolo Bonzini if (cpu->cpu_index == 0) {
122c68c4a56SPaolo Bonzini /* primary CPU doesn't spin */
123c68c4a56SPaolo Bonzini return;
124c68c4a56SPaolo Bonzini }
125c68c4a56SPaolo Bonzini
126c68c4a56SPaolo Bonzini curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
127c68c4a56SPaolo Bonzini switch (len) {
128c68c4a56SPaolo Bonzini case 1:
129c68c4a56SPaolo Bonzini stb_p(curspin_p, value);
130c68c4a56SPaolo Bonzini break;
131c68c4a56SPaolo Bonzini case 2:
132c68c4a56SPaolo Bonzini stw_p(curspin_p, value);
133c68c4a56SPaolo Bonzini break;
134c68c4a56SPaolo Bonzini case 4:
135c68c4a56SPaolo Bonzini stl_p(curspin_p, value);
136c68c4a56SPaolo Bonzini break;
137c68c4a56SPaolo Bonzini }
138c68c4a56SPaolo Bonzini
139c68c4a56SPaolo Bonzini if (!(ldq_p(&curspin->addr) & 1)) {
140c68c4a56SPaolo Bonzini /* run CPU */
14114e6fe12SPaolo Bonzini run_on_cpu(cpu, spin_kick, RUN_ON_CPU_HOST_PTR(curspin));
142c68c4a56SPaolo Bonzini }
143c68c4a56SPaolo Bonzini }
144c68c4a56SPaolo Bonzini
spin_read(void * opaque,hwaddr addr,unsigned len)145c68c4a56SPaolo Bonzini static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len)
146c68c4a56SPaolo Bonzini {
147c68c4a56SPaolo Bonzini SpinState *s = opaque;
148c68c4a56SPaolo Bonzini uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
149c68c4a56SPaolo Bonzini
150c68c4a56SPaolo Bonzini switch (len) {
151c68c4a56SPaolo Bonzini case 1:
152c68c4a56SPaolo Bonzini return ldub_p(spin_p);
153c68c4a56SPaolo Bonzini case 2:
154c68c4a56SPaolo Bonzini return lduw_p(spin_p);
155c68c4a56SPaolo Bonzini case 4:
156c68c4a56SPaolo Bonzini return ldl_p(spin_p);
157c68c4a56SPaolo Bonzini default:
158c68c4a56SPaolo Bonzini hw_error("ppce500: unexpected %s with len = %u", __func__, len);
159c68c4a56SPaolo Bonzini }
160c68c4a56SPaolo Bonzini }
161c68c4a56SPaolo Bonzini
162c68c4a56SPaolo Bonzini static const MemoryRegionOps spin_rw_ops = {
163c68c4a56SPaolo Bonzini .read = spin_read,
164c68c4a56SPaolo Bonzini .write = spin_write,
165c68c4a56SPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN,
166c68c4a56SPaolo Bonzini };
167c68c4a56SPaolo Bonzini
ppce500_spin_initfn(Object * obj)16809a7eb97Sxiaoqiang zhao static void ppce500_spin_initfn(Object *obj)
169c68c4a56SPaolo Bonzini {
17009a7eb97Sxiaoqiang zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj);
171880fc798SAndreas Färber SpinState *s = E500_SPIN(dev);
172c68c4a56SPaolo Bonzini
17309a7eb97Sxiaoqiang zhao memory_region_init_io(&s->iomem, obj, &spin_rw_ops, s,
17440c5dce9SPaolo Bonzini "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS);
175c68c4a56SPaolo Bonzini sysbus_init_mmio(dev, &s->iomem);
176c68c4a56SPaolo Bonzini }
177c68c4a56SPaolo Bonzini
ppce500_spin_class_init(ObjectClass * klass,void * data)178c68c4a56SPaolo Bonzini static void ppce500_spin_class_init(ObjectClass *klass, void *data)
179c68c4a56SPaolo Bonzini {
18009a7eb97Sxiaoqiang zhao DeviceClass *dc = DEVICE_CLASS(klass);
181c68c4a56SPaolo Bonzini
182e3d08143SPeter Maydell device_class_set_legacy_reset(dc, spin_reset);
183c68c4a56SPaolo Bonzini }
184c68c4a56SPaolo Bonzini
185c68c4a56SPaolo Bonzini static const TypeInfo ppce500_spin_info = {
186880fc798SAndreas Färber .name = TYPE_E500_SPIN,
187c68c4a56SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
188c68c4a56SPaolo Bonzini .instance_size = sizeof(SpinState),
18909a7eb97Sxiaoqiang zhao .instance_init = ppce500_spin_initfn,
190c68c4a56SPaolo Bonzini .class_init = ppce500_spin_class_init,
191c68c4a56SPaolo Bonzini };
192c68c4a56SPaolo Bonzini
ppce500_spin_register_types(void)193c68c4a56SPaolo Bonzini static void ppce500_spin_register_types(void)
194c68c4a56SPaolo Bonzini {
195c68c4a56SPaolo Bonzini type_register_static(&ppce500_spin_info);
196c68c4a56SPaolo Bonzini }
197c68c4a56SPaolo Bonzini
198c68c4a56SPaolo Bonzini type_init(ppce500_spin_register_types)
199