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