]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
MdeModulePkg: Skip invalid bus number scanning in PciBusDxe driver
[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
5c13180c 4Copyright (c) 2006 - 2015, 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
1795 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1796 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1797\r
1798 } else {\r
1799\r
1800 Mask = 0xfffffff0;\r
1801\r
1802 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1803\r
1804 switch (Value & 0x07) {\r
1805\r
1806 //\r
1807 //memory space; anywhere in 32 bit address space\r
1808 //\r
1809 case 0x00:\r
1810 if ((Value & 0x08) != 0) {\r
1811 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1812 } else {\r
1813 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1814 }\r
1815\r
1816 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1817 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1818 //\r
1819 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1820 //\r
1821 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1822 } else {\r
1823 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1824 }\r
1825 break;\r
1826\r
1827 //\r
1828 // memory space; anywhere in 64 bit address space\r
1829 //\r
1830 case 0x04:\r
1831 if ((Value & 0x08) != 0) {\r
1832 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1833 } else {\r
1834 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1835 }\r
1836\r
1837 //\r
1838 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1839 // is regarded as an extension for the first bar. As a result\r
1840 // the sizing will be conducted on combined 64 bit value\r
1841 // Here just store the masked first 32bit value for future size\r
1842 // calculation\r
1843 //\r
1844 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1845 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1846\r
1847 //\r
1848 // Increment the offset to point to next DWORD\r
1849 //\r
1850 Offset += 4;\r
1851\r
1852 Status = BarExisted (\r
1853 PciIoDevice,\r
1854 Offset,\r
1855 &Value,\r
1856 &OriginalValue\r
1857 );\r
1858\r
1859 if (EFI_ERROR (Status)) {\r
1860 //\r
1861 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1862 //\r
1863 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1864 //\r
1865 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1866 //\r
1867 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
5c13180c 1868 return Offset + 4;\r
9060e3ec 1869 }\r
9060e3ec 1870 }\r
1871\r
1872 //\r
1873 // Fix the length to support some spefic 64 bit BAR\r
1874 //\r
5c13180c
RN
1875 if (Value == 0) {\r
1876 DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));\r
1877 Value = (UINT32) -1;\r
1878 } else {\r
1879 Value |= ((UINT32)(-1) << HighBitSet32 (Value));\r
1880 }\r
9060e3ec 1881\r
1882 //\r
1883 // Calculate the size of 64bit bar\r
1884 //\r
1885 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1886\r
1887 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1888 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1889 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1890 //\r
1891 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1892 //\r
1893 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1894 } else {\r
1895 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1896 }\r
1897\r
1898 break;\r
1899\r
1900 //\r
1901 // reserved\r
1902 //\r
1903 default:\r
1904 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1905 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1906 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1907 //\r
1908 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1909 //\r
1910 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1911 } else {\r
1912 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1913 }\r
1914 break;\r
1915 }\r
1916 }\r
1917\r
1918 //\r
1919 // Check the length again so as to keep compatible with some special bars\r
1920 //\r
1921 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1922 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1923 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1924 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1925 }\r
1926\r
1927 //\r
1928 // Increment number of bar\r
1929 //\r
1930 return Offset + 4;\r
1931}\r
1932\r
1933/**\r
1934 This routine is used to initialize the bar of a PCI device.\r
1935\r
1936 @param PciIoDevice Pci device instance.\r
1937\r
1938 @note It can be called typically when a device is going to be rejected.\r
1939\r
1940**/\r
1941VOID\r
1942InitializePciDevice (\r
1943 IN PCI_IO_DEVICE *PciIoDevice\r
1944 )\r
1945{\r
1946 EFI_PCI_IO_PROTOCOL *PciIo;\r
1947 UINT8 Offset;\r
1948\r
1949 PciIo = &(PciIoDevice->PciIo);\r
1950\r
1951 //\r
1952 // Put all the resource apertures\r
1953 // Resource base is set to all ones so as to indicate its resource\r
1954 // has not been alloacted\r
1955 //\r
1956 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1957 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1958 }\r
1959}\r
1960\r
1961/**\r
1962 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1963\r
1964 @param PciIoDevice PCI-PCI bridge device instance.\r
1965\r
1966**/\r
1967VOID\r
1968InitializePpb (\r
1969 IN PCI_IO_DEVICE *PciIoDevice\r
1970 )\r
1971{\r
1972 EFI_PCI_IO_PROTOCOL *PciIo;\r
1973\r
1974 PciIo = &(PciIoDevice->PciIo);\r
1975\r
1976 //\r
1977 // Put all the resource apertures including IO16\r
1978 // Io32, pMem32, pMem64 to quiescent state\r
1979 // Resource base all ones, Resource limit all zeros\r
1980 //\r
1981 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1982 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1983\r
1984 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1985 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1986\r
1987 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1988 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1989\r
1990 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1991 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1992\r
1993 //\r
1994 // Don't support use io32 as for now\r
1995 //\r
1996 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1997 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1998\r
1999 //\r
2000 // Force Interrupt line to zero for cards that come up randomly\r
2001 //\r
2002 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2003}\r
2004\r
2005/**\r
2006 This routine is used to initialize the bar of a PCI Card Bridge device.\r
2007\r
2008 @param PciIoDevice PCI Card bridge device.\r
2009\r
2010**/\r
2011VOID\r
2012InitializeP2C (\r
2013 IN PCI_IO_DEVICE *PciIoDevice\r
2014 )\r
2015{\r
2016 EFI_PCI_IO_PROTOCOL *PciIo;\r
2017\r
2018 PciIo = &(PciIoDevice->PciIo);\r
2019\r
2020 //\r
2021 // Put all the resource apertures including IO16\r
2022 // Io32, pMem32, pMem64 to quiescent state(\r
2023 // Resource base all ones, Resource limit all zeros\r
2024 //\r
2025 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
2026 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
2027\r
2028 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
2029 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
2030\r
2031 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
2032 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
2033\r
2034 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
2035 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
2036\r
2037 //\r
2038 // Force Interrupt line to zero for cards that come up randomly\r
2039 //\r
2040 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
2041}\r
2042\r
2043/**\r
2044 Create and initiliaze general PCI I/O device instance for\r
2045 PCI device/bridge device/hotplug bridge device.\r
2046\r
2047 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2048 @param Pci Input Pci information block.\r
2049 @param Bus Device Bus NO.\r
2050 @param Device Device device NO.\r
2051 @param Func Device func NO.\r
2052\r
2053 @return Instance of PCI device. NULL means no instance created.\r
2054\r
2055**/\r
2056PCI_IO_DEVICE *\r
2057CreatePciIoDevice (\r
d4048391 2058 IN PCI_IO_DEVICE *Bridge,\r
9060e3ec 2059 IN PCI_TYPE00 *Pci,\r
2060 IN UINT8 Bus,\r
2061 IN UINT8 Device,\r
2062 IN UINT8 Func\r
2063 )\r
2064{\r
d4048391 2065 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 2066 EFI_PCI_IO_PROTOCOL *PciIo;\r
2067 EFI_STATUS Status;\r
2068\r
2069 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
2070 if (PciIoDevice == NULL) {\r
2071 return NULL;\r
2072 }\r
2073\r
2074 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
2075 PciIoDevice->Handle = NULL;\r
d4048391 2076 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
9060e3ec 2077 PciIoDevice->DevicePath = NULL;\r
2078 PciIoDevice->BusNumber = Bus;\r
2079 PciIoDevice->DeviceNumber = Device;\r
2080 PciIoDevice->FunctionNumber = Func;\r
2081 PciIoDevice->Decodes = 0;\r
2082\r
2083 if (gFullEnumeration) {\r
2084 PciIoDevice->Allocated = FALSE;\r
2085 } else {\r
2086 PciIoDevice->Allocated = TRUE;\r
2087 }\r
2088\r
2089 PciIoDevice->Registered = FALSE;\r
2090 PciIoDevice->Attributes = 0;\r
2091 PciIoDevice->Supports = 0;\r
2092 PciIoDevice->BusOverride = FALSE;\r
2093 PciIoDevice->AllOpRomProcessed = FALSE;\r
2094\r
2095 PciIoDevice->IsPciExp = FALSE;\r
2096\r
2097 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
2098\r
2099 //\r
2100 // Initialize the PCI I/O instance structure\r
2101 //\r
2102 InitializePciIoInstance (PciIoDevice);\r
2103 InitializePciDriverOverrideInstance (PciIoDevice);\r
2104 InitializePciLoadFile2 (PciIoDevice);\r
2105 PciIo = &PciIoDevice->PciIo;\r
2106\r
b0bc24af
AW
2107 //\r
2108 // Create a device path for this PCI device and store it into its private data\r
2109 //\r
2110 CreatePciDevicePath (\r
2111 Bridge->DevicePath,\r
2112 PciIoDevice\r
2113 );\r
2114\r
9060e3ec 2115 //\r
2116 // Detect if PCI Express Device\r
2117 //\r
2118 PciIoDevice->PciExpressCapabilityOffset = 0;\r
2119 Status = LocateCapabilityRegBlock (\r
2120 PciIoDevice,\r
2121 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
2122 &PciIoDevice->PciExpressCapabilityOffset,\r
2123 NULL\r
2124 );\r
2125 if (!EFI_ERROR (Status)) {\r
2126 PciIoDevice->IsPciExp = TRUE;\r
2127 }\r
2128\r
d4048391 2129 if (PcdGetBool (PcdAriSupport)) {\r
2130 //\r
2131 // Check if the device is an ARI device.\r
2132 //\r
2133 Status = LocatePciExpressCapabilityRegBlock (\r
2134 PciIoDevice,\r
2135 EFI_PCIE_CAPABILITY_ID_ARI,\r
2136 &PciIoDevice->AriCapabilityOffset,\r
2137 NULL\r
2138 );\r
2139 if (!EFI_ERROR (Status)) {\r
2140 //\r
2141 // We need to enable ARI feature before calculate BusReservation,\r
2142 // because FirstVFOffset and VFStride may change after that.\r
2143 //\r
2144 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
2145 UINT32 Data32;\r
9060e3ec 2146\r
d4048391 2147 //\r
2148 // Check if its parent supports ARI forwarding.\r
2149 //\r
2150 ParentPciIo = &Bridge->PciIo;\r
2151 ParentPciIo->Pci.Read (\r
2152 ParentPciIo, \r
2153 EfiPciIoWidthUint32,\r
2154 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
2155 1,\r
2156 &Data32\r
2157 );\r
2158 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
2159 //\r
2160 // ARI forward support in bridge, so enable it.\r
2161 //\r
2162 ParentPciIo->Pci.Read (\r
2163 ParentPciIo,\r
2164 EfiPciIoWidthUint32,\r
2165 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2166 1,\r
2167 &Data32\r
2168 );\r
2169 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2170 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2171 ParentPciIo->Pci.Write (\r
2172 ParentPciIo,\r
2173 EfiPciIoWidthUint32,\r
2174 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2175 1,\r
2176 &Data32\r
2177 );\r
2178 DEBUG ((\r
2179 EFI_D_INFO,\r
8db6a82c
RN
2180 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",\r
2181 Bridge->BusNumber,\r
2182 Bridge->DeviceNumber,\r
2183 Bridge->FunctionNumber\r
d4048391 2184 ));\r
2185 }\r
2186 }\r
9060e3ec 2187\r
8db6a82c 2188 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));\r
d4048391 2189 }\r
9060e3ec 2190 }\r
2191\r
2192 //\r
d4048391 2193 // Initialization for SR-IOV\r
9060e3ec 2194 //\r
9060e3ec 2195\r
d4048391 2196 if (PcdGetBool (PcdSrIovSupport)) {\r
2197 Status = LocatePciExpressCapabilityRegBlock (\r
2198 PciIoDevice,\r
2199 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2200 &PciIoDevice->SrIovCapabilityOffset,\r
2201 NULL\r
2202 );\r
2203 if (!EFI_ERROR (Status)) {\r
8db6a82c 2204 UINT32 SupportedPageSize;\r
d4048391 2205 UINT16 VFStride;\r
2206 UINT16 FirstVFOffset;\r
2207 UINT16 Data16;\r
2208 UINT32 PFRid;\r
2209 UINT32 LastVF;\r
2210\r
2211 //\r
2212 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2213 //\r
2214 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {\r
2215 PciIo->Pci.Read (\r
2216 PciIo,\r
2217 EfiPciIoWidthUint16,\r
2218 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2219 1,\r
2220 &Data16\r
2221 );\r
2222 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2223 PciIo->Pci.Write (\r
2224 PciIo,\r
2225 EfiPciIoWidthUint16,\r
2226 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2227 1,\r
2228 &Data16\r
2229 );\r
2230 }\r
9060e3ec 2231\r
d4048391 2232 //\r
2233 // Calculate SystemPageSize\r
2234 //\r
9060e3ec 2235\r
d4048391 2236 PciIo->Pci.Read (\r
2237 PciIo,\r
2238 EfiPciIoWidthUint32,\r
2239 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2240 1,\r
8db6a82c 2241 &SupportedPageSize\r
d4048391 2242 );\r
8db6a82c 2243 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);\r
d4048391 2244 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2245\r
2246 PciIo->Pci.Write (\r
2247 PciIo,\r
2248 EfiPciIoWidthUint32,\r
2249 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2250 1,\r
2251 &PciIoDevice->SystemPageSize\r
2252 );\r
d4048391 2253 //\r
2254 // Adjust SystemPageSize for Alignment usage later\r
2255 //\r
2256 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2257\r
d4048391 2258 //\r
2259 // Calculate BusReservation for PCI IOV\r
2260 //\r
9060e3ec 2261\r
d4048391 2262 //\r
2263 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2264 //\r
2265 PciIo->Pci.Read (\r
2266 PciIo,\r
2267 EfiPciIoWidthUint16,\r
2268 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2269 1,\r
2270 &FirstVFOffset\r
2271 );\r
d4048391 2272 PciIo->Pci.Read (\r
2273 PciIo,\r
2274 EfiPciIoWidthUint16,\r
2275 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2276 1,\r
2277 &PciIoDevice->InitialVFs\r
2278 );\r
d4048391 2279 PciIo->Pci.Read (\r
2280 PciIo,\r
2281 EfiPciIoWidthUint16,\r
2282 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2283 1,\r
2284 &VFStride\r
2285 );\r
d4048391 2286 //\r
2287 // Calculate LastVF\r
2288 //\r
2289 PFRid = EFI_PCI_RID(Bus, Device, Func);\r
2290 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2291\r
d4048391 2292 //\r
2293 // Calculate ReservedBusNum for this PF\r
2294 //\r
2295 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
8db6a82c 2296\r
d4048391 2297 DEBUG ((\r
2298 EFI_D_INFO,\r
8db6a82c
RN
2299 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",\r
2300 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset\r
d4048391 2301 ));\r
d4048391 2302 DEBUG ((\r
2303 EFI_D_INFO,\r
8db6a82c
RN
2304 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",\r
2305 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset\r
d4048391 2306 ));\r
2307 }\r
9060e3ec 2308 }\r
2309\r
d4048391 2310 if (PcdGetBool (PcdMrIovSupport)) {\r
2311 Status = LocatePciExpressCapabilityRegBlock (\r
2312 PciIoDevice,\r
2313 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2314 &PciIoDevice->MrIovCapabilityOffset,\r
2315 NULL\r
2316 );\r
2317 if (!EFI_ERROR (Status)) {\r
8db6a82c 2318 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));\r
d4048391 2319 }\r
2320 }\r
9060e3ec 2321\r
2322 //\r
2323 // Initialize the reserved resource list\r
2324 //\r
2325 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2326\r
2327 //\r
2328 // Initialize the driver list\r
2329 //\r
2330 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2331\r
2332 //\r
2333 // Initialize the child list\r
2334 //\r
2335 InitializeListHead (&PciIoDevice->ChildList);\r
2336\r
2337 return PciIoDevice;\r
2338}\r
2339\r
2340/**\r
2341 This routine is used to enumerate entire pci bus system\r
2342 in a given platform.\r
2343\r
2344 It is only called on the second start on the same Root Bridge.\r
2345\r
2346 @param Controller Parent bridge handler.\r
2347\r
2348 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2349 @retval other Some error occurred when enumerating the pci bus system.\r
2350\r
2351**/\r
2352EFI_STATUS\r
2353PciEnumeratorLight (\r
2354 IN EFI_HANDLE Controller\r
2355 )\r
2356{\r
2357\r
2358 EFI_STATUS Status;\r
2359 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2360 PCI_IO_DEVICE *RootBridgeDev;\r
2361 UINT16 MinBus;\r
2362 UINT16 MaxBus;\r
2363 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
2364\r
2365 MinBus = 0;\r
2366 MaxBus = PCI_MAX_BUS;\r
2367 Descriptors = NULL;\r
2368\r
2369 //\r
2370 // If this root bridge has been already enumerated, then return successfully\r
2371 //\r
2372 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2373 return EFI_SUCCESS;\r
2374 }\r
2375\r
2376 //\r
2377 // Open pci root bridge io protocol\r
2378 //\r
2379 Status = gBS->OpenProtocol (\r
2380 Controller,\r
2381 &gEfiPciRootBridgeIoProtocolGuid,\r
2382 (VOID **) &PciRootBridgeIo,\r
2383 gPciBusDriverBinding.DriverBindingHandle,\r
2384 Controller,\r
2385 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2386 );\r
2387 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2388 return Status;\r
2389 }\r
2390\r
2391 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2392\r
2393 if (EFI_ERROR (Status)) {\r
2394 return Status;\r
2395 }\r
2396\r
2397 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
2398\r
2399 //\r
2400 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2401 //\r
2402 RootBridgeDev = CreateRootBridge (Controller);\r
2403\r
2404 if (RootBridgeDev == NULL) {\r
2405 Descriptors++;\r
2406 continue;\r
2407 }\r
2408\r
2409 //\r
2410 // Record the root bridgeio protocol\r
2411 //\r
2412 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2413\r
2414 Status = PciPciDeviceInfoCollector (\r
2415 RootBridgeDev,\r
2416 (UINT8) MinBus\r
2417 );\r
2418\r
2419 if (!EFI_ERROR (Status)) {\r
2420\r
2421 //\r
2422 // Remove those PCI devices which are rejected when full enumeration\r
2423 //\r
2424 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2425\r
2426 //\r
2427 // Process option rom light\r
2428 //\r
2429 ProcessOptionRomLight (RootBridgeDev);\r
2430\r
2431 //\r
2432 // Determine attributes for all devices under this root bridge\r
2433 //\r
2434 DetermineDeviceAttribute (RootBridgeDev);\r
2435\r
2436 //\r
2437 // If successfully, insert the node into device pool\r
2438 //\r
2439 InsertRootBridge (RootBridgeDev);\r
2440 } else {\r
2441\r
2442 //\r
2443 // If unsuccessly, destroy the entire node\r
2444 //\r
2445 DestroyRootBridge (RootBridgeDev);\r
2446 }\r
2447\r
2448 Descriptors++;\r
2449 }\r
2450\r
2451 return EFI_SUCCESS;\r
2452}\r
2453\r
2454/**\r
2455 Get bus range from PCI resource descriptor list.\r
2456\r
2457 @param Descriptors A pointer to the address space descriptor.\r
2458 @param MinBus The min bus returned.\r
2459 @param MaxBus The max bus returned.\r
2460 @param BusRange The bus range returned.\r
2461\r
2462 @retval EFI_SUCCESS Successfully got bus range.\r
2463 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2464\r
2465**/\r
2466EFI_STATUS\r
2467PciGetBusRange (\r
2468 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2469 OUT UINT16 *MinBus,\r
2470 OUT UINT16 *MaxBus,\r
2471 OUT UINT16 *BusRange\r
2472 )\r
2473{\r
2474 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2475 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2476 if (MinBus != NULL) {\r
2477 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
2478 }\r
2479\r
2480 if (MaxBus != NULL) {\r
2481 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
2482 }\r
2483\r
2484 if (BusRange != NULL) {\r
2485 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
2486 }\r
2487\r
2488 return EFI_SUCCESS;\r
2489 }\r
2490\r
2491 (*Descriptors)++;\r
2492 }\r
2493\r
2494 return EFI_NOT_FOUND;\r
2495}\r
2496\r
2497/**\r
2498 This routine can be used to start the root bridge.\r
2499\r
2500 @param RootBridgeDev Pci device instance.\r
2501\r
2502 @retval EFI_SUCCESS This device started.\r
2503 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2504\r
2505**/\r
2506EFI_STATUS\r
2507StartManagingRootBridge (\r
2508 IN PCI_IO_DEVICE *RootBridgeDev\r
2509 )\r
2510{\r
2511 EFI_HANDLE RootBridgeHandle;\r
2512 EFI_STATUS Status;\r
2513 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2514\r
2515 //\r
2516 // Get the root bridge handle\r
2517 //\r
2518 RootBridgeHandle = RootBridgeDev->Handle;\r
2519 PciRootBridgeIo = NULL;\r
2520\r
2521 //\r
2522 // Get the pci root bridge io protocol\r
2523 //\r
2524 Status = gBS->OpenProtocol (\r
2525 RootBridgeHandle,\r
2526 &gEfiPciRootBridgeIoProtocolGuid,\r
2527 (VOID **) &PciRootBridgeIo,\r
2528 gPciBusDriverBinding.DriverBindingHandle,\r
2529 RootBridgeHandle,\r
2530 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2531 );\r
2532\r
2533 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2534 return Status;\r
2535 }\r
2536\r
2537 //\r
2538 // Store the PciRootBridgeIo protocol into root bridge private data\r
2539 //\r
2540 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2541\r
2542 return EFI_SUCCESS;\r
2543\r
2544}\r
2545\r
2546/**\r
2547 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2548\r
2549 @param PciIoDevice Pci device instance.\r
2550\r
2551 @retval TRUE This device should be rejected.\r
2552 @retval FALSE This device shouldn't be rejected.\r
2553\r
2554**/\r
2555BOOLEAN\r
2556IsPciDeviceRejected (\r
2557 IN PCI_IO_DEVICE *PciIoDevice\r
2558 )\r
2559{\r
2560 EFI_STATUS Status;\r
2561 UINT32 TestValue;\r
2562 UINT32 OldValue;\r
2563 UINT32 Mask;\r
2564 UINT8 BarOffset;\r
2565\r
2566 //\r
2567 // PPB should be skip!\r
2568 //\r
2569 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2570 return FALSE;\r
2571 }\r
2572\r
2573 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2574 //\r
2575 // Only test base registers for P2C\r
2576 //\r
2577 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2578\r
2579 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2580 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2581 if (EFI_ERROR (Status)) {\r
2582 continue;\r
2583 }\r
2584\r
2585 TestValue = TestValue & Mask;\r
2586 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2587 //\r
2588 // The bar isn't programed, so it should be rejected\r
2589 //\r
2590 return TRUE;\r
2591 }\r
2592 }\r
2593\r
2594 return FALSE;\r
2595 }\r
2596\r
2597 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2598 //\r
2599 // Test PCI devices\r
2600 //\r
2601 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2602 if (EFI_ERROR (Status)) {\r
2603 continue;\r
2604 }\r
2605\r
2606 if ((TestValue & 0x01) != 0) {\r
2607\r
2608 //\r
2609 // IO Bar\r
2610 //\r
2611 Mask = 0xFFFFFFFC;\r
2612 TestValue = TestValue & Mask;\r
2613 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2614 return TRUE;\r
2615 }\r
2616\r
2617 } else {\r
2618\r
2619 //\r
2620 // Mem Bar\r
2621 //\r
2622 Mask = 0xFFFFFFF0;\r
2623 TestValue = TestValue & Mask;\r
2624\r
2625 if ((TestValue & 0x07) == 0x04) {\r
2626\r
2627 //\r
2628 // Mem64 or PMem64\r
2629 //\r
2630 BarOffset += sizeof (UINT32);\r
2631 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2632\r
2633 //\r
2634 // Test its high 32-Bit BAR\r
2635 //\r
2636 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2637 if (TestValue == OldValue) {\r
2638 return TRUE;\r
2639 }\r
2640 }\r
2641\r
2642 } else {\r
2643\r
2644 //\r
2645 // Mem32 or PMem32\r
2646 //\r
2647 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2648 return TRUE;\r
2649 }\r
2650 }\r
2651 }\r
2652 }\r
2653\r
2654 return FALSE;\r
2655}\r
2656\r
2657/**\r
2658 Reset all bus number from specific bridge.\r
2659\r
2660 @param Bridge Parent specific bridge.\r
2661 @param StartBusNumber Start bus number.\r
2662\r
2663**/\r
2664VOID\r
2665ResetAllPpbBusNumber (\r
2666 IN PCI_IO_DEVICE *Bridge,\r
2667 IN UINT8 StartBusNumber\r
2668 )\r
2669{\r
2670 EFI_STATUS Status;\r
2671 PCI_TYPE00 Pci;\r
2672 UINT8 Device;\r
2673 UINT32 Register;\r
2674 UINT8 Func;\r
2675 UINT64 Address;\r
2676 UINT8 SecondaryBus;\r
2677 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2678\r
2679 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2680\r
2681 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2682 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2683\r
2684 //\r
2685 // Check to see whether a pci device is present\r
2686 //\r
2687 Status = PciDevicePresent (\r
2688 PciRootBridgeIo,\r
2689 &Pci,\r
2690 StartBusNumber,\r
2691 Device,\r
2692 Func\r
2693 );\r
2694\r
25a26646
JS
2695 if (EFI_ERROR (Status) && Func == 0) {\r
2696 //\r
2697 // go to next device if there is no Function 0\r
2698 //\r
2699 break;\r
2700 }\r
2701\r
9060e3ec 2702 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2703\r
2704 Register = 0;\r
2705 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2706 Status = PciRootBridgeIo->Pci.Read (\r
2707 PciRootBridgeIo,\r
2708 EfiPciWidthUint32,\r
2709 Address,\r
2710 1,\r
2711 &Register\r
2712 );\r
2713 SecondaryBus = (UINT8)(Register >> 8);\r
2714\r
2715 if (SecondaryBus != 0) {\r
2716 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2717 }\r
2718\r
2719 //\r
2720 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2721 //\r
2722 Register &= 0xFF000000;\r
2723 Status = PciRootBridgeIo->Pci.Write (\r
2724 PciRootBridgeIo,\r
2725 EfiPciWidthUint32,\r
2726 Address,\r
2727 1,\r
2728 &Register\r
2729 );\r
2730 }\r
2731\r
2732 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2733 //\r
2734 // Skip sub functions, this is not a multi function device\r
2735 //\r
2736 Func = PCI_MAX_FUNC;\r
2737 }\r
2738 }\r
2739 }\r
2740}\r
2741\r