pci_subr.c revision 90554
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 90554 2002-02-12 01:28:49Z 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" 4889383Simp#include "opt_pci.h" 4969783Smsmith 5069783Smsmith/* 5169783Smsmith * Bridge-specific data. 5269783Smsmith */ 5369783Smsmithstruct pcib_softc 5469783Smsmith{ 5569783Smsmith device_t dev; 5669953Smsmith u_int16_t command; /* command register */ 5769783Smsmith u_int8_t secbus; /* secondary bus number */ 5869783Smsmith u_int8_t subbus; /* subordinate bus number */ 5969783Smsmith pci_addr_t pmembase; /* base address of prefetchable memory */ 6069783Smsmith pci_addr_t pmemlimit; /* topmost address of prefetchable memory */ 6169953Smsmith pci_addr_t membase; /* base address of memory window */ 6269953Smsmith pci_addr_t memlimit; /* topmost address of memory window */ 6369783Smsmith u_int32_t iobase; /* base address of port window */ 6469783Smsmith u_int32_t iolimit; /* topmost address of port window */ 6569783Smsmith u_int16_t secstat; /* secondary bus status register */ 6669783Smsmith u_int16_t bridgectl; /* bridge control register */ 6769783Smsmith u_int8_t seclat; /* secondary bus latency timer */ 6869783Smsmith}; 6969783Smsmith 7069783Smsmithstatic int pcib_probe(device_t dev); 7169783Smsmithstatic int pcib_attach(device_t dev); 7269783Smsmithstatic int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); 7369783Smsmithstatic int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value); 7469783Smsmithstatic struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 7569783Smsmith u_long start, u_long end, u_long count, u_int flags); 7669783Smsmithstatic int pcib_maxslots(device_t dev); 7769783Smsmithstatic u_int32_t pcib_read_config(device_t dev, int b, int s, int f, int reg, int width); 7869783Smsmithstatic void pcib_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, int width); 7969783Smsmithstatic int pcib_route_interrupt(device_t pcib, device_t dev, int pin); 8069783Smsmith 8169783Smsmithstatic device_method_t pcib_methods[] = { 8269783Smsmith /* Device interface */ 8369783Smsmith DEVMETHOD(device_probe, pcib_probe), 8469783Smsmith DEVMETHOD(device_attach, pcib_attach), 8569783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 8669783Smsmith DEVMETHOD(device_suspend, bus_generic_suspend), 8769783Smsmith DEVMETHOD(device_resume, bus_generic_resume), 8869783Smsmith 8969783Smsmith /* Bus interface */ 9069783Smsmith DEVMETHOD(bus_print_child, bus_generic_print_child), 9169783Smsmith DEVMETHOD(bus_read_ivar, pcib_read_ivar), 9269783Smsmith DEVMETHOD(bus_write_ivar, pcib_write_ivar), 9369783Smsmith DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 9469783Smsmith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 9569783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 9669783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 9769783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 9869783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 9969783Smsmith 10069783Smsmith /* pcib interface */ 10169783Smsmith DEVMETHOD(pcib_maxslots, pcib_maxslots), 10269783Smsmith DEVMETHOD(pcib_read_config, pcib_read_config), 10369783Smsmith DEVMETHOD(pcib_write_config, pcib_write_config), 10469783Smsmith DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 10569783Smsmith 10669783Smsmith { 0, 0 } 10769783Smsmith}; 10869783Smsmith 10969783Smsmithstatic driver_t pcib_driver = { 11069783Smsmith "pcib", 11169783Smsmith pcib_methods, 11269783Smsmith sizeof(struct pcib_softc), 11369783Smsmith}; 11469783Smsmith 11569783Smsmithstatic devclass_t pcib_devclass; 11669783Smsmith 11769783SmsmithDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); 11869783Smsmith 11969783Smsmith/* 12069783Smsmith * Generic device interface 12169783Smsmith */ 12269783Smsmithstatic int 12369783Smsmithpcib_probe(device_t dev) 12469783Smsmith{ 12569783Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 12669783Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 12769783Smsmith device_set_desc(dev, "PCI-PCI bridge"); 12869783Smsmith return(-10000); 12969783Smsmith } 13069783Smsmith return(ENXIO); 13169783Smsmith} 13269783Smsmith 13369783Smsmithstatic int 13469783Smsmithpcib_attach(device_t dev) 13569783Smsmith{ 13669783Smsmith struct pcib_softc *sc; 13769908Smsmith device_t child; 13869908Smsmith u_int8_t iolow; 13969783Smsmith 14069783Smsmith sc = device_get_softc(dev); 14169783Smsmith sc->dev = dev; 14269783Smsmith 14369908Smsmith /* 14469908Smsmith * Get current bridge configuration. 14569908Smsmith */ 14669953Smsmith sc->command = pci_read_config(dev, PCIR_COMMAND, 1); 14769908Smsmith sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 14869908Smsmith sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 14969908Smsmith sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 15069908Smsmith sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 15169908Smsmith sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 15269783Smsmith 15369908Smsmith /* 15469908Smsmith * Determine current I/O decode. 15569908Smsmith */ 15669953Smsmith if (sc->command & PCIM_CMD_PORTEN) { 15769953Smsmith iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 15869953Smsmith if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 15969953Smsmith sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), 16069953Smsmith pci_read_config(dev, PCIR_IOBASEL_1, 1)); 16169953Smsmith } else { 16269953Smsmith sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); 16369953Smsmith } 16469908Smsmith 16569953Smsmith iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 16669953Smsmith if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 16769953Smsmith sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), 16869953Smsmith pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 16969953Smsmith } else { 17069953Smsmith sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 17169953Smsmith } 17269908Smsmith } 17369908Smsmith 17469908Smsmith /* 17569908Smsmith * Determine current memory decode. 17669908Smsmith */ 17769953Smsmith if (sc->command & PCIM_CMD_MEMEN) { 17869953Smsmith sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); 17969953Smsmith sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 18069953Smsmith sc->pmembase = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4), 18169953Smsmith pci_read_config(dev, PCIR_PMBASEL_1, 2)); 18269953Smsmith sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4), 18369953Smsmith pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 18469953Smsmith } 18569908Smsmith 18669908Smsmith /* 18769908Smsmith * Quirk handling. 18869908Smsmith */ 18969908Smsmith switch (pci_get_devid(dev)) { 19069908Smsmith case 0x12258086: /* Intel 82454KX/GX (Orion) */ 19169908Smsmith { 19269908Smsmith u_int8_t supbus; 19369908Smsmith 19469908Smsmith supbus = pci_read_config(dev, 0x41, 1); 19569908Smsmith if (supbus != 0xff) { 19669908Smsmith sc->secbus = supbus + 1; 19769908Smsmith sc->subbus = supbus + 1; 19869908Smsmith } 19969908Smsmith } 20069908Smsmith break; 20169908Smsmith } 20269908Smsmith 20369783Smsmith if (bootverbose) { 20469783Smsmith device_printf(dev, " secondary bus %d\n", sc->secbus); 20569783Smsmith device_printf(dev, " subordinate bus %d\n", sc->subbus); 20669783Smsmith device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); 20769783Smsmith device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit); 20869783Smsmith device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit); 20969783Smsmith } 21069783Smsmith 21169783Smsmith /* 21269783Smsmith * XXX If the secondary bus number is zero, we should assign a bus number 21369783Smsmith * since the BIOS hasn't, then initialise the bridge. 21469783Smsmith */ 21569783Smsmith 21669783Smsmith /* 21769783Smsmith * XXX If the subordinate bus number is less than the secondary bus number, 21869783Smsmith * we should pick a better value. One sensible alternative would be to 21969783Smsmith * pick 255; the only tradeoff here is that configuration transactions 22069783Smsmith * would be more widely routed than absolutely necessary. 22169783Smsmith */ 22269783Smsmith 22369783Smsmith if (sc->secbus != 0) { 22469783Smsmith child = device_add_child(dev, "pci", -1); 22569783Smsmith if (child != NULL) 22669783Smsmith return(bus_generic_attach(dev)); 22769783Smsmith } 22869783Smsmith 22969783Smsmith /* no secondary bus; we should have fixed this */ 23069783Smsmith return(0); 23169783Smsmith} 23269783Smsmith 23369783Smsmithstatic int 23469783Smsmithpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 23569783Smsmith{ 23669783Smsmith struct pcib_softc *sc = device_get_softc(dev); 23769783Smsmith 23869783Smsmith switch (which) { 23969783Smsmith case PCIB_IVAR_BUS: 24069783Smsmith *result = sc->secbus; 24169783Smsmith return(0); 24269783Smsmith } 24369783Smsmith return(ENOENT); 24469783Smsmith} 24569783Smsmith 24669783Smsmithstatic int 24769783Smsmithpcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 24869783Smsmith{ 24969783Smsmith struct pcib_softc *sc = device_get_softc(dev); 25069783Smsmith 25169783Smsmith switch (which) { 25269783Smsmith case PCIB_IVAR_BUS: 25369783Smsmith sc->secbus = value; 25469783Smsmith break; 25569783Smsmith } 25669783Smsmith return(ENOENT); 25769783Smsmith} 25869783Smsmith 25969783Smsmith/* 26090388Simp * Is this a decoded ISA I/O port address? Note, we need to do the mask that 26190388Simp * we do below because of the ISA alias addresses. I'm not 100% sure that 26290388Simp * this is correct. 26390388Simp */ 26490388Simpstatic int 26590388Simppcib_is_isa_io(u_long start) 26690388Simp{ 26790388Simp if ((start & 0xfffUL) > 0x3ffUL) 26890388Simp return (0); 26990388Simp return (1); 27090388Simp} 27190388Simp 27290388Simp/* 27390388Simp * Is this a decoded ISA memory address? 27490388Simp */ 27590388Simpstatic int 27690388Simppcib_is_isa_mem(u_long start) 27790388Simp{ 27890388Simp if (start > 0xfffffUL) 27990388Simp return (0); 28090388Simp return (1); 28190388Simp} 28290388Simp 28390388Simp/* 28469783Smsmith * We have to trap resource allocation requests and ensure that the bridge 28569783Smsmith * is set up to, or capable of handling them. 28669783Smsmith */ 28769783Smsmithstatic struct resource * 28869783Smsmithpcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 28969783Smsmith u_long start, u_long end, u_long count, u_int flags) 29069783Smsmith{ 29169783Smsmith struct pcib_softc *sc = device_get_softc(dev); 29269783Smsmith 29369783Smsmith /* 29469783Smsmith * If this is a "default" allocation against this rid, we can't work 29569783Smsmith * out where it's coming from (we should actually never see these) so we 29669783Smsmith * just have to punt. 29769783Smsmith */ 29869783Smsmith if ((start == 0) && (end == ~0)) { 29969783Smsmith device_printf(dev, "can't decode default resource id %d for %s%d, bypassing\n", 30069783Smsmith *rid, device_get_name(child), device_get_unit(child)); 30169783Smsmith } else { 30269783Smsmith /* 30369783Smsmith * Fail the allocation for this range if it's not supported. 30469783Smsmith * 30569783Smsmith * XXX we should probably just fix up the bridge decode and soldier on. 30669783Smsmith */ 30769783Smsmith switch (type) { 30869783Smsmith case SYS_RES_IOPORT: 30990388Simp if (!pcib_is_isa_io(start) && 31090388Simp ((start < sc->iobase) || (end > sc->iolimit))) { 31169783Smsmith device_printf(dev, "device %s%d requested unsupported I/O range 0x%lx-0x%lx" 31269783Smsmith " (decoding 0x%x-0x%x)\n", 31369783Smsmith device_get_name(child), device_get_unit(child), start, end, 31469783Smsmith sc->iobase, sc->iolimit); 31590388Simp return (NULL); 31669783Smsmith } 31769908Smsmith if (bootverbose) 31869908Smsmith device_printf(sc->dev, "device %s%d requested decoded I/O range 0x%lx-0x%lx\n", 31969908Smsmith device_get_name(child), device_get_unit(child), start, end); 32069783Smsmith break; 32169783Smsmith 32269783Smsmith /* 32369783Smsmith * XXX will have to decide whether the device making the request is asking 32469783Smsmith * for prefetchable memory or not. If it's coming from another bridge 32569783Smsmith * down the line, do we assume not, or ask the bridge to pass in another 32669783Smsmith * flag as the request bubbles up? 32769783Smsmith */ 32869783Smsmith case SYS_RES_MEMORY: 32990388Simp if (!pcib_is_isa_mem(start) && 33090388Simp (((start < sc->membase) || (end > sc->memlimit)) && 33190388Simp ((start < sc->pmembase) || (end > sc->pmemlimit)))) { 33290435Simp if (bootverbose) 33390435Simp device_printf(dev, 33490435Simp "device %s%d requested unsupported memory range " 33590435Simp "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", 33690435Simp device_get_name(child), device_get_unit(child), start, 33790435Simp end, sc->membase, sc->memlimit, sc->pmembase, 33890435Simp sc->pmemlimit); 33983951Sbrooks#ifndef PCI_ALLOW_UNSUPPORTED_IO_RANGE 34069783Smsmith return(NULL); 34183951Sbrooks#endif 34269783Smsmith } 34369908Smsmith if (bootverbose) 34469908Smsmith device_printf(sc->dev, "device %s%d requested decoded memory range 0x%lx-0x%lx\n", 34569908Smsmith device_get_name(child), device_get_unit(child), start, end); 34669908Smsmith break; 34769908Smsmith 34869783Smsmith default: 34969908Smsmith break; 35069783Smsmith } 35169783Smsmith } 35269908Smsmith 35369783Smsmith /* 35469783Smsmith * Bridge is OK decoding this resource, so pass it up. 35569783Smsmith */ 35669783Smsmith return(bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); 35769783Smsmith} 35869783Smsmith 35969783Smsmith/* 36069783Smsmith * PCIB interface. 36169783Smsmith */ 36269783Smsmithstatic int 36369783Smsmithpcib_maxslots(device_t dev) 36469783Smsmith{ 36569908Smsmith return(PCI_SLOTMAX); 36669783Smsmith} 36769783Smsmith 36869783Smsmith/* 36969783Smsmith * Since we are a child of a PCI bus, its parent must support the pcib interface. 37069783Smsmith */ 37169783Smsmithstatic u_int32_t 37269783Smsmithpcib_read_config(device_t dev, int b, int s, int f, int reg, int width) 37369783Smsmith{ 37469783Smsmith return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 37569783Smsmith} 37669783Smsmith 37769783Smsmithstatic void 37869783Smsmithpcib_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, int width) 37969783Smsmith{ 38069783Smsmith PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 38169783Smsmith} 38269783Smsmith 38369783Smsmith/* 38469783Smsmith * Route an interrupt across a PCI bridge. 38569783Smsmith */ 38669783Smsmithstatic int 38769783Smsmithpcib_route_interrupt(device_t pcib, device_t dev, int pin) 38869783Smsmith{ 38969783Smsmith device_t bus; 39069783Smsmith int parent_intpin; 39169783Smsmith int intnum; 39269783Smsmith 39369783Smsmith /* 39469783Smsmith * 39569783Smsmith * The PCI standard defines a swizzle of the child-side device/intpin to 39669783Smsmith * the parent-side intpin as follows. 39769783Smsmith * 39869783Smsmith * device = device on child bus 39969783Smsmith * child_intpin = intpin on child bus slot (0-3) 40069783Smsmith * parent_intpin = intpin on parent bus slot (0-3) 40169783Smsmith * 40269783Smsmith * parent_intpin = (device + child_intpin) % 4 40369783Smsmith */ 40469783Smsmith parent_intpin = (pci_get_slot(pcib) + (pin - 1)) % 4; 40569783Smsmith 40669783Smsmith /* 40769783Smsmith * Our parent is a PCI bus. Its parent must export the pcib interface 40869783Smsmith * which includes the ability to route interrupts. 40969783Smsmith */ 41069783Smsmith bus = device_get_parent(pcib); 41169783Smsmith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 41290554Smsmith if (PCI_INTERRUPT_VALID(intnum)) { 41390554Smsmith device_printf(pcib, "routed slot %d INT%c to irq %d\n", pci_get_slot(dev), 41490554Smsmith 'A' + pin - 1, intnum); 41590554Smsmith } 41669783Smsmith return(intnum); 41769783Smsmith} 418