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