Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 1 | /* |
| 2 | * QEMU PowerPC e500v2 ePAPR spinning code |
| 3 | * |
| 4 | * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. |
| 5 | * |
| 6 | * Author: Alexander Graf, <agraf@suse.de> |
| 7 | * |
| 8 | * This library is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU Lesser General Public |
| 10 | * License as published by the Free Software Foundation; either |
Chetan Pant | 6bd039c | 2020-10-19 06:11:26 +0000 | [diff] [blame] | 11 | * version 2.1 of the License, or (at your option) any later version. |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 12 | * |
| 13 | * This library is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | * Lesser General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU Lesser General Public |
| 19 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 20 | * |
| 21 | * This code is not really a device, but models an interface that usually |
| 22 | * firmware takes care of. It's used when QEMU plays the role of firmware. |
| 23 | * |
| 24 | * Specification: |
| 25 | * |
| 26 | * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf |
| 27 | * |
| 28 | */ |
| 29 | |
Peter Maydell | 0d75590 | 2016-01-26 18:16:58 +0000 | [diff] [blame] | 30 | #include "qemu/osdep.h" |
Markus Armbruster | 0b8fa32 | 2019-05-23 16:35:07 +0200 | [diff] [blame] | 31 | #include "qemu/module.h" |
Philippe Mathieu-Daudé | ab3dd74 | 2018-06-25 09:42:24 -0300 | [diff] [blame] | 32 | #include "qemu/units.h" |
Paolo Bonzini | 83c9f4c | 2013-02-04 15:40:22 +0100 | [diff] [blame] | 33 | #include "hw/hw.h" |
Paolo Bonzini | 83c9f4c | 2013-02-04 15:40:22 +0100 | [diff] [blame] | 34 | #include "hw/sysbus.h" |
Vincent Palatin | b394662 | 2017-01-10 11:59:55 +0100 | [diff] [blame] | 35 | #include "sysemu/hw_accel.h" |
Aaron Larson | a36848f | 2016-06-28 06:50:05 -0700 | [diff] [blame] | 36 | #include "e500.h" |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 37 | #include "qom/object.h" |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 38 | |
| 39 | #define MAX_CPUS 32 |
| 40 | |
| 41 | typedef struct spin_info { |
| 42 | uint64_t addr; |
| 43 | uint64_t r3; |
| 44 | uint32_t resv; |
| 45 | uint32_t pir; |
| 46 | uint64_t reserved; |
Stefan Weil | 7c7bb02 | 2012-07-18 18:12:37 +0200 | [diff] [blame] | 47 | } QEMU_PACKED SpinInfo; |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 48 | |
Andreas Färber | 880fc79 | 2013-07-27 13:03:07 +0200 | [diff] [blame] | 49 | #define TYPE_E500_SPIN "e500-spin" |
Eduardo Habkost | 8063396 | 2020-09-16 14:25:19 -0400 | [diff] [blame] | 50 | OBJECT_DECLARE_SIMPLE_TYPE(SpinState, E500_SPIN) |
Andreas Färber | 880fc79 | 2013-07-27 13:03:07 +0200 | [diff] [blame] | 51 | |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 52 | struct SpinState { |
Andreas Färber | 880fc79 | 2013-07-27 13:03:07 +0200 | [diff] [blame] | 53 | SysBusDevice parent_obj; |
| 54 | |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 55 | MemoryRegion iomem; |
| 56 | SpinInfo spin[MAX_CPUS]; |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 57 | }; |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 58 | |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 59 | static void spin_reset(DeviceState *dev) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 60 | { |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 61 | SpinState *s = E500_SPIN(dev); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 62 | int i; |
| 63 | |
| 64 | for (i = 0; i < MAX_CPUS; i++) { |
| 65 | SpinInfo *info = &s->spin[i]; |
| 66 | |
Alexander Graf | 6a2b3d8 | 2014-04-07 16:48:42 +0200 | [diff] [blame] | 67 | stl_p(&info->pir, i); |
| 68 | stq_p(&info->r3, i); |
| 69 | stq_p(&info->addr, 1); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 70 | } |
| 71 | } |
| 72 | |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 73 | static void mmubooke_create_initial_mapping(CPUPPCState *env, |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 74 | target_ulong va, |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 75 | hwaddr pa, |
| 76 | hwaddr len) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 77 | { |
| 78 | ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1); |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 79 | hwaddr size; |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 80 | |
| 81 | size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT); |
| 82 | tlb->mas1 = MAS1_VALID | size; |
| 83 | tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M; |
| 84 | tlb->mas7_3 = pa & TARGET_PAGE_MASK; |
| 85 | tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; |
Philippe Mathieu-Daudé | 0573997 | 2023-04-04 11:14:58 +0200 | [diff] [blame] | 86 | #ifdef CONFIG_KVM |
Bharat Bhushan | 58f90f2 | 2012-03-26 17:56:46 +0000 | [diff] [blame] | 87 | env->tlb_dirty = true; |
Philippe Mathieu-Daudé | 0573997 | 2023-04-04 11:14:58 +0200 | [diff] [blame] | 88 | #endif |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 89 | } |
| 90 | |
Paolo Bonzini | 14e6fe1 | 2016-10-31 10:36:08 +0100 | [diff] [blame] | 91 | static void spin_kick(CPUState *cs, run_on_cpu_data data) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 92 | { |
Alex Bennée | e0eeb4a | 2016-08-02 18:27:33 +0100 | [diff] [blame] | 93 | PowerPCCPU *cpu = POWERPC_CPU(cs); |
| 94 | CPUPPCState *env = &cpu->env; |
Paolo Bonzini | 14e6fe1 | 2016-10-31 10:36:08 +0100 | [diff] [blame] | 95 | SpinInfo *curspin = data.host_ptr; |
Philippe Mathieu-Daudé | ab3dd74 | 2018-06-25 09:42:24 -0300 | [diff] [blame] | 96 | hwaddr map_size = 64 * MiB; |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 97 | hwaddr map_start; |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 98 | |
Alex Bennée | e0eeb4a | 2016-08-02 18:27:33 +0100 | [diff] [blame] | 99 | cpu_synchronize_state(cs); |
Aaron Larson | 6d18a7a | 2016-06-23 15:35:17 -0700 | [diff] [blame] | 100 | stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 101 | env->nip = ldq_p(&curspin->addr) & (map_size - 1); |
| 102 | env->gpr[3] = ldq_p(&curspin->r3); |
| 103 | env->gpr[4] = 0; |
| 104 | env->gpr[5] = 0; |
| 105 | env->gpr[6] = 0; |
| 106 | env->gpr[7] = map_size; |
| 107 | env->gpr[8] = 0; |
| 108 | env->gpr[9] = 0; |
| 109 | |
| 110 | map_start = ldq_p(&curspin->addr) & ~(map_size - 1); |
| 111 | mmubooke_create_initial_mapping(env, 0, map_start, map_size); |
| 112 | |
Alex Bennée | e0eeb4a | 2016-08-02 18:27:33 +0100 | [diff] [blame] | 113 | cs->halted = 0; |
| 114 | cs->exception_index = -1; |
| 115 | cs->stopped = false; |
| 116 | qemu_cpu_kick(cs); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 117 | } |
| 118 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 119 | static void spin_write(void *opaque, hwaddr addr, uint64_t value, |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 120 | unsigned len) |
| 121 | { |
| 122 | SpinState *s = opaque; |
| 123 | int env_idx = addr / sizeof(SpinInfo); |
Andreas Färber | 912ebe1 | 2013-02-15 15:56:27 +0100 | [diff] [blame] | 124 | CPUState *cpu; |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 125 | SpinInfo *curspin = &s->spin[env_idx]; |
| 126 | uint8_t *curspin_p = (uint8_t*)curspin; |
| 127 | |
Andreas Färber | 912ebe1 | 2013-02-15 15:56:27 +0100 | [diff] [blame] | 128 | cpu = qemu_get_cpu(env_idx); |
Andreas Färber | 55e5c28 | 2012-12-17 06:18:02 +0100 | [diff] [blame] | 129 | if (cpu == NULL) { |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 130 | /* Unknown CPU */ |
| 131 | return; |
| 132 | } |
| 133 | |
Andreas Färber | 55e5c28 | 2012-12-17 06:18:02 +0100 | [diff] [blame] | 134 | if (cpu->cpu_index == 0) { |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 135 | /* primary CPU doesn't spin */ |
| 136 | return; |
| 137 | } |
| 138 | |
| 139 | curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; |
| 140 | switch (len) { |
| 141 | case 1: |
| 142 | stb_p(curspin_p, value); |
| 143 | break; |
| 144 | case 2: |
| 145 | stw_p(curspin_p, value); |
| 146 | break; |
| 147 | case 4: |
| 148 | stl_p(curspin_p, value); |
| 149 | break; |
| 150 | } |
| 151 | |
| 152 | if (!(ldq_p(&curspin->addr) & 1)) { |
| 153 | /* run CPU */ |
Paolo Bonzini | 14e6fe1 | 2016-10-31 10:36:08 +0100 | [diff] [blame] | 154 | run_on_cpu(cpu, spin_kick, RUN_ON_CPU_HOST_PTR(curspin)); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 155 | } |
| 156 | } |
| 157 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 158 | static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 159 | { |
| 160 | SpinState *s = opaque; |
| 161 | uint8_t *spin_p = &((uint8_t*)s->spin)[addr]; |
| 162 | |
| 163 | switch (len) { |
| 164 | case 1: |
| 165 | return ldub_p(spin_p); |
| 166 | case 2: |
| 167 | return lduw_p(spin_p); |
| 168 | case 4: |
| 169 | return ldl_p(spin_p); |
| 170 | default: |
Stefan Weil | 5f2c23e | 2012-04-28 17:52:31 +0200 | [diff] [blame] | 171 | hw_error("ppce500: unexpected %s with len = %u", __func__, len); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 172 | } |
| 173 | } |
| 174 | |
Stefan Weil | b7c28f0 | 2012-02-25 02:37:12 +0000 | [diff] [blame] | 175 | static const MemoryRegionOps spin_rw_ops = { |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 176 | .read = spin_read, |
| 177 | .write = spin_write, |
| 178 | .endianness = DEVICE_BIG_ENDIAN, |
| 179 | }; |
| 180 | |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 181 | static void ppce500_spin_initfn(Object *obj) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 182 | { |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 183 | SysBusDevice *dev = SYS_BUS_DEVICE(obj); |
Andreas Färber | 880fc79 | 2013-07-27 13:03:07 +0200 | [diff] [blame] | 184 | SpinState *s = E500_SPIN(dev); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 185 | |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 186 | memory_region_init_io(&s->iomem, obj, &spin_rw_ops, s, |
Paolo Bonzini | 40c5dce | 2013-06-06 21:25:08 -0400 | [diff] [blame] | 187 | "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS); |
Avi Kivity | 750ecd4 | 2011-11-27 11:38:10 +0200 | [diff] [blame] | 188 | sysbus_init_mmio(dev, &s->iomem); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 189 | } |
| 190 | |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 191 | static void ppce500_spin_class_init(ObjectClass *klass, void *data) |
| 192 | { |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 193 | DeviceClass *dc = DEVICE_CLASS(klass); |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 194 | |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 195 | dc->reset = spin_reset; |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 196 | } |
| 197 | |
Andreas Färber | 8c43a6f | 2013-01-10 16:19:07 +0100 | [diff] [blame] | 198 | static const TypeInfo ppce500_spin_info = { |
Andreas Färber | 880fc79 | 2013-07-27 13:03:07 +0200 | [diff] [blame] | 199 | .name = TYPE_E500_SPIN, |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 200 | .parent = TYPE_SYS_BUS_DEVICE, |
| 201 | .instance_size = sizeof(SpinState), |
xiaoqiang zhao | 09a7eb9 | 2017-01-06 08:26:27 +0800 | [diff] [blame] | 202 | .instance_init = ppce500_spin_initfn, |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 203 | .class_init = ppce500_spin_class_init, |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 204 | }; |
| 205 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 206 | static void ppce500_spin_register_types(void) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 207 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 208 | type_register_static(&ppce500_spin_info); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 209 | } |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 210 | |
| 211 | type_init(ppce500_spin_register_types) |