1 /* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000, BSDi 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 #include <dev/pci/pcivar.h> 38 #include <dev/pci/pcireg.h> 39 #include <machine/pci_cfgreg.h> 40 #include <machine/pc/bios.h> 41 42 #define PRVERB(a) do { \ 43 if (bootverbose) \ 44 printf a ; \ 45 } while(0) 46 47 static int cfgmech; 48 static int devmax; 49 50 static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); 51 static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 52 static int pcireg_cfgopen(void); 53 54 static struct mtx pcicfg_mtx; 55 56 /* 57 * Some BIOS writers seem to want to ignore the spec and put 58 * 0 in the intline rather than 255 to indicate none. Some use 59 * numbers in the range 128-254 to indicate something strange and 60 * apparently undocumented anywhere. Assume these are completely bogus 61 * and map them to 255, which means "none". 62 */ 63 static __inline int 64 pci_i386_map_intline(int line) 65 { 66 if (line == 0 || line >= 128) 67 return (PCI_INVALID_IRQ); 68 return (line); 69 } 70 71 static u_int16_t 72 pcibios_get_version(void) 73 { 74 struct bios_regs args; 75 76 if (PCIbios.ventry == 0) { 77 PRVERB(("pcibios: No call entry point\n")); 78 return (0); 79 } 80 args.eax = PCIBIOS_BIOS_PRESENT; 81 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 82 PRVERB(("pcibios: BIOS_PRESENT call failed\n")); 83 return (0); 84 } 85 if (args.edx != 0x20494350) { 86 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); 87 return (0); 88 } 89 return (args.ebx & 0xffff); 90 } 91 92 /* 93 * Initialise access to PCI configuration space 94 */ 95 int 96 pci_cfgregopen(void) 97 { 98 static int opened = 0; 99 u_int16_t v; 100 101 if (opened) 102 return(1); 103 104 if (pcireg_cfgopen() == 0) 105 return(0); 106 107 v = pcibios_get_version(); 108 if (v > 0) 109 PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, 110 v & 0xff)); 111 mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 112 opened = 1; 113 114 /* $PIR requires PCI BIOS 2.10 or greater. */ 115 if (v >= 0x0210) 116 pci_pir_open(); 117 return(1); 118 } 119 120 /* 121 * Read configuration space register 122 */ 123 u_int32_t 124 pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 125 { 126 uint32_t line; 127 128 /* 129 * Some BIOS writers seem to want to ignore the spec and put 130 * 0 in the intline rather than 255 to indicate none. The rest of 131 * the code uses 255 as an invalid IRQ. 132 */ 133 if (reg == PCIR_INTLINE && bytes == 1) { 134 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1); 135 return (pci_i386_map_intline(line)); 136 } 137 return (pcireg_cfgread(bus, slot, func, reg, bytes)); 138 } 139 140 /* 141 * Write configuration space register 142 */ 143 void 144 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 145 { 146 147 pcireg_cfgwrite(bus, slot, func, reg, data, bytes); 148 } 149 150 /* 151 * Configuration space access using direct register operations 152 */ 153 154 /* enable configuration space accesses and return data port address */ 155 static int 156 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 157 { 158 int dataport = 0; 159 160 if (bus <= PCI_BUSMAX 161 && slot < devmax 162 && func <= PCI_FUNCMAX 163 && reg <= PCI_REGMAX 164 && bytes != 3 165 && (unsigned) bytes <= 4 166 && (reg & (bytes - 1)) == 0) { 167 switch (cfgmech) { 168 case 1: 169 outl(CONF1_ADDR_PORT, (1 << 31) 170 | (bus << 16) | (slot << 11) 171 | (func << 8) | (reg & ~0x03)); 172 dataport = CONF1_DATA_PORT + (reg & 0x03); 173 break; 174 case 2: 175 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 176 outb(CONF2_FORWARD_PORT, bus); 177 dataport = 0xc000 | (slot << 8) | reg; 178 break; 179 } 180 } 181 return (dataport); 182 } 183 184 /* disable configuration space accesses */ 185 static void 186 pci_cfgdisable(void) 187 { 188 switch (cfgmech) { 189 case 1: 190 outl(CONF1_ADDR_PORT, 0); 191 break; 192 case 2: 193 outb(CONF2_ENABLE_PORT, 0); 194 outb(CONF2_FORWARD_PORT, 0); 195 break; 196 } 197 } 198 199 static int 200 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 201 { 202 int data = -1; 203 int port; 204 205 mtx_lock_spin(&pcicfg_mtx); 206 port = pci_cfgenable(bus, slot, func, reg, bytes); 207 if (port != 0) { 208 switch (bytes) { 209 case 1: 210 data = inb(port); 211 break; 212 case 2: 213 data = inw(port); 214 break; 215 case 4: 216 data = inl(port); 217 break; 218 } 219 pci_cfgdisable(); 220 } 221 mtx_unlock_spin(&pcicfg_mtx); 222 return (data); 223 } 224 225 static void 226 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 227 { 228 int port; 229 230 mtx_lock_spin(&pcicfg_mtx); 231 port = pci_cfgenable(bus, slot, func, reg, bytes); 232 if (port != 0) { 233 switch (bytes) { 234 case 1: 235 outb(port, data); 236 break; 237 case 2: 238 outw(port, data); 239 break; 240 case 4: 241 outl(port, data); 242 break; 243 } 244 pci_cfgdisable(); 245 } 246 mtx_unlock_spin(&pcicfg_mtx); 247 } 248 249 /* check whether the configuration mechanism has been correctly identified */ 250 static int 251 pci_cfgcheck(int maxdev) 252 { 253 uint32_t id, class; 254 uint8_t header; 255 uint8_t device; 256 int port; 257 258 if (bootverbose) 259 printf("pci_cfgcheck:\tdevice "); 260 261 for (device = 0; device < maxdev; device++) { 262 if (bootverbose) 263 printf("%d ", device); 264 265 port = pci_cfgenable(0, device, 0, 0, 4); 266 id = inl(port); 267 if (id == 0 || id == 0xffffffff) 268 continue; 269 270 port = pci_cfgenable(0, device, 0, 8, 4); 271 class = inl(port) >> 8; 272 if (bootverbose) 273 printf("[class=%06x] ", class); 274 if (class == 0 || (class & 0xf870ff) != 0) 275 continue; 276 277 port = pci_cfgenable(0, device, 0, 14, 1); 278 header = inb(port); 279 if (bootverbose) 280 printf("[hdr=%02x] ", header); 281 if ((header & 0x7e) != 0) 282 continue; 283 284 if (bootverbose) 285 printf("is there (id=%08x)\n", id); 286 287 pci_cfgdisable(); 288 return (1); 289 } 290 if (bootverbose) 291 printf("-- nothing found\n"); 292 293 pci_cfgdisable(); 294 return (0); 295 } 296 297 static int 298 pcireg_cfgopen(void) 299 { 300 uint32_t mode1res, oldval1; 301 uint8_t mode2res, oldval2; 302 303 oldval1 = inl(CONF1_ADDR_PORT); 304 305 if (bootverbose) { 306 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n", 307 oldval1); 308 } 309 310 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 311 312 cfgmech = 1; 313 devmax = 32; 314 315 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 316 DELAY(1); 317 mode1res = inl(CONF1_ADDR_PORT); 318 outl(CONF1_ADDR_PORT, oldval1); 319 320 if (bootverbose) 321 printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 322 mode1res, CONF1_ENABLE_CHK); 323 324 if (mode1res) { 325 if (pci_cfgcheck(32)) 326 return (cfgmech); 327 } 328 329 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 330 mode1res = inl(CONF1_ADDR_PORT); 331 outl(CONF1_ADDR_PORT, oldval1); 332 333 if (bootverbose) 334 printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 335 mode1res, CONF1_ENABLE_CHK1); 336 337 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 338 if (pci_cfgcheck(32)) 339 return (cfgmech); 340 } 341 } 342 343 oldval2 = inb(CONF2_ENABLE_PORT); 344 345 if (bootverbose) { 346 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 347 oldval2); 348 } 349 350 if ((oldval2 & 0xf0) == 0) { 351 352 cfgmech = 2; 353 devmax = 16; 354 355 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 356 mode2res = inb(CONF2_ENABLE_PORT); 357 outb(CONF2_ENABLE_PORT, oldval2); 358 359 if (bootverbose) 360 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 361 mode2res, CONF2_ENABLE_CHK); 362 363 if (mode2res == CONF2_ENABLE_RES) { 364 if (bootverbose) 365 printf("pci_open(2a):\tnow trying mechanism 2\n"); 366 367 if (pci_cfgcheck(16)) 368 return (cfgmech); 369 } 370 } 371 372 cfgmech = 0; 373 devmax = 0; 374 return (cfgmech); 375 } 376 377