1255643Snwhitehorn/*- 2255643Snwhitehorn * Copyright 2011 Nathan Whitehorn 3255643Snwhitehorn * 4255643Snwhitehorn * Redistribution and use in source and binary forms, with or without 5255643Snwhitehorn * modification, are permitted provided that the following conditions 6255643Snwhitehorn * are met: 7255643Snwhitehorn * 1. Redistributions of source code must retain the above copyright 8255643Snwhitehorn * notice, this list of conditions and the following disclaimer. 9255643Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 10255643Snwhitehorn * notice, this list of conditions and the following disclaimer in the 11255643Snwhitehorn * documentation and/or other materials provided with the distribution. 12255643Snwhitehorn * 13255643Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14255643Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15255643Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16255643Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17255643Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18255643Snwhitehorn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19255643Snwhitehorn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20255643Snwhitehorn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21255643Snwhitehorn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22255643Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23255643Snwhitehorn * SUCH DAMAGE. 24255643Snwhitehorn */ 25255643Snwhitehorn 26255643Snwhitehorn#include <sys/cdefs.h> 27255643Snwhitehorn__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/pseries/xics.c 266160 2014-05-15 17:30:16Z ian $"); 28255643Snwhitehorn 29255643Snwhitehorn#include <sys/param.h> 30255643Snwhitehorn#include <sys/systm.h> 31255643Snwhitehorn#include <sys/module.h> 32255643Snwhitehorn#include <sys/bus.h> 33255643Snwhitehorn#include <sys/conf.h> 34255643Snwhitehorn#include <sys/kernel.h> 35255643Snwhitehorn#include <sys/malloc.h> 36255643Snwhitehorn#include <sys/smp.h> 37255643Snwhitehorn 38255643Snwhitehorn#include <vm/vm.h> 39255643Snwhitehorn#include <vm/pmap.h> 40255643Snwhitehorn 41255643Snwhitehorn#include <machine/bus.h> 42255643Snwhitehorn#include <machine/intr_machdep.h> 43255643Snwhitehorn#include <machine/md_var.h> 44255643Snwhitehorn#include <machine/rtas.h> 45255643Snwhitehorn 46255643Snwhitehorn#include <dev/ofw/ofw_bus.h> 47255643Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 48255643Snwhitehorn 49255643Snwhitehorn#include "phyp-hvcall.h" 50255643Snwhitehorn#include "pic_if.h" 51255643Snwhitehorn 52255643Snwhitehorn#define XICP_PRIORITY 5 /* Random non-zero number */ 53255643Snwhitehorn#define XICP_IPI 2 54255643Snwhitehorn#define MAX_XICP_IRQS (1<<24) /* 24-bit XIRR field */ 55255643Snwhitehorn 56255643Snwhitehornstatic int xicp_probe(device_t); 57255643Snwhitehornstatic int xicp_attach(device_t); 58255643Snwhitehornstatic int xics_probe(device_t); 59255643Snwhitehornstatic int xics_attach(device_t); 60255643Snwhitehorn 61255643Snwhitehornstatic void xicp_bind(device_t dev, u_int irq, cpuset_t cpumask); 62255643Snwhitehornstatic void xicp_dispatch(device_t, struct trapframe *); 63255643Snwhitehornstatic void xicp_enable(device_t, u_int, u_int); 64255643Snwhitehornstatic void xicp_eoi(device_t, u_int); 65255643Snwhitehornstatic void xicp_ipi(device_t, u_int); 66255643Snwhitehornstatic void xicp_mask(device_t, u_int); 67255643Snwhitehornstatic void xicp_unmask(device_t, u_int); 68255643Snwhitehorn 69255643Snwhitehornstatic device_method_t xicp_methods[] = { 70255643Snwhitehorn /* Device interface */ 71255643Snwhitehorn DEVMETHOD(device_probe, xicp_probe), 72255643Snwhitehorn DEVMETHOD(device_attach, xicp_attach), 73255643Snwhitehorn 74255643Snwhitehorn /* PIC interface */ 75255643Snwhitehorn DEVMETHOD(pic_bind, xicp_bind), 76255643Snwhitehorn DEVMETHOD(pic_dispatch, xicp_dispatch), 77255643Snwhitehorn DEVMETHOD(pic_enable, xicp_enable), 78255643Snwhitehorn DEVMETHOD(pic_eoi, xicp_eoi), 79255643Snwhitehorn DEVMETHOD(pic_ipi, xicp_ipi), 80255643Snwhitehorn DEVMETHOD(pic_mask, xicp_mask), 81255643Snwhitehorn DEVMETHOD(pic_unmask, xicp_unmask), 82255643Snwhitehorn 83255643Snwhitehorn { 0, 0 }, 84255643Snwhitehorn}; 85255643Snwhitehorn 86255643Snwhitehornstatic device_method_t xics_methods[] = { 87255643Snwhitehorn /* Device interface */ 88255643Snwhitehorn DEVMETHOD(device_probe, xics_probe), 89255643Snwhitehorn DEVMETHOD(device_attach, xics_attach), 90255643Snwhitehorn 91255643Snwhitehorn { 0, 0 }, 92255643Snwhitehorn}; 93255643Snwhitehorn 94255643Snwhitehornstruct xicp_softc { 95255643Snwhitehorn struct mtx sc_mtx; 96255643Snwhitehorn 97255643Snwhitehorn int ibm_int_on; 98255643Snwhitehorn int ibm_int_off; 99255643Snwhitehorn int ibm_get_xive; 100255643Snwhitehorn int ibm_set_xive; 101255643Snwhitehorn 102255643Snwhitehorn /* XXX: inefficient -- hash table? tree? */ 103255643Snwhitehorn struct { 104255643Snwhitehorn int irq; 105255643Snwhitehorn int vector; 106255643Snwhitehorn } intvecs[256]; 107255643Snwhitehorn int nintvecs; 108255643Snwhitehorn}; 109255643Snwhitehorn 110255643Snwhitehornstatic driver_t xicp_driver = { 111255643Snwhitehorn "xicp", 112255643Snwhitehorn xicp_methods, 113255643Snwhitehorn sizeof(struct xicp_softc) 114255643Snwhitehorn}; 115255643Snwhitehorn 116255643Snwhitehornstatic driver_t xics_driver = { 117255643Snwhitehorn "xics", 118255643Snwhitehorn xics_methods, 119255643Snwhitehorn 0 120255643Snwhitehorn}; 121255643Snwhitehorn 122255643Snwhitehornstatic devclass_t xicp_devclass; 123255643Snwhitehornstatic devclass_t xics_devclass; 124255643Snwhitehorn 125266160SianEARLY_DRIVER_MODULE(xicp, ofwbus, xicp_driver, xicp_devclass, 0, 0, 126255643Snwhitehorn BUS_PASS_INTERRUPT-1); 127266160SianEARLY_DRIVER_MODULE(xics, ofwbus, xics_driver, xics_devclass, 0, 0, 128255643Snwhitehorn BUS_PASS_INTERRUPT); 129255643Snwhitehorn 130255643Snwhitehornstatic int 131255643Snwhitehornxicp_probe(device_t dev) 132255643Snwhitehorn{ 133255643Snwhitehorn if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev), 134255643Snwhitehorn "interrupt-controller") != 0) 135255643Snwhitehorn return (ENXIO); 136255643Snwhitehorn 137255643Snwhitehorn if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp")) 138255643Snwhitehorn return (ENXIO); 139255643Snwhitehorn 140255643Snwhitehorn device_set_desc(dev, "PAPR virtual interrupt controller"); 141255643Snwhitehorn return (BUS_PROBE_GENERIC); 142255643Snwhitehorn} 143255643Snwhitehorn 144255643Snwhitehornstatic int 145255643Snwhitehornxics_probe(device_t dev) 146255643Snwhitehorn{ 147255643Snwhitehorn if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev), 148255643Snwhitehorn "interrupt-controller") != 0) 149255643Snwhitehorn return (ENXIO); 150255643Snwhitehorn 151255643Snwhitehorn if (!ofw_bus_is_compatible(dev, "ibm,ppc-xics")) 152255643Snwhitehorn return (ENXIO); 153255643Snwhitehorn 154255643Snwhitehorn device_set_desc(dev, "PAPR virtual interrupt source"); 155255643Snwhitehorn return (BUS_PROBE_GENERIC); 156255643Snwhitehorn} 157255643Snwhitehorn 158255643Snwhitehornstatic int 159255643Snwhitehornxicp_attach(device_t dev) 160255643Snwhitehorn{ 161255643Snwhitehorn struct xicp_softc *sc = device_get_softc(dev); 162255643Snwhitehorn phandle_t phandle = ofw_bus_get_node(dev); 163255643Snwhitehorn 164255643Snwhitehorn mtx_init(&sc->sc_mtx, "XICP", NULL, MTX_DEF); 165255643Snwhitehorn sc->nintvecs = 0; 166255643Snwhitehorn 167255643Snwhitehorn sc->ibm_int_on = rtas_token_lookup("ibm,int-on"); 168255643Snwhitehorn sc->ibm_int_off = rtas_token_lookup("ibm,int-off"); 169255643Snwhitehorn sc->ibm_set_xive = rtas_token_lookup("ibm,set-xive"); 170255643Snwhitehorn sc->ibm_get_xive = rtas_token_lookup("ibm,get-xive"); 171255643Snwhitehorn 172255643Snwhitehorn if (OF_getproplen(phandle, "ibm,phandle") > 0) 173255643Snwhitehorn OF_getprop(phandle, "ibm,phandle", &phandle, sizeof(phandle)); 174255643Snwhitehorn 175255643Snwhitehorn powerpc_register_pic(dev, phandle, MAX_XICP_IRQS, 176255643Snwhitehorn 1 /* Number of IPIs */, FALSE); 177255643Snwhitehorn root_pic = dev; 178255643Snwhitehorn 179255643Snwhitehorn return (0); 180255643Snwhitehorn} 181255643Snwhitehorn 182255643Snwhitehornstatic int 183255643Snwhitehornxics_attach(device_t dev) 184255643Snwhitehorn{ 185255643Snwhitehorn phandle_t phandle = ofw_bus_get_node(dev); 186255643Snwhitehorn 187255643Snwhitehorn if (OF_getproplen(phandle, "ibm,phandle") > 0) 188255643Snwhitehorn OF_getprop(phandle, "ibm,phandle", &phandle, sizeof(phandle)); 189255643Snwhitehorn 190255643Snwhitehorn /* The XICP (root PIC) will handle all our interrupts */ 191255643Snwhitehorn powerpc_register_pic(root_pic, phandle, MAX_XICP_IRQS, 192255643Snwhitehorn 1 /* Number of IPIs */, FALSE); 193255643Snwhitehorn 194255643Snwhitehorn return (0); 195255643Snwhitehorn} 196255643Snwhitehorn 197255643Snwhitehorn/* 198255643Snwhitehorn * PIC I/F methods. 199255643Snwhitehorn */ 200255643Snwhitehorn 201255643Snwhitehornstatic void 202255643Snwhitehornxicp_bind(device_t dev, u_int irq, cpuset_t cpumask) 203255643Snwhitehorn{ 204255643Snwhitehorn struct xicp_softc *sc = device_get_softc(dev); 205255643Snwhitehorn cell_t status, cpu; 206255643Snwhitehorn 207255643Snwhitehorn /* 208255643Snwhitehorn * This doesn't appear to actually support affinity groups, so just 209255643Snwhitehorn * use the first CPU. 210255643Snwhitehorn */ 211255643Snwhitehorn CPU_FOREACH(cpu) 212255643Snwhitehorn if (CPU_ISSET(cpu, &cpumask)) break; 213255643Snwhitehorn 214255643Snwhitehorn rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, 215255643Snwhitehorn &status); 216255643Snwhitehorn} 217255643Snwhitehorn 218255643Snwhitehornstatic void 219255643Snwhitehornxicp_dispatch(device_t dev, struct trapframe *tf) 220255643Snwhitehorn{ 221255643Snwhitehorn struct xicp_softc *sc; 222255643Snwhitehorn uint64_t xirr, junk; 223255643Snwhitehorn int i; 224255643Snwhitehorn 225255643Snwhitehorn sc = device_get_softc(dev); 226255643Snwhitehorn for (;;) { 227255643Snwhitehorn /* Return value in R4, use the PFT call */ 228255643Snwhitehorn phyp_pft_hcall(H_XIRR, 0, 0, 0, 0, &xirr, &junk, &junk); 229255643Snwhitehorn xirr &= 0x00ffffff; 230255643Snwhitehorn 231255643Snwhitehorn if (xirr == 0) { /* No more pending interrupts? */ 232255643Snwhitehorn phyp_hcall(H_CPPR, (uint64_t)0xff); 233255643Snwhitehorn break; 234255643Snwhitehorn } 235255643Snwhitehorn if (xirr == XICP_IPI) { /* Magic number for IPIs */ 236255643Snwhitehorn xirr = MAX_XICP_IRQS; /* Map to FreeBSD magic */ 237255643Snwhitehorn phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(cpuid)), 238255643Snwhitehorn 0xff); /* Clear IPI */ 239255643Snwhitehorn } 240255643Snwhitehorn 241255643Snwhitehorn /* XXX: super inefficient */ 242255643Snwhitehorn for (i = 0; i < sc->nintvecs; i++) { 243255643Snwhitehorn if (sc->intvecs[i].irq == xirr) 244255643Snwhitehorn break; 245255643Snwhitehorn } 246255643Snwhitehorn 247255643Snwhitehorn KASSERT(i < sc->nintvecs, ("Unmapped XIRR")); 248255643Snwhitehorn powerpc_dispatch_intr(sc->intvecs[i].vector, tf); 249255643Snwhitehorn } 250255643Snwhitehorn} 251255643Snwhitehorn 252255643Snwhitehornstatic void 253255643Snwhitehornxicp_enable(device_t dev, u_int irq, u_int vector) 254255643Snwhitehorn{ 255255643Snwhitehorn struct xicp_softc *sc; 256255643Snwhitehorn cell_t status, cpu; 257255643Snwhitehorn 258255643Snwhitehorn sc = device_get_softc(dev); 259255643Snwhitehorn 260255643Snwhitehorn KASSERT(sc->nintvecs + 1 < sizeof(sc->intvecs)/sizeof(sc->intvecs[0]), 261255643Snwhitehorn ("Too many XICP interrupts")); 262255643Snwhitehorn 263255643Snwhitehorn mtx_lock(&sc->sc_mtx); 264255643Snwhitehorn sc->intvecs[sc->nintvecs].irq = irq; 265255643Snwhitehorn sc->intvecs[sc->nintvecs].vector = vector; 266255643Snwhitehorn mb(); 267255643Snwhitehorn sc->nintvecs++; 268255643Snwhitehorn mtx_unlock(&sc->sc_mtx); 269255643Snwhitehorn 270255643Snwhitehorn /* IPIs are also enabled */ 271255643Snwhitehorn if (irq == MAX_XICP_IRQS) 272255643Snwhitehorn return; 273255643Snwhitehorn 274255643Snwhitehorn /* Bind to this CPU to start: distrib. ID is last entry in gserver# */ 275255643Snwhitehorn cpu = PCPU_GET(cpuid); 276255643Snwhitehorn rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, 277255643Snwhitehorn &status); 278255643Snwhitehorn xicp_unmask(dev, irq); 279255643Snwhitehorn} 280255643Snwhitehorn 281255643Snwhitehornstatic void 282255643Snwhitehornxicp_eoi(device_t dev, u_int irq) 283255643Snwhitehorn{ 284255643Snwhitehorn uint64_t xirr; 285255643Snwhitehorn 286255643Snwhitehorn if (irq == MAX_XICP_IRQS) /* Remap IPI interrupt to internal value */ 287255643Snwhitehorn irq = XICP_IPI; 288255643Snwhitehorn xirr = irq | (XICP_PRIORITY << 24); 289255643Snwhitehorn 290255643Snwhitehorn phyp_hcall(H_EOI, xirr); 291255643Snwhitehorn} 292255643Snwhitehorn 293255643Snwhitehornstatic void 294255643Snwhitehornxicp_ipi(device_t dev, u_int cpu) 295255643Snwhitehorn{ 296255643Snwhitehorn 297255643Snwhitehorn phyp_hcall(H_IPI, (uint64_t)cpu, XICP_PRIORITY); 298255643Snwhitehorn} 299255643Snwhitehorn 300255643Snwhitehornstatic void 301255643Snwhitehornxicp_mask(device_t dev, u_int irq) 302255643Snwhitehorn{ 303255643Snwhitehorn struct xicp_softc *sc = device_get_softc(dev); 304255643Snwhitehorn cell_t status; 305255643Snwhitehorn 306255643Snwhitehorn if (irq == MAX_XICP_IRQS) 307255643Snwhitehorn return; 308255643Snwhitehorn 309255643Snwhitehorn rtas_call_method(sc->ibm_int_off, 1, 1, irq, &status); 310255643Snwhitehorn} 311255643Snwhitehorn 312255643Snwhitehornstatic void 313255643Snwhitehornxicp_unmask(device_t dev, u_int irq) 314255643Snwhitehorn{ 315255643Snwhitehorn struct xicp_softc *sc = device_get_softc(dev); 316255643Snwhitehorn cell_t status; 317255643Snwhitehorn 318255643Snwhitehorn if (irq == MAX_XICP_IRQS) 319255643Snwhitehorn return; 320255643Snwhitehorn 321255643Snwhitehorn rtas_call_method(sc->ibm_int_on, 1, 1, irq, &status); 322255643Snwhitehorn} 323255643Snwhitehorn 324