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$ 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 */ 55 static u_int openpic_read(struct openpic_softc *, int); 56 static void openpic_write(struct openpic_softc *, int, u_int); 57 static int openpic_read_irq(struct openpic_softc *, int); 58 static void openpic_eoi(struct openpic_softc *, int); 59 static void openpic_enable_irq(struct openpic_softc *, int, int); 60 static void openpic_disable_irq(struct openpic_softc *, int); 61 static void openpic_set_priority(struct openpic_softc *, int, int); 62 static void openpic_intr(void); 63 static void openpic_ext_enable_irq(uintptr_t); 64 static void openpic_ext_disable_irq(uintptr_t); 65 66 /* XXX This limits us to one openpic */ 67 static 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 */ 73 int 74 openpic_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 98 int 99 openpic_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 192 struct resource * 193 openpic_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 230 int 231 openpic_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 266 int 267 openpic_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 281 int 282 openpic_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 300 static u_int 301 openpic_read(struct openpic_softc *sc, int reg) 302 { 303 return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 304 } 305 306 static void 307 openpic_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 312 static int 313 openpic_read_irq(struct openpic_softc *sc, int cpu) 314 { 315 return openpic_read(sc, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK; 316 } 317 318 static void 319 openpic_eoi(struct openpic_softc *sc, int cpu) 320 { 321 openpic_write(sc, OPENPIC_EOI(cpu), 0); 322 } 323 324 static void 325 openpic_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 338 static void 339 openpic_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 348 static void 349 openpic_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 359 static void 360 openpic_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 374 start: 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 390 static void 391 openpic_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 399 static void 400 openpic_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