xref: /qemu/hw/intc/loongarch_ipi.c (revision c5e2c4042e3c50b96cc5eaa9683325c5a96913b0)
1c403d5ffSBibo Mao /* SPDX-License-Identifier: GPL-2.0-or-later */
2c403d5ffSBibo Mao /*
3c403d5ffSBibo Mao  * LoongArch IPI interrupt support
4c403d5ffSBibo Mao  *
5c403d5ffSBibo Mao  * Copyright (C) 2024 Loongson Technology Corporation Limited
6c403d5ffSBibo Mao  */
7c403d5ffSBibo Mao 
8c403d5ffSBibo Mao #include "qemu/osdep.h"
99d71149aSBibo Mao #include "qemu/error-report.h"
10c403d5ffSBibo Mao #include "hw/boards.h"
1159c54c1cSBibo Mao #include "qapi/error.h"
12c403d5ffSBibo Mao #include "hw/intc/loongarch_ipi.h"
13ce78dacfSBibo Mao #include "hw/qdev-properties.h"
14c403d5ffSBibo Mao #include "target/loongarch/cpu.h"
15c403d5ffSBibo Mao 
get_iocsr_as(CPUState * cpu)16c403d5ffSBibo Mao static AddressSpace *get_iocsr_as(CPUState *cpu)
17c403d5ffSBibo Mao {
18c403d5ffSBibo Mao     return LOONGARCH_CPU(cpu)->env.address_space_iocsr;
19c403d5ffSBibo Mao }
20c403d5ffSBibo Mao 
loongarch_ipi_cmp(const void * a,const void * b)21bb81f237SBibo Mao static int loongarch_ipi_cmp(const void *a, const void *b)
22c403d5ffSBibo Mao {
23bb81f237SBibo Mao    IPICore *ipi_a = (IPICore *)a;
24bb81f237SBibo Mao    IPICore *ipi_b = (IPICore *)b;
25c403d5ffSBibo Mao 
26bb81f237SBibo Mao    return ipi_a->arch_id - ipi_b->arch_id;
27c403d5ffSBibo Mao }
28c403d5ffSBibo Mao 
loongarch_cpu_by_arch_id(LoongsonIPICommonState * lics,int64_t arch_id,int * index,CPUState ** pcs)29999b112dSBibo Mao static int loongarch_cpu_by_arch_id(LoongsonIPICommonState *lics,
30999b112dSBibo Mao                                     int64_t arch_id, int *index, CPUState **pcs)
31c403d5ffSBibo Mao {
32bb81f237SBibo Mao     IPICore ipi, *found;
33c403d5ffSBibo Mao 
34bb81f237SBibo Mao     ipi.arch_id = arch_id;
35bb81f237SBibo Mao     found = bsearch(&ipi, lics->cpu, lics->num_cpu, sizeof(IPICore),
36bb81f237SBibo Mao                     loongarch_ipi_cmp);
37bb81f237SBibo Mao     if (found && found->cpu) {
38999b112dSBibo Mao         if (index) {
39bb81f237SBibo Mao             *index = found - lics->cpu;
40c403d5ffSBibo Mao         }
41c403d5ffSBibo Mao 
42999b112dSBibo Mao         if (pcs) {
43bb81f237SBibo Mao             *pcs = found->cpu;
44999b112dSBibo Mao         }
45999b112dSBibo Mao 
46999b112dSBibo Mao         return MEMTX_OK;
47999b112dSBibo Mao     }
48999b112dSBibo Mao 
49999b112dSBibo Mao     return MEMTX_ERROR;
50c403d5ffSBibo Mao }
51c403d5ffSBibo Mao 
loongarch_ipi_get_cpu(LoongsonIPICommonState * lics,DeviceState * dev)5254492213SBibo Mao static IPICore *loongarch_ipi_get_cpu(LoongsonIPICommonState *lics,
5354492213SBibo Mao                                       DeviceState *dev)
5454492213SBibo Mao {
5554492213SBibo Mao     CPUClass *k = CPU_GET_CLASS(dev);
5654492213SBibo Mao     uint64_t arch_id = k->get_arch_id(CPU(dev));
5754492213SBibo Mao     int i;
5854492213SBibo Mao 
5954492213SBibo Mao     for (i = 0; i < lics->num_cpu; i++) {
6054492213SBibo Mao         if (lics->cpu[i].arch_id == arch_id) {
6154492213SBibo Mao             return &lics->cpu[i];
6254492213SBibo Mao         }
6354492213SBibo Mao     }
6454492213SBibo Mao 
6554492213SBibo Mao     return NULL;
6654492213SBibo Mao }
6754492213SBibo Mao 
loongarch_ipi_realize(DeviceState * dev,Error ** errp)6859c54c1cSBibo Mao static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
6959c54c1cSBibo Mao {
705b82177aSBibo Mao     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(dev);
7159c54c1cSBibo Mao     LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(dev);
7214dc02b5SBibo Mao     MachineState *machine = MACHINE(qdev_get_machine());
7314dc02b5SBibo Mao     MachineClass *mc = MACHINE_GET_CLASS(machine);
7414dc02b5SBibo Mao     const CPUArchIdList *id_list;
7559c54c1cSBibo Mao     Error *local_err = NULL;
765b82177aSBibo Mao     int i;
7759c54c1cSBibo Mao 
7859c54c1cSBibo Mao     lic->parent_realize(dev, &local_err);
7959c54c1cSBibo Mao     if (local_err) {
8059c54c1cSBibo Mao         error_propagate(errp, local_err);
8159c54c1cSBibo Mao         return;
8259c54c1cSBibo Mao     }
835b82177aSBibo Mao 
8414dc02b5SBibo Mao     assert(mc->possible_cpu_arch_ids);
8514dc02b5SBibo Mao     id_list = mc->possible_cpu_arch_ids(machine);
8614dc02b5SBibo Mao     lics->num_cpu = id_list->len;
875b82177aSBibo Mao     lics->cpu = g_new0(IPICore, lics->num_cpu);
885b82177aSBibo Mao     for (i = 0; i < lics->num_cpu; i++) {
8914dc02b5SBibo Mao         lics->cpu[i].arch_id = id_list->cpus[i].arch_id;
9014dc02b5SBibo Mao         lics->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
915b82177aSBibo Mao         lics->cpu[i].ipi = lics;
925b82177aSBibo Mao         qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1);
935b82177aSBibo Mao     }
9459c54c1cSBibo Mao }
9559c54c1cSBibo Mao 
loongarch_ipi_reset_hold(Object * obj,ResetType type)96*36ad84ecSBibo Mao static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
97*36ad84ecSBibo Mao {
98*36ad84ecSBibo Mao     int i;
99*36ad84ecSBibo Mao     LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(obj);
100*36ad84ecSBibo Mao     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(obj);
101*36ad84ecSBibo Mao     IPICore *core;
102*36ad84ecSBibo Mao 
103*36ad84ecSBibo Mao     if (lic->parent_phases.hold) {
104*36ad84ecSBibo Mao         lic->parent_phases.hold(obj, type);
105*36ad84ecSBibo Mao     }
106*36ad84ecSBibo Mao 
107*36ad84ecSBibo Mao     for (i = 0; i < lics->num_cpu; i++) {
108*36ad84ecSBibo Mao         core = lics->cpu + i;
109*36ad84ecSBibo Mao         /* IPI with targeted CPU available however not present */
110*36ad84ecSBibo Mao         if (!core->cpu) {
111*36ad84ecSBibo Mao             continue;
112*36ad84ecSBibo Mao         }
113*36ad84ecSBibo Mao 
114*36ad84ecSBibo Mao         core->status = 0;
115*36ad84ecSBibo Mao         core->en = 0;
116*36ad84ecSBibo Mao         core->set = 0;
117*36ad84ecSBibo Mao         core->clear = 0;
118*36ad84ecSBibo Mao         memset(core->buf, 0, sizeof(core->buf));
119*36ad84ecSBibo Mao     }
120*36ad84ecSBibo Mao }
121*36ad84ecSBibo Mao 
loongarch_ipi_cpu_plug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)1229d71149aSBibo Mao static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
1239d71149aSBibo Mao                                    DeviceState *dev, Error **errp)
1249d71149aSBibo Mao {
12554492213SBibo Mao     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
1269d71149aSBibo Mao     Object *obj = OBJECT(dev);
12754492213SBibo Mao     IPICore *core;
12854492213SBibo Mao     int index;
1299d71149aSBibo Mao 
1309d71149aSBibo Mao     if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
1319d71149aSBibo Mao         warn_report("LoongArch extioi: Invalid %s device type",
1329d71149aSBibo Mao                                        object_get_typename(obj));
1339d71149aSBibo Mao         return;
1349d71149aSBibo Mao     }
13554492213SBibo Mao 
13654492213SBibo Mao     core = loongarch_ipi_get_cpu(lics, dev);
13754492213SBibo Mao     if (!core) {
13854492213SBibo Mao         return;
13954492213SBibo Mao     }
14054492213SBibo Mao 
14154492213SBibo Mao     core->cpu = CPU(dev);
14254492213SBibo Mao     index = core - lics->cpu;
14354492213SBibo Mao 
14454492213SBibo Mao     /* connect ipi irq to cpu irq */
14554492213SBibo Mao     qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI));
1469d71149aSBibo Mao }
1479d71149aSBibo Mao 
loongarch_ipi_cpu_unplug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)1489d71149aSBibo Mao static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev,
1499d71149aSBibo Mao                                      DeviceState *dev, Error **errp)
1509d71149aSBibo Mao {
15154492213SBibo Mao     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
1529d71149aSBibo Mao     Object *obj = OBJECT(dev);
15354492213SBibo Mao     IPICore *core;
1549d71149aSBibo Mao 
1559d71149aSBibo Mao     if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
1569d71149aSBibo Mao         warn_report("LoongArch extioi: Invalid %s device type",
1579d71149aSBibo Mao                                        object_get_typename(obj));
1589d71149aSBibo Mao         return;
1599d71149aSBibo Mao     }
16054492213SBibo Mao 
16154492213SBibo Mao     core = loongarch_ipi_get_cpu(lics, dev);
16254492213SBibo Mao     if (!core) {
16354492213SBibo Mao         return;
16454492213SBibo Mao     }
16554492213SBibo Mao 
16654492213SBibo Mao     core->cpu = NULL;
1679d71149aSBibo Mao }
1689d71149aSBibo Mao 
loongarch_ipi_class_init(ObjectClass * klass,const void * data)16912d1a768SPhilippe Mathieu-Daudé static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
170c403d5ffSBibo Mao {
171c403d5ffSBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
1729d71149aSBibo Mao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
17359c54c1cSBibo Mao     LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass);
174*36ad84ecSBibo Mao     ResettableClass *rc = RESETTABLE_CLASS(klass);
17559c54c1cSBibo Mao     DeviceClass *dc = DEVICE_CLASS(klass);
176c403d5ffSBibo Mao 
17759c54c1cSBibo Mao     device_class_set_parent_realize(dc, loongarch_ipi_realize,
17859c54c1cSBibo Mao                                     &lic->parent_realize);
179*36ad84ecSBibo Mao     resettable_class_set_parent_phases(rc, NULL, loongarch_ipi_reset_hold,
180*36ad84ecSBibo Mao                                        NULL, &lic->parent_phases);
181c403d5ffSBibo Mao     licc->get_iocsr_as = get_iocsr_as;
182c403d5ffSBibo Mao     licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
1839d71149aSBibo Mao     hc->plug = loongarch_ipi_cpu_plug;
1849d71149aSBibo Mao     hc->unplug = loongarch_ipi_cpu_unplug;
185c403d5ffSBibo Mao }
186c403d5ffSBibo Mao 
187c403d5ffSBibo Mao static const TypeInfo loongarch_ipi_types[] = {
188c403d5ffSBibo Mao     {
189c403d5ffSBibo Mao         .name               = TYPE_LOONGARCH_IPI,
190c403d5ffSBibo Mao         .parent             = TYPE_LOONGSON_IPI_COMMON,
19159c54c1cSBibo Mao         .instance_size      = sizeof(LoongarchIPIState),
19259c54c1cSBibo Mao         .class_size         = sizeof(LoongarchIPIClass),
193c403d5ffSBibo Mao         .class_init         = loongarch_ipi_class_init,
1942cd09e47SPhilippe Mathieu-Daudé         .interfaces         = (const InterfaceInfo[]) {
1959d71149aSBibo Mao             { TYPE_HOTPLUG_HANDLER },
1969d71149aSBibo Mao             { }
1979d71149aSBibo Mao         },
198c403d5ffSBibo Mao     }
199c403d5ffSBibo Mao };
200c403d5ffSBibo Mao 
201c403d5ffSBibo Mao DEFINE_TYPES(loongarch_ipi_types)
202