]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
MdeModulePkg/Bus: Fix typos in comments
[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
ed356b9e 602 // PCI bridge supporting non-standard I/O window alignment less than 4K.\r
1ef26783 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
ed356b9e 609 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.\r
1ef26783 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
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
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
05070c1b
RN
1419\r
1420 //\r
1421 // Ignored if granularity is 0.\r
1422 // Ignored if PCI BAR is I/O or 32-bit memory.\r
1423 // If PCI BAR is 64-bit memory and granularity is 32, then\r
1424 // the PCI BAR resource is allocated below 4GB.\r
1425 // If PCI BAR is 64-bit memory and granularity is 64, then\r
1426 // the PCI BAR resource is allocated above 4GB.\r
1427 //\r
1428 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {\r
1429 switch (Ptr->AddrSpaceGranularity) {\r
1430 case 32:\r
1431 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1432 case 64:\r
1433 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1434 break;\r
1435 default:\r
1436 break;\r
1437 }\r
1438 }\r
1439\r
1440 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {\r
1441 switch (Ptr->AddrSpaceGranularity) {\r
1442 case 32:\r
1443 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1444 case 64:\r
1445 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;\r
1446 break;\r
1447 default:\r
1448 break;\r
1449 }\r
1450 }\r
9060e3ec 1451 }\r
1452 break;\r
1453\r
1454 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1455\r
1456 //\r
1457 // Make sure the bar is IO type\r
1458 //\r
1459 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1460 SetFlag = TRUE;\r
1461 }\r
1462 break;\r
1463 }\r
1464\r
1465 if (SetFlag) {\r
1466\r
1467 //\r
1468 // Update the new alignment for the device\r
1469 //\r
1470 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1471\r
1472 //\r
1473 // Update the new length for the device\r
1474 //\r
1475 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
1476 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1477 }\r
1478 }\r
1479 }\r
1480\r
1481 Ptr++;\r
1482 }\r
1483\r
1484 FreePool (Configuration);\r
1485\r
1486 return EFI_SUCCESS;\r
1487}\r
1488\r
1489/**\r
1490 This routine will update the alignment with the new alignment.\r
1491\r
1492 @param Alignment Input Old alignment. Output updated alignment.\r
1493 @param NewAlignment New alignment.\r
1494\r
1495**/\r
1496VOID\r
1497SetNewAlign (\r
1498 IN OUT UINT64 *Alignment,\r
1499 IN UINT64 NewAlignment\r
1500 )\r
1501{\r
1502 UINT64 OldAlignment;\r
1503 UINTN ShiftBit;\r
1504\r
1505 //\r
1506 // The new alignment is the same as the original,\r
1507 // so skip it\r
1508 //\r
1509 if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1510 return ;\r
1511 }\r
1512 //\r
1513 // Check the validity of the parameter\r
1514 //\r
1515 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
1516 NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1517 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1518 *Alignment = NewAlignment;\r
1519 return ;\r
1520 }\r
1521\r
1522 OldAlignment = (*Alignment) + 1;\r
1523 ShiftBit = 0;\r
1524\r
1525 //\r
1526 // Get the first non-zero hex value of the length\r
1527 //\r
1528 while ((OldAlignment & 0x0F) == 0x00) {\r
1529 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1530 ShiftBit += 4;\r
1531 }\r
1532\r
1533 //\r
1534 // Adjust the alignment to even, quad or double quad boundary\r
1535 //\r
1536 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
1537 if ((OldAlignment & 0x01) != 0) {\r
1538 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1539 }\r
1540 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
1541 if ((OldAlignment & 0x03) != 0) {\r
1542 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1543 }\r
1544 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
1545 if ((OldAlignment & 0x07) != 0) {\r
1546 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1547 }\r
1548 }\r
1549\r
1550 //\r
1551 // Update the old value\r
1552 //\r
1553 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1554 *Alignment = NewAlignment;\r
1555\r
1556 return ;\r
1557}\r
1558\r
1559/**\r
1560 Parse PCI IOV VF bar information and fill them into PCI device instance.\r
1561\r
1562 @param PciIoDevice Pci device instance.\r
1563 @param Offset Bar offset.\r
1564 @param BarIndex Bar index.\r
1565\r
1566 @return Next bar offset.\r
1567\r
1568**/\r
1569UINTN\r
1570PciIovParseVfBar (\r
1571 IN PCI_IO_DEVICE *PciIoDevice,\r
1572 IN UINTN Offset,\r
1573 IN UINTN BarIndex\r
1574 )\r
1575{\r
1576 UINT32 Value;\r
1577 UINT32 OriginalValue;\r
1578 UINT32 Mask;\r
9060e3ec 1579 EFI_STATUS Status;\r
1580\r
1581 //\r
1582 // Ensure it is called properly\r
1583 //\r
1584 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1585 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1586 return 0;\r
1587 }\r
1588\r
1589 OriginalValue = 0;\r
1590 Value = 0;\r
1591\r
1592 Status = VfBarExisted (\r
1593 PciIoDevice,\r
1594 Offset,\r
1595 &Value,\r
1596 &OriginalValue\r
1597 );\r
1598\r
1599 if (EFI_ERROR (Status)) {\r
1600 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1601 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1602 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1603\r
1604 //\r
1605 // Scan all the BARs anyway\r
1606 //\r
d4048391 1607 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
9060e3ec 1608 return Offset + 4;\r
1609 }\r
1610\r
d4048391 1611 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
aa75dfec 1612 if ((Value & 0x01) != 0) {\r
9060e3ec 1613 //\r
1614 // Device I/Os. Impossible\r
1615 //\r
1616 ASSERT (FALSE);\r
1617 return Offset + 4;\r
1618\r
1619 } else {\r
1620\r
1621 Mask = 0xfffffff0;\r
1622\r
1623 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1624\r
1625 switch (Value & 0x07) {\r
1626\r
1627 //\r
1628 //memory space; anywhere in 32 bit address space\r
1629 //\r
1630 case 0x00:\r
aa75dfec 1631 if ((Value & 0x08) != 0) {\r
9060e3ec 1632 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1633 } else {\r
1634 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1635 }\r
1636\r
1637 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1638 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1639\r
1640 //\r
1641 // Adjust Length\r
1642 //\r
1643 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1644 //\r
1645 // Adjust Alignment\r
1646 //\r
1647 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1648 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1649 }\r
1650\r
1651 break;\r
1652\r
1653 //\r
1654 // memory space; anywhere in 64 bit address space\r
1655 //\r
1656 case 0x04:\r
aa75dfec 1657 if ((Value & 0x08) != 0) {\r
9060e3ec 1658 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1659 } else {\r
1660 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1661 }\r
1662\r
1663 //\r
1664 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1665 // is regarded as an extension for the first bar. As a result\r
1666 // the sizing will be conducted on combined 64 bit value\r
1667 // Here just store the masked first 32bit value for future size\r
1668 // calculation\r
1669 //\r
1670 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1671 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1672\r
1673 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1674 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1675 }\r
1676\r
1677 //\r
1678 // Increment the offset to point to next DWORD\r
1679 //\r
1680 Offset += 4;\r
1681\r
1682 Status = VfBarExisted (\r
1683 PciIoDevice,\r
1684 Offset,\r
1685 &Value,\r
1686 &OriginalValue\r
1687 );\r
1688\r
1689 if (EFI_ERROR (Status)) {\r
1690 return Offset + 4;\r
1691 }\r
1692\r
1693 //\r
1694 // Fix the length to support some spefic 64 bit BAR\r
1695 //\r
c0394e04 1696 Value |= ((UINT32) -1 << HighBitSet32 (Value));\r
9060e3ec 1697\r
1698 //\r
1699 // Calculate the size of 64bit bar\r
1700 //\r
1701 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1702\r
1703 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1704 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1705 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1706\r
1707 //\r
1708 // Adjust Length\r
1709 //\r
1710 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1711 //\r
1712 // Adjust Alignment\r
1713 //\r
1714 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1715 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1716 }\r
1717\r
1718 break;\r
1719\r
1720 //\r
1721 // reserved\r
1722 //\r
1723 default:\r
1724 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1725 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1726 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1727\r
1728 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1729 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1730 }\r
1731\r
1732 break;\r
1733 }\r
1734 }\r
1735 \r
1736 //\r
1737 // Check the length again so as to keep compatible with some special bars\r
1738 //\r
1739 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1740 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1741 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1742 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1743 }\r
1744 \r
1745 //\r
1746 // Increment number of bar\r
1747 //\r
1748 return Offset + 4;\r
1749}\r
1750\r
1751/**\r
1752 Parse PCI bar information and fill them into PCI device instance.\r
1753\r
1754 @param PciIoDevice Pci device instance.\r
1755 @param Offset Bar offset.\r
1756 @param BarIndex Bar index.\r
1757\r
1758 @return Next bar offset.\r
1759\r
1760**/\r
1761UINTN\r
1762PciParseBar (\r
1763 IN PCI_IO_DEVICE *PciIoDevice,\r
1764 IN UINTN Offset,\r
1765 IN UINTN BarIndex\r
1766 )\r
1767{\r
1768 UINT32 Value;\r
1769 UINT32 OriginalValue;\r
1770 UINT32 Mask;\r
9060e3ec 1771 EFI_STATUS Status;\r
1772\r
1773 OriginalValue = 0;\r
1774 Value = 0;\r
1775\r
1776 Status = BarExisted (\r
1777 PciIoDevice,\r
1778 Offset,\r
1779 &Value,\r
1780 &OriginalValue\r
1781 );\r
1782\r
1783 if (EFI_ERROR (Status)) {\r
1784 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1785 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1786 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1787\r
1788 //\r
1789 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1790 //\r
1791 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1792 return Offset + 4;\r
1793 }\r
1794\r
05070c1b 1795 PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;\r
9060e3ec 1796 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1797 if ((Value & 0x01) != 0) {\r
1798 //\r
1799 // Device I/Os\r
1800 //\r
1801 Mask = 0xfffffffc;\r
1802\r
1803 if ((Value & 0xFFFF0000) != 0) {\r
1804 //\r
1805 // It is a IO32 bar\r
1806 //\r
1807 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1808 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1809 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1810\r
1811 } else {\r
1812 //\r
1813 // It is a IO16 bar\r
1814 //\r
1815 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1816 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1817 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1818\r
1819 }\r
1820 //\r
1821 // Workaround. Some platforms inplement IO bar with 0 length\r
1822 // Need to treat it as no-bar\r
1823 //\r
1824 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1825 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1826 }\r
1827\r
9060e3ec 1828 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1829\r
1830 } else {\r
1831\r
1832 Mask = 0xfffffff0;\r
1833\r
1834 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1835\r
1836 switch (Value & 0x07) {\r
1837\r
1838 //\r
1839 //memory space; anywhere in 32 bit address space\r
1840 //\r
1841 case 0x00:\r
1842 if ((Value & 0x08) != 0) {\r
1843 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1844 } else {\r
1845 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1846 }\r
1847\r
1848 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1849 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1850 //\r
1851 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1852 //\r
1853 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1854 } else {\r
1855 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1856 }\r
1857 break;\r
1858\r
1859 //\r
1860 // memory space; anywhere in 64 bit address space\r
1861 //\r
1862 case 0x04:\r
1863 if ((Value & 0x08) != 0) {\r
1864 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1865 } else {\r
1866 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1867 }\r
1868\r
1869 //\r
1870 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1871 // is regarded as an extension for the first bar. As a result\r
1872 // the sizing will be conducted on combined 64 bit value\r
1873 // Here just store the masked first 32bit value for future size\r
1874 // calculation\r
1875 //\r
1876 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1877 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1878\r
1879 //\r
1880 // Increment the offset to point to next DWORD\r
1881 //\r
1882 Offset += 4;\r
1883\r
1884 Status = BarExisted (\r
1885 PciIoDevice,\r
1886 Offset,\r
1887 &Value,\r
1888 &OriginalValue\r
1889 );\r
1890\r
1891 if (EFI_ERROR (Status)) {\r
1892 //\r
1893 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1894 //\r
1895 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1896 //\r
1897 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1898 //\r
1899 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
5c13180c 1900 return Offset + 4;\r
9060e3ec 1901 }\r
9060e3ec 1902 }\r
1903\r
1904 //\r
1905 // Fix the length to support some spefic 64 bit BAR\r
1906 //\r
5c13180c
RN
1907 if (Value == 0) {\r
1908 DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));\r
1909 Value = (UINT32) -1;\r
1910 } else {\r
1911 Value |= ((UINT32)(-1) << HighBitSet32 (Value));\r
1912 }\r
9060e3ec 1913\r
1914 //\r
1915 // Calculate the size of 64bit bar\r
1916 //\r
1917 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1918\r
1919 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1920 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1921 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1922 //\r
1923 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1924 //\r
1925 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1926 } else {\r
1927 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1928 }\r
1929\r
1930 break;\r
1931\r
1932 //\r
1933 // reserved\r
1934 //\r
1935 default:\r
1936 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1937 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1938 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1939 //\r
1940 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1941 //\r
1942 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1943 } else {\r
1944 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1945 }\r
1946 break;\r
1947 }\r
1948 }\r
1949\r
1950 //\r
1951 // Check the length again so as to keep compatible with some special bars\r
1952 //\r
1953 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1954 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1955 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1956 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1957 }\r
1958\r
1959 //\r
1960 // Increment number of bar\r
1961 //\r
1962 return Offset + 4;\r
1963}\r
1964\r
1965/**\r
1966 This routine is used to initialize the bar of a PCI device.\r
1967\r
1968 @param PciIoDevice Pci device instance.\r
1969\r
1970 @note It can be called typically when a device is going to be rejected.\r
1971\r
1972**/\r
1973VOID\r
1974InitializePciDevice (\r
1975 IN PCI_IO_DEVICE *PciIoDevice\r
1976 )\r
1977{\r
1978 EFI_PCI_IO_PROTOCOL *PciIo;\r
1979 UINT8 Offset;\r
1980\r
1981 PciIo = &(PciIoDevice->PciIo);\r
1982\r
1983 //\r
1984 // Put all the resource apertures\r
1985 // Resource base is set to all ones so as to indicate its resource\r
1986 // has not been alloacted\r
1987 //\r
1988 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1989 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1990 }\r
1991}\r
1992\r
1993/**\r
1994 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1995\r
1996 @param PciIoDevice PCI-PCI bridge device instance.\r
1997\r
1998**/\r
1999VOID\r
2000InitializePpb (\r
2001 IN PCI_IO_DEVICE *PciIoDevice\r
2002 )\r
2003{\r
2004 EFI_PCI_IO_PROTOCOL *PciIo;\r
2005\r
2006 PciIo = &(PciIoDevice->PciIo);\r
2007\r
2008 //\r
2009 // Put all the resource apertures including IO16\r
2010 // Io32, pMem32, pMem64 to quiescent state\r
2011 // Resource base all ones, Resource limit all zeros\r
2012 //\r
2013 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
2014 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
2015\r
2016 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
2017 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
2018\r
2019 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
2020 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
2021\r
2022 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
2023 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
2024\r
2025 //\r
2026 // Don't support use io32 as for now\r
2027 //\r
2028 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
2029 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
2030\r
2031 //\r
2032 // Force Interrupt line to zero for cards that come up randomly\r
2033 //\r
2034 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2035}\r
2036\r
2037/**\r
2038 This routine is used to initialize the bar of a PCI Card Bridge device.\r
2039\r
2040 @param PciIoDevice PCI Card bridge device.\r
2041\r
2042**/\r
2043VOID\r
2044InitializeP2C (\r
2045 IN PCI_IO_DEVICE *PciIoDevice\r
2046 )\r
2047{\r
2048 EFI_PCI_IO_PROTOCOL *PciIo;\r
2049\r
2050 PciIo = &(PciIoDevice->PciIo);\r
2051\r
2052 //\r
2053 // Put all the resource apertures including IO16\r
2054 // Io32, pMem32, pMem64 to quiescent state(\r
2055 // Resource base all ones, Resource limit all zeros\r
2056 //\r
2057 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
2058 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
2059\r
2060 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
2061 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
2062\r
2063 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
2064 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
2065\r
2066 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
2067 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
2068\r
2069 //\r
2070 // Force Interrupt line to zero for cards that come up randomly\r
2071 //\r
2072 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2073}\r
2074\r
2075/**\r
2076 Create and initiliaze general PCI I/O device instance for\r
2077 PCI device/bridge device/hotplug bridge device.\r
2078\r
2079 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2080 @param Pci Input Pci information block.\r
2081 @param Bus Device Bus NO.\r
2082 @param Device Device device NO.\r
2083 @param Func Device func NO.\r
2084\r
2085 @return Instance of PCI device. NULL means no instance created.\r
2086\r
2087**/\r
2088PCI_IO_DEVICE *\r
2089CreatePciIoDevice (\r
d4048391 2090 IN PCI_IO_DEVICE *Bridge,\r
9060e3ec 2091 IN PCI_TYPE00 *Pci,\r
2092 IN UINT8 Bus,\r
2093 IN UINT8 Device,\r
2094 IN UINT8 Func\r
2095 )\r
2096{\r
d4048391 2097 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 2098 EFI_PCI_IO_PROTOCOL *PciIo;\r
2099 EFI_STATUS Status;\r
2100\r
2101 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
2102 if (PciIoDevice == NULL) {\r
2103 return NULL;\r
2104 }\r
2105\r
2106 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
2107 PciIoDevice->Handle = NULL;\r
d4048391 2108 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
9060e3ec 2109 PciIoDevice->DevicePath = NULL;\r
2110 PciIoDevice->BusNumber = Bus;\r
2111 PciIoDevice->DeviceNumber = Device;\r
2112 PciIoDevice->FunctionNumber = Func;\r
2113 PciIoDevice->Decodes = 0;\r
2114\r
2115 if (gFullEnumeration) {\r
2116 PciIoDevice->Allocated = FALSE;\r
2117 } else {\r
2118 PciIoDevice->Allocated = TRUE;\r
2119 }\r
2120\r
2121 PciIoDevice->Registered = FALSE;\r
2122 PciIoDevice->Attributes = 0;\r
2123 PciIoDevice->Supports = 0;\r
2124 PciIoDevice->BusOverride = FALSE;\r
2125 PciIoDevice->AllOpRomProcessed = FALSE;\r
2126\r
2127 PciIoDevice->IsPciExp = FALSE;\r
2128\r
2129 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
2130\r
2131 //\r
2132 // Initialize the PCI I/O instance structure\r
2133 //\r
2134 InitializePciIoInstance (PciIoDevice);\r
2135 InitializePciDriverOverrideInstance (PciIoDevice);\r
2136 InitializePciLoadFile2 (PciIoDevice);\r
2137 PciIo = &PciIoDevice->PciIo;\r
2138\r
b0bc24af
AW
2139 //\r
2140 // Create a device path for this PCI device and store it into its private data\r
2141 //\r
2142 CreatePciDevicePath (\r
2143 Bridge->DevicePath,\r
2144 PciIoDevice\r
2145 );\r
2146\r
9060e3ec 2147 //\r
2148 // Detect if PCI Express Device\r
2149 //\r
2150 PciIoDevice->PciExpressCapabilityOffset = 0;\r
2151 Status = LocateCapabilityRegBlock (\r
2152 PciIoDevice,\r
2153 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2154 &PciIoDevice->PciExpressCapabilityOffset,\r
2155 NULL\r
2156 );\r
2157 if (!EFI_ERROR (Status)) {\r
2158 PciIoDevice->IsPciExp = TRUE;\r
2159 }\r
2160\r
d4048391 2161 if (PcdGetBool (PcdAriSupport)) {\r
2162 //\r
2163 // Check if the device is an ARI device.\r
2164 //\r
2165 Status = LocatePciExpressCapabilityRegBlock (\r
2166 PciIoDevice,\r
2167 EFI_PCIE_CAPABILITY_ID_ARI,\r
2168 &PciIoDevice->AriCapabilityOffset,\r
2169 NULL\r
2170 );\r
2171 if (!EFI_ERROR (Status)) {\r
2172 //\r
2173 // We need to enable ARI feature before calculate BusReservation,\r
2174 // because FirstVFOffset and VFStride may change after that.\r
2175 //\r
2176 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2177 UINT32 Data32;\r
9060e3ec 2178\r
d4048391 2179 //\r
2180 // Check if its parent supports ARI forwarding.\r
2181 //\r
2182 ParentPciIo = &Bridge->PciIo;\r
2183 ParentPciIo->Pci.Read (\r
2184 ParentPciIo, \r
2185 EfiPciIoWidthUint32,\r
2186 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2187 1,\r
2188 &Data32\r
2189 );\r
2190 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
2191 //\r
2192 // ARI forward support in bridge, so enable it.\r
2193 //\r
2194 ParentPciIo->Pci.Read (\r
2195 ParentPciIo,\r
2196 EfiPciIoWidthUint32,\r
2197 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2198 1,\r
2199 &Data32\r
2200 );\r
2201 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2202 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2203 ParentPciIo->Pci.Write (\r
2204 ParentPciIo,\r
2205 EfiPciIoWidthUint32,\r
2206 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2207 1,\r
2208 &Data32\r
2209 );\r
2210 DEBUG ((\r
2211 EFI_D_INFO,\r
8db6a82c
RN
2212 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2213 Bridge->BusNumber,\r
2214 Bridge->DeviceNumber,\r
2215 Bridge->FunctionNumber\r
d4048391 2216 ));\r
2217 }\r
2218 }\r
9060e3ec 2219\r
8db6a82c 2220 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2221 }\r
9060e3ec 2222 }\r
2223\r
2224 //\r
d4048391 2225 // Initialization for SR-IOV\r
9060e3ec 2226 //\r
9060e3ec 2227\r
d4048391 2228 if (PcdGetBool (PcdSrIovSupport)) {\r
2229 Status = LocatePciExpressCapabilityRegBlock (\r
2230 PciIoDevice,\r
2231 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2232 &PciIoDevice->SrIovCapabilityOffset,\r
2233 NULL\r
2234 );\r
2235 if (!EFI_ERROR (Status)) {\r
8db6a82c 2236 UINT32 SupportedPageSize;\r
d4048391 2237 UINT16 VFStride;\r
2238 UINT16 FirstVFOffset;\r
2239 UINT16 Data16;\r
2240 UINT32 PFRid;\r
2241 UINT32 LastVF;\r
2242\r
2243 //\r
2244 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2245 //\r
2246 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {\r
2247 PciIo->Pci.Read (\r
2248 PciIo,\r
2249 EfiPciIoWidthUint16,\r
2250 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2251 1,\r
2252 &Data16\r
2253 );\r
2254 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2255 PciIo->Pci.Write (\r
2256 PciIo,\r
2257 EfiPciIoWidthUint16,\r
2258 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2259 1,\r
2260 &Data16\r
2261 );\r
2262 }\r
9060e3ec 2263\r
d4048391 2264 //\r
2265 // Calculate SystemPageSize\r
2266 //\r
9060e3ec 2267\r
d4048391 2268 PciIo->Pci.Read (\r
2269 PciIo,\r
2270 EfiPciIoWidthUint32,\r
2271 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2272 1,\r
8db6a82c 2273 &SupportedPageSize\r
d4048391 2274 );\r
8db6a82c 2275 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2276 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2277\r
2278 PciIo->Pci.Write (\r
2279 PciIo,\r
2280 EfiPciIoWidthUint32,\r
2281 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2282 1,\r
2283 &PciIoDevice->SystemPageSize\r
2284 );\r
d4048391 2285 //\r
2286 // Adjust SystemPageSize for Alignment usage later\r
2287 //\r
2288 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2289\r
d4048391 2290 //\r
2291 // Calculate BusReservation for PCI IOV\r
2292 //\r
9060e3ec 2293\r
d4048391 2294 //\r
2295 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2296 //\r
2297 PciIo->Pci.Read (\r
2298 PciIo,\r
2299 EfiPciIoWidthUint16,\r
2300 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2301 1,\r
2302 &FirstVFOffset\r
2303 );\r
d4048391 2304 PciIo->Pci.Read (\r
2305 PciIo,\r
2306 EfiPciIoWidthUint16,\r
2307 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2308 1,\r
2309 &PciIoDevice->InitialVFs\r
2310 );\r
d4048391 2311 PciIo->Pci.Read (\r
2312 PciIo,\r
2313 EfiPciIoWidthUint16,\r
2314 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2315 1,\r
2316 &VFStride\r
2317 );\r
d4048391 2318 //\r
2319 // Calculate LastVF\r
2320 //\r
2321 PFRid = EFI_PCI_RID(Bus, Device, Func);\r
2322 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2323\r
d4048391 2324 //\r
2325 // Calculate ReservedBusNum for this PF\r
2326 //\r
2327 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
8db6a82c 2328\r
d4048391 2329 DEBUG ((\r
2330 EFI_D_INFO,\r
8db6a82c
RN
2331 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
2332 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset\r
d4048391 2333 ));\r
d4048391 2334 DEBUG ((\r
2335 EFI_D_INFO,\r
8db6a82c
RN
2336 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
2337 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset\r
d4048391 2338 ));\r
2339 }\r
9060e3ec 2340 }\r
2341\r
d4048391 2342 if (PcdGetBool (PcdMrIovSupport)) {\r
2343 Status = LocatePciExpressCapabilityRegBlock (\r
2344 PciIoDevice,\r
2345 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2346 &PciIoDevice->MrIovCapabilityOffset,\r
2347 NULL\r
2348 );\r
2349 if (!EFI_ERROR (Status)) {\r
8db6a82c 2350 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2351 }\r
2352 }\r
9060e3ec 2353\r
2354 //\r
2355 // Initialize the reserved resource list\r
2356 //\r
2357 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2358\r
2359 //\r
2360 // Initialize the driver list\r
2361 //\r
2362 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2363\r
2364 //\r
2365 // Initialize the child list\r
2366 //\r
2367 InitializeListHead (&PciIoDevice->ChildList);\r
2368\r
2369 return PciIoDevice;\r
2370}\r
2371\r
2372/**\r
2373 This routine is used to enumerate entire pci bus system\r
2374 in a given platform.\r
2375\r
2376 It is only called on the second start on the same Root Bridge.\r
2377\r
2378 @param Controller Parent bridge handler.\r
2379\r
2380 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2381 @retval other Some error occurred when enumerating the pci bus system.\r
2382\r
2383**/\r
2384EFI_STATUS\r
2385PciEnumeratorLight (\r
2386 IN EFI_HANDLE Controller\r
2387 )\r
2388{\r
2389\r
2390 EFI_STATUS Status;\r
2391 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2392 PCI_IO_DEVICE *RootBridgeDev;\r
2393 UINT16 MinBus;\r
2394 UINT16 MaxBus;\r
2395 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
2396\r
2397 MinBus = 0;\r
2398 MaxBus = PCI_MAX_BUS;\r
2399 Descriptors = NULL;\r
2400\r
2401 //\r
2402 // If this root bridge has been already enumerated, then return successfully\r
2403 //\r
2404 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2405 return EFI_SUCCESS;\r
2406 }\r
2407\r
2408 //\r
2409 // Open pci root bridge io protocol\r
2410 //\r
2411 Status = gBS->OpenProtocol (\r
2412 Controller,\r
2413 &gEfiPciRootBridgeIoProtocolGuid,\r
2414 (VOID **) &PciRootBridgeIo,\r
2415 gPciBusDriverBinding.DriverBindingHandle,\r
2416 Controller,\r
2417 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2418 );\r
2419 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2420 return Status;\r
2421 }\r
2422\r
2423 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2424\r
2425 if (EFI_ERROR (Status)) {\r
2426 return Status;\r
2427 }\r
2428\r
2429 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
2430\r
2431 //\r
2432 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2433 //\r
2434 RootBridgeDev = CreateRootBridge (Controller);\r
2435\r
2436 if (RootBridgeDev == NULL) {\r
2437 Descriptors++;\r
2438 continue;\r
2439 }\r
2440\r
2441 //\r
2442 // Record the root bridgeio protocol\r
2443 //\r
2444 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2445\r
2446 Status = PciPciDeviceInfoCollector (\r
2447 RootBridgeDev,\r
2448 (UINT8) MinBus\r
2449 );\r
2450\r
2451 if (!EFI_ERROR (Status)) {\r
2452\r
2453 //\r
2454 // Remove those PCI devices which are rejected when full enumeration\r
2455 //\r
2456 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2457\r
2458 //\r
2459 // Process option rom light\r
2460 //\r
2461 ProcessOptionRomLight (RootBridgeDev);\r
2462\r
2463 //\r
2464 // Determine attributes for all devices under this root bridge\r
2465 //\r
2466 DetermineDeviceAttribute (RootBridgeDev);\r
2467\r
2468 //\r
2469 // If successfully, insert the node into device pool\r
2470 //\r
2471 InsertRootBridge (RootBridgeDev);\r
2472 } else {\r
2473\r
2474 //\r
2475 // If unsuccessly, destroy the entire node\r
2476 //\r
2477 DestroyRootBridge (RootBridgeDev);\r
2478 }\r
2479\r
2480 Descriptors++;\r
2481 }\r
2482\r
2483 return EFI_SUCCESS;\r
2484}\r
2485\r
2486/**\r
2487 Get bus range from PCI resource descriptor list.\r
2488\r
2489 @param Descriptors A pointer to the address space descriptor.\r
2490 @param MinBus The min bus returned.\r
2491 @param MaxBus The max bus returned.\r
2492 @param BusRange The bus range returned.\r
2493\r
2494 @retval EFI_SUCCESS Successfully got bus range.\r
2495 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2496\r
2497**/\r
2498EFI_STATUS\r
2499PciGetBusRange (\r
2500 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2501 OUT UINT16 *MinBus,\r
2502 OUT UINT16 *MaxBus,\r
2503 OUT UINT16 *BusRange\r
2504 )\r
2505{\r
2506 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2507 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2508 if (MinBus != NULL) {\r
2509 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
2510 }\r
2511\r
2512 if (MaxBus != NULL) {\r
2513 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
2514 }\r
2515\r
2516 if (BusRange != NULL) {\r
2517 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
2518 }\r
2519\r
2520 return EFI_SUCCESS;\r
2521 }\r
2522\r
2523 (*Descriptors)++;\r
2524 }\r
2525\r
2526 return EFI_NOT_FOUND;\r
2527}\r
2528\r
2529/**\r
2530 This routine can be used to start the root bridge.\r
2531\r
2532 @param RootBridgeDev Pci device instance.\r
2533\r
2534 @retval EFI_SUCCESS This device started.\r
2535 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2536\r
2537**/\r
2538EFI_STATUS\r
2539StartManagingRootBridge (\r
2540 IN PCI_IO_DEVICE *RootBridgeDev\r
2541 )\r
2542{\r
2543 EFI_HANDLE RootBridgeHandle;\r
2544 EFI_STATUS Status;\r
2545 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2546\r
2547 //\r
2548 // Get the root bridge handle\r
2549 //\r
2550 RootBridgeHandle = RootBridgeDev->Handle;\r
2551 PciRootBridgeIo = NULL;\r
2552\r
2553 //\r
2554 // Get the pci root bridge io protocol\r
2555 //\r
2556 Status = gBS->OpenProtocol (\r
2557 RootBridgeHandle,\r
2558 &gEfiPciRootBridgeIoProtocolGuid,\r
2559 (VOID **) &PciRootBridgeIo,\r
2560 gPciBusDriverBinding.DriverBindingHandle,\r
2561 RootBridgeHandle,\r
2562 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2563 );\r
2564\r
2565 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2566 return Status;\r
2567 }\r
2568\r
2569 //\r
2570 // Store the PciRootBridgeIo protocol into root bridge private data\r
2571 //\r
2572 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2573\r
2574 return EFI_SUCCESS;\r
2575\r
2576}\r
2577\r
2578/**\r
2579 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2580\r
2581 @param PciIoDevice Pci device instance.\r
2582\r
2583 @retval TRUE This device should be rejected.\r
2584 @retval FALSE This device shouldn't be rejected.\r
2585\r
2586**/\r
2587BOOLEAN\r
2588IsPciDeviceRejected (\r
2589 IN PCI_IO_DEVICE *PciIoDevice\r
2590 )\r
2591{\r
2592 EFI_STATUS Status;\r
2593 UINT32 TestValue;\r
2594 UINT32 OldValue;\r
2595 UINT32 Mask;\r
2596 UINT8 BarOffset;\r
2597\r
2598 //\r
2599 // PPB should be skip!\r
2600 //\r
2601 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2602 return FALSE;\r
2603 }\r
2604\r
2605 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2606 //\r
2607 // Only test base registers for P2C\r
2608 //\r
2609 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2610\r
2611 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2612 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2613 if (EFI_ERROR (Status)) {\r
2614 continue;\r
2615 }\r
2616\r
2617 TestValue = TestValue & Mask;\r
2618 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2619 //\r
2620 // The bar isn't programed, so it should be rejected\r
2621 //\r
2622 return TRUE;\r
2623 }\r
2624 }\r
2625\r
2626 return FALSE;\r
2627 }\r
2628\r
2629 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2630 //\r
2631 // Test PCI devices\r
2632 //\r
2633 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2634 if (EFI_ERROR (Status)) {\r
2635 continue;\r
2636 }\r
2637\r
2638 if ((TestValue & 0x01) != 0) {\r
2639\r
2640 //\r
2641 // IO Bar\r
2642 //\r
2643 Mask = 0xFFFFFFFC;\r
2644 TestValue = TestValue & Mask;\r
2645 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2646 return TRUE;\r
2647 }\r
2648\r
2649 } else {\r
2650\r
2651 //\r
2652 // Mem Bar\r
2653 //\r
2654 Mask = 0xFFFFFFF0;\r
2655 TestValue = TestValue & Mask;\r
2656\r
2657 if ((TestValue & 0x07) == 0x04) {\r
2658\r
2659 //\r
2660 // Mem64 or PMem64\r
2661 //\r
2662 BarOffset += sizeof (UINT32);\r
2663 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2664\r
2665 //\r
2666 // Test its high 32-Bit BAR\r
2667 //\r
2668 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2669 if (TestValue == OldValue) {\r
2670 return TRUE;\r
2671 }\r
2672 }\r
2673\r
2674 } else {\r
2675\r
2676 //\r
2677 // Mem32 or PMem32\r
2678 //\r
2679 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2680 return TRUE;\r
2681 }\r
2682 }\r
2683 }\r
2684 }\r
2685\r
2686 return FALSE;\r
2687}\r
2688\r
2689/**\r
2690 Reset all bus number from specific bridge.\r
2691\r
2692 @param Bridge Parent specific bridge.\r
2693 @param StartBusNumber Start bus number.\r
2694\r
2695**/\r
2696VOID\r
2697ResetAllPpbBusNumber (\r
2698 IN PCI_IO_DEVICE *Bridge,\r
2699 IN UINT8 StartBusNumber\r
2700 )\r
2701{\r
2702 EFI_STATUS Status;\r
2703 PCI_TYPE00 Pci;\r
2704 UINT8 Device;\r
2705 UINT32 Register;\r
2706 UINT8 Func;\r
2707 UINT64 Address;\r
2708 UINT8 SecondaryBus;\r
2709 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2710\r
2711 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2712\r
2713 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2714 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2715\r
2716 //\r
2717 // Check to see whether a pci device is present\r
2718 //\r
2719 Status = PciDevicePresent (\r
2720 PciRootBridgeIo,\r
2721 &Pci,\r
2722 StartBusNumber,\r
2723 Device,\r
2724 Func\r
2725 );\r
2726\r
25a26646
JS
2727 if (EFI_ERROR (Status) && Func == 0) {\r
2728 //\r
2729 // go to next device if there is no Function 0\r
2730 //\r
2731 break;\r
2732 }\r
2733\r
9060e3ec 2734 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2735\r
2736 Register = 0;\r
2737 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2738 Status = PciRootBridgeIo->Pci.Read (\r
2739 PciRootBridgeIo,\r
2740 EfiPciWidthUint32,\r
2741 Address,\r
2742 1,\r
2743 &Register\r
2744 );\r
2745 SecondaryBus = (UINT8)(Register >> 8);\r
2746\r
2747 if (SecondaryBus != 0) {\r
2748 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2749 }\r
2750\r
2751 //\r
2752 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2753 //\r
2754 Register &= 0xFF000000;\r
2755 Status = PciRootBridgeIo->Pci.Write (\r
2756 PciRootBridgeIo,\r
2757 EfiPciWidthUint32,\r
2758 Address,\r
2759 1,\r
2760 &Register\r
2761 );\r
2762 }\r
2763\r
2764 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2765 //\r
2766 // Skip sub functions, this is not a multi function device\r
2767 //\r
2768 Func = PCI_MAX_FUNC;\r
2769 }\r
2770 }\r
2771 }\r
2772}\r
2773\r