Home | History | Annotate | Line # | Download | only in tc
ioasic.c revision 1.40
      1 /* $NetBSD: ioasic.c,v 1.40 2009/03/14 14:45:54 dsl 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.40 2009/03/14 14:45:54 dsl 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 <machine/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(struct device *, struct cfdata *, void *);
     83 void	ioasicattach(struct device *, struct device *, void *);
     84 
     85 CFATTACH_DECL(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(parent, cfdata, aux)
    129 	struct device *parent;
    130 	struct cfdata *cfdata;
    131 	void *aux;
    132 {
    133 	struct tc_attach_args *ta = aux;
    134 
    135 	/* Make sure that we're looking for this type of device. */
    136 	if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
    137 		return (0);
    138 
    139 	/* Check that it can actually exist. */
    140 	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
    141 		panic("ioasicmatch: how did we get here?");
    142 
    143 	if (ioasicfound)
    144 		return (0);
    145 
    146 	return (1);
    147 }
    148 
    149 void
    150 ioasicattach(parent, self, aux)
    151 	struct device *parent, *self;
    152 	void *aux;
    153 {
    154 	struct ioasic_softc *sc = (struct ioasic_softc *)self;
    155 	struct tc_attach_args *ta = aux;
    156 #ifdef DEC_3000_300
    157 	u_long ssr;
    158 #endif
    159 	u_long i, imsk;
    160 	const struct evcnt *pevcnt;
    161 	char *cp;
    162 
    163 	ioasicfound = 1;
    164 
    165 	sc->sc_bst = ta->ta_memt;
    166 	if (bus_space_map(ta->ta_memt, ta->ta_addr,
    167 			0x400000, 0, &sc->sc_bsh)) {
    168 		printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
    169 		return;
    170 	}
    171 	sc->sc_dmat = ta->ta_dmat;
    172 
    173 	ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
    174 
    175 #ifdef DEC_3000_300
    176 	if (cputype == ST_DEC_3000_300) {
    177 		ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
    178 		ssr |= IOASIC_CSR_FASTMODE;
    179 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
    180 		printf(": slow mode\n");
    181 	} else
    182 #endif
    183 		printf(": fast mode\n");
    184 
    185 	/*
    186 	 * Turn off all device interrupt bits.
    187 	 * (This does _not_ include 3000/300 TC option slot bits.
    188 	 */
    189 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    190 	for (i = 0; i < ioasic_ndevs; i++)
    191 		imsk &= ~ioasic_devs[i].iad_intrbits;
    192 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    193 
    194 	/*
    195 	 * Set up interrupt handlers.
    196 	 */
    197 	pevcnt = tc_intr_evcnt(parent, ta->ta_cookie);
    198 	for (i = 0; i < IOASIC_NCOOKIES; i++) {
    199 		ioasicintrs[i].iai_func = ioasic_intrnull;
    200 		ioasicintrs[i].iai_arg = (void *)i;
    201 
    202 		cp = malloc(12, M_DEVBUF, M_NOWAIT);
    203 		if (cp == NULL)
    204 			panic("ioasicattach");
    205 		sprintf(cp, "slot %lu", i);
    206 		evcnt_attach_dynamic(&ioasicintrs[i].iai_evcnt,
    207 		    EVCNT_TYPE_INTR, pevcnt, self->dv_xname, cp);
    208 	}
    209 	tc_intr_establish(parent, ta->ta_cookie, TC_IPL_NONE, ioasic_intr, sc);
    210 
    211 	/*
    212 	 * Try to configure each device.
    213 	 */
    214 	ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
    215 }
    216 
    217 void
    218 ioasic_intr_establish(device_t ioa, void *cookie, tc_intrlevel_t level,
    219 		int (*func)(void *), void *arg)
    220 {
    221 	struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0);
    222 	u_long dev, i, imsk;
    223 
    224 	dev = (u_long)cookie;
    225 #ifdef DIAGNOSTIC
    226 	/* XXX check cookie. */
    227 #endif
    228 
    229 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
    230 		panic("ioasic_intr_establish: cookie %lu twice", dev);
    231 
    232 	ioasicintrs[dev].iai_func = func;
    233 	ioasicintrs[dev].iai_arg = arg;
    234 
    235 	/* Enable interrupts for the device. */
    236 	for (i = 0; i < ioasic_ndevs; i++)
    237 		if (ioasic_devs[i].iad_cookie == cookie)
    238 			break;
    239 	if (i == ioasic_ndevs)
    240 		panic("ioasic_intr_establish: invalid cookie.");
    241 
    242 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    243         imsk |= ioasic_devs[i].iad_intrbits;
    244         bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    245 }
    246 
    247 void
    248 ioasic_intr_disestablish(device_t ioa, void *cookie)
    249 {
    250 	struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0);
    251 	u_long dev, i, imsk;
    252 
    253 	dev = (u_long)cookie;
    254 #ifdef DIAGNOSTIC
    255 	/* XXX check cookie. */
    256 #endif
    257 
    258 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
    259 		panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
    260 
    261 	/* Enable interrupts for the device. */
    262 	for (i = 0; i < ioasic_ndevs; i++)
    263 		if (ioasic_devs[i].iad_cookie == cookie)
    264 			break;
    265 	if (i == ioasic_ndevs)
    266 		panic("ioasic_intr_disestablish: invalid cookie.");
    267 
    268 	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
    269 	imsk &= ~ioasic_devs[i].iad_intrbits;
    270 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
    271 
    272 	ioasicintrs[dev].iai_func = ioasic_intrnull;
    273 	ioasicintrs[dev].iai_arg = (void *)dev;
    274 }
    275 
    276 int
    277 ioasic_intrnull(val)
    278 	void *val;
    279 {
    280 
    281 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
    282 	    (u_long)val);
    283 }
    284 
    285 /*
    286  * ASIC interrupt handler.
    287  */
    288 int
    289 ioasic_intr(val)
    290 	void *val;
    291 {
    292 	register struct ioasic_softc *sc = val;
    293 	register int ifound;
    294 	int gifound;
    295 	u_int32_t sir, osir;
    296 
    297 	gifound = 0;
    298 	do {
    299 		ifound = 0;
    300 		tc_syncbus();
    301 
    302 		osir = sir =
    303 		    bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
    304 
    305 #define	INCRINTRCNT(slot)	ioasicintrs[slot].iai_evcnt.ev_count++
    306 
    307 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
    308 #define	CHECKINTR(slot, bits, clear)					\
    309 		if (sir & (bits)) {					\
    310 			ifound = 1;					\
    311 			INCRINTRCNT(slot);				\
    312 			(*ioasicintrs[slot].iai_func)			\
    313 			    (ioasicintrs[slot].iai_arg);		\
    314 			if (clear)					\
    315 				sir &= ~(bits);				\
    316 		}
    317 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
    318 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
    319 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
    320 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
    321 		    IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
    322 
    323 		if (sir != osir)
    324 			bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    325 			    IOASIC_INTR, sir);
    326 
    327 		gifound |= ifound;
    328 	} while (ifound);
    329 
    330 	return (gifound);
    331 }
    332