1ac19f918SStefan Eßer /* 25bec6157SStefan Eßer * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 35bec6157SStefan Eßer * All rights reserved. 45bec6157SStefan Eßer * 55bec6157SStefan Eßer * Redistribution and use in source and binary forms, with or without 65bec6157SStefan Eßer * modification, are permitted provided that the following conditions 75bec6157SStefan Eßer * are met: 85bec6157SStefan Eßer * 1. Redistributions of source code must retain the above copyright 95bec6157SStefan Eßer * notice unmodified, this list of conditions, and the following 105bec6157SStefan Eßer * disclaimer. 115bec6157SStefan Eßer * 2. Redistributions in binary form must reproduce the above copyright 125bec6157SStefan Eßer * notice, this list of conditions and the following disclaimer in the 135bec6157SStefan Eßer * documentation and/or other materials provided with the distribution. 145bec6157SStefan Eßer * 155bec6157SStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 165bec6157SStefan Eßer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 175bec6157SStefan Eßer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 185bec6157SStefan Eßer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 195bec6157SStefan Eßer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 205bec6157SStefan Eßer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 215bec6157SStefan Eßer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 225bec6157SStefan Eßer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 235bec6157SStefan Eßer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 245bec6157SStefan Eßer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 255bec6157SStefan Eßer * 26c3aac50fSPeter Wemm * $FreeBSD$ 275bec6157SStefan Eßer * 28ac19f918SStefan Eßer */ 29ac19f918SStefan Eßer 308dc26439SPeter Wemm #include <sys/param.h> 315bec6157SStefan Eßer #include <sys/systm.h> 328dc26439SPeter Wemm #include <sys/bus.h> 338dc26439SPeter Wemm #include <sys/kernel.h> 34ac19f918SStefan Eßer 355bec6157SStefan Eßer #include <pci/pcivar.h> 3685001303SMike Smith #include <pci/pcireg.h> 375bec6157SStefan Eßer #include <i386/isa/pcibus.h> 38ac19f918SStefan Eßer 39300451c4SMike Smith #include <machine/segments.h> 40300451c4SMike Smith #include <machine/pc/bios.h> 41300451c4SMike Smith 425bec6157SStefan Eßer static int cfgmech; 435bec6157SStefan Eßer static int devmax; 44300451c4SMike Smith static int usebios; 45300451c4SMike Smith 46300451c4SMike Smith static int pcibios_cfgread(pcicfgregs *cfg, int reg, int bytes); 47300451c4SMike Smith static void pcibios_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes); 48300451c4SMike Smith static int pcibios_cfgopen(void); 49300451c4SMike Smith static int pcireg_cfgread(pcicfgregs *cfg, int reg, int bytes); 50300451c4SMike Smith static void pcireg_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes); 51300451c4SMike Smith static int pcireg_cfgopen(void); 52300451c4SMike Smith 53300451c4SMike Smith /* read configuration space register */ 54300451c4SMike Smith 55300451c4SMike Smith int 56300451c4SMike Smith pci_cfgread(pcicfgregs *cfg, int reg, int bytes) 57300451c4SMike Smith { 58300451c4SMike Smith return(usebios ? 59300451c4SMike Smith pcibios_cfgread(cfg, reg, bytes) : 60300451c4SMike Smith pcireg_cfgread(cfg, reg, bytes)); 61300451c4SMike Smith } 62300451c4SMike Smith 63300451c4SMike Smith /* write configuration space register */ 64300451c4SMike Smith 65300451c4SMike Smith void 66300451c4SMike Smith pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 67300451c4SMike Smith { 68300451c4SMike Smith return(usebios ? 69300451c4SMike Smith pcibios_cfgwrite(cfg, reg, data, bytes) : 70300451c4SMike Smith pcireg_cfgwrite(cfg, reg, data, bytes)); 71300451c4SMike Smith } 72300451c4SMike Smith 73300451c4SMike Smith /* initialise access to PCI configuration space */ 74300451c4SMike Smith static int 75300451c4SMike Smith pci_cfgopen(void) 76300451c4SMike Smith { 77300451c4SMike Smith if (pcibios_cfgopen() != 0) { 78300451c4SMike Smith usebios = 1; 79300451c4SMike Smith } else if (pcireg_cfgopen() != 0) { 80300451c4SMike Smith usebios = 0; 81300451c4SMike Smith } else { 82300451c4SMike Smith return(0); 83300451c4SMike Smith } 84300451c4SMike Smith return(1); 85300451c4SMike Smith } 86300451c4SMike Smith 87300451c4SMike Smith /* config space access using BIOS functions */ 88300451c4SMike Smith 89300451c4SMike Smith static int 90300451c4SMike Smith pcibios_cfgread(pcicfgregs *cfg, int reg, int bytes) 91300451c4SMike Smith { 92300451c4SMike Smith struct bios_regs args; 93300451c4SMike Smith 94300451c4SMike Smith switch(bytes) { 95300451c4SMike Smith case 1: 96300451c4SMike Smith args.eax = PCIBIOS_READ_CONFIG_BYTE; 97300451c4SMike Smith break; 98300451c4SMike Smith case 2: 99300451c4SMike Smith args.eax = PCIBIOS_READ_CONFIG_WORD; 100300451c4SMike Smith break; 101300451c4SMike Smith case 4: 102300451c4SMike Smith args.eax = PCIBIOS_READ_CONFIG_DWORD; 103300451c4SMike Smith break; 104300451c4SMike Smith default: 105300451c4SMike Smith return(-1); 106300451c4SMike Smith } 107300451c4SMike Smith args.ebx = (cfg->bus << 8) | (cfg->slot << 3) | (cfg->func); 108300451c4SMike Smith args.edi = reg; 109300451c4SMike Smith bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 110300451c4SMike Smith /* check call results? */ 111300451c4SMike Smith return(args.ecx); 112300451c4SMike Smith } 113300451c4SMike Smith 114300451c4SMike Smith static void 115300451c4SMike Smith pcibios_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 116300451c4SMike Smith { 117300451c4SMike Smith struct bios_regs args; 118300451c4SMike Smith 119300451c4SMike Smith switch(bytes) { 120300451c4SMike Smith case 1: 121300451c4SMike Smith args.eax = PCIBIOS_WRITE_CONFIG_BYTE; 122300451c4SMike Smith break; 123300451c4SMike Smith case 2: 124300451c4SMike Smith args.eax = PCIBIOS_WRITE_CONFIG_WORD; 125300451c4SMike Smith break; 126300451c4SMike Smith case 4: 127300451c4SMike Smith args.eax = PCIBIOS_WRITE_CONFIG_DWORD; 128300451c4SMike Smith break; 129300451c4SMike Smith default: 130300451c4SMike Smith return; 131300451c4SMike Smith } 132300451c4SMike Smith args.ebx = (cfg->bus << 8) | (cfg->slot << 3) | (cfg->func); 133300451c4SMike Smith args.ecx = data; 134300451c4SMike Smith args.edi = reg; 135300451c4SMike Smith bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 136300451c4SMike Smith } 137300451c4SMike Smith 138300451c4SMike Smith /* determine whether there is a PCI BIOS present */ 139300451c4SMike Smith 140300451c4SMike Smith static int 141300451c4SMike Smith pcibios_cfgopen(void) 142300451c4SMike Smith { 143300451c4SMike Smith /* check for a found entrypoint */ 144300451c4SMike Smith return(PCIbios.entry != 0); 145300451c4SMike Smith } 146300451c4SMike Smith 147300451c4SMike Smith /* configuration space access using direct register operations */ 148ac19f918SStefan Eßer 1495bec6157SStefan Eßer /* enable configuration space accesses and return data port address */ 150ac19f918SStefan Eßer 151a3adc4f8SStefan Eßer static int 1525bec6157SStefan Eßer pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 1535bec6157SStefan Eßer { 1545bec6157SStefan Eßer int dataport = 0; 1555bec6157SStefan Eßer 1565bec6157SStefan Eßer if (bus <= PCI_BUSMAX 1575bec6157SStefan Eßer && slot < devmax 1585bec6157SStefan Eßer && func <= PCI_FUNCMAX 1595bec6157SStefan Eßer && reg <= PCI_REGMAX 1605bec6157SStefan Eßer && bytes != 3 1615bec6157SStefan Eßer && (unsigned) bytes <= 4 1625bec6157SStefan Eßer && (reg & (bytes -1)) == 0) { 1635bec6157SStefan Eßer switch (cfgmech) { 1645bec6157SStefan Eßer case 1: 165b3daa02eSStefan Eßer outl(CONF1_ADDR_PORT, (1 << 31) 166b3daa02eSStefan Eßer | (bus << 16) | (slot << 11) 167b3daa02eSStefan Eßer | (func << 8) | (reg & ~0x03)); 168b3daa02eSStefan Eßer dataport = CONF1_DATA_PORT + (reg & 0x03); 1695bec6157SStefan Eßer break; 1705bec6157SStefan Eßer case 2: 1715bec6157SStefan Eßer outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 1725bec6157SStefan Eßer outb(CONF2_FORWARD_PORT, bus); 1735bec6157SStefan Eßer dataport = 0xc000 | (slot << 8) | reg; 1745bec6157SStefan Eßer break; 1755bec6157SStefan Eßer } 1765bec6157SStefan Eßer } 1775bec6157SStefan Eßer return (dataport); 1785bec6157SStefan Eßer } 1795bec6157SStefan Eßer 1805bec6157SStefan Eßer /* disable configuration space accesses */ 1815bec6157SStefan Eßer 1825bec6157SStefan Eßer static void 1835bec6157SStefan Eßer pci_cfgdisable(void) 1845bec6157SStefan Eßer { 1855bec6157SStefan Eßer switch (cfgmech) { 1865bec6157SStefan Eßer case 1: 1875bec6157SStefan Eßer outl(CONF1_ADDR_PORT, 0); 1885bec6157SStefan Eßer break; 1895bec6157SStefan Eßer case 2: 1905bec6157SStefan Eßer outb(CONF2_ENABLE_PORT, 0); 1915bec6157SStefan Eßer outb(CONF2_FORWARD_PORT, 0); 1925bec6157SStefan Eßer break; 1935bec6157SStefan Eßer } 1945bec6157SStefan Eßer } 1955bec6157SStefan Eßer 196300451c4SMike Smith static int 197300451c4SMike Smith pcireg_cfgread(pcicfgregs *cfg, int reg, int bytes) 1985bec6157SStefan Eßer { 1995bec6157SStefan Eßer int data = -1; 2005bec6157SStefan Eßer int port; 2015bec6157SStefan Eßer 2025bec6157SStefan Eßer port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 2035bec6157SStefan Eßer 2045bec6157SStefan Eßer if (port != 0) { 2055bec6157SStefan Eßer switch (bytes) { 2065bec6157SStefan Eßer case 1: 2075bec6157SStefan Eßer data = inb(port); 2085bec6157SStefan Eßer break; 2095bec6157SStefan Eßer case 2: 2105bec6157SStefan Eßer data = inw(port); 2115bec6157SStefan Eßer break; 2125bec6157SStefan Eßer case 4: 2135bec6157SStefan Eßer data = inl(port); 2145bec6157SStefan Eßer break; 2155bec6157SStefan Eßer } 2165bec6157SStefan Eßer pci_cfgdisable(); 2175bec6157SStefan Eßer } 2185bec6157SStefan Eßer return (data); 2195bec6157SStefan Eßer } 2205bec6157SStefan Eßer 221300451c4SMike Smith static void 222300451c4SMike Smith pcireg_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 2235bec6157SStefan Eßer { 2245bec6157SStefan Eßer int port; 2255bec6157SStefan Eßer 2265bec6157SStefan Eßer port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 2275bec6157SStefan Eßer if (port != 0) { 2285bec6157SStefan Eßer switch (bytes) { 2295bec6157SStefan Eßer case 1: 2305bec6157SStefan Eßer outb(port, data); 2315bec6157SStefan Eßer break; 2325bec6157SStefan Eßer case 2: 2335bec6157SStefan Eßer outw(port, data); 2345bec6157SStefan Eßer break; 2355bec6157SStefan Eßer case 4: 2365bec6157SStefan Eßer outl(port, data); 2375bec6157SStefan Eßer break; 2385bec6157SStefan Eßer } 2395bec6157SStefan Eßer pci_cfgdisable(); 2405bec6157SStefan Eßer } 2415bec6157SStefan Eßer } 2425bec6157SStefan Eßer 2435bec6157SStefan Eßer /* check whether the configuration mechanism has been correct identified */ 2445bec6157SStefan Eßer 2455bec6157SStefan Eßer static int 2465bec6157SStefan Eßer pci_cfgcheck(int maxdev) 247a3adc4f8SStefan Eßer { 248a3adc4f8SStefan Eßer u_char device; 249a3adc4f8SStefan Eßer 2505bec6157SStefan Eßer if (bootverbose) 2515bec6157SStefan Eßer printf("pci_cfgcheck:\tdevice "); 25277b57314SStefan Eßer 2535bec6157SStefan Eßer for (device = 0; device < maxdev; device++) { 2545bec6157SStefan Eßer unsigned id, class, header; 255c7483249SStefan Eßer if (bootverbose) 256c7483249SStefan Eßer printf("%d ", device); 2575bec6157SStefan Eßer 2585bec6157SStefan Eßer id = inl(pci_cfgenable(0, device, 0, 0, 4)); 2595bec6157SStefan Eßer if (id == 0 || id == -1) 26081cf5d7aSStefan Eßer continue; 26181cf5d7aSStefan Eßer 2625bec6157SStefan Eßer class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 26381cf5d7aSStefan Eßer if (bootverbose) 2645bec6157SStefan Eßer printf("[class=%06x] ", class); 2658277ac25SStefan Eßer if (class == 0 || (class & 0xf870ff) != 0) 26681cf5d7aSStefan Eßer continue; 26781cf5d7aSStefan Eßer 2685bec6157SStefan Eßer header = inb(pci_cfgenable(0, device, 0, 14, 1)); 26981cf5d7aSStefan Eßer if (bootverbose) 2705bec6157SStefan Eßer printf("[hdr=%02x] ", header); 2715bec6157SStefan Eßer if ((header & 0x7e) != 0) 27281cf5d7aSStefan Eßer continue; 27381cf5d7aSStefan Eßer 2745bec6157SStefan Eßer if (bootverbose) 2755bec6157SStefan Eßer printf("is there (id=%08x)\n", id); 2765bec6157SStefan Eßer 2775bec6157SStefan Eßer pci_cfgdisable(); 2785bec6157SStefan Eßer return (1); 279a3adc4f8SStefan Eßer } 280c7483249SStefan Eßer if (bootverbose) 281c7483249SStefan Eßer printf("-- nothing found\n"); 2825bec6157SStefan Eßer 2835bec6157SStefan Eßer pci_cfgdisable(); 2845bec6157SStefan Eßer return (0); 285a3adc4f8SStefan Eßer } 286d7ea35fcSStefan Eßer 2878dc26439SPeter Wemm static int 288300451c4SMike Smith pcireg_cfgopen(void) 289ac19f918SStefan Eßer { 290287911bdSStefan Eßer unsigned long mode1res,oldval1; 291287911bdSStefan Eßer unsigned char mode2res,oldval2; 2920847c06dSStefan Eßer 293287911bdSStefan Eßer oldval1 = inl(CONF1_ADDR_PORT); 294a3adc4f8SStefan Eßer 29577b57314SStefan Eßer if (bootverbose) { 2965bec6157SStefan Eßer printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 2975bec6157SStefan Eßer oldval1); 298a3adc4f8SStefan Eßer } 299a3adc4f8SStefan Eßer 3000e2f699bSStefan Eßer if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 301287911bdSStefan Eßer 3025bec6157SStefan Eßer cfgmech = 1; 3035bec6157SStefan Eßer devmax = 32; 30477b57314SStefan Eßer 30577b57314SStefan Eßer outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 30677b57314SStefan Eßer outb(CONF1_ADDR_PORT +3, 0); 30777b57314SStefan Eßer mode1res = inl(CONF1_ADDR_PORT); 308287911bdSStefan Eßer outl(CONF1_ADDR_PORT, oldval1); 30977b57314SStefan Eßer 31077b57314SStefan Eßer if (bootverbose) 3115bec6157SStefan Eßer printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 31277b57314SStefan Eßer mode1res, CONF1_ENABLE_CHK); 31377b57314SStefan Eßer 31477b57314SStefan Eßer if (mode1res) { 3155bec6157SStefan Eßer if (pci_cfgcheck(32)) 3165bec6157SStefan Eßer return (cfgmech); 3175bec6157SStefan Eßer } 31877b57314SStefan Eßer 31977b57314SStefan Eßer outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 32077b57314SStefan Eßer mode1res = inl(CONF1_ADDR_PORT); 321287911bdSStefan Eßer outl(CONF1_ADDR_PORT, oldval1); 32277b57314SStefan Eßer 32377b57314SStefan Eßer if (bootverbose) 3245bec6157SStefan Eßer printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 32577b57314SStefan Eßer mode1res, CONF1_ENABLE_CHK1); 32677b57314SStefan Eßer 327c7483249SStefan Eßer if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 3285bec6157SStefan Eßer if (pci_cfgcheck(32)) 3295bec6157SStefan Eßer return (cfgmech); 330287911bdSStefan Eßer } 3315bec6157SStefan Eßer } 33277b57314SStefan Eßer 333287911bdSStefan Eßer oldval2 = inb(CONF2_ENABLE_PORT); 334287911bdSStefan Eßer 335287911bdSStefan Eßer if (bootverbose) { 3365bec6157SStefan Eßer printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 3375bec6157SStefan Eßer oldval2); 338287911bdSStefan Eßer } 339287911bdSStefan Eßer 340287911bdSStefan Eßer if ((oldval2 & 0xf0) == 0) { 341c7483249SStefan Eßer 3425bec6157SStefan Eßer cfgmech = 2; 3435bec6157SStefan Eßer devmax = 16; 34477b57314SStefan Eßer 345287911bdSStefan Eßer outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 346287911bdSStefan Eßer mode2res = inb(CONF2_ENABLE_PORT); 347287911bdSStefan Eßer outb(CONF2_ENABLE_PORT, oldval2); 348287911bdSStefan Eßer 349287911bdSStefan Eßer if (bootverbose) 3505bec6157SStefan Eßer printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 351287911bdSStefan Eßer mode2res, CONF2_ENABLE_CHK); 352287911bdSStefan Eßer 353287911bdSStefan Eßer if (mode2res == CONF2_ENABLE_RES) { 354287911bdSStefan Eßer if (bootverbose) 3555bec6157SStefan Eßer printf("pci_open(2a):\tnow trying mechanism 2\n"); 356287911bdSStefan Eßer 3575bec6157SStefan Eßer if (pci_cfgcheck(16)) 3585bec6157SStefan Eßer return (cfgmech); 359287911bdSStefan Eßer } 360287911bdSStefan Eßer } 36177b57314SStefan Eßer 3625bec6157SStefan Eßer cfgmech = 0; 3635bec6157SStefan Eßer devmax = 0; 3645bec6157SStefan Eßer return (cfgmech); 365ac19f918SStefan Eßer } 3668dc26439SPeter Wemm 3678dc26439SPeter Wemm static devclass_t pcib_devclass; 3688dc26439SPeter Wemm 36985001303SMike Smith static const char * 37085001303SMike Smith nexus_pcib_is_host_bridge(pcicfgregs *cfg, 37185001303SMike Smith u_int32_t id, u_int8_t class, u_int8_t subclass, 37285001303SMike Smith u_int8_t *busnum) 37385001303SMike Smith { 374d9d628b0SBill Paul const char *s = NULL; 37585001303SMike Smith static u_int8_t pxb[4]; /* hack for 450nx */ 37685001303SMike Smith 37785001303SMike Smith *busnum = 0; 37885001303SMike Smith 37985001303SMike Smith switch (id) { 38085001303SMike Smith case 0x12258086: 38185001303SMike Smith s = "Intel 824?? host to PCI bridge"; 38285001303SMike Smith /* XXX This is a guess */ 383ac19291fSDoug Rabson /* *busnum = pci_cfgread(cfg, 0x41, 1); */ 384ac19291fSDoug Rabson *busnum = cfg->bus; 38585001303SMike Smith break; 3864f2e8d63SNick Hibma case 0x71208086: 3874f2e8d63SNick Hibma s = "Intel 82810 (i810 GMCH) Host To Hub bridge"; 3884f2e8d63SNick Hibma break; 3894f2e8d63SNick Hibma case 0x71228086: 3904f2e8d63SNick Hibma s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"; 3914f2e8d63SNick Hibma break; 3924f2e8d63SNick Hibma case 0x71248086: 3934f2e8d63SNick Hibma s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; 3944f2e8d63SNick Hibma break; 39585001303SMike Smith case 0x71808086: 39685001303SMike Smith s = "Intel 82443LX (440 LX) host to PCI bridge"; 39785001303SMike Smith break; 39885001303SMike Smith case 0x71908086: 39985001303SMike Smith s = "Intel 82443BX (440 BX) host to PCI bridge"; 40085001303SMike Smith break; 40185001303SMike Smith case 0x71928086: 40285001303SMike Smith s = "Intel 82443BX host to PCI bridge (AGP disabled)"; 40385001303SMike Smith break; 40485001303SMike Smith case 0x71a08086: 40585001303SMike Smith s = "Intel 82443GX host to PCI bridge"; 40685001303SMike Smith break; 40785001303SMike Smith case 0x71a18086: 40885001303SMike Smith s = "Intel 82443GX host to AGP bridge"; 40985001303SMike Smith break; 41085001303SMike Smith case 0x71a28086: 41185001303SMike Smith s = "Intel 82443GX host to PCI bridge (AGP disabled)"; 41285001303SMike Smith break; 41385001303SMike Smith case 0x84c48086: 41485001303SMike Smith s = "Intel 82454KX/GX (Orion) host to PCI bridge"; 41585001303SMike Smith *busnum = pci_cfgread(cfg, 0x4a, 1); 41685001303SMike Smith break; 41785001303SMike Smith case 0x84ca8086: 41885001303SMike Smith /* 41985001303SMike Smith * For the 450nx chipset, there is a whole bundle of 42085001303SMike Smith * things pretending to be host bridges. The MIOC will 42185001303SMike Smith * be seen first and isn't really a pci bridge (the 42285001303SMike Smith * actual busses are attached to the PXB's). We need to 42385001303SMike Smith * read the registers of the MIOC to figure out the 42485001303SMike Smith * bus numbers for the PXB channels. 42585001303SMike Smith * 42685001303SMike Smith * Since the MIOC doesn't have a pci bus attached, we 42785001303SMike Smith * pretend it wasn't there. 42885001303SMike Smith */ 42985001303SMike Smith pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */ 43085001303SMike Smith pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */ 43185001303SMike Smith pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */ 43285001303SMike Smith pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */ 43385001303SMike Smith return NULL; 43485001303SMike Smith case 0x84cb8086: 43585001303SMike Smith switch (cfg->slot) { 43685001303SMike Smith case 0x12: 43785001303SMike Smith s = "Intel 82454NX PXB#0, Bus#A"; 43885001303SMike Smith *busnum = pxb[0]; 43985001303SMike Smith break; 44085001303SMike Smith case 0x13: 44185001303SMike Smith s = "Intel 82454NX PXB#0, Bus#B"; 44285001303SMike Smith *busnum = pxb[1]; 44385001303SMike Smith break; 44485001303SMike Smith case 0x14: 44585001303SMike Smith s = "Intel 82454NX PXB#1, Bus#A"; 44685001303SMike Smith *busnum = pxb[2]; 44785001303SMike Smith break; 44885001303SMike Smith case 0x15: 44985001303SMike Smith s = "Intel 82454NX PXB#1, Bus#B"; 45085001303SMike Smith *busnum = pxb[3]; 45185001303SMike Smith break; 45285001303SMike Smith } 45385001303SMike Smith break; 45485001303SMike Smith 455eab7cc95SAlan Cox /* AMD -- vendor 0x1022 */ 456eab7cc95SAlan Cox case 0x70061022: 457eab7cc95SAlan Cox s = "AMD-751 host to PCI bridge"; 458eab7cc95SAlan Cox break; 459eab7cc95SAlan Cox 46085001303SMike Smith /* SiS -- vendor 0x1039 */ 46185001303SMike Smith case 0x04961039: 46285001303SMike Smith s = "SiS 85c496"; 46385001303SMike Smith break; 46485001303SMike Smith case 0x04061039: 46585001303SMike Smith s = "SiS 85c501"; 46685001303SMike Smith break; 46785001303SMike Smith case 0x06011039: 46885001303SMike Smith s = "SiS 85c601"; 46985001303SMike Smith break; 47085001303SMike Smith case 0x55911039: 47185001303SMike Smith s = "SiS 5591 host to PCI bridge"; 47285001303SMike Smith break; 47385001303SMike Smith case 0x00011039: 47485001303SMike Smith s = "SiS 5591 host to AGP bridge"; 47585001303SMike Smith break; 47685001303SMike Smith 47785001303SMike Smith /* VLSI -- vendor 0x1004 */ 47885001303SMike Smith case 0x00051004: 47985001303SMike Smith s = "VLSI 82C592 Host to PCI bridge"; 48085001303SMike Smith break; 48185001303SMike Smith 48285001303SMike Smith /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ 48385001303SMike Smith /* totally. Please let me know if anything wrong. -F */ 48485001303SMike Smith /* XXX need info on the MVP3 -- any takers? */ 48585001303SMike Smith case 0x05981106: 48685001303SMike Smith s = "VIA 82C598MVP (Apollo MVP3) host bridge"; 48785001303SMike Smith break; 48885001303SMike Smith 48985001303SMike Smith /* AcerLabs -- vendor 0x10b9 */ 49085001303SMike Smith /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ 49185001303SMike Smith /* id is '10b9" but the register always shows "10b9". -Foxfair */ 49285001303SMike Smith case 0x154110b9: 49385001303SMike Smith s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; 49485001303SMike Smith break; 49585001303SMike Smith 49685001303SMike Smith /* OPTi -- vendor 0x1045 */ 49785001303SMike Smith case 0xc8221045: 49885001303SMike Smith s = "OPTi 82C822 host to PCI Bridge"; 49985001303SMike Smith break; 50085001303SMike Smith 501da400920SAndrew Gallatin /* RCC -- vendor 0x1166 */ 50285001303SMike Smith case 0x00051166: 503da400920SAndrew Gallatin s = "RCC HE host to PCI bridge"; 504da400920SAndrew Gallatin *busnum = pci_cfgread(cfg, 0x44, 1); 505da400920SAndrew Gallatin break; 506da400920SAndrew Gallatin 507da400920SAndrew Gallatin case 0x00061166: 508da400920SAndrew Gallatin /* FALLTHROUGH */ 509da400920SAndrew Gallatin case 0x00081166: 510da400920SAndrew Gallatin s = "RCC host to PCI bridge"; 511da400920SAndrew Gallatin *busnum = pci_cfgread(cfg, 0x44, 1); 512da400920SAndrew Gallatin break; 513da400920SAndrew Gallatin 514da400920SAndrew Gallatin case 0x00091166: 515da400920SAndrew Gallatin s = "RCC LE host to PCI bridge"; 516da400920SAndrew Gallatin *busnum = pci_cfgread(cfg, 0x44, 1); 51785001303SMike Smith break; 518accc665bSPeter Wemm 519accc665bSPeter Wemm /* Integrated Micro Solutions -- vendor 0x10e0 */ 520d9d628b0SBill Paul case 0x884910e0: 521d9d628b0SBill Paul s = "Integrated Micro Solutions VL Bridge"; 522d9d628b0SBill Paul break; 523accc665bSPeter Wemm 524d9d628b0SBill Paul default: 525accc665bSPeter Wemm if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 526d9d628b0SBill Paul s = "Host to PCI bridge"; 527d9d628b0SBill Paul break; 52885001303SMike Smith } 52985001303SMike Smith 53085001303SMike Smith return s; 53185001303SMike Smith } 53285001303SMike Smith 53385001303SMike Smith /* 53485001303SMike Smith * Scan the first pci bus for host-pci bridges and add pcib instances 53585001303SMike Smith * to the nexus for each bridge. 53685001303SMike Smith */ 53785001303SMike Smith static void 53885001303SMike Smith nexus_pcib_identify(driver_t *driver, device_t parent) 53985001303SMike Smith { 54085001303SMike Smith pcicfgregs probe; 541da400920SAndrew Gallatin u_int8_t hdrtype; 542cde35e1aSPeter Wemm int found = 0; 543da400920SAndrew Gallatin int pcifunchigh; 544ac19291fSDoug Rabson int found824xx = 0; 54585001303SMike Smith 546cac6a044SPeter Wemm if (pci_cfgopen() == 0) 547cac6a044SPeter Wemm return; 54885001303SMike Smith probe.hose = 0; 54985001303SMike Smith probe.bus = 0; 550ac19291fSDoug Rabson retry: 55185001303SMike Smith for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { 5529a1498a4SDoug Rabson probe.func = 0; 553da400920SAndrew Gallatin hdrtype = pci_cfgread(&probe, PCIR_HEADERTYPE, 1); 554da400920SAndrew Gallatin if (hdrtype & PCIM_MFDEV) 555da400920SAndrew Gallatin pcifunchigh = 7; 556da400920SAndrew Gallatin else 557da400920SAndrew Gallatin pcifunchigh = 0; 55885001303SMike Smith for (probe.func = 0; 55985001303SMike Smith probe.func <= pcifunchigh; 56085001303SMike Smith probe.func++) { 56185001303SMike Smith /* 56285001303SMike Smith * Read the IDs and class from the device. 56385001303SMike Smith */ 56485001303SMike Smith u_int32_t id; 56585001303SMike Smith u_int8_t class, subclass, busnum; 56685001303SMike Smith device_t child; 56785001303SMike Smith const char *s; 56885001303SMike Smith 56985001303SMike Smith id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4); 57085001303SMike Smith if (id == -1) 57185001303SMike Smith continue; 57285001303SMike Smith class = pci_cfgread(&probe, PCIR_CLASS, 1); 57385001303SMike Smith subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1); 57485001303SMike Smith 57585001303SMike Smith s = nexus_pcib_is_host_bridge(&probe, id, 57685001303SMike Smith class, subclass, 57785001303SMike Smith &busnum); 57885001303SMike Smith if (s) { 579f3b63bd3SPeter Wemm /* 580f3b63bd3SPeter Wemm * Add at priority 100 to make sure we 581f3b63bd3SPeter Wemm * go after any motherboard resources 582f3b63bd3SPeter Wemm */ 583f3b63bd3SPeter Wemm child = BUS_ADD_CHILD(parent, 100, 58485001303SMike Smith "pcib", busnum); 58585001303SMike Smith device_set_desc(child, s); 586cde35e1aSPeter Wemm found = 1; 587ac19291fSDoug Rabson if (id == 0x12258086) 588ac19291fSDoug Rabson found824xx = 1; 58985001303SMike Smith } 59085001303SMike Smith } 59185001303SMike Smith } 592ac19291fSDoug Rabson if (found824xx && probe.bus == 0) { 593ac19291fSDoug Rabson probe.bus++; 594ac19291fSDoug Rabson goto retry; 595ac19291fSDoug Rabson } 596cde35e1aSPeter Wemm 597cde35e1aSPeter Wemm /* 598cde35e1aSPeter Wemm * Make sure we add at least one bridge since some old 599cde35e1aSPeter Wemm * hardware doesn't actually have a host-pci bridge device. 600cde35e1aSPeter Wemm * Note that pci_cfgopen() thinks we have PCI devices.. 601cde35e1aSPeter Wemm */ 602cde35e1aSPeter Wemm if (!found) { 603cde35e1aSPeter Wemm if (bootverbose) 604cde35e1aSPeter Wemm printf( 605cde35e1aSPeter Wemm "nexus_pcib_identify: no bridge found, adding pcib0 anyway\n"); 606cde35e1aSPeter Wemm BUS_ADD_CHILD(parent, 100, "pcib", 0); 607cde35e1aSPeter Wemm } 60885001303SMike Smith } 60985001303SMike Smith 6108dc26439SPeter Wemm static int 6118dc26439SPeter Wemm nexus_pcib_probe(device_t dev) 6128dc26439SPeter Wemm { 6138dc26439SPeter Wemm if (pci_cfgopen() != 0) { 614fe0d4089SMatthew N. Dodd device_add_child(dev, "pci", device_get_unit(dev)); 6158dc26439SPeter Wemm return 0; 6168dc26439SPeter Wemm } 6178dc26439SPeter Wemm return ENXIO; 6188dc26439SPeter Wemm } 6198dc26439SPeter Wemm 6208dc26439SPeter Wemm static device_method_t nexus_pcib_methods[] = { 6218dc26439SPeter Wemm /* Device interface */ 62285001303SMike Smith DEVMETHOD(device_identify, nexus_pcib_identify), 6238dc26439SPeter Wemm DEVMETHOD(device_probe, nexus_pcib_probe), 6248dc26439SPeter Wemm DEVMETHOD(device_attach, bus_generic_attach), 6258dc26439SPeter Wemm DEVMETHOD(device_shutdown, bus_generic_shutdown), 6268dc26439SPeter Wemm DEVMETHOD(device_suspend, bus_generic_suspend), 6278dc26439SPeter Wemm DEVMETHOD(device_resume, bus_generic_resume), 6288dc26439SPeter Wemm 6298dc26439SPeter Wemm /* Bus interface */ 6308dc26439SPeter Wemm DEVMETHOD(bus_print_child, bus_generic_print_child), 6318dc26439SPeter Wemm DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 6328dc26439SPeter Wemm DEVMETHOD(bus_release_resource, bus_generic_release_resource), 6338dc26439SPeter Wemm DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 6348dc26439SPeter Wemm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 6358dc26439SPeter Wemm DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 6368dc26439SPeter Wemm DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 6378dc26439SPeter Wemm 6388dc26439SPeter Wemm { 0, 0 } 6398dc26439SPeter Wemm }; 6408dc26439SPeter Wemm 6418dc26439SPeter Wemm static driver_t nexus_pcib_driver = { 6428dc26439SPeter Wemm "pcib", 6438dc26439SPeter Wemm nexus_pcib_methods, 6448dc26439SPeter Wemm 1, 6458dc26439SPeter Wemm }; 6468dc26439SPeter Wemm 6478dc26439SPeter Wemm DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0); 648