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