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 * 26b3daa02eSStefan Eßer * $Id: pcibus.c,v 1.38 1997/05/26 21:25:24 se Exp $ 275bec6157SStefan Eßer * 28ac19f918SStefan Eßer */ 29ac19f918SStefan Eßer 305bec6157SStefan Eßer #include <sys/types.h> 315bec6157SStefan Eßer #include <sys/systm.h> 32ac19f918SStefan Eßer 335bec6157SStefan Eßer #include <pci/pcireg.h> 345bec6157SStefan Eßer #include <pci/pcivar.h> 355bec6157SStefan Eßer #include <i386/isa/pcibus.h> 36ac19f918SStefan Eßer 375bec6157SStefan Eßer #ifdef PCI_COMPAT 385bec6157SStefan Eßer /* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 395bec6157SStefan Eßer #define cfgmech pci_mechanism 405bec6157SStefan Eßer int cfgmech; 41e30f0011SSatoshi Asami #else 425bec6157SStefan Eßer static int cfgmech; 435bec6157SStefan Eßer #endif /* PCI_COMPAT */ 445bec6157SStefan Eßer static int devmax; 45ac19f918SStefan Eßer 465bec6157SStefan Eßer /* enable configuration space accesses and return data port address */ 47ac19f918SStefan Eßer 48a3adc4f8SStefan Eßer static int 495bec6157SStefan Eßer pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 505bec6157SStefan Eßer { 515bec6157SStefan Eßer int dataport = 0; 525bec6157SStefan Eßer 535bec6157SStefan Eßer if (bus <= PCI_BUSMAX 545bec6157SStefan Eßer && slot < devmax 555bec6157SStefan Eßer && func <= PCI_FUNCMAX 565bec6157SStefan Eßer && reg <= PCI_REGMAX 575bec6157SStefan Eßer && bytes != 3 585bec6157SStefan Eßer && (unsigned) bytes <= 4 595bec6157SStefan Eßer && (reg & (bytes -1)) == 0) { 605bec6157SStefan Eßer switch (cfgmech) { 615bec6157SStefan Eßer case 1: 62b3daa02eSStefan Eßer outl(CONF1_ADDR_PORT, (1 << 31) 63b3daa02eSStefan Eßer | (bus << 16) | (slot << 11) 64b3daa02eSStefan Eßer | (func << 8) | (reg & ~0x03)); 65b3daa02eSStefan Eßer dataport = CONF1_DATA_PORT + (reg & 0x03); 665bec6157SStefan Eßer break; 675bec6157SStefan Eßer case 2: 685bec6157SStefan Eßer outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 695bec6157SStefan Eßer outb(CONF2_FORWARD_PORT, bus); 705bec6157SStefan Eßer dataport = 0xc000 | (slot << 8) | reg; 715bec6157SStefan Eßer break; 725bec6157SStefan Eßer } 735bec6157SStefan Eßer } 745bec6157SStefan Eßer return (dataport); 755bec6157SStefan Eßer } 765bec6157SStefan Eßer 775bec6157SStefan Eßer /* disable configuration space accesses */ 785bec6157SStefan Eßer 795bec6157SStefan Eßer static void 805bec6157SStefan Eßer pci_cfgdisable(void) 815bec6157SStefan Eßer { 825bec6157SStefan Eßer switch (cfgmech) { 835bec6157SStefan Eßer case 1: 845bec6157SStefan Eßer outl(CONF1_ADDR_PORT, 0); 855bec6157SStefan Eßer break; 865bec6157SStefan Eßer case 2: 875bec6157SStefan Eßer outb(CONF2_ENABLE_PORT, 0); 885bec6157SStefan Eßer outb(CONF2_FORWARD_PORT, 0); 895bec6157SStefan Eßer break; 905bec6157SStefan Eßer } 915bec6157SStefan Eßer } 925bec6157SStefan Eßer 935bec6157SStefan Eßer /* read configuration space register */ 945bec6157SStefan Eßer 955bec6157SStefan Eßer int 965bec6157SStefan Eßer pci_cfgread(pcicfgregs *cfg, int reg, int bytes) 975bec6157SStefan Eßer { 985bec6157SStefan Eßer int data = -1; 995bec6157SStefan Eßer int port; 1005bec6157SStefan Eßer 1015bec6157SStefan Eßer port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 1025bec6157SStefan Eßer 1035bec6157SStefan Eßer if (port != 0) { 1045bec6157SStefan Eßer switch (bytes) { 1055bec6157SStefan Eßer case 1: 1065bec6157SStefan Eßer data = inb(port); 1075bec6157SStefan Eßer break; 1085bec6157SStefan Eßer case 2: 1095bec6157SStefan Eßer data = inw(port); 1105bec6157SStefan Eßer break; 1115bec6157SStefan Eßer case 4: 1125bec6157SStefan Eßer data = inl(port); 1135bec6157SStefan Eßer break; 1145bec6157SStefan Eßer } 1155bec6157SStefan Eßer pci_cfgdisable(); 1165bec6157SStefan Eßer } 1175bec6157SStefan Eßer return (data); 1185bec6157SStefan Eßer } 1195bec6157SStefan Eßer 1205bec6157SStefan Eßer /* write configuration space register */ 1215bec6157SStefan Eßer 1225bec6157SStefan Eßer void 1235bec6157SStefan Eßer pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 1245bec6157SStefan Eßer { 1255bec6157SStefan Eßer int port; 1265bec6157SStefan Eßer 1275bec6157SStefan Eßer port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 1285bec6157SStefan Eßer if (port != 0) { 1295bec6157SStefan Eßer switch (bytes) { 1305bec6157SStefan Eßer case 1: 1315bec6157SStefan Eßer outb(port, data); 1325bec6157SStefan Eßer break; 1335bec6157SStefan Eßer case 2: 1345bec6157SStefan Eßer outw(port, data); 1355bec6157SStefan Eßer break; 1365bec6157SStefan Eßer case 4: 1375bec6157SStefan Eßer outl(port, data); 1385bec6157SStefan Eßer break; 1395bec6157SStefan Eßer } 1405bec6157SStefan Eßer pci_cfgdisable(); 1415bec6157SStefan Eßer } 1425bec6157SStefan Eßer } 1435bec6157SStefan Eßer 1445bec6157SStefan Eßer /* check whether the configuration mechanism has been correct identified */ 1455bec6157SStefan Eßer 1465bec6157SStefan Eßer static int 1475bec6157SStefan Eßer pci_cfgcheck(int maxdev) 148a3adc4f8SStefan Eßer { 149a3adc4f8SStefan Eßer u_char device; 150a3adc4f8SStefan Eßer 1515bec6157SStefan Eßer if (bootverbose) 1525bec6157SStefan Eßer printf("pci_cfgcheck:\tdevice "); 15377b57314SStefan Eßer 1545bec6157SStefan Eßer for (device = 0; device < maxdev; device++) { 1555bec6157SStefan Eßer unsigned id, class, header; 156c7483249SStefan Eßer if (bootverbose) 157c7483249SStefan Eßer printf("%d ", device); 1585bec6157SStefan Eßer 1595bec6157SStefan Eßer id = inl(pci_cfgenable(0, device, 0, 0, 4)); 1605bec6157SStefan Eßer if (id == 0 || id == -1) 16181cf5d7aSStefan Eßer continue; 16281cf5d7aSStefan Eßer 1635bec6157SStefan Eßer class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 16481cf5d7aSStefan Eßer if (bootverbose) 1655bec6157SStefan Eßer printf("[class=%06x] ", class); 1665bec6157SStefan Eßer if (class == 0 || (class & 0xf8f0ff) != 0) 16781cf5d7aSStefan Eßer continue; 16881cf5d7aSStefan Eßer 1695bec6157SStefan Eßer header = inb(pci_cfgenable(0, device, 0, 14, 1)); 17081cf5d7aSStefan Eßer if (bootverbose) 1715bec6157SStefan Eßer printf("[hdr=%02x] ", header); 1725bec6157SStefan Eßer if ((header & 0x7e) != 0) 17381cf5d7aSStefan Eßer continue; 17481cf5d7aSStefan Eßer 1755bec6157SStefan Eßer if (bootverbose) 1765bec6157SStefan Eßer printf("is there (id=%08x)\n", id); 1775bec6157SStefan Eßer 1785bec6157SStefan Eßer pci_cfgdisable(); 1795bec6157SStefan Eßer return (1); 180a3adc4f8SStefan Eßer } 181c7483249SStefan Eßer if (bootverbose) 182c7483249SStefan Eßer printf("-- nothing found\n"); 1835bec6157SStefan Eßer 1845bec6157SStefan Eßer pci_cfgdisable(); 1855bec6157SStefan Eßer return (0); 186a3adc4f8SStefan Eßer } 187d7ea35fcSStefan Eßer 1885bec6157SStefan Eßer int 1895bec6157SStefan Eßer pci_cfgopen(void) 190ac19f918SStefan Eßer { 191287911bdSStefan Eßer unsigned long mode1res,oldval1; 192287911bdSStefan Eßer unsigned char mode2res,oldval2; 1930847c06dSStefan Eßer 194287911bdSStefan Eßer oldval1 = inl(CONF1_ADDR_PORT); 195a3adc4f8SStefan Eßer 19677b57314SStefan Eßer if (bootverbose) { 1975bec6157SStefan Eßer printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 1985bec6157SStefan Eßer oldval1); 199a3adc4f8SStefan Eßer } 200a3adc4f8SStefan Eßer 2010e2f699bSStefan Eßer if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 202287911bdSStefan Eßer 2035bec6157SStefan Eßer cfgmech = 1; 2045bec6157SStefan Eßer devmax = 32; 20577b57314SStefan Eßer 20677b57314SStefan Eßer outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 20777b57314SStefan Eßer outb(CONF1_ADDR_PORT +3, 0); 20877b57314SStefan Eßer mode1res = inl(CONF1_ADDR_PORT); 209287911bdSStefan Eßer outl(CONF1_ADDR_PORT, oldval1); 21077b57314SStefan Eßer 21177b57314SStefan Eßer if (bootverbose) 2125bec6157SStefan Eßer printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 21377b57314SStefan Eßer mode1res, CONF1_ENABLE_CHK); 21477b57314SStefan Eßer 21577b57314SStefan Eßer if (mode1res) { 2165bec6157SStefan Eßer if (pci_cfgcheck(32)) 2175bec6157SStefan Eßer return (cfgmech); 2185bec6157SStefan Eßer } 21977b57314SStefan Eßer 22077b57314SStefan Eßer outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 22177b57314SStefan Eßer mode1res = inl(CONF1_ADDR_PORT); 222287911bdSStefan Eßer outl(CONF1_ADDR_PORT, oldval1); 22377b57314SStefan Eßer 22477b57314SStefan Eßer if (bootverbose) 2255bec6157SStefan Eßer printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 22677b57314SStefan Eßer mode1res, CONF1_ENABLE_CHK1); 22777b57314SStefan Eßer 228c7483249SStefan Eßer if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 2295bec6157SStefan Eßer if (pci_cfgcheck(32)) 2305bec6157SStefan Eßer return (cfgmech); 231287911bdSStefan Eßer } 2325bec6157SStefan Eßer } 23377b57314SStefan Eßer 234287911bdSStefan Eßer oldval2 = inb(CONF2_ENABLE_PORT); 235287911bdSStefan Eßer 236287911bdSStefan Eßer if (bootverbose) { 2375bec6157SStefan Eßer printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 2385bec6157SStefan Eßer oldval2); 239287911bdSStefan Eßer } 240287911bdSStefan Eßer 241287911bdSStefan Eßer if ((oldval2 & 0xf0) == 0) { 242c7483249SStefan Eßer 2435bec6157SStefan Eßer cfgmech = 2; 2445bec6157SStefan Eßer devmax = 16; 24577b57314SStefan Eßer 246287911bdSStefan Eßer outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 247287911bdSStefan Eßer mode2res = inb(CONF2_ENABLE_PORT); 248287911bdSStefan Eßer outb(CONF2_ENABLE_PORT, oldval2); 249287911bdSStefan Eßer 250287911bdSStefan Eßer if (bootverbose) 2515bec6157SStefan Eßer printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 252287911bdSStefan Eßer mode2res, CONF2_ENABLE_CHK); 253287911bdSStefan Eßer 254287911bdSStefan Eßer if (mode2res == CONF2_ENABLE_RES) { 255287911bdSStefan Eßer if (bootverbose) 2565bec6157SStefan Eßer printf("pci_open(2a):\tnow trying mechanism 2\n"); 257287911bdSStefan Eßer 2585bec6157SStefan Eßer if (pci_cfgcheck(16)) 2595bec6157SStefan Eßer return (cfgmech); 260287911bdSStefan Eßer } 261287911bdSStefan Eßer } 26277b57314SStefan Eßer 2635bec6157SStefan Eßer cfgmech = 0; 2645bec6157SStefan Eßer devmax = 0; 2655bec6157SStefan Eßer return (cfgmech); 266ac19f918SStefan Eßer } 267