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 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 }
ProgramPciLatency(IN EFI_PCI_IO_PROTOCOL * PciIo)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 }
SavePciLanAddress(IN EFI_PCI_IO_PROTOCOL * PciIo)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 }
PciBusEvent(IN EFI_EVENT Event,IN VOID * Context)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