1 /* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $Id: pcibus.c,v 1.39 1997/05/26 21:52:41 se Exp $ 27 * 28 */ 29 30 #include <sys/types.h> 31 #include <sys/systm.h> 32 33 #include <pci/pcivar.h> 34 #include <i386/isa/pcibus.h> 35 36 #ifdef PCI_COMPAT 37 /* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 38 #define cfgmech pci_mechanism 39 int cfgmech; 40 #else 41 static int cfgmech; 42 #endif /* PCI_COMPAT */ 43 static int devmax; 44 45 /* enable configuration space accesses and return data port address */ 46 47 static int 48 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 49 { 50 int dataport = 0; 51 52 if (bus <= PCI_BUSMAX 53 && slot < devmax 54 && func <= PCI_FUNCMAX 55 && reg <= PCI_REGMAX 56 && bytes != 3 57 && (unsigned) bytes <= 4 58 && (reg & (bytes -1)) == 0) { 59 switch (cfgmech) { 60 case 1: 61 outl(CONF1_ADDR_PORT, (1 << 31) 62 | (bus << 16) | (slot << 11) 63 | (func << 8) | (reg & ~0x03)); 64 dataport = CONF1_DATA_PORT + (reg & 0x03); 65 break; 66 case 2: 67 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 68 outb(CONF2_FORWARD_PORT, bus); 69 dataport = 0xc000 | (slot << 8) | reg; 70 break; 71 } 72 } 73 return (dataport); 74 } 75 76 /* disable configuration space accesses */ 77 78 static void 79 pci_cfgdisable(void) 80 { 81 switch (cfgmech) { 82 case 1: 83 outl(CONF1_ADDR_PORT, 0); 84 break; 85 case 2: 86 outb(CONF2_ENABLE_PORT, 0); 87 outb(CONF2_FORWARD_PORT, 0); 88 break; 89 } 90 } 91 92 /* read configuration space register */ 93 94 int 95 pci_cfgread(pcicfgregs *cfg, int reg, int bytes) 96 { 97 int data = -1; 98 int port; 99 100 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 101 102 if (port != 0) { 103 switch (bytes) { 104 case 1: 105 data = inb(port); 106 break; 107 case 2: 108 data = inw(port); 109 break; 110 case 4: 111 data = inl(port); 112 break; 113 } 114 pci_cfgdisable(); 115 } 116 return (data); 117 } 118 119 /* write configuration space register */ 120 121 void 122 pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 123 { 124 int port; 125 126 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 127 if (port != 0) { 128 switch (bytes) { 129 case 1: 130 outb(port, data); 131 break; 132 case 2: 133 outw(port, data); 134 break; 135 case 4: 136 outl(port, data); 137 break; 138 } 139 pci_cfgdisable(); 140 } 141 } 142 143 /* check whether the configuration mechanism has been correct identified */ 144 145 static int 146 pci_cfgcheck(int maxdev) 147 { 148 u_char device; 149 150 if (bootverbose) 151 printf("pci_cfgcheck:\tdevice "); 152 153 for (device = 0; device < maxdev; device++) { 154 unsigned id, class, header; 155 if (bootverbose) 156 printf("%d ", device); 157 158 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 159 if (id == 0 || id == -1) 160 continue; 161 162 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 163 if (bootverbose) 164 printf("[class=%06x] ", class); 165 if (class == 0 || (class & 0xf8f0ff) != 0) 166 continue; 167 168 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 169 if (bootverbose) 170 printf("[hdr=%02x] ", header); 171 if ((header & 0x7e) != 0) 172 continue; 173 174 if (bootverbose) 175 printf("is there (id=%08x)\n", id); 176 177 pci_cfgdisable(); 178 return (1); 179 } 180 if (bootverbose) 181 printf("-- nothing found\n"); 182 183 pci_cfgdisable(); 184 return (0); 185 } 186 187 int 188 pci_cfgopen(void) 189 { 190 unsigned long mode1res,oldval1; 191 unsigned char mode2res,oldval2; 192 193 oldval1 = inl(CONF1_ADDR_PORT); 194 195 if (bootverbose) { 196 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 197 oldval1); 198 } 199 200 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 201 202 cfgmech = 1; 203 devmax = 32; 204 205 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 206 outb(CONF1_ADDR_PORT +3, 0); 207 mode1res = inl(CONF1_ADDR_PORT); 208 outl(CONF1_ADDR_PORT, oldval1); 209 210 if (bootverbose) 211 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 212 mode1res, CONF1_ENABLE_CHK); 213 214 if (mode1res) { 215 if (pci_cfgcheck(32)) 216 return (cfgmech); 217 } 218 219 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 220 mode1res = inl(CONF1_ADDR_PORT); 221 outl(CONF1_ADDR_PORT, oldval1); 222 223 if (bootverbose) 224 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 225 mode1res, CONF1_ENABLE_CHK1); 226 227 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 228 if (pci_cfgcheck(32)) 229 return (cfgmech); 230 } 231 } 232 233 oldval2 = inb(CONF2_ENABLE_PORT); 234 235 if (bootverbose) { 236 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 237 oldval2); 238 } 239 240 if ((oldval2 & 0xf0) == 0) { 241 242 cfgmech = 2; 243 devmax = 16; 244 245 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 246 mode2res = inb(CONF2_ENABLE_PORT); 247 outb(CONF2_ENABLE_PORT, oldval2); 248 249 if (bootverbose) 250 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 251 mode2res, CONF2_ENABLE_CHK); 252 253 if (mode2res == CONF2_ENABLE_RES) { 254 if (bootverbose) 255 printf("pci_open(2a):\tnow trying mechanism 2\n"); 256 257 if (pci_cfgcheck(16)) 258 return (cfgmech); 259 } 260 } 261 262 cfgmech = 0; 263 devmax = 0; 264 return (cfgmech); 265 } 266