1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 23 Module Name: 24 25 26 PciDevice.c 27 28 Abstract: 29 30 Platform Initialization Driver. 31 32 Revision History 33 34 --*/ 35 36 #include "PlatformDxe.h" 37 #include "Library/DxeServicesTableLib.h" 38 #include "PciBus.h" 39 #include "Guid/PciLanInfo.h" 40 41 extern VOID *mPciLanInfo; 42 extern UINTN mPciLanCount; 43 44 extern EFI_HANDLE mImageHandle; 45 extern SYSTEM_CONFIGURATION mSystemConfiguration; 46 47 48 VOID *mPciRegistration; 49 #define NCR_VENDOR_ID 0x1000 50 #define ATI_VENDOR_ID 0x1002 51 #define INTEL_VENDOR_ID 0x8086 52 #define ATI_RV423_ID 0x5548 53 #define ATI_RV423_ID2 0x5d57 54 #define ATI_RV380_ID 0x3e50 55 #define ATI_RV370_ID 0x5b60 56 #define SI_VENDOR_ID 0x1095 57 #define SI_SISATA_ID 0x3114 58 #define SI_SIRAID_PCIUNL 0x40 59 #define INTEL_82573E_IDER 0x108D 60 61 typedef struct { 62 UINT8 ClassCode; 63 UINT8 SubClassCode; 64 UINT16 VendorId; 65 UINT16 DeviceId; 66 } BAD_DEVICE_TABLE; 67 68 BAD_DEVICE_TABLE BadDeviceTable[] = { 69 {(UINT8)PCI_CLASS_MASS_STORAGE,(UINT8)PCI_CLASS_MASS_STORAGE_SCSI,(UINT16)NCR_VENDOR_ID, (UINT16)0xffff}, // Any NCR cards 70 {(UINT8)PCI_CLASS_MASS_STORAGE,(UINT8)PCI_CLASS_MASS_STORAGE_IDE,(UINT16)INTEL_VENDOR_ID, (UINT16)INTEL_82573E_IDER}, // Intel i82573E Tekoa GBit Lan IDE-R 71 {(UINT8)0xff,(UINT8)0xff,(UINT16)0xffff,(UINT16)0xffff} 72 }; 73 74 EFI_STATUS 75 PciBusDriverHook ( 76 ) 77 { 78 EFI_STATUS Status; 79 EFI_EVENT FilterEvent; 80 81 // 82 // Register for callback to PCI I/O protocol 83 // 84 Status = gBS->CreateEvent ( 85 EVT_NOTIFY_SIGNAL, 86 TPL_CALLBACK, 87 PciBusEvent, 88 NULL, 89 &FilterEvent 90 ); 91 ASSERT_EFI_ERROR(Status); 92 93 // 94 // Register for protocol notifications on this event 95 // 96 Status = gBS->RegisterProtocolNotify ( 97 &gEfiPciIoProtocolGuid, 98 FilterEvent, 99 &mPciRegistration 100 ); 101 ASSERT_EFI_ERROR (Status); 102 103 return EFI_SUCCESS; 104 } 105 106 VOID 107 InitBadBars( 108 IN EFI_PCI_IO_PROTOCOL *PciIo, 109 IN UINT16 VendorId, 110 IN UINT16 DeviceId 111 ) 112 { 113 114 EFI_STATUS Status; 115 PCI_IO_DEVICE *PciIoDevice; 116 UINT64 BaseAddress = 0; 117 UINT64 TempBaseAddress = 0; 118 UINT8 RevId = 0; 119 UINT32 Bar; 120 UINT64 IoSize; 121 UINT64 MemSize; 122 UINTN MemSizeBits; 123 124 125 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); 126 switch ( VendorId) { 127 case ATI_VENDOR_ID: 128 // 129 // ATI fix-ups. At this time all ATI cards in BadDeviceTable 130 // have same problem in that OPROM BAR needs to be increased. 131 // 132 Bar = 0x30 ; 133 // 134 // Get original BAR address 135 // 136 Status = PciIo->Pci.Read ( 137 PciIo, 138 EfiPciIoWidthUint32, 139 Bar, 140 1, 141 (VOID *) &BaseAddress 142 ); 143 // 144 // Find BAR size 145 // 146 TempBaseAddress = 0xffffffff; 147 Status = PciIo->Pci.Write ( 148 PciIo, 149 EfiPciIoWidthUint32, 150 Bar, 151 1, 152 (VOID *) &TempBaseAddress 153 ); 154 Status = PciIo->Pci.Read ( 155 PciIo, 156 EfiPciIoWidthUint32, 157 Bar, 158 1, 159 (VOID *) &TempBaseAddress 160 ); 161 TempBaseAddress &= 0xfffffffe; 162 MemSize = 1; 163 while ((TempBaseAddress & 0x01) == 0) { 164 TempBaseAddress = TempBaseAddress >> 1; 165 MemSize = MemSize << 1; 166 } 167 168 // 169 // Free up allocated memory memory and re-allocate with increased size. 170 // 171 Status = gDS->FreeMemorySpace ( 172 BaseAddress, 173 MemSize 174 ); 175 // 176 // Force new alignment 177 // 178 MemSize = 0x8000000; 179 MemSizeBits = 28; 180 181 Status = gDS->AllocateMemorySpace ( 182 EfiGcdAllocateAnySearchBottomUp, 183 EfiGcdMemoryTypeMemoryMappedIo, 184 MemSizeBits, // Alignment 185 MemSize, 186 &BaseAddress, 187 mImageHandle, 188 NULL 189 ); 190 Status = PciIo->Pci.Write ( 191 PciIo, 192 EfiPciIoWidthUint32, 193 Bar, 194 1, 195 (VOID *) &BaseAddress 196 ); 197 198 break; 199 case NCR_VENDOR_ID: 200 #define MIN_NCR_IO_SIZE 0x800 201 #define NCR_GRAN 11 // 2**11 = 0x800 202 // 203 // NCR SCSI cards like 8250S lie about IO needed. Assign as least 0x80. 204 // 205 for (Bar = 0x10; Bar < 0x28; Bar+= 4) { 206 207 Status = PciIo->Pci.Read ( 208 PciIo, 209 EfiPciIoWidthUint32, 210 Bar, 211 1, 212 (VOID *) &BaseAddress 213 ); 214 if (BaseAddress && 0x01) { 215 TempBaseAddress = 0xffffffff; 216 Status = PciIo->Pci.Write ( 217 PciIo, 218 EfiPciIoWidthUint32, 219 Bar, 220 1, 221 (VOID *) &TempBaseAddress 222 ); 223 TempBaseAddress &= 0xfffffffc; 224 IoSize = 1; 225 while ((TempBaseAddress & 0x01) == 0) { 226 TempBaseAddress = TempBaseAddress >> 1; 227 IoSize = IoSize << 1; 228 } 229 if (IoSize < MIN_NCR_IO_SIZE) { 230 Status = gDS->FreeIoSpace ( 231 BaseAddress, 232 IoSize 233 ); 234 235 Status = gDS->AllocateIoSpace ( 236 EfiGcdAllocateAnySearchTopDown, 237 EfiGcdIoTypeIo, 238 NCR_GRAN, // Alignment 239 MIN_NCR_IO_SIZE, 240 &BaseAddress, 241 mImageHandle, 242 NULL 243 ); 244 TempBaseAddress = BaseAddress + 1; 245 Status = PciIo->Pci.Write ( 246 PciIo, 247 EfiPciIoWidthUint32, 248 Bar, 249 1, 250 (VOID *) &TempBaseAddress 251 ); 252 } 253 } 254 } 255 256 break; 257 258 case INTEL_VENDOR_ID: 259 if (DeviceId == INTEL_82573E_IDER) { 260 // 261 // Tekoa i82573E IDE-R fix-ups. At this time A2 step and earlier parts do not 262 // support any BARs except BAR0. Other BARS will actualy map to BAR0 so disable 263 // them all for Control Blocks and Bus mastering ops as well as Secondary IDE 264 // Controller. 265 // All Tekoa A2 or earlier step chips for now. 266 // 267 Status = PciIo->Pci.Read ( 268 PciIo, 269 EfiPciIoWidthUint8, 270 PCI_REVISION_ID_OFFSET, 271 1, 272 &RevId 273 ); 274 if (RevId <= 0x02) { 275 for (Bar = 0x14; Bar < 0x24; Bar+= 4) { 276 // 277 // Maybe want to clean this up a bit later but for now just clear out the secondary 278 // Bars don't worry aboyut freeing up thge allocs. 279 // 280 TempBaseAddress = 0x0; 281 Status = PciIo->Pci.Write ( 282 PciIo, 283 EfiPciIoWidthUint32, 284 Bar, 285 1, 286 (VOID *) &TempBaseAddress 287 ); 288 } // end for 289 } 290 else 291 { 292 // 293 //Tekoa A3 or above: 294 //Clear bus master base address (PCI register 0x20) 295 //since Tekoa does not fully support IDE Bus Mastering 296 // 297 TempBaseAddress = 0x0; 298 Status = PciIo->Pci.Write ( 299 PciIo, 300 EfiPciIoWidthUint32, 301 0x20, 302 1, 303 (VOID *) &TempBaseAddress 304 ); 305 } 306 } 307 break; 308 309 default: 310 break; 311 } 312 return; 313 } 314 315 VOID 316 ProgramPciLatency( 317 IN EFI_PCI_IO_PROTOCOL *PciIo 318 ) 319 { 320 EFI_STATUS Status; 321 322 // 323 // Program Master Latency Timer 324 // 325 if (mSystemConfiguration.PciLatency != 0) { 326 Status = PciIo->Pci.Write ( 327 PciIo, 328 EfiPciIoWidthUint8, 329 PCI_LATENCY_TIMER_OFFSET, 330 1, 331 &mSystemConfiguration.PciLatency 332 ); 333 } 334 return; 335 } 336 337 /** 338 During S5 shutdown, we need to program PME in all LAN devices. 339 Here we identify LAN devices and save their bus/dev/func. 340 341 **/ 342 VOID 343 SavePciLanAddress( 344 IN EFI_PCI_IO_PROTOCOL *PciIo 345 ) 346 { 347 EFI_STATUS Status; 348 UINTN PciSegment, 349 PciBus, 350 PciDevice, 351 PciFunction; 352 VOID *NewBuffer; 353 PCI_LAN_INFO *x; 354 355 Status = PciIo->GetLocation ( 356 PciIo, 357 &PciSegment, 358 &PciBus, 359 &PciDevice, 360 &PciFunction 361 ); 362 if (EFI_ERROR (Status)) { 363 return; 364 } 365 366 mPciLanCount ++; 367 Status = gBS->AllocatePool ( 368 EfiBootServicesData, 369 mPciLanCount * sizeof(PCI_LAN_INFO), 370 &NewBuffer 371 ); 372 if (EFI_ERROR (Status)) { 373 return; 374 } 375 376 if (mPciLanCount > 1) { 377 // 378 // copy old data into new, larger buffer 379 // 380 gBS->CopyMem ( 381 NewBuffer, 382 mPciLanInfo, 383 (mPciLanCount - 1) * sizeof(PCI_LAN_INFO) 384 ); 385 386 // 387 // free the old memory buffer 388 // 389 gBS->FreePool (mPciLanInfo); 390 391 } 392 393 // 394 // init the new entry 395 // 396 x = (PCI_LAN_INFO *)NewBuffer + (mPciLanCount - 1); 397 x->PciBus = (UINT8)PciBus; 398 x->PciDevice = (UINT8)PciDevice; 399 x->PciFunction = (UINT8)PciFunction; 400 401 mPciLanInfo = NewBuffer; 402 403 return; 404 } 405 406 /** 407 @param Event the event that is signaled. 408 @param Context not used here. 409 410 411 **/ 412 VOID 413 EFIAPI 414 PciBusEvent ( 415 IN EFI_EVENT Event, 416 IN VOID* Context 417 ) 418 { 419 420 EFI_STATUS Status; 421 UINTN BufferSize; 422 EFI_HANDLE Handle; 423 EFI_PCI_IO_PROTOCOL *PciIo; 424 PCI_IO_DEVICE *PciIoDevice; 425 UINT64 Supports; 426 UINTN Index; 427 UINT8 mCacheLineSize = 0x10; 428 429 while (TRUE) { 430 BufferSize = sizeof (EFI_HANDLE); 431 Status = gBS->LocateHandle ( 432 ByRegisterNotify, 433 NULL, 434 mPciRegistration, 435 &BufferSize, 436 &Handle 437 ); 438 if (EFI_ERROR (Status)) { 439 // 440 // If no more notification events exist 441 // 442 return; 443 } 444 445 Status = gBS->HandleProtocol ( 446 Handle, 447 &gEfiPciIoProtocolGuid, 448 (void **)&PciIo 449 ); 450 451 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); 452 453 // 454 // Enable I/O for bridge so port 0x80 codes will come out 455 // 456 if (PciIoDevice->Pci.Hdr.VendorId == V_PCH_INTEL_VENDOR_ID) 457 { 458 Status = PciIo->Attributes( 459 PciIo, 460 EfiPciIoAttributeOperationSupported, 461 0, 462 &Supports 463 ); 464 Supports &= EFI_PCI_DEVICE_ENABLE; 465 Status = PciIo->Attributes ( 466 PciIo, 467 EfiPciIoAttributeOperationEnable, 468 Supports, 469 NULL 470 ); 471 break; 472 } 473 474 // 475 // Program PCI Latency Timer 476 // 477 ProgramPciLatency(PciIo); 478 479 // 480 // Program Cache Line Size to 64 bytes (0x10 DWORDs) 481 // 482 Status = PciIo->Pci.Write ( 483 PciIo, 484 EfiPciIoWidthUint8, 485 PCI_CACHELINE_SIZE_OFFSET, 486 1, 487 &mCacheLineSize 488 ); 489 490 // 491 // If PCI LAN device, save bus/dev/func info 492 // so we can program PME during S5 shutdown 493 // 494 if (PciIoDevice->Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) { 495 SavePciLanAddress(PciIo); 496 break; 497 } 498 499 // 500 // Workaround for cards with bad BARs 501 // 502 Index = 0; 503 while (BadDeviceTable[Index].ClassCode != 0xff) { 504 if (BadDeviceTable[Index].DeviceId == 0xffff) { 505 if ((PciIoDevice->Pci.Hdr.ClassCode[2] == BadDeviceTable[Index].ClassCode) && 506 (PciIoDevice->Pci.Hdr.ClassCode[1] == BadDeviceTable[Index].SubClassCode) && 507 (PciIoDevice->Pci.Hdr.VendorId == BadDeviceTable[Index].VendorId)) { 508 InitBadBars(PciIo,BadDeviceTable[Index].VendorId,BadDeviceTable[Index].DeviceId); 509 } 510 } else { 511 if ((PciIoDevice->Pci.Hdr.ClassCode[2] == BadDeviceTable[Index].ClassCode) && 512 (PciIoDevice->Pci.Hdr.ClassCode[1] == BadDeviceTable[Index].SubClassCode) && 513 (PciIoDevice->Pci.Hdr.VendorId == BadDeviceTable[Index].VendorId) && 514 (PciIoDevice->Pci.Hdr.DeviceId == BadDeviceTable[Index].DeviceId)) { 515 516 InitBadBars(PciIo,BadDeviceTable[Index].VendorId,BadDeviceTable[Index].DeviceId); 517 } 518 } 519 ++Index; 520 } 521 break; 522 } 523 524 return; 525 } 526 527