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