isa_pci.c revision 106219
169783Smsmith/*- 269783Smsmith * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 369783Smsmith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 469783Smsmith * Copyright (c) 2000 BSDi 569783Smsmith * All rights reserved. 669783Smsmith * 769783Smsmith * Redistribution and use in source and binary forms, with or without 869783Smsmith * modification, are permitted provided that the following conditions 969783Smsmith * are met: 1069783Smsmith * 1. Redistributions of source code must retain the above copyright 1169783Smsmith * notice, this list of conditions and the following disclaimer. 1269783Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1369783Smsmith * notice, this list of conditions and the following disclaimer in the 1469783Smsmith * documentation and/or other materials provided with the distribution. 1569783Smsmith * 3. The name of the author may not be used to endorse or promote products 1669783Smsmith * derived from this software without specific prior written permission. 1769783Smsmith * 1869783Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1969783Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2069783Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2169783Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2269783Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2369783Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2469783Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2569783Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2669783Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2769783Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2869783Smsmith * SUCH DAMAGE. 2969783Smsmith * 3069783Smsmith * $FreeBSD: head/sys/dev/pci/isa_pci.c 106219 2002-10-30 19:55:06Z iedowse $ 3169783Smsmith */ 3269783Smsmith 3369783Smsmith/* 3469783Smsmith * PCI:ISA bridge support 3569783Smsmith */ 3669783Smsmith 3769783Smsmith#include <sys/param.h> 3869783Smsmith#include <sys/systm.h> 3969783Smsmith#include <sys/kernel.h> 40106219Siedowse#include <machine/bus.h> 41106219Siedowse#include <machine/resource.h> 4269783Smsmith#include <sys/bus.h> 43106219Siedowse#include <sys/rman.h> 4469783Smsmith 4569783Smsmith#include <pci/pcivar.h> 4669783Smsmith#include <pci/pcireg.h> 4769783Smsmith 48106219Siedowse#define ELCR_IOADDR 0x4d0 /* Interrupt Edge/Level Control Registers */ 49106219Siedowse#define ELCR_IOLEN 2 50106219Siedowse 51106219Siedowsestruct isab_softc { 52106219Siedowse struct resource *elcr_res; 53106219Siedowse u_char saved_elcr[ELCR_IOLEN]; 54106219Siedowse}; 55106219Siedowse 5669783Smsmithstatic int isab_probe(device_t dev); 5769783Smsmithstatic int isab_attach(device_t dev); 58106219Siedowsestatic int isab_detach(device_t dev); 59106219Siedowsestatic int isab_resume(device_t dev); 60106219Siedowsestatic int isab_suspend(device_t dev); 6169783Smsmith 6269783Smsmithstatic device_method_t isab_methods[] = { 6369783Smsmith /* Device interface */ 6469783Smsmith DEVMETHOD(device_probe, isab_probe), 6569783Smsmith DEVMETHOD(device_attach, isab_attach), 66106219Siedowse DEVMETHOD(device_detach, isab_detach), 6769783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 68106219Siedowse DEVMETHOD(device_suspend, isab_suspend), 69106219Siedowse DEVMETHOD(device_resume, isab_resume), 7069783Smsmith 7169783Smsmith /* Bus interface */ 7269783Smsmith DEVMETHOD(bus_print_child, bus_generic_print_child), 7369783Smsmith DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 7469783Smsmith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 7569783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 7669783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 7769783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 7869783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 7969783Smsmith 8069783Smsmith { 0, 0 } 8169783Smsmith}; 8269783Smsmith 8369783Smsmithstatic driver_t isab_driver = { 8469783Smsmith "isab", 8569783Smsmith isab_methods, 86106219Siedowse sizeof(struct isab_softc), 8769783Smsmith}; 8869783Smsmith 8969783Smsmithstatic devclass_t isab_devclass; 9069783Smsmith 9169783SmsmithDRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); 9269783Smsmith 9369783Smsmith/* 9469783Smsmith * XXX we need to add a quirk list here for bridges that don't correctly 9569783Smsmith * report themselves. 9669783Smsmith */ 9769783Smsmithstatic int 9869783Smsmithisab_probe(device_t dev) 9969783Smsmith{ 10069783Smsmith int matched = 0; 10169783Smsmith 10269783Smsmith /* 10369783Smsmith * Try for a generic match based on class/subclass. 10469783Smsmith */ 10569890Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 10669890Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) { 10769890Smsmith matched = 1; 10869890Smsmith } else { 10969890Smsmith /* 11069890Smsmith * These are devices that we *know* are PCI:ISA bridges. 11169890Smsmith * Sometimes, however, they don't report themselves as 11269890Smsmith * such. Check in case one of them is pretending to be 11369890Smsmith * something else. 11469890Smsmith */ 11569890Smsmith switch (pci_get_devid(dev)) { 11669890Smsmith case 0x04848086: /* Intel 82378ZB/82378IB */ 11769890Smsmith case 0x122e8086: /* Intel 82371FB */ 11869890Smsmith case 0x70008086: /* Intel 82371SB */ 11969890Smsmith case 0x71108086: /* Intel 82371AB */ 12088323Spirzyk case 0x71988086: /* Intel 82443MX */ 12169890Smsmith case 0x24108086: /* Intel 82801AA (ICH) */ 12269890Smsmith case 0x24208086: /* Intel 82801AB (ICH0) */ 12369890Smsmith case 0x24408086: /* Intel 82801AB (ICH2) */ 12469890Smsmith case 0x00061004: /* VLSI 82C593 */ 12569890Smsmith case 0x05861106: /* VIA 82C586 */ 12669890Smsmith case 0x05961106: /* VIA 82C596 */ 12769890Smsmith case 0x06861106: /* VIA 82C686 */ 12869890Smsmith case 0x153310b9: /* AcerLabs M1533 */ 12969890Smsmith case 0x154310b9: /* AcerLabs M1543 */ 13069890Smsmith case 0x00081039: /* SiS 85c503 */ 13169890Smsmith case 0x00001078: /* Cyrix Cx5510 */ 13269890Smsmith case 0x01001078: /* Cyrix Cx5530 */ 13369890Smsmith case 0xc7001045: /* OPTi 82C700 (FireStar) */ 13469890Smsmith case 0x00011033: /* NEC 0001 (C-bus) */ 13569890Smsmith case 0x002c1033: /* NEC 002C (C-bus) */ 13669890Smsmith case 0x003b1033: /* NEC 003B (C-bus) */ 13769890Smsmith case 0x886a1060: /* UMC UM8886 ISA */ 13869890Smsmith case 0x02001166: /* ServerWorks IB6566 PCI */ 13969890Smsmith if (bootverbose) 14069890Smsmith printf("PCI-ISA bridge with incorrect subclass 0x%x\n", 14169890Smsmith pci_get_subclass(dev)); 14269849Smsmith matched = 1; 14369890Smsmith break; 14469849Smsmith 14569890Smsmith default: 14669890Smsmith break; 14769783Smsmith } 14869783Smsmith } 14969783Smsmith 15069783Smsmith if (matched) { 15169783Smsmith device_set_desc(dev, "PCI-ISA bridge"); 15269783Smsmith return(-10000); 15369783Smsmith } 15469783Smsmith return(ENXIO); 15569783Smsmith} 15669783Smsmith 15769783Smsmithstatic int 15869783Smsmithisab_attach(device_t dev) 15969783Smsmith{ 16069783Smsmith device_t child; 161106219Siedowse struct isab_softc *sc = device_get_softc(dev); 162106219Siedowse int error, rid; 16369783Smsmith 16469783Smsmith /* 16569783Smsmith * Attach an ISA bus. Note that we can only have one ISA bus. 16669783Smsmith */ 16769783Smsmith child = device_add_child(dev, "isa", 0); 168106219Siedowse if (child != NULL) { 169106219Siedowse error = bus_generic_attach(dev); 170106219Siedowse if (error) 171106219Siedowse return (error); 172106219Siedowse } 17369783Smsmith 174106219Siedowse switch (pci_get_devid(dev)) { 175106219Siedowse case 0x71108086: /* Intel 82371AB */ 176106219Siedowse /* 177106219Siedowse * Sometimes the ELCR (Edge/Level Control Register) is not restored 178106219Siedowse * correctly on resume by the BIOS, so we handle it ourselves. 179106219Siedowse */ 180106219Siedowse rid = 0; 181106219Siedowse bus_set_resource(dev, SYS_RES_IOPORT, rid, ELCR_IOADDR, ELCR_IOLEN); 182106219Siedowse sc->elcr_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 183106219Siedowse RF_ACTIVE); 184106219Siedowse if (sc->elcr_res == NULL) 185106219Siedowse device_printf(dev, "failed to allocate ELCR resource\n"); 186106219Siedowse break; 187106219Siedowse } 188106219Siedowse 18969783Smsmith return(0); 19069783Smsmith} 19169783Smsmith 192106219Siedowsestatic int 193106219Siedowseisab_detach(device_t dev) 194106219Siedowse{ 195106219Siedowse struct isab_softc *sc = device_get_softc(dev); 196106219Siedowse 197106219Siedowse if (sc->elcr_res != NULL) 198106219Siedowse bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->elcr_res); 199106219Siedowse 200106219Siedowse return (bus_generic_detach(dev)); 201106219Siedowse} 202106219Siedowse 203106219Siedowsestatic int 204106219Siedowseisab_suspend(device_t dev) 205106219Siedowse{ 206106219Siedowse struct isab_softc *sc = device_get_softc(dev); 207106219Siedowse bus_space_tag_t bst; 208106219Siedowse bus_space_handle_t bsh; 209106219Siedowse int i; 210106219Siedowse 211106219Siedowse /* Save the ELCR if required. */ 212106219Siedowse if (sc->elcr_res != NULL) { 213106219Siedowse bst = rman_get_bustag(sc->elcr_res); 214106219Siedowse bsh = rman_get_bushandle(sc->elcr_res); 215106219Siedowse for (i = 0; i < ELCR_IOLEN; i++) 216106219Siedowse sc->saved_elcr[i] = bus_space_read_1(bst, bsh, i); 217106219Siedowse } 218106219Siedowse 219106219Siedowse return (bus_generic_suspend(dev)); 220106219Siedowse} 221106219Siedowse 222106219Siedowsestatic int 223106219Siedowseisab_resume(device_t dev) 224106219Siedowse{ 225106219Siedowse struct isab_softc *sc = device_get_softc(dev); 226106219Siedowse bus_space_tag_t bst; 227106219Siedowse bus_space_handle_t bsh; 228106219Siedowse int i; 229106219Siedowse 230106219Siedowse /* Restore the ELCR if required. */ 231106219Siedowse if (sc->elcr_res != NULL) { 232106219Siedowse bst = rman_get_bustag(sc->elcr_res); 233106219Siedowse bsh = rman_get_bushandle(sc->elcr_res); 234106219Siedowse for (i = 0; i < ELCR_IOLEN; i++) 235106219Siedowse bus_space_write_1(bst, bsh, i, sc->saved_elcr[i]); 236106219Siedowse } 237106219Siedowse 238106219Siedowse return (bus_generic_resume(dev)); 239106219Siedowse} 240