xref: /qemu/hw/intc/loongson_ipi_common.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 
loongson_ipi_core_readl(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)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 
loongson_ipi_iocsr_readl(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)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 
send_ipi_data(LoongsonIPICommonState * ipi,CPUState * cpu,uint64_t val,hwaddr addr,MemTxAttrs attrs)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 
mail_send(LoongsonIPICommonState * ipi,uint64_t val,MemTxAttrs attrs)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 
any_send(LoongsonIPICommonState * ipi,uint64_t val,MemTxAttrs attrs)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 
loongson_ipi_core_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)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 
loongson_ipi_iocsr_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)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 */
loongson_ipi_writeq(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)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 
loongson_ipi_common_realize(DeviceState * dev,Error ** errp)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 
loongson_ipi_common_unrealize(DeviceState * dev)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 
loongson_ipi_common_class_init(ObjectClass * klass,const void * data)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