pci.c revision 6131
1/************************************************************************** 2** 3** $Id: pci.c,v 1.9 1994/11/02 23:47:13 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 <pci/pcireg.h> 67 68#ifdef __FreeBSD2__ 69#include <sys/devconf.h> 70 71struct 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__ 82extern pmap_t pmap_kernel(void); 83static 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 */ 88typedef 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 */ 95typedef 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 109static int 110register_intr __P((int intr, int device_id, unsigned int flags, 111 inthand2_t *handler, unsigned int * mptr, int unit)); 112extern 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 139static 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 154static 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 169static void not_supported (pcici_t tag, u_long type); 170 171static unsigned long pci_seen[NPCI]; 172 173static int pci_conf_count; 174 175#ifdef __FreeBSD2__ 176static int 177pci_externalize (struct proc *, struct kern_devconf *, void *, size_t); 178 179static int 180pci_internalize (struct proc *, struct kern_devconf *, void *, size_t); 181 182#endif /* __FreeBSD2__ */ 183 184void 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 402int 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 420int 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 517static int 518pci_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 541static int 542pci_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 554static unsigned int pci_int_mask [16]; 555 556int 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*/ 618struct vt { 619 u_short ident; 620 char* name; 621}; 622 623static 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 634static const char *const majclasses[] = { 635 "old", "storage", "network", "display", 636 "multimedia", "memory", "bridge" 637}; 638 639void 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 702extern vm_map_t kernel_map; 703 704static 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 748int pci_int_unit [16]; 749inthand2_t* (pci_int_hdlr [16]); 750unsigned int * pci_int_mptr [16]; 751unsigned int pci_int_count[16]; 752 753extern void 754 Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(), 755 Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15(); 756 757static 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 761static int 762register_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