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