ibex_plic.c (9714B)
1/* 2 * QEMU RISC-V lowRISC Ibex PLIC 3 * 4 * Copyright (c) 2020 Western Digital 5 * 6 * Documentation avaliable: https://docs.opentitan.org/hw/ip/rv_plic/doc/ 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2 or later, as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21#include "qemu/osdep.h" 22#include "qemu/log.h" 23#include "hw/qdev-properties.h" 24#include "hw/core/cpu.h" 25#include "hw/boards.h" 26#include "hw/pci/msi.h" 27#include "target/riscv/cpu_bits.h" 28#include "target/riscv/cpu.h" 29#include "hw/intc/ibex_plic.h" 30#include "hw/irq.h" 31 32static bool addr_between(uint32_t addr, uint32_t base, uint32_t num) 33{ 34 uint32_t end = base + (num * 0x04); 35 36 if (addr >= base && addr < end) { 37 return true; 38 } 39 40 return false; 41} 42 43static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level) 44{ 45 int pending_num = irq / 32; 46 47 if (!level) { 48 /* 49 * If the level is low make sure we clear the hidden_pending. 50 */ 51 s->hidden_pending[pending_num] &= ~(1 << (irq % 32)); 52 } 53 54 if (s->claimed[pending_num] & 1 << (irq % 32)) { 55 /* 56 * The interrupt has been claimed, but not completed. 57 * The pending bit can't be set. 58 * Save the pending level for after the interrupt is completed. 59 */ 60 s->hidden_pending[pending_num] |= level << (irq % 32); 61 } else { 62 s->pending[pending_num] |= level << (irq % 32); 63 } 64} 65 66static bool ibex_plic_irqs_pending(IbexPlicState *s, uint32_t context) 67{ 68 int i; 69 uint32_t max_irq = 0; 70 uint32_t max_prio = s->threshold; 71 72 for (i = 0; i < s->pending_num; i++) { 73 uint32_t irq_num = ctz64(s->pending[i]) + (i * 32); 74 75 if (!(s->pending[i] & s->enable[i])) { 76 /* No pending and enabled IRQ */ 77 continue; 78 } 79 80 if (s->priority[irq_num] > max_prio) { 81 max_irq = irq_num; 82 max_prio = s->priority[irq_num]; 83 } 84 } 85 86 if (max_irq) { 87 s->claim = max_irq; 88 return true; 89 } 90 91 return false; 92} 93 94static void ibex_plic_update(IbexPlicState *s) 95{ 96 int i; 97 98 for (i = 0; i < s->num_cpus; i++) { 99 qemu_set_irq(s->external_irqs[i], ibex_plic_irqs_pending(s, 0)); 100 } 101} 102 103static void ibex_plic_reset(DeviceState *dev) 104{ 105 IbexPlicState *s = IBEX_PLIC(dev); 106 107 s->threshold = 0x00000000; 108 s->claim = 0x00000000; 109} 110 111static uint64_t ibex_plic_read(void *opaque, hwaddr addr, 112 unsigned int size) 113{ 114 IbexPlicState *s = opaque; 115 int offset; 116 uint32_t ret = 0; 117 118 if (addr_between(addr, s->pending_base, s->pending_num)) { 119 offset = (addr - s->pending_base) / 4; 120 ret = s->pending[offset]; 121 } else if (addr_between(addr, s->source_base, s->source_num)) { 122 qemu_log_mask(LOG_UNIMP, 123 "%s: Interrupt source mode not supported\n", __func__); 124 } else if (addr_between(addr, s->priority_base, s->priority_num)) { 125 offset = (addr - s->priority_base) / 4; 126 ret = s->priority[offset]; 127 } else if (addr_between(addr, s->enable_base, s->enable_num)) { 128 offset = (addr - s->enable_base) / 4; 129 ret = s->enable[offset]; 130 } else if (addr_between(addr, s->threshold_base, 1)) { 131 ret = s->threshold; 132 } else if (addr_between(addr, s->claim_base, 1)) { 133 int pending_num = s->claim / 32; 134 s->pending[pending_num] &= ~(1 << (s->claim % 32)); 135 136 /* Set the interrupt as claimed, but not completed */ 137 s->claimed[pending_num] |= 1 << (s->claim % 32); 138 139 /* Return the current claimed interrupt */ 140 ret = s->claim; 141 142 /* Clear the claimed interrupt */ 143 s->claim = 0x00000000; 144 145 /* Update the interrupt status after the claim */ 146 ibex_plic_update(s); 147 } 148 149 return ret; 150} 151 152static void ibex_plic_write(void *opaque, hwaddr addr, 153 uint64_t value, unsigned int size) 154{ 155 IbexPlicState *s = opaque; 156 157 if (addr_between(addr, s->pending_base, s->pending_num)) { 158 qemu_log_mask(LOG_GUEST_ERROR, 159 "%s: Pending registers are read only\n", __func__); 160 } else if (addr_between(addr, s->source_base, s->source_num)) { 161 qemu_log_mask(LOG_UNIMP, 162 "%s: Interrupt source mode not supported\n", __func__); 163 } else if (addr_between(addr, s->priority_base, s->priority_num)) { 164 uint32_t irq = ((addr - s->priority_base) >> 2) + 1; 165 s->priority[irq] = value & 7; 166 ibex_plic_update(s); 167 } else if (addr_between(addr, s->enable_base, s->enable_num)) { 168 uint32_t enable_reg = (addr - s->enable_base) / 4; 169 170 s->enable[enable_reg] = value; 171 } else if (addr_between(addr, s->threshold_base, 1)) { 172 s->threshold = value & 3; 173 } else if (addr_between(addr, s->claim_base, 1)) { 174 if (s->claim == value) { 175 /* Interrupt was completed */ 176 s->claim = 0; 177 } 178 if (s->claimed[value / 32] & 1 << (value % 32)) { 179 int pending_num = value / 32; 180 181 /* This value was already claimed, clear it. */ 182 s->claimed[pending_num] &= ~(1 << (value % 32)); 183 184 if (s->hidden_pending[pending_num] & (1 << (value % 32))) { 185 /* 186 * If the bit in hidden_pending is set then that means we 187 * received an interrupt between claiming and completing 188 * the interrupt that hasn't since been de-asserted. 189 * On hardware this would trigger an interrupt, so let's 190 * trigger one here as well. 191 */ 192 s->pending[pending_num] |= 1 << (value % 32); 193 } 194 } 195 } 196 197 ibex_plic_update(s); 198} 199 200static const MemoryRegionOps ibex_plic_ops = { 201 .read = ibex_plic_read, 202 .write = ibex_plic_write, 203 .endianness = DEVICE_NATIVE_ENDIAN, 204 .valid = { 205 .min_access_size = 4, 206 .max_access_size = 4 207 } 208}; 209 210static void ibex_plic_irq_request(void *opaque, int irq, int level) 211{ 212 IbexPlicState *s = opaque; 213 214 ibex_plic_irqs_set_pending(s, irq, level > 0); 215 ibex_plic_update(s); 216} 217 218static Property ibex_plic_properties[] = { 219 DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1), 220 DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 176), 221 222 DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0), 223 DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 6), 224 225 DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x18), 226 DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 6), 227 228 DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x30), 229 DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 177), 230 231 DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x300), 232 DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 6), 233 234 DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x318), 235 236 DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x31c), 237 DEFINE_PROP_END_OF_LIST(), 238}; 239 240static void ibex_plic_init(Object *obj) 241{ 242 IbexPlicState *s = IBEX_PLIC(obj); 243 244 memory_region_init_io(&s->mmio, obj, &ibex_plic_ops, s, 245 TYPE_IBEX_PLIC, 0x400); 246 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 247} 248 249static void ibex_plic_realize(DeviceState *dev, Error **errp) 250{ 251 IbexPlicState *s = IBEX_PLIC(dev); 252 int i; 253 254 s->pending = g_new0(uint32_t, s->pending_num); 255 s->hidden_pending = g_new0(uint32_t, s->pending_num); 256 s->claimed = g_new0(uint32_t, s->pending_num); 257 s->source = g_new0(uint32_t, s->source_num); 258 s->priority = g_new0(uint32_t, s->priority_num); 259 s->enable = g_new0(uint32_t, s->enable_num); 260 261 qdev_init_gpio_in(dev, ibex_plic_irq_request, s->num_sources); 262 263 s->external_irqs = g_malloc(sizeof(qemu_irq) * s->num_cpus); 264 qdev_init_gpio_out(dev, s->external_irqs, s->num_cpus); 265 266 /* 267 * We can't allow the supervisor to control SEIP as this would allow the 268 * supervisor to clear a pending external interrupt which will result in 269 * a lost interrupt in the case a PLIC is attached. The SEIP bit must be 270 * hardware controlled when a PLIC is attached. 271 */ 272 MachineState *ms = MACHINE(qdev_get_machine()); 273 unsigned int smp_cpus = ms->smp.cpus; 274 for (i = 0; i < smp_cpus; i++) { 275 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i)); 276 if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { 277 error_report("SEIP already claimed"); 278 exit(1); 279 } 280 } 281 282 msi_nonbroken = true; 283} 284 285static void ibex_plic_class_init(ObjectClass *klass, void *data) 286{ 287 DeviceClass *dc = DEVICE_CLASS(klass); 288 289 dc->reset = ibex_plic_reset; 290 device_class_set_props(dc, ibex_plic_properties); 291 dc->realize = ibex_plic_realize; 292} 293 294static const TypeInfo ibex_plic_info = { 295 .name = TYPE_IBEX_PLIC, 296 .parent = TYPE_SYS_BUS_DEVICE, 297 .instance_size = sizeof(IbexPlicState), 298 .instance_init = ibex_plic_init, 299 .class_init = ibex_plic_class_init, 300}; 301 302static void ibex_plic_register_types(void) 303{ 304 type_register_static(&ibex_plic_info); 305} 306 307type_init(ibex_plic_register_types)