1 /* 2 * RISC-V IMSIC (Incoming Message Signaled Interrupt Controller) 3 * 4 * Copyright (c) 2021 Western Digital Corporation or its affiliates. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "qemu/osdep.h" 20 #include "qapi/error.h" 21 #include "qemu/log.h" 22 #include "qemu/module.h" 23 #include "qemu/error-report.h" 24 #include "qemu/bswap.h" 25 #include "exec/address-spaces.h" 26 #include "hw/sysbus.h" 27 #include "hw/pci/msi.h" 28 #include "hw/boards.h" 29 #include "hw/qdev-properties.h" 30 #include "hw/intc/riscv_imsic.h" 31 #include "hw/irq.h" 32 #include "target/riscv/cpu.h" 33 #include "target/riscv/cpu_bits.h" 34 #include "sysemu/sysemu.h" 35 #include "migration/vmstate.h" 36 37 #define IMSIC_MMIO_PAGE_LE 0x00 38 #define IMSIC_MMIO_PAGE_BE 0x04 39 40 #define IMSIC_MIN_ID ((IMSIC_EIPx_BITS * 2) - 1) 41 #define IMSIC_MAX_ID (IMSIC_TOPEI_IID_MASK) 42 43 #define IMSIC_EISTATE_PENDING (1U << 0) 44 #define IMSIC_EISTATE_ENABLED (1U << 1) 45 #define IMSIC_EISTATE_ENPEND (IMSIC_EISTATE_ENABLED | \ 46 IMSIC_EISTATE_PENDING) 47 48 static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page) 49 { 50 uint32_t i, max_irq, base; 51 52 base = page * imsic->num_irqs; 53 max_irq = (imsic->eithreshold[page] && 54 (imsic->eithreshold[page] <= imsic->num_irqs)) ? 55 imsic->eithreshold[page] : imsic->num_irqs; 56 for (i = 1; i < max_irq; i++) { 57 if ((imsic->eistate[base + i] & IMSIC_EISTATE_ENPEND) == 58 IMSIC_EISTATE_ENPEND) { 59 return (i << IMSIC_TOPEI_IID_SHIFT) | i; 60 } 61 } 62 63 return 0; 64 } 65 66 static void riscv_imsic_update(RISCVIMSICState *imsic, uint32_t page) 67 { 68 if (imsic->eidelivery[page] && riscv_imsic_topei(imsic, page)) { 69 qemu_irq_raise(imsic->external_irqs[page]); 70 } else { 71 qemu_irq_lower(imsic->external_irqs[page]); 72 } 73 } 74 75 static int riscv_imsic_eidelivery_rmw(RISCVIMSICState *imsic, uint32_t page, 76 target_ulong *val, 77 target_ulong new_val, 78 target_ulong wr_mask) 79 { 80 target_ulong old_val = imsic->eidelivery[page]; 81 82 if (val) { 83 *val = old_val; 84 } 85 86 wr_mask &= 0x1; 87 imsic->eidelivery[page] = (old_val & ~wr_mask) | (new_val & wr_mask); 88 89 riscv_imsic_update(imsic, page); 90 return 0; 91 } 92 93 static int riscv_imsic_eithreshold_rmw(RISCVIMSICState *imsic, uint32_t page, 94 target_ulong *val, 95 target_ulong new_val, 96 target_ulong wr_mask) 97 { 98 target_ulong old_val = imsic->eithreshold[page]; 99 100 if (val) { 101 *val = old_val; 102 } 103 104 wr_mask &= IMSIC_MAX_ID; 105 imsic->eithreshold[page] = (old_val & ~wr_mask) | (new_val & wr_mask); 106 107 riscv_imsic_update(imsic, page); 108 return 0; 109 } 110 111 static int riscv_imsic_topei_rmw(RISCVIMSICState *imsic, uint32_t page, 112 target_ulong *val, target_ulong new_val, 113 target_ulong wr_mask) 114 { 115 uint32_t base, topei = riscv_imsic_topei(imsic, page); 116 117 /* Read pending and enabled interrupt with highest priority */ 118 if (val) { 119 *val = topei; 120 } 121 122 /* Writes ignore value and clear top pending interrupt */ 123 if (topei && wr_mask) { 124 topei >>= IMSIC_TOPEI_IID_SHIFT; 125 base = page * imsic->num_irqs; 126 if (topei) { 127 imsic->eistate[base + topei] &= ~IMSIC_EISTATE_PENDING; 128 } 129 130 riscv_imsic_update(imsic, page); 131 } 132 133 return 0; 134 } 135 136 static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic, 137 uint32_t xlen, uint32_t page, 138 uint32_t num, bool pend, target_ulong *val, 139 target_ulong new_val, target_ulong wr_mask) 140 { 141 uint32_t i, base; 142 target_ulong mask; 143 uint32_t state = (pend) ? IMSIC_EISTATE_PENDING : IMSIC_EISTATE_ENABLED; 144 145 if (xlen != 32) { 146 if (num & 0x1) { 147 return -EINVAL; 148 } 149 num >>= 1; 150 } 151 if (num >= (imsic->num_irqs / xlen)) { 152 return -EINVAL; 153 } 154 155 base = (page * imsic->num_irqs) + (num * xlen); 156 157 if (val) { 158 *val = 0; 159 for (i = 0; i < xlen; i++) { 160 mask = (target_ulong)1 << i; 161 *val |= (imsic->eistate[base + i] & state) ? mask : 0; 162 } 163 } 164 165 for (i = 0; i < xlen; i++) { 166 /* Bit0 of eip0 and eie0 are read-only zero */ 167 if (!num && !i) { 168 continue; 169 } 170 171 mask = (target_ulong)1 << i; 172 if (wr_mask & mask) { 173 if (new_val & mask) { 174 imsic->eistate[base + i] |= state; 175 } else { 176 imsic->eistate[base + i] &= ~state; 177 } 178 } 179 } 180 181 riscv_imsic_update(imsic, page); 182 return 0; 183 } 184 185 static int riscv_imsic_rmw(void *arg, target_ulong reg, target_ulong *val, 186 target_ulong new_val, target_ulong wr_mask) 187 { 188 RISCVIMSICState *imsic = arg; 189 uint32_t isel, priv, virt, vgein, xlen, page; 190 191 priv = AIA_IREG_PRIV(reg); 192 virt = AIA_IREG_VIRT(reg); 193 isel = AIA_IREG_ISEL(reg); 194 vgein = AIA_IREG_VGEIN(reg); 195 xlen = AIA_IREG_XLEN(reg); 196 197 if (imsic->mmode) { 198 if (priv == PRV_M && !virt) { 199 page = 0; 200 } else { 201 goto err; 202 } 203 } else { 204 if (priv == PRV_S) { 205 if (virt) { 206 if (vgein && vgein < imsic->num_pages) { 207 page = vgein; 208 } else { 209 goto err; 210 } 211 } else { 212 page = 0; 213 } 214 } else { 215 goto err; 216 } 217 } 218 219 switch (isel) { 220 case ISELECT_IMSIC_EIDELIVERY: 221 return riscv_imsic_eidelivery_rmw(imsic, page, val, 222 new_val, wr_mask); 223 case ISELECT_IMSIC_EITHRESHOLD: 224 return riscv_imsic_eithreshold_rmw(imsic, page, val, 225 new_val, wr_mask); 226 case ISELECT_IMSIC_TOPEI: 227 return riscv_imsic_topei_rmw(imsic, page, val, new_val, wr_mask); 228 case ISELECT_IMSIC_EIP0 ... ISELECT_IMSIC_EIP63: 229 return riscv_imsic_eix_rmw(imsic, xlen, page, 230 isel - ISELECT_IMSIC_EIP0, 231 true, val, new_val, wr_mask); 232 case ISELECT_IMSIC_EIE0 ... ISELECT_IMSIC_EIE63: 233 return riscv_imsic_eix_rmw(imsic, xlen, page, 234 isel - ISELECT_IMSIC_EIE0, 235 false, val, new_val, wr_mask); 236 default: 237 break; 238 }; 239 240 err: 241 qemu_log_mask(LOG_GUEST_ERROR, 242 "%s: Invalid register priv=%d virt=%d isel=%d vgein=%d\n", 243 __func__, priv, virt, isel, vgein); 244 return -EINVAL; 245 } 246 247 static uint64_t riscv_imsic_read(void *opaque, hwaddr addr, unsigned size) 248 { 249 RISCVIMSICState *imsic = opaque; 250 251 /* Reads must be 4 byte words */ 252 if ((addr & 0x3) != 0) { 253 goto err; 254 } 255 256 /* Reads cannot be out of range */ 257 if (addr > IMSIC_MMIO_SIZE(imsic->num_pages)) { 258 goto err; 259 } 260 261 return 0; 262 263 err: 264 qemu_log_mask(LOG_GUEST_ERROR, 265 "%s: Invalid register read 0x%" HWADDR_PRIx "\n", 266 __func__, addr); 267 return 0; 268 } 269 270 static void riscv_imsic_write(void *opaque, hwaddr addr, uint64_t value, 271 unsigned size) 272 { 273 RISCVIMSICState *imsic = opaque; 274 uint32_t page; 275 276 /* Writes must be 4 byte words */ 277 if ((addr & 0x3) != 0) { 278 goto err; 279 } 280 281 /* Writes cannot be out of range */ 282 if (addr > IMSIC_MMIO_SIZE(imsic->num_pages)) { 283 goto err; 284 } 285 286 /* Writes only supported for MSI little-endian registers */ 287 page = addr >> IMSIC_MMIO_PAGE_SHIFT; 288 if ((addr & (IMSIC_MMIO_PAGE_SZ - 1)) == IMSIC_MMIO_PAGE_LE) { 289 if (value && (value < imsic->num_irqs)) { 290 imsic->eistate[(page * imsic->num_irqs) + value] |= 291 IMSIC_EISTATE_PENDING; 292 } 293 } 294 295 /* Update CPU external interrupt status */ 296 riscv_imsic_update(imsic, page); 297 298 return; 299 300 err: 301 qemu_log_mask(LOG_GUEST_ERROR, 302 "%s: Invalid register write 0x%" HWADDR_PRIx "\n", 303 __func__, addr); 304 } 305 306 static const MemoryRegionOps riscv_imsic_ops = { 307 .read = riscv_imsic_read, 308 .write = riscv_imsic_write, 309 .endianness = DEVICE_LITTLE_ENDIAN, 310 .valid = { 311 .min_access_size = 4, 312 .max_access_size = 4 313 } 314 }; 315 316 static void riscv_imsic_realize(DeviceState *dev, Error **errp) 317 { 318 RISCVIMSICState *imsic = RISCV_IMSIC(dev); 319 RISCVCPU *rcpu = RISCV_CPU(qemu_get_cpu(imsic->hartid)); 320 CPUState *cpu = qemu_get_cpu(imsic->hartid); 321 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 322 323 imsic->num_eistate = imsic->num_pages * imsic->num_irqs; 324 imsic->eidelivery = g_new0(uint32_t, imsic->num_pages); 325 imsic->eithreshold = g_new0(uint32_t, imsic->num_pages); 326 imsic->eistate = g_new0(uint32_t, imsic->num_eistate); 327 328 memory_region_init_io(&imsic->mmio, OBJECT(dev), &riscv_imsic_ops, 329 imsic, TYPE_RISCV_IMSIC, 330 IMSIC_MMIO_SIZE(imsic->num_pages)); 331 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &imsic->mmio); 332 333 /* Claim the CPU interrupt to be triggered by this IMSIC */ 334 if (riscv_cpu_claim_interrupts(rcpu, 335 (imsic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) { 336 error_setg(errp, "%s already claimed", 337 (imsic->mmode) ? "MEIP" : "SEIP"); 338 return; 339 } 340 341 /* Create output IRQ lines */ 342 imsic->external_irqs = g_malloc(sizeof(qemu_irq) * imsic->num_pages); 343 qdev_init_gpio_out(dev, imsic->external_irqs, imsic->num_pages); 344 345 /* Force select AIA feature and setup CSR read-modify-write callback */ 346 if (env) { 347 if (!imsic->mmode) { 348 rcpu->cfg.ext_ssaia = true; 349 riscv_cpu_set_geilen(env, imsic->num_pages - 1); 350 } else { 351 rcpu->cfg.ext_smaia = true; 352 } 353 riscv_cpu_set_aia_ireg_rmw_fn(env, (imsic->mmode) ? PRV_M : PRV_S, 354 riscv_imsic_rmw, imsic); 355 } 356 357 msi_nonbroken = true; 358 } 359 360 static Property riscv_imsic_properties[] = { 361 DEFINE_PROP_BOOL("mmode", RISCVIMSICState, mmode, 0), 362 DEFINE_PROP_UINT32("hartid", RISCVIMSICState, hartid, 0), 363 DEFINE_PROP_UINT32("num-pages", RISCVIMSICState, num_pages, 0), 364 DEFINE_PROP_UINT32("num-irqs", RISCVIMSICState, num_irqs, 0), 365 DEFINE_PROP_END_OF_LIST(), 366 }; 367 368 static const VMStateDescription vmstate_riscv_imsic = { 369 .name = "riscv_imsic", 370 .version_id = 1, 371 .minimum_version_id = 1, 372 .fields = (VMStateField[]) { 373 VMSTATE_VARRAY_UINT32(eidelivery, RISCVIMSICState, 374 num_pages, 0, 375 vmstate_info_uint32, uint32_t), 376 VMSTATE_VARRAY_UINT32(eithreshold, RISCVIMSICState, 377 num_pages, 0, 378 vmstate_info_uint32, uint32_t), 379 VMSTATE_VARRAY_UINT32(eistate, RISCVIMSICState, 380 num_eistate, 0, 381 vmstate_info_uint32, uint32_t), 382 VMSTATE_END_OF_LIST() 383 } 384 }; 385 386 static void riscv_imsic_class_init(ObjectClass *klass, void *data) 387 { 388 DeviceClass *dc = DEVICE_CLASS(klass); 389 390 device_class_set_props(dc, riscv_imsic_properties); 391 dc->realize = riscv_imsic_realize; 392 dc->vmsd = &vmstate_riscv_imsic; 393 } 394 395 static const TypeInfo riscv_imsic_info = { 396 .name = TYPE_RISCV_IMSIC, 397 .parent = TYPE_SYS_BUS_DEVICE, 398 .instance_size = sizeof(RISCVIMSICState), 399 .class_init = riscv_imsic_class_init, 400 }; 401 402 static void riscv_imsic_register_types(void) 403 { 404 type_register_static(&riscv_imsic_info); 405 } 406 407 type_init(riscv_imsic_register_types) 408 409 /* 410 * Create IMSIC device. 411 */ 412 DeviceState *riscv_imsic_create(hwaddr addr, uint32_t hartid, bool mmode, 413 uint32_t num_pages, uint32_t num_ids) 414 { 415 DeviceState *dev = qdev_new(TYPE_RISCV_IMSIC); 416 CPUState *cpu = qemu_get_cpu(hartid); 417 uint32_t i; 418 419 assert(!(addr & (IMSIC_MMIO_PAGE_SZ - 1))); 420 if (mmode) { 421 assert(num_pages == 1); 422 } else { 423 assert(num_pages >= 1 && num_pages <= (IRQ_LOCAL_GUEST_MAX + 1)); 424 } 425 assert(IMSIC_MIN_ID <= num_ids); 426 assert(num_ids <= IMSIC_MAX_ID); 427 assert((num_ids & IMSIC_MIN_ID) == IMSIC_MIN_ID); 428 429 qdev_prop_set_bit(dev, "mmode", mmode); 430 qdev_prop_set_uint32(dev, "hartid", hartid); 431 qdev_prop_set_uint32(dev, "num-pages", num_pages); 432 qdev_prop_set_uint32(dev, "num-irqs", num_ids + 1); 433 434 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 435 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 436 437 for (i = 0; i < num_pages; i++) { 438 if (!i) { 439 qdev_connect_gpio_out_named(dev, NULL, i, 440 qdev_get_gpio_in(DEVICE(cpu), 441 (mmode) ? IRQ_M_EXT : IRQ_S_EXT)); 442 } else { 443 qdev_connect_gpio_out_named(dev, NULL, i, 444 qdev_get_gpio_in(DEVICE(cpu), 445 IRQ_LOCAL_MAX + i - 1)); 446 } 447 } 448 449 return dev; 450 } 451