1 /************************************************************************** 2 ** 3 ** $Id: pci.c,v 1.8 1994/10/25 23:09:08 se Exp $ 4 ** 5 ** General subroutines for the PCI bus on 80*86 systems. 6 ** pci_configure () 7 ** 8 ** 386bsd / FreeBSD 9 ** 10 **------------------------------------------------------------------------- 11 ** 12 ** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. 13 ** 14 ** Redistribution and use in source and binary forms, with or without 15 ** modification, are permitted provided that the following conditions 16 ** are met: 17 ** 1. Redistributions of source code must retain the above copyright 18 ** notice, this list of conditions and the following disclaimer. 19 ** 2. Redistributions in binary form must reproduce the above copyright 20 ** notice, this list of conditions and the following disclaimer in the 21 ** documentation and/or other materials provided with the distribution. 22 ** 3. The name of the author may not be used to endorse or promote products 23 ** derived from this software without specific prior written permission. 24 ** 25 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 ** 36 *************************************************************************** 37 */ 38 39 #include <pci.h> 40 #if NPCI > 0 41 42 #ifndef __FreeBSD2__ 43 #if __FreeBSD__ >= 2 44 #define __FreeBSD2__ 45 #endif 46 #endif 47 48 /*======================================================== 49 ** 50 ** #includes and declarations 51 ** 52 **======================================================== 53 */ 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/malloc.h> 58 #include <sys/errno.h> 59 60 #include <vm/vm.h> 61 #include <vm/vm_param.h> 62 63 #include <i386/isa/isa.h> 64 #include <i386/isa/isa_device.h> 65 #include <i386/isa/icu.h> 66 #include <i386/pci/pcireg.h> 67 68 #ifdef __FreeBSD2__ 69 #include <sys/devconf.h> 70 71 struct pci_devconf { 72 struct kern_devconf pdc_kdc; 73 struct pci_info pdc_pi; 74 }; 75 #endif 76 77 /* 78 ** Function prototypes missing in system headers 79 */ 80 81 #ifndef __FreeBSD2__ 82 extern pmap_t pmap_kernel(void); 83 static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize); 84 85 /* 86 * Type of the first (asm) part of an interrupt handler. 87 */ 88 typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss)); 89 90 /* 91 * Usual type of the second (C) part of an interrupt handler. Some bogus 92 * ones need the arg to be the interrupt frame (and not a copy of it, which 93 * is all that is possible in C). 94 */ 95 typedef void inthand2_t __P((int unit)); 96 97 /* 98 ** XXX @FreeBSD2@ 99 ** 100 ** Unfortunately, the mptr argument is _no_ pointer in 2.0 FreeBSD. 101 ** We would prefer a pointer because it enables us to install 102 ** new interrupt handlers at any time. 103 ** (This is just going to be changed ... <se> :) 104 ** In 2.0 FreeBSD later installed interrupt handlers may change 105 ** the xyz_imask, but this would not be recognized by handlers 106 ** which are installed before. 107 */ 108 109 static int 110 register_intr __P((int intr, int device_id, unsigned int flags, 111 inthand2_t *handler, unsigned int * mptr, int unit)); 112 extern unsigned intr_mask[ICU_LEN]; 113 114 #endif /* !__FreeBSD2__ */ 115 116 /*======================================================== 117 ** 118 ** Autoconfiguration of pci devices. 119 ** 120 ** This is reverse to the isa configuration. 121 ** (1) find a pci device. 122 ** (2) look for a driver. 123 ** 124 **======================================================== 125 */ 126 127 /*-------------------------------------------------------- 128 ** 129 ** The pci devices can be mapped to any address. 130 ** As default we start at the last gigabyte. 131 ** 132 **-------------------------------------------------------- 133 */ 134 135 #ifndef PCI_PMEM_START 136 #define PCI_PMEM_START 0xc0000000 137 #endif 138 139 static vm_offset_t pci_paddr = PCI_PMEM_START; 140 141 /*-------------------------------------------------------- 142 ** 143 ** The pci device interrupt lines should have been 144 ** assigned by the bios. But if the bios failed to 145 ** to it, we set it. 146 ** 147 **-------------------------------------------------------- 148 */ 149 150 #ifndef PCI_IRQ 151 #define PCI_IRQ 0 152 #endif 153 154 static u_long pci_irq = PCI_IRQ; 155 156 /*--------------------------------------------------------- 157 ** 158 ** pci_configure () 159 ** 160 ** Probe all devices on pci bus and attach them. 161 ** 162 ** May be called more than once. 163 ** Any device is attached only once. 164 ** (Attached devices are remembered in pci_seen.) 165 ** 166 **--------------------------------------------------------- 167 */ 168 169 static void not_supported (pcici_t tag, u_long type); 170 171 static unsigned long pci_seen[NPCI]; 172 173 static int pci_conf_count; 174 175 #ifdef __FreeBSD2__ 176 static int 177 pci_externalize (struct proc *, struct kern_devconf *, void *, size_t); 178 179 static int 180 pci_internalize (struct proc *, struct kern_devconf *, void *, size_t); 181 182 #endif /* __FreeBSD2__ */ 183 184 void pci_configure() 185 { 186 u_char device,last_device; 187 u_short bus; 188 pcici_t tag; 189 pcidi_t type; 190 u_long data; 191 int unit; 192 int pci_mechanism; 193 int pciint; 194 int irq; 195 char* name=0; 196 vm_offset_t old_addr=pci_paddr; 197 198 struct pci_driver *drp=0; 199 struct pci_device *dvp; 200 201 #ifdef __FreeBSD2__ 202 struct pci_devconf *pdcp; 203 #endif 204 205 /* 206 ** check pci bus present 207 */ 208 209 pci_mechanism = pci_conf_mode (); 210 if (!pci_mechanism) return; 211 last_device = pci_mechanism==1 ? 31 : 15; 212 213 /* 214 ** hello world .. 215 */ 216 217 218 for (bus=0;bus<NPCI;bus++) { 219 #ifndef PCI_QUIET 220 printf ("pci%d: scanning device 0..%d, mechanism=%d.\n", 221 bus, last_device, pci_mechanism); 222 #endif 223 for (device=0; device<=last_device; device ++) { 224 225 if (pci_seen[bus] & (1ul << device)) 226 continue; 227 228 tag = pcitag (bus, device, 0); 229 type = pci_conf_read (tag, PCI_ID_REG); 230 231 if ((!type) || (type==0xfffffffful)) continue; 232 233 /* 234 ** lookup device in ioconfiguration: 235 */ 236 237 for (dvp = pci_devtab; dvp->pd_name; dvp++) { 238 drp = dvp->pd_driver; 239 if (!drp) 240 continue; 241 if ((name=(*drp->probe)(tag, type))) 242 break; 243 }; 244 245 if (!dvp->pd_name) { 246 #ifndef PCI_QUIET 247 if (pci_conf_count) 248 continue; 249 printf("pci%d:%d: ", bus, device); 250 not_supported (tag, type); 251 #endif 252 continue; 253 }; 254 255 pci_seen[bus] |= (1ul << device); 256 /* 257 ** Get and increment the unit. 258 */ 259 260 unit = (*drp->count)++; 261 262 /* 263 ** ignore device ? 264 */ 265 266 if (!*name) continue; 267 268 /* 269 ** Announce this device 270 */ 271 272 printf ("%s%d <%s>", dvp->pd_name, unit, name); 273 274 /* 275 ** Get the int pin number (pci interrupt number a-d) 276 ** from the pci configuration space. 277 */ 278 279 data = pci_conf_read (tag, PCI_INTERRUPT_REG); 280 pciint = PCI_INTERRUPT_PIN_EXTRACT(data); 281 282 if (pciint) { 283 284 printf (" int %c", 0x60+pciint); 285 286 /* 287 ** If the interrupt line register is not set, 288 ** set it now from PCI_IRQ. 289 */ 290 291 if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) { 292 293 irq = pci_irq & 0x0f; 294 pci_irq >>= 4; 295 296 data = PCI_INTERRUPT_LINE_INSERT(data, irq); 297 printf (" (config)"); 298 pci_conf_write (tag, PCI_INTERRUPT_REG, data); 299 }; 300 301 irq = PCI_INTERRUPT_LINE_EXTRACT(data); 302 303 /* 304 ** If it's zero, the isa irq number is unknown, 305 ** and we cannot bind the pci interrupt to isa. 306 */ 307 308 if (irq) 309 printf (" irq %d", irq); 310 else 311 printf (" not bound"); 312 }; 313 314 /* 315 ** enable memory access 316 */ 317 318 data = (pci_conf_read (tag, PCI_COMMAND_STATUS_REG) 319 & 0xffff) | PCI_COMMAND_MEM_ENABLE; 320 321 pci_conf_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data); 322 323 /* 324 ** show pci slot. 325 */ 326 327 printf (" on pci%d:%d\n", bus, device); 328 329 #ifdef __FreeBSD2__ 330 331 /* 332 ** Allocate a devconf structure 333 */ 334 335 pdcp = (struct pci_devconf *) 336 malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK); 337 338 /* 339 ** Fill in. 340 ** 341 ** Sorry, this is not yet complete. 342 ** We should, and eventually will, set the 343 ** parent pointer to a pci bus devconf structure, 344 ** and arrange to set the state field dynamically. 345 ** 346 ** But I'll go to vacation today, and after all, 347 ** wasn't there a new feature freeze on Oct 1.? 348 */ 349 350 pdcp -> pdc_pi.pi_bus = bus; 351 pdcp -> pdc_pi.pi_device = device; 352 353 pdcp -> pdc_kdc.kdc_name = dvp->pd_name; 354 pdcp -> pdc_kdc.kdc_unit = unit; 355 356 pdcp -> pdc_kdc.kdc_md.mddc_devtype = MDDT_PCI; 357 358 pdcp -> pdc_kdc.kdc_externalize = pci_externalize; 359 pdcp -> pdc_kdc.kdc_internalize = pci_internalize; 360 361 pdcp -> pdc_kdc.kdc_datalen = PCI_EXTERNAL_LEN; 362 pdcp -> pdc_kdc.kdc_parentdata = &pdcp->pdc_pi; 363 pdcp -> pdc_kdc.kdc_state = DC_UNKNOWN; 364 pdcp -> pdc_kdc.kdc_description = name; 365 366 /* 367 ** And register this device 368 */ 369 370 dev_attach (&pdcp->pdc_kdc); 371 372 #endif /* __FreeBSD2__ */ 373 374 375 /* 376 ** attach device 377 ** may produce additional log messages, 378 ** i.e. when installing subdevices. 379 */ 380 381 (*drp->attach) (tag, unit); 382 }; 383 }; 384 385 #ifndef PCI_QUIET 386 if (pci_paddr != old_addr) 387 printf ("pci uses physical addresses from 0x%lx to 0x%lx\n", 388 (u_long)PCI_PMEM_START, (u_long)pci_paddr); 389 #endif 390 pci_conf_count++; 391 } 392 393 /*----------------------------------------------------------------------- 394 ** 395 ** Map device into port space. 396 ** 397 ** PCI-Specification: 6.2.5.1: address maps 398 ** 399 **----------------------------------------------------------------------- 400 */ 401 402 int pci_map_port (pcici_t tag, u_long reg, u_short* pa) 403 { 404 /* 405 ** @MAPIO@ not yet implemented. 406 */ 407 printf ("pci_map_port failed: not yet implemented\n"); 408 return (0); 409 } 410 411 /*----------------------------------------------------------------------- 412 ** 413 ** Map device into virtual and physical space 414 ** 415 ** PCI-Specification: 6.2.5.1: address maps 416 ** 417 **----------------------------------------------------------------------- 418 */ 419 420 int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) 421 { 422 u_long data; 423 vm_size_t vsize; 424 vm_offset_t vaddr; 425 426 /* 427 ** sanity check 428 */ 429 430 if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { 431 printf ("pci_map_mem failed: bad register=0x%x\n", 432 (unsigned)reg); 433 return (0); 434 }; 435 436 /* 437 ** get size and type of memory 438 ** 439 ** type is in the lowest four bits. 440 ** If device requires 2^n bytes, the next 441 ** n-4 bits are read as 0. 442 */ 443 444 pci_conf_write (tag, reg, 0xfffffffful); 445 data = pci_conf_read (tag, reg); 446 447 switch (data & 0x0f) { 448 449 case PCI_MAP_MEMORY_TYPE_32BIT: /* 32 bit non cachable */ 450 break; 451 452 default: /* unknown */ 453 printf ("pci_map_mem failed: bad memory type=0x%x\n", 454 (unsigned) data); 455 return (0); 456 }; 457 458 /* 459 ** mask out the type, 460 ** and round up to a page size 461 */ 462 463 vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK)); 464 465 if (!vsize) return (0); 466 467 /* 468 ** align physical address to virtual size 469 */ 470 471 if ((data = pci_paddr % vsize)) 472 pci_paddr += vsize - data; 473 474 vaddr = (vm_offset_t) pmap_mapdev (pci_paddr, vsize); 475 476 477 if (!vaddr) return (0); 478 479 #ifndef PCI_QUIET 480 /* 481 ** display values. 482 */ 483 484 printf ("\treg%d: virtual=0x%lx physical=0x%lx\n", 485 (unsigned) reg, (u_long)vaddr, (u_long)pci_paddr); 486 #endif 487 488 /* 489 ** return them to the driver 490 */ 491 492 *va = vaddr; 493 *pa = pci_paddr; 494 495 /* 496 ** set device address 497 */ 498 499 pci_conf_write (tag, reg, pci_paddr); 500 501 /* 502 ** and don't forget to increment pci_paddr 503 */ 504 505 pci_paddr += vsize; 506 507 return (1); 508 } 509 510 /*------------------------------------------------------------ 511 ** 512 ** Interface functions for the devconf module. 513 ** 514 **------------------------------------------------------------ 515 */ 516 517 static int 518 pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l) 519 { 520 struct pci_externalize_buffer buffer; 521 struct pci_info * pip = kdcp->kdc_parentdata; 522 pcici_t tag; 523 int i; 524 525 if (l < sizeof buffer) { 526 return ENOMEM; 527 }; 528 529 tag = pcitag (pip->pi_bus, pip->pi_device, 0); 530 531 buffer.peb_pci_info = *pip; 532 533 for (i=0; i<PCI_EXT_CONF_LEN; i++) { 534 buffer.peb_config[i] = pci_conf_read (tag, i*4); 535 }; 536 537 return copyout(&buffer, u, sizeof buffer); 538 } 539 540 541 static int 542 pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s) 543 { 544 return EOPNOTSUPP; 545 } 546 547 /*----------------------------------------------------------------------- 548 ** 549 ** Map pci interrupts to isa interrupts. 550 ** 551 **----------------------------------------------------------------------- 552 */ 553 554 static unsigned int pci_int_mask [16]; 555 556 int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr) 557 { 558 int irq; 559 unsigned mask; 560 561 irq = PCI_INTERRUPT_LINE_EXTRACT( 562 pci_conf_read (tag, PCI_INTERRUPT_REG)); 563 564 if (irq >= 16 || irq <= 0) { 565 printf ("pci_map_int failed: no int line set.\n"); 566 return (0); 567 } 568 569 mask = 1ul << irq; 570 571 if (!maskptr) 572 maskptr = &pci_int_mask[irq]; 573 574 INTRMASK (*maskptr, mask); 575 576 register_intr( 577 irq, /* isa irq */ 578 0, /* deviced?? */ 579 0, /* flags? */ 580 (inthand2_t*) func, /* handler */ 581 maskptr, /* mask pointer */ 582 (int) arg); /* handler arg */ 583 584 #ifdef __FreeBSD2__ 585 /* 586 ** XXX See comment at beginning of file. 587 ** 588 ** Have to update all the interrupt masks ... Grrrrr!!! 589 */ 590 { 591 unsigned * mp = &intr_mask[0]; 592 /* 593 ** update the isa interrupt masks. 594 */ 595 for (mp=&intr_mask[0]; mp<&intr_mask[ICU_LEN]; mp++) 596 if (*mp & *maskptr) 597 *mp |= mask; 598 /* 599 ** update the pci interrupt masks. 600 */ 601 for (mp=&pci_int_mask[0]; mp<&pci_int_mask[16]; mp++) 602 if (*mp & *maskptr) 603 *mp |= mask; 604 }; 605 #endif 606 607 INTREN (mask); 608 609 return (1); 610 } 611 612 /*----------------------------------------------------------- 613 ** 614 ** Display of unknown devices. 615 ** 616 **----------------------------------------------------------- 617 */ 618 struct vt { 619 u_short ident; 620 char* name; 621 }; 622 623 static struct vt VendorTable[] = { 624 {0x1002, "ATI TECHNOLOGIES INC"}, 625 {0x1011, "DIGITAL EQUIPMENT CORPORATION"}, 626 {0x101A, "NCR"}, 627 {0x102B, "MATROX"}, 628 {0x1045, "OPTI"}, 629 {0x5333, "S3 INC."}, 630 {0x8086, "INTEL CORPORATION"}, 631 {0,0} 632 }; 633 634 static const char *const majclasses[] = { 635 "old", "storage", "network", "display", 636 "multimedia", "memory", "bridge" 637 }; 638 639 void not_supported (pcici_t tag, u_long type) 640 { 641 u_char reg; 642 u_long data; 643 struct vt * vp; 644 645 /* 646 ** lookup the names. 647 */ 648 649 for (vp=VendorTable; vp->ident; vp++) 650 if (vp->ident == (type & 0xffff)) 651 break; 652 653 /* 654 ** and display them. 655 */ 656 657 if (vp->ident) printf (vp->name); 658 else printf ("vendor=0x%lx", type & 0xffff); 659 660 printf (", device=0x%lx", type >> 16); 661 662 data = (pci_conf_read(tag, PCI_CLASS_REG) >> 24) & 0xff; 663 if (data < sizeof(majclasses) / sizeof(majclasses[0])) 664 printf(", class=%s", majclasses[data]); 665 666 printf (" [not supported]\n"); 667 668 for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) { 669 data = pci_conf_read (tag, reg); 670 if (!data) continue; 671 switch (data&7) { 672 673 case 1: 674 case 5: 675 printf (" map(%x): io(%lx)\n", 676 reg, data & ~3); 677 break; 678 case 0: 679 printf (" map(%x): mem32(%lx)\n", 680 reg, data & ~7); 681 break; 682 case 2: 683 printf (" map(%x): mem20(%lx)\n", 684 reg, data & ~7); 685 break; 686 case 4: 687 printf (" map(%x): mem64(%lx)\n", 688 reg, data & ~7); 689 break; 690 } 691 } 692 } 693 694 #ifndef __FreeBSD2__ 695 /*----------------------------------------------------------- 696 ** 697 ** Mapping of physical to virtual memory 698 ** 699 **----------------------------------------------------------- 700 */ 701 702 extern vm_map_t kernel_map; 703 704 static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize) 705 { 706 vm_offset_t vaddr,value; 707 u_long result; 708 709 vaddr = vm_map_min (kernel_map); 710 711 result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0, 712 &vaddr, vsize, TRUE); 713 714 if (result != KERN_SUCCESS) { 715 printf (" vm_map_find failed(%d)\n", result); 716 return (0); 717 }; 718 719 /* 720 ** map physical 721 */ 722 723 value = vaddr; 724 while (vsize >= NBPG) { 725 pmap_enter (pmap_kernel(), vaddr, paddr, 726 VM_PROT_READ|VM_PROT_WRITE, TRUE); 727 vaddr += NBPG; 728 paddr += NBPG; 729 vsize -= NBPG; 730 }; 731 return (value); 732 } 733 734 /*------------------------------------------------------------ 735 ** 736 ** Emulate the register_intr() function of FreeBSD 2.0 737 ** 738 ** requires a patch: 739 ** FreeBSD 2.0: "/sys/i386/isa/vector.s" 740 ** 386bsd0.1: "/sys/i386/isa/icu.s" 741 ** 386bsd1.0: Please ask Jesus Monroy Jr. 742 ** 743 **------------------------------------------------------------ 744 */ 745 746 #include <machine/segments.h> 747 748 int pci_int_unit [16]; 749 inthand2_t* (pci_int_hdlr [16]); 750 unsigned int * pci_int_mptr [16]; 751 unsigned int pci_int_count[16]; 752 753 extern void 754 Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(), 755 Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15(); 756 757 static inthand_t* pci_int_glue[16] = { 758 0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8, 759 Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 }; 760 761 static int 762 register_intr __P((int intr, int device_id, unsigned int flags, 763 inthand2_t *handler, unsigned int* mptr, int unit)) 764 { 765 if (intr >= 16 || intr <= 2) 766 return (EINVAL); 767 if (pci_int_hdlr [intr]) 768 return (EBUSY); 769 770 pci_int_hdlr [intr] = handler; 771 pci_int_unit [intr] = unit; 772 pci_int_mptr [intr] = mptr; 773 774 setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL); 775 return (0); 776 } 777 #endif /* __FreeBSD2__ */ 778 #endif /* NPCI */ 779