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