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