1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * LoongArch ipi interrupt support 4 * 5 * Copyright (C) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "hw/sysbus.h" 10 #include "hw/intc/loongarch_ipi.h" 11 #include "hw/irq.h" 12 #include "qapi/error.h" 13 #include "qemu/log.h" 14 #include "exec/address-spaces.h" 15 #include "hw/loongarch/virt.h" 16 #include "migration/vmstate.h" 17 #include "target/loongarch/internals.h" 18 #include "trace.h" 19 20 static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size) 21 { 22 IPICore *s = opaque; 23 uint64_t ret = 0; 24 int index = 0; 25 26 addr &= 0xff; 27 switch (addr) { 28 case CORE_STATUS_OFF: 29 ret = s->status; 30 break; 31 case CORE_EN_OFF: 32 ret = s->en; 33 break; 34 case CORE_SET_OFF: 35 ret = 0; 36 break; 37 case CORE_CLEAR_OFF: 38 ret = 0; 39 break; 40 case CORE_BUF_20 ... CORE_BUF_38 + 4: 41 index = (addr - CORE_BUF_20) >> 2; 42 ret = s->buf[index]; 43 break; 44 default: 45 qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr); 46 break; 47 } 48 49 trace_loongarch_ipi_read(size, (uint64_t)addr, ret); 50 return ret; 51 } 52 53 static int get_ipi_data(target_ulong val) 54 { 55 int i, mask, data; 56 57 data = val >> 32; 58 mask = (val >> 27) & 0xf; 59 60 for (i = 0; i < 4; i++) { 61 if ((mask >> i) & 1) { 62 data &= ~(0xff << (i * 8)); 63 } 64 } 65 return data; 66 } 67 68 static void ipi_send(uint64_t val) 69 { 70 int cpuid, data; 71 CPULoongArchState *env; 72 73 cpuid = (val >> 16) & 0x3ff; 74 /* IPI status vector */ 75 data = 1 << (val & 0x1f); 76 qemu_mutex_lock_iothread(); 77 CPUState *cs = qemu_get_cpu(cpuid); 78 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 79 env = &cpu->env; 80 loongarch_cpu_set_irq(cpu, IRQ_IPI, 1); 81 qemu_mutex_unlock_iothread(); 82 address_space_stl(&env->address_space_iocsr, 0x1008, 83 data, MEMTXATTRS_UNSPECIFIED, NULL); 84 85 } 86 87 static void mail_send(uint64_t val) 88 { 89 int cpuid, data; 90 hwaddr addr; 91 CPULoongArchState *env; 92 93 cpuid = (val >> 16) & 0x3ff; 94 addr = 0x1020 + (val & 0x1c); 95 CPUState *cs = qemu_get_cpu(cpuid); 96 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 97 env = &cpu->env; 98 data = get_ipi_data(val); 99 address_space_stl(&env->address_space_iocsr, addr, 100 data, MEMTXATTRS_UNSPECIFIED, NULL); 101 } 102 103 static void any_send(uint64_t val) 104 { 105 int cpuid, data; 106 hwaddr addr; 107 CPULoongArchState *env; 108 109 cpuid = (val >> 16) & 0x3ff; 110 addr = val & 0xffff; 111 CPUState *cs = qemu_get_cpu(cpuid); 112 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 113 env = &cpu->env; 114 data = get_ipi_data(val); 115 address_space_stl(&env->address_space_iocsr, addr, 116 data, MEMTXATTRS_UNSPECIFIED, NULL); 117 } 118 119 static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val, 120 unsigned size) 121 { 122 IPICore *s = opaque; 123 int index = 0; 124 125 addr &= 0xff; 126 trace_loongarch_ipi_write(size, (uint64_t)addr, val); 127 switch (addr) { 128 case CORE_STATUS_OFF: 129 qemu_log_mask(LOG_GUEST_ERROR, "can not be written"); 130 break; 131 case CORE_EN_OFF: 132 s->en = val; 133 break; 134 case CORE_SET_OFF: 135 s->status |= val; 136 if (s->status != 0 && (s->status & s->en) != 0) { 137 qemu_irq_raise(s->irq); 138 } 139 break; 140 case CORE_CLEAR_OFF: 141 s->status &= ~val; 142 if (s->status == 0 && s->en != 0) { 143 qemu_irq_lower(s->irq); 144 } 145 break; 146 case CORE_BUF_20 ... CORE_BUF_38 + 4: 147 index = (addr - CORE_BUF_20) >> 2; 148 s->buf[index] = val; 149 break; 150 case IOCSR_IPI_SEND: 151 ipi_send(val); 152 break; 153 case IOCSR_MAIL_SEND: 154 mail_send(val); 155 break; 156 case IOCSR_ANY_SEND: 157 any_send(val); 158 break; 159 default: 160 qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr); 161 break; 162 } 163 } 164 165 static const MemoryRegionOps loongarch_ipi_ops = { 166 .read = loongarch_ipi_readl, 167 .write = loongarch_ipi_writel, 168 .impl.min_access_size = 4, 169 .impl.max_access_size = 4, 170 .valid.min_access_size = 4, 171 .valid.max_access_size = 8, 172 .endianness = DEVICE_LITTLE_ENDIAN, 173 }; 174 175 static void loongarch_ipi_init(Object *obj) 176 { 177 int cpu; 178 LoongArchMachineState *lams; 179 LoongArchIPI *s = LOONGARCH_IPI(obj); 180 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 181 Object *machine = qdev_get_machine(); 182 ObjectClass *mc = object_get_class(machine); 183 /* 'lams' should be initialized */ 184 if (!strcmp(MACHINE_CLASS(mc)->name, "none")) { 185 return; 186 } 187 lams = LOONGARCH_MACHINE(machine); 188 for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) { 189 memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops, 190 &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x100); 191 sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]); 192 qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1); 193 } 194 } 195 196 static const VMStateDescription vmstate_ipi_core = { 197 .name = "ipi-single", 198 .version_id = 0, 199 .minimum_version_id = 0, 200 .fields = (VMStateField[]) { 201 VMSTATE_UINT32(status, IPICore), 202 VMSTATE_UINT32(en, IPICore), 203 VMSTATE_UINT32(set, IPICore), 204 VMSTATE_UINT32(clear, IPICore), 205 VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2), 206 VMSTATE_END_OF_LIST() 207 } 208 }; 209 210 static const VMStateDescription vmstate_loongarch_ipi = { 211 .name = TYPE_LOONGARCH_IPI, 212 .version_id = 0, 213 .minimum_version_id = 0, 214 .fields = (VMStateField[]) { 215 VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState, 216 MAX_IPI_CORE_NUM, 0, 217 vmstate_ipi_core, IPICore), 218 VMSTATE_END_OF_LIST() 219 } 220 }; 221 222 static void loongarch_ipi_class_init(ObjectClass *klass, void *data) 223 { 224 DeviceClass *dc = DEVICE_CLASS(klass); 225 226 dc->vmsd = &vmstate_loongarch_ipi; 227 } 228 229 static const TypeInfo loongarch_ipi_info = { 230 .name = TYPE_LOONGARCH_IPI, 231 .parent = TYPE_SYS_BUS_DEVICE, 232 .instance_size = sizeof(LoongArchIPI), 233 .instance_init = loongarch_ipi_init, 234 .class_init = loongarch_ipi_class_init, 235 }; 236 237 static void loongarch_ipi_register_types(void) 238 { 239 type_register_static(&loongarch_ipi_info); 240 } 241 242 type_init(loongarch_ipi_register_types) 243