Home | History | Annotate | Download | only in PlatformDxe
      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