1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * QEMU Loongson 7A1000 I/O interrupt controller. 4 * 5 * Copyright (C) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/bitops.h" 10 #include "qemu/log.h" 11 #include "hw/irq.h" 12 #include "hw/intc/loongarch_pch_pic.h" 13 #include "system/kvm.h" 14 #include "trace.h" 15 #include "qapi/error.h" 16 17 static void pch_pic_update_irq(LoongArchPICCommonState *s, uint64_t mask, 18 int level) 19 { 20 uint64_t val; 21 int irq; 22 23 if (level) { 24 val = mask & s->intirr & ~s->int_mask; 25 if (val) { 26 irq = ctz64(val); 27 s->intisr |= MAKE_64BIT_MASK(irq, 1); 28 qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); 29 } 30 } else { 31 /* 32 * intirr means requested pending irq 33 * do not clear pending irq for edge-triggered on lowering edge 34 */ 35 val = mask & s->intisr & ~s->intirr; 36 if (val) { 37 irq = ctz64(val); 38 s->intisr &= ~MAKE_64BIT_MASK(irq, 1); 39 qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); 40 } 41 } 42 } 43 44 static void pch_pic_irq_handler(void *opaque, int irq, int level) 45 { 46 LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); 47 uint64_t mask = 1ULL << irq; 48 49 assert(irq < s->irq_num); 50 trace_loongarch_pch_pic_irq_handler(irq, level); 51 52 if (kvm_irqchip_in_kernel()) { 53 kvm_set_irq(kvm_state, irq, !!level); 54 return; 55 } 56 57 if (s->intedge & mask) { 58 /* Edge triggered */ 59 if (level) { 60 if ((s->last_intirr & mask) == 0) { 61 /* marked pending on a rising edge */ 62 s->intirr |= mask; 63 } 64 s->last_intirr |= mask; 65 } else { 66 s->last_intirr &= ~mask; 67 } 68 } else { 69 /* Level triggered */ 70 if (level) { 71 s->intirr |= mask; 72 s->last_intirr |= mask; 73 } else { 74 s->intirr &= ~mask; 75 s->last_intirr &= ~mask; 76 } 77 } 78 pch_pic_update_irq(s, mask, level); 79 } 80 81 static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask) 82 { 83 LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); 84 uint64_t val = 0; 85 uint32_t offset; 86 87 offset = addr & 7; 88 addr -= offset; 89 switch (addr) { 90 case PCH_PIC_INT_ID: 91 val = cpu_to_le64(s->id.data); 92 break; 93 case PCH_PIC_INT_MASK: 94 val = s->int_mask; 95 break; 96 case PCH_PIC_INT_EDGE: 97 val = s->intedge; 98 break; 99 case PCH_PIC_HTMSI_EN: 100 val = s->htmsi_en; 101 break; 102 case PCH_PIC_AUTO_CTRL0: 103 case PCH_PIC_AUTO_CTRL1: 104 /* PCH PIC connect to EXTIOI always, discard auto_ctrl access */ 105 break; 106 case PCH_PIC_INT_STATUS: 107 val = s->intisr & (~s->int_mask); 108 break; 109 case PCH_PIC_INT_POL: 110 val = s->int_polarity; 111 break; 112 case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: 113 val = ldq_le_p(&s->htmsi_vector[addr - PCH_PIC_HTMSI_VEC]); 114 break; 115 case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: 116 val = ldq_le_p(&s->route_entry[addr - PCH_PIC_ROUTE_ENTRY]); 117 break; 118 default: 119 qemu_log_mask(LOG_GUEST_ERROR, 120 "pch_pic_read: Bad address 0x%"PRIx64"\n", addr); 121 break; 122 } 123 124 return (val >> (offset * 8)) & field_mask; 125 } 126 127 static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value, 128 uint64_t field_mask) 129 { 130 LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); 131 uint32_t offset; 132 uint64_t old, mask, data; 133 void *ptemp; 134 135 offset = addr & 7; 136 addr -= offset; 137 mask = field_mask << (offset * 8); 138 data = (value & field_mask) << (offset * 8); 139 switch (addr) { 140 case PCH_PIC_INT_MASK: 141 old = s->int_mask; 142 s->int_mask = (old & ~mask) | data; 143 if (old & ~data) { 144 pch_pic_update_irq(s, old & ~data, 1); 145 } 146 147 if (~old & data) { 148 pch_pic_update_irq(s, ~old & data, 0); 149 } 150 break; 151 case PCH_PIC_INT_EDGE: 152 s->intedge = (s->intedge & ~mask) | data; 153 break; 154 case PCH_PIC_INT_CLEAR: 155 if (s->intedge & data) { 156 s->intirr &= ~data; 157 pch_pic_update_irq(s, data, 0); 158 s->intisr &= ~data; 159 } 160 break; 161 case PCH_PIC_HTMSI_EN: 162 s->htmsi_en = (s->htmsi_en & ~mask) | data; 163 break; 164 case PCH_PIC_AUTO_CTRL0: 165 case PCH_PIC_AUTO_CTRL1: 166 /* Discard auto_ctrl access */ 167 break; 168 case PCH_PIC_INT_POL: 169 s->int_polarity = (s->int_polarity & ~mask) | data; 170 break; 171 case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END: 172 ptemp = &s->htmsi_vector[addr - PCH_PIC_HTMSI_VEC]; 173 stq_le_p(ptemp, (ldq_le_p(ptemp) & ~mask) | data); 174 break; 175 case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END: 176 ptemp = (uint64_t *)&s->route_entry[addr - PCH_PIC_ROUTE_ENTRY]; 177 stq_le_p(ptemp, (ldq_le_p(ptemp) & ~mask) | data); 178 break; 179 default: 180 qemu_log_mask(LOG_GUEST_ERROR, 181 "pch_pic_write: Bad address 0x%"PRIx64"\n", addr); 182 break; 183 } 184 } 185 186 static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr, 187 unsigned size) 188 { 189 uint64_t val = 0; 190 191 switch (size) { 192 case 1: 193 val = pch_pic_read(opaque, addr, UCHAR_MAX); 194 break; 195 case 2: 196 val = pch_pic_read(opaque, addr, USHRT_MAX); 197 break; 198 case 4: 199 val = pch_pic_read(opaque, addr, UINT_MAX); 200 break; 201 case 8: 202 val = pch_pic_read(opaque, addr, UINT64_MAX); 203 break; 204 default: 205 qemu_log_mask(LOG_GUEST_ERROR, 206 "loongarch_pch_pic_read: Bad size %d\n", size); 207 break; 208 } 209 210 trace_loongarch_pch_pic_read(size, addr, val); 211 return val; 212 } 213 214 static void loongarch_pch_pic_write(void *opaque, hwaddr addr, 215 uint64_t value, unsigned size) 216 { 217 trace_loongarch_pch_pic_write(size, addr, value); 218 219 switch (size) { 220 case 1: 221 pch_pic_write(opaque, addr, value, UCHAR_MAX); 222 break; 223 case 2: 224 pch_pic_write(opaque, addr, value, USHRT_MAX); 225 break; 226 break; 227 case 4: 228 pch_pic_write(opaque, addr, value, UINT_MAX); 229 break; 230 case 8: 231 pch_pic_write(opaque, addr, value, UINT64_MAX); 232 break; 233 default: 234 qemu_log_mask(LOG_GUEST_ERROR, 235 "loongarch_pch_pic_write: Bad size %d\n", size); 236 break; 237 } 238 } 239 240 static const MemoryRegionOps loongarch_pch_pic_ops = { 241 .read = loongarch_pch_pic_read, 242 .write = loongarch_pch_pic_write, 243 .valid = { 244 .min_access_size = 1, 245 .max_access_size = 8, 246 /* 247 * PCH PIC device would not work correctly if the guest was doing 248 * unaligned access. This might not be a limitation on the real 249 * device but in practice there is no reason for a guest to access 250 * this device unaligned. 251 */ 252 .unaligned = false, 253 }, 254 .impl = { 255 .min_access_size = 1, 256 .max_access_size = 8, 257 }, 258 .endianness = DEVICE_LITTLE_ENDIAN, 259 }; 260 261 static void loongarch_pic_reset_hold(Object *obj, ResetType type) 262 { 263 LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(obj); 264 265 if (lpc->parent_phases.hold) { 266 lpc->parent_phases.hold(obj, type); 267 } 268 269 if (kvm_irqchip_in_kernel()) { 270 kvm_pic_put(obj, 0); 271 } 272 } 273 274 static void loongarch_pic_realize(DeviceState *dev, Error **errp) 275 { 276 LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(dev); 277 LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(dev); 278 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 279 Error *local_err = NULL; 280 281 lpc->parent_realize(dev, &local_err); 282 if (local_err) { 283 error_propagate(errp, local_err); 284 return; 285 } 286 287 qdev_init_gpio_out(dev, s->parent_irq, s->irq_num); 288 qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num); 289 290 if (kvm_irqchip_in_kernel()) { 291 kvm_pic_realize(dev, errp); 292 } else { 293 memory_region_init_io(&s->iomem, OBJECT(dev), 294 &loongarch_pch_pic_ops, 295 s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE); 296 sysbus_init_mmio(sbd, &s->iomem); 297 } 298 } 299 300 static int loongarch_pic_pre_save(LoongArchPICCommonState *opaque) 301 { 302 if (kvm_irqchip_in_kernel()) { 303 return kvm_pic_get(opaque); 304 } 305 306 return 0; 307 } 308 309 static int loongarch_pic_post_load(LoongArchPICCommonState *opaque, 310 int version_id) 311 { 312 if (kvm_irqchip_in_kernel()) { 313 return kvm_pic_put(opaque, version_id); 314 } 315 316 return 0; 317 } 318 319 static void loongarch_pic_class_init(ObjectClass *klass, const void *data) 320 { 321 DeviceClass *dc = DEVICE_CLASS(klass); 322 LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass); 323 LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass); 324 ResettableClass *rc = RESETTABLE_CLASS(klass); 325 326 resettable_class_set_parent_phases(rc, NULL, loongarch_pic_reset_hold, 327 NULL, &lpc->parent_phases); 328 device_class_set_parent_realize(dc, loongarch_pic_realize, 329 &lpc->parent_realize); 330 lpcc->pre_save = loongarch_pic_pre_save; 331 lpcc->post_load = loongarch_pic_post_load; 332 } 333 334 static const TypeInfo loongarch_pic_types[] = { 335 { 336 .name = TYPE_LOONGARCH_PIC, 337 .parent = TYPE_LOONGARCH_PIC_COMMON, 338 .instance_size = sizeof(LoongarchPICState), 339 .class_size = sizeof(LoongarchPICClass), 340 .class_init = loongarch_pic_class_init, 341 } 342 }; 343 344 DEFINE_TYPES(loongarch_pic_types) 345