Home | History | Annotate | Line # | Download | only in pci
pcib.c revision 1.18.66.1
      1 /*	$NetBSD: pcib.c,v 1.18.66.1 2008/05/16 02:21:44 yamt 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.18.66.1 2008/05/16 02:21:44 yamt 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(self)
    293 	struct device *self;
    294 {
    295 	struct pcib_softc *sc = (struct pcib_softc *)self;
    296 	struct isabus_attach_args iba;
    297 
    298 	memset(&iba, 0, sizeof(iba));
    299 
    300 #if defined(ALGOR_P5064)
    301 	    {
    302 		struct p5064_config *acp = &p5064_configuration;
    303 
    304 		iba.iba_iot = &acp->ac_iot;
    305 		iba.iba_memt = &acp->ac_memt;
    306 		iba.iba_dmat = &acp->ac_isa_dmat;
    307 	    }
    308 #elif defined(ALGOR_P6032)
    309 	    {
    310 		struct p6032_config *acp = &p6032_configuration;
    311 
    312 		iba.iba_iot = &acp->ac_iot;
    313 		iba.iba_memt = &acp->ac_memt;
    314 		iba.iba_dmat = &acp->ac_isa_dmat;
    315 	    }
    316 #endif
    317 
    318 	iba.iba_ic = &sc->sc_ic;
    319 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
    320 
    321 	(void) config_found_ia(&sc->sc_dev, "isabus", &iba, isabusprint);
    322 }
    323 
    324 void
    325 pcib_isa_attach_hook(struct device *parent, struct device *self,
    326     struct isabus_attach_args *iba)
    327 {
    328 
    329 	/* Nothing to do. */
    330 }
    331 
    332 void
    333 pcib_set_icus(struct pcib_softc *sc)
    334 {
    335 
    336 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
    337 	if ((sc->sc_imask & 0xff00) != 0xff00)
    338 		sc->sc_imask &= ~(1U << 2);
    339 	else
    340 		sc->sc_imask |= (1U << 2);
    341 
    342 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
    343 	    sc->sc_imask & 0xff);
    344 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
    345 	    (sc->sc_imask >> 8) & 0xff);
    346 
    347 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    348 	    sc->sc_elcr & 0xff);
    349 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    350 	    (sc->sc_elcr >> 8) & 0xff);
    351 }
    352 
    353 int
    354 pcib_intr(void *v)
    355 {
    356 	struct pcib_softc *sc = v;
    357 	struct algor_intrhand *ih;
    358 	int irq;
    359 
    360 	for (;;) {
    361 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    362 		    OCW3_SELECT | OCW3_POLL);
    363 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
    364 		if ((irq & OCW3_POLL_PENDING) == 0)
    365 			return (1);
    366 
    367 		irq = OCW3_POLL_IRQ(irq);
    368 
    369 		if (irq == 2) {
    370 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    371 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
    372 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
    373 			    PIC_OCW3);
    374 			if (irq & OCW3_POLL_PENDING)
    375 				irq = OCW3_POLL_IRQ(irq) + 8;
    376 			else
    377 				irq = 2;
    378 		}
    379 
    380 		sc->sc_intrtab[irq].intr_count.ev_count++;
    381 		for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
    382 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
    383 			(*ih->ih_func)(ih->ih_arg);
    384 		}
    385 
    386 		/* Send a specific EOI to the 8259. */
    387 		if (irq > 7) {
    388 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    389 			    PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
    390 			    OCW2_ILS(irq & 7));
    391 			irq = 2;
    392 		}
    393 
    394 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
    395 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
    396 	}
    397 }
    398 
    399 const struct evcnt *
    400 pcib_isa_intr_evcnt(void *v, int irq)
    401 {
    402 	struct pcib_softc *sc = v;
    403 
    404 #if defined(ALGOR_P5064)
    405 	if (p5064_isa_to_irqmap[irq] != -1)
    406 		return (isa_intr_evcnt(sc->sc_parent_ic, irq));
    407 #endif
    408 
    409 	return (&sc->sc_intrtab[irq].intr_count);
    410 }
    411 
    412 void *
    413 pcib_isa_intr_establish(void *v, int irq, int type, int level,
    414     int (*func)(void *), void *arg)
    415 {
    416 	struct pcib_softc *sc = v;
    417 	struct algor_intrhand *ih;
    418 	int s;
    419 
    420 	if (irq > 15 || irq == 2 || type == IST_NONE)
    421 		panic("pcib_isa_intr_establish: bad irq or type");
    422 
    423 #if defined(ALGOR_P5064)
    424 	if (p5064_isa_to_irqmap[irq] != -1)
    425 		return (isa_intr_establish(sc->sc_parent_ic, irq, type,
    426 		    level, func, arg));
    427 #endif
    428 
    429 	switch (sc->sc_intrtab[irq].intr_type) {
    430 	case IST_NONE:
    431 		sc->sc_intrtab[irq].intr_type = type;
    432 		break;
    433 
    434 	case IST_EDGE:
    435 	case IST_LEVEL:
    436 		if (type == sc->sc_intrtab[irq].intr_type)
    437 			break;
    438 		/* FALLTHROUGH */
    439 	case IST_PULSE:
    440 		/*
    441 		 * We can't share interrupts in this case.
    442 		 */
    443 		return (NULL);
    444 	}
    445 
    446 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    447 	if (ih == NULL)
    448 		return (NULL);
    449 
    450 	ih->ih_func = func;
    451 	ih->ih_arg = arg;
    452 	ih->ih_irq = irq;
    453 	ih->ih_irqmap = NULL;
    454 
    455 	s = splhigh();
    456 
    457 	/* Insert the handler into the table. */
    458 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
    459 	sc->sc_intrtab[irq].intr_type = type;
    460 
    461 	/* Enable it, set trigger mode. */
    462 	sc->sc_imask &= ~(1 << irq);
    463 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
    464 		sc->sc_elcr |= (1 << irq);
    465 	else
    466 		sc->sc_elcr &= ~(1 << irq);
    467 
    468 	pcib_set_icus(sc);
    469 
    470 	splx(s);
    471 
    472 	return (ih);
    473 }
    474 
    475 void
    476 pcib_isa_intr_disestablish(void *v, void *arg)
    477 {
    478 	struct pcib_softc *sc = v;
    479 	struct algor_intrhand *ih = arg;
    480 	int s;
    481 
    482 #if defined(ALGOR_P5064)
    483 	if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
    484 		isa_intr_disestablish(sc->sc_parent_ic, ih);
    485 		return;
    486 	}
    487 #endif
    488 
    489 	s = splhigh();
    490 
    491 	LIST_REMOVE(ih, ih_q);
    492 
    493 	/* If there are no more handlers on this IRQ, disable it. */
    494 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
    495 		sc->sc_imask |= (1 << ih->ih_irq);
    496 		pcib_set_icus(sc);
    497 	}
    498 
    499 	splx(s);
    500 
    501 	free(ih, M_DEVBUF);
    502 }
    503 
    504 int
    505 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
    506 {
    507 	struct pcib_softc *sc = v;
    508 	int i, tmp, bestirq, count;
    509 	struct algor_intrhand *ih;
    510 
    511 	if (type == IST_NONE)
    512 		panic("pcib_intr_alloc: bogus type");
    513 
    514 	bestirq = -1;
    515 	count = -1;
    516 
    517 	mask &= ~sc->sc_reserved;
    518 
    519 #if 0
    520 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
    521 #endif
    522 
    523 	for (i = 0; i < 16; i++) {
    524 		if ((mask & (1 << i)) == 0)
    525 			continue;
    526 
    527 		switch (sc->sc_intrtab[i].intr_type) {
    528 		case IST_NONE:
    529 			/*
    530 			 * If nothing's using the IRQ, just return it.
    531 			 */
    532 			*irq = i;
    533 			return (0);
    534 
    535 		case IST_EDGE:
    536 		case IST_LEVEL:
    537 			if (type != sc->sc_intrtab[i].intr_type)
    538 				continue;
    539 			/*
    540 			 * If the IRQ is sharable, count the number of
    541 			 * other handlers, and if it's smaller than the
    542 			 * last IRQ like this, remember it.
    543 			 */
    544 			tmp = 0;
    545 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
    546 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
    547 				tmp++;
    548 			if (bestirq == -1 || count > tmp) {
    549 				bestirq = i;
    550 				count = tmp;
    551 			}
    552 			break;
    553 
    554 		case IST_PULSE:
    555 			/* This just isn't sharable. */
    556 			continue;
    557 		}
    558 	}
    559 
    560 	if (bestirq == -1)
    561 		return (1);
    562 
    563 	*irq = bestirq;
    564 	return (0);
    565 }
    566