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