1 /* $NetBSD: ioasic.c,v 1.46 2014/03/26 08:09:06 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 35 * All rights reserved. 36 * 37 * Author: Keith Bostic, Chris G. Demetriou 38 * 39 * Permission to use, copy, modify and distribute this software and 40 * its documentation is hereby granted, provided that both the copyright 41 * notice and this permission notice appear in all copies of the 42 * software, derivative works or modified versions, and any portions 43 * thereof, and that both notices appear in supporting documentation. 44 * 45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 46 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 47 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 48 * 49 * Carnegie Mellon requests users of this software to return to 50 * 51 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 52 * School of Computer Science 53 * Carnegie Mellon University 54 * Pittsburgh PA 15213-3890 55 * 56 * any improvements or extensions that they make and grant Carnegie the 57 * rights to redistribute these changes. 58 */ 59 60 #include "opt_dec_3000_300.h" 61 62 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 63 64 __KERNEL_RCSID(0, "$NetBSD: ioasic.c,v 1.46 2014/03/26 08:09:06 christos Exp $"); 65 66 #include <sys/param.h> 67 #include <sys/kernel.h> 68 #include <sys/systm.h> 69 #include <sys/device.h> 70 #include <sys/malloc.h> 71 72 #include <machine/autoconf.h> 73 #include <sys/bus.h> 74 #include <machine/pte.h> 75 #include <machine/rpb.h> 76 77 #include <dev/tc/tcvar.h> 78 #include <dev/tc/ioasicreg.h> 79 #include <dev/tc/ioasicvar.h> 80 81 /* Definition of the driver for autoconfig. */ 82 int ioasicmatch(device_t, cfdata_t, void *); 83 void ioasicattach(device_t, device_t, void *); 84 85 CFATTACH_DECL_NEW(ioasic, sizeof(struct ioasic_softc), 86 ioasicmatch, ioasicattach, NULL, NULL); 87 88 int ioasic_intr(void *); 89 int ioasic_intrnull(void *); 90 91 #define C(x) ((void *)(x)) 92 93 #define IOASIC_DEV_LANCE 0 94 #define IOASIC_DEV_SCC0 1 95 #define IOASIC_DEV_SCC1 2 96 #define IOASIC_DEV_ISDN 3 97 98 #define IOASIC_DEV_BOGUS -1 99 100 #define IOASIC_NCOOKIES 4 101 102 struct ioasic_dev ioasic_devs[] = { 103 { "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE), 104 IOASIC_INTR_LANCE, }, 105 { "z8530 ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0), 106 IOASIC_INTR_SCC_0, }, 107 { "z8530 ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1), 108 IOASIC_INTR_SCC_1, }, 109 { "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS), 110 0, }, 111 { "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN), 112 IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD, }, 113 }; 114 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]); 115 116 struct ioasicintr { 117 int (*iai_func)(void *); 118 void *iai_arg; 119 struct evcnt iai_evcnt; 120 } ioasicintrs[IOASIC_NCOOKIES]; 121 122 tc_addr_t ioasic_base; /* XXX XXX XXX */ 123 124 /* There can be only one. */ 125 int ioasicfound; 126 127 int 128 ioasicmatch(device_t parent, cfdata_t cf, void *aux) 129 { 130 struct tc_attach_args *ta = aux; 131 132 /* Make sure that we're looking for this type of device. */ 133 if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN)) 134 return (0); 135 136 /* Check that it can actually exist. */ 137 if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) 138 panic("ioasicmatch: how did we get here?"); 139 140 if (ioasicfound) 141 return (0); 142 143 return (1); 144 } 145 146 void 147 ioasicattach(device_t parent, device_t self, void *aux) 148 { 149 struct ioasic_softc *sc = device_private(self); 150 struct tc_attach_args *ta = aux; 151 #ifdef DEC_3000_300 152 u_long ssr; 153 #endif 154 u_long i, imsk; 155 const struct evcnt *pevcnt; 156 char *cp; 157 158 ioasicfound = 1; 159 160 sc->sc_dev = self; 161 sc->sc_bst = ta->ta_memt; 162 if (bus_space_map(ta->ta_memt, ta->ta_addr, 163 0x400000, 0, &sc->sc_bsh)) { 164 printf("%s: unable to map device\n", device_xname(self)); 165 return; 166 } 167 sc->sc_dmat = ta->ta_dmat; 168 169 ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */ 170 171 #ifdef DEC_3000_300 172 if (cputype == ST_DEC_3000_300) { 173 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 174 ssr |= IOASIC_CSR_FASTMODE; 175 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 176 printf(": slow mode\n"); 177 } else 178 #endif 179 printf(": fast mode\n"); 180 181 /* 182 * Turn off all device interrupt bits. 183 * (This does _not_ include 3000/300 TC option slot bits. 184 */ 185 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 186 for (i = 0; i < ioasic_ndevs; i++) 187 imsk &= ~ioasic_devs[i].iad_intrbits; 188 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 189 190 /* 191 * Set up interrupt handlers. 192 */ 193 pevcnt = tc_intr_evcnt(parent, ta->ta_cookie); 194 for (i = 0; i < IOASIC_NCOOKIES; i++) { 195 static const size_t len = 12; 196 ioasicintrs[i].iai_func = ioasic_intrnull; 197 ioasicintrs[i].iai_arg = (void *)i; 198 199 cp = malloc(len, M_DEVBUF, M_NOWAIT); 200 if (cp == NULL) 201 panic("ioasicattach"); 202 snprintf(cp, len, "slot %lu", i); 203 evcnt_attach_dynamic(&ioasicintrs[i].iai_evcnt, 204 EVCNT_TYPE_INTR, pevcnt, device_xname(self), cp); 205 } 206 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_NONE, ioasic_intr, sc); 207 208 /* 209 * Try to configure each device. 210 */ 211 ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs); 212 } 213 214 void 215 ioasic_intr_establish(device_t ioa, void *cookie, tc_intrlevel_t level, 216 int (*func)(void *), void *arg) 217 { 218 struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0); 219 u_long dev, i, imsk; 220 221 dev = (u_long)cookie; 222 #ifdef DIAGNOSTIC 223 /* XXX check cookie. */ 224 #endif 225 226 if (ioasicintrs[dev].iai_func != ioasic_intrnull) 227 panic("ioasic_intr_establish: cookie %lu twice", dev); 228 229 ioasicintrs[dev].iai_func = func; 230 ioasicintrs[dev].iai_arg = arg; 231 232 /* Enable interrupts for the device. */ 233 for (i = 0; i < ioasic_ndevs; i++) 234 if (ioasic_devs[i].iad_cookie == cookie) 235 break; 236 if (i == ioasic_ndevs) 237 panic("ioasic_intr_establish: invalid cookie."); 238 239 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 240 imsk |= ioasic_devs[i].iad_intrbits; 241 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 242 } 243 244 void 245 ioasic_intr_disestablish(device_t ioa, void *cookie) 246 { 247 struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0); 248 u_long dev, i, imsk; 249 250 dev = (u_long)cookie; 251 #ifdef DIAGNOSTIC 252 /* XXX check cookie. */ 253 #endif 254 255 if (ioasicintrs[dev].iai_func == ioasic_intrnull) 256 panic("ioasic_intr_disestablish: cookie %lu missing intr", dev); 257 258 /* Enable interrupts for the device. */ 259 for (i = 0; i < ioasic_ndevs; i++) 260 if (ioasic_devs[i].iad_cookie == cookie) 261 break; 262 if (i == ioasic_ndevs) 263 panic("ioasic_intr_disestablish: invalid cookie."); 264 265 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 266 imsk &= ~ioasic_devs[i].iad_intrbits; 267 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 268 269 ioasicintrs[dev].iai_func = ioasic_intrnull; 270 ioasicintrs[dev].iai_arg = (void *)dev; 271 } 272 273 int 274 ioasic_intrnull(void *val) 275 { 276 277 panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld", 278 (u_long)val); 279 } 280 281 /* 282 * ASIC interrupt handler. 283 */ 284 int 285 ioasic_intr(void *val) 286 { 287 register struct ioasic_softc *sc = val; 288 register int ifound; 289 int gifound; 290 uint32_t sir, osir; 291 292 gifound = 0; 293 do { 294 ifound = 0; 295 tc_syncbus(); 296 297 osir = sir = 298 bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 299 300 #define INCRINTRCNT(slot) ioasicintrs[slot].iai_evcnt.ev_count++ 301 302 /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */ 303 #define CHECKINTR(slot, bits, clear) \ 304 if (sir & (bits)) { \ 305 ifound = 1; \ 306 INCRINTRCNT(slot); \ 307 (*ioasicintrs[slot].iai_func) \ 308 (ioasicintrs[slot].iai_arg); \ 309 if (clear) \ 310 sir &= ~(bits); \ 311 } 312 CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0); 313 CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0); 314 CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0); 315 CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD | 316 IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1); 317 318 if (sir != osir) 319 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 320 IOASIC_INTR, sir); 321 322 gifound |= ifound; 323 } while (ifound); 324 325 return (gifound); 326 } 327