1139790Simp/*- 226159Sse * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 326159Sse * All rights reserved. 426159Sse * 526159Sse * Redistribution and use in source and binary forms, with or without 626159Sse * modification, are permitted provided that the following conditions 726159Sse * are met: 826159Sse * 1. Redistributions of source code must retain the above copyright 926159Sse * notice unmodified, this list of conditions, and the following 1026159Sse * disclaimer. 1126159Sse * 2. Redistributions in binary form must reproduce the above copyright 1226159Sse * notice, this list of conditions and the following disclaimer in the 1326159Sse * documentation and/or other materials provided with the distribution. 1426159Sse * 1526159Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1626159Sse * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1726159Sse * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1826159Sse * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1926159Sse * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2026159Sse * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2126159Sse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2226159Sse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2326159Sse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2426159Sse * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2526159Sse */ 266104Sse 27115706Sobrien#include <sys/cdefs.h> 28115706Sobrien__FBSDID("$FreeBSD$"); 29115706Sobrien 30103122Sphk#include "opt_cpu.h" 31103122Sphk 3247307Speter#include <sys/param.h> 336734Sbde#include <sys/systm.h> 3447307Speter#include <sys/bus.h> 3547307Speter#include <sys/kernel.h> 3665304Speter#include <sys/malloc.h> 37129876Sphk#include <sys/module.h> 38221393Sjhb#include <sys/rman.h> 39136397Simp#include <sys/sysctl.h> 406734Sbde 41119288Simp#include <dev/pci/pcivar.h> 42119288Simp#include <dev/pci/pcireg.h> 43119288Simp#include <dev/pci/pcib_private.h> 4461994Smsmith#include <isa/isavar.h> 45126016Sjhb#ifdef CPU_ELAN 46126016Sjhb#include <machine/md_var.h> 47126016Sjhb#endif 48233707Sjhb#include <x86/legacyvar.h> 4966529Smsmith#include <machine/pci_cfgreg.h> 50136188Simp#include <machine/resource.h> 5159294Smsmith 5265176Sdfr#include "pcib_if.h" 5365176Sdfr 54115908Sjhbint 55115908Sjhblegacy_pcib_maxslots(device_t dev) 5659294Smsmith{ 5765176Sdfr return 31; 5865176Sdfr} 5965176Sdfr 6066529Smsmith/* read configuration space register */ 6166529Smsmith 62223428Sjhbuint32_t 63194018Savglegacy_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 64194018Savg u_int reg, int bytes) 6565176Sdfr{ 6666529Smsmith return(pci_cfgregread(bus, slot, func, reg, bytes)); 6759294Smsmith} 6859294Smsmith 6959294Smsmith/* write configuration space register */ 7059294Smsmith 71115908Sjhbvoid 72194018Savglegacy_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 73223428Sjhb u_int reg, uint32_t data, int bytes) 7459294Smsmith{ 7566529Smsmith pci_cfgregwrite(bus, slot, func, reg, data, bytes); 7659294Smsmith} 7759294Smsmith 78223440Sjhb/* route interrupt */ 79223440Sjhb 80223440Sjhbstatic int 81223440Sjhblegacy_pcib_route_interrupt(device_t pcib, device_t dev, int pin) 82223440Sjhb{ 83223440Sjhb 84223440Sjhb#ifdef __HAVE_PIR 85223440Sjhb return (pci_pir_route_interrupt(pci_get_bus(dev), pci_get_slot(dev), 86223440Sjhb pci_get_function(dev), pin)); 87223440Sjhb#else 88223440Sjhb /* No routing possible */ 89223440Sjhb return (PCI_INVALID_IRQ); 90223440Sjhb#endif 91223440Sjhb} 92223440Sjhb 93169221Sjhb/* Pass MSI requests up to the nexus. */ 94165128Sjhb 95165128Sjhbstatic int 96165128Sjhblegacy_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, 97165128Sjhb int *irqs) 98165128Sjhb{ 99165128Sjhb device_t bus; 100165128Sjhb 101165128Sjhb bus = device_get_parent(pcib); 102165128Sjhb return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 103165128Sjhb irqs)); 104165128Sjhb} 105165128Sjhb 106165128Sjhbstatic int 107169221Sjhblegacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 108165128Sjhb{ 109165128Sjhb device_t bus; 110165128Sjhb 111165128Sjhb bus = device_get_parent(pcib); 112169221Sjhb return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 113165128Sjhb} 114165128Sjhb 115233676Sjhbint 116169221Sjhblegacy_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 117169221Sjhb uint32_t *data) 118169221Sjhb{ 119233676Sjhb device_t bus, hostb; 120233676Sjhb int error, func, slot; 121169221Sjhb 122169221Sjhb bus = device_get_parent(pcib); 123233676Sjhb error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 124233676Sjhb if (error) 125233676Sjhb return (error); 126233676Sjhb 127233676Sjhb slot = legacy_get_pcislot(pcib); 128233676Sjhb func = legacy_get_pcifunc(pcib); 129233676Sjhb if (slot == -1 || func == -1) 130233676Sjhb return (0); 131233676Sjhb hostb = pci_find_bsf(0, slot, func); 132233676Sjhb KASSERT(hostb != NULL, ("%s: missing hostb for 0:%d:%d", __func__, 133233676Sjhb slot, func)); 134233676Sjhb pci_ht_map_msi(hostb, *addr); 135233676Sjhb return (0); 136169221Sjhb} 137169221Sjhb 13848832Smsmithstatic const char * 139115908Sjhblegacy_pcib_is_host_bridge(int bus, int slot, int func, 140136188Simp uint32_t id, uint8_t class, uint8_t subclass, 141136188Simp uint8_t *busnum) 14248832Smsmith{ 143223440Sjhb#ifdef __i386__ 14449580Swpaul const char *s = NULL; 145136188Simp static uint8_t pxb[4]; /* hack for 450nx */ 14648832Smsmith 14748832Smsmith *busnum = 0; 14848832Smsmith 14948832Smsmith switch (id) { 15048832Smsmith case 0x12258086: 15148832Smsmith s = "Intel 824?? host to PCI bridge"; 15248832Smsmith /* XXX This is a guess */ 153115908Sjhb /* *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x41, 1); */ 15465176Sdfr *busnum = bus; 15548832Smsmith break; 15657021Sn_hibma case 0x71208086: 15757021Sn_hibma s = "Intel 82810 (i810 GMCH) Host To Hub bridge"; 15857021Sn_hibma break; 15957021Sn_hibma case 0x71228086: 16057021Sn_hibma s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"; 16157021Sn_hibma break; 16257021Sn_hibma case 0x71248086: 16357021Sn_hibma s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; 16457021Sn_hibma break; 16567377Sache case 0x11308086: 16667377Sache s = "Intel 82815 (i815 GMCH) Host To Hub bridge"; 16767377Sache break; 16848832Smsmith case 0x71808086: 16948832Smsmith s = "Intel 82443LX (440 LX) host to PCI bridge"; 17048832Smsmith break; 17148832Smsmith case 0x71908086: 17248832Smsmith s = "Intel 82443BX (440 BX) host to PCI bridge"; 17348832Smsmith break; 17448832Smsmith case 0x71928086: 17548832Smsmith s = "Intel 82443BX host to PCI bridge (AGP disabled)"; 17648832Smsmith break; 17760847Skuriyama case 0x71948086: 17860847Skuriyama s = "Intel 82443MX host to PCI bridge"; 17960847Skuriyama break; 18048832Smsmith case 0x71a08086: 18148832Smsmith s = "Intel 82443GX host to PCI bridge"; 18248832Smsmith break; 18348832Smsmith case 0x71a18086: 18448832Smsmith s = "Intel 82443GX host to AGP bridge"; 18548832Smsmith break; 18648832Smsmith case 0x71a28086: 18748832Smsmith s = "Intel 82443GX host to PCI bridge (AGP disabled)"; 18848832Smsmith break; 18948832Smsmith case 0x84c48086: 19048832Smsmith s = "Intel 82454KX/GX (Orion) host to PCI bridge"; 191115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x4a, 1); 19248832Smsmith break; 19348832Smsmith case 0x84ca8086: 19448832Smsmith /* 19548832Smsmith * For the 450nx chipset, there is a whole bundle of 196137098Sdes * things pretending to be host bridges. The MIOC will 19748832Smsmith * be seen first and isn't really a pci bridge (the 198137098Sdes * actual busses are attached to the PXB's). We need to 19948832Smsmith * read the registers of the MIOC to figure out the 20048832Smsmith * bus numbers for the PXB channels. 20148832Smsmith * 20248832Smsmith * Since the MIOC doesn't have a pci bus attached, we 20348832Smsmith * pretend it wasn't there. 20448832Smsmith */ 205115908Sjhb pxb[0] = legacy_pcib_read_config(0, bus, slot, func, 20665176Sdfr 0xd0, 1); /* BUSNO[0] */ 207115908Sjhb pxb[1] = legacy_pcib_read_config(0, bus, slot, func, 20865176Sdfr 0xd1, 1) + 1; /* SUBA[0]+1 */ 209115908Sjhb pxb[2] = legacy_pcib_read_config(0, bus, slot, func, 21065176Sdfr 0xd3, 1); /* BUSNO[1] */ 211115908Sjhb pxb[3] = legacy_pcib_read_config(0, bus, slot, func, 21265176Sdfr 0xd4, 1) + 1; /* SUBA[1]+1 */ 21348832Smsmith return NULL; 21448832Smsmith case 0x84cb8086: 21565176Sdfr switch (slot) { 21648832Smsmith case 0x12: 21748832Smsmith s = "Intel 82454NX PXB#0, Bus#A"; 21848832Smsmith *busnum = pxb[0]; 21948832Smsmith break; 22048832Smsmith case 0x13: 22148832Smsmith s = "Intel 82454NX PXB#0, Bus#B"; 22248832Smsmith *busnum = pxb[1]; 22348832Smsmith break; 22448832Smsmith case 0x14: 22548832Smsmith s = "Intel 82454NX PXB#1, Bus#A"; 22648832Smsmith *busnum = pxb[2]; 22748832Smsmith break; 22848832Smsmith case 0x15: 22948832Smsmith s = "Intel 82454NX PXB#1, Bus#B"; 23048832Smsmith *busnum = pxb[3]; 23148832Smsmith break; 23248832Smsmith } 23348832Smsmith break; 234215820Sjhb case 0x1A308086: 235215820Sjhb s = "Intel 82845 Host to PCI bridge"; 236215820Sjhb break; 23748832Smsmith 23852480Salc /* AMD -- vendor 0x1022 */ 239100310Sphk case 0x30001022: 240100310Sphk s = "AMD Elan SC520 host to PCI bridge"; 241102934Sphk#ifdef CPU_ELAN 242100321Sphk init_AMD_Elan_sc520(); 243102934Sphk#else 244108239Sphk printf( 245108239Sphk"*** WARNING: missing CPU_ELAN -- timekeeping may be wrong\n"); 246102934Sphk#endif 247100310Sphk break; 24852480Salc case 0x70061022: 24952480Salc s = "AMD-751 host to PCI bridge"; 25052480Salc break; 25187603Smurray case 0x700e1022: 25287603Smurray s = "AMD-761 host to PCI bridge"; 25387603Smurray break; 25452480Salc 25548832Smsmith /* SiS -- vendor 0x1039 */ 25648832Smsmith case 0x04961039: 25748832Smsmith s = "SiS 85c496"; 25848832Smsmith break; 25948832Smsmith case 0x04061039: 26048832Smsmith s = "SiS 85c501"; 26148832Smsmith break; 26248832Smsmith case 0x06011039: 26348832Smsmith s = "SiS 85c601"; 26448832Smsmith break; 26548832Smsmith case 0x55911039: 26648832Smsmith s = "SiS 5591 host to PCI bridge"; 26748832Smsmith break; 26848832Smsmith case 0x00011039: 26948832Smsmith s = "SiS 5591 host to AGP bridge"; 27048832Smsmith break; 27149404Speter 27248832Smsmith /* VLSI -- vendor 0x1004 */ 27348832Smsmith case 0x00051004: 27448832Smsmith s = "VLSI 82C592 Host to PCI bridge"; 27548832Smsmith break; 27648832Smsmith 27748832Smsmith /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ 27848832Smsmith /* totally. Please let me know if anything wrong. -F */ 27948832Smsmith /* XXX need info on the MVP3 -- any takers? */ 28048832Smsmith case 0x05981106: 28148832Smsmith s = "VIA 82C598MVP (Apollo MVP3) host bridge"; 28248832Smsmith break; 28348832Smsmith 28448832Smsmith /* AcerLabs -- vendor 0x10b9 */ 28548832Smsmith /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ 28648832Smsmith /* id is '10b9" but the register always shows "10b9". -Foxfair */ 28748832Smsmith case 0x154110b9: 28848832Smsmith s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; 28948832Smsmith break; 29048832Smsmith 29148832Smsmith /* OPTi -- vendor 0x1045 */ 29260862Skuriyama case 0xc7011045: 29360862Skuriyama s = "OPTi 82C700 host to PCI bridge"; 29460862Skuriyama break; 29548832Smsmith case 0xc8221045: 29648832Smsmith s = "OPTi 82C822 host to PCI Bridge"; 29748832Smsmith break; 29848832Smsmith 29967126Salc /* ServerWorks -- vendor 0x1166 */ 30048832Smsmith case 0x00051166: 30167126Salc s = "ServerWorks NB6536 2.0HE host to PCI bridge"; 302115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 30348832Smsmith break; 304137098Sdes 30557092Sgallatin case 0x00061166: 30657092Sgallatin /* FALLTHROUGH */ 30757092Sgallatin case 0x00081166: 308100374Sgallatin /* FALLTHROUGH */ 309100374Sgallatin case 0x02011166: 310100374Sgallatin /* FALLTHROUGH */ 311100374Sgallatin case 0x010f1014: /* IBM re-badged ServerWorks chipset */ 31267126Salc s = "ServerWorks host to PCI bridge"; 313115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 31457092Sgallatin break; 31549601Speter 31657092Sgallatin case 0x00091166: 31767126Salc s = "ServerWorks NB6635 3.0LE host to PCI bridge"; 318115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 31957092Sgallatin break; 32057092Sgallatin 321106878Speter case 0x00101166: 322106878Speter s = "ServerWorks CIOB30 host to PCI bridge"; 323115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 324106878Speter break; 325106878Speter 326100374Sgallatin case 0x00111166: 327100374Sgallatin /* FALLTHROUGH */ 328100374Sgallatin case 0x03021014: /* IBM re-badged ServerWorks chipset */ 329100374Sgallatin s = "ServerWorks CMIC-HE host to PCI-X bridge"; 330115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 331100374Sgallatin break; 332100374Sgallatin 333104381Siwasaki /* XXX unknown chipset, but working */ 334104381Siwasaki case 0x00171166: 335104381Siwasaki /* FALLTHROUGH */ 336104381Siwasaki case 0x01011166: 337215820Sjhb case 0x01101166: 338215820Sjhb case 0x02251166: 339104381Siwasaki s = "ServerWorks host to PCI bridge(unknown chipset)"; 340115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 341104381Siwasaki break; 342104381Siwasaki 343144110Sjhb /* Compaq/HP -- vendor 0x0e11 */ 344144110Sjhb case 0x60100e11: 345144110Sjhb s = "Compaq/HP Model 6010 HotPlug PCI Bridge"; 346144110Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0xc8, 1); 347144110Sjhb break; 348144110Sjhb 34949601Speter /* Integrated Micro Solutions -- vendor 0x10e0 */ 35049580Swpaul case 0x884910e0: 35149580Swpaul s = "Integrated Micro Solutions VL Bridge"; 35249580Swpaul break; 35349601Speter 35449580Swpaul default: 35549601Speter if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 35649601Speter s = "Host to PCI bridge"; 35749580Swpaul break; 35848832Smsmith } 35948832Smsmith 36048832Smsmith return s; 361223440Sjhb#else 362223440Sjhb const char *s = NULL; 363223440Sjhb 364223440Sjhb *busnum = 0; 365223440Sjhb if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 366223440Sjhb s = "Host to PCI bridge"; 367223440Sjhb return s; 368223440Sjhb#endif 36948832Smsmith} 37048832Smsmith 37148832Smsmith/* 37248832Smsmith * Scan the first pci bus for host-pci bridges and add pcib instances 37348832Smsmith * to the nexus for each bridge. 37448832Smsmith */ 37548832Smsmithstatic void 376115908Sjhblegacy_pcib_identify(driver_t *driver, device_t parent) 37748832Smsmith{ 37865176Sdfr int bus, slot, func; 379223428Sjhb uint8_t hdrtype; 38053363Speter int found = 0; 38157092Sgallatin int pcifunchigh; 38257402Sdfr int found824xx = 0; 38368485Smsmith int found_orion = 0; 38465304Speter device_t child; 38566843Smsmith devclass_t pci_devclass; 38648832Smsmith 38766529Smsmith if (pci_cfgregopen() == 0) 38849404Speter return; 38966843Smsmith /* 39066843Smsmith * Check to see if we haven't already had a PCI bus added 39166843Smsmith * via some other means. If we have, bail since otherwise 39266843Smsmith * we're going to end up duplicating it. 39366843Smsmith */ 394137098Sdes if ((pci_devclass = devclass_find("pci")) && 39566843Smsmith devclass_get_device(pci_devclass, 0)) 39666843Smsmith return; 39766843Smsmith 39866843Smsmith 39965176Sdfr bus = 0; 40057402Sdfr retry: 40165176Sdfr for (slot = 0; slot <= PCI_SLOTMAX; slot++) { 40265176Sdfr func = 0; 403115908Sjhb hdrtype = legacy_pcib_read_config(0, bus, slot, func, 404119539Sjhb PCIR_HDRTYPE, 1); 405118328Simp /* 406118328Simp * When enumerating bus devices, the standard says that 407118328Simp * one should check the header type and ignore the slots whose 408118328Simp * header types that the software doesn't know about. We use 409118328Simp * this to filter out devices. 410118328Simp */ 411119539Sjhb if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 412118328Simp continue; 413137098Sdes if ((hdrtype & PCIM_MFDEV) && 41468485Smsmith (!found_orion || hdrtype != 0xff)) 415119539Sjhb pcifunchigh = PCI_FUNCMAX; 41657092Sgallatin else 41757092Sgallatin pcifunchigh = 0; 41865176Sdfr for (func = 0; func <= pcifunchigh; func++) { 41948832Smsmith /* 42048832Smsmith * Read the IDs and class from the device. 42148832Smsmith */ 422223428Sjhb uint32_t id; 423223428Sjhb uint8_t class, subclass, busnum; 42448832Smsmith const char *s; 42565459Speter device_t *devs; 42665459Speter int ndevs, i; 42748832Smsmith 428115908Sjhb id = legacy_pcib_read_config(0, bus, slot, func, 42965176Sdfr PCIR_DEVVENDOR, 4); 430105535Sphk if (id == -1) 431105535Sphk continue; 432115908Sjhb class = legacy_pcib_read_config(0, bus, slot, func, 43365176Sdfr PCIR_CLASS, 1); 434115908Sjhb subclass = legacy_pcib_read_config(0, bus, slot, func, 43565176Sdfr PCIR_SUBCLASS, 1); 43648832Smsmith 437115908Sjhb s = legacy_pcib_is_host_bridge(bus, slot, func, 43865176Sdfr id, class, subclass, 43948832Smsmith &busnum); 44065459Speter if (s == NULL) 44165459Speter continue; 44265304Speter 44365459Speter /* 44465459Speter * Check to see if the physical bus has already 44565459Speter * been seen. Eg: hybrid 32 and 64 bit host 44665459Speter * bridges to the same logical bus. 44765459Speter */ 44865459Speter if (device_get_children(parent, &devs, &ndevs) == 0) { 44965459Speter for (i = 0; s != NULL && i < ndevs; i++) { 45065459Speter if (strcmp(device_get_name(devs[i]), 45165459Speter "pcib") != 0) 45265459Speter continue; 453103863Sjhb if (legacy_get_pcibus(devs[i]) == busnum) 45465459Speter s = NULL; 45565459Speter } 45665459Speter free(devs, M_TEMP); 45765459Speter } 45865304Speter 45965459Speter if (s == NULL) 46065459Speter continue; 46165459Speter /* 46265459Speter * Add at priority 100 to make sure we 46365459Speter * go after any motherboard resources 46465459Speter */ 46565459Speter child = BUS_ADD_CHILD(parent, 100, 46665459Speter "pcib", busnum); 46765459Speter device_set_desc(child, s); 468103863Sjhb legacy_set_pcibus(child, busnum); 469233676Sjhb legacy_set_pcislot(child, slot); 470233676Sjhb legacy_set_pcifunc(child, func); 47165459Speter 47265459Speter found = 1; 47365459Speter if (id == 0x12258086) 47465459Speter found824xx = 1; 47568485Smsmith if (id == 0x84c48086) 47668485Smsmith found_orion = 1; 47748832Smsmith } 47848832Smsmith } 47965176Sdfr if (found824xx && bus == 0) { 48065176Sdfr bus++; 48157402Sdfr goto retry; 48257402Sdfr } 48353363Speter 48453363Speter /* 48553363Speter * Make sure we add at least one bridge since some old 48653363Speter * hardware doesn't actually have a host-pci bridge device. 48766529Smsmith * Note that pci_cfgregopen() thinks we have PCI devices.. 48853363Speter */ 48953363Speter if (!found) { 49053363Speter if (bootverbose) 49153363Speter printf( 492115908Sjhb "legacy_pcib_identify: no bridge found, adding pcib0 anyway\n"); 49365304Speter child = BUS_ADD_CHILD(parent, 100, "pcib", 0); 494103863Sjhb legacy_set_pcibus(child, 0); 49553363Speter } 49648832Smsmith} 49748832Smsmith 49847307Speterstatic int 499115908Sjhblegacy_pcib_probe(device_t dev) 50047307Speter{ 50165304Speter 50266843Smsmith if (pci_cfgregopen() == 0) 50366843Smsmith return ENXIO; 504121822Sjhb return -100; 50547307Speter} 50647307Speter 507128874Sjhbstatic int 508115908Sjhblegacy_pcib_attach(device_t dev) 50965176Sdfr{ 510223440Sjhb#ifdef __HAVE_PIR 511128933Sjhb device_t pir; 512223440Sjhb#endif 513125981Sjhb int bus; 51465304Speter 515223440Sjhb bus = pcib_get_bus(dev); 516223440Sjhb#ifdef __HAVE_PIR 517125981Sjhb /* 518125981Sjhb * Look for a PCI BIOS interrupt routing table as that will be 519125981Sjhb * our method of routing interrupts if we have one. 520125981Sjhb */ 521128933Sjhb if (pci_pir_probe(bus, 0)) { 522128933Sjhb pir = BUS_ADD_CHILD(device_get_parent(dev), 0, "pir", 0); 523129962Sjhb if (pir != NULL) 524129962Sjhb device_probe_and_attach(pir); 525128933Sjhb } 526223440Sjhb#endif 527125981Sjhb device_add_child(dev, "pci", bus); 52865304Speter return bus_generic_attach(dev); 52965304Speter} 53065304Speter 531115908Sjhbint 532115908Sjhblegacy_pcib_read_ivar(device_t dev, device_t child, int which, 533115908Sjhb uintptr_t *result) 53465304Speter{ 53565304Speter 53665176Sdfr switch (which) { 537172394Smarius case PCIB_IVAR_DOMAIN: 538172394Smarius *result = 0; 539172394Smarius return 0; 54065176Sdfr case PCIB_IVAR_BUS: 541103863Sjhb *result = legacy_get_pcibus(dev); 54265176Sdfr return 0; 54365176Sdfr } 54465176Sdfr return ENOENT; 54565176Sdfr} 54665176Sdfr 547115908Sjhbint 548115908Sjhblegacy_pcib_write_ivar(device_t dev, device_t child, int which, 549115908Sjhb uintptr_t value) 55065304Speter{ 55165304Speter 55265304Speter switch (which) { 553172394Smarius case PCIB_IVAR_DOMAIN: 554172394Smarius return EINVAL; 55565304Speter case PCIB_IVAR_BUS: 556103863Sjhb legacy_set_pcibus(dev, value); 55765304Speter return 0; 55865304Speter } 55965304Speter return ENOENT; 56065304Speter} 56165304Speter 562223424Sjhb/* 563223424Sjhb * Helper routine for x86 Host-PCI bridge driver resource allocation. 564223424Sjhb * This is used to adjust the start address of wildcard allocation 565223424Sjhb * requests to avoid low addresses that are known to be problematic. 566223424Sjhb * 567223424Sjhb * If no memory preference is given, use upper 32MB slot most BIOSes 568223424Sjhb * use for their memory window. This is typically only used on older 569223424Sjhb * laptops that don't have PCI busses behind a PCI bridge, so assuming 570223424Sjhb * > 32MB is likely OK. 571223424Sjhb * 572223424Sjhb * However, this can cause problems for other chipsets, so we make 573223424Sjhb * this tunable by hw.pci.host_mem_start. 574223424Sjhb */ 575136397SimpSYSCTL_DECL(_hw_pci); 576136397Simp 577223424Sjhbstatic unsigned long host_mem_start = 0x80000000; 578223424SjhbTUNABLE_ULONG("hw.pci.host_mem_start", &host_mem_start); 579223424SjhbSYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RDTUN, &host_mem_start, 580223424Sjhb 0, "Limit the host bridge memory to being above this address."); 581136397Simp 582223424Sjhbu_long 583223424Sjhbhostb_alloc_start(int type, u_long start, u_long end, u_long count) 584223424Sjhb{ 585223424Sjhb 586223424Sjhb if (start + count - 1 != end) { 587223424Sjhb if (type == SYS_RES_MEMORY && start < host_mem_start) 588223424Sjhb start = host_mem_start; 589223424Sjhb if (type == SYS_RES_IOPORT && start < 0x1000) 590223424Sjhb start = 0x1000; 591223424Sjhb } 592223424Sjhb return (start); 593223424Sjhb} 594223424Sjhb 595150264Simpstruct resource * 596136188Simplegacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 597136188Simp u_long start, u_long end, u_long count, u_int flags) 598136188Simp{ 599223424Sjhb 600223424Sjhb start = hostb_alloc_start(type, start, end, count); 601136188Simp return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 602136188Simp count, flags)); 603136188Simp} 604136188Simp 605115908Sjhbstatic device_method_t legacy_pcib_methods[] = { 60647307Speter /* Device interface */ 607115908Sjhb DEVMETHOD(device_identify, legacy_pcib_identify), 608115908Sjhb DEVMETHOD(device_probe, legacy_pcib_probe), 609115908Sjhb DEVMETHOD(device_attach, legacy_pcib_attach), 61047307Speter DEVMETHOD(device_shutdown, bus_generic_shutdown), 61147307Speter DEVMETHOD(device_suspend, bus_generic_suspend), 61247307Speter DEVMETHOD(device_resume, bus_generic_resume), 61347307Speter 61447307Speter /* Bus interface */ 615115908Sjhb DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar), 616115908Sjhb DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar), 617136188Simp DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), 618221324Sjhb DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 61947307Speter DEVMETHOD(bus_release_resource, bus_generic_release_resource), 62047307Speter DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 62147307Speter DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 62247307Speter DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 62347307Speter DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 62447307Speter 62565176Sdfr /* pcib interface */ 626115908Sjhb DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots), 627115908Sjhb DEVMETHOD(pcib_read_config, legacy_pcib_read_config), 628115908Sjhb DEVMETHOD(pcib_write_config, legacy_pcib_write_config), 629223440Sjhb DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), 630165128Sjhb DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), 631164265Sjhb DEVMETHOD(pcib_release_msi, pcib_release_msi), 632165128Sjhb DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), 633164265Sjhb DEVMETHOD(pcib_release_msix, pcib_release_msix), 634169221Sjhb DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi), 63565176Sdfr 636227843Smarius DEVMETHOD_END 63747307Speter}; 63847307Speter 639154079Sjhbstatic devclass_t hostb_devclass; 64047307Speter 641154079SjhbDEFINE_CLASS_0(pcib, legacy_pcib_driver, legacy_pcib_methods, 1); 642154079SjhbDRIVER_MODULE(pcib, legacy, legacy_pcib_driver, hostb_devclass, 0, 0); 64361994Smsmith 64465459Speter 64561994Smsmith/* 64661994Smsmith * Install placeholder to claim the resources owned by the 647137098Sdes * PCI bus interface. This could be used to extract the 64861994Smsmith * config space registers in the extreme case where the PnP 64961994Smsmith * ID is available and the PCI BIOS isn't, but for now we just 65061994Smsmith * eat the PnP ID and do nothing else. 65161994Smsmith * 652137098Sdes * XXX we should silence this probe, as it will generally confuse 65361994Smsmith * people. 65461994Smsmith */ 65561994Smsmithstatic struct isa_pnp_id pcibus_pnp_ids[] = { 65695374Simp { 0x030ad041 /* PNP0A03 */, "PCI Bus" }, 657195666Sjkim { 0x080ad041 /* PNP0A08 */, "PCIe Bus" }, 65861994Smsmith { 0 } 65961994Smsmith}; 66061994Smsmith 66161994Smsmithstatic int 66261994Smsmithpcibus_pnp_probe(device_t dev) 66361994Smsmith{ 66461994Smsmith int result; 665137098Sdes 66661994Smsmith if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0) 66761994Smsmith device_quiet(dev); 66861994Smsmith return(result); 66961994Smsmith} 67061994Smsmith 67161994Smsmithstatic int 67261994Smsmithpcibus_pnp_attach(device_t dev) 67361994Smsmith{ 67461994Smsmith return(0); 67561994Smsmith} 67661994Smsmith 67761994Smsmithstatic device_method_t pcibus_pnp_methods[] = { 67861994Smsmith /* Device interface */ 67961994Smsmith DEVMETHOD(device_probe, pcibus_pnp_probe), 68061994Smsmith DEVMETHOD(device_attach, pcibus_pnp_attach), 68161994Smsmith DEVMETHOD(device_detach, bus_generic_detach), 68261994Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 68361994Smsmith DEVMETHOD(device_suspend, bus_generic_suspend), 68461994Smsmith DEVMETHOD(device_resume, bus_generic_resume), 68561994Smsmith { 0, 0 } 68661994Smsmith}; 68761994Smsmith 68861994Smsmithstatic devclass_t pcibus_pnp_devclass; 68961994Smsmith 690154079SjhbDEFINE_CLASS_0(pcibus_pnp, pcibus_pnp_driver, pcibus_pnp_methods, 1); 69161994SmsmithDRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0); 692103044Sjhb 693223440Sjhb#ifdef __HAVE_PIR 694103044Sjhb/* 695103044Sjhb * Provide a PCI-PCI bridge driver for PCI busses behind PCI-PCI bridges 696103044Sjhb * that appear in the PCIBIOS Interrupt Routing Table to use the routing 697103044Sjhb * table for interrupt routing when possible. 698103044Sjhb */ 699103044Sjhbstatic int pcibios_pcib_probe(device_t bus); 700103044Sjhb 701103044Sjhbstatic device_method_t pcibios_pcib_pci_methods[] = { 702103044Sjhb /* Device interface */ 703103044Sjhb DEVMETHOD(device_probe, pcibios_pcib_probe), 704103044Sjhb 705103044Sjhb /* pcib interface */ 706223440Sjhb DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), 707103044Sjhb 708103044Sjhb {0, 0} 709103044Sjhb}; 710103044Sjhb 711154079Sjhbstatic devclass_t pcib_devclass; 712103044Sjhb 713210868SjhbDEFINE_CLASS_1(pcib, pcibios_pcib_driver, pcibios_pcib_pci_methods, 714210868Sjhb sizeof(struct pcib_softc), pcib_driver); 715103044SjhbDRIVER_MODULE(pcibios_pcib, pci, pcibios_pcib_driver, pcib_devclass, 0, 0); 716103044Sjhb 717103044Sjhbstatic int 718103044Sjhbpcibios_pcib_probe(device_t dev) 719103044Sjhb{ 720115906Sjhb int bus; 721103044Sjhb 722103044Sjhb if ((pci_get_class(dev) != PCIC_BRIDGE) || 723103044Sjhb (pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) 724103044Sjhb return (ENXIO); 725115906Sjhb bus = pci_read_config(dev, PCIR_SECBUS_1, 1); 726115906Sjhb if (bus == 0) 727103044Sjhb return (ENXIO); 728125981Sjhb if (!pci_pir_probe(bus, 1)) 729115906Sjhb return (ENXIO); 730103044Sjhb device_set_desc(dev, "PCIBIOS PCI-PCI bridge"); 731103044Sjhb return (-2000); 732103044Sjhb} 733223440Sjhb#endif 734