17e555781SBibo Mao /* SPDX-License-Identifier: GPL-2.0-or-later */ 27e555781SBibo Mao /* 37e555781SBibo Mao * Loongson IPI interrupt common support 47e555781SBibo Mao * 57e555781SBibo Mao * Copyright (C) 2021 Loongson Technology Corporation Limited 67e555781SBibo Mao */ 77e555781SBibo Mao 87e555781SBibo Mao #include "qemu/osdep.h" 97e555781SBibo Mao #include "hw/sysbus.h" 107e555781SBibo Mao #include "hw/intc/loongson_ipi_common.h" 11ec859557SBibo Mao #include "hw/irq.h" 12ec859557SBibo Mao #include "qemu/log.h" 136c8698a5SBibo Mao #include "migration/vmstate.h" 14ec859557SBibo Mao #include "trace.h" 15ec859557SBibo Mao 16ec859557SBibo Mao MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data, 17ec859557SBibo Mao unsigned size, MemTxAttrs attrs) 18ec859557SBibo Mao { 19ec859557SBibo Mao IPICore *s = opaque; 20ec859557SBibo Mao uint64_t ret = 0; 21ec859557SBibo Mao int index = 0; 22ec859557SBibo Mao 23ec859557SBibo Mao addr &= 0xff; 24ec859557SBibo Mao switch (addr) { 25ec859557SBibo Mao case CORE_STATUS_OFF: 26ec859557SBibo Mao ret = s->status; 27ec859557SBibo Mao break; 28ec859557SBibo Mao case CORE_EN_OFF: 29ec859557SBibo Mao ret = s->en; 30ec859557SBibo Mao break; 31ec859557SBibo Mao case CORE_SET_OFF: 32ec859557SBibo Mao ret = 0; 33ec859557SBibo Mao break; 34ec859557SBibo Mao case CORE_CLEAR_OFF: 35ec859557SBibo Mao ret = 0; 36ec859557SBibo Mao break; 37ec859557SBibo Mao case CORE_BUF_20 ... CORE_BUF_38 + 4: 38ec859557SBibo Mao index = (addr - CORE_BUF_20) >> 2; 39ec859557SBibo Mao ret = s->buf[index]; 40ec859557SBibo Mao break; 41ec859557SBibo Mao default: 42ec859557SBibo Mao qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr); 43ec859557SBibo Mao break; 44ec859557SBibo Mao } 45ec859557SBibo Mao 46ec859557SBibo Mao trace_loongson_ipi_read(size, (uint64_t)addr, ret); 47ec859557SBibo Mao *data = ret; 48ec859557SBibo Mao 49ec859557SBibo Mao return MEMTX_OK; 50ec859557SBibo Mao } 51ec859557SBibo Mao 52ec859557SBibo Mao static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr, 53ec859557SBibo Mao uint64_t *data, unsigned size, 54ec859557SBibo Mao MemTxAttrs attrs) 55ec859557SBibo Mao { 56ec859557SBibo Mao LoongsonIPICommonState *ipi = opaque; 57ec859557SBibo Mao IPICore *s; 58ec859557SBibo Mao 59ec859557SBibo Mao if (attrs.requester_id >= ipi->num_cpu) { 60ec859557SBibo Mao return MEMTX_DECODE_ERROR; 61ec859557SBibo Mao } 62ec859557SBibo Mao 63ec859557SBibo Mao s = &ipi->cpu[attrs.requester_id]; 64ec859557SBibo Mao return loongson_ipi_core_readl(s, addr, data, size, attrs); 65ec859557SBibo Mao } 66ec859557SBibo Mao 67ec859557SBibo Mao static MemTxResult send_ipi_data(LoongsonIPICommonState *ipi, CPUState *cpu, 68ec859557SBibo Mao uint64_t val, hwaddr addr, MemTxAttrs attrs) 69ec859557SBibo Mao { 70ec859557SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi); 71ec859557SBibo Mao int i, mask = 0, data = 0; 72ec859557SBibo Mao AddressSpace *iocsr_as = licc->get_iocsr_as(cpu); 73ec859557SBibo Mao 74ec859557SBibo Mao if (!iocsr_as) { 75ec859557SBibo Mao return MEMTX_DECODE_ERROR; 76ec859557SBibo Mao } 77ec859557SBibo Mao 78ec859557SBibo Mao /* 79ec859557SBibo Mao * bit 27-30 is mask for byte writing, 80ec859557SBibo Mao * if the mask is 0, we need not to do anything. 81ec859557SBibo Mao */ 82ec859557SBibo Mao if ((val >> 27) & 0xf) { 83ec859557SBibo Mao data = address_space_ldl_le(iocsr_as, addr, attrs, NULL); 84ec859557SBibo Mao for (i = 0; i < 4; i++) { 85ec859557SBibo Mao /* get mask for byte writing */ 86ec859557SBibo Mao if (val & (0x1 << (27 + i))) { 87ec859557SBibo Mao mask |= 0xff << (i * 8); 88ec859557SBibo Mao } 89ec859557SBibo Mao } 90ec859557SBibo Mao } 91ec859557SBibo Mao 92ec859557SBibo Mao data &= mask; 93ec859557SBibo Mao data |= (val >> 32) & ~mask; 94ec859557SBibo Mao address_space_stl_le(iocsr_as, addr, data, attrs, NULL); 95ec859557SBibo Mao 96ec859557SBibo Mao return MEMTX_OK; 97ec859557SBibo Mao } 98ec859557SBibo Mao 99ec859557SBibo Mao static MemTxResult mail_send(LoongsonIPICommonState *ipi, 100ec859557SBibo Mao uint64_t val, MemTxAttrs attrs) 101ec859557SBibo Mao { 102ec859557SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi); 103ec859557SBibo Mao uint32_t cpuid; 104ec859557SBibo Mao hwaddr addr; 105ec859557SBibo Mao CPUState *cs; 106999b112dSBibo Mao int cpu, ret; 107ec859557SBibo Mao 108ec859557SBibo Mao cpuid = extract32(val, 16, 10); 109999b112dSBibo Mao ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs); 110999b112dSBibo Mao if (ret != MEMTX_OK) { 111ec859557SBibo Mao return MEMTX_DECODE_ERROR; 112ec859557SBibo Mao } 113ec859557SBibo Mao 114ec859557SBibo Mao /* override requester_id */ 115ec859557SBibo Mao addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c); 116999b112dSBibo Mao attrs.requester_id = cpu; 117ec859557SBibo Mao return send_ipi_data(ipi, cs, val, addr, attrs); 118ec859557SBibo Mao } 119ec859557SBibo Mao 120ec859557SBibo Mao static MemTxResult any_send(LoongsonIPICommonState *ipi, 121ec859557SBibo Mao uint64_t val, MemTxAttrs attrs) 122ec859557SBibo Mao { 123ec859557SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi); 124ec859557SBibo Mao uint32_t cpuid; 125ec859557SBibo Mao hwaddr addr; 126ec859557SBibo Mao CPUState *cs; 127999b112dSBibo Mao int cpu, ret; 128ec859557SBibo Mao 129ec859557SBibo Mao cpuid = extract32(val, 16, 10); 130999b112dSBibo Mao ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs); 131999b112dSBibo Mao if (ret != MEMTX_OK) { 132ec859557SBibo Mao return MEMTX_DECODE_ERROR; 133ec859557SBibo Mao } 134ec859557SBibo Mao 135ec859557SBibo Mao /* override requester_id */ 136ec859557SBibo Mao addr = val & 0xffff; 137999b112dSBibo Mao attrs.requester_id = cpu; 138ec859557SBibo Mao return send_ipi_data(ipi, cs, val, addr, attrs); 139ec859557SBibo Mao } 140ec859557SBibo Mao 141ec859557SBibo Mao MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val, 142ec859557SBibo Mao unsigned size, MemTxAttrs attrs) 143ec859557SBibo Mao { 144ec859557SBibo Mao IPICore *s = opaque; 145ec859557SBibo Mao LoongsonIPICommonState *ipi = s->ipi; 146ec859557SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi); 147ec859557SBibo Mao int index = 0; 148ec859557SBibo Mao uint32_t cpuid; 149ec859557SBibo Mao uint8_t vector; 150ec859557SBibo Mao CPUState *cs; 151999b112dSBibo Mao int cpu, ret; 152ec859557SBibo Mao 153ec859557SBibo Mao addr &= 0xff; 154ec859557SBibo Mao trace_loongson_ipi_write(size, (uint64_t)addr, val); 155ec859557SBibo Mao switch (addr) { 156ec859557SBibo Mao case CORE_STATUS_OFF: 157ec859557SBibo Mao qemu_log_mask(LOG_GUEST_ERROR, "can not be written"); 158ec859557SBibo Mao break; 159ec859557SBibo Mao case CORE_EN_OFF: 160ec859557SBibo Mao s->en = val; 161ec859557SBibo Mao break; 162ec859557SBibo Mao case CORE_SET_OFF: 163ec859557SBibo Mao s->status |= val; 164ec859557SBibo Mao if (s->status != 0 && (s->status & s->en) != 0) { 165ec859557SBibo Mao qemu_irq_raise(s->irq); 166ec859557SBibo Mao } 167ec859557SBibo Mao break; 168ec859557SBibo Mao case CORE_CLEAR_OFF: 169ec859557SBibo Mao s->status &= ~val; 170ec859557SBibo Mao if (s->status == 0 && s->en != 0) { 171ec859557SBibo Mao qemu_irq_lower(s->irq); 172ec859557SBibo Mao } 173ec859557SBibo Mao break; 174ec859557SBibo Mao case CORE_BUF_20 ... CORE_BUF_38 + 4: 175ec859557SBibo Mao index = (addr - CORE_BUF_20) >> 2; 176ec859557SBibo Mao s->buf[index] = val; 177ec859557SBibo Mao break; 178ec859557SBibo Mao case IOCSR_IPI_SEND: 179ec859557SBibo Mao cpuid = extract32(val, 16, 10); 180ec859557SBibo Mao /* IPI status vector */ 181ec859557SBibo Mao vector = extract8(val, 0, 5); 182999b112dSBibo Mao ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs); 183999b112dSBibo Mao if (ret != MEMTX_OK || cpu >= ipi->num_cpu) { 184ec859557SBibo Mao return MEMTX_DECODE_ERROR; 185ec859557SBibo Mao } 186999b112dSBibo Mao loongson_ipi_core_writel(&ipi->cpu[cpu], CORE_SET_OFF, 187ec859557SBibo Mao BIT(vector), 4, attrs); 188ec859557SBibo Mao break; 189ec859557SBibo Mao default: 190ec859557SBibo Mao qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr); 191ec859557SBibo Mao break; 192ec859557SBibo Mao } 193ec859557SBibo Mao 194ec859557SBibo Mao return MEMTX_OK; 195ec859557SBibo Mao } 196ec859557SBibo Mao 197ec859557SBibo Mao static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr, 198ec859557SBibo Mao uint64_t val, unsigned size, 199ec859557SBibo Mao MemTxAttrs attrs) 200ec859557SBibo Mao { 201ec859557SBibo Mao LoongsonIPICommonState *ipi = opaque; 202ec859557SBibo Mao IPICore *s; 203ec859557SBibo Mao 204ec859557SBibo Mao if (attrs.requester_id >= ipi->num_cpu) { 205ec859557SBibo Mao return MEMTX_DECODE_ERROR; 206ec859557SBibo Mao } 207ec859557SBibo Mao 208ec859557SBibo Mao s = &ipi->cpu[attrs.requester_id]; 209ec859557SBibo Mao return loongson_ipi_core_writel(s, addr, val, size, attrs); 210ec859557SBibo Mao } 211ec859557SBibo Mao 212ec859557SBibo Mao static const MemoryRegionOps loongson_ipi_iocsr_ops = { 213ec859557SBibo Mao .read_with_attrs = loongson_ipi_iocsr_readl, 214ec859557SBibo Mao .write_with_attrs = loongson_ipi_iocsr_writel, 215ec859557SBibo Mao .impl.min_access_size = 4, 216ec859557SBibo Mao .impl.max_access_size = 4, 217ec859557SBibo Mao .valid.min_access_size = 4, 218ec859557SBibo Mao .valid.max_access_size = 8, 219ec859557SBibo Mao .endianness = DEVICE_LITTLE_ENDIAN, 220ec859557SBibo Mao }; 221ec859557SBibo Mao 222ec859557SBibo Mao /* mail send and any send only support writeq */ 223ec859557SBibo Mao static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, uint64_t val, 224ec859557SBibo Mao unsigned size, MemTxAttrs attrs) 225ec859557SBibo Mao { 226ec859557SBibo Mao LoongsonIPICommonState *ipi = opaque; 227ec859557SBibo Mao MemTxResult ret = MEMTX_OK; 228ec859557SBibo Mao 229ec859557SBibo Mao addr &= 0xfff; 230ec859557SBibo Mao switch (addr) { 231ec859557SBibo Mao case MAIL_SEND_OFFSET: 232ec859557SBibo Mao ret = mail_send(ipi, val, attrs); 233ec859557SBibo Mao break; 234ec859557SBibo Mao case ANY_SEND_OFFSET: 235ec859557SBibo Mao ret = any_send(ipi, val, attrs); 236ec859557SBibo Mao break; 237ec859557SBibo Mao default: 238ec859557SBibo Mao break; 239ec859557SBibo Mao } 240ec859557SBibo Mao 241ec859557SBibo Mao return ret; 242ec859557SBibo Mao } 243ec859557SBibo Mao 244ec859557SBibo Mao static const MemoryRegionOps loongson_ipi64_ops = { 245ec859557SBibo Mao .write_with_attrs = loongson_ipi_writeq, 246ec859557SBibo Mao .impl.min_access_size = 8, 247ec859557SBibo Mao .impl.max_access_size = 8, 248ec859557SBibo Mao .valid.min_access_size = 8, 249ec859557SBibo Mao .valid.max_access_size = 8, 250ec859557SBibo Mao .endianness = DEVICE_LITTLE_ENDIAN, 251ec859557SBibo Mao }; 252ec859557SBibo Mao 253ec859557SBibo Mao static void loongson_ipi_common_realize(DeviceState *dev, Error **errp) 254ec859557SBibo Mao { 255ec859557SBibo Mao LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev); 256ec859557SBibo Mao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 257ec859557SBibo Mao 258ec859557SBibo Mao memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev), 259ec859557SBibo Mao &loongson_ipi_iocsr_ops, 260ec859557SBibo Mao s, "loongson_ipi_iocsr", 0x48); 261ec859557SBibo Mao 262ec859557SBibo Mao /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */ 263ec859557SBibo Mao s->ipi_iocsr_mem.disable_reentrancy_guard = true; 264ec859557SBibo Mao 265ec859557SBibo Mao sysbus_init_mmio(sbd, &s->ipi_iocsr_mem); 266ec859557SBibo Mao 267ec859557SBibo Mao memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev), 268ec859557SBibo Mao &loongson_ipi64_ops, 269ec859557SBibo Mao s, "loongson_ipi64_iocsr", 0x118); 270ec859557SBibo Mao sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem); 271ec859557SBibo Mao } 272ec859557SBibo Mao 273ec859557SBibo Mao static void loongson_ipi_common_unrealize(DeviceState *dev) 274ec859557SBibo Mao { 275ec859557SBibo Mao LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev); 276ec859557SBibo Mao 277ec859557SBibo Mao g_free(s->cpu); 278ec859557SBibo Mao } 2796c8698a5SBibo Mao 2806c8698a5SBibo Mao static const VMStateDescription vmstate_ipi_core = { 2816c8698a5SBibo Mao .name = "ipi-single", 2826c8698a5SBibo Mao .version_id = 2, 2836c8698a5SBibo Mao .minimum_version_id = 2, 2846c8698a5SBibo Mao .fields = (const VMStateField[]) { 2856c8698a5SBibo Mao VMSTATE_UINT32(status, IPICore), 2866c8698a5SBibo Mao VMSTATE_UINT32(en, IPICore), 2876c8698a5SBibo Mao VMSTATE_UINT32(set, IPICore), 2886c8698a5SBibo Mao VMSTATE_UINT32(clear, IPICore), 2896c8698a5SBibo Mao VMSTATE_UINT32_ARRAY(buf, IPICore, IPI_MBX_NUM * 2), 2906c8698a5SBibo Mao VMSTATE_END_OF_LIST() 2916c8698a5SBibo Mao } 2926c8698a5SBibo Mao }; 2936c8698a5SBibo Mao 2946c8698a5SBibo Mao static const VMStateDescription vmstate_loongson_ipi_common = { 2956c8698a5SBibo Mao .name = "loongson_ipi", 2966c8698a5SBibo Mao .version_id = 2, 2976c8698a5SBibo Mao .minimum_version_id = 2, 2986c8698a5SBibo Mao .fields = (const VMStateField[]) { 2996c8698a5SBibo Mao VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongsonIPICommonState, 3006c8698a5SBibo Mao num_cpu, vmstate_ipi_core, 3016c8698a5SBibo Mao IPICore), 3026c8698a5SBibo Mao VMSTATE_END_OF_LIST() 3036c8698a5SBibo Mao } 3046c8698a5SBibo Mao }; 3056c8698a5SBibo Mao 306*12d1a768SPhilippe Mathieu-Daudé static void loongson_ipi_common_class_init(ObjectClass *klass, const void *data) 3076c8698a5SBibo Mao { 3086c8698a5SBibo Mao DeviceClass *dc = DEVICE_CLASS(klass); 309ec859557SBibo Mao LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); 3106c8698a5SBibo Mao 311ec859557SBibo Mao device_class_set_parent_realize(dc, loongson_ipi_common_realize, 312ec859557SBibo Mao &licc->parent_realize); 313ec859557SBibo Mao device_class_set_parent_unrealize(dc, loongson_ipi_common_unrealize, 314ec859557SBibo Mao &licc->parent_unrealize); 3156c8698a5SBibo Mao dc->vmsd = &vmstate_loongson_ipi_common; 3166c8698a5SBibo Mao } 3177e555781SBibo Mao 3187e555781SBibo Mao static const TypeInfo loongarch_ipi_common_types[] = { 3197e555781SBibo Mao { 3207e555781SBibo Mao .name = TYPE_LOONGSON_IPI_COMMON, 3217e555781SBibo Mao .parent = TYPE_SYS_BUS_DEVICE, 3227e555781SBibo Mao .instance_size = sizeof(LoongsonIPICommonState), 3237e555781SBibo Mao .class_size = sizeof(LoongsonIPICommonClass), 3246c8698a5SBibo Mao .class_init = loongson_ipi_common_class_init, 3257e555781SBibo Mao .abstract = true, 3267e555781SBibo Mao } 3277e555781SBibo Mao }; 3287e555781SBibo Mao 3297e555781SBibo Mao DEFINE_TYPES(loongarch_ipi_common_types) 330