Home | History | Annotate | Line # | Download | only in pci
pcib.c revision 1.3
      1 /*	$NetBSD: pcib.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000, 2001 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.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     40 
     41 __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $");
     42 
     43 #include "opt_algor_p5064.h"
     44 #include "opt_algor_p6032.h"
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/kernel.h>
     49 #include <sys/device.h>
     50 #include <sys/malloc.h>
     51 
     52 #include <machine/intr.h>
     53 #include <machine/bus.h>
     54 
     55 #include <dev/isa/isareg.h>
     56 #include <dev/isa/isavar.h>
     57 
     58 #include <dev/pci/pcireg.h>
     59 #include <dev/pci/pcivar.h>
     60 #include <dev/pci/pcidevs.h>
     61 
     62 #ifdef ALGOR_P5064
     63 #include <algor/algor/algor_p5064var.h>
     64 #endif
     65 
     66 #ifdef ALGOR_P6032
     67 #include <algor/algor/algor_p6032var.h>
     68 #endif
     69 
     70 const char *pcib_intrnames[16] = {
     71 	"irq 0",
     72 	"irq 1",
     73 	"irq 2",
     74 	"irq 3",
     75 	"irq 4",
     76 	"irq 5",
     77 	"irq 6",
     78 	"irq 7",
     79 	"irq 8",
     80 	"irq 9",
     81 	"irq 10",
     82 	"irq 11",
     83 	"irq 12",
     84 	"irq 13",
     85 	"irq 14",
     86 	"irq 15",
     87 };
     88 
     89 struct pcib_intrhead {
     90 	LIST_HEAD(, algor_intrhand) intr_q;
     91 	struct evcnt intr_count;
     92 	int intr_type;
     93 };
     94 
     95 struct pcib_softc {
     96 	struct device	sc_dev;
     97 
     98 	bus_space_tag_t	sc_iot;
     99 	bus_space_handle_t sc_ioh_icu1;
    100 	bus_space_handle_t sc_ioh_icu2;
    101 	bus_space_handle_t sc_ioh_elcr;
    102 
    103 	struct algor_isa_chipset sc_ic;
    104 
    105 	struct pcib_intrhead sc_intrtab[16];
    106 
    107 	u_int16_t	sc_inten;
    108 	u_int16_t	sc_elcr;
    109 
    110 #if defined(ALGOR_P5064)
    111 	isa_chipset_tag_t sc_parent_ic;
    112 	u_int16_t	sc_reserved;
    113 #endif
    114 
    115 	void		*sc_ih;
    116 };
    117 
    118 int	pcib_match(struct device *, struct cfdata *, void *);
    119 void	pcib_attach(struct device *, struct device *, void *);
    120 
    121 struct cfattach pcib_ca = {
    122 	sizeof(struct pcib_softc), pcib_match, pcib_attach,
    123 };
    124 
    125 int	pcib_print(void *, const char *pnp);
    126 void	pcib_isa_attach_hook(struct device *, struct device *,
    127 	    struct isabus_attach_args *);
    128 
    129 int	pcib_intr(void *);
    130 
    131 void	pcib_bridge_callback(struct device *);
    132 
    133 const struct evcnt *pcib_isa_intr_evcnt(void *, int);
    134 void	*pcib_isa_intr_establish(void *, int, int, int,
    135 	    int (*)(void *), void *);
    136 void	pcib_isa_intr_disestablish(void *, void *);
    137 int	pcib_isa_intr_alloc(void *, int, int, int *);
    138 
    139 void	pcib_set_icus(struct pcib_softc *);
    140 
    141 int
    142 pcib_match(struct device *parent, struct cfdata *match, void *aux)
    143 {
    144 	struct pci_attach_args *pa = aux;
    145 
    146 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
    147 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
    148 		return (1);
    149 
    150 	return (0);
    151 }
    152 
    153 void
    154 pcib_attach(struct device *parent, struct device *self, void *aux)
    155 {
    156 	struct pcib_softc *sc = (void *) self;
    157 	struct pci_attach_args *pa = aux;
    158 	char devinfo[256];
    159 	int i;
    160 
    161 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
    162 	printf(": %s (rev. 0x%02x)\n", devinfo,
    163 	    PCI_REVISION(pa->pa_class));
    164 
    165 	sc->sc_iot = pa->pa_iot;
    166 
    167 	/*
    168 	 * Map the PIC/ELCR registers.
    169 	 */
    170 	if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
    171 		printf("%s: unable to map ELCR registers\n",
    172 		    sc->sc_dev.dv_xname);
    173 	if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
    174 		printf("%s: unable to map ICU1 registers\n",
    175 		    sc->sc_dev.dv_xname);
    176 	if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
    177 		printf("%s: unable to map ICU2 registers\n",
    178 		    sc->sc_dev.dv_xname);
    179 
    180 	/*
    181 	 * Initialize the 8259s.
    182 	 */
    183 
    184 	/* ICW1: reset; program device, 4 bytes */
    185 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x11);
    186 
    187 	/* ICW2: vector base address */
    188 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 32/*XXX*/);
    189 
    190 	/* ICW3: cascade mode */
    191 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 0x04);
    192 
    193 	/* ICW4: 8086 mode */
    194 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 0x01);
    195 
    196 	/* OCW1: mask all interrupts */
    197 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1,
    198 	    ~sc->sc_inten & 0xff);
    199 
    200 	/* OCW3: enable special mask mode */
    201 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x68);
    202 
    203 	/* OCW3: read IRR by default */
    204 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x0a);
    205 
    206 
    207 	/* ICW1: reset; program device, 4 bytes */
    208 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x11);
    209 
    210 	/* ICW2: vector base address */
    211 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 32+8/*XXX*/);
    212 
    213 	/* ICW3: slave ID code */
    214 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 0x02);
    215 
    216 	/* ICW4: 8086 mode */
    217 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 0x01);
    218 
    219 	/* OCW1: mask all interrupts */
    220 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1,
    221 	    (~sc->sc_inten >> 8) & 0xff);
    222 
    223 	/* OCW3: enable special mask mode */
    224 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x68);
    225 
    226 	/* OCW3: read IRR by default */
    227 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x0a);
    228 
    229 	/*
    230 	 * Default all interrupts to edge-triggered.
    231 	 */
    232 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    233 	    sc->sc_elcr & 0xff);
    234 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    235 	    (sc->sc_elcr >> 8) & 0xff);
    236 
    237 #if defined(ALGOR_P5064)
    238 	/*
    239 	 * Some "ISA" interrupts are a little wacky, wired up directly
    240 	 * to the P-5064 interrupt controller.
    241 	 */
    242 	sc->sc_reserved =
    243 		(1 << 1) |
    244 		(1 << 3) |
    245 		(1 << 4) |
    246 		(1 << 6) |
    247 		(1 << 7) |
    248 		(1 << 8) |
    249 		(1 << 12) |
    250 		(1 << 14) |
    251 		(1 << 15);
    252 
    253 	sc->sc_parent_ic = &p5064_configuration.ac_ic;
    254 #endif /* ALGOR_P5064 */
    255 
    256 	/* Set up our ISA chipset. */
    257 	sc->sc_ic.ic_v = sc;
    258 	sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
    259 	sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
    260 	sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
    261 	sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
    262 
    263 	/* Initialize our interrupt table. */
    264 	for (i = 0; i < 16; i++) {
    265 		LIST_INIT(&sc->sc_intrtab[i].intr_q);
    266 		evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
    267 		    EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
    268 		sc->sc_intrtab[i].intr_type = IST_NONE;
    269 	}
    270 
    271 	/* Hook up our interrupt handler. */
    272 #if defined(ALGOR_P5064)
    273 	sc->sc_ih = algor_p5064_intr_establish(&p5064_irqmap[
    274 	    P5064_IRQ_ISABRIDGE], pcib_intr, sc);
    275 #elif defined(ALGOR_P6032)
    276 	sc->sc_ih = algor_p6032_intr_establish(&p6032_irqmap[XXX],
    277 	    pcib_intr, sc);
    278 #endif
    279 	if (sc->sc_ih == NULL)
    280 		printf("%s: WARNING: unable to register interrupt handler\n",
    281 		    sc->sc_dev.dv_xname);
    282 
    283 	config_defer(self, pcib_bridge_callback);
    284 }
    285 
    286 void
    287 pcib_bridge_callback(self)
    288 	struct device *self;
    289 {
    290 	struct pcib_softc *sc = (struct pcib_softc *)self;
    291 	struct isabus_attach_args iba;
    292 
    293 	memset(&iba, 0, sizeof(iba));
    294 
    295 	iba.iba_busname = "isa";
    296 #if defined(ALGOR_P5064)
    297 	    {
    298 		struct p5064_config *acp = &p5064_configuration;
    299 
    300 		iba.iba_iot = &acp->ac_iot;
    301 		iba.iba_memt = &acp->ac_memt;
    302 		iba.iba_dmat = &acp->ac_isa_dmat;
    303 		iba.iba_ic = &acp->ac_ic;
    304 	    }
    305 #elif defined(ALGOR_P6032)
    306 	    {
    307 		/* XXX */
    308 	    }
    309 #endif
    310 
    311 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
    312 
    313 	(void) config_found(&sc->sc_dev, &iba, pcib_print);
    314 }
    315 
    316 int
    317 pcib_print(void *aux, const char *pnp)
    318 {
    319 	struct isabus_attach_args *iba;
    320 
    321 	if (pnp)
    322 		printf("%s at %s", iba->iba_busname, pnp);
    323 	return (UNCONF);
    324 }
    325 
    326 void
    327 pcib_isa_attach_hook(struct device *parent, struct device *self,
    328     struct isabus_attach_args *iba)
    329 {
    330 
    331 	/* Nothing to do. */
    332 }
    333 
    334 void
    335 pcib_set_icus(struct pcib_softc *sc)
    336 {
    337 
    338 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
    339 	if (sc->sc_inten & 0xff00)
    340 		sc->sc_inten |= (1 << 2);
    341 	else
    342 		sc->sc_inten &= ~(1 << 2);
    343 
    344 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1,
    345 	    ~sc->sc_inten & 0xff);
    346 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1,
    347 	    (~sc->sc_inten >> 8) & 0xff);
    348 
    349 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    350 	    sc->sc_elcr & 0xff);
    351 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    352 	    (sc->sc_elcr >> 8) & 0xff);
    353 }
    354 
    355 int
    356 pcib_intr(void *v)
    357 {
    358 	struct pcib_softc *sc = v;
    359 	struct algor_intrhand *ih;
    360 	u_int16_t ipending;
    361 	int i;
    362 
    363 	ipending = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, 0) |
    364 	    (bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 0) << 8);
    365 	ipending &= (sc->sc_inten & ~0x02);
    366 	if (ipending == 0)
    367 		return (0);
    368 
    369 	for (i = 0; i < 16; i++) {
    370 		if ((ipending & (1 << i)) == 0)
    371 			continue;
    372 		sc->sc_intrtab[i].intr_count.ev_count++;
    373 		for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
    374 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
    375 			(*ih->ih_func)(ih->ih_arg);
    376 		}
    377 
    378 		/* Send a specific EOI to the 8259. */
    379 		if (i > 7)
    380 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    381 			    0, 0x20 | (i & 0x07));
    382 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0,
    383 		    0x20 | (i > 7 ? 2 : i));
    384 	}
    385 
    386 	return (1);
    387 }
    388 
    389 const struct evcnt *
    390 pcib_isa_intr_evcnt(void *v, int irq)
    391 {
    392 	struct pcib_softc *sc = v;
    393 
    394 	return (&sc->sc_intrtab[irq].intr_count);
    395 }
    396 
    397 void *
    398 pcib_isa_intr_establish(void *v, int irq, int type, int level,
    399     int (*func)(void *), void *arg)
    400 {
    401 	struct pcib_softc *sc = v;
    402 	struct algor_intrhand *ih;
    403 	int s;
    404 
    405 	if (irq > 15 || irq == 2 || type == IST_NONE)
    406 		panic("pcib_isa_intr_establish: bad irq or type");
    407 
    408 #if defined(ALGOR_P5064)
    409 	if (sc->sc_reserved & (1 << irq)) {
    410 		ih = isa_intr_establish(sc->sc_parent_ic, irq, type,
    411 		    level, func, arg);
    412 		if (ih != NULL)
    413 			ih->ih_irq = irq;
    414 	}
    415 #endif
    416 
    417 	switch (sc->sc_intrtab[irq].intr_type) {
    418 	case IST_NONE:
    419 		sc->sc_intrtab[irq].intr_type = type;
    420 		break;
    421 
    422 	case IST_EDGE:
    423 	case IST_LEVEL:
    424 		if (type == sc->sc_intrtab[irq].intr_type)
    425 			break;
    426 		/* FALLTHROUGH */
    427 	case IST_PULSE:
    428 		/*
    429 		 * We can't share interrupts in this case.
    430 		 */
    431 		return (NULL);
    432 	}
    433 
    434 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    435 	if (ih == NULL)
    436 		return (NULL);
    437 
    438 	ih->ih_func = func;
    439 	ih->ih_arg = arg;
    440 	ih->ih_irq = irq;
    441 	ih->ih_irqmap = NULL;
    442 
    443 	s = splhigh();
    444 
    445 	/* Insert the handler into the table. */
    446 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
    447 	sc->sc_intrtab[irq].intr_type = type;
    448 
    449 	/* Enable it, set trigger mode. */
    450 	sc->sc_inten |= (1 << irq);
    451 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
    452 		sc->sc_elcr |= (1 << irq);
    453 	else
    454 		sc->sc_elcr &= ~(1 << irq);
    455 
    456 	pcib_set_icus(sc);
    457 
    458 	splx(s);
    459 
    460 	return (ih);
    461 }
    462 
    463 void
    464 pcib_isa_intr_disestablish(void *v, void *arg)
    465 {
    466 	struct pcib_softc *sc = v;
    467 	struct algor_intrhand *ih = arg;
    468 	int s;
    469 
    470 #if defined(ALGOR_P5064)
    471 	if (sc->sc_reserved & (1 << ih->ih_irq)) {
    472 		isa_intr_disestablish(sc->sc_parent_ic, ih);
    473 		return;
    474 	}
    475 #endif
    476 
    477 	s = splhigh();
    478 
    479 	LIST_REMOVE(ih, ih_q);
    480 
    481 	/* If there are no more handlers on this IRQ, disable it. */
    482 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
    483 		sc->sc_inten &= ~(1 << ih->ih_irq);
    484 		pcib_set_icus(sc);
    485 	}
    486 
    487 	splx(s);
    488 
    489 	free(ih, M_DEVBUF);
    490 }
    491 
    492 int
    493 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
    494 {
    495 	struct pcib_softc *sc = v;
    496 	int i, tmp, bestirq, count;
    497 	struct algor_intrhand *ih;
    498 
    499 	if (type == IST_NONE)
    500 		panic("pcib_intr_alloc: bogus type");
    501 
    502 	bestirq = -1;
    503 	count = -1;
    504 
    505 #if defined(ALGOR_P5064)
    506 	mask &= ~sc->sc_reserved;
    507 #endif
    508 
    509 	for (i = 0; i < 16; i++) {
    510 		if (i == 2 || (mask & (1 << i)) == 0)
    511 			continue;
    512 
    513 		switch (sc->sc_intrtab[i].intr_type) {
    514 		case IST_NONE:
    515 			/*
    516 			 * If nothing's using the IRQ, just return it.
    517 			 */
    518 			*irq = i;
    519 			return (0);
    520 
    521 		case IST_EDGE:
    522 		case IST_LEVEL:
    523 			if (type != sc->sc_intrtab[i].intr_type)
    524 				continue;
    525 			/*
    526 			 * If the IRQ is sharable, count the number of
    527 			 * other handlers, and if it's smaller than the
    528 			 * last IRQ like this, remember it.
    529 			 */
    530 			tmp = 0;
    531 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
    532 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
    533 				tmp++;
    534 			if (bestirq == -1 || count > tmp) {
    535 				bestirq = i;
    536 				count = tmp;
    537 			}
    538 			break;
    539 
    540 		case IST_PULSE:
    541 			/* This just isn't sharable. */
    542 			continue;
    543 		}
    544 	}
    545 
    546 	if (bestirq == -1)
    547 		return (1);
    548 
    549 	*irq = bestirq;
    550 	return (0);
    551 }
    552