Home | History | Annotate | Line # | Download | only in tc
ioasic.c revision 1.46.10.1
      1 /* $NetBSD: ioasic.c,v 1.46.10.1 2016/07/19 06:26:58 pgoyette 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 (at) 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.10.1 2016/07/19 06:26:58 pgoyette 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 	device_t self;
    219 	struct ioasic_softc *sc;
    220 	u_long dev, i, imsk;
    221 
    222 	self = device_lookup_acquire(&ioasic_cd, 0);
    223 	if (self == NULL)
    224 		return;
    225 	sc = device_private(self);
    226 	if (sc == NULL) {
    227 		device_release(self);
    228 		return;
    229 	}
    230 
    231 	dev = (u_long)cookie;
    232 #ifdef DIAGNOSTIC
    233 	/* XXX check cookie. */
    234 #endif
    235 
    236 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
    237 		panic("ioasic_intr_establish: cookie %lu twice", dev);
    238 
    239 	ioasicintrs[dev].iai_func = func;
    240 	ioasicintrs[dev].iai_arg = arg;
    241 
    242 	/* Enable interrupts for the device. */
    243 	for (i = 0; i < ioasic_ndevs; i++)
    244 		if (ioasic_devs[i].iad_cookie == cookie)
    245 			break;
    246 	if (i == ioasic_ndevs)
    247 		panic("ioasic_intr_establish: invalid cookie.");
    248 
    249 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    250 	imsk |= ioasic_devs[i].iad_intrbits;
    251 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    252 
    253 	device_release(self);
    254 }
    255 
    256 void
    257 ioasic_intr_disestablish(device_t ioa, void *cookie)
    258 {
    259 	device_t self;
    260 	struct ioasic_softc *sc;
    261 	u_long dev, i, imsk;
    262 
    263 	self = device_lookup_acquire(&ioasic_cd, 0);
    264 	if (self == NULL)
    265 		return;
    266 	sc = device_private(self);
    267 	if (sc == NULL) {
    268 		device_release(self);
    269 		return;
    270 	}
    271 
    272 	dev = (u_long)cookie;
    273 #ifdef DIAGNOSTIC
    274 	/* XXX check cookie. */
    275 #endif
    276 
    277 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
    278 		panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
    279 
    280 	/* Enable interrupts for the device. */
    281 	for (i = 0; i < ioasic_ndevs; i++)
    282 		if (ioasic_devs[i].iad_cookie == cookie)
    283 			break;
    284 	if (i == ioasic_ndevs)
    285 		panic("ioasic_intr_disestablish: invalid cookie.");
    286 
    287 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    288 	imsk &= ~ioasic_devs[i].iad_intrbits;
    289 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    290 
    291 	ioasicintrs[dev].iai_func = ioasic_intrnull;
    292 	ioasicintrs[dev].iai_arg = (void *)dev;
    293 
    294 	device_release(self);
    295 }
    296 
    297 int
    298 ioasic_intrnull(void *val)
    299 {
    300 
    301 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
    302 	    (u_long)val);
    303 }
    304 
    305 /*
    306  * ASIC interrupt handler.
    307  */
    308 int
    309 ioasic_intr(void *val)
    310 {
    311 	register struct ioasic_softc *sc = val;
    312 	register int ifound;
    313 	int gifound;
    314 	uint32_t sir, osir;
    315 
    316 	gifound = 0;
    317 	do {
    318 		ifound = 0;
    319 		tc_syncbus();
    320 
    321 		osir = sir =
    322 		    bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
    323 
    324 #define	INCRINTRCNT(slot)	ioasicintrs[slot].iai_evcnt.ev_count++
    325 
    326 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
    327 #define	CHECKINTR(slot, bits, clear)					\
    328 		if (sir & (bits)) {					\
    329 			ifound = 1;					\
    330 			INCRINTRCNT(slot);				\
    331 			(*ioasicintrs[slot].iai_func)			\
    332 			    (ioasicintrs[slot].iai_arg);		\
    333 			if (clear)					\
    334 				sir &= ~(bits);				\
    335 		}
    336 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
    337 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
    338 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
    339 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
    340 		    IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
    341 
    342 		if (sir != osir)
    343 			bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    344 			    IOASIC_INTR, sir);
    345 
    346 		gifound |= ifound;
    347 	} while (ifound);
    348 
    349 	return (gifound);
    350 }
    351