qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/intc: RX62N interrupt controller (ICUa)

This implementation supported only ICUa.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200224141923.82118-15-ysato@users.sourceforge.jp>
[PMD: Fill VMStateField for migration, cover files in MAINTAINERS]
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

authored by

Yoshinori Sato and committed by
Philippe Mathieu-Daudé
e78597cc f4d2382a

+483
+6
MAINTAINERS
··· 1975 1975 F: hw/timer/sh_timer.c 1976 1976 F: include/hw/sh4/sh.h 1977 1977 1978 + Renesas RX peripherals 1979 + M: Yoshinori Sato <ysato@users.sourceforge.jp> 1980 + S: Maintained 1981 + F: hw/intc/rx_icu.c 1982 + F: include/hw/intc/rx_icu.h 1983 + 1978 1984 Subsystems 1979 1985 ---------- 1980 1986 Audio
+3
hw/intc/Kconfig
··· 61 61 62 62 config OMPIC 63 63 bool 64 + 65 + config RX_ICU 66 + bool
+1
hw/intc/Makefile.objs
··· 20 20 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o 21 21 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o 22 22 common-obj-$(CONFIG_OPENPIC) += openpic.o 23 + common-obj-$(CONFIG_RX_ICU) += rx_icu.o 23 24 common-obj-y += intc.o 24 25 25 26 obj-$(CONFIG_APIC) += apic.o apic_common.o
+397
hw/intc/rx_icu.c
··· 1 + /* 2 + * RX Interrupt Control Unit 3 + * 4 + * Warning: Only ICUa is supported. 5 + * 6 + * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware 7 + * (Rev.1.40 R01UH0033EJ0140) 8 + * 9 + * Copyright (c) 2019 Yoshinori Sato 10 + * 11 + * SPDX-License-Identifier: GPL-2.0-or-later 12 + * 13 + * This program is free software; you can redistribute it and/or modify it 14 + * under the terms and conditions of the GNU General Public License, 15 + * version 2 or later, as published by the Free Software Foundation. 16 + * 17 + * This program is distributed in the hope it will be useful, but WITHOUT 18 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 20 + * more details. 21 + * 22 + * You should have received a copy of the GNU General Public License along with 23 + * this program. If not, see <http://www.gnu.org/licenses/>. 24 + */ 25 + 26 + #include "qemu/osdep.h" 27 + #include "qemu/log.h" 28 + #include "qemu/error-report.h" 29 + #include "hw/irq.h" 30 + #include "hw/registerfields.h" 31 + #include "hw/qdev-properties.h" 32 + #include "hw/intc/rx_icu.h" 33 + #include "migration/vmstate.h" 34 + 35 + REG8(IR, 0) 36 + FIELD(IR, IR, 0, 1) 37 + REG8(DTCER, 0x100) 38 + FIELD(DTCER, DTCE, 0, 1) 39 + REG8(IER, 0x200) 40 + REG8(SWINTR, 0x2e0) 41 + FIELD(SWINTR, SWINT, 0, 1) 42 + REG16(FIR, 0x2f0) 43 + FIELD(FIR, FVCT, 0, 8) 44 + FIELD(FIR, FIEN, 15, 1) 45 + REG8(IPR, 0x300) 46 + FIELD(IPR, IPR, 0, 4) 47 + REG8(DMRSR, 0x400) 48 + REG8(IRQCR, 0x500) 49 + FIELD(IRQCR, IRQMD, 2, 2) 50 + REG8(NMISR, 0x580) 51 + FIELD(NMISR, NMIST, 0, 1) 52 + FIELD(NMISR, LVDST, 1, 1) 53 + FIELD(NMISR, OSTST, 2, 1) 54 + REG8(NMIER, 0x581) 55 + FIELD(NMIER, NMIEN, 0, 1) 56 + FIELD(NMIER, LVDEN, 1, 1) 57 + FIELD(NMIER, OSTEN, 2, 1) 58 + REG8(NMICLR, 0x582) 59 + FIELD(NMICLR, NMICLR, 0, 1) 60 + FIELD(NMICLR, OSTCLR, 2, 1) 61 + REG8(NMICR, 0x583) 62 + FIELD(NMICR, NMIMD, 3, 1) 63 + 64 + static void set_irq(RXICUState *icu, int n_IRQ, int req) 65 + { 66 + if ((icu->fir & R_FIR_FIEN_MASK) && 67 + (icu->fir & R_FIR_FVCT_MASK) == n_IRQ) { 68 + qemu_set_irq(icu->_fir, req); 69 + } else { 70 + qemu_set_irq(icu->_irq, req); 71 + } 72 + } 73 + 74 + static uint16_t rxicu_level(RXICUState *icu, unsigned n) 75 + { 76 + return (icu->ipr[icu->map[n]] << 8) | n; 77 + } 78 + 79 + static void rxicu_request(RXICUState *icu, int n_IRQ) 80 + { 81 + int enable; 82 + 83 + enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7)); 84 + if (n_IRQ > 0 && enable != 0 && atomic_read(&icu->req_irq) < 0) { 85 + atomic_set(&icu->req_irq, n_IRQ); 86 + set_irq(icu, n_IRQ, rxicu_level(icu, n_IRQ)); 87 + } 88 + } 89 + 90 + static void rxicu_set_irq(void *opaque, int n_IRQ, int level) 91 + { 92 + RXICUState *icu = opaque; 93 + struct IRQSource *src; 94 + int issue; 95 + 96 + if (n_IRQ >= NR_IRQS) { 97 + error_report("%s: IRQ %d out of range", __func__, n_IRQ); 98 + return; 99 + } 100 + 101 + src = &icu->src[n_IRQ]; 102 + 103 + level = (level != 0); 104 + switch (src->sense) { 105 + case TRG_LEVEL: 106 + /* level-sensitive irq */ 107 + issue = level; 108 + src->level = level; 109 + break; 110 + case TRG_NEDGE: 111 + issue = (level == 0 && src->level == 1); 112 + src->level = level; 113 + break; 114 + case TRG_PEDGE: 115 + issue = (level == 1 && src->level == 0); 116 + src->level = level; 117 + break; 118 + case TRG_BEDGE: 119 + issue = ((level ^ src->level) & 1); 120 + src->level = level; 121 + break; 122 + default: 123 + g_assert_not_reached(); 124 + } 125 + if (issue == 0 && src->sense == TRG_LEVEL) { 126 + icu->ir[n_IRQ] = 0; 127 + if (atomic_read(&icu->req_irq) == n_IRQ) { 128 + /* clear request */ 129 + set_irq(icu, n_IRQ, 0); 130 + atomic_set(&icu->req_irq, -1); 131 + } 132 + return; 133 + } 134 + if (issue) { 135 + icu->ir[n_IRQ] = 1; 136 + rxicu_request(icu, n_IRQ); 137 + } 138 + } 139 + 140 + static void rxicu_ack_irq(void *opaque, int no, int level) 141 + { 142 + RXICUState *icu = opaque; 143 + int i; 144 + int n_IRQ; 145 + int max_pri; 146 + 147 + n_IRQ = atomic_read(&icu->req_irq); 148 + if (n_IRQ < 0) { 149 + return; 150 + } 151 + atomic_set(&icu->req_irq, -1); 152 + if (icu->src[n_IRQ].sense != TRG_LEVEL) { 153 + icu->ir[n_IRQ] = 0; 154 + } 155 + 156 + max_pri = 0; 157 + n_IRQ = -1; 158 + for (i = 0; i < NR_IRQS; i++) { 159 + if (icu->ir[i]) { 160 + if (max_pri < icu->ipr[icu->map[i]]) { 161 + n_IRQ = i; 162 + max_pri = icu->ipr[icu->map[i]]; 163 + } 164 + } 165 + } 166 + 167 + if (n_IRQ >= 0) { 168 + rxicu_request(icu, n_IRQ); 169 + } 170 + } 171 + 172 + static uint64_t icu_read(void *opaque, hwaddr addr, unsigned size) 173 + { 174 + RXICUState *icu = opaque; 175 + int reg = addr & 0xff; 176 + 177 + if ((addr != A_FIR && size != 1) || 178 + (addr == A_FIR && size != 2)) { 179 + qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid read size 0x%" 180 + HWADDR_PRIX "\n", 181 + addr); 182 + return UINT64_MAX; 183 + } 184 + switch (addr) { 185 + case A_IR ... A_IR + 0xff: 186 + return icu->ir[reg] & R_IR_IR_MASK; 187 + case A_DTCER ... A_DTCER + 0xff: 188 + return icu->dtcer[reg] & R_DTCER_DTCE_MASK; 189 + case A_IER ... A_IER + 0x1f: 190 + return icu->ier[reg]; 191 + case A_SWINTR: 192 + return 0; 193 + case A_FIR: 194 + return icu->fir & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK); 195 + case A_IPR ... A_IPR + 0x8f: 196 + return icu->ipr[reg] & R_IPR_IPR_MASK; 197 + case A_DMRSR: 198 + case A_DMRSR + 4: 199 + case A_DMRSR + 8: 200 + case A_DMRSR + 12: 201 + return icu->dmasr[reg >> 2]; 202 + case A_IRQCR ... A_IRQCR + 0x1f: 203 + return icu->src[64 + reg].sense << R_IRQCR_IRQMD_SHIFT; 204 + case A_NMISR: 205 + case A_NMICLR: 206 + return 0; 207 + case A_NMIER: 208 + return icu->nmier; 209 + case A_NMICR: 210 + return icu->nmicr; 211 + default: 212 + qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " " 213 + "not implemented.\n", 214 + addr); 215 + break; 216 + } 217 + return UINT64_MAX; 218 + } 219 + 220 + static void icu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 221 + { 222 + RXICUState *icu = opaque; 223 + int reg = addr & 0xff; 224 + 225 + if ((addr != A_FIR && size != 1) || 226 + (addr == A_FIR && size != 2)) { 227 + qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid write size at " 228 + "0x%" HWADDR_PRIX "\n", 229 + addr); 230 + return; 231 + } 232 + switch (addr) { 233 + case A_IR ... A_IR + 0xff: 234 + if (icu->src[reg].sense != TRG_LEVEL && val == 0) { 235 + icu->ir[reg] = 0; 236 + } 237 + break; 238 + case A_DTCER ... A_DTCER + 0xff: 239 + icu->dtcer[reg] = val & R_DTCER_DTCE_MASK; 240 + qemu_log_mask(LOG_UNIMP, "rx_icu: DTC not implemented\n"); 241 + break; 242 + case A_IER ... A_IER + 0x1f: 243 + icu->ier[reg] = val; 244 + break; 245 + case A_SWINTR: 246 + if (val & R_SWINTR_SWINT_MASK) { 247 + qemu_irq_pulse(icu->_swi); 248 + } 249 + break; 250 + case A_FIR: 251 + icu->fir = val & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK); 252 + break; 253 + case A_IPR ... A_IPR + 0x8f: 254 + icu->ipr[reg] = val & R_IPR_IPR_MASK; 255 + break; 256 + case A_DMRSR: 257 + case A_DMRSR + 4: 258 + case A_DMRSR + 8: 259 + case A_DMRSR + 12: 260 + icu->dmasr[reg >> 2] = val; 261 + qemu_log_mask(LOG_UNIMP, "rx_icu: DMAC not implemented\n"); 262 + break; 263 + case A_IRQCR ... A_IRQCR + 0x1f: 264 + icu->src[64 + reg].sense = val >> R_IRQCR_IRQMD_SHIFT; 265 + break; 266 + case A_NMICLR: 267 + break; 268 + case A_NMIER: 269 + icu->nmier |= val & (R_NMIER_NMIEN_MASK | 270 + R_NMIER_LVDEN_MASK | 271 + R_NMIER_OSTEN_MASK); 272 + break; 273 + case A_NMICR: 274 + if ((icu->nmier & R_NMIER_NMIEN_MASK) == 0) { 275 + icu->nmicr = val & R_NMICR_NMIMD_MASK; 276 + } 277 + break; 278 + default: 279 + qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " " 280 + "not implemented\n", 281 + addr); 282 + break; 283 + } 284 + } 285 + 286 + static const MemoryRegionOps icu_ops = { 287 + .write = icu_write, 288 + .read = icu_read, 289 + .endianness = DEVICE_LITTLE_ENDIAN, 290 + .impl = { 291 + .min_access_size = 1, 292 + .max_access_size = 2, 293 + }, 294 + .valid = { 295 + .min_access_size = 1, 296 + .max_access_size = 2, 297 + }, 298 + }; 299 + 300 + static void rxicu_realize(DeviceState *dev, Error **errp) 301 + { 302 + RXICUState *icu = RX_ICU(dev); 303 + int i, j; 304 + 305 + if (icu->init_sense == NULL) { 306 + qemu_log_mask(LOG_GUEST_ERROR, 307 + "rx_icu: trigger-level property must be set."); 308 + return; 309 + } 310 + for (i = j = 0; i < NR_IRQS; i++) { 311 + if (icu->init_sense[j] == i) { 312 + icu->src[i].sense = TRG_LEVEL; 313 + if (j < icu->nr_sense) { 314 + j++; 315 + } 316 + } else { 317 + icu->src[i].sense = TRG_PEDGE; 318 + } 319 + } 320 + icu->req_irq = -1; 321 + } 322 + 323 + static void rxicu_init(Object *obj) 324 + { 325 + SysBusDevice *d = SYS_BUS_DEVICE(obj); 326 + RXICUState *icu = RX_ICU(obj); 327 + 328 + memory_region_init_io(&icu->memory, OBJECT(icu), &icu_ops, 329 + icu, "rx-icu", 0x600); 330 + sysbus_init_mmio(d, &icu->memory); 331 + 332 + qdev_init_gpio_in(DEVICE(d), rxicu_set_irq, NR_IRQS); 333 + qdev_init_gpio_in_named(DEVICE(d), rxicu_ack_irq, "ack", 1); 334 + sysbus_init_irq(d, &icu->_irq); 335 + sysbus_init_irq(d, &icu->_fir); 336 + sysbus_init_irq(d, &icu->_swi); 337 + } 338 + 339 + static void rxicu_fini(Object *obj) 340 + { 341 + RXICUState *icu = RX_ICU(obj); 342 + g_free(icu->map); 343 + g_free(icu->init_sense); 344 + } 345 + 346 + static const VMStateDescription vmstate_rxicu = { 347 + .name = "rx-icu", 348 + .version_id = 1, 349 + .minimum_version_id = 1, 350 + .fields = (VMStateField[]) { 351 + VMSTATE_UINT8_ARRAY(ir, RXICUState, NR_IRQS), 352 + VMSTATE_UINT8_ARRAY(dtcer, RXICUState, NR_IRQS), 353 + VMSTATE_UINT8_ARRAY(ier, RXICUState, NR_IRQS / 8), 354 + VMSTATE_UINT8_ARRAY(ipr, RXICUState, 142), 355 + VMSTATE_UINT8_ARRAY(dmasr, RXICUState, 4), 356 + VMSTATE_UINT16(fir, RXICUState), 357 + VMSTATE_UINT8(nmisr, RXICUState), 358 + VMSTATE_UINT8(nmier, RXICUState), 359 + VMSTATE_UINT8(nmiclr, RXICUState), 360 + VMSTATE_UINT8(nmicr, RXICUState), 361 + VMSTATE_INT16(req_irq, RXICUState), 362 + VMSTATE_END_OF_LIST() 363 + } 364 + }; 365 + 366 + static Property rxicu_properties[] = { 367 + DEFINE_PROP_ARRAY("ipr-map", RXICUState, nr_irqs, map, 368 + qdev_prop_uint8, uint8_t), 369 + DEFINE_PROP_ARRAY("trigger-level", RXICUState, nr_sense, init_sense, 370 + qdev_prop_uint8, uint8_t), 371 + DEFINE_PROP_END_OF_LIST(), 372 + }; 373 + 374 + static void rxicu_class_init(ObjectClass *klass, void *data) 375 + { 376 + DeviceClass *dc = DEVICE_CLASS(klass); 377 + 378 + dc->realize = rxicu_realize; 379 + dc->vmsd = &vmstate_rxicu; 380 + device_class_set_props(dc, rxicu_properties); 381 + } 382 + 383 + static const TypeInfo rxicu_info = { 384 + .name = TYPE_RX_ICU, 385 + .parent = TYPE_SYS_BUS_DEVICE, 386 + .instance_size = sizeof(RXICUState), 387 + .instance_init = rxicu_init, 388 + .instance_finalize = rxicu_fini, 389 + .class_init = rxicu_class_init, 390 + }; 391 + 392 + static void rxicu_register_types(void) 393 + { 394 + type_register_static(&rxicu_info); 395 + } 396 + 397 + type_init(rxicu_register_types)
+76
include/hw/intc/rx_icu.h
··· 1 + /* 2 + * RX Interrupt Control Unit 3 + * 4 + * Copyright (c) 2019 Yoshinori Sato 5 + * 6 + * SPDX-License-Identifier: GPL-2.0-or-later 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 + #ifndef HW_INTC_RX_ICU_H 22 + #define HW_INTC_RX_ICU_H 23 + 24 + #include "hw/sysbus.h" 25 + 26 + enum TRG_MODE { 27 + TRG_LEVEL = 0, 28 + TRG_NEDGE = 1, /* Falling */ 29 + TRG_PEDGE = 2, /* Raising */ 30 + TRG_BEDGE = 3, /* Both */ 31 + }; 32 + 33 + struct IRQSource { 34 + enum TRG_MODE sense; 35 + int level; 36 + }; 37 + 38 + enum { 39 + /* Software interrupt request */ 40 + SWI = 27, 41 + NR_IRQS = 256 42 + }; 43 + 44 + struct RXICUState { 45 + /*< private >*/ 46 + SysBusDevice parent_obj; 47 + /*< public >*/ 48 + 49 + MemoryRegion memory; 50 + struct IRQSource src[NR_IRQS]; 51 + uint32_t nr_irqs; 52 + uint8_t *map; 53 + uint32_t nr_sense; 54 + uint8_t *init_sense; 55 + 56 + uint8_t ir[NR_IRQS]; 57 + uint8_t dtcer[NR_IRQS]; 58 + uint8_t ier[NR_IRQS / 8]; 59 + uint8_t ipr[142]; 60 + uint8_t dmasr[4]; 61 + uint16_t fir; 62 + uint8_t nmisr; 63 + uint8_t nmier; 64 + uint8_t nmiclr; 65 + uint8_t nmicr; 66 + int16_t req_irq; 67 + qemu_irq _irq; 68 + qemu_irq _fir; 69 + qemu_irq _swi; 70 + }; 71 + typedef struct RXICUState RXICUState; 72 + 73 + #define TYPE_RX_ICU "rx-icu" 74 + #define RX_ICU(obj) OBJECT_CHECK(RXICUState, (obj), TYPE_RX_ICU) 75 + 76 + #endif /* RX_ICU_H */