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