1 /************************************************************************** 2 ** 3 ** $Id: pcibus.c,v 1.31 1997/02/22 09:36:58 peter Exp $ 4 ** 5 ** pci bus subroutines for i386 architecture. 6 ** 7 ** FreeBSD 8 ** 9 **------------------------------------------------------------------------- 10 ** 11 ** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. 12 ** 13 ** Redistribution and use in source and binary forms, with or without 14 ** modification, are permitted provided that the following conditions 15 ** are met: 16 ** 1. Redistributions of source code must retain the above copyright 17 ** notice, this list of conditions and the following disclaimer. 18 ** 2. Redistributions in binary form must reproduce the above copyright 19 ** notice, this list of conditions and the following disclaimer in the 20 ** documentation and/or other materials provided with the distribution. 21 ** 3. The name of the author may not be used to endorse or promote products 22 ** derived from this software without specific prior written permission. 23 ** 24 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 ** 35 *************************************************************************** 36 */ 37 38 #include "vector.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 44 #include <i386/isa/icu.h> 45 #include <i386/isa/isa_device.h> 46 47 #include <pci/pcivar.h> 48 #include <pci/pcireg.h> 49 #include <pci/pcibus.h> 50 51 /*----------------------------------------------------------------- 52 ** 53 ** The following functions are provided by the pci bios. 54 ** They are used only by the pci configuration. 55 ** 56 ** pcibus_setup(): 57 ** Probes for a pci system. 58 ** Sets pci_maxdevice and pci_mechanism. 59 ** 60 ** pcibus_tag(): 61 ** Creates a handle for pci configuration space access. 62 ** This handle is given to the read/write functions. 63 ** 64 ** pcibus_ftag(): 65 ** Creates a modified handle. 66 ** 67 ** pcibus_read(): 68 ** Read a long word from the pci configuration space. 69 ** Requires a tag (from pcitag) and the register 70 ** number (should be a long word alligned one). 71 ** 72 ** pcibus_write(): 73 ** Writes a long word to the pci configuration space. 74 ** Requires a tag (from pcitag), the register number 75 ** (should be a long word alligned one), and a value. 76 ** 77 ** pcibus_regirq(): 78 ** Register an interupt handler for a pci device. 79 ** Requires a tag (from pcitag), the register number 80 ** (should be a long word alligned one), and a value. 81 ** 82 **----------------------------------------------------------------- 83 */ 84 85 static int 86 pcibus_check (void); 87 88 static void 89 pcibus_setup (void); 90 91 static pcici_t 92 pcibus_tag (u_char bus, u_char device, u_char func); 93 94 static pcici_t 95 pcibus_ftag (pcici_t tag, u_char func); 96 97 static u_long 98 pcibus_read (pcici_t tag, u_long reg); 99 100 static void 101 pcibus_write (pcici_t tag, u_long reg, u_long data); 102 103 static int 104 pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); 105 106 static int 107 pcibus_ihandler_detach (int irq, inthand2_t *func); 108 109 static int 110 pcibus_imask_include (int irq, unsigned* maskptr); 111 112 static int 113 pcibus_imask_exclude (int irq, unsigned* maskptr); 114 115 static struct pcibus i386pci = { 116 "pci", 117 pcibus_setup, 118 pcibus_tag, 119 pcibus_ftag, 120 pcibus_read, 121 pcibus_write, 122 pcibus_ihandler_attach, 123 pcibus_ihandler_detach, 124 pcibus_imask_include, 125 pcibus_imask_exclude, 126 }; 127 128 /* 129 ** Announce structure to generic driver 130 */ 131 132 DATA_SET (pcibus_set, i386pci); 133 134 /*-------------------------------------------------------------------- 135 ** 136 ** Determine configuration mode 137 ** 138 **-------------------------------------------------------------------- 139 */ 140 141 142 #define CONF1_ADDR_PORT 0x0cf8 143 #define CONF1_DATA_PORT 0x0cfc 144 145 #define CONF1_ENABLE 0x80000000ul 146 #define CONF1_ENABLE_CHK 0x80000000ul 147 #define CONF1_ENABLE_MSK 0x7ff00000ul 148 #define CONF1_ENABLE_CHK1 0xff000001ul 149 #define CONF1_ENABLE_MSK1 0x80000001ul 150 #define CONF1_ENABLE_RES1 0x80000000ul 151 152 #define CONF2_ENABLE_PORT 0x0cf8 153 #ifdef PC98 154 #define CONF2_FORWARD_PORT 0x0cf9 155 #else 156 #define CONF2_FORWARD_PORT 0x0cfa 157 #endif 158 159 #define CONF2_ENABLE_CHK 0x0e 160 #define CONF2_ENABLE_RES 0x0e 161 162 static int 163 pcibus_check (void) 164 { 165 u_char device; 166 167 if (bootverbose) printf ("pcibus_check:\tdevice "); 168 169 for (device = 0; device < pci_maxdevice; device++) { 170 unsigned long id, class, header; 171 if (bootverbose) 172 printf ("%d ", device); 173 id = pcibus_read (pcibus_tag (0,device,0), 0); 174 if ((id == 0) || (id == 0xfffffffful)) 175 continue; 176 177 class = pcibus_read (pcibus_tag (0,device,0), 8); 178 if (bootverbose) 179 printf ("[class=%x] ", class >> 8); 180 if ((class & 0xfff0ff00) != 0x06000000) 181 continue; 182 183 header = pcibus_read (pcibus_tag (0,device,0), 12); 184 if (bootverbose) 185 printf ("[hdr=%x] ", (header >> 16) & 0xff); 186 if ((header & 0x007e0000) != 0) 187 continue; 188 189 if (bootverbose) printf ("is there (id=%08lx)\n", id); 190 return 1; 191 } 192 if (bootverbose) 193 printf ("-- nothing found\n"); 194 return 0; 195 } 196 197 static void 198 pcibus_setup (void) 199 { 200 unsigned long mode1res,oldval1; 201 unsigned char mode2res,oldval2; 202 203 oldval1 = inl (CONF1_ADDR_PORT); 204 205 if (bootverbose) { 206 printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); 207 } 208 209 /*--------------------------------------- 210 ** Assume configuration mechanism 1 for now ... 211 **--------------------------------------- 212 */ 213 214 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 215 216 pci_mechanism = 1; 217 pci_maxdevice = 32; 218 219 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 220 outb (CONF1_ADDR_PORT +3, 0); 221 mode1res = inl (CONF1_ADDR_PORT); 222 outl (CONF1_ADDR_PORT, oldval1); 223 224 if (bootverbose) 225 printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", 226 mode1res, CONF1_ENABLE_CHK); 227 228 if (mode1res) { 229 if (pcibus_check()) 230 return; 231 }; 232 233 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 234 mode1res = inl(CONF1_ADDR_PORT); 235 outl (CONF1_ADDR_PORT, oldval1); 236 237 if (bootverbose) 238 printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", 239 mode1res, CONF1_ENABLE_CHK1); 240 241 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 242 if (pcibus_check()) 243 return; 244 }; 245 } 246 247 /*--------------------------------------- 248 ** Try configuration mechanism 2 ... 249 **--------------------------------------- 250 */ 251 252 oldval2 = inb (CONF2_ENABLE_PORT); 253 254 if (bootverbose) { 255 printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); 256 } 257 258 if ((oldval2 & 0xf0) == 0) { 259 260 pci_mechanism = 2; 261 pci_maxdevice = 16; 262 263 outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 264 mode2res = inb(CONF2_ENABLE_PORT); 265 outb (CONF2_ENABLE_PORT, oldval2); 266 267 if (bootverbose) 268 printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", 269 mode2res, CONF2_ENABLE_CHK); 270 271 if (mode2res == CONF2_ENABLE_RES) { 272 if (bootverbose) 273 printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); 274 275 if (pcibus_check()) 276 return; 277 } 278 } 279 280 /*--------------------------------------- 281 ** No PCI bus host bridge found 282 **--------------------------------------- 283 */ 284 285 pci_mechanism = 0; 286 pci_maxdevice = 0; 287 } 288 289 /*-------------------------------------------------------------------- 290 ** 291 ** Build a pcitag from bus, device and function number 292 ** 293 **-------------------------------------------------------------------- 294 */ 295 296 static pcici_t 297 pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) 298 { 299 pcici_t tag; 300 301 tag.cfg1 = 0; 302 if (func >= 8) return tag; 303 304 switch (pci_mechanism) { 305 306 case 1: 307 if (device < 32) { 308 tag.cfg1 = CONF1_ENABLE 309 | (((u_long) bus ) << 16ul) 310 | (((u_long) device) << 11ul) 311 | (((u_long) func ) << 8ul); 312 } 313 break; 314 case 2: 315 if (device < 16) { 316 tag.cfg2.port = 0xc000 | (device << 8ul); 317 tag.cfg2.enable = 0xf0 | (func << 1ul); 318 tag.cfg2.forward = bus; 319 } 320 break; 321 }; 322 return tag; 323 } 324 325 static pcici_t 326 pcibus_ftag (pcici_t tag, u_char func) 327 { 328 switch (pci_mechanism) { 329 330 case 1: 331 tag.cfg1 &= ~0x700ul; 332 tag.cfg1 |= (((u_long) func) << 8ul); 333 break; 334 case 2: 335 tag.cfg2.enable = 0xf0 | (func << 1ul); 336 break; 337 }; 338 return tag; 339 } 340 341 /*-------------------------------------------------------------------- 342 ** 343 ** Read register from configuration space. 344 ** 345 **-------------------------------------------------------------------- 346 */ 347 348 static u_long 349 pcibus_read (pcici_t tag, u_long reg) 350 { 351 u_long addr, data = 0; 352 353 if (!tag.cfg1) return (0xfffffffful); 354 355 switch (pci_mechanism) { 356 357 case 1: 358 addr = tag.cfg1 | (reg & 0xfc); 359 #ifdef PCI_DEBUG 360 printf ("pci_conf_read(1): addr=%x ", addr); 361 #endif 362 outl (CONF1_ADDR_PORT, addr); 363 data = inl (CONF1_DATA_PORT); 364 outl (CONF1_ADDR_PORT, 0 ); 365 break; 366 367 case 2: 368 addr = tag.cfg2.port | (reg & 0xfc); 369 #ifdef PCI_DEBUG 370 printf ("pci_conf_read(2): addr=%x ", addr); 371 #endif 372 outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); 373 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 374 375 data = inl ((u_short) addr); 376 377 outb (CONF2_ENABLE_PORT, 0); 378 outb (CONF2_FORWARD_PORT, 0); 379 break; 380 }; 381 382 #ifdef PCI_DEBUG 383 printf ("data=%x\n", data); 384 #endif 385 386 return (data); 387 } 388 389 /*-------------------------------------------------------------------- 390 ** 391 ** Write register into configuration space. 392 ** 393 **-------------------------------------------------------------------- 394 */ 395 396 static void 397 pcibus_write (pcici_t tag, u_long reg, u_long data) 398 { 399 u_long addr; 400 401 if (!tag.cfg1) return; 402 403 switch (pci_mechanism) { 404 405 case 1: 406 addr = tag.cfg1 | (reg & 0xfc); 407 #ifdef PCI_DEBUG 408 printf ("pci_conf_write(1): addr=%x data=%x\n", 409 addr, data); 410 #endif 411 outl (CONF1_ADDR_PORT, addr); 412 outl (CONF1_DATA_PORT, data); 413 outl (CONF1_ADDR_PORT, 0 ); 414 break; 415 416 case 2: 417 addr = tag.cfg2.port | (reg & 0xfc); 418 #ifdef PCI_DEBUG 419 printf ("pci_conf_write(2): addr=%x data=%x\n", 420 addr, data); 421 #endif 422 outb (CONF2_ENABLE_PORT, tag.cfg2.enable); 423 outb (CONF2_FORWARD_PORT, tag.cfg2.forward); 424 425 outl ((u_short) addr, data); 426 427 outb (CONF2_ENABLE_PORT, 0); 428 outb (CONF2_FORWARD_PORT, 0); 429 break; 430 }; 431 } 432 433 /*----------------------------------------------------------------------- 434 ** 435 ** Register an interupt handler for a pci device. 436 ** 437 **----------------------------------------------------------------------- 438 */ 439 440 static int 441 pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) 442 { 443 char buf[16]; 444 char *cp; 445 int free_id, id, result; 446 447 sprintf(buf, "pci irq%d", irq); 448 for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { 449 if (strcmp(cp, buf) == 0) 450 break; 451 if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) 452 free_id = id; 453 while (*cp++ != '\0') 454 ; 455 } 456 if (id == NR_DEVICES) { 457 id = free_id; 458 if (id == 0) { 459 /* 460 * All pci irq counters are in use, perhaps because 461 * config is old so there aren't any. Abuse the 462 * clk0 counter. 463 */ 464 printf ( 465 "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", 466 irq); 467 } 468 } 469 result = register_intr( 470 irq, /* isa irq */ 471 id, /* device id */ 472 0, /* flags? */ 473 func, /* handler */ 474 maskptr, /* mask pointer */ 475 arg); /* handler arg */ 476 477 if (result) { 478 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); 479 return (result); 480 }; 481 update_intr_masks(); 482 483 INTREN ((1ul<<irq)); 484 return (0); 485 } 486 487 static int 488 pcibus_ihandler_detach (int irq, inthand2_t *func) 489 { 490 int result; 491 492 INTRDIS ((1ul<<irq)); 493 494 result = unregister_intr (irq, func); 495 496 if (result) 497 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); 498 499 update_intr_masks(); 500 501 return (result); 502 } 503 504 static int 505 pcibus_imask_include (int irq, unsigned* maskptr) 506 { 507 unsigned mask; 508 509 if (!maskptr) return (0); 510 511 mask = 1ul << irq; 512 513 if (*maskptr & mask) 514 return (-1); 515 516 INTRMASK (*maskptr, mask); 517 update_intr_masks(); 518 519 return (0); 520 } 521 522 static int 523 pcibus_imask_exclude (int irq, unsigned* maskptr) 524 { 525 unsigned mask; 526 527 if (!maskptr) return (0); 528 529 mask = 1ul << irq; 530 531 if (! (*maskptr & mask)) 532 return (-1); 533 534 INTRUNMASK (*maskptr, mask); 535 update_intr_masks(); 536 537 return (0); 538 } 539