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