openpic.c revision 131400
1/* 2 * Copyright (C) 2002 Benno Rice. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD: head/sys/powerpc/powerpc/openpic.c 131400 2004-07-01 07:59:08Z grehan $ 26 */ 27 28#define __RMAN_RESOURCE_VISIBLE 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/bus.h> 32#include <sys/conf.h> 33#include <sys/kernel.h> 34 35#include <machine/bus.h> 36#include <machine/intr.h> 37#include <machine/intr_machdep.h> 38#include <machine/md_var.h> 39#include <machine/pio.h> 40#include <machine/resource.h> 41 42#include <vm/vm.h> 43#include <vm/pmap.h> 44 45#include <sys/rman.h> 46 47#include <machine/openpicreg.h> 48#include <machine/openpicvar.h> 49 50#include "pic_if.h" 51 52/* 53 * Local routines 54 */ 55static u_int openpic_read(struct openpic_softc *, int); 56static void openpic_write(struct openpic_softc *, int, u_int); 57static int openpic_read_irq(struct openpic_softc *, int); 58static void openpic_eoi(struct openpic_softc *, int); 59static void openpic_enable_irq(struct openpic_softc *, int, int); 60static void openpic_disable_irq(struct openpic_softc *, int); 61static void openpic_set_priority(struct openpic_softc *, int, int); 62static void openpic_intr(void); 63static void openpic_ext_enable_irq(uintptr_t); 64static void openpic_ext_disable_irq(uintptr_t); 65 66/* XXX This limits us to one openpic */ 67static struct openpic_softc *openpic_softc; 68 69/* 70 * Called at nexus-probe time to allow interrupts to be enabled by 71 * devices that are probed before the OpenPIC h/w is probed. 72 */ 73int 74openpic_early_attach(device_t dev) 75{ 76 struct openpic_softc *sc; 77 78 sc = device_get_softc(dev); 79 openpic_softc = sc; 80 81 sc->sc_rman.rm_type = RMAN_ARRAY; 82 sc->sc_rman.rm_descr = device_get_nameunit(dev); 83 84 if (rman_init(&sc->sc_rman) != 0 || 85 rman_manage_region(&sc->sc_rman, 0, OPENPIC_IRQMAX-1) != 0) { 86 device_printf(dev, "could not set up resource management"); 87 return (ENXIO); 88 } 89 90 intr_init(openpic_intr, OPENPIC_IRQMAX, openpic_ext_enable_irq, 91 openpic_ext_disable_irq); 92 93 sc->sc_early_done = 1; 94 95 return (0); 96} 97 98int 99openpic_attach(device_t dev) 100{ 101 struct openpic_softc *sc; 102 u_int irq; 103 u_int32_t x; 104 105 sc = device_get_softc(dev); 106 sc->sc_hwprobed = 1; 107 108 if (!sc->sc_early_done) 109 openpic_early_attach(dev); 110 111 x = openpic_read(sc, OPENPIC_FEATURE); 112 switch (x & OPENPIC_FEATURE_VERSION_MASK) { 113 case 1: 114 sc->sc_version = "1.0"; 115 break; 116 case 2: 117 sc->sc_version = "1.2"; 118 break; 119 case 3: 120 sc->sc_version = "1.3"; 121 break; 122 default: 123 sc->sc_version = "unknown"; 124 break; 125 } 126 127 sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> 128 OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; 129 sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> 130 OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; 131 132 /* 133 * PSIM seems to report 1 too many IRQs 134 */ 135 if (sc->sc_psim) 136 sc->sc_nirq--; 137 138 if (bootverbose) 139 device_printf(dev, 140 "Version %s, supports %d CPUs and %d irqs\n", 141 sc->sc_version, sc->sc_ncpu, sc->sc_nirq); 142 143 /* disable all interrupts */ 144 for (irq = 0; irq < sc->sc_nirq; irq++) 145 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK); 146 147 openpic_set_priority(sc, 0, 15); 148 149 /* we don't need 8259 passthrough mode */ 150 x = openpic_read(sc, OPENPIC_CONFIG); 151 x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; 152 openpic_write(sc, OPENPIC_CONFIG, x); 153 154 /* send all interrupts to cpu 0 */ 155 for (irq = 0; irq < sc->sc_nirq; irq++) 156 openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0); 157 158 for (irq = 0; irq < sc->sc_nirq; irq++) { 159 x = irq; 160 x |= OPENPIC_IMASK; 161 x |= OPENPIC_POLARITY_POSITIVE; 162 x |= OPENPIC_SENSE_LEVEL; 163 x |= 8 << OPENPIC_PRIORITY_SHIFT; 164 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 165 } 166 167 /* XXX IPI */ 168 /* XXX set spurious intr vector */ 169 170 openpic_set_priority(sc, 0, 0); 171 172 /* clear all pending interrupts */ 173 for (irq = 0; irq < sc->sc_nirq; irq++) { 174 openpic_read_irq(sc, 0); 175 openpic_eoi(sc, 0); 176 } 177 178 /* enable pre-h/w reserved irqs, disable all others */ 179 for (irq = 0; irq < sc->sc_nirq; irq++) 180 if (sc->sc_irqrsv[irq]) 181 openpic_enable_irq(sc, irq, IST_LEVEL); 182 else 183 openpic_disable_irq(sc, irq); 184 185 return (0); 186} 187 188/* 189 * PIC interface 190 */ 191 192struct resource * 193openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr, 194 u_int flags) 195{ 196 struct openpic_softc *sc; 197 struct resource *rv; 198 int needactivate; 199 200 sc = device_get_softc(dev); 201 needactivate = flags & RF_ACTIVE; 202 flags &= ~RF_ACTIVE; 203 204 if (sc->sc_hwprobed && (intr > sc->sc_nirq)) { 205 device_printf(dev, "interrupt reservation %ld out of range\n", 206 intr); 207 return (NULL); 208 } 209 210 rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child); 211 if (rv == NULL) { 212 device_printf(dev, "interrupt reservation failed for %s\n", 213 device_get_nameunit(child)); 214 return (NULL); 215 } 216 217 if (needactivate) { 218 if (bus_activate_resource(child, SYS_RES_IRQ, *rid, rv) != 0) { 219 device_printf(dev, 220 "resource activation failed for %s\n", 221 device_get_nameunit(child)); 222 rman_release_resource(rv); 223 return (NULL); 224 } 225 } 226 227 return (rv); 228} 229 230int 231openpic_setup_intr(device_t dev, device_t child, struct resource *res, 232 int flags, driver_intr_t *intr, void *arg, void **cookiep) 233{ 234 struct openpic_softc *sc; 235 int error; 236 237 sc = device_get_softc(dev); 238 239 if (res == NULL) { 240 device_printf(dev, "null interrupt resource from %s\n", 241 device_get_nameunit(child)); 242 return (EINVAL); 243 } 244 245 if ((res->r_flags & RF_SHAREABLE) == 0) 246 flags |= INTR_EXCL; 247 248 /* 249 * We depend here on rman_activate_resource() being idempotent. 250 */ 251 error = rman_activate_resource(res); 252 if (error) 253 return (error); 254 255 error = inthand_add(device_get_nameunit(child), res->r_start, intr, 256 arg, flags, cookiep); 257 258 if (sc->sc_hwprobed) 259 openpic_enable_irq(sc, res->r_start, IST_LEVEL); 260 else 261 sc->sc_irqrsv[res->r_start] = 1; 262 263 return (error); 264} 265 266int 267openpic_teardown_intr(device_t dev, device_t child, struct resource *res, 268 void *ih) 269{ 270 int error; 271 272 error = rman_deactivate_resource(res); 273 if (error) 274 return (error); 275 276 error = inthand_remove(res->r_start, ih); 277 278 return (error); 279} 280 281int 282openpic_release_intr(device_t dev, device_t child, int rid, 283 struct resource *res) 284{ 285 int error; 286 287 if (rman_get_flags(res) & RF_ACTIVE) { 288 error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res); 289 if (error) 290 return (error); 291 } 292 293 return (rman_release_resource(res)); 294} 295 296/* 297 * Local routines 298 */ 299 300static u_int 301openpic_read(struct openpic_softc *sc, int reg) 302{ 303 return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 304} 305 306static void 307openpic_write(struct openpic_softc *sc, int reg, u_int val) 308{ 309 bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 310} 311 312static int 313openpic_read_irq(struct openpic_softc *sc, int cpu) 314{ 315 return openpic_read(sc, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK; 316} 317 318static void 319openpic_eoi(struct openpic_softc *sc, int cpu) 320{ 321 openpic_write(sc, OPENPIC_EOI(cpu), 0); 322} 323 324static void 325openpic_enable_irq(struct openpic_softc *sc, int irq, int type) 326{ 327 u_int x; 328 329 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 330 x &= ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL | OPENPIC_SENSE_EDGE); 331 if (type == IST_LEVEL) 332 x |= OPENPIC_SENSE_LEVEL; 333 else 334 x |= OPENPIC_SENSE_EDGE; 335 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 336} 337 338static void 339openpic_disable_irq(struct openpic_softc *sc, int irq) 340{ 341 u_int x; 342 343 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 344 x |= OPENPIC_IMASK; 345 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 346} 347 348static void 349openpic_set_priority(struct openpic_softc *sc, int cpu, int pri) 350{ 351 u_int x; 352 353 x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu)); 354 x &= ~OPENPIC_CPU_PRIORITY_MASK; 355 x |= pri; 356 openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x); 357} 358 359static void 360openpic_intr(void) 361{ 362 struct openpic_softc *sc; 363 int irq; 364 u_int32_t msr; 365 366 sc = openpic_softc; 367 msr = mfmsr(); 368 369 irq = openpic_read_irq(sc, 0); 370 if (irq == 255) { 371 return; 372 } 373 374start: 375 openpic_disable_irq(sc, irq); 376 /*mtmsr(msr | PSL_EE);*/ 377 378 /* do the interrupt thang */ 379 intr_handle(irq); 380 381 mtmsr(msr); 382 383 openpic_eoi(sc, 0); 384 385 irq = openpic_read_irq(sc, 0); 386 if (irq != 255) 387 goto start; 388} 389 390static void 391openpic_ext_enable_irq(uintptr_t irq) 392{ 393 if (!openpic_softc->sc_hwprobed) 394 return; 395 396 openpic_enable_irq(openpic_softc, irq, IST_LEVEL); 397} 398 399static void 400openpic_ext_disable_irq(uintptr_t irq) 401{ 402 if (!openpic_softc->sc_hwprobed) 403 return; 404 405 openpic_disable_irq(openpic_softc, irq); 406} 407