]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
MdeModulePkg: Update PciEnumeratorSupport to ignore OptionRom if needed
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
CommitLineData
9060e3ec 1/** @file\r
2 PCI emumeration support functions implementation for PCI Bus module.\r
3\r
0785c619 4Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>\r
25a26646 5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
9060e3ec 7\r
8**/\r
9\r
10#include "PciBus.h"\r
11\r
1436aea4
MK
12extern CHAR16 *mBarTypeStr[];\r
13extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;\r
8db6a82c 14\r
1436aea4
MK
15#define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL\r
16#define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL\r
17#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL\r
18#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL\r
8a93fa1e 19\r
9060e3ec 20/**\r
21 This routine is used to check whether the pci device is present.\r
22\r
23 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
24 @param Pci Output buffer for PCI device configuration space.\r
25 @param Bus PCI bus NO.\r
26 @param Device PCI device NO.\r
27 @param Func PCI Func NO.\r
28\r
29 @retval EFI_NOT_FOUND PCI device not present.\r
30 @retval EFI_SUCCESS PCI device is found.\r
31\r
32**/\r
33EFI_STATUS\r
34PciDevicePresent (\r
1436aea4
MK
35 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
36 OUT PCI_TYPE00 *Pci,\r
37 IN UINT8 Bus,\r
38 IN UINT8 Device,\r
39 IN UINT8 Func\r
9060e3ec 40 )\r
41{\r
42 UINT64 Address;\r
43 EFI_STATUS Status;\r
44\r
45 //\r
46 // Create PCI address map in terms of Bus, Device and Func\r
47 //\r
48 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
49\r
50 //\r
51 // Read the Vendor ID register\r
52 //\r
53 Status = PciRootBridgeIo->Pci.Read (\r
54 PciRootBridgeIo,\r
55 EfiPciWidthUint32,\r
56 Address,\r
57 1,\r
58 Pci\r
59 );\r
60\r
1436aea4 61 if (!EFI_ERROR (Status) && ((Pci->Hdr).VendorId != 0xffff)) {\r
9060e3ec 62 //\r
63 // Read the entire config header for the device\r
64 //\r
65 Status = PciRootBridgeIo->Pci.Read (\r
66 PciRootBridgeIo,\r
67 EfiPciWidthUint32,\r
68 Address,\r
69 sizeof (PCI_TYPE00) / sizeof (UINT32),\r
70 Pci\r
71 );\r
72\r
73 return EFI_SUCCESS;\r
74 }\r
75\r
76 return EFI_NOT_FOUND;\r
77}\r
78\r
79/**\r
80 Collect all the resource information under this root bridge.\r
81\r
82 A database that records all the information about pci device subject to this\r
83 root bridge will then be created.\r
84\r
85 @param Bridge Parent bridge instance.\r
fcdfcdbf 86 @param StartBusNumber Bus number of beginning.\r
9060e3ec 87\r
88 @retval EFI_SUCCESS PCI device is found.\r
89 @retval other Some error occurred when reading PCI bridge information.\r
90\r
91**/\r
92EFI_STATUS\r
93PciPciDeviceInfoCollector (\r
1436aea4
MK
94 IN PCI_IO_DEVICE *Bridge,\r
95 IN UINT8 StartBusNumber\r
9060e3ec 96 )\r
97{\r
1436aea4
MK
98 EFI_STATUS Status;\r
99 PCI_TYPE00 Pci;\r
100 UINT8 Device;\r
101 UINT8 Func;\r
102 UINT8 SecBus;\r
103 PCI_IO_DEVICE *PciIoDevice;\r
104 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 105\r
1436aea4
MK
106 Status = EFI_SUCCESS;\r
107 SecBus = 0;\r
9060e3ec 108\r
109 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
9060e3ec 110 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
9060e3ec 111 //\r
112 // Check to see whether PCI device is present\r
113 //\r
114 Status = PciDevicePresent (\r
115 Bridge->PciRootBridgeIo,\r
116 &Pci,\r
1436aea4
MK
117 (UINT8)StartBusNumber,\r
118 (UINT8)Device,\r
119 (UINT8)Func\r
9060e3ec 120 );\r
25a26646 121\r
1436aea4 122 if (EFI_ERROR (Status) && (Func == 0)) {\r
25a26646
JS
123 //\r
124 // go to next device if there is no Function 0\r
125 //\r
126 break;\r
127 }\r
128\r
9060e3ec 129 if (!EFI_ERROR (Status)) {\r
9060e3ec 130 //\r
131 // Call back to host bridge function\r
132 //\r
1436aea4 133 PreprocessController (Bridge, (UINT8)StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);\r
9060e3ec 134\r
135 //\r
136 // Collect all the information about the PCI device discovered\r
137 //\r
138 Status = PciSearchDevice (\r
139 Bridge,\r
140 &Pci,\r
1436aea4 141 (UINT8)StartBusNumber,\r
9060e3ec 142 Device,\r
143 Func,\r
144 &PciIoDevice\r
145 );\r
146\r
147 //\r
148 // Recursively scan PCI busses on the other side of PCI-PCI bridges\r
149 //\r
150 //\r
151 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {\r
9060e3ec 152 //\r
153 // If it is PPB, we need to get the secondary bus to continue the enumeration\r
154 //\r
1436aea4 155 PciIo = &(PciIoDevice->PciIo);\r
9060e3ec 156\r
1436aea4 157 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);\r
9060e3ec 158\r
159 if (EFI_ERROR (Status)) {\r
160 return Status;\r
161 }\r
162\r
c28306c3
MM
163 //\r
164 // Ensure secondary bus number is greater than the primary bus number to avoid\r
165 // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE\r
166 //\r
167 if (SecBus <= StartBusNumber) {\r
168 break;\r
169 }\r
170\r
9060e3ec 171 //\r
172 // Get resource padding for PPB\r
173 //\r
174 GetResourcePaddingPpb (PciIoDevice);\r
175\r
176 //\r
177 // Deep enumerate the next level bus\r
178 //\r
179 Status = PciPciDeviceInfoCollector (\r
180 PciIoDevice,\r
1436aea4 181 (UINT8)(SecBus)\r
9060e3ec 182 );\r
9060e3ec 183 }\r
184\r
1436aea4 185 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {\r
9060e3ec 186 //\r
187 // Skip sub functions, this is not a multi function device\r
188 //\r
189 Func = PCI_MAX_FUNC;\r
190 }\r
191 }\r
9060e3ec 192 }\r
193 }\r
194\r
195 return EFI_SUCCESS;\r
196}\r
197\r
198/**\r
fcdfcdbf 199 Search required device and create PCI device instance.\r
9060e3ec 200\r
201 @param Bridge Parent bridge instance.\r
202 @param Pci Input PCI device information block.\r
203 @param Bus PCI bus NO.\r
204 @param Device PCI device NO.\r
205 @param Func PCI func NO.\r
206 @param PciDevice Output of searched PCI device instance.\r
207\r
208 @retval EFI_SUCCESS Successfully created PCI device instance.\r
209 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.\r
210\r
211**/\r
212EFI_STATUS\r
213PciSearchDevice (\r
1436aea4
MK
214 IN PCI_IO_DEVICE *Bridge,\r
215 IN PCI_TYPE00 *Pci,\r
216 IN UINT8 Bus,\r
217 IN UINT8 Device,\r
218 IN UINT8 Func,\r
219 OUT PCI_IO_DEVICE **PciDevice\r
9060e3ec 220 )\r
221{\r
1436aea4 222 PCI_IO_DEVICE *PciIoDevice;\r
cb8349f0 223 BOOLEAN IgnoreOptionRom;\r
9060e3ec 224\r
cb8349f0
MX
225 PciIoDevice = NULL;\r
226 IgnoreOptionRom = FALSE;\r
9060e3ec 227\r
8db6a82c 228 DEBUG ((\r
87000d77 229 DEBUG_INFO,\r
8db6a82c
RN
230 "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",\r
231 IS_PCI_BRIDGE (Pci) ? L"PPB" :\r
232 IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :\r
1436aea4
MK
233 L"PCI",\r
234 Bus,\r
235 Device,\r
236 Func\r
8db6a82c
RN
237 ));\r
238\r
9060e3ec 239 if (!IS_PCI_BRIDGE (Pci)) {\r
9060e3ec 240 if (IS_CARDBUS_BRIDGE (Pci)) {\r
241 PciIoDevice = GatherP2CInfo (\r
242 Bridge,\r
243 Pci,\r
244 Bus,\r
245 Device,\r
246 Func\r
247 );\r
248 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
249 InitializeP2C (PciIoDevice);\r
250 }\r
251 } else {\r
9060e3ec 252 //\r
253 // Create private data for Pci Device\r
254 //\r
255 PciIoDevice = GatherDeviceInfo (\r
256 Bridge,\r
257 Pci,\r
258 Bus,\r
259 Device,\r
260 Func\r
261 );\r
9060e3ec 262 }\r
9060e3ec 263 } else {\r
9060e3ec 264 //\r
265 // Create private data for PPB\r
266 //\r
267 PciIoDevice = GatherPpbInfo (\r
268 Bridge,\r
269 Pci,\r
270 Bus,\r
271 Device,\r
272 Func\r
273 );\r
274\r
275 //\r
276 // Special initialization for PPB including making the PPB quiet\r
277 //\r
278 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
279 InitializePpb (PciIoDevice);\r
280 }\r
281 }\r
282\r
283 if (PciIoDevice == NULL) {\r
284 return EFI_OUT_OF_RESOURCES;\r
285 }\r
286\r
287 //\r
288 // Update the bar information for this PCI device so as to support some specific device\r
289 //\r
cb8349f0 290 UpdatePciInfo (PciIoDevice, &IgnoreOptionRom);\r
9060e3ec 291\r
292 if (PciIoDevice->DevicePath == NULL) {\r
293 return EFI_OUT_OF_RESOURCES;\r
294 }\r
295\r
296 //\r
297 // Detect this function has option rom\r
298 //\r
299 if (gFullEnumeration) {\r
cb8349f0 300 if (!IS_CARDBUS_BRIDGE (Pci) && !IgnoreOptionRom) {\r
9060e3ec 301 GetOpRomInfo (PciIoDevice);\r
9060e3ec 302 }\r
303\r
304 ResetPowerManagementFeature (PciIoDevice);\r
9060e3ec 305 }\r
306\r
307 //\r
308 // Insert it into a global tree for future reference\r
309 //\r
310 InsertPciDevice (Bridge, PciIoDevice);\r
311\r
312 //\r
313 // Determine PCI device attributes\r
314 //\r
315\r
316 if (PciDevice != NULL) {\r
317 *PciDevice = PciIoDevice;\r
318 }\r
319\r
320 return EFI_SUCCESS;\r
321}\r
322\r
f67bd32d
RN
323/**\r
324 Dump the PPB padding resource information.\r
325\r
326 @param PciIoDevice PCI IO instance.\r
327 @param ResourceType The desired resource type to dump.\r
328 PciBarTypeUnknown means to dump all types of resources.\r
329**/\r
330VOID\r
331DumpPpbPaddingResource (\r
1436aea4
MK
332 IN PCI_IO_DEVICE *PciIoDevice,\r
333 IN PCI_BAR_TYPE ResourceType\r
f67bd32d
RN
334 )\r
335{\r
1436aea4
MK
336 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
337 PCI_BAR_TYPE Type;\r
f67bd32d
RN
338\r
339 if (PciIoDevice->ResourcePaddingDescriptors == NULL) {\r
340 return;\r
341 }\r
342\r
1436aea4 343 if ((ResourceType == PciBarTypeIo16) || (ResourceType == PciBarTypeIo32)) {\r
f67bd32d
RN
344 ResourceType = PciBarTypeIo;\r
345 }\r
346\r
347 for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {\r
f67bd32d 348 Type = PciBarTypeUnknown;\r
1436aea4 349 if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {\r
f67bd32d 350 Type = PciBarTypeIo;\r
1436aea4 351 } else if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {\r
f67bd32d
RN
352 if (Descriptor->AddrSpaceGranularity == 32) {\r
353 //\r
fcdfcdbf 354 // prefetchable\r
f67bd32d
RN
355 //\r
356 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {\r
357 Type = PciBarTypePMem32;\r
358 }\r
359\r
360 //\r
fcdfcdbf 361 // Non-prefetchable\r
f67bd32d
RN
362 //\r
363 if (Descriptor->SpecificFlag == 0) {\r
364 Type = PciBarTypeMem32;\r
365 }\r
366 }\r
367\r
368 if (Descriptor->AddrSpaceGranularity == 64) {\r
369 //\r
fcdfcdbf 370 // prefetchable\r
f67bd32d
RN
371 //\r
372 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {\r
373 Type = PciBarTypePMem64;\r
374 }\r
375\r
376 //\r
fcdfcdbf 377 // Non-prefetchable\r
f67bd32d
RN
378 //\r
379 if (Descriptor->SpecificFlag == 0) {\r
380 Type = PciBarTypeMem64;\r
381 }\r
382 }\r
383 }\r
384\r
385 if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) {\r
386 DEBUG ((\r
87000d77 387 DEBUG_INFO,\r
f67bd32d 388 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",\r
1436aea4
MK
389 mBarTypeStr[Type],\r
390 Descriptor->AddrRangeMax,\r
391 Descriptor->AddrLen\r
f67bd32d
RN
392 ));\r
393 }\r
394 }\r
f67bd32d
RN
395}\r
396\r
8db6a82c
RN
397/**\r
398 Dump the PCI BAR information.\r
399\r
400 @param PciIoDevice PCI IO instance.\r
401**/\r
402VOID\r
403DumpPciBars (\r
1436aea4 404 IN PCI_IO_DEVICE *PciIoDevice\r
8db6a82c
RN
405 )\r
406{\r
1436aea4 407 UINTN Index;\r
8db6a82c
RN
408\r
409 for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
410 if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {\r
411 continue;\r
412 }\r
413\r
414 DEBUG ((\r
87000d77 415 DEBUG_INFO,\r
980050bc 416 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",\r
1436aea4
MK
417 Index,\r
418 mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)],\r
419 PciIoDevice->PciBar[Index].Alignment,\r
420 PciIoDevice->PciBar[Index].Length,\r
421 PciIoDevice->PciBar[Index].Offset\r
8db6a82c
RN
422 ));\r
423 }\r
424\r
425 for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
426 if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) {\r
427 continue;\r
428 }\r
429\r
430 DEBUG ((\r
87000d77 431 DEBUG_INFO,\r
980050bc 432 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",\r
1436aea4
MK
433 Index,\r
434 mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)],\r
435 PciIoDevice->VfPciBar[Index].Alignment,\r
436 PciIoDevice->VfPciBar[Index].Length,\r
437 PciIoDevice->VfPciBar[Index].Offset\r
8db6a82c
RN
438 ));\r
439 }\r
1436aea4 440\r
87000d77 441 DEBUG ((DEBUG_INFO, "\n"));\r
8db6a82c
RN
442}\r
443\r
9060e3ec 444/**\r
445 Create PCI device instance for PCI device.\r
446\r
447 @param Bridge Parent bridge instance.\r
448 @param Pci Input PCI device information block.\r
449 @param Bus PCI device Bus NO.\r
450 @param Device PCI device Device NO.\r
451 @param Func PCI device's func NO.\r
452\r
453 @return Created PCI device instance.\r
454\r
455**/\r
456PCI_IO_DEVICE *\r
457GatherDeviceInfo (\r
1436aea4
MK
458 IN PCI_IO_DEVICE *Bridge,\r
459 IN PCI_TYPE00 *Pci,\r
460 IN UINT8 Bus,\r
461 IN UINT8 Device,\r
462 IN UINT8 Func\r
9060e3ec 463 )\r
464{\r
1436aea4
MK
465 UINTN Offset;\r
466 UINTN BarIndex;\r
467 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 468\r
9060e3ec 469 PciIoDevice = CreatePciIoDevice (\r
d4048391 470 Bridge,\r
9060e3ec 471 Pci,\r
472 Bus,\r
473 Device,\r
474 Func\r
475 );\r
476\r
477 if (PciIoDevice == NULL) {\r
478 return NULL;\r
479 }\r
480\r
9060e3ec 481 //\r
482 // If it is a full enumeration, disconnect the device in advance\r
483 //\r
484 if (gFullEnumeration) {\r
9060e3ec 485 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
9060e3ec 486 }\r
487\r
488 //\r
489 // Start to parse the bars\r
490 //\r
491 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {\r
492 Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
493 }\r
494\r
495 //\r
496 // Parse the SR-IOV VF bars\r
497 //\r
1436aea4 498 if (PcdGetBool (PcdSrIovSupport) && (PciIoDevice->SrIovCapabilityOffset != 0)) {\r
9060e3ec 499 for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;\r
500 Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;\r
1436aea4
MK
501 BarIndex++)\r
502 {\r
9060e3ec 503 ASSERT (BarIndex < PCI_MAX_BAR);\r
504 Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);\r
505 }\r
506 }\r
8db6a82c 507\r
1436aea4
MK
508 DEBUG_CODE (\r
509 DumpPciBars (PciIoDevice);\r
510 );\r
9060e3ec 511 return PciIoDevice;\r
512}\r
513\r
514/**\r
515 Create PCI device instance for PCI-PCI bridge.\r
516\r
517 @param Bridge Parent bridge instance.\r
518 @param Pci Input PCI device information block.\r
519 @param Bus PCI device Bus NO.\r
520 @param Device PCI device Device NO.\r
521 @param Func PCI device's func NO.\r
522\r
523 @return Created PCI device instance.\r
524\r
525**/\r
526PCI_IO_DEVICE *\r
527GatherPpbInfo (\r
1436aea4
MK
528 IN PCI_IO_DEVICE *Bridge,\r
529 IN PCI_TYPE00 *Pci,\r
530 IN UINT8 Bus,\r
531 IN UINT8 Device,\r
532 IN UINT8 Func\r
9060e3ec 533 )\r
534{\r
1436aea4
MK
535 PCI_IO_DEVICE *PciIoDevice;\r
536 EFI_STATUS Status;\r
537 UINT8 Value;\r
538 EFI_PCI_IO_PROTOCOL *PciIo;\r
539 UINT8 Temp;\r
540 UINT32 PMemBaseLimit;\r
541 UINT16 PrefetchableMemoryBase;\r
542 UINT16 PrefetchableMemoryLimit;\r
9060e3ec 543\r
9060e3ec 544 PciIoDevice = CreatePciIoDevice (\r
d4048391 545 Bridge,\r
9060e3ec 546 Pci,\r
547 Bus,\r
548 Device,\r
549 Func\r
550 );\r
551\r
552 if (PciIoDevice == NULL) {\r
553 return NULL;\r
554 }\r
555\r
9060e3ec 556 if (gFullEnumeration) {\r
557 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
558\r
559 //\r
fcdfcdbf 560 // Initialize the bridge control register\r
9060e3ec 561 //\r
562 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
9060e3ec 563 }\r
564\r
565 //\r
566 // PPB can have two BARs\r
567 //\r
568 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {\r
569 //\r
570 // Not 64-bit bar\r
571 //\r
572 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);\r
573 }\r
574\r
575 PciIo = &PciIoDevice->PciIo;\r
576\r
577 //\r
578 // Test whether it support 32 decode or not\r
579 //\r
580 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
581 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
582 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
583 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
584\r
585 if (Value != 0) {\r
586 if ((Value & 0x01) != 0) {\r
587 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
588 } else {\r
589 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
590 }\r
591 }\r
592\r
1ef26783 593 //\r
594 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes\r
ed356b9e 595 // PCI bridge supporting non-standard I/O window alignment less than 4K.\r
1ef26783 596 //\r
597\r
598 PciIoDevice->BridgeIoAlignment = 0xFFF;\r
599 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {\r
600 //\r
601 // Check any bits of bit 3-1 of I/O Base Register are writable.\r
ed356b9e 602 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.\r
1ef26783 603 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.\r
604 //\r
f00b5d83 605 Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));\r
1ef26783 606 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
607 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
608 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
f00b5d83 609 Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));\r
1ef26783 610 switch (Value) {\r
611 case BIT3:\r
612 PciIoDevice->BridgeIoAlignment = 0x7FF;\r
613 break;\r
614 case BIT3 | BIT2:\r
615 PciIoDevice->BridgeIoAlignment = 0x3FF;\r
616 break;\r
617 case BIT3 | BIT2 | BIT1:\r
618 PciIoDevice->BridgeIoAlignment = 0x1FF;\r
619 break;\r
620 }\r
621 }\r
622\r
9060e3ec 623 Status = BarExisted (\r
1436aea4
MK
624 PciIoDevice,\r
625 0x24,\r
626 NULL,\r
627 &PMemBaseLimit\r
628 );\r
9060e3ec 629\r
630 //\r
631 // Test if it supports 64 memory or not\r
632 //\r
07bcff9d 633 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit\r
634 // registers:\r
635 // 0 - the bridge supports only 32 bit addresses.\r
636 // 1 - the bridge supports 64-bit addresses.\r
637 //\r
1436aea4 638 PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);\r
571e9831 639 PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);\r
07bcff9d 640 if (!EFI_ERROR (Status) &&\r
1436aea4
MK
641 ((PrefetchableMemoryBase & 0x000f) == 0x0001) &&\r
642 ((PrefetchableMemoryLimit & 0x000f) == 0x0001))\r
643 {\r
9060e3ec 644 Status = BarExisted (\r
1436aea4
MK
645 PciIoDevice,\r
646 0x28,\r
647 NULL,\r
648 NULL\r
649 );\r
9060e3ec 650\r
651 if (!EFI_ERROR (Status)) {\r
652 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
653 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
654 } else {\r
655 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
656 }\r
657 }\r
658\r
659 //\r
660 // Memory 32 code is required for ppb\r
661 //\r
662 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
663\r
664 GetResourcePaddingPpb (PciIoDevice);\r
665\r
f67bd32d
RN
666 DEBUG_CODE (\r
667 DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);\r
668 DumpPciBars (PciIoDevice);\r
1436aea4 669 );\r
8db6a82c 670\r
9060e3ec 671 return PciIoDevice;\r
672}\r
673\r
9060e3ec 674/**\r
675 Create PCI device instance for PCI Card bridge device.\r
676\r
677 @param Bridge Parent bridge instance.\r
678 @param Pci Input PCI device information block.\r
679 @param Bus PCI device Bus NO.\r
680 @param Device PCI device Device NO.\r
681 @param Func PCI device's func NO.\r
682\r
683 @return Created PCI device instance.\r
684\r
685**/\r
686PCI_IO_DEVICE *\r
687GatherP2CInfo (\r
1436aea4
MK
688 IN PCI_IO_DEVICE *Bridge,\r
689 IN PCI_TYPE00 *Pci,\r
690 IN UINT8 Bus,\r
691 IN UINT8 Device,\r
692 IN UINT8 Func\r
9060e3ec 693 )\r
694{\r
1436aea4 695 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 696\r
9060e3ec 697 PciIoDevice = CreatePciIoDevice (\r
d4048391 698 Bridge,\r
9060e3ec 699 Pci,\r
700 Bus,\r
701 Device,\r
702 Func\r
703 );\r
704\r
705 if (PciIoDevice == NULL) {\r
706 return NULL;\r
707 }\r
708\r
9060e3ec 709 if (gFullEnumeration) {\r
710 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
711\r
712 //\r
fcdfcdbf 713 // Initialize the bridge control register\r
9060e3ec 714 //\r
715 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
716 }\r
717\r
718 //\r
719 // P2C only has one bar that is in 0x10\r
720 //\r
721 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);\r
722\r
723 //\r
724 // Read PciBar information from the bar register\r
725 //\r
726 GetBackPcCardBar (PciIoDevice);\r
727 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |\r
728 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |\r
729 EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
730\r
1436aea4
MK
731 DEBUG_CODE (\r
732 DumpPciBars (PciIoDevice);\r
733 );\r
8db6a82c 734\r
9060e3ec 735 return PciIoDevice;\r
736}\r
737\r
738/**\r
fcdfcdbf 739 Create device path for pci device.\r
9060e3ec 740\r
741 @param ParentDevicePath Parent bridge's path.\r
742 @param PciIoDevice Pci device instance.\r
743\r
744 @return Device path protocol instance for specific pci device.\r
745\r
746**/\r
747EFI_DEVICE_PATH_PROTOCOL *\r
748CreatePciDevicePath (\r
1436aea4
MK
749 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
750 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 751 )\r
752{\r
1436aea4 753 PCI_DEVICE_PATH PciNode;\r
9060e3ec 754\r
755 //\r
756 // Create PCI device path\r
757 //\r
1436aea4
MK
758 PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
759 PciNode.Header.SubType = HW_PCI_DP;\r
9060e3ec 760 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
761\r
762 PciNode.Device = PciIoDevice->DeviceNumber;\r
763 PciNode.Function = PciIoDevice->FunctionNumber;\r
764 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);\r
765\r
766 return PciIoDevice->DevicePath;\r
767}\r
768\r
769/**\r
770 Check whether the PCI IOV VF bar is existed or not.\r
771\r
772 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
773 @param Offset The offset.\r
774 @param BarLengthValue The bar length value returned.\r
775 @param OriginalBarValue The original bar value returned.\r
776\r
777 @retval EFI_NOT_FOUND The bar doesn't exist.\r
778 @retval EFI_SUCCESS The bar exist.\r
779\r
780**/\r
781EFI_STATUS\r
782VfBarExisted (\r
1436aea4
MK
783 IN PCI_IO_DEVICE *PciIoDevice,\r
784 IN UINTN Offset,\r
785 OUT UINT32 *BarLengthValue,\r
786 OUT UINT32 *OriginalBarValue\r
9060e3ec 787 )\r
788{\r
1436aea4
MK
789 EFI_PCI_IO_PROTOCOL *PciIo;\r
790 UINT32 OriginalValue;\r
791 UINT32 Value;\r
792 EFI_TPL OldTpl;\r
9060e3ec 793\r
794 //\r
795 // Ensure it is called properly\r
796 //\r
797 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
798 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
799 return EFI_NOT_FOUND;\r
800 }\r
801\r
802 PciIo = &PciIoDevice->PciIo;\r
803\r
804 //\r
805 // Preserve the original value\r
806 //\r
807\r
808 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
809\r
810 //\r
811 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
812 //\r
813 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
814\r
815 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);\r
816 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);\r
817\r
818 //\r
819 // Write back the original value\r
820 //\r
821 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
822\r
823 //\r
824 // Restore TPL to its original level\r
825 //\r
826 gBS->RestoreTPL (OldTpl);\r
827\r
828 if (BarLengthValue != NULL) {\r
829 *BarLengthValue = Value;\r
830 }\r
831\r
832 if (OriginalBarValue != NULL) {\r
833 *OriginalBarValue = OriginalValue;\r
834 }\r
835\r
836 if (Value == 0) {\r
837 return EFI_NOT_FOUND;\r
838 } else {\r
839 return EFI_SUCCESS;\r
840 }\r
841}\r
842\r
843/**\r
844 Check whether the bar is existed or not.\r
845\r
846 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
847 @param Offset The offset.\r
848 @param BarLengthValue The bar length value returned.\r
849 @param OriginalBarValue The original bar value returned.\r
850\r
851 @retval EFI_NOT_FOUND The bar doesn't exist.\r
852 @retval EFI_SUCCESS The bar exist.\r
853\r
854**/\r
855EFI_STATUS\r
856BarExisted (\r
1436aea4
MK
857 IN PCI_IO_DEVICE *PciIoDevice,\r
858 IN UINTN Offset,\r
859 OUT UINT32 *BarLengthValue,\r
860 OUT UINT32 *OriginalBarValue\r
9060e3ec 861 )\r
862{\r
1436aea4
MK
863 EFI_PCI_IO_PROTOCOL *PciIo;\r
864 UINT32 OriginalValue;\r
865 UINT32 Value;\r
866 EFI_TPL OldTpl;\r
9060e3ec 867\r
868 PciIo = &PciIoDevice->PciIo;\r
869\r
870 //\r
871 // Preserve the original value\r
872 //\r
1436aea4 873 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);\r
9060e3ec 874\r
875 //\r
876 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
877 //\r
878 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
879\r
1436aea4
MK
880 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &gAllOne);\r
881 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &Value);\r
9060e3ec 882\r
883 //\r
884 // Write back the original value\r
885 //\r
1436aea4 886 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);\r
9060e3ec 887\r
888 //\r
889 // Restore TPL to its original level\r
890 //\r
891 gBS->RestoreTPL (OldTpl);\r
892\r
893 if (BarLengthValue != NULL) {\r
894 *BarLengthValue = Value;\r
895 }\r
896\r
897 if (OriginalBarValue != NULL) {\r
898 *OriginalBarValue = OriginalValue;\r
899 }\r
900\r
901 if (Value == 0) {\r
902 return EFI_NOT_FOUND;\r
903 } else {\r
904 return EFI_SUCCESS;\r
905 }\r
906}\r
907\r
908/**\r
909 Test whether the device can support given attributes.\r
910\r
911 @param PciIoDevice Pci device instance.\r
912 @param Command Input command register value, and\r
913 returned supported register value.\r
fcdfcdbf 914 @param BridgeControl Input bridge control value for PPB or P2C, and\r
9060e3ec 915 returned supported bridge control value.\r
916 @param OldCommand Returned and stored old command register offset.\r
917 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.\r
918\r
919**/\r
920VOID\r
921PciTestSupportedAttribute (\r
1436aea4
MK
922 IN PCI_IO_DEVICE *PciIoDevice,\r
923 IN OUT UINT16 *Command,\r
924 IN OUT UINT16 *BridgeControl,\r
925 OUT UINT16 *OldCommand,\r
926 OUT UINT16 *OldBridgeControl\r
9060e3ec 927 )\r
928{\r
1436aea4
MK
929 EFI_TPL OldTpl;\r
930 UINT16 CommandValue;\r
9060e3ec 931\r
932 //\r
933 // Preserve the original value\r
934 //\r
935 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);\r
936\r
937 //\r
938 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
939 //\r
1436aea4 940 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
46b4606b 941 CommandValue = *Command | *OldCommand;\r
9060e3ec 942\r
46b4606b 943 PCI_SET_COMMAND_REGISTER (PciIoDevice, CommandValue);\r
944 PCI_READ_COMMAND_REGISTER (PciIoDevice, &CommandValue);\r
9060e3ec 945\r
46b4606b 946 *Command = *Command & CommandValue;\r
9060e3ec 947 //\r
948 // Write back the original value\r
949 //\r
950 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);\r
951\r
952 //\r
953 // Restore TPL to its original level\r
954 //\r
955 gBS->RestoreTPL (OldTpl);\r
956\r
957 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 958 //\r
959 // Preserve the original value\r
960 //\r
961 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);\r
962\r
963 //\r
964 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
965 //\r
966 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
967\r
968 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);\r
969 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);\r
970\r
971 //\r
972 // Write back the original value\r
973 //\r
974 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);\r
975\r
976 //\r
977 // Restore TPL to its original level\r
978 //\r
979 gBS->RestoreTPL (OldTpl);\r
9060e3ec 980 } else {\r
981 *OldBridgeControl = 0;\r
982 *BridgeControl = 0;\r
983 }\r
984}\r
985\r
986/**\r
987 Set the supported or current attributes of a PCI device.\r
988\r
989 @param PciIoDevice Structure pointer for PCI device.\r
990 @param Command Command register value.\r
991 @param BridgeControl Bridge control value for PPB or P2C.\r
992 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
993\r
994**/\r
995VOID\r
996PciSetDeviceAttribute (\r
1436aea4
MK
997 IN PCI_IO_DEVICE *PciIoDevice,\r
998 IN UINT16 Command,\r
999 IN UINT16 BridgeControl,\r
1000 IN UINTN Option\r
9060e3ec 1001 )\r
1002{\r
1003 UINT64 Attributes;\r
1004\r
1005 Attributes = 0;\r
1006\r
1007 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {\r
1008 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
1009 }\r
1010\r
1011 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {\r
1012 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
1013 }\r
1014\r
1015 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
1016 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
1017 }\r
1018\r
1019 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {\r
1020 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1021 }\r
1022\r
1023 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {\r
1024 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
1025 }\r
1026\r
1027 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {\r
1028 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
1029 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
1030 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1031 }\r
1032\r
1033 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {\r
1034 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
1035 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
1036 }\r
1037\r
1038 if (Option == EFI_SET_SUPPORTS) {\r
1436aea4
MK
1039 Attributes |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
1040 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |\r
1041 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |\r
1042 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
1043 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
1044 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9060e3ec 1045\r
e0ee9d93 1046 if (IS_PCI_LPC (&PciIoDevice->Pci)) {\r
1436aea4
MK
1047 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
1048 Attributes |= (mReserveIsaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO : \\r
1049 (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);\r
9060e3ec 1050 }\r
1051\r
1052 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1053 //\r
1054 // For bridge, it should support IDE attributes\r
1055 //\r
1056 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
1057 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
e0ee9d93 1058\r
1059 if (mReserveVgaAliases) {\r
1060 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \\r
1061 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);\r
1062 } else {\r
1063 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \\r
1064 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);\r
1065 }\r
9060e3ec 1066 } else {\r
9060e3ec 1067 if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
1068 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
1069 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
1070 }\r
1071\r
1072 if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
1073 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
1436aea4
MK
1074 Attributes |= (mReserveVgaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO : \\r
1075 (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);\r
9060e3ec 1076 }\r
1077 }\r
1078\r
1436aea4
MK
1079 PciIoDevice->Supports = Attributes;\r
1080 PciIoDevice->Supports &= ((PciIoDevice->Parent->Supports) | \\r
1081 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
1082 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER);\r
9060e3ec 1083 } else {\r
4ed4e19c 1084 //\r
1085 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were\r
1086 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.\r
1087 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize\r
1088 // fields is not from the the ROM BAR of the PCI controller.\r
1089 //\r
1090 if (!PciIoDevice->EmbeddedRom) {\r
1091 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;\r
1092 }\r
1436aea4 1093\r
9060e3ec 1094 PciIoDevice->Attributes = Attributes;\r
1095 }\r
1096}\r
1097\r
1098/**\r
1099 Determine if the device can support Fast Back to Back attribute.\r
1100\r
1101 @param PciIoDevice Pci device instance.\r
1102 @param StatusIndex Status register value.\r
1103\r
1104 @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
1105 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
1106\r
1107**/\r
1108EFI_STATUS\r
1109GetFastBackToBackSupport (\r
1436aea4
MK
1110 IN PCI_IO_DEVICE *PciIoDevice,\r
1111 IN UINT8 StatusIndex\r
9060e3ec 1112 )\r
1113{\r
1436aea4
MK
1114 EFI_PCI_IO_PROTOCOL *PciIo;\r
1115 EFI_STATUS Status;\r
1116 UINT32 StatusRegister;\r
9060e3ec 1117\r
1118 //\r
1119 // Read the status register\r
1120 //\r
1436aea4
MK
1121 PciIo = &PciIoDevice->PciIo;\r
1122 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
9060e3ec 1123 if (EFI_ERROR (Status)) {\r
1124 return EFI_UNSUPPORTED;\r
1125 }\r
1126\r
1127 //\r
1128 // Check the Fast B2B bit\r
1129 //\r
1130 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
1131 return EFI_SUCCESS;\r
1132 } else {\r
1133 return EFI_UNSUPPORTED;\r
1134 }\r
1135}\r
1136\r
1137/**\r
1138 Process the option ROM for all the children of the specified parent PCI device.\r
1139 It can only be used after the first full Option ROM process.\r
1140\r
1141 @param PciIoDevice Pci device instance.\r
1142\r
1143**/\r
1144VOID\r
1145ProcessOptionRomLight (\r
1436aea4 1146 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1147 )\r
1148{\r
1436aea4
MK
1149 PCI_IO_DEVICE *Temp;\r
1150 LIST_ENTRY *CurrentLink;\r
9060e3ec 1151\r
1152 //\r
1153 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1154 //\r
1155 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1156 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
9060e3ec 1157 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1158\r
1159 if (!IsListEmpty (&Temp->ChildList)) {\r
1160 ProcessOptionRomLight (Temp);\r
1161 }\r
1162\r
3f90ac3e 1163 Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp);\r
9060e3ec 1164\r
1165 CurrentLink = CurrentLink->ForwardLink;\r
1166 }\r
1167}\r
1168\r
1169/**\r
1170 Determine the related attributes of all devices under a Root Bridge.\r
1171\r
1172 @param PciIoDevice PCI device instance.\r
1173\r
1174**/\r
1175EFI_STATUS\r
1176DetermineDeviceAttribute (\r
1436aea4 1177 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1178 )\r
1179{\r
1436aea4
MK
1180 UINT16 Command;\r
1181 UINT16 BridgeControl;\r
1182 UINT16 OldCommand;\r
1183 UINT16 OldBridgeControl;\r
1184 BOOLEAN FastB2BSupport;\r
1185 PCI_IO_DEVICE *Temp;\r
1186 LIST_ENTRY *CurrentLink;\r
1187 EFI_STATUS Status;\r
9060e3ec 1188\r
1189 //\r
fcdfcdbf 1190 // For Root Bridge, just copy it by RootBridgeIo protocol\r
9060e3ec 1191 // so as to keep consistent with the actual attribute\r
1192 //\r
1193 if (PciIoDevice->Parent == NULL) {\r
1194 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1436aea4
MK
1195 PciIoDevice->PciRootBridgeIo,\r
1196 &PciIoDevice->Supports,\r
1197 &PciIoDevice->Attributes\r
1198 );\r
9060e3ec 1199 if (EFI_ERROR (Status)) {\r
1200 return Status;\r
1201 }\r
1436aea4 1202\r
5a3a6aa7 1203 //\r
a8035b90 1204 // Assume the PCI Root Bridge supports DAC\r
5a3a6aa7 1205 //\r
6e1e5405 1206 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
1436aea4
MK
1207 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
1208 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
9060e3ec 1209 } else {\r
9060e3ec 1210 //\r
1211 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
1212 // Since some devices only support part of them, it is better to set the\r
1213 // attribute according to its command or bridge control register\r
1214 //\r
1215 Command = EFI_PCI_COMMAND_IO_SPACE |\r
1216 EFI_PCI_COMMAND_MEMORY_SPACE |\r
a8035b90 1217 EFI_PCI_COMMAND_BUS_MASTER |\r
9060e3ec 1218 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1219\r
1220 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1221\r
1222 //\r
1223 // Test whether the device can support attributes above\r
1224 //\r
1225 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
1226\r
1227 //\r
1228 // Set the supported attributes for specified PCI device\r
1229 //\r
1230 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
1231\r
1232 //\r
1233 // Set the current attributes for specified PCI device\r
1234 //\r
1235 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
1236\r
1237 //\r
d9233654
RN
1238 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL\r
1239 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.\r
1240 if (!PciIoDevice->IsPciExp) {\r
1241 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
1242 }\r
9060e3ec 1243 }\r
1244\r
1245 FastB2BSupport = TRUE;\r
1246\r
1247 //\r
1248 // P2C can not support FB2B on the secondary side\r
1249 //\r
1250 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1251 FastB2BSupport = FALSE;\r
1252 }\r
1253\r
1254 //\r
1255 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1256 //\r
1257 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1258 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1436aea4
MK
1259 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1260 Status = DetermineDeviceAttribute (Temp);\r
9060e3ec 1261 if (EFI_ERROR (Status)) {\r
1262 return Status;\r
1263 }\r
1436aea4 1264\r
9060e3ec 1265 //\r
fcdfcdbf 1266 // Detect Fast Back to Back support for the device under the bridge\r
9060e3ec 1267 //\r
1268 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1269 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1270 FastB2BSupport = FALSE;\r
1271 }\r
1272\r
1273 CurrentLink = CurrentLink->ForwardLink;\r
1274 }\r
1436aea4 1275\r
9060e3ec 1276 //\r
1277 // Set or clear Fast Back to Back bit for the whole bridge\r
1278 //\r
1279 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
9060e3ec 1280 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 1281 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1282\r
1283 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1284 FastB2BSupport = FALSE;\r
1285 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1286 } else {\r
1287 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1288 }\r
1289 }\r
1290\r
1291 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1292 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1293 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1294 if (FastB2BSupport) {\r
1295 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1296 } else {\r
1297 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1298 }\r
1299\r
1300 CurrentLink = CurrentLink->ForwardLink;\r
1301 }\r
1302 }\r
1436aea4 1303\r
9060e3ec 1304 //\r
1305 // End for IsListEmpty\r
1306 //\r
1307 return EFI_SUCCESS;\r
1308}\r
1309\r
1310/**\r
1311 This routine is used to update the bar information for those incompatible PCI device.\r
1312\r
1313 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
1314 Bar information.\r
cb8349f0 1315 @param IgnoreOptionRom Output If the option rom of incompatible device need to be ignored.\r
9060e3ec 1316\r
1317 @retval EFI_SUCCESS Successfully updated bar information.\r
1318 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
1319\r
1320**/\r
1321EFI_STATUS\r
1322UpdatePciInfo (\r
cb8349f0
MX
1323 IN OUT PCI_IO_DEVICE *PciIoDevice,\r
1324 OUT BOOLEAN *IgnoreOptionRom\r
9060e3ec 1325 )\r
1326{\r
1436aea4
MK
1327 EFI_STATUS Status;\r
1328 UINTN BarIndex;\r
1329 BOOLEAN SetFlag;\r
1330 VOID *Configuration;\r
1331 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
9060e3ec 1332\r
1333 Configuration = NULL;\r
1334 Status = EFI_SUCCESS;\r
1335\r
ea669c1b 1336 if (gIncompatiblePciDeviceSupport == NULL) {\r
9060e3ec 1337 //\r
1338 // It can only be supported after the Incompatible PCI Device\r
1339 // Support Protocol has been installed\r
1340 //\r
1341 Status = gBS->LocateProtocol (\r
1342 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1343 NULL,\r
1436aea4 1344 (VOID **)&gIncompatiblePciDeviceSupport\r
9060e3ec 1345 );\r
1346 }\r
9060e3ec 1347\r
1436aea4
MK
1348 if (Status == EFI_SUCCESS) {\r
1349 //\r
1350 // Check whether the device belongs to incompatible devices from protocol or not\r
1351 // If it is , then get its special requirement in the ACPI table\r
1352 //\r
1353 Status = gIncompatiblePciDeviceSupport->CheckDevice (\r
1354 gIncompatiblePciDeviceSupport,\r
1355 PciIoDevice->Pci.Hdr.VendorId,\r
1356 PciIoDevice->Pci.Hdr.DeviceId,\r
1357 PciIoDevice->Pci.Hdr.RevisionID,\r
1358 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1359 PciIoDevice->Pci.Device.SubsystemID,\r
1360 &Configuration\r
1361 );\r
9060e3ec 1362 }\r
1363\r
1436aea4 1364 if (EFI_ERROR (Status) || (Configuration == NULL)) {\r
9060e3ec 1365 return EFI_UNSUPPORTED;\r
1366 }\r
1367\r
1368 //\r
1369 // Update PCI device information from the ACPI table\r
1370 //\r
1436aea4 1371 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r
9060e3ec 1372\r
1373 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
9060e3ec 1374 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1375 //\r
1376 // The format is not support\r
1377 //\r
1378 break;\r
1379 }\r
1380\r
cb8349f0
MX
1381 //\r
1382 // According to "Table 20. ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage"\r
1383 // in PI Spec 1.7, Type-specific flags can be set to 0 when Address Translation\r
1384 // Offset == 6 to skip device option ROM (do not probe option rom BAR).\r
1385 //\r
1386 if (((Ptr->AddrTranslationOffset == PCI_MAX_BAR) && (Ptr->SpecificFlag == 0))) {\r
1387 *IgnoreOptionRom = TRUE;\r
1388 Ptr++;\r
1389 continue;\r
1390 }\r
1391\r
063bcff7
RN
1392 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {\r
1393 if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&\r
1394 (Ptr->AddrTranslationOffset != MAX_UINT8) &&\r
1395 (Ptr->AddrTranslationOffset != BarIndex)\r
1436aea4
MK
1396 )\r
1397 {\r
063bcff7
RN
1398 //\r
1399 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).\r
1400 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.\r
1401 // Comparing against MAX_UINT8 is to keep backward compatibility.\r
1402 //\r
1403 continue;\r
1404 }\r
9060e3ec 1405\r
9060e3ec 1406 SetFlag = FALSE;\r
1407 switch (Ptr->ResType) {\r
1436aea4 1408 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
05070c1b
RN
1409\r
1410 //\r
1436aea4 1411 // Make sure the bar is memory type\r
05070c1b 1412 //\r
1436aea4
MK
1413 if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeMem)) {\r
1414 SetFlag = TRUE;\r
1415\r
1416 //\r
1417 // Ignored if granularity is 0.\r
1418 // Ignored if PCI BAR is I/O or 32-bit memory.\r
1419 // If PCI BAR is 64-bit memory and granularity is 32, then\r
1420 // the PCI BAR resource is allocated below 4GB.\r
1421 // If PCI BAR is 64-bit memory and granularity is 64, then\r
1422 // the PCI BAR resource is allocated above 4GB.\r
1423 //\r
1424 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {\r
1425 switch (Ptr->AddrSpaceGranularity) {\r
1426 case 32:\r
1427 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1428 case 64:\r
1429 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1430 break;\r
1431 default:\r
1432 break;\r
1433 }\r
05070c1b 1434 }\r
05070c1b 1435\r
1436aea4
MK
1436 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {\r
1437 switch (Ptr->AddrSpaceGranularity) {\r
1438 case 32:\r
1439 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1440 case 64:\r
1441 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1442 break;\r
1443 default:\r
1444 break;\r
1445 }\r
05070c1b
RN
1446 }\r
1447 }\r
9060e3ec 1448\r
1436aea4 1449 break;\r
9060e3ec 1450\r
1436aea4
MK
1451 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1452\r
1453 //\r
1454 // Make sure the bar is IO type\r
1455 //\r
1456 if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeIo)) {\r
1457 SetFlag = TRUE;\r
1458 }\r
1459\r
1460 break;\r
9060e3ec 1461 }\r
1462\r
1463 if (SetFlag) {\r
9060e3ec 1464 //\r
1465 // Update the new alignment for the device\r
1466 //\r
1467 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1468\r
1469 //\r
1470 // Update the new length for the device\r
1471 //\r
8a93fa1e 1472 if (Ptr->AddrLen != 0) {\r
9060e3ec 1473 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1474 }\r
1475 }\r
1476 }\r
1477\r
1478 Ptr++;\r
1479 }\r
1480\r
1481 FreePool (Configuration);\r
1482\r
1483 return EFI_SUCCESS;\r
1484}\r
1485\r
1486/**\r
1487 This routine will update the alignment with the new alignment.\r
8a93fa1e
RN
1488 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep\r
1489 backward compatibility.\r
9060e3ec 1490\r
1491 @param Alignment Input Old alignment. Output updated alignment.\r
1492 @param NewAlignment New alignment.\r
1493\r
1494**/\r
1495VOID\r
1496SetNewAlign (\r
1436aea4
MK
1497 IN OUT UINT64 *Alignment,\r
1498 IN UINT64 NewAlignment\r
9060e3ec 1499 )\r
1500{\r
1501 UINT64 OldAlignment;\r
1502 UINTN ShiftBit;\r
1503\r
1504 //\r
1505 // The new alignment is the same as the original,\r
1506 // so skip it\r
1507 //\r
8a93fa1e 1508 if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {\r
1436aea4 1509 return;\r
9060e3ec 1510 }\r
1436aea4 1511\r
9060e3ec 1512 //\r
1513 // Check the validity of the parameter\r
1514 //\r
1436aea4
MK
1515 if ((NewAlignment != EVEN_ALIGN) &&\r
1516 (NewAlignment != SQUAD_ALIGN) &&\r
1517 (NewAlignment != DQUAD_ALIGN))\r
1518 {\r
9060e3ec 1519 *Alignment = NewAlignment;\r
1436aea4 1520 return;\r
9060e3ec 1521 }\r
1522\r
1436aea4
MK
1523 OldAlignment = (*Alignment) + 1;\r
1524 ShiftBit = 0;\r
9060e3ec 1525\r
1526 //\r
1527 // Get the first non-zero hex value of the length\r
1528 //\r
1529 while ((OldAlignment & 0x0F) == 0x00) {\r
1530 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1436aea4 1531 ShiftBit += 4;\r
9060e3ec 1532 }\r
1533\r
1534 //\r
1535 // Adjust the alignment to even, quad or double quad boundary\r
1536 //\r
8a93fa1e 1537 if (NewAlignment == EVEN_ALIGN) {\r
9060e3ec 1538 if ((OldAlignment & 0x01) != 0) {\r
1539 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1540 }\r
8a93fa1e 1541 } else if (NewAlignment == SQUAD_ALIGN) {\r
9060e3ec 1542 if ((OldAlignment & 0x03) != 0) {\r
1543 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1544 }\r
8a93fa1e 1545 } else if (NewAlignment == DQUAD_ALIGN) {\r
9060e3ec 1546 if ((OldAlignment & 0x07) != 0) {\r
1547 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1548 }\r
1549 }\r
1550\r
1551 //\r
1552 // Update the old value\r
1553 //\r
1436aea4
MK
1554 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1555 *Alignment = NewAlignment;\r
9060e3ec 1556\r
1436aea4 1557 return;\r
9060e3ec 1558}\r
1559\r
1560/**\r
1561 Parse PCI IOV VF bar information and fill them into PCI device instance.\r
1562\r
1563 @param PciIoDevice Pci device instance.\r
1564 @param Offset Bar offset.\r
1565 @param BarIndex Bar index.\r
1566\r
1567 @return Next bar offset.\r
1568\r
1569**/\r
1570UINTN\r
1571PciIovParseVfBar (\r
1572 IN PCI_IO_DEVICE *PciIoDevice,\r
1573 IN UINTN Offset,\r
1574 IN UINTN BarIndex\r
1575 )\r
1576{\r
1577 UINT32 Value;\r
1578 UINT32 OriginalValue;\r
1579 UINT32 Mask;\r
9060e3ec 1580 EFI_STATUS Status;\r
1581\r
1582 //\r
1583 // Ensure it is called properly\r
1584 //\r
1585 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1586 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1587 return 0;\r
1588 }\r
1589\r
1590 OriginalValue = 0;\r
1591 Value = 0;\r
1592\r
1593 Status = VfBarExisted (\r
1436aea4
MK
1594 PciIoDevice,\r
1595 Offset,\r
1596 &Value,\r
1597 &OriginalValue\r
1598 );\r
9060e3ec 1599\r
1600 if (EFI_ERROR (Status)) {\r
1601 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1602 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1603 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1604\r
1605 //\r
1606 // Scan all the BARs anyway\r
1607 //\r
1436aea4 1608 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;\r
9060e3ec 1609 return Offset + 4;\r
1610 }\r
1611\r
1436aea4 1612 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;\r
aa75dfec 1613 if ((Value & 0x01) != 0) {\r
9060e3ec 1614 //\r
1615 // Device I/Os. Impossible\r
1616 //\r
1617 ASSERT (FALSE);\r
1618 return Offset + 4;\r
9060e3ec 1619 } else {\r
1436aea4 1620 Mask = 0xfffffff0;\r
9060e3ec 1621\r
1622 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1623\r
1624 switch (Value & 0x07) {\r
1436aea4
MK
1625 //\r
1626 // memory space; anywhere in 32 bit address space\r
1627 //\r
1628 case 0x00:\r
1629 if ((Value & 0x08) != 0) {\r
1630 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1631 } else {\r
1632 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1633 }\r
9060e3ec 1634\r
1436aea4
MK
1635 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1636 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1637\r
1638 //\r
1639 // Adjust Length\r
1640 //\r
1641 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1642 //\r
1643 // Adjust Alignment\r
1644 //\r
1645 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1646 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1647 }\r
9060e3ec 1648\r
1436aea4 1649 break;\r
9060e3ec 1650\r
1651 //\r
1436aea4 1652 // memory space; anywhere in 64 bit address space\r
9060e3ec 1653 //\r
1436aea4
MK
1654 case 0x04:\r
1655 if ((Value & 0x08) != 0) {\r
1656 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1657 } else {\r
1658 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1659 }\r
9060e3ec 1660\r
1436aea4
MK
1661 //\r
1662 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1663 // is regarded as an extension for the first bar. As a result\r
1664 // the sizing will be conducted on combined 64 bit value\r
1665 // Here just store the masked first 32bit value for future size\r
1666 // calculation\r
1667 //\r
1668 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1669 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
9060e3ec 1670\r
1436aea4
MK
1671 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1672 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1673 }\r
9060e3ec 1674\r
1436aea4
MK
1675 //\r
1676 // Increment the offset to point to next DWORD\r
1677 //\r
1678 Offset += 4;\r
9060e3ec 1679\r
1436aea4
MK
1680 Status = VfBarExisted (\r
1681 PciIoDevice,\r
1682 Offset,\r
1683 &Value,\r
1684 &OriginalValue\r
1685 );\r
9060e3ec 1686\r
1436aea4
MK
1687 if (EFI_ERROR (Status)) {\r
1688 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1689 return Offset + 4;\r
1690 }\r
9060e3ec 1691\r
1436aea4
MK
1692 //\r
1693 // Fix the length to support some special 64 bit BAR\r
1694 //\r
1695 Value |= ((UINT32)-1 << HighBitSet32 (Value));\r
9060e3ec 1696\r
1436aea4
MK
1697 //\r
1698 // Calculate the size of 64bit bar\r
1699 //\r
1700 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);\r
9060e3ec 1701\r
1436aea4
MK
1702 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);\r
1703 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1704 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
9060e3ec 1705\r
1436aea4
MK
1706 //\r
1707 // Adjust Length\r
1708 //\r
1709 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1710 //\r
1711 // Adjust Alignment\r
1712 //\r
1713 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1714 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1715 }\r
9060e3ec 1716\r
1436aea4 1717 break;\r
9060e3ec 1718\r
1719 //\r
1436aea4 1720 // reserved\r
9060e3ec 1721 //\r
1436aea4
MK
1722 default:\r
1723 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1724 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1725 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
9060e3ec 1726\r
1436aea4
MK
1727 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1728 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1729 }\r
9060e3ec 1730\r
1436aea4 1731 break;\r
9060e3ec 1732 }\r
1733 }\r
d1102dba 1734\r
9060e3ec 1735 //\r
1736 // Check the length again so as to keep compatible with some special bars\r
1737 //\r
1738 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1739 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1740 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1741 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1742 }\r
d1102dba 1743\r
9060e3ec 1744 //\r
1745 // Increment number of bar\r
1746 //\r
1747 return Offset + 4;\r
1748}\r
1749\r
1750/**\r
1751 Parse PCI bar information and fill them into PCI device instance.\r
1752\r
1753 @param PciIoDevice Pci device instance.\r
1754 @param Offset Bar offset.\r
1755 @param BarIndex Bar index.\r
1756\r
1757 @return Next bar offset.\r
1758\r
1759**/\r
1760UINTN\r
1761PciParseBar (\r
1762 IN PCI_IO_DEVICE *PciIoDevice,\r
1763 IN UINTN Offset,\r
1764 IN UINTN BarIndex\r
1765 )\r
1766{\r
1767 UINT32 Value;\r
1768 UINT32 OriginalValue;\r
1769 UINT32 Mask;\r
9060e3ec 1770 EFI_STATUS Status;\r
1771\r
1772 OriginalValue = 0;\r
1773 Value = 0;\r
1774\r
1775 Status = BarExisted (\r
1776 PciIoDevice,\r
1777 Offset,\r
1778 &Value,\r
1779 &OriginalValue\r
1780 );\r
1781\r
1782 if (EFI_ERROR (Status)) {\r
1783 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1784 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1785 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1786\r
1787 //\r
1788 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1789 //\r
1436aea4 1790 PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;\r
9060e3ec 1791 return Offset + 4;\r
1792 }\r
1793\r
05070c1b 1794 PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;\r
1436aea4 1795 PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;\r
9060e3ec 1796 if ((Value & 0x01) != 0) {\r
1797 //\r
1798 // Device I/Os\r
1799 //\r
1800 Mask = 0xfffffffc;\r
1801\r
1802 if ((Value & 0xFFFF0000) != 0) {\r
1803 //\r
1804 // It is a IO32 bar\r
1805 //\r
1806 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1807 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1808 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1809 } else {\r
1810 //\r
1811 // It is a IO16 bar\r
1812 //\r
1813 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1814 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1815 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1816 }\r
1436aea4 1817\r
9060e3ec 1818 //\r
fcdfcdbf 1819 // Workaround. Some platforms implement IO bar with 0 length\r
9060e3ec 1820 // Need to treat it as no-bar\r
1821 //\r
1822 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1436aea4 1823 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE)0;\r
9060e3ec 1824 }\r
1825\r
1436aea4 1826 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
9060e3ec 1827 } else {\r
1436aea4 1828 Mask = 0xfffffff0;\r
9060e3ec 1829\r
1830 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1831\r
1832 switch (Value & 0x07) {\r
1436aea4
MK
1833 //\r
1834 // memory space; anywhere in 32 bit address space\r
1835 //\r
1836 case 0x00:\r
1837 if ((Value & 0x08) != 0) {\r
1838 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1839 } else {\r
1840 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1841 }\r
9060e3ec 1842\r
1436aea4
MK
1843 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1844 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1845 //\r
1846 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1847 //\r
1848 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1849 } else {\r
1850 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1851 }\r
1852\r
1853 break;\r
1854\r
1855 //\r
1856 // memory space; anywhere in 64 bit address space\r
1857 //\r
1858 case 0x04:\r
1859 if ((Value & 0x08) != 0) {\r
1860 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1861 } else {\r
1862 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1863 }\r
9060e3ec 1864\r
9060e3ec 1865 //\r
1436aea4
MK
1866 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1867 // is regarded as an extension for the first bar. As a result\r
1868 // the sizing will be conducted on combined 64 bit value\r
1869 // Here just store the masked first 32bit value for future size\r
1870 // calculation\r
9060e3ec 1871 //\r
1436aea4 1872 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
9060e3ec 1873 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1874\r
1436aea4
MK
1875 //\r
1876 // Increment the offset to point to next DWORD\r
1877 //\r
1878 Offset += 4;\r
9060e3ec 1879\r
1436aea4
MK
1880 Status = BarExisted (\r
1881 PciIoDevice,\r
1882 Offset,\r
1883 &Value,\r
1884 &OriginalValue\r
1885 );\r
9060e3ec 1886\r
1436aea4
MK
1887 if (EFI_ERROR (Status)) {\r
1888 //\r
1889 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1890 //\r
1891 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1892 //\r
1893 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1894 //\r
1895 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1896 return Offset + 4;\r
1897 }\r
1898 }\r
9060e3ec 1899\r
1436aea4
MK
1900 //\r
1901 // Fix the length to support some special 64 bit BAR\r
1902 //\r
1903 if (Value == 0) {\r
1904 DEBUG ((DEBUG_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));\r
1905 Value = (UINT32)-1;\r
1906 } else {\r
1907 Value |= ((UINT32)(-1) << HighBitSet32 (Value));\r
1908 }\r
9060e3ec 1909\r
9060e3ec 1910 //\r
1436aea4 1911 // Calculate the size of 64bit bar\r
9060e3ec 1912 //\r
1436aea4
MK
1913 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);\r
1914\r
1915 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);\r
1916 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1917 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
9060e3ec 1918 //\r
1436aea4 1919 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
9060e3ec 1920 //\r
1436aea4
MK
1921 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1922 } else {\r
1923 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
9060e3ec 1924 }\r
9060e3ec 1925\r
1436aea4 1926 break;\r
9060e3ec 1927\r
1928 //\r
1436aea4 1929 // reserved\r
9060e3ec 1930 //\r
1436aea4
MK
1931 default:\r
1932 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1933 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1934 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1935 //\r
1936 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1937 //\r
1938 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1939 } else {\r
1940 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1941 }\r
9060e3ec 1942\r
1436aea4 1943 break;\r
9060e3ec 1944 }\r
1945 }\r
1946\r
1947 //\r
1948 // Check the length again so as to keep compatible with some special bars\r
1949 //\r
1950 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1951 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1952 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1953 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1954 }\r
1955\r
1956 //\r
1957 // Increment number of bar\r
1958 //\r
1959 return Offset + 4;\r
1960}\r
1961\r
1962/**\r
1963 This routine is used to initialize the bar of a PCI device.\r
1964\r
1965 @param PciIoDevice Pci device instance.\r
1966\r
1967 @note It can be called typically when a device is going to be rejected.\r
1968\r
1969**/\r
1970VOID\r
1971InitializePciDevice (\r
1436aea4 1972 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1973 )\r
1974{\r
1436aea4
MK
1975 EFI_PCI_IO_PROTOCOL *PciIo;\r
1976 UINT8 Offset;\r
9060e3ec 1977\r
1978 PciIo = &(PciIoDevice->PciIo);\r
1979\r
1980 //\r
1981 // Put all the resource apertures\r
1982 // Resource base is set to all ones so as to indicate its resource\r
fcdfcdbf 1983 // has not been allocated\r
9060e3ec 1984 //\r
1985 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1986 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1987 }\r
1988}\r
1989\r
1990/**\r
1991 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1992\r
1993 @param PciIoDevice PCI-PCI bridge device instance.\r
1994\r
1995**/\r
1996VOID\r
1997InitializePpb (\r
1436aea4 1998 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 1999 )\r
2000{\r
1436aea4 2001 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 2002\r
2003 PciIo = &(PciIoDevice->PciIo);\r
2004\r
2005 //\r
2006 // Put all the resource apertures including IO16\r
2007 // Io32, pMem32, pMem64 to quiescent state\r
2008 // Resource base all ones, Resource limit all zeros\r
2009 //\r
2010 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
2011 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
2012\r
2013 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
2014 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
2015\r
2016 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
2017 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
2018\r
2019 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
2020 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
2021\r
2022 //\r
2023 // Don't support use io32 as for now\r
2024 //\r
2025 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
2026 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
2027\r
2028 //\r
2029 // Force Interrupt line to zero for cards that come up randomly\r
2030 //\r
2031 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2032}\r
2033\r
2034/**\r
2035 This routine is used to initialize the bar of a PCI Card Bridge device.\r
2036\r
2037 @param PciIoDevice PCI Card bridge device.\r
2038\r
2039**/\r
2040VOID\r
2041InitializeP2C (\r
1436aea4 2042 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 2043 )\r
2044{\r
1436aea4 2045 EFI_PCI_IO_PROTOCOL *PciIo;\r
9060e3ec 2046\r
2047 PciIo = &(PciIoDevice->PciIo);\r
2048\r
2049 //\r
2050 // Put all the resource apertures including IO16\r
2051 // Io32, pMem32, pMem64 to quiescent state(\r
2052 // Resource base all ones, Resource limit all zeros\r
2053 //\r
2054 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
2055 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
2056\r
2057 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
2058 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
2059\r
2060 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
2061 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
2062\r
2063 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
2064 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
2065\r
2066 //\r
2067 // Force Interrupt line to zero for cards that come up randomly\r
2068 //\r
2069 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2070}\r
2071\r
1e947f9b 2072/**\r
995d8b85
JY
2073 Authenticate the PCI device by using DeviceSecurityProtocol.\r
2074\r
2075 @param PciIoDevice PCI device.\r
2076\r
2077 @retval EFI_SUCCESS The device passes the authentication.\r
2078 @return not EFI_SUCCESS The device failes the authentication or\r
2079 unexpected error happen during authentication.\r
1e947f9b 2080**/\r
995d8b85
JY
2081EFI_STATUS\r
2082AuthenticatePciDevice (\r
1436aea4 2083 IN PCI_IO_DEVICE *PciIoDevice\r
995d8b85
JY
2084 )\r
2085{\r
2086 EDKII_DEVICE_IDENTIFIER DeviceIdentifier;\r
2087 EFI_STATUS Status;\r
2088\r
2089 if (mDeviceSecurityProtocol != NULL) {\r
2090 //\r
2091 // Prepare the parameter\r
2092 //\r
2093 DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;\r
2094 CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);\r
2095 DeviceIdentifier.DeviceHandle = NULL;\r
1436aea4
MK
2096 Status = gBS->InstallMultipleProtocolInterfaces (\r
2097 &DeviceIdentifier.DeviceHandle,\r
2098 &gEfiDevicePathProtocolGuid,\r
2099 PciIoDevice->DevicePath,\r
2100 &gEdkiiDeviceIdentifierTypePciGuid,\r
2101 &PciIoDevice->PciIo,\r
2102 NULL\r
2103 );\r
2104 if (EFI_ERROR (Status)) {\r
995d8b85
JY
2105 return Status;\r
2106 }\r
2107\r
2108 //\r
2109 // Do DeviceAuthentication\r
2110 //\r
2111 Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);\r
2112 //\r
2113 // Always uninstall, because they are only for Authentication.\r
2114 // No need to check return Status.\r
2115 //\r
2116 gBS->UninstallMultipleProtocolInterfaces (\r
1436aea4
MK
2117 DeviceIdentifier.DeviceHandle,\r
2118 &gEfiDevicePathProtocolGuid,\r
2119 PciIoDevice->DevicePath,\r
2120 &gEdkiiDeviceIdentifierTypePciGuid,\r
2121 &PciIoDevice->PciIo,\r
2122 NULL\r
2123 );\r
995d8b85
JY
2124 return Status;\r
2125 }\r
2126\r
2127 //\r
2128 // Device Security Protocol is not found, just return success\r
2129 //\r
2130 return EFI_SUCCESS;\r
2131}\r
2132\r
c095122d
RN
2133/**\r
2134 Checks if PCI device is Root Bridge.\r
2135\r
2136 @param PciIoDevice Instance of PCI device\r
2137\r
2138 @retval TRUE Device is Root Bridge\r
2139 @retval FALSE Device is not Root Bridge\r
2140\r
2141**/\r
2142BOOLEAN\r
2143IsRootBridge (\r
2144 IN PCI_IO_DEVICE *PciIoDevice\r
2145 )\r
2146{\r
2147 if (PciIoDevice->Parent == NULL) {\r
2148 return TRUE;\r
2149 } else {\r
2150 return FALSE;\r
2151 }\r
2152}\r
2153\r
9060e3ec 2154/**\r
fcdfcdbf 2155 Create and initialize general PCI I/O device instance for\r
9060e3ec 2156 PCI device/bridge device/hotplug bridge device.\r
2157\r
fcdfcdbf 2158 @param Bridge Parent bridge instance.\r
9060e3ec 2159 @param Pci Input Pci information block.\r
2160 @param Bus Device Bus NO.\r
2161 @param Device Device device NO.\r
2162 @param Func Device func NO.\r
2163\r
2164 @return Instance of PCI device. NULL means no instance created.\r
2165\r
2166**/\r
2167PCI_IO_DEVICE *\r
2168CreatePciIoDevice (\r
1436aea4
MK
2169 IN PCI_IO_DEVICE *Bridge,\r
2170 IN PCI_TYPE00 *Pci,\r
2171 IN UINT8 Bus,\r
2172 IN UINT8 Device,\r
2173 IN UINT8 Func\r
9060e3ec 2174 )\r
2175{\r
d4048391 2176 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 2177 EFI_PCI_IO_PROTOCOL *PciIo;\r
2178 EFI_STATUS Status;\r
2179\r
2180 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
2181 if (PciIoDevice == NULL) {\r
2182 return NULL;\r
2183 }\r
2184\r
1436aea4
MK
2185 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
2186 PciIoDevice->Handle = NULL;\r
2187 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2188 PciIoDevice->DevicePath = NULL;\r
2189 PciIoDevice->BusNumber = Bus;\r
2190 PciIoDevice->DeviceNumber = Device;\r
2191 PciIoDevice->FunctionNumber = Func;\r
2192 PciIoDevice->Decodes = 0;\r
9060e3ec 2193\r
2194 if (gFullEnumeration) {\r
2195 PciIoDevice->Allocated = FALSE;\r
2196 } else {\r
2197 PciIoDevice->Allocated = TRUE;\r
2198 }\r
2199\r
1436aea4
MK
2200 PciIoDevice->Registered = FALSE;\r
2201 PciIoDevice->Attributes = 0;\r
2202 PciIoDevice->Supports = 0;\r
2203 PciIoDevice->BusOverride = FALSE;\r
2204 PciIoDevice->AllOpRomProcessed = FALSE;\r
9060e3ec 2205\r
1436aea4 2206 PciIoDevice->IsPciExp = FALSE;\r
9060e3ec 2207\r
2208 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
2209\r
2210 //\r
2211 // Initialize the PCI I/O instance structure\r
2212 //\r
2213 InitializePciIoInstance (PciIoDevice);\r
2214 InitializePciDriverOverrideInstance (PciIoDevice);\r
2215 InitializePciLoadFile2 (PciIoDevice);\r
2216 PciIo = &PciIoDevice->PciIo;\r
2217\r
b0bc24af
AW
2218 //\r
2219 // Create a device path for this PCI device and store it into its private data\r
2220 //\r
2221 CreatePciDevicePath (\r
2222 Bridge->DevicePath,\r
2223 PciIoDevice\r
2224 );\r
2225\r
9060e3ec 2226 //\r
2227 // Detect if PCI Express Device\r
2228 //\r
2229 PciIoDevice->PciExpressCapabilityOffset = 0;\r
1436aea4
MK
2230 Status = LocateCapabilityRegBlock (\r
2231 PciIoDevice,\r
2232 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2233 &PciIoDevice->PciExpressCapabilityOffset,\r
2234 NULL\r
2235 );\r
9060e3ec 2236 if (!EFI_ERROR (Status)) {\r
2237 PciIoDevice->IsPciExp = TRUE;\r
2238 }\r
2239\r
995d8b85
JY
2240 //\r
2241 // Now we can do the authentication check for the device.\r
2242 //\r
2243 Status = AuthenticatePciDevice (PciIoDevice);\r
2244 //\r
2245 // If authentication fails, skip this device.\r
2246 //\r
1436aea4 2247 if (EFI_ERROR (Status)) {\r
995d8b85
JY
2248 if (PciIoDevice->DevicePath != NULL) {\r
2249 FreePool (PciIoDevice->DevicePath);\r
2250 }\r
1436aea4 2251\r
995d8b85
JY
2252 FreePool (PciIoDevice);\r
2253 return NULL;\r
2254 }\r
2255\r
c095122d
RN
2256 //\r
2257 // Check if device's parent is not Root Bridge\r
2258 //\r
2259 if (PcdGetBool (PcdAriSupport) && !IsRootBridge (Bridge)) {\r
d4048391 2260 //\r
2261 // Check if the device is an ARI device.\r
2262 //\r
2263 Status = LocatePciExpressCapabilityRegBlock (\r
2264 PciIoDevice,\r
2265 EFI_PCIE_CAPABILITY_ID_ARI,\r
2266 &PciIoDevice->AriCapabilityOffset,\r
2267 NULL\r
2268 );\r
2269 if (!EFI_ERROR (Status)) {\r
2270 //\r
2271 // We need to enable ARI feature before calculate BusReservation,\r
2272 // because FirstVFOffset and VFStride may change after that.\r
2273 //\r
2274 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2275 UINT32 Data32;\r
9060e3ec 2276\r
d4048391 2277 //\r
2278 // Check if its parent supports ARI forwarding.\r
2279 //\r
2280 ParentPciIo = &Bridge->PciIo;\r
2281 ParentPciIo->Pci.Read (\r
1436aea4
MK
2282 ParentPciIo,\r
2283 EfiPciIoWidthUint32,\r
2284 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2285 1,\r
2286 &Data32\r
2287 );\r
d4048391 2288 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
2289 //\r
2290 // ARI forward support in bridge, so enable it.\r
2291 //\r
2292 ParentPciIo->Pci.Read (\r
1436aea4
MK
2293 ParentPciIo,\r
2294 EfiPciIoWidthUint32,\r
2295 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2296 1,\r
2297 &Data32\r
2298 );\r
d4048391 2299 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2300 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2301 ParentPciIo->Pci.Write (\r
1436aea4
MK
2302 ParentPciIo,\r
2303 EfiPciIoWidthUint32,\r
2304 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2305 1,\r
2306 &Data32\r
2307 );\r
d4048391 2308 DEBUG ((\r
87000d77 2309 DEBUG_INFO,\r
8db6a82c
RN
2310 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2311 Bridge->BusNumber,\r
2312 Bridge->DeviceNumber,\r
2313 Bridge->FunctionNumber\r
d4048391 2314 ));\r
2315 }\r
2316 }\r
9060e3ec 2317\r
87000d77 2318 DEBUG ((DEBUG_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2319 }\r
9060e3ec 2320 }\r
2321\r
2322 //\r
d4048391 2323 // Initialization for SR-IOV\r
9060e3ec 2324 //\r
9060e3ec 2325\r
d4048391 2326 if (PcdGetBool (PcdSrIovSupport)) {\r
2327 Status = LocatePciExpressCapabilityRegBlock (\r
2328 PciIoDevice,\r
2329 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2330 &PciIoDevice->SrIovCapabilityOffset,\r
2331 NULL\r
2332 );\r
2333 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
2334 UINT32 SupportedPageSize;\r
2335 UINT16 VFStride;\r
2336 UINT16 FirstVFOffset;\r
2337 UINT16 Data16;\r
2338 UINT32 PFRid;\r
2339 UINT32 LastVF;\r
d4048391 2340\r
2341 //\r
2342 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2343 //\r
1436aea4 2344 if (PcdGetBool (PcdAriSupport) && (PciIoDevice->AriCapabilityOffset != 0)) {\r
d4048391 2345 PciIo->Pci.Read (\r
2346 PciIo,\r
2347 EfiPciIoWidthUint16,\r
2348 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2349 1,\r
2350 &Data16\r
2351 );\r
2352 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2353 PciIo->Pci.Write (\r
2354 PciIo,\r
2355 EfiPciIoWidthUint16,\r
2356 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2357 1,\r
2358 &Data16\r
2359 );\r
2360 }\r
9060e3ec 2361\r
d4048391 2362 //\r
2363 // Calculate SystemPageSize\r
2364 //\r
9060e3ec 2365\r
d4048391 2366 PciIo->Pci.Read (\r
2367 PciIo,\r
2368 EfiPciIoWidthUint32,\r
2369 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2370 1,\r
8db6a82c 2371 &SupportedPageSize\r
d4048391 2372 );\r
8db6a82c 2373 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2374 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2375\r
2376 PciIo->Pci.Write (\r
2377 PciIo,\r
2378 EfiPciIoWidthUint32,\r
2379 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2380 1,\r
2381 &PciIoDevice->SystemPageSize\r
2382 );\r
d4048391 2383 //\r
2384 // Adjust SystemPageSize for Alignment usage later\r
2385 //\r
2386 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2387\r
d4048391 2388 //\r
2389 // Calculate BusReservation for PCI IOV\r
2390 //\r
9060e3ec 2391\r
d4048391 2392 //\r
2393 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2394 //\r
2395 PciIo->Pci.Read (\r
2396 PciIo,\r
2397 EfiPciIoWidthUint16,\r
2398 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2399 1,\r
2400 &FirstVFOffset\r
2401 );\r
d4048391 2402 PciIo->Pci.Read (\r
2403 PciIo,\r
2404 EfiPciIoWidthUint16,\r
2405 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2406 1,\r
2407 &PciIoDevice->InitialVFs\r
2408 );\r
d4048391 2409 PciIo->Pci.Read (\r
2410 PciIo,\r
2411 EfiPciIoWidthUint16,\r
2412 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2413 1,\r
2414 &VFStride\r
2415 );\r
d4048391 2416 //\r
2417 // Calculate LastVF\r
2418 //\r
1436aea4 2419 PFRid = EFI_PCI_RID (Bus, Device, Func);\r
d4048391 2420 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2421\r
d4048391 2422 //\r
2423 // Calculate ReservedBusNum for this PF\r
2424 //\r
2425 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
8db6a82c 2426\r
d4048391 2427 DEBUG ((\r
87000d77 2428 DEBUG_INFO,\r
8db6a82c 2429 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
1436aea4
MK
2430 SupportedPageSize,\r
2431 PciIoDevice->SystemPageSize >> 12,\r
2432 FirstVFOffset\r
d4048391 2433 ));\r
d4048391 2434 DEBUG ((\r
87000d77 2435 DEBUG_INFO,\r
8db6a82c 2436 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
1436aea4
MK
2437 PciIoDevice->InitialVFs,\r
2438 PciIoDevice->ReservedBusNum,\r
2439 PciIoDevice->SrIovCapabilityOffset\r
d4048391 2440 ));\r
2441 }\r
9060e3ec 2442 }\r
2443\r
d4048391 2444 if (PcdGetBool (PcdMrIovSupport)) {\r
2445 Status = LocatePciExpressCapabilityRegBlock (\r
2446 PciIoDevice,\r
2447 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2448 &PciIoDevice->MrIovCapabilityOffset,\r
2449 NULL\r
2450 );\r
2451 if (!EFI_ERROR (Status)) {\r
87000d77 2452 DEBUG ((DEBUG_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2453 }\r
2454 }\r
9060e3ec 2455\r
0785c619
LH
2456 PciIoDevice->ResizableBarOffset = 0;\r
2457 if (PcdGetBool (PcdPcieResizableBarSupport)) {\r
2458 Status = LocatePciExpressCapabilityRegBlock (\r
2459 PciIoDevice,\r
2460 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,\r
2461 &PciIoDevice->ResizableBarOffset,\r
2462 NULL\r
2463 );\r
2464 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
2465 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl;\r
2466 UINT32 Offset;\r
0785c619 2467 Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)\r
1436aea4 2468 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),\r
0785c619 2469 PciIo->Pci.Read (\r
1436aea4
MK
2470 PciIo,\r
2471 EfiPciIoWidthUint8,\r
2472 Offset,\r
2473 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),\r
2474 &ResizableBarControl\r
2475 );\r
0785c619
LH
2476 PciIoDevice->ResizableBarNumber = ResizableBarControl.Bits.ResizableBarNumber;\r
2477 PciProgramResizableBar (PciIoDevice, PciResizableBarMax);\r
2478 }\r
2479 }\r
2480\r
9060e3ec 2481 //\r
2482 // Initialize the reserved resource list\r
2483 //\r
2484 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2485\r
2486 //\r
2487 // Initialize the driver list\r
2488 //\r
2489 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2490\r
2491 //\r
2492 // Initialize the child list\r
2493 //\r
2494 InitializeListHead (&PciIoDevice->ChildList);\r
2495\r
2496 return PciIoDevice;\r
2497}\r
2498\r
2499/**\r
2500 This routine is used to enumerate entire pci bus system\r
2501 in a given platform.\r
2502\r
2503 It is only called on the second start on the same Root Bridge.\r
2504\r
2505 @param Controller Parent bridge handler.\r
2506\r
2507 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2508 @retval other Some error occurred when enumerating the pci bus system.\r
2509\r
2510**/\r
2511EFI_STATUS\r
2512PciEnumeratorLight (\r
1436aea4 2513 IN EFI_HANDLE Controller\r
9060e3ec 2514 )\r
2515{\r
1436aea4
MK
2516 EFI_STATUS Status;\r
2517 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2518 PCI_IO_DEVICE *RootBridgeDev;\r
2519 UINT16 MinBus;\r
2520 UINT16 MaxBus;\r
2521 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
9060e3ec 2522\r
2523 MinBus = 0;\r
2524 MaxBus = PCI_MAX_BUS;\r
2525 Descriptors = NULL;\r
2526\r
2527 //\r
2528 // If this root bridge has been already enumerated, then return successfully\r
2529 //\r
2530 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2531 return EFI_SUCCESS;\r
2532 }\r
2533\r
2534 //\r
2535 // Open pci root bridge io protocol\r
2536 //\r
2537 Status = gBS->OpenProtocol (\r
2538 Controller,\r
2539 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 2540 (VOID **)&PciRootBridgeIo,\r
9060e3ec 2541 gPciBusDriverBinding.DriverBindingHandle,\r
2542 Controller,\r
2543 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2544 );\r
1436aea4 2545 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
9060e3ec 2546 return Status;\r
2547 }\r
2548\r
1436aea4 2549 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&Descriptors);\r
9060e3ec 2550\r
2551 if (EFI_ERROR (Status)) {\r
2552 return Status;\r
2553 }\r
2554\r
2555 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
9060e3ec 2556 //\r
2557 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2558 //\r
2559 RootBridgeDev = CreateRootBridge (Controller);\r
2560\r
2561 if (RootBridgeDev == NULL) {\r
2562 Descriptors++;\r
2563 continue;\r
2564 }\r
2565\r
2566 //\r
fcdfcdbf 2567 // Record the root bridge-io protocol\r
9060e3ec 2568 //\r
2569 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2570\r
2571 Status = PciPciDeviceInfoCollector (\r
2572 RootBridgeDev,\r
1436aea4 2573 (UINT8)MinBus\r
9060e3ec 2574 );\r
2575\r
2576 if (!EFI_ERROR (Status)) {\r
9060e3ec 2577 //\r
2578 // Remove those PCI devices which are rejected when full enumeration\r
2579 //\r
2580 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2581\r
2582 //\r
2583 // Process option rom light\r
2584 //\r
2585 ProcessOptionRomLight (RootBridgeDev);\r
2586\r
2587 //\r
2588 // Determine attributes for all devices under this root bridge\r
2589 //\r
2590 DetermineDeviceAttribute (RootBridgeDev);\r
2591\r
2592 //\r
2593 // If successfully, insert the node into device pool\r
2594 //\r
2595 InsertRootBridge (RootBridgeDev);\r
2596 } else {\r
9060e3ec 2597 //\r
fcdfcdbf 2598 // If unsuccessfully, destroy the entire node\r
9060e3ec 2599 //\r
2600 DestroyRootBridge (RootBridgeDev);\r
2601 }\r
2602\r
2603 Descriptors++;\r
2604 }\r
2605\r
2606 return EFI_SUCCESS;\r
2607}\r
2608\r
2609/**\r
2610 Get bus range from PCI resource descriptor list.\r
2611\r
2612 @param Descriptors A pointer to the address space descriptor.\r
2613 @param MinBus The min bus returned.\r
2614 @param MaxBus The max bus returned.\r
2615 @param BusRange The bus range returned.\r
2616\r
2617 @retval EFI_SUCCESS Successfully got bus range.\r
2618 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2619\r
2620**/\r
2621EFI_STATUS\r
2622PciGetBusRange (\r
2623 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2624 OUT UINT16 *MinBus,\r
2625 OUT UINT16 *MaxBus,\r
2626 OUT UINT16 *BusRange\r
2627 )\r
2628{\r
2629 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2630 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2631 if (MinBus != NULL) {\r
1436aea4 2632 *MinBus = (UINT16)(*Descriptors)->AddrRangeMin;\r
9060e3ec 2633 }\r
2634\r
2635 if (MaxBus != NULL) {\r
1436aea4 2636 *MaxBus = (UINT16)(*Descriptors)->AddrRangeMax;\r
9060e3ec 2637 }\r
2638\r
2639 if (BusRange != NULL) {\r
1436aea4 2640 *BusRange = (UINT16)(*Descriptors)->AddrLen;\r
9060e3ec 2641 }\r
2642\r
2643 return EFI_SUCCESS;\r
2644 }\r
2645\r
2646 (*Descriptors)++;\r
2647 }\r
2648\r
2649 return EFI_NOT_FOUND;\r
2650}\r
2651\r
2652/**\r
2653 This routine can be used to start the root bridge.\r
2654\r
2655 @param RootBridgeDev Pci device instance.\r
2656\r
2657 @retval EFI_SUCCESS This device started.\r
2658 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2659\r
2660**/\r
2661EFI_STATUS\r
2662StartManagingRootBridge (\r
1436aea4 2663 IN PCI_IO_DEVICE *RootBridgeDev\r
9060e3ec 2664 )\r
2665{\r
1436aea4
MK
2666 EFI_HANDLE RootBridgeHandle;\r
2667 EFI_STATUS Status;\r
2668 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 2669\r
2670 //\r
2671 // Get the root bridge handle\r
2672 //\r
2673 RootBridgeHandle = RootBridgeDev->Handle;\r
2674 PciRootBridgeIo = NULL;\r
2675\r
2676 //\r
2677 // Get the pci root bridge io protocol\r
2678 //\r
2679 Status = gBS->OpenProtocol (\r
2680 RootBridgeHandle,\r
2681 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 2682 (VOID **)&PciRootBridgeIo,\r
9060e3ec 2683 gPciBusDriverBinding.DriverBindingHandle,\r
2684 RootBridgeHandle,\r
2685 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2686 );\r
2687\r
1436aea4 2688 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
9060e3ec 2689 return Status;\r
2690 }\r
2691\r
2692 //\r
2693 // Store the PciRootBridgeIo protocol into root bridge private data\r
2694 //\r
2695 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2696\r
2697 return EFI_SUCCESS;\r
9060e3ec 2698}\r
2699\r
2700/**\r
2701 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2702\r
2703 @param PciIoDevice Pci device instance.\r
2704\r
2705 @retval TRUE This device should be rejected.\r
2706 @retval FALSE This device shouldn't be rejected.\r
2707\r
2708**/\r
2709BOOLEAN\r
2710IsPciDeviceRejected (\r
1436aea4 2711 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 2712 )\r
2713{\r
2714 EFI_STATUS Status;\r
2715 UINT32 TestValue;\r
2716 UINT32 OldValue;\r
2717 UINT32 Mask;\r
2718 UINT8 BarOffset;\r
2719\r
2720 //\r
2721 // PPB should be skip!\r
2722 //\r
2723 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2724 return FALSE;\r
2725 }\r
2726\r
2727 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2728 //\r
2729 // Only test base registers for P2C\r
2730 //\r
2731 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
1436aea4
MK
2732 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2733 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
9060e3ec 2734 if (EFI_ERROR (Status)) {\r
2735 continue;\r
2736 }\r
2737\r
2738 TestValue = TestValue & Mask;\r
2739 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2740 //\r
2741 // The bar isn't programed, so it should be rejected\r
2742 //\r
2743 return TRUE;\r
2744 }\r
2745 }\r
2746\r
2747 return FALSE;\r
2748 }\r
2749\r
2750 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2751 //\r
2752 // Test PCI devices\r
2753 //\r
2754 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2755 if (EFI_ERROR (Status)) {\r
2756 continue;\r
2757 }\r
2758\r
2759 if ((TestValue & 0x01) != 0) {\r
9060e3ec 2760 //\r
2761 // IO Bar\r
2762 //\r
2763 Mask = 0xFFFFFFFC;\r
2764 TestValue = TestValue & Mask;\r
2765 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2766 return TRUE;\r
2767 }\r
9060e3ec 2768 } else {\r
9060e3ec 2769 //\r
2770 // Mem Bar\r
2771 //\r
2772 Mask = 0xFFFFFFF0;\r
2773 TestValue = TestValue & Mask;\r
2774\r
2775 if ((TestValue & 0x07) == 0x04) {\r
9060e3ec 2776 //\r
2777 // Mem64 or PMem64\r
2778 //\r
2779 BarOffset += sizeof (UINT32);\r
2780 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
9060e3ec 2781 //\r
2782 // Test its high 32-Bit BAR\r
2783 //\r
2784 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2785 if (TestValue == OldValue) {\r
2786 return TRUE;\r
2787 }\r
2788 }\r
9060e3ec 2789 } else {\r
9060e3ec 2790 //\r
2791 // Mem32 or PMem32\r
2792 //\r
2793 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2794 return TRUE;\r
2795 }\r
2796 }\r
2797 }\r
2798 }\r
2799\r
2800 return FALSE;\r
2801}\r
2802\r
2803/**\r
2804 Reset all bus number from specific bridge.\r
2805\r
2806 @param Bridge Parent specific bridge.\r
2807 @param StartBusNumber Start bus number.\r
2808\r
2809**/\r
2810VOID\r
2811ResetAllPpbBusNumber (\r
1436aea4
MK
2812 IN PCI_IO_DEVICE *Bridge,\r
2813 IN UINT8 StartBusNumber\r
9060e3ec 2814 )\r
2815{\r
1436aea4
MK
2816 EFI_STATUS Status;\r
2817 PCI_TYPE00 Pci;\r
2818 UINT8 Device;\r
2819 UINT32 Register;\r
2820 UINT8 Func;\r
2821 UINT64 Address;\r
2822 UINT8 SecondaryBus;\r
2823 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 2824\r
2825 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2826\r
2827 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2828 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
9060e3ec 2829 //\r
2830 // Check to see whether a pci device is present\r
2831 //\r
2832 Status = PciDevicePresent (\r
2833 PciRootBridgeIo,\r
2834 &Pci,\r
2835 StartBusNumber,\r
2836 Device,\r
2837 Func\r
2838 );\r
2839\r
1436aea4 2840 if (EFI_ERROR (Status) && (Func == 0)) {\r
25a26646
JS
2841 //\r
2842 // go to next device if there is no Function 0\r
2843 //\r
2844 break;\r
2845 }\r
2846\r
9060e3ec 2847 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
1436aea4
MK
2848 Register = 0;\r
2849 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2850 Status = PciRootBridgeIo->Pci.Read (\r
2851 PciRootBridgeIo,\r
2852 EfiPciWidthUint32,\r
2853 Address,\r
2854 1,\r
2855 &Register\r
2856 );\r
9060e3ec 2857 SecondaryBus = (UINT8)(Register >> 8);\r
2858\r
2859 if (SecondaryBus != 0) {\r
2860 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2861 }\r
2862\r
2863 //\r
2864 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2865 //\r
2866 Register &= 0xFF000000;\r
1436aea4
MK
2867 Status = PciRootBridgeIo->Pci.Write (\r
2868 PciRootBridgeIo,\r
2869 EfiPciWidthUint32,\r
2870 Address,\r
2871 1,\r
2872 &Register\r
2873 );\r
9060e3ec 2874 }\r
2875\r
1436aea4 2876 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {\r
9060e3ec 2877 //\r
2878 // Skip sub functions, this is not a multi function device\r
2879 //\r
2880 Func = PCI_MAX_FUNC;\r
2881 }\r
2882 }\r
2883 }\r
2884}\r