1b4a12dfcSJiaxun Yang /* SPDX-License-Identifier: GPL-2.0-or-later */ 2b4a12dfcSJiaxun Yang /* 3b4a12dfcSJiaxun Yang * Loongson ipi interrupt support 4b4a12dfcSJiaxun Yang * 5b4a12dfcSJiaxun Yang * Copyright (C) 2021 Loongson Technology Corporation Limited 6b4a12dfcSJiaxun Yang */ 7b4a12dfcSJiaxun Yang 8b4a12dfcSJiaxun Yang #include "qemu/osdep.h" 9b4a12dfcSJiaxun Yang #include "hw/boards.h" 10b4a12dfcSJiaxun Yang #include "hw/sysbus.h" 11b4a12dfcSJiaxun Yang #include "hw/intc/loongson_ipi.h" 12b4a12dfcSJiaxun Yang #include "hw/irq.h" 13b4a12dfcSJiaxun Yang #include "hw/qdev-properties.h" 14b4a12dfcSJiaxun Yang #include "qapi/error.h" 15b4a12dfcSJiaxun Yang #include "qemu/log.h" 16b4a12dfcSJiaxun Yang #include "exec/address-spaces.h" 172465c89fSBibo Mao #include "exec/memory.h" 18b4a12dfcSJiaxun Yang #include "migration/vmstate.h" 1991d0b151SJiaxun Yang #ifdef TARGET_LOONGARCH64 20b4a12dfcSJiaxun Yang #include "target/loongarch/cpu.h" 2191d0b151SJiaxun Yang #endif 2291d0b151SJiaxun Yang #ifdef TARGET_MIPS 2391d0b151SJiaxun Yang #include "target/mips/cpu.h" 2491d0b151SJiaxun Yang #endif 25b4a12dfcSJiaxun Yang #include "trace.h" 26b4a12dfcSJiaxun Yang 2749eba52aSJiaxun Yang static MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, 28b4a12dfcSJiaxun Yang uint64_t *data, 29b4a12dfcSJiaxun Yang unsigned size, MemTxAttrs attrs) 30b4a12dfcSJiaxun Yang { 3149eba52aSJiaxun Yang IPICore *s = opaque; 32b4a12dfcSJiaxun Yang uint64_t ret = 0; 33b4a12dfcSJiaxun Yang int index = 0; 34b4a12dfcSJiaxun Yang 35b4a12dfcSJiaxun Yang addr &= 0xff; 36b4a12dfcSJiaxun Yang switch (addr) { 37b4a12dfcSJiaxun Yang case CORE_STATUS_OFF: 38b4a12dfcSJiaxun Yang ret = s->status; 39b4a12dfcSJiaxun Yang break; 40b4a12dfcSJiaxun Yang case CORE_EN_OFF: 41b4a12dfcSJiaxun Yang ret = s->en; 42b4a12dfcSJiaxun Yang break; 43b4a12dfcSJiaxun Yang case CORE_SET_OFF: 44b4a12dfcSJiaxun Yang ret = 0; 45b4a12dfcSJiaxun Yang break; 46b4a12dfcSJiaxun Yang case CORE_CLEAR_OFF: 47b4a12dfcSJiaxun Yang ret = 0; 48b4a12dfcSJiaxun Yang break; 49b4a12dfcSJiaxun Yang case CORE_BUF_20 ... CORE_BUF_38 + 4: 50b4a12dfcSJiaxun Yang index = (addr - CORE_BUF_20) >> 2; 51b4a12dfcSJiaxun Yang ret = s->buf[index]; 52b4a12dfcSJiaxun Yang break; 53b4a12dfcSJiaxun Yang default: 54b4a12dfcSJiaxun Yang qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr); 55b4a12dfcSJiaxun Yang break; 56b4a12dfcSJiaxun Yang } 57b4a12dfcSJiaxun Yang 58b4a12dfcSJiaxun Yang trace_loongson_ipi_read(size, (uint64_t)addr, ret); 59b4a12dfcSJiaxun Yang *data = ret; 60b4a12dfcSJiaxun Yang return MEMTX_OK; 61b4a12dfcSJiaxun Yang } 62b4a12dfcSJiaxun Yang 6349eba52aSJiaxun Yang static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr, 6449eba52aSJiaxun Yang uint64_t *data, 6549eba52aSJiaxun Yang unsigned size, MemTxAttrs attrs) 6649eba52aSJiaxun Yang { 676c8698a5SBibo Mao LoongsonIPICommonState *ipi = opaque; 6849eba52aSJiaxun Yang IPICore *s; 6949eba52aSJiaxun Yang 7049eba52aSJiaxun Yang if (attrs.requester_id >= ipi->num_cpu) { 7149eba52aSJiaxun Yang return MEMTX_DECODE_ERROR; 7249eba52aSJiaxun Yang } 7349eba52aSJiaxun Yang 7449eba52aSJiaxun Yang s = &ipi->cpu[attrs.requester_id]; 7549eba52aSJiaxun Yang return loongson_ipi_core_readl(s, addr, data, size, attrs); 7649eba52aSJiaxun Yang } 7749eba52aSJiaxun Yang 7891d0b151SJiaxun Yang #ifdef TARGET_LOONGARCH64 79*a81cd679SBibo Mao static AddressSpace *get_iocsr_as(CPUState *cpu) 80*a81cd679SBibo Mao { 8191d0b151SJiaxun Yang return LOONGARCH_CPU(cpu)->env.address_space_iocsr; 82*a81cd679SBibo Mao } 8391d0b151SJiaxun Yang #endif 84*a81cd679SBibo Mao 8591d0b151SJiaxun Yang #ifdef TARGET_MIPS 86*a81cd679SBibo Mao static AddressSpace *get_iocsr_as(CPUState *cpu) 87*a81cd679SBibo Mao { 8891d0b151SJiaxun Yang if (ase_lcsr_available(&MIPS_CPU(cpu)->env)) { 8991d0b151SJiaxun Yang return &MIPS_CPU(cpu)->env.iocsr.as; 9091d0b151SJiaxun Yang } 91*a81cd679SBibo Mao 9291d0b151SJiaxun Yang return NULL; 9391d0b151SJiaxun Yang } 94*a81cd679SBibo Mao #endif 9591d0b151SJiaxun Yang 96ed722e0eSBibo Mao static MemTxResult send_ipi_data(LoongsonIPICommonState *ipi, CPUState *cpu, 97ed722e0eSBibo Mao uint64_t val, hwaddr addr, MemTxAttrs attrs) 98b4a12dfcSJiaxun Yang { 99*a81cd679SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi); 100b4a12dfcSJiaxun Yang int i, mask = 0, data = 0; 101*a81cd679SBibo Mao AddressSpace *iocsr_as = licc->get_iocsr_as(cpu); 10291d0b151SJiaxun Yang 10391d0b151SJiaxun Yang if (!iocsr_as) { 10491d0b151SJiaxun Yang return MEMTX_DECODE_ERROR; 10591d0b151SJiaxun Yang } 106b4a12dfcSJiaxun Yang 107b4a12dfcSJiaxun Yang /* 108b4a12dfcSJiaxun Yang * bit 27-30 is mask for byte writing, 109b4a12dfcSJiaxun Yang * if the mask is 0, we need not to do anything. 110b4a12dfcSJiaxun Yang */ 111b4a12dfcSJiaxun Yang if ((val >> 27) & 0xf) { 1122465c89fSBibo Mao data = address_space_ldl_le(iocsr_as, addr, attrs, NULL); 113b4a12dfcSJiaxun Yang for (i = 0; i < 4; i++) { 114b4a12dfcSJiaxun Yang /* get mask for byte writing */ 115b4a12dfcSJiaxun Yang if (val & (0x1 << (27 + i))) { 116b4a12dfcSJiaxun Yang mask |= 0xff << (i * 8); 117b4a12dfcSJiaxun Yang } 118b4a12dfcSJiaxun Yang } 119b4a12dfcSJiaxun Yang } 120b4a12dfcSJiaxun Yang 121b4a12dfcSJiaxun Yang data &= mask; 122b4a12dfcSJiaxun Yang data |= (val >> 32) & ~mask; 1232465c89fSBibo Mao address_space_stl_le(iocsr_as, addr, data, attrs, NULL); 12491d0b151SJiaxun Yang 12591d0b151SJiaxun Yang return MEMTX_OK; 126b4a12dfcSJiaxun Yang } 127b4a12dfcSJiaxun Yang 128ed722e0eSBibo Mao static MemTxResult mail_send(LoongsonIPICommonState *ipi, 129ed722e0eSBibo Mao uint64_t val, MemTxAttrs attrs) 130b4a12dfcSJiaxun Yang { 131b4a12dfcSJiaxun Yang uint32_t cpuid; 132b4a12dfcSJiaxun Yang hwaddr addr; 133b4a12dfcSJiaxun Yang CPUState *cs; 134b4a12dfcSJiaxun Yang 135b4a12dfcSJiaxun Yang cpuid = extract32(val, 16, 10); 13603ca348bSJiaxun Yang cs = cpu_by_arch_id(cpuid); 137b4a12dfcSJiaxun Yang if (cs == NULL) { 138b4a12dfcSJiaxun Yang return MEMTX_DECODE_ERROR; 139b4a12dfcSJiaxun Yang } 140b4a12dfcSJiaxun Yang 141b4a12dfcSJiaxun Yang /* override requester_id */ 142b4a12dfcSJiaxun Yang addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c); 143b4a12dfcSJiaxun Yang attrs.requester_id = cs->cpu_index; 144ed722e0eSBibo Mao return send_ipi_data(ipi, cs, val, addr, attrs); 145b4a12dfcSJiaxun Yang } 146b4a12dfcSJiaxun Yang 147ed722e0eSBibo Mao static MemTxResult any_send(LoongsonIPICommonState *ipi, 148ed722e0eSBibo Mao uint64_t val, MemTxAttrs attrs) 149b4a12dfcSJiaxun Yang { 150b4a12dfcSJiaxun Yang uint32_t cpuid; 151b4a12dfcSJiaxun Yang hwaddr addr; 152b4a12dfcSJiaxun Yang CPUState *cs; 153b4a12dfcSJiaxun Yang 154b4a12dfcSJiaxun Yang cpuid = extract32(val, 16, 10); 15503ca348bSJiaxun Yang cs = cpu_by_arch_id(cpuid); 156b4a12dfcSJiaxun Yang if (cs == NULL) { 157b4a12dfcSJiaxun Yang return MEMTX_DECODE_ERROR; 158b4a12dfcSJiaxun Yang } 159b4a12dfcSJiaxun Yang 160b4a12dfcSJiaxun Yang /* override requester_id */ 161b4a12dfcSJiaxun Yang addr = val & 0xffff; 162b4a12dfcSJiaxun Yang attrs.requester_id = cs->cpu_index; 163ed722e0eSBibo Mao return send_ipi_data(ipi, cs, val, addr, attrs); 164b4a12dfcSJiaxun Yang } 165b4a12dfcSJiaxun Yang 16649eba52aSJiaxun Yang static MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, 16749eba52aSJiaxun Yang uint64_t val, unsigned size, 16849eba52aSJiaxun Yang MemTxAttrs attrs) 169b4a12dfcSJiaxun Yang { 17049eba52aSJiaxun Yang IPICore *s = opaque; 1716c8698a5SBibo Mao LoongsonIPICommonState *ipi = s->ipi; 172b4a12dfcSJiaxun Yang int index = 0; 173b4a12dfcSJiaxun Yang uint32_t cpuid; 174b4a12dfcSJiaxun Yang uint8_t vector; 175b4a12dfcSJiaxun Yang CPUState *cs; 176b4a12dfcSJiaxun Yang 177b4a12dfcSJiaxun Yang addr &= 0xff; 178b4a12dfcSJiaxun Yang trace_loongson_ipi_write(size, (uint64_t)addr, val); 179b4a12dfcSJiaxun Yang switch (addr) { 180b4a12dfcSJiaxun Yang case CORE_STATUS_OFF: 181b4a12dfcSJiaxun Yang qemu_log_mask(LOG_GUEST_ERROR, "can not be written"); 182b4a12dfcSJiaxun Yang break; 183b4a12dfcSJiaxun Yang case CORE_EN_OFF: 184b4a12dfcSJiaxun Yang s->en = val; 185b4a12dfcSJiaxun Yang break; 186b4a12dfcSJiaxun Yang case CORE_SET_OFF: 187b4a12dfcSJiaxun Yang s->status |= val; 188b4a12dfcSJiaxun Yang if (s->status != 0 && (s->status & s->en) != 0) { 189b4a12dfcSJiaxun Yang qemu_irq_raise(s->irq); 190b4a12dfcSJiaxun Yang } 191b4a12dfcSJiaxun Yang break; 192b4a12dfcSJiaxun Yang case CORE_CLEAR_OFF: 193b4a12dfcSJiaxun Yang s->status &= ~val; 194b4a12dfcSJiaxun Yang if (s->status == 0 && s->en != 0) { 195b4a12dfcSJiaxun Yang qemu_irq_lower(s->irq); 196b4a12dfcSJiaxun Yang } 197b4a12dfcSJiaxun Yang break; 198b4a12dfcSJiaxun Yang case CORE_BUF_20 ... CORE_BUF_38 + 4: 199b4a12dfcSJiaxun Yang index = (addr - CORE_BUF_20) >> 2; 200b4a12dfcSJiaxun Yang s->buf[index] = val; 201b4a12dfcSJiaxun Yang break; 202b4a12dfcSJiaxun Yang case IOCSR_IPI_SEND: 203b4a12dfcSJiaxun Yang cpuid = extract32(val, 16, 10); 204b4a12dfcSJiaxun Yang /* IPI status vector */ 205b4a12dfcSJiaxun Yang vector = extract8(val, 0, 5); 20603ca348bSJiaxun Yang cs = cpu_by_arch_id(cpuid); 20749eba52aSJiaxun Yang if (cs == NULL || cs->cpu_index >= ipi->num_cpu) { 208b4a12dfcSJiaxun Yang return MEMTX_DECODE_ERROR; 209b4a12dfcSJiaxun Yang } 21049eba52aSJiaxun Yang loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], CORE_SET_OFF, 21149eba52aSJiaxun Yang BIT(vector), 4, attrs); 212b4a12dfcSJiaxun Yang break; 213b4a12dfcSJiaxun Yang default: 214b4a12dfcSJiaxun Yang qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr); 215b4a12dfcSJiaxun Yang break; 216b4a12dfcSJiaxun Yang } 217b4a12dfcSJiaxun Yang 218b4a12dfcSJiaxun Yang return MEMTX_OK; 219b4a12dfcSJiaxun Yang } 220b4a12dfcSJiaxun Yang 22149eba52aSJiaxun Yang static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr, 22249eba52aSJiaxun Yang uint64_t val, unsigned size, 22349eba52aSJiaxun Yang MemTxAttrs attrs) 22449eba52aSJiaxun Yang { 2256c8698a5SBibo Mao LoongsonIPICommonState *ipi = opaque; 22649eba52aSJiaxun Yang IPICore *s; 22749eba52aSJiaxun Yang 22849eba52aSJiaxun Yang if (attrs.requester_id >= ipi->num_cpu) { 22949eba52aSJiaxun Yang return MEMTX_DECODE_ERROR; 23049eba52aSJiaxun Yang } 23149eba52aSJiaxun Yang 23249eba52aSJiaxun Yang s = &ipi->cpu[attrs.requester_id]; 23349eba52aSJiaxun Yang return loongson_ipi_core_writel(s, addr, val, size, attrs); 23449eba52aSJiaxun Yang } 23549eba52aSJiaxun Yang 23649eba52aSJiaxun Yang static const MemoryRegionOps loongson_ipi_core_ops = { 23749eba52aSJiaxun Yang .read_with_attrs = loongson_ipi_core_readl, 23849eba52aSJiaxun Yang .write_with_attrs = loongson_ipi_core_writel, 23949eba52aSJiaxun Yang .impl.min_access_size = 4, 24049eba52aSJiaxun Yang .impl.max_access_size = 4, 24149eba52aSJiaxun Yang .valid.min_access_size = 4, 24249eba52aSJiaxun Yang .valid.max_access_size = 8, 24349eba52aSJiaxun Yang .endianness = DEVICE_LITTLE_ENDIAN, 24449eba52aSJiaxun Yang }; 24549eba52aSJiaxun Yang 24649eba52aSJiaxun Yang static const MemoryRegionOps loongson_ipi_iocsr_ops = { 24749eba52aSJiaxun Yang .read_with_attrs = loongson_ipi_iocsr_readl, 24849eba52aSJiaxun Yang .write_with_attrs = loongson_ipi_iocsr_writel, 249b4a12dfcSJiaxun Yang .impl.min_access_size = 4, 250b4a12dfcSJiaxun Yang .impl.max_access_size = 4, 251b4a12dfcSJiaxun Yang .valid.min_access_size = 4, 252b4a12dfcSJiaxun Yang .valid.max_access_size = 8, 253b4a12dfcSJiaxun Yang .endianness = DEVICE_LITTLE_ENDIAN, 254b4a12dfcSJiaxun Yang }; 255b4a12dfcSJiaxun Yang 256b4a12dfcSJiaxun Yang /* mail send and any send only support writeq */ 257b4a12dfcSJiaxun Yang static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, uint64_t val, 258b4a12dfcSJiaxun Yang unsigned size, MemTxAttrs attrs) 259b4a12dfcSJiaxun Yang { 260ed722e0eSBibo Mao LoongsonIPICommonState *ipi = opaque; 261b4a12dfcSJiaxun Yang MemTxResult ret = MEMTX_OK; 262b4a12dfcSJiaxun Yang 263b4a12dfcSJiaxun Yang addr &= 0xfff; 264b4a12dfcSJiaxun Yang switch (addr) { 265b4a12dfcSJiaxun Yang case MAIL_SEND_OFFSET: 266ed722e0eSBibo Mao ret = mail_send(ipi, val, attrs); 267b4a12dfcSJiaxun Yang break; 268b4a12dfcSJiaxun Yang case ANY_SEND_OFFSET: 269ed722e0eSBibo Mao ret = any_send(ipi, val, attrs); 270b4a12dfcSJiaxun Yang break; 271b4a12dfcSJiaxun Yang default: 272b4a12dfcSJiaxun Yang break; 273b4a12dfcSJiaxun Yang } 274b4a12dfcSJiaxun Yang 275b4a12dfcSJiaxun Yang return ret; 276b4a12dfcSJiaxun Yang } 277b4a12dfcSJiaxun Yang 278b4a12dfcSJiaxun Yang static const MemoryRegionOps loongson_ipi64_ops = { 279b4a12dfcSJiaxun Yang .write_with_attrs = loongson_ipi_writeq, 280b4a12dfcSJiaxun Yang .impl.min_access_size = 8, 281b4a12dfcSJiaxun Yang .impl.max_access_size = 8, 282b4a12dfcSJiaxun Yang .valid.min_access_size = 8, 283b4a12dfcSJiaxun Yang .valid.max_access_size = 8, 284b4a12dfcSJiaxun Yang .endianness = DEVICE_LITTLE_ENDIAN, 285b4a12dfcSJiaxun Yang }; 286b4a12dfcSJiaxun Yang 287530e6dafSBibo Mao static void loongson_ipi_common_realize(DeviceState *dev, Error **errp) 288b4a12dfcSJiaxun Yang { 2896c8698a5SBibo Mao LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev); 290b4a12dfcSJiaxun Yang SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 291b4a12dfcSJiaxun Yang int i; 292b4a12dfcSJiaxun Yang 293b4a12dfcSJiaxun Yang if (s->num_cpu == 0) { 294b4a12dfcSJiaxun Yang error_setg(errp, "num-cpu must be at least 1"); 295b4a12dfcSJiaxun Yang return; 296b4a12dfcSJiaxun Yang } 297b4a12dfcSJiaxun Yang 29849eba52aSJiaxun Yang memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev), 29949eba52aSJiaxun Yang &loongson_ipi_iocsr_ops, 300b4a12dfcSJiaxun Yang s, "loongson_ipi_iocsr", 0x48); 301b4a12dfcSJiaxun Yang 302b4a12dfcSJiaxun Yang /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */ 303b4a12dfcSJiaxun Yang s->ipi_iocsr_mem.disable_reentrancy_guard = true; 304b4a12dfcSJiaxun Yang 305b4a12dfcSJiaxun Yang sysbus_init_mmio(sbd, &s->ipi_iocsr_mem); 306b4a12dfcSJiaxun Yang 307b4a12dfcSJiaxun Yang memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev), 308b4a12dfcSJiaxun Yang &loongson_ipi64_ops, 309b4a12dfcSJiaxun Yang s, "loongson_ipi64_iocsr", 0x118); 310b4a12dfcSJiaxun Yang sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem); 311b4a12dfcSJiaxun Yang 312b4a12dfcSJiaxun Yang s->cpu = g_new0(IPICore, s->num_cpu); 313b4a12dfcSJiaxun Yang for (i = 0; i < s->num_cpu; i++) { 31449eba52aSJiaxun Yang s->cpu[i].ipi = s; 31549eba52aSJiaxun Yang 316b4a12dfcSJiaxun Yang qdev_init_gpio_out(dev, &s->cpu[i].irq, 1); 317b4a12dfcSJiaxun Yang } 318b4a12dfcSJiaxun Yang } 319b4a12dfcSJiaxun Yang 320530e6dafSBibo Mao static void loongson_ipi_realize(DeviceState *dev, Error **errp) 321530e6dafSBibo Mao { 3226c8698a5SBibo Mao LoongsonIPICommonState *sc = LOONGSON_IPI_COMMON(dev); 323530e6dafSBibo Mao LoongsonIPIState *s = LOONGSON_IPI(dev); 324530e6dafSBibo Mao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 325530e6dafSBibo Mao Error *local_err = NULL; 326530e6dafSBibo Mao 327530e6dafSBibo Mao loongson_ipi_common_realize(dev, &local_err); 328530e6dafSBibo Mao if (local_err) { 329530e6dafSBibo Mao error_propagate(errp, local_err); 330530e6dafSBibo Mao return; 331530e6dafSBibo Mao } 332530e6dafSBibo Mao 3336c8698a5SBibo Mao s->ipi_mmio_mem = g_new0(MemoryRegion, sc->num_cpu); 3346c8698a5SBibo Mao for (unsigned i = 0; i < sc->num_cpu; i++) { 335530e6dafSBibo Mao g_autofree char *name = g_strdup_printf("loongson_ipi_cpu%d_mmio", i); 3366c8698a5SBibo Mao 337a022e0deSBibo Mao memory_region_init_io(&s->ipi_mmio_mem[i], OBJECT(dev), 3386c8698a5SBibo Mao &loongson_ipi_core_ops, &sc->cpu[i], name, 0x48); 339a022e0deSBibo Mao sysbus_init_mmio(sbd, &s->ipi_mmio_mem[i]); 340530e6dafSBibo Mao } 341530e6dafSBibo Mao } 342530e6dafSBibo Mao 343530e6dafSBibo Mao static void loongson_ipi_common_unrealize(DeviceState *dev) 3440c2086bcSPhilippe Mathieu-Daudé { 3456c8698a5SBibo Mao LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev); 3460c2086bcSPhilippe Mathieu-Daudé 3470c2086bcSPhilippe Mathieu-Daudé g_free(s->cpu); 3480c2086bcSPhilippe Mathieu-Daudé } 3490c2086bcSPhilippe Mathieu-Daudé 350530e6dafSBibo Mao static void loongson_ipi_unrealize(DeviceState *dev) 351530e6dafSBibo Mao { 352a022e0deSBibo Mao LoongsonIPIState *s = LOONGSON_IPI(dev); 353a022e0deSBibo Mao 354a022e0deSBibo Mao g_free(s->ipi_mmio_mem); 355a022e0deSBibo Mao 356530e6dafSBibo Mao loongson_ipi_common_unrealize(dev); 357530e6dafSBibo Mao } 358530e6dafSBibo Mao 359b4a12dfcSJiaxun Yang static void loongson_ipi_class_init(ObjectClass *klass, void *data) 360b4a12dfcSJiaxun Yang { 361b4a12dfcSJiaxun Yang DeviceClass *dc = DEVICE_CLASS(klass); 3627e555781SBibo Mao LoongsonIPIClass *lic = LOONGSON_IPI_CLASS(klass); 363*a81cd679SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); 364b4a12dfcSJiaxun Yang 3657e555781SBibo Mao device_class_set_parent_realize(dc, loongson_ipi_realize, 3667e555781SBibo Mao &lic->parent_realize); 3677e555781SBibo Mao device_class_set_parent_unrealize(dc, loongson_ipi_unrealize, 3687e555781SBibo Mao &lic->parent_unrealize); 369*a81cd679SBibo Mao licc->get_iocsr_as = get_iocsr_as; 370b4a12dfcSJiaxun Yang } 371b4a12dfcSJiaxun Yang 37213e8ec6cSPhilippe Mathieu-Daudé static const TypeInfo loongson_ipi_types[] = { 37313e8ec6cSPhilippe Mathieu-Daudé { 374b4a12dfcSJiaxun Yang .name = TYPE_LOONGSON_IPI, 3757e555781SBibo Mao .parent = TYPE_LOONGSON_IPI_COMMON, 37640a0815eSBibo Mao .instance_size = sizeof(LoongsonIPIState), 3777e555781SBibo Mao .class_size = sizeof(LoongsonIPIClass), 378b4a12dfcSJiaxun Yang .class_init = loongson_ipi_class_init, 37913e8ec6cSPhilippe Mathieu-Daudé } 380b4a12dfcSJiaxun Yang }; 381b4a12dfcSJiaxun Yang 38213e8ec6cSPhilippe Mathieu-Daudé DEFINE_TYPES(loongson_ipi_types) 383