1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * LoongArch IPI interrupt support 4 * 5 * Copyright (C) 2024 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/error-report.h" 10 #include "hw/boards.h" 11 #include "qapi/error.h" 12 #include "hw/intc/loongarch_ipi.h" 13 #include "hw/qdev-properties.h" 14 #include "target/loongarch/cpu.h" 15 16 static AddressSpace *get_iocsr_as(CPUState *cpu) 17 { 18 return LOONGARCH_CPU(cpu)->env.address_space_iocsr; 19 } 20 21 static int loongarch_ipi_cmp(const void *a, const void *b) 22 { 23 IPICore *ipi_a = (IPICore *)a; 24 IPICore *ipi_b = (IPICore *)b; 25 26 return ipi_a->arch_id - ipi_b->arch_id; 27 } 28 29 static int loongarch_cpu_by_arch_id(LoongsonIPICommonState *lics, 30 int64_t arch_id, int *index, CPUState **pcs) 31 { 32 IPICore ipi, *found; 33 34 ipi.arch_id = arch_id; 35 found = bsearch(&ipi, lics->cpu, lics->num_cpu, sizeof(IPICore), 36 loongarch_ipi_cmp); 37 if (found && found->cpu) { 38 if (index) { 39 *index = found - lics->cpu; 40 } 41 42 if (pcs) { 43 *pcs = found->cpu; 44 } 45 46 return MEMTX_OK; 47 } 48 49 return MEMTX_ERROR; 50 } 51 52 static IPICore *loongarch_ipi_get_cpu(LoongsonIPICommonState *lics, 53 DeviceState *dev) 54 { 55 CPUClass *k = CPU_GET_CLASS(dev); 56 uint64_t arch_id = k->get_arch_id(CPU(dev)); 57 int i; 58 59 for (i = 0; i < lics->num_cpu; i++) { 60 if (lics->cpu[i].arch_id == arch_id) { 61 return &lics->cpu[i]; 62 } 63 } 64 65 return NULL; 66 } 67 68 static void loongarch_ipi_realize(DeviceState *dev, Error **errp) 69 { 70 LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(dev); 71 LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(dev); 72 MachineState *machine = MACHINE(qdev_get_machine()); 73 MachineClass *mc = MACHINE_GET_CLASS(machine); 74 const CPUArchIdList *id_list; 75 Error *local_err = NULL; 76 int i; 77 78 lic->parent_realize(dev, &local_err); 79 if (local_err) { 80 error_propagate(errp, local_err); 81 return; 82 } 83 84 assert(mc->possible_cpu_arch_ids); 85 id_list = mc->possible_cpu_arch_ids(machine); 86 lics->num_cpu = id_list->len; 87 lics->cpu = g_new0(IPICore, lics->num_cpu); 88 for (i = 0; i < lics->num_cpu; i++) { 89 lics->cpu[i].arch_id = id_list->cpus[i].arch_id; 90 lics->cpu[i].cpu = CPU(id_list->cpus[i].cpu); 91 lics->cpu[i].ipi = lics; 92 qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1); 93 } 94 } 95 96 static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev, 97 DeviceState *dev, Error **errp) 98 { 99 LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev); 100 Object *obj = OBJECT(dev); 101 IPICore *core; 102 int index; 103 104 if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { 105 warn_report("LoongArch extioi: Invalid %s device type", 106 object_get_typename(obj)); 107 return; 108 } 109 110 core = loongarch_ipi_get_cpu(lics, dev); 111 if (!core) { 112 return; 113 } 114 115 core->cpu = CPU(dev); 116 index = core - lics->cpu; 117 118 /* connect ipi irq to cpu irq */ 119 qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI)); 120 } 121 122 static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev, 123 DeviceState *dev, Error **errp) 124 { 125 LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev); 126 Object *obj = OBJECT(dev); 127 IPICore *core; 128 129 if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { 130 warn_report("LoongArch extioi: Invalid %s device type", 131 object_get_typename(obj)); 132 return; 133 } 134 135 core = loongarch_ipi_get_cpu(lics, dev); 136 if (!core) { 137 return; 138 } 139 140 core->cpu = NULL; 141 } 142 143 static void loongarch_ipi_class_init(ObjectClass *klass, void *data) 144 { 145 LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); 146 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); 147 LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass); 148 DeviceClass *dc = DEVICE_CLASS(klass); 149 150 device_class_set_parent_realize(dc, loongarch_ipi_realize, 151 &lic->parent_realize); 152 licc->get_iocsr_as = get_iocsr_as; 153 licc->cpu_by_arch_id = loongarch_cpu_by_arch_id; 154 hc->plug = loongarch_ipi_cpu_plug; 155 hc->unplug = loongarch_ipi_cpu_unplug; 156 } 157 158 static const TypeInfo loongarch_ipi_types[] = { 159 { 160 .name = TYPE_LOONGARCH_IPI, 161 .parent = TYPE_LOONGSON_IPI_COMMON, 162 .instance_size = sizeof(LoongarchIPIState), 163 .class_size = sizeof(LoongarchIPIClass), 164 .class_init = loongarch_ipi_class_init, 165 .interfaces = (InterfaceInfo[]) { 166 { TYPE_HOTPLUG_HANDLER }, 167 { } 168 }, 169 } 170 }; 171 172 DEFINE_TYPES(loongarch_ipi_types) 173