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 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 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 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 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