xref: /qemu/hw/intc/loongarch_ipi.c (revision 12d1a768bdfea6e27a3a829228840d72507613a1)
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 
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 
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 
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 
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 
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 
969d71149aSBibo Mao static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
979d71149aSBibo Mao                                    DeviceState *dev, Error **errp)
989d71149aSBibo Mao {
9954492213SBibo Mao     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
1009d71149aSBibo Mao     Object *obj = OBJECT(dev);
10154492213SBibo Mao     IPICore *core;
10254492213SBibo Mao     int index;
1039d71149aSBibo Mao 
1049d71149aSBibo Mao     if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
1059d71149aSBibo Mao         warn_report("LoongArch extioi: Invalid %s device type",
1069d71149aSBibo Mao                                        object_get_typename(obj));
1079d71149aSBibo Mao         return;
1089d71149aSBibo Mao     }
10954492213SBibo Mao 
11054492213SBibo Mao     core = loongarch_ipi_get_cpu(lics, dev);
11154492213SBibo Mao     if (!core) {
11254492213SBibo Mao         return;
11354492213SBibo Mao     }
11454492213SBibo Mao 
11554492213SBibo Mao     core->cpu = CPU(dev);
11654492213SBibo Mao     index = core - lics->cpu;
11754492213SBibo Mao 
11854492213SBibo Mao     /* connect ipi irq to cpu irq */
11954492213SBibo Mao     qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI));
1209d71149aSBibo Mao }
1219d71149aSBibo Mao 
1229d71149aSBibo Mao static void loongarch_ipi_cpu_unplug(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;
1289d71149aSBibo Mao 
1299d71149aSBibo Mao     if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
1309d71149aSBibo Mao         warn_report("LoongArch extioi: Invalid %s device type",
1319d71149aSBibo Mao                                        object_get_typename(obj));
1329d71149aSBibo Mao         return;
1339d71149aSBibo Mao     }
13454492213SBibo Mao 
13554492213SBibo Mao     core = loongarch_ipi_get_cpu(lics, dev);
13654492213SBibo Mao     if (!core) {
13754492213SBibo Mao         return;
13854492213SBibo Mao     }
13954492213SBibo Mao 
14054492213SBibo Mao     core->cpu = NULL;
1419d71149aSBibo Mao }
1429d71149aSBibo Mao 
143*12d1a768SPhilippe Mathieu-Daudé static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
144c403d5ffSBibo Mao {
145c403d5ffSBibo Mao     LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
1469d71149aSBibo Mao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
14759c54c1cSBibo Mao     LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass);
14859c54c1cSBibo Mao     DeviceClass *dc = DEVICE_CLASS(klass);
149c403d5ffSBibo Mao 
15059c54c1cSBibo Mao     device_class_set_parent_realize(dc, loongarch_ipi_realize,
15159c54c1cSBibo Mao                                     &lic->parent_realize);
152c403d5ffSBibo Mao     licc->get_iocsr_as = get_iocsr_as;
153c403d5ffSBibo Mao     licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
1549d71149aSBibo Mao     hc->plug = loongarch_ipi_cpu_plug;
1559d71149aSBibo Mao     hc->unplug = loongarch_ipi_cpu_unplug;
156c403d5ffSBibo Mao }
157c403d5ffSBibo Mao 
158c403d5ffSBibo Mao static const TypeInfo loongarch_ipi_types[] = {
159c403d5ffSBibo Mao     {
160c403d5ffSBibo Mao         .name               = TYPE_LOONGARCH_IPI,
161c403d5ffSBibo Mao         .parent             = TYPE_LOONGSON_IPI_COMMON,
16259c54c1cSBibo Mao         .instance_size      = sizeof(LoongarchIPIState),
16359c54c1cSBibo Mao         .class_size         = sizeof(LoongarchIPIClass),
164c403d5ffSBibo Mao         .class_init         = loongarch_ipi_class_init,
1659d71149aSBibo Mao         .interfaces         = (InterfaceInfo[]) {
1669d71149aSBibo Mao             { TYPE_HOTPLUG_HANDLER },
1679d71149aSBibo Mao             { }
1689d71149aSBibo Mao         },
169c403d5ffSBibo Mao     }
170c403d5ffSBibo Mao };
171c403d5ffSBibo Mao 
172c403d5ffSBibo Mao DEFINE_TYPES(loongarch_ipi_types)
173