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