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