1/* 2 * Code to deal with the PReP residual data. 3 * 4 * Written by: Cort Dougan (cort@cs.nmt.edu) 5 * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es) 6 * 7 * This file is based on the following documentation: 8 * 9 * IBM Power Personal Systems Architecture 10 * Residual Data 11 * Document Number: PPS-AR-FW0001 12 * 13 * This file is subject to the terms and conditions of the GNU General Public 14 * License. See the file COPYING in the main directory of this archive 15 * for more details. 16 * 17 */ 18 19#include <linux/string.h> 20#include <asm/residual.h> 21#include <asm/pnp.h> 22#include <asm/byteorder.h> 23 24#include <linux/errno.h> 25#include <linux/sched.h> 26#include <linux/kernel.h> 27#include <linux/mm.h> 28#include <linux/stddef.h> 29#include <linux/unistd.h> 30#include <linux/ptrace.h> 31#include <linux/slab.h> 32#include <linux/user.h> 33#include <linux/a.out.h> 34#include <linux/tty.h> 35#include <linux/major.h> 36#include <linux/interrupt.h> 37#include <linux/reboot.h> 38#include <linux/init.h> 39#include <linux/ioport.h> 40#include <linux/pci.h> 41#include <linux/ide.h> 42 43#include <asm/sections.h> 44#include <asm/mmu.h> 45#include <asm/io.h> 46#include <asm/pgtable.h> 47#include <asm/ide.h> 48 49 50unsigned char __res[sizeof(RESIDUAL)] = {0,}; 51RESIDUAL *res = (RESIDUAL *)&__res; 52 53char * PnP_BASE_TYPES[] __initdata = { 54 "Reserved", 55 "MassStorageDevice", 56 "NetworkInterfaceController", 57 "DisplayController", 58 "MultimediaController", 59 "MemoryController", 60 "BridgeController", 61 "CommunicationsDevice", 62 "SystemPeripheral", 63 "InputDevice", 64 "ServiceProcessor" 65 }; 66 67/* Device Sub Type Codes */ 68 69unsigned char * PnP_SUB_TYPES[] __initdata = { 70 "\001\000SCSIController", 71 "\001\001IDEController", 72 "\001\002FloppyController", 73 "\001\003IPIController", 74 "\001\200OtherMassStorageController", 75 "\002\000EthernetController", 76 "\002\001TokenRingController", 77 "\002\002FDDIController", 78 "\002\0x80OtherNetworkController", 79 "\003\000VGAController", 80 "\003\001SVGAController", 81 "\003\002XGAController", 82 "\003\200OtherDisplayController", 83 "\004\000VideoController", 84 "\004\001AudioController", 85 "\004\200OtherMultimediaController", 86 "\005\000RAM", 87 "\005\001FLASH", 88 "\005\200OtherMemoryDevice", 89 "\006\000HostProcessorBridge", 90 "\006\001ISABridge", 91 "\006\002EISABridge", 92 "\006\003MicroChannelBridge", 93 "\006\004PCIBridge", 94 "\006\005PCMCIABridge", 95 "\006\006VMEBridge", 96 "\006\200OtherBridgeDevice", 97 "\007\000RS232Device", 98 "\007\001ATCompatibleParallelPort", 99 "\007\200OtherCommunicationsDevice", 100 "\010\000ProgrammableInterruptController", 101 "\010\001DMAController", 102 "\010\002SystemTimer", 103 "\010\003RealTimeClock", 104 "\010\004L2Cache", 105 "\010\005NVRAM", 106 "\010\006PowerManagement", 107 "\010\007CMOS", 108 "\010\010OperatorPanel", 109 "\010\011ServiceProcessorClass1", 110 "\010\012ServiceProcessorClass2", 111 "\010\013ServiceProcessorClass3", 112 "\010\014GraphicAssist", 113 "\010\017SystemPlanar", 114 "\010\200OtherSystemPeripheral", 115 "\011\000KeyboardController", 116 "\011\001Digitizer", 117 "\011\002MouseController", 118 "\011\003TabletController", 119 "\011\0x80OtherInputController", 120 "\012\000GeneralMemoryController", 121 NULL 122}; 123 124/* Device Interface Type Codes */ 125 126unsigned char * PnP_INTERFACES[] __initdata = { 127 "\000\000\000General", 128 "\001\000\000GeneralSCSI", 129 "\001\001\000GeneralIDE", 130 "\001\001\001ATACompatible", 131 132 "\001\002\000GeneralFloppy", 133 "\001\002\001Compatible765", 134 "\001\002\002NS398_Floppy", /* NS Super I/O wired to use index 135 register at port 398 and data 136 register at port 399 */ 137 "\001\002\003NS26E_Floppy", /* Ports 26E and 26F */ 138 "\001\002\004NS15C_Floppy", /* Ports 15C and 15D */ 139 "\001\002\005NS2E_Floppy", /* Ports 2E and 2F */ 140 "\001\002\006CHRP_Floppy", /* CHRP Floppy in PR*P system */ 141 142 "\001\003\000GeneralIPI", 143 144 "\002\000\000GeneralEther", 145 "\002\001\000GeneralToken", 146 "\002\002\000GeneralFDDI", 147 148 "\003\000\000GeneralVGA", 149 "\003\001\000GeneralSVGA", 150 "\003\002\000GeneralXGA", 151 152 "\004\000\000GeneralVideo", 153 "\004\001\000GeneralAudio", 154 "\004\001\001CS4232Audio", /* CS 4232 Plug 'n Play Configured */ 155 156 "\005\000\000GeneralRAM", 157 /* This one is obviously wrong ! */ 158 "\005\000\000PCIMemoryController", /* PCI Config Method */ 159 "\005\000\001RS6KMemoryController", /* RS6K Config Method */ 160 "\005\001\000GeneralFLASH", 161 162 "\006\000\000GeneralHostBridge", 163 "\006\001\000GeneralISABridge", 164 "\006\002\000GeneralEISABridge", 165 "\006\003\000GeneralMCABridge", 166 /* GeneralPCIBridge = 0, */ 167 "\006\004\000PCIBridgeDirect", 168 "\006\004\001PCIBridgeIndirect", 169 "\006\004\002PCIBridgeRS6K", 170 "\006\005\000GeneralPCMCIABridge", 171 "\006\006\000GeneralVMEBridge", 172 173 "\007\000\000GeneralRS232", 174 "\007\000\001COMx", 175 "\007\000\002Compatible16450", 176 "\007\000\003Compatible16550", 177 "\007\000\004NS398SerPort", /* NS Super I/O wired to use index 178 register at port 398 and data 179 register at port 399 */ 180 "\007\000\005NS26ESerPort", /* Ports 26E and 26F */ 181 "\007\000\006NS15CSerPort", /* Ports 15C and 15D */ 182 "\007\000\007NS2ESerPort", /* Ports 2E and 2F */ 183 184 "\007\001\000GeneralParPort", 185 "\007\001\001LPTx", 186 "\007\001\002NS398ParPort", /* NS Super I/O wired to use index 187 register at port 398 and data 188 register at port 399 */ 189 "\007\001\003NS26EParPort", /* Ports 26E and 26F */ 190 "\007\001\004NS15CParPort", /* Ports 15C and 15D */ 191 "\007\001\005NS2EParPort", /* Ports 2E and 2F */ 192 193 "\010\000\000GeneralPIC", 194 "\010\000\001ISA_PIC", 195 "\010\000\002EISA_PIC", 196 "\010\000\003MPIC", 197 "\010\000\004RS6K_PIC", 198 199 "\010\001\000GeneralDMA", 200 "\010\001\001ISA_DMA", 201 "\010\001\002EISA_DMA", 202 203 "\010\002\000GeneralTimer", 204 "\010\002\001ISA_Timer", 205 "\010\002\002EISA_Timer", 206 "\010\003\000GeneralRTC", 207 "\010\003\001ISA_RTC", 208 209 "\010\004\001StoreThruOnly", 210 "\010\004\002StoreInEnabled", 211 "\010\004\003RS6KL2Cache", 212 213 "\010\005\000IndirectNVRAM", /* Indirectly addressed */ 214 "\010\005\001DirectNVRAM", /* Memory Mapped */ 215 "\010\005\002IndirectNVRAM24", /* Indirectly addressed - 24 bit */ 216 217 "\010\006\000GeneralPowerManagement", 218 "\010\006\001EPOWPowerManagement", 219 "\010\006\002PowerControl", // d1378 220 221 "\010\007\000GeneralCMOS", 222 223 "\010\010\000GeneralOPPanel", 224 "\010\010\001HarddiskLight", 225 "\010\010\002CDROMLight", 226 "\010\010\003PowerLight", 227 "\010\010\004KeyLock", 228 "\010\010\005ANDisplay", /* AlphaNumeric Display */ 229 "\010\010\006SystemStatusLED", /* 3 digit 7 segment LED */ 230 "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system */ 231 232 "\010\011\000GeneralServiceProcessor", 233 "\010\012\000GeneralServiceProcessor", 234 "\010\013\000GeneralServiceProcessor", 235 236 "\010\014\001TransferData", 237 "\010\014\002IGMC32", 238 "\010\014\003IGMC64", 239 240 "\010\017\000GeneralSystemPlanar", /* 10/5/95 */ 241 NULL 242 }; 243 244static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, 245 unsigned char SubType) { 246 unsigned char ** s=PnP_SUB_TYPES; 247 while (*s && !((*s)[0]==BaseType 248 && (*s)[1]==SubType)) s++; 249 if (*s) return *s+2; 250 else return("Unknown !"); 251}; 252 253static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, 254 unsigned char SubType, 255 unsigned char Interface) { 256 unsigned char ** s=PnP_INTERFACES; 257 while (*s && !((*s)[0]==BaseType 258 && (*s)[1]==SubType 259 && (*s)[2]==Interface)) s++; 260 if (*s) return *s+3; 261 else return NULL; 262}; 263 264static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) { 265 int i, c; 266 char decomp[4]; 267#define p pkt->S14_Pack.S14_Data.S14_PPCPack 268 switch(p.Type) { 269 case 1: 270 /* Decompress first 3 chars */ 271 c = *(unsigned short *)p.PPCData; 272 decomp[0]='A'-1+((c>>10)&0x1F); 273 decomp[1]='A'-1+((c>>5)&0x1F); 274 decomp[2]='A'-1+(c&0x1F); 275 decomp[3]=0; 276 printk(" Chip identification: %s%4.4X\n", 277 decomp, ld_le16((unsigned short *)(p.PPCData+2))); 278 break; 279 default: 280 printk(" Small vendor item type 0x%2.2x, data (hex): ", 281 p.Type); 282 for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]); 283 printk("\n"); 284 break; 285 } 286#undef p 287} 288 289static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) { 290 static const unsigned char * intlevel[] = {"high", "low"}; 291 static const unsigned char * intsense[] = {"edge", "level"}; 292 293 switch (tag_small_item_name(pkt->S1_Pack.Tag)) { 294 case PnPVersion: 295 printk(" PnPversion 0x%x.%x\n", 296 pkt->S1_Pack.Version[0], /* How to interpret version ? */ 297 pkt->S1_Pack.Version[1]); 298 break; 299// case Logicaldevice: 300 break; 301// case CompatibleDevice: 302 break; 303 case IRQFormat: 304#define p pkt->S4_Pack 305 printk(" IRQ Mask 0x%4.4x, %s %s sensitive\n", 306 ld_le16((unsigned short *)p.IRQMask), 307 intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0], 308 intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]); 309#undef p 310 break; 311 case DMAFormat: 312#define p pkt->S5_Pack 313 printk(" DMA channel mask 0x%2.2x, info 0x%2.2x\n", 314 p.DMAMask, p.DMAInfo); 315#undef p 316 break; 317 case StartDepFunc: 318 printk("Start dependent function:\n"); 319 break; 320 case EndDepFunc: 321 printk("End dependent function\n"); 322 break; 323 case IOPort: 324#define p pkt->S8_Pack 325 printk(" Variable (%d decoded bits) I/O port\n" 326 " from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n", 327 p.IOInfo&ISAAddr16bit?16:10, 328 ld_le16((unsigned short *)p.RangeMin), 329 ld_le16((unsigned short *)p.RangeMax), 330 p.IOAlign, p.IONum); 331#undef p 332 break; 333 case FixedIOPort: 334#define p pkt->S9_Pack 335 printk(" Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n", 336 (p.Range[1]<<8)|p.Range[0], 337 ((p.Range[1]<<8)|p.Range[0])+p.IONum-1); 338#undef p 339 break; 340 case Res1: 341 case Res2: 342 case Res3: 343 printk(" Undefined packet type %d!\n", 344 tag_small_item_name(pkt->S1_Pack.Tag)); 345 break; 346 case SmallVendorItem: 347 printsmallvendor(pkt,size); 348 break; 349 default: 350 printk(" Type 0x2.2x%d, size=%d\n", 351 pkt->S1_Pack.Tag, size); 352 break; 353 } 354} 355 356static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) { 357 static const unsigned char * addrtype[] = {"I/O", "Memory", "System"}; 358 static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"}; 359 static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"}; 360 static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"}; 361 static const unsigned char * L2type[] = {"WriteThru", "CopyBack"}; 362 static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"}; 363 364 int i; 365 char tmpstr[30], *t; 366#define p pkt->L4_Pack.L4_Data.L4_PPCPack 367 switch(p.Type) { 368 case 2: 369 printk(" %d K %s %s L2 cache, %d/%d bytes line/sector size\n", 370 ld_le32((unsigned int *)p.PPCData), 371 L2type[p.PPCData[10]-1], 372 L2assoc[p.PPCData[4]-1], 373 ld_le16((unsigned short *)p.PPCData+3), 374 ld_le16((unsigned short *)p.PPCData+4)); 375 break; 376 case 3: 377 printk(" PCI Bridge parameters\n" 378 " ConfigBaseAddress %0x\n" 379 " ConfigBaseData %0x\n" 380 " Bus number %d\n", 381 ld_le32((unsigned int *)p.PPCData), 382 ld_le32((unsigned int *)(p.PPCData+8)), 383 p.PPCData[16]); 384 for(i=20; i<size-4; i+=12) { 385 int j, first; 386 if(p.PPCData[i]) printk(" PCI Slot %d", p.PPCData[i]); 387 else printk (" Integrated PCI device"); 388 for(j=0, first=1, t=tmpstr; j<4; j++) { 389 int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j); 390 if(line!=0xffff){ 391 if(first) first=0; else *t++='/'; 392 *t++='A'+j; 393 } 394 } 395 *t='\0'; 396 printk(" DevFunc 0x%x interrupt line(s) %s routed to", 397 p.PPCData[i+1],tmpstr); 398 sprintf(tmpstr, 399 inttype[p.PPCData[i+2]-1], 400 p.PPCData[i+3]); 401 printk(" %s line(s) ", 402 tmpstr); 403 for(j=0, first=1, t=tmpstr; j<4; j++) { 404 int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j); 405 if(line!=0xffff){ 406 if(first) first=0; else *t++='/'; 407 t+=sprintf(t,"%d(%c)", 408 line&0x7fff, 409 line&0x8000?'E':'L'); 410 } 411 } 412 printk("%s\n",tmpstr); 413 } 414 break; 415 case 5: 416 printk(" Bridge address translation, %s decoding:\n" 417 " Processor Bus Size Conversion Translation\n" 418 " 0x%8.8x 0x%8.8x 0x%8.8x %s %s\n", 419 p.PPCData[0]&1 ? "positive" : "subtractive", 420 ld_le32((unsigned int *)p.PPCData+1), 421 ld_le32((unsigned int *)p.PPCData+3), 422 ld_le32((unsigned int *)p.PPCData+5), 423 convtype[p.PPCData[2]-1], 424 transtype[p.PPCData[1]-1]); 425 break; 426 case 6: 427 printk(" Bus speed %d Hz, %d slot(s)\n", 428 ld_le32((unsigned int *)p.PPCData), 429 p.PPCData[4]); 430 break; 431 case 7: 432 printk(" SCSI buses: %d, id(s):", p.PPCData[0]); 433 for(i=1; i<=p.PPCData[0]; i++) 434 printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ','); 435 break; 436 case 9: 437 printk(" %s address (%d bits), at 0x%x size 0x%x bytes\n", 438 addrtype[p.PPCData[0]-1], 439 p.PPCData[1], 440 ld_le32((unsigned int *)(p.PPCData+4)), 441 ld_le32((unsigned int *)(p.PPCData+12))); 442 break; 443 case 10: 444 sprintf(tmpstr, 445 inttype[p.PPCData[0]-1], 446 p.PPCData[1]); 447 448 printk(" ISA interrupts routed to %s\n" 449 " lines", 450 tmpstr); 451 for(i=0; i<16; i++) { 452 int line=ld_le16((unsigned short *)p.PPCData+i+1); 453 if (line!=0xffff) printk(" %d(IRQ%d)", line, i); 454 } 455 printk("\n"); 456 break; 457 default: 458 printk(" Large vendor item type 0x%2.2x\n Data (hex):", 459 p.Type); 460 for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]); 461 printk("\n"); 462#undef p 463 } 464} 465 466static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) { 467 switch (tag_large_item_name(pkt->S1_Pack.Tag)) { 468 case LargeVendorItem: 469 printlargevendor(pkt, size); 470 break; 471 default: 472 printk(" Type 0x2.2x%d, size=%d\n", 473 pkt->S1_Pack.Tag, size); 474 break; 475 } 476} 477 478static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) 479{ 480 if (pkt->S1_Pack.Tag== END_TAG) { 481 printk(" No packets describing %s resources.\n", cat); 482 return; 483 } 484 printk( " Packets describing %s resources:\n",cat); 485 do { 486 int size; 487 if (tag_type(pkt->S1_Pack.Tag)) { 488 size= 3 + 489 pkt->L1_Pack.Count0 + 490 pkt->L1_Pack.Count1*256; 491 printlargepacket(pkt, size); 492 } else { 493 size=tag_small_count(pkt->S1_Pack.Tag)+1; 494 printsmallpacket(pkt, size); 495 } 496 pkt = (PnP_TAG_PACKET *)((unsigned char *) pkt + size); 497 } while (pkt->S1_Pack.Tag != END_TAG); 498} 499 500void __init print_residual_device_info(void) 501{ 502 int i; 503 PPC_DEVICE *dev; 504#define did dev->DeviceId 505 506 /* make sure we have residual data first */ 507 if (!have_residual_data) 508 return; 509 510 printk("Residual: %ld devices\n", res->ActualNumDevices); 511 for ( i = 0; 512 i < res->ActualNumDevices ; 513 i++) 514 { 515 char decomp[4], sn[20]; 516 const char * s; 517 dev = &res->Devices[i]; 518 s = PnP_INTERFACE_STR(did.BaseType, did.SubType, 519 did.Interface); 520 if(!s) { 521 sprintf(sn, "interface %d", did.Interface); 522 s=sn; 523 } 524 if ( did.BusId & PCIDEVICE ) 525 printk("PCI Device, Bus %d, DevFunc 0x%x:", 526 dev->BusAccess.PCIAccess.BusNumber, 527 dev->BusAccess.PCIAccess.DevFuncNumber); 528 if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:"); 529 if ( did.BusId & ISADEVICE ) 530 printk("ISA Device, Slot %d, LogicalDev %d:", 531 dev->BusAccess.ISAAccess.SlotNumber, 532 dev->BusAccess.ISAAccess.LogicalDevNumber); 533 if ( did.BusId & EISADEVICE ) printk("EISA Device:"); 534 if ( did.BusId & PROCESSORDEVICE ) 535 printk("ProcBus Device, Bus %d, BUID %d: ", 536 dev->BusAccess.ProcBusAccess.BusNumber, 537 dev->BusAccess.ProcBusAccess.BUID); 538 if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA "); 539 if ( did.BusId & VMEDEVICE ) printk("VME "); 540 if ( did.BusId & MCADEVICE ) printk("MCA "); 541 if ( did.BusId & MXDEVICE ) printk("MX "); 542 /* Decompress first 3 chars */ 543 decomp[0]='A'-1+((did.DevId>>26)&0x1F); 544 decomp[1]='A'-1+((did.DevId>>21)&0x1F); 545 decomp[2]='A'-1+((did.DevId>>16)&0x1F); 546 decomp[3]=0; 547 printk(" %s%4.4lX, %s, %s, %s\n", 548 decomp, did.DevId&0xffff, 549 PnP_BASE_TYPES[did.BaseType], 550 PnP_SUB_TYPE_STR(did.BaseType,did.SubType), 551 s); 552 if ( dev->AllocatedOffset ) 553 printpackets( (union _PnP_TAG_PACKET *) 554 &res->DevicePnPHeap[dev->AllocatedOffset], 555 "allocated"); 556 if ( dev->PossibleOffset ) 557 printpackets( (union _PnP_TAG_PACKET *) 558 &res->DevicePnPHeap[dev->PossibleOffset], 559 "possible"); 560 if ( dev->CompatibleOffset ) 561 printpackets( (union _PnP_TAG_PACKET *) 562 &res->DevicePnPHeap[dev->CompatibleOffset], 563 "compatible"); 564 } 565} 566 567 568 569/* Returns the device index in the residual data, 570 any of the search items may be set as -1 for wildcard, 571 DevID number field (second halfword) is big endian ! 572 573 Examples: 574 - search for the Interrupt controller (8259 type), 2 methods: 575 1) i8259 = residual_find_device(~0, 576 NULL, 577 SystemPeripheral, 578 ProgrammableInterruptController, 579 ISA_PIC, 580 0); 581 2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) 582 583 - search for the first two serial devices, whatever their type) 584 iserial1 = residual_find_device(~0,NULL, 585 CommunicationsDevice, 586 RS232Device, 587 -1, 0) 588 iserial2 = residual_find_device(~0,NULL, 589 CommunicationsDevice, 590 RS232Device, 591 -1, 1) 592 - but search for typical COM1 and COM2 is not easy due to the 593 fact that the interface may be anything and the name "PNP0500" or 594 "PNP0501". Quite bad. 595 596*/ 597 598/* devid are easier to uncompress than to compress, so to minimize bloat 599in this rarely used area we unencode and compare */ 600 601/* in residual data number is big endian in the device table and 602little endian in the heap, so we use two parameters to avoid writing 603two very similar functions */ 604 605static int __init same_DevID(unsigned short vendor, 606 unsigned short Number, 607 char * str) 608{ 609 static unsigned const char hexdigit[]="0123456789ABCDEF"; 610 if (strlen(str)!=7) return 0; 611 if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) && 612 ( ((vendor>>5)&0x1f)+'A'-1 == str[1]) && 613 ( (vendor&0x1f)+'A'-1 == str[2]) && 614 (hexdigit[(Number>>12)&0x0f] == str[3]) && 615 (hexdigit[(Number>>8)&0x0f] == str[4]) && 616 (hexdigit[(Number>>4)&0x0f] == str[5]) && 617 (hexdigit[Number&0x0f] == str[6]) ) return 1; 618 return 0; 619} 620 621PPC_DEVICE __init *residual_find_device(unsigned long BusMask, 622 unsigned char * DevID, 623 int BaseType, 624 int SubType, 625 int Interface, 626 int n) 627{ 628 int i; 629 if (!have_residual_data) return NULL; 630 for (i=0; i<res->ActualNumDevices; i++) { 631#define Dev res->Devices[i].DeviceId 632 if ( (Dev.BusId&BusMask) && 633 (BaseType==-1 || Dev.BaseType==BaseType) && 634 (SubType==-1 || Dev.SubType==SubType) && 635 (Interface==-1 || Dev.Interface==Interface) && 636 (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff, 637 Dev.DevId&0xffff, DevID)) && 638 !(n--) ) return res->Devices+i; 639#undef Dev 640 } 641 return NULL; 642} 643 644PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask, 645 unsigned short DevID, 646 int BaseType, 647 int SubType, 648 int Interface, 649 int n) 650{ 651 int i; 652 if (!have_residual_data) return NULL; 653 for (i=0; i<res->ActualNumDevices; i++) { 654#define Dev res->Devices[i].DeviceId 655 if ( (Dev.BusId&BusMask) && 656 (BaseType==-1 || Dev.BaseType==BaseType) && 657 (SubType==-1 || Dev.SubType==SubType) && 658 (Interface==-1 || Dev.Interface==Interface) && 659 (DevID==0xffff || (Dev.DevId&0xffff) == DevID) && 660 !(n--) ) return res->Devices+i; 661#undef Dev 662 } 663 return NULL; 664} 665 666static int __init 667residual_scan_pcibridge(PnP_TAG_PACKET * pkt, struct pci_dev *dev) 668{ 669 int irq = -1; 670 671#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData 672 if (dev->bus->number == data[16]) { 673 int i, size; 674 675 size = 3 + ld_le16((u_short *) (&pkt->L4_Pack.Count0)); 676 for (i = 20; i < size - 4; i += 12) { 677 unsigned char pin; 678 int line_irq; 679 680 if (dev->devfn != data[i + 1]) 681 continue; 682 683 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); 684 if (pin) { 685 line_irq = ld_le16((unsigned short *) 686 (&data[i + 4 + 2 * (pin - 1)])); 687 irq = (line_irq == 0xffff) ? 0 688 : line_irq & 0x7fff; 689 } else 690 irq = 0; 691 692 break; 693 } 694 } 695#undef data 696 697 return irq; 698} 699 700int __init 701residual_pcidev_irq(struct pci_dev *dev) 702{ 703 int i = 0; 704 int irq = -1; 705 PPC_DEVICE *bridge; 706 707 while ((bridge = residual_find_device 708 (-1, NULL, BridgeController, PCIBridge, -1, i++))) { 709 710 PnP_TAG_PACKET *pkt; 711 if (bridge->AllocatedOffset) { 712 pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + 713 bridge->AllocatedOffset, 3, 0); 714 if (!pkt) 715 continue; 716 717 irq = residual_scan_pcibridge(pkt, dev); 718 if (irq != -1) 719 break; 720 } 721 } 722 723 return (irq < 0) ? 0 : irq; 724} 725 726void __init residual_irq_mask(char *irq_edge_mask_lo, char *irq_edge_mask_hi) 727{ 728 PPC_DEVICE *dev; 729 int i = 0; 730 unsigned short irq_mask = 0x000; /* default to edge */ 731 732 while ((dev = residual_find_device(-1, NULL, -1, -1, -1, i++))) { 733 PnP_TAG_PACKET *pkt; 734 unsigned short mask; 735 int size; 736 int offset = dev->AllocatedOffset; 737 738 if (!offset) 739 continue; 740 741 pkt = PnP_find_packet(res->DevicePnPHeap + offset, 742 IRQFormat, 0); 743 if (!pkt) 744 continue; 745 746 size = tag_small_count(pkt->S1_Pack.Tag) + 1; 747 mask = ld_le16((unsigned short *)pkt->S4_Pack.IRQMask); 748 if (size > 3 && (pkt->S4_Pack.IRQInfo & 0x0c)) 749 irq_mask |= mask; 750 } 751 752 *irq_edge_mask_lo = irq_mask & 0xff; 753 *irq_edge_mask_hi = irq_mask >> 8; 754} 755 756unsigned int __init residual_isapic_addr(void) 757{ 758 PPC_DEVICE *isapic; 759 PnP_TAG_PACKET *pkt; 760 unsigned int addr; 761 762 isapic = residual_find_device(~0, NULL, SystemPeripheral, 763 ProgrammableInterruptController, 764 ISA_PIC, 0); 765 if (!isapic) 766 goto unknown; 767 768 pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap + 769 isapic->AllocatedOffset, 9, 0); 770 if (!pkt) 771 goto unknown; 772 773#define p pkt->L4_Pack.L4_Data.L4_PPCPack 774 /* Must be 32-bit system address */ 775 if (!((p.PPCData[0] == 3) && (p.PPCData[1] == 32))) 776 goto unknown; 777 778 /* It doesn't seem to work where length != 1 (what can I say? :-/ ) */ 779 if (ld_le32((unsigned int *)(p.PPCData + 12)) != 1) 780 goto unknown; 781 782 addr = ld_le32((unsigned int *) (p.PPCData + 4)); 783#undef p 784 return addr; 785unknown: 786 return 0; 787} 788 789PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, 790 unsigned packet_tag, 791 int n) 792{ 793 unsigned mask, masked_tag, size; 794 if(!p) return NULL; 795 if (tag_type(packet_tag)) mask=0xff; else mask=0xF8; 796 masked_tag = packet_tag&mask; 797 for(; *p != END_TAG; p+=size) { 798 if ((*p & mask) == masked_tag && !(n--)) 799 return (PnP_TAG_PACKET *) p; 800 if (tag_type(*p)) 801 size=ld_le16((unsigned short *)(p+1))+3; 802 else 803 size=tag_small_count(*p)+1; 804 } 805 return NULL; /* not found */ 806} 807 808PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p, 809 unsigned packet_type, 810 int n) 811{ 812 int next=0; 813 while (p) { 814 p = (unsigned char *) PnP_find_packet(p, 0x70, next); 815 if (p && p[1]==packet_type && !(n--)) 816 return (PnP_TAG_PACKET *) p; 817 next = 1; 818 }; 819 return NULL; /* not found */ 820} 821 822PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p, 823 unsigned packet_type, 824 int n) 825{ 826 int next=0; 827 while (p) { 828 p = (unsigned char *) PnP_find_packet(p, 0x84, next); 829 if (p && p[3]==packet_type && !(n--)) 830 return (PnP_TAG_PACKET *) p; 831 next = 1; 832 }; 833 return NULL; /* not found */ 834} 835 836#ifdef CONFIG_PROC_PREPRESIDUAL 837static int proc_prep_residual_read(char * buf, char ** start, off_t off, 838 int count, int *eof, void *data) 839{ 840 int n; 841 842 n = res->ResidualLength - off; 843 if (n < 0) { 844 *eof = 1; 845 n = 0; 846 } 847 else { 848 if (n > count) 849 n = count; 850 else 851 *eof = 1; 852 853 memcpy(buf, (char *)res + off, n); 854 *start = buf; 855 } 856 857 return n; 858} 859 860int __init 861proc_prep_residual_init(void) 862{ 863 if (have_residual_data) 864 create_proc_read_entry("residual", S_IRUGO, NULL, 865 proc_prep_residual_read, NULL); 866 return 0; 867} 868 869__initcall(proc_prep_residual_init); 870#endif 871