1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright 2011 Nathan Whitehorn 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/module.h> 34 #include <sys/bus.h> 35 #include <sys/conf.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/smp.h> 39 40 #include <vm/vm.h> 41 #include <vm/pmap.h> 42 43 #include <machine/bus.h> 44 #include <machine/intr_machdep.h> 45 #include <machine/md_var.h> 46 #include <machine/rtas.h> 47 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 51 #include "phyp-hvcall.h" 52 #include "pic_if.h" 53 54 #define XICP_PRIORITY 5 /* Random non-zero number */ 55 #define XICP_IPI 2 56 #define MAX_XICP_IRQS (1<<24) /* 24-bit XIRR field */ 57 58 static int xicp_probe(device_t); 59 static int xicp_attach(device_t); 60 static int xics_probe(device_t); 61 static int xics_attach(device_t); 62 63 static void xicp_bind(device_t dev, u_int irq, cpuset_t cpumask); 64 static void xicp_dispatch(device_t, struct trapframe *); 65 static void xicp_enable(device_t, u_int, u_int); 66 static void xicp_eoi(device_t, u_int); 67 static void xicp_ipi(device_t, u_int); 68 static void xicp_mask(device_t, u_int); 69 static void xicp_unmask(device_t, u_int); 70 71 static device_method_t xicp_methods[] = { 72 /* Device interface */ 73 DEVMETHOD(device_probe, xicp_probe), 74 DEVMETHOD(device_attach, xicp_attach), 75 76 /* PIC interface */ 77 DEVMETHOD(pic_bind, xicp_bind), 78 DEVMETHOD(pic_dispatch, xicp_dispatch), 79 DEVMETHOD(pic_enable, xicp_enable), 80 DEVMETHOD(pic_eoi, xicp_eoi), 81 DEVMETHOD(pic_ipi, xicp_ipi), 82 DEVMETHOD(pic_mask, xicp_mask), 83 DEVMETHOD(pic_unmask, xicp_unmask), 84 85 { 0, 0 }, 86 }; 87 88 static device_method_t xics_methods[] = { 89 /* Device interface */ 90 DEVMETHOD(device_probe, xics_probe), 91 DEVMETHOD(device_attach, xics_attach), 92 93 { 0, 0 }, 94 }; 95 96 struct xicp_softc { 97 struct mtx sc_mtx; 98 99 int ibm_int_on; 100 int ibm_int_off; 101 int ibm_get_xive; 102 int ibm_set_xive; 103 104 /* XXX: inefficient -- hash table? tree? */ 105 struct { 106 int irq; 107 int vector; 108 } intvecs[256]; 109 int nintvecs; 110 }; 111 112 static driver_t xicp_driver = { 113 "xicp", 114 xicp_methods, 115 sizeof(struct xicp_softc) 116 }; 117 118 static driver_t xics_driver = { 119 "xics", 120 xics_methods, 121 0 122 }; 123 124 static devclass_t xicp_devclass; 125 static devclass_t xics_devclass; 126 127 EARLY_DRIVER_MODULE(xicp, ofwbus, xicp_driver, xicp_devclass, 0, 0, 128 BUS_PASS_INTERRUPT-1); 129 EARLY_DRIVER_MODULE(xics, ofwbus, xics_driver, xics_devclass, 0, 0, 130 BUS_PASS_INTERRUPT); 131 132 static int 133 xicp_probe(device_t dev) 134 { 135 if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev), 136 "interrupt-controller") != 0) 137 return (ENXIO); 138 139 if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp")) 140 return (ENXIO); 141 142 device_set_desc(dev, "PAPR virtual interrupt controller"); 143 return (BUS_PROBE_GENERIC); 144 } 145 146 static int 147 xics_probe(device_t dev) 148 { 149 if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev), 150 "interrupt-controller") != 0) 151 return (ENXIO); 152 153 if (!ofw_bus_is_compatible(dev, "ibm,ppc-xics")) 154 return (ENXIO); 155 156 device_set_desc(dev, "PAPR virtual interrupt source"); 157 return (BUS_PROBE_GENERIC); 158 } 159 160 static int 161 xicp_attach(device_t dev) 162 { 163 struct xicp_softc *sc = device_get_softc(dev); 164 phandle_t phandle = ofw_bus_get_node(dev); 165 166 mtx_init(&sc->sc_mtx, "XICP", NULL, MTX_DEF); 167 sc->nintvecs = 0; 168 169 sc->ibm_int_on = rtas_token_lookup("ibm,int-on"); 170 sc->ibm_int_off = rtas_token_lookup("ibm,int-off"); 171 sc->ibm_set_xive = rtas_token_lookup("ibm,set-xive"); 172 sc->ibm_get_xive = rtas_token_lookup("ibm,get-xive"); 173 174 powerpc_register_pic(dev, OF_xref_from_node(phandle), MAX_XICP_IRQS, 175 1 /* Number of IPIs */, FALSE); 176 root_pic = dev; 177 178 return (0); 179 } 180 181 static int 182 xics_attach(device_t dev) 183 { 184 phandle_t phandle = ofw_bus_get_node(dev); 185 186 /* The XICP (root PIC) will handle all our interrupts */ 187 powerpc_register_pic(root_pic, OF_xref_from_node(phandle), 188 MAX_XICP_IRQS, 1 /* Number of IPIs */, FALSE); 189 190 return (0); 191 } 192 193 /* 194 * PIC I/F methods. 195 */ 196 197 static void 198 xicp_bind(device_t dev, u_int irq, cpuset_t cpumask) 199 { 200 struct xicp_softc *sc = device_get_softc(dev); 201 cell_t status, cpu; 202 int ncpus, i, error; 203 204 /* 205 * This doesn't appear to actually support affinity groups, so pick a 206 * random CPU. 207 */ 208 ncpus = 0; 209 CPU_FOREACH(cpu) 210 if (CPU_ISSET(cpu, &cpumask)) ncpus++; 211 212 i = mftb() % ncpus; 213 ncpus = 0; 214 CPU_FOREACH(cpu) { 215 if (!CPU_ISSET(cpu, &cpumask)) 216 continue; 217 if (ncpus == i) 218 break; 219 ncpus++; 220 } 221 222 223 error = rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, 224 XICP_PRIORITY, &status); 225 if (error < 0) 226 panic("Cannot bind interrupt %d to CPU %d", irq, cpu); 227 } 228 229 static void 230 xicp_dispatch(device_t dev, struct trapframe *tf) 231 { 232 struct xicp_softc *sc; 233 uint64_t xirr, junk; 234 int i; 235 236 sc = device_get_softc(dev); 237 for (;;) { 238 /* Return value in R4, use the PFT call */ 239 phyp_pft_hcall(H_XIRR, 0, 0, 0, 0, &xirr, &junk, &junk); 240 xirr &= 0x00ffffff; 241 242 if (xirr == 0) { /* No more pending interrupts? */ 243 phyp_hcall(H_CPPR, (uint64_t)0xff); 244 break; 245 } 246 if (xirr == XICP_IPI) { /* Magic number for IPIs */ 247 xirr = MAX_XICP_IRQS; /* Map to FreeBSD magic */ 248 phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(cpuid)), 249 0xff); /* Clear IPI */ 250 } 251 252 /* XXX: super inefficient */ 253 for (i = 0; i < sc->nintvecs; i++) { 254 if (sc->intvecs[i].irq == xirr) 255 break; 256 } 257 258 KASSERT(i < sc->nintvecs, ("Unmapped XIRR")); 259 powerpc_dispatch_intr(sc->intvecs[i].vector, tf); 260 } 261 } 262 263 static void 264 xicp_enable(device_t dev, u_int irq, u_int vector) 265 { 266 struct xicp_softc *sc; 267 cell_t status, cpu; 268 269 sc = device_get_softc(dev); 270 271 KASSERT(sc->nintvecs + 1 < nitems(sc->intvecs), 272 ("Too many XICP interrupts")); 273 274 mtx_lock(&sc->sc_mtx); 275 sc->intvecs[sc->nintvecs].irq = irq; 276 sc->intvecs[sc->nintvecs].vector = vector; 277 mb(); 278 sc->nintvecs++; 279 mtx_unlock(&sc->sc_mtx); 280 281 /* IPIs are also enabled */ 282 if (irq == MAX_XICP_IRQS) 283 return; 284 285 /* Bind to this CPU to start: distrib. ID is last entry in gserver# */ 286 cpu = PCPU_GET(cpuid); 287 rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, 288 &status); 289 xicp_unmask(dev, irq); 290 } 291 292 static void 293 xicp_eoi(device_t dev, u_int irq) 294 { 295 uint64_t xirr; 296 297 if (irq == MAX_XICP_IRQS) /* Remap IPI interrupt to internal value */ 298 irq = XICP_IPI; 299 xirr = irq | (XICP_PRIORITY << 24); 300 301 phyp_hcall(H_EOI, xirr); 302 } 303 304 static void 305 xicp_ipi(device_t dev, u_int cpu) 306 { 307 308 phyp_hcall(H_IPI, (uint64_t)cpu, XICP_PRIORITY); 309 } 310 311 static void 312 xicp_mask(device_t dev, u_int irq) 313 { 314 struct xicp_softc *sc = device_get_softc(dev); 315 cell_t status; 316 317 if (irq == MAX_XICP_IRQS) 318 return; 319 320 rtas_call_method(sc->ibm_int_off, 1, 1, irq, &status); 321 } 322 323 static void 324 xicp_unmask(device_t dev, u_int irq) 325 { 326 struct xicp_softc *sc = device_get_softc(dev); 327 cell_t status; 328 329 if (irq == MAX_XICP_IRQS) 330 return; 331 332 rtas_call_method(sc->ibm_int_on, 1, 1, irq, &status); 333 } 334 335