Add another option PCIBIOS_INTR_GUESS for no compatible ICU found case.

Under this option, if only one IRQ is available for the link,
we assumes that the IRQ is already connected, and configure
PCI Interrupt Configuration Register accordingly.
This is what Linux pcmcia-cs-3.1.19 does by default.

This fixes unconfigured pccbb interrupt problem of
Sharp Mebius MN-5500. It's interrupt router is ITExpress Inc. IT8330G.
(http://www.ite.com.tw/, vendor=0x1283, product=0x8330)
Problem reporeted by Kitagawa <sk@kiu.ac.jp> in
http://www.kaynet.or.jp/~kay/ml/netbsd-pcmcia/msg/msg00608.html
This commit is contained in:
soda 2000-08-10 21:18:27 +00:00
parent 3f6d813859
commit b63f6b5096

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci_intr_fixup.c,v 1.9 2000/07/22 17:43:36 soda Exp $ */
/* $NetBSD: pci_intr_fixup.c,v 1.10 2000/08/10 21:18:27 soda Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -95,7 +95,7 @@ struct pciintr_link_map {
SIMPLEQ_ENTRY(pciintr_link_map) list;
};
pciintr_icu_tag_t pciintr_icu_tag;
pciintr_icu_tag_t pciintr_icu_tag = NULL;
pciintr_icu_handle_t pciintr_icu_handle;
#ifdef PCIBIOS_IRQS_HINT
@ -109,6 +109,9 @@ struct pcibios_intr_routing *pciintr_pir_lookup __P((int, int));
static int pciintr_bitmap_count_irq __P((int, int *));
static int pciintr_bitmap_find_lowest_irq __P((int, int *));
int pciintr_link_init __P((void));
#ifdef PCIBIOS_INTR_GUESS
int pciintr_guess_irq __P((void));
#endif
int pciintr_link_fixup __P((void));
int pciintr_link_route __P((u_int16_t *));
int pciintr_irq_release __P((u_int16_t *));
@ -190,39 +193,44 @@ pciintr_link_alloc(pir, pin)
int link = pir->linkmap[pin].link, clink, irq;
struct pciintr_link_map *l, *lstart;
/*
* Get the canonical link value for this entry.
*/
if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, link,
&clink) != 0) {
if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */
/*
* ICU doesn't understand the link value.
* Just ignore this PIR entry.
* Get the canonical link value for this entry.
*/
if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle,
link, &clink) != 0) {
/*
* ICU doesn't understand the link value.
* Just ignore this PIR entry.
*/
#ifdef DIAGNOSTIC
printf("pciintr_link_alloc: bus %d device %d: "
"link 0x%02x invalid\n",
pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link);
printf("pciintr_link_alloc: bus %d device %d: "
"link 0x%02x invalid\n",
pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link);
#endif
return (NULL);
}
return (NULL);
}
/*
* Check the link value by asking the ICU for the canonical link value.
* Also, determine if this PIRQ is mapped to an IRQ.
*/
if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, clink,
&irq) != 0) {
/*
* ICU doesn't understand the canonical link value.
* Just ignore this PIR entry.
* Check the link value by asking the ICU for the
* canonical link value.
* Also, determine if this PIRQ is mapped to an IRQ.
*/
if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle,
clink, &irq) != 0) {
/*
* ICU doesn't understand the canonical link value.
* Just ignore this PIR entry.
*/
#ifdef DIAGNOSTIC
printf("pciintr_link_alloc: bus %d device %d link 0x%02x: "
"PIRQ 0x%02x invalid\n",
pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link, clink);
printf("pciintr_link_alloc: "
"bus %d device %d link 0x%02x: "
"PIRQ 0x%02x invalid\n",
pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link,
clink);
#endif
return (NULL);
return (NULL);
}
}
l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT);
@ -233,8 +241,13 @@ pciintr_link_alloc(pir, pin)
l->link = link;
l->bitmap = pir->linkmap[pin].bitmap;
l->clink = clink;
l->irq = irq; /* may be I386_PCI_INTERRUPT_LINE_NO_CONNECTION */
if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */
l->clink = clink;
l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */
} else {
l->clink = link; /* only for PCIBIOSVERBOSE diagnostic */
l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION;
}
lstart = SIMPLEQ_FIRST(&pciintr_link_map_list);
if (lstart == NULL || lstart->link < l->link)
@ -303,7 +316,7 @@ pciintr_bitmap_find_lowest_irq(irq_bitmap, irqp)
int
pciintr_link_init()
{
int entry, pin, error, link;
int entry, pin, link;
struct pcibios_intr_routing *pir;
struct pciintr_link_map *l;
@ -313,7 +326,6 @@ pciintr_link_init()
return (1);
}
error = 0;
SIMPLEQ_INIT(&pciintr_link_map_list);
for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
@ -352,9 +364,43 @@ pciintr_link_init()
}
}
return (error);
return (0);
}
#ifdef PCIBIOS_INTR_GUESS
/*
* No compatible PCI ICU found.
* Hopes the BIOS already setup the ICU.
*/
int
pciintr_guess_irq()
{
struct pciintr_link_map *l;
int irq, guessed = 0;
/*
* Stage 1: If only one IRQ is available for the link, use it.
*/
for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
l = SIMPLEQ_NEXT(l, list)) {
if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
continue;
if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) {
l->irq = irq;
l->fixup_stage = 1;
#ifdef PCIINTR_DEBUG
printf("pciintr_guess_irq (stage 1): "
"guessing PIRQ 0x%02x to be IRQ %d\n",
l->clink, l->irq);
#endif
guessed = 1;
}
}
return (guessed ? 0 : -1);
}
#endif /* PCIBIOS_INTR_GUESS */
int
pciintr_link_fixup()
{
@ -610,7 +656,17 @@ pciintr_do_header_fixup(pc, tag)
if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
/* Appropriate interrupt was not found. */
PCIBIOS_PRINTV((" WARNING: missing IRQ\n"));
if (pciintr_icu_tag == NULL &&
irq != 0 && irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
/*
* Do not print warning,
* if no compatible PCI ICU found,
* but the irq is already assigned by BIOS.
*/
PCIBIOS_PRINTV(("\n"));
} else {
PCIBIOS_PRINTV((" WARNING: missing IRQ\n"));
}
return;
}
@ -628,7 +684,7 @@ pciintr_do_header_fixup(pc, tag)
/* believe PCI IRQ Routing table */
PCIBIOS_PRINTV((" WARNING: overriding irq %d\n", irq));
#else
/* believe PCI Interrupt Configuration Register (default) */
/* believe PCI Interrupt Configuration Register (default) */
PCIBIOS_PRINTV((" WARNING: preserving irq %d\n", irq));
return;
#endif
@ -696,8 +752,22 @@ pci_intr_fixup(pc, iot, pciirq)
}
if (piit == NULL) {
printf("pci_intr_fixup: no compatible PCI ICU found\n");
printf("pci_intr_fixup: no compatible PCI ICU found");
if (pcibios_pir_header.signature != 0 && icuid != 0)
printf(": ICU vendor 0x%04x product 0x%04x",
PCI_VENDOR(icuid), PCI_PRODUCT(icuid));
printf("\n");
#ifdef PCIBIOS_INTR_GUESS
if (pciintr_link_init())
return (-1); /* non-fatal */
if (pciintr_guess_irq())
return (-1); /* non-fatal */
if (pciintr_header_fixup(pc))
return (1); /* fatal */
return (0); /* success! */
#else
return (-1); /* non-fatal */
#endif
}
/*