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 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD$"); 33119418Sobrien 3469783Smsmith/* 3569783Smsmith * PCI:ISA bridge support 3669783Smsmith */ 3769783Smsmith 3869783Smsmith#include <sys/param.h> 3969783Smsmith#include <sys/systm.h> 4069783Smsmith#include <sys/kernel.h> 41129876Sphk#include <sys/module.h> 4269783Smsmith#include <sys/bus.h> 4369783Smsmith 44117337Sjhb#include <isa/isavar.h> 45119285Simp#include <dev/pci/pcivar.h> 46119285Simp#include <dev/pci/pcireg.h> 4769783Smsmith 48221839Sbrix#include <machine/bus.h> 49221839Sbrix#include <sys/rman.h> 50221839Sbrix#include <machine/resource.h> 5169783Smsmith 52221839Sbrixstatic int isab_pci_probe(device_t dev); 53221839Sbrixstatic int isab_pci_attach(device_t dev); 54221839Sbrixstatic struct resource * isab_pci_alloc_resource(device_t dev, 55221839Sbrix device_t child, int type, int *rid, u_long start, u_long end, u_long count, 56221839Sbrix u_int flags); 57221839Sbrixstatic int isab_pci_release_resource(device_t dev, device_t child, 58221839Sbrix int type, int rid, struct resource *r); 59221839Sbrix 6069783Smsmithstatic device_method_t isab_methods[] = { 6169783Smsmith /* Device interface */ 62221839Sbrix DEVMETHOD(device_probe, isab_pci_probe), 63221839Sbrix DEVMETHOD(device_attach, isab_pci_attach), 64150714Sjhb DEVMETHOD(device_detach, bus_generic_detach), 6569783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 66150714Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 67150714Sjhb DEVMETHOD(device_resume, bus_generic_resume), 6869783Smsmith 6969783Smsmith /* Bus interface */ 70229625Sjhb DEVMETHOD(bus_add_child, bus_generic_add_child), 71221839Sbrix DEVMETHOD(bus_alloc_resource, isab_pci_alloc_resource), 72221839Sbrix DEVMETHOD(bus_release_resource, isab_pci_release_resource), 7369783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 7469783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 7569783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 7669783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 7769783Smsmith 78229093Shselasky DEVMETHOD_END 7969783Smsmith}; 8069783Smsmith 81221839Sbrixstruct isab_pci_resource { 82221839Sbrix struct resource *ip_res; 83221839Sbrix int ip_refs; 84221839Sbrix}; 85221839Sbrix 86221839Sbrixstruct isab_pci_softc { 87221839Sbrix struct isab_pci_resource isab_pci_res[PCIR_MAX_BAR_0 + 1]; 88221839Sbrix}; 89221839Sbrix 9069783Smsmithstatic driver_t isab_driver = { 9169783Smsmith "isab", 9269783Smsmith isab_methods, 93221839Sbrix sizeof(struct isab_pci_softc), 9469783Smsmith}; 9569783Smsmith 9669783SmsmithDRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); 9769783Smsmith 9869783Smsmith/* 9969783Smsmith * XXX we need to add a quirk list here for bridges that don't correctly 10069783Smsmith * report themselves. 10169783Smsmith */ 10269783Smsmithstatic int 103221839Sbrixisab_pci_probe(device_t dev) 10469783Smsmith{ 10569783Smsmith int matched = 0; 10669783Smsmith 10769783Smsmith /* 10869783Smsmith * Try for a generic match based on class/subclass. 10969783Smsmith */ 11069890Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 11169890Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) { 11269890Smsmith matched = 1; 11369890Smsmith } else { 11469890Smsmith /* 11569890Smsmith * These are devices that we *know* are PCI:ISA bridges. 11669890Smsmith * Sometimes, however, they don't report themselves as 11769890Smsmith * such. Check in case one of them is pretending to be 11869890Smsmith * something else. 11969890Smsmith */ 12069890Smsmith switch (pci_get_devid(dev)) { 12169890Smsmith case 0x04848086: /* Intel 82378ZB/82378IB */ 12269890Smsmith case 0x122e8086: /* Intel 82371FB */ 12369890Smsmith case 0x70008086: /* Intel 82371SB */ 12469890Smsmith case 0x71108086: /* Intel 82371AB */ 12588323Spirzyk case 0x71988086: /* Intel 82443MX */ 12669890Smsmith case 0x24108086: /* Intel 82801AA (ICH) */ 12769890Smsmith case 0x24208086: /* Intel 82801AB (ICH0) */ 12869890Smsmith case 0x24408086: /* Intel 82801AB (ICH2) */ 12969890Smsmith case 0x00061004: /* VLSI 82C593 */ 13069890Smsmith case 0x05861106: /* VIA 82C586 */ 13169890Smsmith case 0x05961106: /* VIA 82C596 */ 13269890Smsmith case 0x06861106: /* VIA 82C686 */ 13369890Smsmith case 0x153310b9: /* AcerLabs M1533 */ 13469890Smsmith case 0x154310b9: /* AcerLabs M1543 */ 13569890Smsmith case 0x00081039: /* SiS 85c503 */ 13669890Smsmith case 0x00001078: /* Cyrix Cx5510 */ 13769890Smsmith case 0x01001078: /* Cyrix Cx5530 */ 13869890Smsmith case 0xc7001045: /* OPTi 82C700 (FireStar) */ 13969890Smsmith case 0x00011033: /* NEC 0001 (C-bus) */ 14069890Smsmith case 0x002c1033: /* NEC 002C (C-bus) */ 14169890Smsmith case 0x003b1033: /* NEC 003B (C-bus) */ 14269890Smsmith case 0x886a1060: /* UMC UM8886 ISA */ 14369890Smsmith case 0x02001166: /* ServerWorks IB6566 PCI */ 14469890Smsmith if (bootverbose) 14569890Smsmith printf("PCI-ISA bridge with incorrect subclass 0x%x\n", 14669890Smsmith pci_get_subclass(dev)); 14769849Smsmith matched = 1; 14869890Smsmith break; 14969849Smsmith 15069890Smsmith default: 15169890Smsmith break; 15269783Smsmith } 15369783Smsmith } 15469783Smsmith 15569783Smsmith if (matched) { 15669783Smsmith device_set_desc(dev, "PCI-ISA bridge"); 15769783Smsmith return(-10000); 15869783Smsmith } 15969783Smsmith return(ENXIO); 16069783Smsmith} 161221839Sbrix 162221839Sbrixstatic int 163221839Sbrixisab_pci_attach(device_t dev) 164221839Sbrix{ 165221839Sbrix 166221839Sbrix bus_generic_probe(dev); 167221839Sbrix return (isab_attach(dev)); 168221839Sbrix} 169221839Sbrix 170221839Sbrixstatic struct resource * 171221839Sbrixisab_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 172221839Sbrix u_long start, u_long end, u_long count, u_int flags) 173221839Sbrix{ 174221839Sbrix struct isab_pci_softc *sc; 175221839Sbrix int bar; 176221839Sbrix 177221839Sbrix if (device_get_parent(child) != dev) 178221839Sbrix return bus_generic_alloc_resource(dev, child, type, rid, start, 179221839Sbrix end, count, flags); 180221839Sbrix 181221839Sbrix switch (type) { 182221839Sbrix case SYS_RES_MEMORY: 183221839Sbrix case SYS_RES_IOPORT: 184221839Sbrix /* 185221839Sbrix * For BARs, we cache the resource so that we only allocate it 186221839Sbrix * from the PCI bus once. 187221839Sbrix */ 188221839Sbrix bar = PCI_RID2BAR(*rid); 189221839Sbrix if (bar < 0 || bar > PCIR_MAX_BAR_0) 190221839Sbrix return (NULL); 191221839Sbrix sc = device_get_softc(dev); 192221839Sbrix if (sc->isab_pci_res[bar].ip_res == NULL) 193221839Sbrix sc->isab_pci_res[bar].ip_res = bus_alloc_resource(dev, type, 194221839Sbrix rid, start, end, count, flags); 195221839Sbrix if (sc->isab_pci_res[bar].ip_res != NULL) 196221839Sbrix sc->isab_pci_res[bar].ip_refs++; 197221839Sbrix return (sc->isab_pci_res[bar].ip_res); 198221839Sbrix } 199221839Sbrix 200221839Sbrix return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, 201221839Sbrix start, end, count, flags)); 202221839Sbrix} 203221839Sbrix 204221839Sbrixstatic int 205221839Sbrixisab_pci_release_resource(device_t dev, device_t child, int type, int rid, 206221839Sbrix struct resource *r) 207221839Sbrix{ 208221839Sbrix struct isab_pci_softc *sc; 209221839Sbrix int bar, error; 210221839Sbrix 211221839Sbrix if (device_get_parent(child) != dev) 212221839Sbrix return bus_generic_release_resource(dev, child, type, rid, r); 213221839Sbrix 214221839Sbrix switch (type) { 215221839Sbrix case SYS_RES_MEMORY: 216221839Sbrix case SYS_RES_IOPORT: 217221839Sbrix /* 218221839Sbrix * For BARs, we release the resource from the PCI bus 219221839Sbrix * when the last child reference goes away. 220221839Sbrix */ 221221839Sbrix bar = PCI_RID2BAR(rid); 222221839Sbrix if (bar < 0 || bar > PCIR_MAX_BAR_0) 223221839Sbrix return (EINVAL); 224221839Sbrix sc = device_get_softc(dev); 225221839Sbrix if (sc->isab_pci_res[bar].ip_res == NULL) 226221839Sbrix return (EINVAL); 227221839Sbrix KASSERT(sc->isab_pci_res[bar].ip_res == r, 228221839Sbrix ("isa_pci resource mismatch")); 229221839Sbrix if (sc->isab_pci_res[bar].ip_refs > 1) { 230221839Sbrix sc->isab_pci_res[bar].ip_refs--; 231221839Sbrix return (0); 232221839Sbrix } 233221839Sbrix KASSERT(sc->isab_pci_res[bar].ip_refs > 0, 234221839Sbrix ("isa_pci resource reference count underflow")); 235221839Sbrix error = bus_release_resource(dev, type, rid, r); 236221839Sbrix if (error == 0) { 237221839Sbrix sc->isab_pci_res[bar].ip_res = NULL; 238221839Sbrix sc->isab_pci_res[bar].ip_refs = 0; 239221839Sbrix } 240221839Sbrix return (error); 241221839Sbrix } 242221839Sbrix 243221839Sbrix return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, 244221839Sbrix rid, r)); 245221839Sbrix} 246