pci_subr.c revision 69908
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/pci_pci.c 69908 2000-12-12 13:20:35Z msmith $ 3169783Smsmith */ 3269783Smsmith 3369783Smsmith/* 3469783Smsmith * PCI:PCI bridge support. 3569783Smsmith */ 3669783Smsmith 3769783Smsmith#include <sys/param.h> 3869783Smsmith#include <sys/systm.h> 3969783Smsmith#include <sys/kernel.h> 4069783Smsmith#include <sys/bus.h> 4169783Smsmith 4269783Smsmith#include <machine/resource.h> 4369783Smsmith 4469783Smsmith#include <pci/pcivar.h> 4569783Smsmith#include <pci/pcireg.h> 4669783Smsmith 4769783Smsmith#include "pcib_if.h" 4869783Smsmith 4969783Smsmith/* 5069783Smsmith * Bridge-specific data. 5169783Smsmith */ 5269783Smsmithstruct pcib_softc 5369783Smsmith{ 5469783Smsmith device_t dev; 5569783Smsmith u_int8_t secbus; /* secondary bus number */ 5669783Smsmith u_int8_t subbus; /* subordinate bus number */ 5769783Smsmith pci_addr_t pmembase; /* base address of prefetchable memory */ 5869783Smsmith pci_addr_t pmemlimit; /* topmost address of prefetchable memory */ 5969783Smsmith u_int32_t membase; /* base address of memory window */ 6069783Smsmith u_int32_t memlimit; /* topmost address of memory window */ 6169783Smsmith u_int32_t iobase; /* base address of port window */ 6269783Smsmith u_int32_t iolimit; /* topmost address of port window */ 6369783Smsmith u_int16_t secstat; /* secondary bus status register */ 6469783Smsmith u_int16_t bridgectl; /* bridge control register */ 6569783Smsmith u_int8_t seclat; /* secondary bus latency timer */ 6669783Smsmith}; 6769783Smsmith 6869783Smsmithstatic int pcib_probe(device_t dev); 6969783Smsmithstatic int pcib_attach(device_t dev); 7069783Smsmithstatic int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); 7169783Smsmithstatic int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value); 7269783Smsmithstatic struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 7369783Smsmith u_long start, u_long end, u_long count, u_int flags); 7469783Smsmithstatic int pcib_maxslots(device_t dev); 7569783Smsmithstatic u_int32_t pcib_read_config(device_t dev, int b, int s, int f, int reg, int width); 7669783Smsmithstatic void pcib_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, int width); 7769783Smsmithstatic int pcib_route_interrupt(device_t pcib, device_t dev, int pin); 7869783Smsmith 7969783Smsmithstatic device_method_t pcib_methods[] = { 8069783Smsmith /* Device interface */ 8169783Smsmith DEVMETHOD(device_probe, pcib_probe), 8269783Smsmith DEVMETHOD(device_attach, pcib_attach), 8369783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 8469783Smsmith DEVMETHOD(device_suspend, bus_generic_suspend), 8569783Smsmith DEVMETHOD(device_resume, bus_generic_resume), 8669783Smsmith 8769783Smsmith /* Bus interface */ 8869783Smsmith DEVMETHOD(bus_print_child, bus_generic_print_child), 8969783Smsmith DEVMETHOD(bus_read_ivar, pcib_read_ivar), 9069783Smsmith DEVMETHOD(bus_write_ivar, pcib_write_ivar), 9169783Smsmith DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 9269783Smsmith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 9369783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 9469783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 9569783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 9669783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 9769783Smsmith 9869783Smsmith /* pcib interface */ 9969783Smsmith DEVMETHOD(pcib_maxslots, pcib_maxslots), 10069783Smsmith DEVMETHOD(pcib_read_config, pcib_read_config), 10169783Smsmith DEVMETHOD(pcib_write_config, pcib_write_config), 10269783Smsmith DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 10369783Smsmith 10469783Smsmith { 0, 0 } 10569783Smsmith}; 10669783Smsmith 10769783Smsmithstatic driver_t pcib_driver = { 10869783Smsmith "pcib", 10969783Smsmith pcib_methods, 11069783Smsmith sizeof(struct pcib_softc), 11169783Smsmith}; 11269783Smsmith 11369783Smsmithstatic devclass_t pcib_devclass; 11469783Smsmith 11569783SmsmithDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); 11669783Smsmith 11769783Smsmith/* 11869783Smsmith * Generic device interface 11969783Smsmith */ 12069783Smsmithstatic int 12169783Smsmithpcib_probe(device_t dev) 12269783Smsmith{ 12369783Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 12469783Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 12569783Smsmith device_set_desc(dev, "PCI-PCI bridge"); 12669783Smsmith return(-10000); 12769783Smsmith } 12869783Smsmith return(ENXIO); 12969783Smsmith} 13069783Smsmith 13169783Smsmithstatic int 13269783Smsmithpcib_attach(device_t dev) 13369783Smsmith{ 13469783Smsmith struct pcib_softc *sc; 13569908Smsmith device_t child; 13669908Smsmith u_int8_t iolow; 13769783Smsmith 13869783Smsmith sc = device_get_softc(dev); 13969783Smsmith sc->dev = dev; 14069783Smsmith 14169908Smsmith /* 14269908Smsmith * Get current bridge configuration. 14369908Smsmith */ 14469908Smsmith sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 14569908Smsmith sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 14669908Smsmith sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 14769908Smsmith sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 14869908Smsmith sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 14969783Smsmith 15069908Smsmith /* 15169908Smsmith * Determine current I/O decode. 15269908Smsmith */ 15369908Smsmith iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 15469908Smsmith if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 15569908Smsmith sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), 15669908Smsmith pci_read_config(dev, PCIR_IOBASEL_1, 1)); 15769908Smsmith } else { 15869908Smsmith sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); 15969908Smsmith } 16069908Smsmith 16169908Smsmith iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 16269908Smsmith if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 16369908Smsmith sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), 16469908Smsmith pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 16569908Smsmith } else { 16669908Smsmith sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 16769908Smsmith } 16869908Smsmith 16969908Smsmith /* 17069908Smsmith * Determine current memory decode. 17169908Smsmith */ 17269908Smsmith sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); 17369908Smsmith sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 17469908Smsmith sc->pmembase = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4), 17569908Smsmith pci_read_config(dev, PCIR_PMBASEL_1, 2)); 17669908Smsmith sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4), 17769908Smsmith pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 17869908Smsmith 17969908Smsmith /* 18069908Smsmith * Quirk handling. 18169908Smsmith */ 18269908Smsmith switch (pci_get_devid(dev)) { 18369908Smsmith case 0x12258086: /* Intel 82454KX/GX (Orion) */ 18469908Smsmith { 18569908Smsmith u_int8_t supbus; 18669908Smsmith 18769908Smsmith supbus = pci_read_config(dev, 0x41, 1); 18869908Smsmith if (supbus != 0xff) { 18969908Smsmith sc->secbus = supbus + 1; 19069908Smsmith sc->subbus = supbus + 1; 19169908Smsmith } 19269908Smsmith } 19369908Smsmith break; 19469908Smsmith } 19569908Smsmith 19669908Smsmith 19769783Smsmith if (bootverbose) { 19869783Smsmith device_printf(dev, " secondary bus %d\n", sc->secbus); 19969783Smsmith device_printf(dev, " subordinate bus %d\n", sc->subbus); 20069783Smsmith device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); 20169783Smsmith device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit); 20269783Smsmith device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit); 20369783Smsmith } 20469783Smsmith 20569783Smsmith /* 20669783Smsmith * XXX If the secondary bus number is zero, we should assign a bus number 20769783Smsmith * since the BIOS hasn't, then initialise the bridge. 20869783Smsmith */ 20969783Smsmith 21069783Smsmith /* 21169783Smsmith * XXX If the subordinate bus number is less than the secondary bus number, 21269783Smsmith * we should pick a better value. One sensible alternative would be to 21369783Smsmith * pick 255; the only tradeoff here is that configuration transactions 21469783Smsmith * would be more widely routed than absolutely necessary. 21569783Smsmith */ 21669783Smsmith 21769783Smsmith if (sc->secbus != 0) { 21869783Smsmith child = device_add_child(dev, "pci", -1); 21969783Smsmith if (child != NULL) 22069783Smsmith return(bus_generic_attach(dev)); 22169783Smsmith } 22269783Smsmith 22369783Smsmith /* no secondary bus; we should have fixed this */ 22469783Smsmith return(0); 22569783Smsmith} 22669783Smsmith 22769783Smsmithstatic int 22869783Smsmithpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 22969783Smsmith{ 23069783Smsmith struct pcib_softc *sc = device_get_softc(dev); 23169783Smsmith 23269783Smsmith switch (which) { 23369783Smsmith case PCIB_IVAR_BUS: 23469783Smsmith *result = sc->secbus; 23569783Smsmith return(0); 23669783Smsmith } 23769783Smsmith return(ENOENT); 23869783Smsmith} 23969783Smsmith 24069783Smsmithstatic int 24169783Smsmithpcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 24269783Smsmith{ 24369783Smsmith struct pcib_softc *sc = device_get_softc(dev); 24469783Smsmith 24569783Smsmith switch (which) { 24669783Smsmith case PCIB_IVAR_BUS: 24769783Smsmith sc->secbus = value; 24869783Smsmith break; 24969783Smsmith } 25069783Smsmith return(ENOENT); 25169783Smsmith} 25269783Smsmith 25369783Smsmith/* 25469783Smsmith * We have to trap resource allocation requests and ensure that the bridge 25569783Smsmith * is set up to, or capable of handling them. 25669783Smsmith */ 25769783Smsmithstatic struct resource * 25869783Smsmithpcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 25969783Smsmith u_long start, u_long end, u_long count, u_int flags) 26069783Smsmith{ 26169783Smsmith struct pcib_softc *sc = device_get_softc(dev); 26269783Smsmith 26369783Smsmith /* 26469783Smsmith * If this is a "default" allocation against this rid, we can't work 26569783Smsmith * out where it's coming from (we should actually never see these) so we 26669783Smsmith * just have to punt. 26769783Smsmith */ 26869783Smsmith if ((start == 0) && (end == ~0)) { 26969783Smsmith device_printf(dev, "can't decode default resource id %d for %s%d, bypassing\n", 27069783Smsmith *rid, device_get_name(child), device_get_unit(child)); 27169783Smsmith } else { 27269783Smsmith /* 27369783Smsmith * Fail the allocation for this range if it's not supported. 27469783Smsmith * 27569783Smsmith * XXX we should probably just fix up the bridge decode and soldier on. 27669783Smsmith */ 27769783Smsmith switch (type) { 27869783Smsmith case SYS_RES_IOPORT: 27969783Smsmith if ((start < sc->iobase) || (end > sc->iolimit)) { 28069783Smsmith device_printf(dev, "device %s%d requested unsupported I/O range 0x%lx-0x%lx" 28169783Smsmith " (decoding 0x%x-0x%x)\n", 28269783Smsmith device_get_name(child), device_get_unit(child), start, end, 28369783Smsmith sc->iobase, sc->iolimit); 28469783Smsmith return(NULL); 28569783Smsmith } 28669908Smsmith if (bootverbose) 28769908Smsmith device_printf(sc->dev, "device %s%d requested decoded I/O range 0x%lx-0x%lx\n", 28869908Smsmith device_get_name(child), device_get_unit(child), start, end); 28969783Smsmith break; 29069783Smsmith 29169783Smsmith /* 29269783Smsmith * XXX will have to decide whether the device making the request is asking 29369783Smsmith * for prefetchable memory or not. If it's coming from another bridge 29469783Smsmith * down the line, do we assume not, or ask the bridge to pass in another 29569783Smsmith * flag as the request bubbles up? 29669783Smsmith */ 29769783Smsmith case SYS_RES_MEMORY: 29869783Smsmith if (((start < sc->membase) || (end > sc->memlimit)) && 29969783Smsmith ((start < sc->pmembase) || (end > sc->pmemlimit))) { 30069783Smsmith device_printf(dev, "device %s%d requested unsupported memory range 0x%lx-0x%lx" 30169783Smsmith " (decoding 0x%x-0x%x, 0x%x-0x%x)\n", 30269783Smsmith device_get_name(child), device_get_unit(child), start, end, 30369783Smsmith sc->membase, sc->memlimit, sc->pmembase, sc->pmemlimit); 30469783Smsmith return(NULL); 30569783Smsmith } 30669908Smsmith if (bootverbose) 30769908Smsmith device_printf(sc->dev, "device %s%d requested decoded memory range 0x%lx-0x%lx\n", 30869908Smsmith device_get_name(child), device_get_unit(child), start, end); 30969908Smsmith break; 31069908Smsmith 31169783Smsmith default: 31269908Smsmith break; 31369783Smsmith } 31469783Smsmith } 31569908Smsmith 31669783Smsmith /* 31769783Smsmith * Bridge is OK decoding this resource, so pass it up. 31869783Smsmith */ 31969783Smsmith return(bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); 32069783Smsmith} 32169783Smsmith 32269783Smsmith/* 32369783Smsmith * PCIB interface. 32469783Smsmith */ 32569783Smsmithstatic int 32669783Smsmithpcib_maxslots(device_t dev) 32769783Smsmith{ 32869908Smsmith return(PCI_SLOTMAX); 32969783Smsmith} 33069783Smsmith 33169783Smsmith/* 33269783Smsmith * Since we are a child of a PCI bus, its parent must support the pcib interface. 33369783Smsmith */ 33469783Smsmithstatic u_int32_t 33569783Smsmithpcib_read_config(device_t dev, int b, int s, int f, int reg, int width) 33669783Smsmith{ 33769783Smsmith return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 33869783Smsmith} 33969783Smsmith 34069783Smsmithstatic void 34169783Smsmithpcib_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, int width) 34269783Smsmith{ 34369783Smsmith PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 34469783Smsmith} 34569783Smsmith 34669783Smsmith/* 34769783Smsmith * Route an interrupt across a PCI bridge. 34869783Smsmith */ 34969783Smsmithstatic int 35069783Smsmithpcib_route_interrupt(device_t pcib, device_t dev, int pin) 35169783Smsmith{ 35269783Smsmith device_t bus; 35369783Smsmith int parent_intpin; 35469783Smsmith int intnum; 35569783Smsmith 35669783Smsmith /* 35769783Smsmith * 35869783Smsmith * The PCI standard defines a swizzle of the child-side device/intpin to 35969783Smsmith * the parent-side intpin as follows. 36069783Smsmith * 36169783Smsmith * device = device on child bus 36269783Smsmith * child_intpin = intpin on child bus slot (0-3) 36369783Smsmith * parent_intpin = intpin on parent bus slot (0-3) 36469783Smsmith * 36569783Smsmith * parent_intpin = (device + child_intpin) % 4 36669783Smsmith */ 36769783Smsmith parent_intpin = (pci_get_slot(pcib) + (pin - 1)) % 4; 36869783Smsmith 36969783Smsmith /* 37069783Smsmith * Our parent is a PCI bus. Its parent must export the pcib interface 37169783Smsmith * which includes the ability to route interrupts. 37269783Smsmith */ 37369783Smsmith bus = device_get_parent(pcib); 37469783Smsmith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 37569783Smsmith device_printf(pcib, "routed slot %d INT%c to irq %d\n", pci_get_slot(dev), 37669783Smsmith 'A' + pin - 1, intnum); 37769783Smsmith return(intnum); 37869783Smsmith} 379