pci.c revision 2435
1/************************************************************************** 2** 3** $Id: pci.c,v 2.0.0.8 94/08/21 19:57:39 wolf 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** $Log: pci.c,v $ 39** Revision 2.0.0.8 94/08/21 19:57:39 wolf 40** Unneeded declarations removed (FreeBSD2.0) 41** 42** Revision 2.0.0.7 94/08/21 19:25:54 wolf 43** pci_intr simplified. 44** new not_supported() function. 45** Vendor and device ids moved into tables. 46** 47** Revision 2.0.0.6 94/08/18 22:58:23 wolf 48** Symbolic names for pci configuration space registers. 49** last_device: from configuration mode 50** last_bus: from pcibios. 51** PCI_MAX_DPI: changed to 4 (settable by config) 52** interrupt configuration by line or pin 53** 54** Revision 2.0.0.5 94/08/11 19:04:10 wolf 55** display of interrupt line configuration register. 56** 57** Revision 2.0.0.4 94/08/01 20:36:28 wolf 58** Tiny clean up. 59** 60** Revision 2.0.0.3 94/08/01 18:52:33 wolf 61** New vendor entry: S3. 62** Scan pci busses #0..#255 as default. 63** Number of scanned busses and devices settable as option. 64** Show these numbers before starting the scan. 65** 66** Revision 2.0.0.2 94/07/27 09:27:19 wolf 67** New option PCI_QUIET: suppress log messages. 68** 69** Revision 2.0.0.1 94/07/19 19:06:44 wolf 70** New vendor entry: MATROX 71** 72** Revision 2.0 94/07/10 15:53:29 wolf 73** FreeBSD release. 74** 75** Revision 1.0 94/06/07 20:02:19 wolf 76** Beta release. 77** 78*************************************************************************** 79*/ 80 81#include <pci.h> 82#if NPCI > 0 83 84/*======================================================== 85** 86** Configuration 87** 88**======================================================== 89*/ 90 91/* 92** maximum number of devices which share one interrupt line 93*/ 94 95#ifndef PCI_MAX_DPI 96#define PCI_MAX_DPI (4) 97#endif /*PCI_MAX_DPI*/ 98 99 100/*======================================================== 101** 102** #includes and declarations 103** 104**======================================================== 105*/ 106 107#include <types.h> 108#include <cdefs.h> 109#include <errno.h> 110#include <param.h> 111 112#include <vm/vm.h> 113#include <vm/vm_param.h> 114 115#include <i386/isa/icu.h> 116#include <i386/isa/isa.h> 117#include <i386/isa/isa_device.h> 118 119#include <i386/pci/pci.h> 120#include <i386/pci/pci_device.h> 121#include <i386/pci/pcibios.h> 122 123 124char ident_pci_c[] = 125 "\n$Id: pci.c,v 2.0.0.8 94/08/21 19:57:39 wolf Exp $\n" 126 "Copyright (c) 1994, Wolfgang Stanglmeier\n"; 127 128/* 129** Function prototypes missing in system headers 130*/ 131 132extern int printf(); 133extern int ffs(); 134#if ! (__FreeBSD__ >= 2) 135extern pmap_t pmap_kernel(void); 136#endif 137 138 139/*======================================================== 140** 141** Autoconfiguration (of isa bus) 142** 143**======================================================== 144*/ 145 146/* 147** per device (interrupt) data structure. 148*/ 149 150static struct { 151 u_short number; 152 u_short isanum; 153 struct { 154 int (*proc)(int dev); 155 dev_t unit; 156 } vector[PCI_MAX_DPI]; 157} pcidata [NPCI]; 158 159/* 160** check device ready 161*/ 162static int pciprobe (struct isa_device *dev) 163{ 164 if (dev->id_unit >= NPCI) 165 return (0); 166 167 if (!pci_conf_mode()) 168 return (0); 169 170 return (-1); 171} 172 173/* 174** initialize the driver structure 175*/ 176static int pciattach (struct isa_device *isdp) 177{ 178 pcidata[isdp->id_unit].number = 0; 179 pcidata[isdp->id_unit].isanum = ffs(isdp->id_irq)-1; 180 return (1); 181} 182 183/* 184** ISA driver structure 185*/ 186 187struct isa_driver pcidriver = { 188 pciprobe, 189 pciattach, 190 "pci" 191}; 192 193/*======================================================== 194** 195** Interrupt forward from isa to pci devices. 196** 197**======================================================== 198*/ 199 200 201void pciintr (int unit) 202{ 203 u_short i; 204 if (unit >= NPCI) return; 205 for (i=0; i<pcidata[unit].number; i++) { 206 (void)(*pcidata[unit].vector[i].proc)(pcidata[unit].vector[i].unit); 207 }; 208} 209 210 211/*======================================================== 212** 213** Autoconfiguration of pci devices. 214** 215** This is reverse to the isa configuration. 216** (1) find a pci device. 217** (2) look for a driver. 218** 219**======================================================== 220*/ 221 222/*-------------------------------------------------------- 223** 224** The pci devices can be mapped to any address. 225** As default we start at the last gigabyte. 226** 227**-------------------------------------------------------- 228*/ 229 230#ifndef PCI_PMEM_START 231#define PCI_PMEM_START 0xc0000000 232#endif 233 234static vm_offset_t pci_paddr = PCI_PMEM_START; 235 236/*--------------------------------------------------------- 237** 238** pci_configure () 239** 240**--------------------------------------------------------- 241*/ 242 243static void not_supported (pcici_t tag, u_long type); 244 245void pci_configure() 246{ 247 u_char device,last_device; 248 u_short bus,last_bus; 249 pcici_t tag; 250 pcidi_t type; 251 u_long data; 252 int unit; 253 int intpin; 254 int isanum; 255 int pci_mode; 256 257 struct pci_driver *drp; 258 struct pci_device *dvp; 259 260 /* 261 ** check pci bus present 262 */ 263 264 pci_mode = pci_conf_mode (); 265 if (!pci_mode) return; 266 last_bus = pci_last_bus (); 267 last_device = pci_mode==1 ? 31 : 15; 268 269 /* 270 ** hello world .. 271 */ 272 273#ifndef PCI_QUIET 274 printf ("PCI configuration mode %d.\n", pci_mode); 275 printf ("Scanning device 0..%d on pci bus 0..%d " 276 "($Revision: 2.0.0.8 $)\n", 277 last_device, last_bus); 278#endif 279 280 for (bus=0;bus<=last_bus; bus++) 281 for (device=0; device<=last_device; device ++) { 282 tag = pcitag (bus, device, 0); 283 type = pci_conf_read (tag, PCI_ID_REG); 284 285 if ((!type) || (type==0xfffffffful)) continue; 286 287 /* 288 ** lookup device in ioconfiguration: 289 */ 290 291 for (dvp = pci_devtab; drp=dvp->pd_driver; dvp++) { 292 if (drp->device_id == type) break; 293 }; 294 295#ifdef PCI_QUIET 296 if (!drp) continue; 297#endif 298 printf ("on pci%d:%d ", bus, device); 299#ifndef PCI_QUIET 300 if (!drp) { 301 not_supported (tag, type); 302 continue; 303 }; 304#endif 305 306 /* 307 ** found it. 308 ** probe returns the device unit. 309 */ 310 311 printf ("<%s>", drp -> vendor); 312 313 unit = (*drp->probe) (tag); 314 315 if (unit<0) { 316 printf (" probe failed.\n"); 317 continue; 318 }; 319 320 /* 321 ** install interrupts 322 */ 323 324 data = pci_conf_read (tag, PCI_INTERRUPT_REG); 325 intpin = PCI_INTERRUPT_PIN_EXTRACT(data); 326 if (intpin) { 327 int idx=NPCI; 328 329 /* 330 ** Usage of int line register (if set by bios) 331 ** Matt Thomas <thomas@lkg.dec.com> 332 */ 333 334 isanum = PCI_INTERRUPT_LINE_EXTRACT(data); 335 if (isanum) { 336 printf (" il=%d", isanum); 337 for (idx = 0; idx < NPCI; idx++) { 338 if (pcidata[idx].isanum == isanum) 339 break; 340 }; 341 }; 342 343 /* 344 ** Or believe to the interrupt pin register. 345 */ 346 347 if (idx >= NPCI) idx = intpin-1; 348 349 /* 350 ** And install the interrupt. 351 */ 352 353 if (idx<NPCI) { 354 u_short entry = pcidata[idx].number; 355 printf (" irq %c", 0x60+intpin); 356 if (entry < PCI_MAX_DPI) { 357 pcidata[idx].vector[entry].proc = drp->intr; 358 pcidata[idx].vector[entry].unit = unit; 359 entry++; 360 }; 361 printf (" isa=%d [%d]",pcidata[idx].isanum, entry); 362 pcidata[idx].number=entry; 363 } else { 364 printf (" not installed"); 365 }; 366 }; 367 368 /* 369 ** enable memory access 370 */ 371 data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) 372 & 0xffff | PCI_COMMAND_MEM_ENABLE; 373 pci_conf_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data); 374 375 /* 376 ** attach device 377 ** may produce additional log messages, 378 ** i.e. when installing subdevices. 379 */ 380 381 printf (" as %s%d\n", drp->name,unit); 382 (void) (*drp->attach) (tag); 383 384 }; 385 386 printf ("pci uses physical addresses from %x to %x\n", 387 PCI_PMEM_START, pci_paddr); 388} 389 390/*----------------------------------------------------------------------- 391** 392** Map device into port space. 393** 394** PCI-Specification: 6.2.5.1: address maps 395** 396**----------------------------------------------------------------------- 397*/ 398 399extern vm_map_t kernel_map; 400 401int pci_map_port (pcici_t tag, u_long reg, u_short* pa) 402{ 403 /* 404 ** @MAPIO@ not yet implemented. 405 */ 406 return (ENOSYS); 407} 408 409/*----------------------------------------------------------------------- 410** 411** Map device into virtual and physical space 412** 413** PCI-Specification: 6.2.5.1: address maps 414** 415**----------------------------------------------------------------------- 416*/ 417 418int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) 419{ 420 u_long data, result; 421 vm_size_t vsize; 422 vm_offset_t vaddr; 423 424 /* 425 ** sanity check 426 */ 427 428 if (reg <= PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) 429 return (EINVAL); 430 431 /* 432 ** get size and type of memory 433 ** 434 ** type is in the lowest four bits. 435 ** If device requires 2^n bytes, the next 436 ** n-4 bits are read as 0. 437 */ 438 439 pci_conf_write (tag, reg, 0xfffffffful); 440 data = pci_conf_read (tag, reg); 441 442 switch (data & 0x0f) { 443 444 case PCI_MAP_MEMORY_TYPE_32BIT: /* 32 bit non cachable */ 445 break; 446 447 default: /* unknown */ 448 return (EINVAL); 449 }; 450 451 /* 452 ** mask out the type, 453 ** and round up to a page size 454 */ 455 456 vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK)); 457 458 printf (" memory size=0x%x", vsize); 459 460 if (!vsize) return (EINVAL); 461 462 /* 463 ** try to map device to virtual space 464 */ 465 466 vaddr = vm_map_min (kernel_map); 467 468 result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0, 469 &vaddr, vsize, TRUE); 470 471 if (result != KERN_SUCCESS) { 472 printf (" vm_map_find failed(%d)\n", result); 473 return (ENOMEM); 474 }; 475 476 /* 477 ** align physical address to virtual size 478 */ 479 480 if (data = pci_paddr % vsize) 481 pci_paddr += vsize - data; 482 483 /* 484 ** display values. 485 */ 486 487 printf (" virtual=0x%x physical=0x%x\n", vaddr, pci_paddr); 488 489 /* 490 ** return them to the driver 491 */ 492 493 *va = vaddr; 494 *pa = pci_paddr; 495 496 /* 497 ** set device address 498 */ 499 500 pci_conf_write (tag, reg, pci_paddr); 501 502 /* 503 ** map physical 504 */ 505 506 while (vsize >= NBPG) { 507 pmap_enter (pmap_kernel(), vaddr, pci_paddr, 508 VM_PROT_READ|VM_PROT_WRITE, TRUE); 509 vaddr += NBPG; 510 pci_paddr += NBPG; 511 vsize -= NBPG; 512 }; 513 514 return (0); 515} 516 517struct vt { 518 u_short ident; 519 char* name; 520}; 521 522struct dt { 523 u_long ident; 524 char* name; 525}; 526 527static struct vt VendorTable[] = { 528 {0x1002, "ATI TECHNOLOGIES INC"}, 529 {0x1011, "DIGITAL EQUIPMENT COMPANY"}, 530 {0x101A, "NCR"}, 531 {0x102B, "MATROX"}, 532 {0x1045, "OPTI"}, 533 {0x5333, "S3 INC."}, 534 {0x8086, "INTEL CORPORATION"}, 535 {0,0} 536}; 537 538static struct dt DeviceTable[] = { 539 {0x04848086, " 82378IB pci-isa bridge"}, 540 {0x04838086, " 82424ZX cache dram controller"}, 541 {0x04828086, " 82375EB pci-eisa bridge"}, 542 {0x04A38086, " 82434LX pci cache memory controller"}, 543 {0,0} 544}; 545 546void not_supported (pcici_t tag, u_long type) 547{ 548 u_char reg; 549 u_long data; 550 struct vt * vp; 551 struct dt * dp; 552 553 /* 554 ** lookup the names. 555 */ 556 557 for (vp=VendorTable; vp->ident; vp++) 558 if (vp->ident == (type & 0xffff)) 559 break; 560 561 for (dp=DeviceTable; dp->ident; dp++) 562 if (dp->ident == type) 563 break; 564 565 /* 566 ** and display them. 567 */ 568 569 if (vp->ident) printf (vp->name); 570 else printf ("vendor=%x", type & 0xffff); 571 572 if (dp->ident) printf (dp->name); 573 else printf (", device=%x", type >> 16); 574 575 printf (" [not supported]\n"); 576 577 for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) { 578 data = pci_conf_read (tag, reg); 579 if (!data) continue; 580 switch (data&7) { 581 582 case 1: 583 case 5: 584 printf (" map(%x): io(%x)\n", reg, data & ~3); 585 break; 586 case 0: 587 printf (" map(%x): mem32(%x)\n", reg, data & ~7); 588 break; 589 case 2: 590 printf (" map(%x): mem20(%x)\n", reg, data & ~7); 591 break; 592 case 4: 593 printf (" map(%x): mem64(%x)\n", reg, data & ~7); 594 break; 595 }; 596 }; 597} 598#endif 599