xref: /openbmc/qemu/hw/intc/loongson_ipi_common.c (revision ec859557)
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"
11*ec859557SBibo Mao #include "hw/irq.h"
126c8698a5SBibo Mao #include "hw/qdev-properties.h"
13*ec859557SBibo Mao #include "qapi/error.h"
14*ec859557SBibo Mao #include "qemu/log.h"
156c8698a5SBibo Mao #include "migration/vmstate.h"
16*ec859557SBibo Mao #include "trace.h"
17*ec859557SBibo Mao 
loongson_ipi_core_readl(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)18*ec859557SBibo Mao MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
19*ec859557SBibo Mao                                     unsigned size, MemTxAttrs attrs)
20*ec859557SBibo Mao {
21*ec859557SBibo Mao     IPICore *s = opaque;
22*ec859557SBibo Mao     uint64_t ret = 0;
23*ec859557SBibo Mao     int index = 0;
24*ec859557SBibo Mao 
25*ec859557SBibo Mao     addr &= 0xff;
26*ec859557SBibo Mao     switch (addr) {
27*ec859557SBibo Mao     case CORE_STATUS_OFF:
28*ec859557SBibo Mao         ret = s->status;
29*ec859557SBibo Mao         break;
30*ec859557SBibo Mao     case CORE_EN_OFF:
31*ec859557SBibo Mao         ret = s->en;
32*ec859557SBibo Mao         break;
33*ec859557SBibo Mao     case CORE_SET_OFF:
34*ec859557SBibo Mao         ret = 0;
35*ec859557SBibo Mao         break;
36*ec859557SBibo Mao     case CORE_CLEAR_OFF:
37*ec859557SBibo Mao         ret = 0;
38*ec859557SBibo Mao         break;
39*ec859557SBibo Mao     case CORE_BUF_20 ... CORE_BUF_38 + 4:
40*ec859557SBibo Mao         index = (addr - CORE_BUF_20) >> 2;
41*ec859557SBibo Mao         ret = s->buf[index];
42*ec859557SBibo Mao         break;
43*ec859557SBibo Mao     default:
44*ec859557SBibo Mao         qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
45*ec859557SBibo Mao         break;
46*ec859557SBibo Mao     }
47*ec859557SBibo Mao 
48*ec859557SBibo Mao     trace_loongson_ipi_read(size, (uint64_t)addr, ret);
49*ec859557SBibo Mao     *data = ret;
50*ec859557SBibo Mao 
51*ec859557SBibo Mao     return MEMTX_OK;
52*ec859557SBibo Mao }
53*ec859557SBibo Mao 
loongson_ipi_iocsr_readl(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)54*ec859557SBibo Mao static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr,
55*ec859557SBibo Mao                                             uint64_t *data, unsigned size,
56*ec859557SBibo Mao                                             MemTxAttrs attrs)
57*ec859557SBibo Mao {
58*ec859557SBibo Mao     LoongsonIPICommonState *ipi = opaque;
59*ec859557SBibo Mao     IPICore *s;
60*ec859557SBibo Mao 
61*ec859557SBibo Mao     if (attrs.requester_id >= ipi->num_cpu) {
62*ec859557SBibo Mao         return MEMTX_DECODE_ERROR;
63*ec859557SBibo Mao     }
64*ec859557SBibo Mao 
65*ec859557SBibo Mao     s = &ipi->cpu[attrs.requester_id];
66*ec859557SBibo Mao     return loongson_ipi_core_readl(s, addr, data, size, attrs);
67*ec859557SBibo Mao }
68*ec859557SBibo Mao 
send_ipi_data(LoongsonIPICommonState * ipi,CPUState * cpu,uint64_t val,hwaddr addr,MemTxAttrs attrs)69*ec859557SBibo Mao static MemTxResult send_ipi_data(LoongsonIPICommonState *ipi, CPUState *cpu,
70*ec859557SBibo Mao                                  uint64_t val, hwaddr addr, MemTxAttrs attrs)
71*ec859557SBibo Mao {
72*ec859557SBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
73*ec859557SBibo Mao     int i, mask = 0, data = 0;
74*ec859557SBibo Mao     AddressSpace *iocsr_as = licc->get_iocsr_as(cpu);
75*ec859557SBibo Mao 
76*ec859557SBibo Mao     if (!iocsr_as) {
77*ec859557SBibo Mao         return MEMTX_DECODE_ERROR;
78*ec859557SBibo Mao     }
79*ec859557SBibo Mao 
80*ec859557SBibo Mao     /*
81*ec859557SBibo Mao      * bit 27-30 is mask for byte writing,
82*ec859557SBibo Mao      * if the mask is 0, we need not to do anything.
83*ec859557SBibo Mao      */
84*ec859557SBibo Mao     if ((val >> 27) & 0xf) {
85*ec859557SBibo Mao         data = address_space_ldl_le(iocsr_as, addr, attrs, NULL);
86*ec859557SBibo Mao         for (i = 0; i < 4; i++) {
87*ec859557SBibo Mao             /* get mask for byte writing */
88*ec859557SBibo Mao             if (val & (0x1 << (27 + i))) {
89*ec859557SBibo Mao                 mask |= 0xff << (i * 8);
90*ec859557SBibo Mao             }
91*ec859557SBibo Mao         }
92*ec859557SBibo Mao     }
93*ec859557SBibo Mao 
94*ec859557SBibo Mao     data &= mask;
95*ec859557SBibo Mao     data |= (val >> 32) & ~mask;
96*ec859557SBibo Mao     address_space_stl_le(iocsr_as, addr, data, attrs, NULL);
97*ec859557SBibo Mao 
98*ec859557SBibo Mao     return MEMTX_OK;
99*ec859557SBibo Mao }
100*ec859557SBibo Mao 
mail_send(LoongsonIPICommonState * ipi,uint64_t val,MemTxAttrs attrs)101*ec859557SBibo Mao static MemTxResult mail_send(LoongsonIPICommonState *ipi,
102*ec859557SBibo Mao                              uint64_t val, MemTxAttrs attrs)
103*ec859557SBibo Mao {
104*ec859557SBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
105*ec859557SBibo Mao     uint32_t cpuid;
106*ec859557SBibo Mao     hwaddr addr;
107*ec859557SBibo Mao     CPUState *cs;
108*ec859557SBibo Mao 
109*ec859557SBibo Mao     cpuid = extract32(val, 16, 10);
110*ec859557SBibo Mao     cs = licc->cpu_by_arch_id(cpuid);
111*ec859557SBibo Mao     if (cs == NULL) {
112*ec859557SBibo Mao         return MEMTX_DECODE_ERROR;
113*ec859557SBibo Mao     }
114*ec859557SBibo Mao 
115*ec859557SBibo Mao     /* override requester_id */
116*ec859557SBibo Mao     addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
117*ec859557SBibo Mao     attrs.requester_id = cs->cpu_index;
118*ec859557SBibo Mao     return send_ipi_data(ipi, cs, val, addr, attrs);
119*ec859557SBibo Mao }
120*ec859557SBibo Mao 
any_send(LoongsonIPICommonState * ipi,uint64_t val,MemTxAttrs attrs)121*ec859557SBibo Mao static MemTxResult any_send(LoongsonIPICommonState *ipi,
122*ec859557SBibo Mao                             uint64_t val, MemTxAttrs attrs)
123*ec859557SBibo Mao {
124*ec859557SBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
125*ec859557SBibo Mao     uint32_t cpuid;
126*ec859557SBibo Mao     hwaddr addr;
127*ec859557SBibo Mao     CPUState *cs;
128*ec859557SBibo Mao 
129*ec859557SBibo Mao     cpuid = extract32(val, 16, 10);
130*ec859557SBibo Mao     cs = licc->cpu_by_arch_id(cpuid);
131*ec859557SBibo Mao     if (cs == NULL) {
132*ec859557SBibo Mao         return MEMTX_DECODE_ERROR;
133*ec859557SBibo Mao     }
134*ec859557SBibo Mao 
135*ec859557SBibo Mao     /* override requester_id */
136*ec859557SBibo Mao     addr = val & 0xffff;
137*ec859557SBibo Mao     attrs.requester_id = cs->cpu_index;
138*ec859557SBibo Mao     return send_ipi_data(ipi, cs, val, addr, attrs);
139*ec859557SBibo Mao }
140*ec859557SBibo Mao 
loongson_ipi_core_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)141*ec859557SBibo Mao MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val,
142*ec859557SBibo Mao                                      unsigned size, MemTxAttrs attrs)
143*ec859557SBibo Mao {
144*ec859557SBibo Mao     IPICore *s = opaque;
145*ec859557SBibo Mao     LoongsonIPICommonState *ipi = s->ipi;
146*ec859557SBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
147*ec859557SBibo Mao     int index = 0;
148*ec859557SBibo Mao     uint32_t cpuid;
149*ec859557SBibo Mao     uint8_t vector;
150*ec859557SBibo Mao     CPUState *cs;
151*ec859557SBibo Mao 
152*ec859557SBibo Mao     addr &= 0xff;
153*ec859557SBibo Mao     trace_loongson_ipi_write(size, (uint64_t)addr, val);
154*ec859557SBibo Mao     switch (addr) {
155*ec859557SBibo Mao     case CORE_STATUS_OFF:
156*ec859557SBibo Mao         qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
157*ec859557SBibo Mao         break;
158*ec859557SBibo Mao     case CORE_EN_OFF:
159*ec859557SBibo Mao         s->en = val;
160*ec859557SBibo Mao         break;
161*ec859557SBibo Mao     case CORE_SET_OFF:
162*ec859557SBibo Mao         s->status |= val;
163*ec859557SBibo Mao         if (s->status != 0 && (s->status & s->en) != 0) {
164*ec859557SBibo Mao             qemu_irq_raise(s->irq);
165*ec859557SBibo Mao         }
166*ec859557SBibo Mao         break;
167*ec859557SBibo Mao     case CORE_CLEAR_OFF:
168*ec859557SBibo Mao         s->status &= ~val;
169*ec859557SBibo Mao         if (s->status == 0 && s->en != 0) {
170*ec859557SBibo Mao             qemu_irq_lower(s->irq);
171*ec859557SBibo Mao         }
172*ec859557SBibo Mao         break;
173*ec859557SBibo Mao     case CORE_BUF_20 ... CORE_BUF_38 + 4:
174*ec859557SBibo Mao         index = (addr - CORE_BUF_20) >> 2;
175*ec859557SBibo Mao         s->buf[index] = val;
176*ec859557SBibo Mao         break;
177*ec859557SBibo Mao     case IOCSR_IPI_SEND:
178*ec859557SBibo Mao         cpuid = extract32(val, 16, 10);
179*ec859557SBibo Mao         /* IPI status vector */
180*ec859557SBibo Mao         vector = extract8(val, 0, 5);
181*ec859557SBibo Mao         cs = licc->cpu_by_arch_id(cpuid);
182*ec859557SBibo Mao         if (cs == NULL || cs->cpu_index >= ipi->num_cpu) {
183*ec859557SBibo Mao             return MEMTX_DECODE_ERROR;
184*ec859557SBibo Mao         }
185*ec859557SBibo Mao         loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], CORE_SET_OFF,
186*ec859557SBibo Mao                                  BIT(vector), 4, attrs);
187*ec859557SBibo Mao         break;
188*ec859557SBibo Mao     default:
189*ec859557SBibo Mao         qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
190*ec859557SBibo Mao         break;
191*ec859557SBibo Mao     }
192*ec859557SBibo Mao 
193*ec859557SBibo Mao     return MEMTX_OK;
194*ec859557SBibo Mao }
195*ec859557SBibo Mao 
loongson_ipi_iocsr_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)196*ec859557SBibo Mao static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr,
197*ec859557SBibo Mao                                             uint64_t val, unsigned size,
198*ec859557SBibo Mao                                             MemTxAttrs attrs)
199*ec859557SBibo Mao {
200*ec859557SBibo Mao     LoongsonIPICommonState *ipi = opaque;
201*ec859557SBibo Mao     IPICore *s;
202*ec859557SBibo Mao 
203*ec859557SBibo Mao     if (attrs.requester_id >= ipi->num_cpu) {
204*ec859557SBibo Mao         return MEMTX_DECODE_ERROR;
205*ec859557SBibo Mao     }
206*ec859557SBibo Mao 
207*ec859557SBibo Mao     s = &ipi->cpu[attrs.requester_id];
208*ec859557SBibo Mao     return loongson_ipi_core_writel(s, addr, val, size, attrs);
209*ec859557SBibo Mao }
210*ec859557SBibo Mao 
211*ec859557SBibo Mao static const MemoryRegionOps loongson_ipi_iocsr_ops = {
212*ec859557SBibo Mao     .read_with_attrs = loongson_ipi_iocsr_readl,
213*ec859557SBibo Mao     .write_with_attrs = loongson_ipi_iocsr_writel,
214*ec859557SBibo Mao     .impl.min_access_size = 4,
215*ec859557SBibo Mao     .impl.max_access_size = 4,
216*ec859557SBibo Mao     .valid.min_access_size = 4,
217*ec859557SBibo Mao     .valid.max_access_size = 8,
218*ec859557SBibo Mao     .endianness = DEVICE_LITTLE_ENDIAN,
219*ec859557SBibo Mao };
220*ec859557SBibo Mao 
221*ec859557SBibo Mao /* mail send and any send only support writeq */
loongson_ipi_writeq(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)222*ec859557SBibo Mao static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
223*ec859557SBibo Mao                                         unsigned size, MemTxAttrs attrs)
224*ec859557SBibo Mao {
225*ec859557SBibo Mao     LoongsonIPICommonState *ipi = opaque;
226*ec859557SBibo Mao     MemTxResult ret = MEMTX_OK;
227*ec859557SBibo Mao 
228*ec859557SBibo Mao     addr &= 0xfff;
229*ec859557SBibo Mao     switch (addr) {
230*ec859557SBibo Mao     case MAIL_SEND_OFFSET:
231*ec859557SBibo Mao         ret = mail_send(ipi, val, attrs);
232*ec859557SBibo Mao         break;
233*ec859557SBibo Mao     case ANY_SEND_OFFSET:
234*ec859557SBibo Mao         ret = any_send(ipi, val, attrs);
235*ec859557SBibo Mao         break;
236*ec859557SBibo Mao     default:
237*ec859557SBibo Mao        break;
238*ec859557SBibo Mao     }
239*ec859557SBibo Mao 
240*ec859557SBibo Mao     return ret;
241*ec859557SBibo Mao }
242*ec859557SBibo Mao 
243*ec859557SBibo Mao static const MemoryRegionOps loongson_ipi64_ops = {
244*ec859557SBibo Mao     .write_with_attrs = loongson_ipi_writeq,
245*ec859557SBibo Mao     .impl.min_access_size = 8,
246*ec859557SBibo Mao     .impl.max_access_size = 8,
247*ec859557SBibo Mao     .valid.min_access_size = 8,
248*ec859557SBibo Mao     .valid.max_access_size = 8,
249*ec859557SBibo Mao     .endianness = DEVICE_LITTLE_ENDIAN,
250*ec859557SBibo Mao };
251*ec859557SBibo Mao 
loongson_ipi_common_realize(DeviceState * dev,Error ** errp)252*ec859557SBibo Mao static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
253*ec859557SBibo Mao {
254*ec859557SBibo Mao     LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
255*ec859557SBibo Mao     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
256*ec859557SBibo Mao     int i;
257*ec859557SBibo Mao 
258*ec859557SBibo Mao     if (s->num_cpu == 0) {
259*ec859557SBibo Mao         error_setg(errp, "num-cpu must be at least 1");
260*ec859557SBibo Mao         return;
261*ec859557SBibo Mao     }
262*ec859557SBibo Mao 
263*ec859557SBibo Mao     memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
264*ec859557SBibo Mao                           &loongson_ipi_iocsr_ops,
265*ec859557SBibo Mao                           s, "loongson_ipi_iocsr", 0x48);
266*ec859557SBibo Mao 
267*ec859557SBibo Mao     /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */
268*ec859557SBibo Mao     s->ipi_iocsr_mem.disable_reentrancy_guard = true;
269*ec859557SBibo Mao 
270*ec859557SBibo Mao     sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
271*ec859557SBibo Mao 
272*ec859557SBibo Mao     memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
273*ec859557SBibo Mao                           &loongson_ipi64_ops,
274*ec859557SBibo Mao                           s, "loongson_ipi64_iocsr", 0x118);
275*ec859557SBibo Mao     sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
276*ec859557SBibo Mao 
277*ec859557SBibo Mao     s->cpu = g_new0(IPICore, s->num_cpu);
278*ec859557SBibo Mao     for (i = 0; i < s->num_cpu; i++) {
279*ec859557SBibo Mao         s->cpu[i].ipi = s;
280*ec859557SBibo Mao 
281*ec859557SBibo Mao         qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
282*ec859557SBibo Mao     }
283*ec859557SBibo Mao }
284*ec859557SBibo Mao 
loongson_ipi_common_unrealize(DeviceState * dev)285*ec859557SBibo Mao static void loongson_ipi_common_unrealize(DeviceState *dev)
286*ec859557SBibo Mao {
287*ec859557SBibo Mao     LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
288*ec859557SBibo Mao 
289*ec859557SBibo Mao     g_free(s->cpu);
290*ec859557SBibo Mao }
2916c8698a5SBibo Mao 
2926c8698a5SBibo Mao static const VMStateDescription vmstate_ipi_core = {
2936c8698a5SBibo Mao     .name = "ipi-single",
2946c8698a5SBibo Mao     .version_id = 2,
2956c8698a5SBibo Mao     .minimum_version_id = 2,
2966c8698a5SBibo Mao     .fields = (const VMStateField[]) {
2976c8698a5SBibo Mao         VMSTATE_UINT32(status, IPICore),
2986c8698a5SBibo Mao         VMSTATE_UINT32(en, IPICore),
2996c8698a5SBibo Mao         VMSTATE_UINT32(set, IPICore),
3006c8698a5SBibo Mao         VMSTATE_UINT32(clear, IPICore),
3016c8698a5SBibo Mao         VMSTATE_UINT32_ARRAY(buf, IPICore, IPI_MBX_NUM * 2),
3026c8698a5SBibo Mao         VMSTATE_END_OF_LIST()
3036c8698a5SBibo Mao     }
3046c8698a5SBibo Mao };
3056c8698a5SBibo Mao 
3066c8698a5SBibo Mao static const VMStateDescription vmstate_loongson_ipi_common = {
3076c8698a5SBibo Mao     .name = "loongson_ipi",
3086c8698a5SBibo Mao     .version_id = 2,
3096c8698a5SBibo Mao     .minimum_version_id = 2,
3106c8698a5SBibo Mao     .fields = (const VMStateField[]) {
3116c8698a5SBibo Mao         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongsonIPICommonState,
3126c8698a5SBibo Mao                                              num_cpu, vmstate_ipi_core,
3136c8698a5SBibo Mao                                              IPICore),
3146c8698a5SBibo Mao         VMSTATE_END_OF_LIST()
3156c8698a5SBibo Mao     }
3166c8698a5SBibo Mao };
3176c8698a5SBibo Mao 
3186c8698a5SBibo Mao static Property ipi_common_properties[] = {
3196c8698a5SBibo Mao     DEFINE_PROP_UINT32("num-cpu", LoongsonIPICommonState, num_cpu, 1),
3206c8698a5SBibo Mao     DEFINE_PROP_END_OF_LIST(),
3216c8698a5SBibo Mao };
3226c8698a5SBibo Mao 
loongson_ipi_common_class_init(ObjectClass * klass,void * data)3236c8698a5SBibo Mao static void loongson_ipi_common_class_init(ObjectClass *klass, void *data)
3246c8698a5SBibo Mao {
3256c8698a5SBibo Mao     DeviceClass *dc = DEVICE_CLASS(klass);
326*ec859557SBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
3276c8698a5SBibo Mao 
328*ec859557SBibo Mao     device_class_set_parent_realize(dc, loongson_ipi_common_realize,
329*ec859557SBibo Mao                                     &licc->parent_realize);
330*ec859557SBibo Mao     device_class_set_parent_unrealize(dc, loongson_ipi_common_unrealize,
331*ec859557SBibo Mao                                       &licc->parent_unrealize);
3326c8698a5SBibo Mao     device_class_set_props(dc, ipi_common_properties);
3336c8698a5SBibo Mao     dc->vmsd = &vmstate_loongson_ipi_common;
3346c8698a5SBibo Mao }
3357e555781SBibo Mao 
3367e555781SBibo Mao static const TypeInfo loongarch_ipi_common_types[] = {
3377e555781SBibo Mao     {
3387e555781SBibo Mao         .name               = TYPE_LOONGSON_IPI_COMMON,
3397e555781SBibo Mao         .parent             = TYPE_SYS_BUS_DEVICE,
3407e555781SBibo Mao         .instance_size      = sizeof(LoongsonIPICommonState),
3417e555781SBibo Mao         .class_size         = sizeof(LoongsonIPICommonClass),
3426c8698a5SBibo Mao         .class_init         = loongson_ipi_common_class_init,
3437e555781SBibo Mao         .abstract           = true,
3447e555781SBibo Mao     }
3457e555781SBibo Mao };
3467e555781SBibo Mao 
3477e555781SBibo Mao DEFINE_TYPES(loongarch_ipi_common_types)
348