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 48103863Sjhb#include <machine/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 115234150Sjhbint 116169221Sjhblegacy_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 117169221Sjhb uint32_t *data) 118169221Sjhb{ 119234150Sjhb device_t bus, hostb; 120234150Sjhb int error, func, slot; 121169221Sjhb 122169221Sjhb bus = device_get_parent(pcib); 123234150Sjhb error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 124234150Sjhb if (error) 125234150Sjhb return (error); 126234150Sjhb 127234150Sjhb slot = legacy_get_pcislot(pcib); 128234150Sjhb func = legacy_get_pcifunc(pcib); 129234150Sjhb if (slot == -1 || func == -1) 130234150Sjhb return (0); 131234150Sjhb hostb = pci_find_bsf(0, slot, func); 132234150Sjhb KASSERT(hostb != NULL, ("%s: missing hostb for 0:%d:%d", __func__, 133234150Sjhb slot, func)); 134234150Sjhb pci_ht_map_msi(hostb, *addr); 135234150Sjhb return (0); 136234150Sjhb 137169221Sjhb} 138169221Sjhb 13948832Smsmithstatic const char * 140115908Sjhblegacy_pcib_is_host_bridge(int bus, int slot, int func, 141136188Simp uint32_t id, uint8_t class, uint8_t subclass, 142136188Simp uint8_t *busnum) 14348832Smsmith{ 144223440Sjhb#ifdef __i386__ 14549580Swpaul const char *s = NULL; 146136188Simp static uint8_t pxb[4]; /* hack for 450nx */ 14748832Smsmith 14848832Smsmith *busnum = 0; 14948832Smsmith 15048832Smsmith switch (id) { 15148832Smsmith case 0x12258086: 15248832Smsmith s = "Intel 824?? host to PCI bridge"; 15348832Smsmith /* XXX This is a guess */ 154115908Sjhb /* *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x41, 1); */ 15565176Sdfr *busnum = bus; 15648832Smsmith break; 15757021Sn_hibma case 0x71208086: 15857021Sn_hibma s = "Intel 82810 (i810 GMCH) Host To Hub bridge"; 15957021Sn_hibma break; 16057021Sn_hibma case 0x71228086: 16157021Sn_hibma s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"; 16257021Sn_hibma break; 16357021Sn_hibma case 0x71248086: 16457021Sn_hibma s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; 16557021Sn_hibma break; 16667377Sache case 0x11308086: 16767377Sache s = "Intel 82815 (i815 GMCH) Host To Hub bridge"; 16867377Sache break; 16948832Smsmith case 0x71808086: 17048832Smsmith s = "Intel 82443LX (440 LX) host to PCI bridge"; 17148832Smsmith break; 17248832Smsmith case 0x71908086: 17348832Smsmith s = "Intel 82443BX (440 BX) host to PCI bridge"; 17448832Smsmith break; 17548832Smsmith case 0x71928086: 17648832Smsmith s = "Intel 82443BX host to PCI bridge (AGP disabled)"; 17748832Smsmith break; 17860847Skuriyama case 0x71948086: 17960847Skuriyama s = "Intel 82443MX host to PCI bridge"; 18060847Skuriyama break; 18148832Smsmith case 0x71a08086: 18248832Smsmith s = "Intel 82443GX host to PCI bridge"; 18348832Smsmith break; 18448832Smsmith case 0x71a18086: 18548832Smsmith s = "Intel 82443GX host to AGP bridge"; 18648832Smsmith break; 18748832Smsmith case 0x71a28086: 18848832Smsmith s = "Intel 82443GX host to PCI bridge (AGP disabled)"; 18948832Smsmith break; 19048832Smsmith case 0x84c48086: 19148832Smsmith s = "Intel 82454KX/GX (Orion) host to PCI bridge"; 192115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x4a, 1); 19348832Smsmith break; 19448832Smsmith case 0x84ca8086: 19548832Smsmith /* 19648832Smsmith * For the 450nx chipset, there is a whole bundle of 197137098Sdes * things pretending to be host bridges. The MIOC will 19848832Smsmith * be seen first and isn't really a pci bridge (the 199137098Sdes * actual busses are attached to the PXB's). We need to 20048832Smsmith * read the registers of the MIOC to figure out the 20148832Smsmith * bus numbers for the PXB channels. 20248832Smsmith * 20348832Smsmith * Since the MIOC doesn't have a pci bus attached, we 20448832Smsmith * pretend it wasn't there. 20548832Smsmith */ 206115908Sjhb pxb[0] = legacy_pcib_read_config(0, bus, slot, func, 20765176Sdfr 0xd0, 1); /* BUSNO[0] */ 208115908Sjhb pxb[1] = legacy_pcib_read_config(0, bus, slot, func, 20965176Sdfr 0xd1, 1) + 1; /* SUBA[0]+1 */ 210115908Sjhb pxb[2] = legacy_pcib_read_config(0, bus, slot, func, 21165176Sdfr 0xd3, 1); /* BUSNO[1] */ 212115908Sjhb pxb[3] = legacy_pcib_read_config(0, bus, slot, func, 21365176Sdfr 0xd4, 1) + 1; /* SUBA[1]+1 */ 21448832Smsmith return NULL; 21548832Smsmith case 0x84cb8086: 21665176Sdfr switch (slot) { 21748832Smsmith case 0x12: 21848832Smsmith s = "Intel 82454NX PXB#0, Bus#A"; 21948832Smsmith *busnum = pxb[0]; 22048832Smsmith break; 22148832Smsmith case 0x13: 22248832Smsmith s = "Intel 82454NX PXB#0, Bus#B"; 22348832Smsmith *busnum = pxb[1]; 22448832Smsmith break; 22548832Smsmith case 0x14: 22648832Smsmith s = "Intel 82454NX PXB#1, Bus#A"; 22748832Smsmith *busnum = pxb[2]; 22848832Smsmith break; 22948832Smsmith case 0x15: 23048832Smsmith s = "Intel 82454NX PXB#1, Bus#B"; 23148832Smsmith *busnum = pxb[3]; 23248832Smsmith break; 23348832Smsmith } 23448832Smsmith break; 235215820Sjhb case 0x1A308086: 236215820Sjhb s = "Intel 82845 Host to PCI bridge"; 237215820Sjhb break; 23848832Smsmith 23952480Salc /* AMD -- vendor 0x1022 */ 240100310Sphk case 0x30001022: 241100310Sphk s = "AMD Elan SC520 host to PCI bridge"; 242102934Sphk#ifdef CPU_ELAN 243100321Sphk init_AMD_Elan_sc520(); 244102934Sphk#else 245108239Sphk printf( 246108239Sphk"*** WARNING: missing CPU_ELAN -- timekeeping may be wrong\n"); 247102934Sphk#endif 248100310Sphk break; 24952480Salc case 0x70061022: 25052480Salc s = "AMD-751 host to PCI bridge"; 25152480Salc break; 25287603Smurray case 0x700e1022: 25387603Smurray s = "AMD-761 host to PCI bridge"; 25487603Smurray break; 25552480Salc 25648832Smsmith /* SiS -- vendor 0x1039 */ 25748832Smsmith case 0x04961039: 25848832Smsmith s = "SiS 85c496"; 25948832Smsmith break; 26048832Smsmith case 0x04061039: 26148832Smsmith s = "SiS 85c501"; 26248832Smsmith break; 26348832Smsmith case 0x06011039: 26448832Smsmith s = "SiS 85c601"; 26548832Smsmith break; 26648832Smsmith case 0x55911039: 26748832Smsmith s = "SiS 5591 host to PCI bridge"; 26848832Smsmith break; 26948832Smsmith case 0x00011039: 27048832Smsmith s = "SiS 5591 host to AGP bridge"; 27148832Smsmith break; 27249404Speter 27348832Smsmith /* VLSI -- vendor 0x1004 */ 27448832Smsmith case 0x00051004: 27548832Smsmith s = "VLSI 82C592 Host to PCI bridge"; 27648832Smsmith break; 27748832Smsmith 27848832Smsmith /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ 27948832Smsmith /* totally. Please let me know if anything wrong. -F */ 28048832Smsmith /* XXX need info on the MVP3 -- any takers? */ 28148832Smsmith case 0x05981106: 28248832Smsmith s = "VIA 82C598MVP (Apollo MVP3) host bridge"; 28348832Smsmith break; 28448832Smsmith 28548832Smsmith /* AcerLabs -- vendor 0x10b9 */ 28648832Smsmith /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ 28748832Smsmith /* id is '10b9" but the register always shows "10b9". -Foxfair */ 28848832Smsmith case 0x154110b9: 28948832Smsmith s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; 29048832Smsmith break; 29148832Smsmith 29248832Smsmith /* OPTi -- vendor 0x1045 */ 29360862Skuriyama case 0xc7011045: 29460862Skuriyama s = "OPTi 82C700 host to PCI bridge"; 29560862Skuriyama break; 29648832Smsmith case 0xc8221045: 29748832Smsmith s = "OPTi 82C822 host to PCI Bridge"; 29848832Smsmith break; 29948832Smsmith 30067126Salc /* ServerWorks -- vendor 0x1166 */ 30148832Smsmith case 0x00051166: 30267126Salc s = "ServerWorks NB6536 2.0HE host to PCI bridge"; 303115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 30448832Smsmith break; 305137098Sdes 30657092Sgallatin case 0x00061166: 30757092Sgallatin /* FALLTHROUGH */ 30857092Sgallatin case 0x00081166: 309100374Sgallatin /* FALLTHROUGH */ 310100374Sgallatin case 0x02011166: 311100374Sgallatin /* FALLTHROUGH */ 312100374Sgallatin case 0x010f1014: /* IBM re-badged ServerWorks chipset */ 31367126Salc s = "ServerWorks host to PCI bridge"; 314115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 31557092Sgallatin break; 31649601Speter 31757092Sgallatin case 0x00091166: 31867126Salc s = "ServerWorks NB6635 3.0LE host to PCI bridge"; 319115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 32057092Sgallatin break; 32157092Sgallatin 322106878Speter case 0x00101166: 323106878Speter s = "ServerWorks CIOB30 host to PCI bridge"; 324115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 325106878Speter break; 326106878Speter 327100374Sgallatin case 0x00111166: 328100374Sgallatin /* FALLTHROUGH */ 329100374Sgallatin case 0x03021014: /* IBM re-badged ServerWorks chipset */ 330100374Sgallatin s = "ServerWorks CMIC-HE host to PCI-X bridge"; 331115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 332100374Sgallatin break; 333100374Sgallatin 334104381Siwasaki /* XXX unknown chipset, but working */ 335104381Siwasaki case 0x00171166: 336104381Siwasaki /* FALLTHROUGH */ 337104381Siwasaki case 0x01011166: 338215820Sjhb case 0x01101166: 339215820Sjhb case 0x02251166: 340104381Siwasaki s = "ServerWorks host to PCI bridge(unknown chipset)"; 341115908Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1); 342104381Siwasaki break; 343104381Siwasaki 344144110Sjhb /* Compaq/HP -- vendor 0x0e11 */ 345144110Sjhb case 0x60100e11: 346144110Sjhb s = "Compaq/HP Model 6010 HotPlug PCI Bridge"; 347144110Sjhb *busnum = legacy_pcib_read_config(0, bus, slot, func, 0xc8, 1); 348144110Sjhb break; 349144110Sjhb 35049601Speter /* Integrated Micro Solutions -- vendor 0x10e0 */ 35149580Swpaul case 0x884910e0: 35249580Swpaul s = "Integrated Micro Solutions VL Bridge"; 35349580Swpaul break; 35449601Speter 35549580Swpaul default: 35649601Speter if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 35749601Speter s = "Host to PCI bridge"; 35849580Swpaul break; 35948832Smsmith } 36048832Smsmith 36148832Smsmith return s; 362223440Sjhb#else 363223440Sjhb const char *s = NULL; 364223440Sjhb 365223440Sjhb *busnum = 0; 366223440Sjhb if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 367223440Sjhb s = "Host to PCI bridge"; 368223440Sjhb return s; 369223440Sjhb#endif 37048832Smsmith} 37148832Smsmith 37248832Smsmith/* 37348832Smsmith * Scan the first pci bus for host-pci bridges and add pcib instances 37448832Smsmith * to the nexus for each bridge. 37548832Smsmith */ 37648832Smsmithstatic void 377115908Sjhblegacy_pcib_identify(driver_t *driver, device_t parent) 37848832Smsmith{ 37965176Sdfr int bus, slot, func; 380223428Sjhb uint8_t hdrtype; 38153363Speter int found = 0; 38257092Sgallatin int pcifunchigh; 38357402Sdfr int found824xx = 0; 38468485Smsmith int found_orion = 0; 38565304Speter device_t child; 38666843Smsmith devclass_t pci_devclass; 38748832Smsmith 38866529Smsmith if (pci_cfgregopen() == 0) 38949404Speter return; 39066843Smsmith /* 39166843Smsmith * Check to see if we haven't already had a PCI bus added 39266843Smsmith * via some other means. If we have, bail since otherwise 39366843Smsmith * we're going to end up duplicating it. 39466843Smsmith */ 395137098Sdes if ((pci_devclass = devclass_find("pci")) && 39666843Smsmith devclass_get_device(pci_devclass, 0)) 39766843Smsmith return; 39866843Smsmith 39966843Smsmith 40065176Sdfr bus = 0; 40157402Sdfr retry: 40265176Sdfr for (slot = 0; slot <= PCI_SLOTMAX; slot++) { 40365176Sdfr func = 0; 404115908Sjhb hdrtype = legacy_pcib_read_config(0, bus, slot, func, 405119539Sjhb PCIR_HDRTYPE, 1); 406118328Simp /* 407118328Simp * When enumerating bus devices, the standard says that 408118328Simp * one should check the header type and ignore the slots whose 409118328Simp * header types that the software doesn't know about. We use 410118328Simp * this to filter out devices. 411118328Simp */ 412119539Sjhb if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 413118328Simp continue; 414137098Sdes if ((hdrtype & PCIM_MFDEV) && 41568485Smsmith (!found_orion || hdrtype != 0xff)) 416119539Sjhb pcifunchigh = PCI_FUNCMAX; 41757092Sgallatin else 41857092Sgallatin pcifunchigh = 0; 41965176Sdfr for (func = 0; func <= pcifunchigh; func++) { 42048832Smsmith /* 42148832Smsmith * Read the IDs and class from the device. 42248832Smsmith */ 423223428Sjhb uint32_t id; 424223428Sjhb uint8_t class, subclass, busnum; 42548832Smsmith const char *s; 42665459Speter device_t *devs; 42765459Speter int ndevs, i; 42848832Smsmith 429115908Sjhb id = legacy_pcib_read_config(0, bus, slot, func, 43065176Sdfr PCIR_DEVVENDOR, 4); 431105535Sphk if (id == -1) 432105535Sphk continue; 433115908Sjhb class = legacy_pcib_read_config(0, bus, slot, func, 43465176Sdfr PCIR_CLASS, 1); 435115908Sjhb subclass = legacy_pcib_read_config(0, bus, slot, func, 43665176Sdfr PCIR_SUBCLASS, 1); 43748832Smsmith 438115908Sjhb s = legacy_pcib_is_host_bridge(bus, slot, func, 43965176Sdfr id, class, subclass, 44048832Smsmith &busnum); 44165459Speter if (s == NULL) 44265459Speter continue; 44365304Speter 44465459Speter /* 44565459Speter * Check to see if the physical bus has already 44665459Speter * been seen. Eg: hybrid 32 and 64 bit host 44765459Speter * bridges to the same logical bus. 44865459Speter */ 44965459Speter if (device_get_children(parent, &devs, &ndevs) == 0) { 45065459Speter for (i = 0; s != NULL && i < ndevs; i++) { 45165459Speter if (strcmp(device_get_name(devs[i]), 45265459Speter "pcib") != 0) 45365459Speter continue; 454103863Sjhb if (legacy_get_pcibus(devs[i]) == busnum) 45565459Speter s = NULL; 45665459Speter } 45765459Speter free(devs, M_TEMP); 45865459Speter } 45965304Speter 46065459Speter if (s == NULL) 46165459Speter continue; 46265459Speter /* 46365459Speter * Add at priority 100 to make sure we 46465459Speter * go after any motherboard resources 46565459Speter */ 46665459Speter child = BUS_ADD_CHILD(parent, 100, 46765459Speter "pcib", busnum); 46865459Speter device_set_desc(child, s); 469103863Sjhb legacy_set_pcibus(child, busnum); 470234150Sjhb legacy_set_pcislot(child, slot); 471234150Sjhb legacy_set_pcifunc(child, func); 47265459Speter 47365459Speter found = 1; 47465459Speter if (id == 0x12258086) 47565459Speter found824xx = 1; 47668485Smsmith if (id == 0x84c48086) 47768485Smsmith found_orion = 1; 47848832Smsmith } 47948832Smsmith } 48065176Sdfr if (found824xx && bus == 0) { 48165176Sdfr bus++; 48257402Sdfr goto retry; 48357402Sdfr } 48453363Speter 48553363Speter /* 48653363Speter * Make sure we add at least one bridge since some old 48753363Speter * hardware doesn't actually have a host-pci bridge device. 48866529Smsmith * Note that pci_cfgregopen() thinks we have PCI devices.. 48953363Speter */ 49053363Speter if (!found) { 49153363Speter if (bootverbose) 49253363Speter printf( 493115908Sjhb "legacy_pcib_identify: no bridge found, adding pcib0 anyway\n"); 49465304Speter child = BUS_ADD_CHILD(parent, 100, "pcib", 0); 495103863Sjhb legacy_set_pcibus(child, 0); 49653363Speter } 49748832Smsmith} 49848832Smsmith 49947307Speterstatic int 500115908Sjhblegacy_pcib_probe(device_t dev) 50147307Speter{ 50265304Speter 50366843Smsmith if (pci_cfgregopen() == 0) 50466843Smsmith return ENXIO; 505121822Sjhb return -100; 50647307Speter} 50747307Speter 508128874Sjhbstatic int 509115908Sjhblegacy_pcib_attach(device_t dev) 51065176Sdfr{ 511223440Sjhb#ifdef __HAVE_PIR 512128933Sjhb device_t pir; 513223440Sjhb#endif 514125981Sjhb int bus; 51565304Speter 516223440Sjhb bus = pcib_get_bus(dev); 517223440Sjhb#ifdef __HAVE_PIR 518125981Sjhb /* 519125981Sjhb * Look for a PCI BIOS interrupt routing table as that will be 520125981Sjhb * our method of routing interrupts if we have one. 521125981Sjhb */ 522128933Sjhb if (pci_pir_probe(bus, 0)) { 523128933Sjhb pir = BUS_ADD_CHILD(device_get_parent(dev), 0, "pir", 0); 524129962Sjhb if (pir != NULL) 525129962Sjhb device_probe_and_attach(pir); 526128933Sjhb } 527223440Sjhb#endif 528125981Sjhb device_add_child(dev, "pci", bus); 52965304Speter return bus_generic_attach(dev); 53065304Speter} 53165304Speter 532115908Sjhbint 533115908Sjhblegacy_pcib_read_ivar(device_t dev, device_t child, int which, 534115908Sjhb uintptr_t *result) 53565304Speter{ 53665304Speter 53765176Sdfr switch (which) { 538172394Smarius case PCIB_IVAR_DOMAIN: 539172394Smarius *result = 0; 540172394Smarius return 0; 54165176Sdfr case PCIB_IVAR_BUS: 542103863Sjhb *result = legacy_get_pcibus(dev); 54365176Sdfr return 0; 54465176Sdfr } 54565176Sdfr return ENOENT; 54665176Sdfr} 54765176Sdfr 548115908Sjhbint 549115908Sjhblegacy_pcib_write_ivar(device_t dev, device_t child, int which, 550115908Sjhb uintptr_t value) 55165304Speter{ 55265304Speter 55365304Speter switch (which) { 554172394Smarius case PCIB_IVAR_DOMAIN: 555172394Smarius return EINVAL; 55665304Speter case PCIB_IVAR_BUS: 557103863Sjhb legacy_set_pcibus(dev, value); 55865304Speter return 0; 55965304Speter } 56065304Speter return ENOENT; 56165304Speter} 56265304Speter 563223424Sjhb/* 564223424Sjhb * Helper routine for x86 Host-PCI bridge driver resource allocation. 565223424Sjhb * This is used to adjust the start address of wildcard allocation 566223424Sjhb * requests to avoid low addresses that are known to be problematic. 567223424Sjhb * 568223424Sjhb * If no memory preference is given, use upper 32MB slot most BIOSes 569223424Sjhb * use for their memory window. This is typically only used on older 570223424Sjhb * laptops that don't have PCI busses behind a PCI bridge, so assuming 571223424Sjhb * > 32MB is likely OK. 572223424Sjhb * 573223424Sjhb * However, this can cause problems for other chipsets, so we make 574223424Sjhb * this tunable by hw.pci.host_mem_start. 575223424Sjhb */ 576136397SimpSYSCTL_DECL(_hw_pci); 577136397Simp 578223424Sjhbstatic unsigned long host_mem_start = 0x80000000; 579223424SjhbTUNABLE_ULONG("hw.pci.host_mem_start", &host_mem_start); 580223424SjhbSYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RDTUN, &host_mem_start, 581223424Sjhb 0, "Limit the host bridge memory to being above this address."); 582136397Simp 583223424Sjhbu_long 584223424Sjhbhostb_alloc_start(int type, u_long start, u_long end, u_long count) 585223424Sjhb{ 586223424Sjhb 587223424Sjhb if (start + count - 1 != end) { 588223424Sjhb if (type == SYS_RES_MEMORY && start < host_mem_start) 589223424Sjhb start = host_mem_start; 590223424Sjhb if (type == SYS_RES_IOPORT && start < 0x1000) 591223424Sjhb start = 0x1000; 592223424Sjhb } 593223424Sjhb return (start); 594223424Sjhb} 595223424Sjhb 596150264Simpstruct resource * 597136188Simplegacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 598136188Simp u_long start, u_long end, u_long count, u_int flags) 599136188Simp{ 600223424Sjhb 601223424Sjhb start = hostb_alloc_start(type, start, end, count); 602136188Simp return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 603136188Simp count, flags)); 604136188Simp} 605136188Simp 606115908Sjhbstatic device_method_t legacy_pcib_methods[] = { 60747307Speter /* Device interface */ 608115908Sjhb DEVMETHOD(device_identify, legacy_pcib_identify), 609115908Sjhb DEVMETHOD(device_probe, legacy_pcib_probe), 610115908Sjhb DEVMETHOD(device_attach, legacy_pcib_attach), 61147307Speter DEVMETHOD(device_shutdown, bus_generic_shutdown), 61247307Speter DEVMETHOD(device_suspend, bus_generic_suspend), 61347307Speter DEVMETHOD(device_resume, bus_generic_resume), 61447307Speter 61547307Speter /* Bus interface */ 616115908Sjhb DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar), 617115908Sjhb DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar), 618136188Simp DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), 619221324Sjhb DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 62047307Speter DEVMETHOD(bus_release_resource, bus_generic_release_resource), 62147307Speter DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 62247307Speter DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 62347307Speter DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 62447307Speter DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 62547307Speter 62665176Sdfr /* pcib interface */ 627115908Sjhb DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots), 628115908Sjhb DEVMETHOD(pcib_read_config, legacy_pcib_read_config), 629115908Sjhb DEVMETHOD(pcib_write_config, legacy_pcib_write_config), 630223440Sjhb DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), 631165128Sjhb DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), 632164265Sjhb DEVMETHOD(pcib_release_msi, pcib_release_msi), 633165128Sjhb DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), 634164265Sjhb DEVMETHOD(pcib_release_msix, pcib_release_msix), 635169221Sjhb DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi), 63665176Sdfr 637229093Shselasky DEVMETHOD_END 63847307Speter}; 63947307Speter 640154079Sjhbstatic devclass_t hostb_devclass; 64147307Speter 642154079SjhbDEFINE_CLASS_0(pcib, legacy_pcib_driver, legacy_pcib_methods, 1); 643154079SjhbDRIVER_MODULE(pcib, legacy, legacy_pcib_driver, hostb_devclass, 0, 0); 64461994Smsmith 64565459Speter 64661994Smsmith/* 64761994Smsmith * Install placeholder to claim the resources owned by the 648137098Sdes * PCI bus interface. This could be used to extract the 64961994Smsmith * config space registers in the extreme case where the PnP 65061994Smsmith * ID is available and the PCI BIOS isn't, but for now we just 65161994Smsmith * eat the PnP ID and do nothing else. 65261994Smsmith * 653137098Sdes * XXX we should silence this probe, as it will generally confuse 65461994Smsmith * people. 65561994Smsmith */ 65661994Smsmithstatic struct isa_pnp_id pcibus_pnp_ids[] = { 65795374Simp { 0x030ad041 /* PNP0A03 */, "PCI Bus" }, 658195666Sjkim { 0x080ad041 /* PNP0A08 */, "PCIe Bus" }, 65961994Smsmith { 0 } 66061994Smsmith}; 66161994Smsmith 66261994Smsmithstatic int 66361994Smsmithpcibus_pnp_probe(device_t dev) 66461994Smsmith{ 66561994Smsmith int result; 666137098Sdes 66761994Smsmith if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0) 66861994Smsmith device_quiet(dev); 66961994Smsmith return(result); 67061994Smsmith} 67161994Smsmith 67261994Smsmithstatic int 67361994Smsmithpcibus_pnp_attach(device_t dev) 67461994Smsmith{ 67561994Smsmith return(0); 67661994Smsmith} 67761994Smsmith 67861994Smsmithstatic device_method_t pcibus_pnp_methods[] = { 67961994Smsmith /* Device interface */ 68061994Smsmith DEVMETHOD(device_probe, pcibus_pnp_probe), 68161994Smsmith DEVMETHOD(device_attach, pcibus_pnp_attach), 68261994Smsmith DEVMETHOD(device_detach, bus_generic_detach), 68361994Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 68461994Smsmith DEVMETHOD(device_suspend, bus_generic_suspend), 68561994Smsmith DEVMETHOD(device_resume, bus_generic_resume), 68661994Smsmith { 0, 0 } 68761994Smsmith}; 68861994Smsmith 68961994Smsmithstatic devclass_t pcibus_pnp_devclass; 69061994Smsmith 691154079SjhbDEFINE_CLASS_0(pcibus_pnp, pcibus_pnp_driver, pcibus_pnp_methods, 1); 69261994SmsmithDRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0); 693103044Sjhb 694223440Sjhb#ifdef __HAVE_PIR 695103044Sjhb/* 696103044Sjhb * Provide a PCI-PCI bridge driver for PCI busses behind PCI-PCI bridges 697103044Sjhb * that appear in the PCIBIOS Interrupt Routing Table to use the routing 698103044Sjhb * table for interrupt routing when possible. 699103044Sjhb */ 700103044Sjhbstatic int pcibios_pcib_probe(device_t bus); 701103044Sjhb 702103044Sjhbstatic device_method_t pcibios_pcib_pci_methods[] = { 703103044Sjhb /* Device interface */ 704103044Sjhb DEVMETHOD(device_probe, pcibios_pcib_probe), 705103044Sjhb 706103044Sjhb /* pcib interface */ 707223440Sjhb DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), 708103044Sjhb 709103044Sjhb {0, 0} 710103044Sjhb}; 711103044Sjhb 712154079Sjhbstatic devclass_t pcib_devclass; 713103044Sjhb 714210868SjhbDEFINE_CLASS_1(pcib, pcibios_pcib_driver, pcibios_pcib_pci_methods, 715210868Sjhb sizeof(struct pcib_softc), pcib_driver); 716103044SjhbDRIVER_MODULE(pcibios_pcib, pci, pcibios_pcib_driver, pcib_devclass, 0, 0); 717103044Sjhb 718103044Sjhbstatic int 719103044Sjhbpcibios_pcib_probe(device_t dev) 720103044Sjhb{ 721115906Sjhb int bus; 722103044Sjhb 723103044Sjhb if ((pci_get_class(dev) != PCIC_BRIDGE) || 724103044Sjhb (pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) 725103044Sjhb return (ENXIO); 726115906Sjhb bus = pci_read_config(dev, PCIR_SECBUS_1, 1); 727115906Sjhb if (bus == 0) 728103044Sjhb return (ENXIO); 729125981Sjhb if (!pci_pir_probe(bus, 1)) 730115906Sjhb return (ENXIO); 731103044Sjhb device_set_desc(dev, "PCIBIOS PCI-PCI bridge"); 732103044Sjhb return (-2000); 733103044Sjhb} 734223440Sjhb#endif 735