diff options
-rw-r--r-- | sys/pccard/pcic.c | 2 | ||||
-rw-r--r-- | sys/pccard/pcic_pci.c | 103 |
2 files changed, 71 insertions, 34 deletions
diff --git a/sys/pccard/pcic.c b/sys/pccard/pcic.c index 252689e..3aafbdb 100644 --- a/sys/pccard/pcic.c +++ b/sys/pccard/pcic.c @@ -388,6 +388,7 @@ pcic_attach(device_t dev) /* Check for changes */ sp->slt->laststate = sp->slt->state = empty; + sp->putb(sp, PCIC_POWER, 0); if (pcic_boot_deactivated) { if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) == PCIC_CD) { sp->slt->state = inactive; @@ -1282,7 +1283,6 @@ int pcic_isa_mapirq(struct pcic_slot *sp, int irq) { irq = host_irq_to_pcic(irq); - sp->sc->chip->func_intr_way(sp, pcic_iw_isa); if (irq == 0) pcic_clrb(sp, PCIC_INT_GEN, 0xF); else diff --git a/sys/pccard/pcic_pci.c b/sys/pccard/pcic_pci.c index 7518e95..fbd200d 100644 --- a/sys/pccard/pcic_pci.c +++ b/sys/pccard/pcic_pci.c @@ -65,7 +65,8 @@ static int pcic_ignore_function_1 = 0; TUNABLE_INT("hw.pcic.ignore_function_1", &pcic_ignore_function_1); SYSCTL_INT(_hw_pcic, OID_AUTO, ignore_function_1, CTLFLAG_RD, &pcic_ignore_function_1, 0, - "When set, driver ignores pci function 1 of the bridge"); + "When set, driver ignores pci function 1 of the bridge. This option\n\ +is obsolete and will be deleted before FreeBSD 4.8."); /* * The following should be a hint, so we can do it on a per device @@ -76,22 +77,37 @@ SYSCTL_INT(_hw_pcic, OID_AUTO, ignore_function_1, CTLFLAG_RD, static int pcic_intr_path = (int)pcic_iw_pci; TUNABLE_INT("hw.pcic.intr_path", &pcic_intr_path); SYSCTL_INT(_hw_pcic, OID_AUTO, intr_path, CTLFLAG_RD, &pcic_intr_path, 0, - "Which path to send the interrupts over."); + "Which path to send the interrupts over. Normally interrupts for\n\ +cardbus bridges are routed over the PCI bus (2). However, some laptops\n\ +will hang when using PCI interrupts due to bugs in this code. Those\n\ +bugs can be worked around by forcings ISA interrupts (1)."); static int pcic_init_routing = 0; TUNABLE_INT("hw.pcic.init_routing", &pcic_init_routing); SYSCTL_INT(_hw_pcic, OID_AUTO, init_routing, CTLFLAG_RD, &pcic_init_routing, 0, "Force the interrupt routing to be initialized on those bridges where\n\ -doing so will cause probelms. Often when no interrupts appear to be routed\n\ -setting this tunable to 1 will resolve the problem. PCI Cards will almost\n\ -always require this, while builtin bridges need it less often"); +doing so will cause probelms. This is very rare and generally is not\n\ +needed. The default of 0 is almost always appropriate. Only set to 1 if\n\ +instructed to do so for debugging. This option is obsolete and will be\n\ +deleted before FreeBSD 4.8."); static int pcic_ignore_pci = 0; TUNABLE_INT("hw.pcic.ignore_pci", &pcic_ignore_pci); SYSCTL_INT(_hw_pcic, OID_AUTO, ignore_pci, CTLFLAG_RD, &pcic_ignore_pci, 0, - "When set, driver ignores pci cardbus bridges it would otherwise claim."); + "When set, driver ignores pci cardbus bridges it would otherwise claim.\n\ +Generally speaking, this option is not needed for anything other than as an\n\ +aid in debugging."); + +static int pcic_pd6729_intr_path = (int)pcic_iw_isa; +TUNABLE_INT("hw.pcic.pd6729_intr_path", &pcic_pd6729_intr_path); +SYSCTL_INT(_hw_pcic, OID_AUTO, pd6729_intr_path, CTLFLAG_RD, + &pcic_pd6729_intr_path, 0, + "For Cirrus Logic PD6729 and similar I/O space based pcmcia bridges, this\n\ +tells the code if it is wired onto a PCI expansion card (2), or if it is\n\ +installed in a laptop (1). This is similar to hw.pcic.intr_path, but\n\ +separate so that it can default to ISA when intr_path defaults to PCI."); static void pcic_pci_cardbus_init(device_t); static pcic_intr_way_t pcic_pci_gen_func; @@ -454,15 +470,25 @@ pcic_pci_oz68xx_init(device_t dev) /* * The Cirrus Logic PD6729/30. These are weird beasts, so be careful. + * They are ISA parts glued to the PCI bus and do not follow the yenta + * specification for cardbus bridges. They seem to be similar to the + * intel parts that were also cloned by o2micro and maybe others, but + * they are so much more common that the author doesn't have experience + * with them to know for sure. */ static int pcic_pci_pd67xx_func(struct pcic_slot *sp, enum pcic_intr_way way) { /* - * We're only supporting ISA interrupts, so do nothing for the - * moment. + * For pci interrupts, we need to set bit 3 of extension register + * 3 to 1. For ISA interrupts, we need to clear it. */ - /* XXX */ + sp->putb(sp, PCIC_EXT_IND, PCIC_EXTCTRL1); + if (way == pcic_iw_pci) + pcic_setb(sp, PCIC_EXTENDED, PCIC_EC1_CARD_IRQ_INV); + else + pcic_clrb(sp, PCIC_EXTENDED, PCIC_EC1_CARD_IRQ_INV); + return (0); } @@ -470,10 +496,15 @@ static int pcic_pci_pd67xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) { /* - * We're only supporting ISA interrupts, so do nothing for the - * moment. + * For pci interrupts, we need to set bit 4 of extension register + * 3 to 1. For ISA interrupts, we need to clear it. */ - /* XXX */ + sp->putb(sp, PCIC_EXT_IND, PCIC_EXTCTRL1); + if (way == pcic_iw_pci) + pcic_setb(sp, PCIC_EXTENDED, PCIC_EC1_CSC_IRQ_INV); + else + pcic_clrb(sp, PCIC_EXTENDED, PCIC_EC1_CSC_IRQ_INV); + return (0); } @@ -484,7 +515,7 @@ pcic_pci_pd67xx_init(device_t dev) struct pcic_softc *sc = device_get_softc(dev); if (sc->csc_route == pcic_iw_pci || sc->func_route == pcic_iw_pci) - device_printf(dev, "CL-PD67xx broken for PCI routing.\n"); + device_printf(dev, "PD67xx maybe broken for PCI routing.\n"); } /* @@ -882,10 +913,9 @@ pcic_pci_cardbus_init(device_t dev) pci_write_config(dev, CB_PCI_IOLIMIT1, 0, 4); /* - * Force the function interrupts to be pulse rather than - * edge triggered. + * Tell the chip to do its routing thing. */ - sc->chip->func_intr_way(&sc->slots[0], pcic_iw_isa); + sc->chip->func_intr_way(&sc->slots[0], sc->func_route); sc->chip->csc_intr_way(&sc->slots[0], sc->csc_route); return; @@ -1094,12 +1124,6 @@ pcic_pci_shutdown(device_t dev) sp = &sc->slots[0]; /* - * Make the chips use ISA again. - */ - sc->chip->func_intr_way(&sc->slots[0], pcic_iw_isa); - sc->chip->csc_intr_way(&sc->slots[0], pcic_iw_isa); - - /* * Turn off the power to the slot in an attempt to * keep the system from hanging on reboot. We also turn off * card interrupts in an attempt to control interrupt storms. @@ -1205,14 +1229,10 @@ pcic_pci_attach(device_t dev) sp[i].slt = (struct slot *) 1; } /* - * We only support isa at this time. These cards can be - * wired up as either ISA cards *OR* PCI cards (well, weird - * hybrids are possible, but not seen in the wild). Since it - * is an either or thing, we assume ISA since all laptops that - * we supported in 4.3 and earlier work. - */ - sc->csc_route = pcic_iw_isa; - sc->func_route = pcic_iw_isa; + * While one could specify PCI interrupts, that's not + * yet supported other places in the code. + */ + sc->csc_route = sc->func_route = pcic_pd6729_intr_path; if (itm) sc->flags = itm->flags; } else { @@ -1360,13 +1380,30 @@ pcic_pci_gen_mapirq(struct pcic_slot *sp, int irq) /* * If we're doing ISA interrupt routing, then just go to the * generic ISA routine. Also, irq 0 means turn off the interrupts - * at the bridge. We do this by making the interrupts edge - * triggered rather then level. + * at the bridge. */ if (sp->sc->func_route == pcic_iw_isa || irq == 0) return (pcic_isa_mapirq(sp, irq)); - return (sp->sc->chip->func_intr_way(sp, pcic_iw_pci)); + /* + * Ohterwise we're doing PCI interrupts. For those cardbus bridges + * that follow yenta (and the one pcmcia bridge that does), we don't + * do a thing to get the IRQ mapped into the system. However, + * for other controllers that are PCI, but not yetna compliant, we + * need to do some special mapping. + */ + if (sp->controller == PCIC_PD6729) { + /* + * INTA - 3 + * INTB - 4 + * INTC - 5 + * INTD - 7 + */ + sp->putb(sp, PCIC_INT_GEN, /* Assume INTA# */ + (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | 3); + return (0); + } + return (0); } static void |