]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
MdeModulePkg/PciBus: Shadow option ROM after BARs are programmed
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciLib.c
CommitLineData
9060e3ec 1/** @file\r
2 Internal library implementation for PCI Bus module.\r
3\r
2e94e412 4Copyright (c) 2006 - 2018, 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
18GLOBAL_REMOVE_IF_UNREFERENCED\r
19CHAR16 *mBarTypeStr[] = {\r
20 L"Unknow",\r
21 L" Io16",\r
22 L" Io32",\r
23 L" Mem32",\r
24 L"PMem32",\r
25 L" Mem64",\r
26 L"PMem64",\r
0176af14 27 L" OpRom",\r
8db6a82c
RN
28 L" Io",\r
29 L" Mem",\r
30 L"Unknow"\r
31 };\r
9060e3ec 32\r
03ac238b
RN
33/**\r
34 Retrieve the max bus number that is assigned to the Root Bridge hierarchy.\r
35 It can support the case that there are multiple bus ranges.\r
36\r
37 @param Bridge Bridge device instance.\r
38\r
39 @retval The max bus number that is assigned to this Root Bridge hierarchy.\r
40\r
41**/\r
42UINT16\r
43PciGetMaxBusNumber (\r
44 IN PCI_IO_DEVICE *Bridge\r
45 )\r
46{\r
47 PCI_IO_DEVICE *RootBridge;\r
48 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;\r
49 UINT64 MaxNumberInRange;\r
50\r
51 //\r
52 // Get PCI Root Bridge device\r
53 //\r
54 RootBridge = Bridge;\r
55 while (RootBridge->Parent != NULL) {\r
56 RootBridge = RootBridge->Parent;\r
57 }\r
58 MaxNumberInRange = 0;\r
59 //\r
60 // Iterate the bus number ranges to get max PCI bus number\r
61 //\r
62 BusNumberRanges = RootBridge->BusNumberRanges;\r
63 while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
64 MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;\r
65 BusNumberRanges++;\r
66 }\r
67 return (UINT16) MaxNumberInRange;\r
68}\r
69\r
9060e3ec 70/**\r
71 Retrieve the PCI Card device BAR information via PciIo interface.\r
72\r
73 @param PciIoDevice PCI Card device instance.\r
74\r
75**/\r
76VOID\r
77GetBackPcCardBar (\r
78 IN PCI_IO_DEVICE *PciIoDevice\r
79 )\r
80{\r
81 UINT32 Address;\r
82\r
83 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
84 return;\r
85 }\r
86\r
87 //\r
88 // Read PciBar information from the bar register\r
89 //\r
90 if (!gFullEnumeration) {\r
91 Address = 0;\r
92 PciIoDevice->PciIo.Pci.Read (\r
93 &(PciIoDevice->PciIo),\r
94 EfiPciIoWidthUint32,\r
95 PCI_CARD_MEMORY_BASE_0,\r
96 1,\r
97 &Address\r
98 );\r
99\r
100 (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);\r
101 (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;\r
102 (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;\r
103\r
104 Address = 0;\r
105 PciIoDevice->PciIo.Pci.Read (\r
106 &(PciIoDevice->PciIo),\r
107 EfiPciIoWidthUint32,\r
108 PCI_CARD_MEMORY_BASE_1,\r
109 1,\r
110 &Address\r
111 );\r
112 (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);\r
113 (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;\r
114 (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;\r
115\r
116 Address = 0;\r
117 PciIoDevice->PciIo.Pci.Read (\r
118 &(PciIoDevice->PciIo),\r
119 EfiPciIoWidthUint32,\r
120 PCI_CARD_IO_BASE_0_LOWER,\r
121 1,\r
122 &Address\r
123 );\r
124 (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);\r
125 (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;\r
126 (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;\r
127\r
128 Address = 0;\r
129 PciIoDevice->PciIo.Pci.Read (\r
130 &(PciIoDevice->PciIo),\r
131 EfiPciIoWidthUint32,\r
132 PCI_CARD_IO_BASE_1_LOWER,\r
133 1,\r
134 &Address\r
135 );\r
136 (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);\r
137 (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;\r
138 (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;\r
139\r
140 }\r
141\r
142 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
143 GetResourcePaddingForHpb (PciIoDevice);\r
144 }\r
145}\r
146\r
147/**\r
148 Remove rejected pci device from specific root bridge\r
149 handle.\r
150\r
151 @param RootBridgeHandle Specific parent root bridge handle.\r
152 @param Bridge Bridge device instance.\r
153\r
154**/\r
155VOID\r
156RemoveRejectedPciDevices (\r
157 IN EFI_HANDLE RootBridgeHandle,\r
158 IN PCI_IO_DEVICE *Bridge\r
159 )\r
160{\r
161 PCI_IO_DEVICE *Temp;\r
162 LIST_ENTRY *CurrentLink;\r
163 LIST_ENTRY *LastLink;\r
164\r
165 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
166 return;\r
167 }\r
168\r
169 CurrentLink = Bridge->ChildList.ForwardLink;\r
170\r
171 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
172\r
173 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
174\r
175 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
176 //\r
177 // Remove rejected devices recusively\r
178 //\r
179 RemoveRejectedPciDevices (RootBridgeHandle, Temp);\r
180 } else {\r
181 //\r
182 // Skip rejection for all PPBs, while detect rejection for others\r
183 //\r
184 if (IsPciDeviceRejected (Temp)) {\r
185\r
186 //\r
187 // For P2C, remove all devices on it\r
188 //\r
189 if (!IsListEmpty (&Temp->ChildList)) {\r
190 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
191 }\r
192\r
193 //\r
194 // Finally remove itself\r
195 //\r
196 LastLink = CurrentLink->BackLink;\r
197 RemoveEntryList (CurrentLink);\r
198 FreePciDevice (Temp);\r
199\r
200 CurrentLink = LastLink;\r
201 }\r
202 }\r
203\r
204 CurrentLink = CurrentLink->ForwardLink;\r
205 }\r
206}\r
207\r
8db6a82c
RN
208/**\r
209 Dump the resourc map of the bridge device.\r
210\r
211 @param[in] BridgeResource Resource descriptor of the bridge device.\r
212**/\r
213VOID\r
214DumpBridgeResource (\r
215 IN PCI_RESOURCE_NODE *BridgeResource\r
216 )\r
217{\r
218 LIST_ENTRY *Link;\r
219 PCI_RESOURCE_NODE *Resource;\r
220 PCI_BAR *Bar;\r
221\r
222 if ((BridgeResource != NULL) && (BridgeResource->Length != 0)) {\r
223 DEBUG ((\r
980050bc 224 EFI_D_INFO, "Type = %s; Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx\n",\r
8db6a82c
RN
225 mBarTypeStr[MIN (BridgeResource->ResType, PciBarTypeMaxType)],\r
226 BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress,\r
227 BridgeResource->Length, BridgeResource->Alignment\r
228 ));\r
f67bd32d
RN
229 for ( Link = GetFirstNode (&BridgeResource->ChildList)\r
230 ; !IsNull (&BridgeResource->ChildList, Link)\r
231 ; Link = GetNextNode (&BridgeResource->ChildList, Link)\r
8db6a82c
RN
232 ) {\r
233 Resource = RESOURCE_NODE_FROM_LINK (Link);\r
234 if (Resource->ResourceUsage == PciResUsageTypical) {\r
235 Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource->PciDev->PciBar;\r
236 DEBUG ((\r
f67bd32d 237 EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx;\tOwner = %s [%02x|%02x|%02x:",\r
8db6a82c
RN
238 Bar[Resource->Bar].BaseAddress, Resource->Length, Resource->Alignment,\r
239 IS_PCI_BRIDGE (&Resource->PciDev->Pci) ? L"PPB" :\r
240 IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" :\r
f67bd32d
RN
241 L"PCI",\r
242 Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,\r
243 Resource->PciDev->FunctionNumber\r
8db6a82c
RN
244 ));\r
245\r
246 if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) && !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) ||\r
247 (IS_PCI_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < PPB_IO_RANGE)) ||\r
248 (IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < P2C_MEM_1))\r
249 ) {\r
250 //\r
251 // The resource requirement comes from the device itself.\r
252 //\r
f67bd32d 253 DEBUG ((EFI_D_INFO, "%02x]", Bar[Resource->Bar].Offset));\r
8db6a82c
RN
254 } else {\r
255 //\r
256 // The resource requirement comes from the subordinate devices.\r
257 //\r
f67bd32d 258 DEBUG ((EFI_D_INFO, "**]"));\r
8db6a82c
RN
259 }\r
260 } else {\r
f67bd32d 261 DEBUG ((EFI_D_INFO, " Base = Padding;\tLength = 0x%lx;\tAlignment = 0x%lx", Resource->Length, Resource->Alignment));\r
8db6a82c 262 }\r
f67bd32d
RN
263 if (BridgeResource->ResType != Resource->ResType) {\r
264 DEBUG ((EFI_D_INFO, "; Type = %s", mBarTypeStr[MIN (Resource->ResType, PciBarTypeMaxType)]));\r
265 }\r
266 DEBUG ((EFI_D_INFO, "\n"));\r
8db6a82c
RN
267 }\r
268 }\r
269}\r
270\r
271/**\r
272 Find the corresponding resource node for the Device in child list of BridgeResource.\r
d1102dba 273\r
f67bd32d
RN
274 @param[in] Device Pointer to PCI_IO_DEVICE.\r
275 @param[in] BridgeResource Pointer to PCI_RESOURCE_NODE.\r
276 @param[out] DeviceResources Pointer to a buffer to receive resources for the Device.\r
d1102dba 277\r
f67bd32d 278 @return Count of the resource descriptors returned.\r
8db6a82c 279**/\r
f67bd32d 280UINTN\r
8db6a82c 281FindResourceNode (\r
f67bd32d
RN
282 IN PCI_IO_DEVICE *Device,\r
283 IN PCI_RESOURCE_NODE *BridgeResource,\r
284 OUT PCI_RESOURCE_NODE **DeviceResources OPTIONAL\r
8db6a82c
RN
285 )\r
286{\r
287 LIST_ENTRY *Link;\r
288 PCI_RESOURCE_NODE *Resource;\r
f67bd32d 289 UINTN Count;\r
8db6a82c 290\r
f67bd32d 291 Count = 0;\r
8db6a82c
RN
292 for ( Link = BridgeResource->ChildList.ForwardLink\r
293 ; Link != &BridgeResource->ChildList\r
294 ; Link = Link->ForwardLink\r
295 ) {\r
296 Resource = RESOURCE_NODE_FROM_LINK (Link);\r
297 if (Resource->PciDev == Device) {\r
f67bd32d
RN
298 if (DeviceResources != NULL) {\r
299 DeviceResources[Count] = Resource;\r
300 }\r
301 Count++;\r
8db6a82c
RN
302 }\r
303 }\r
304\r
f67bd32d 305 return Count;\r
8db6a82c
RN
306}\r
307\r
308/**\r
309 Dump the resource map of all the devices under Bridge.\r
d1102dba 310\r
f67bd32d
RN
311 @param[in] Bridge Bridge device instance.\r
312 @param[in] Resources Resource descriptors for the bridge device.\r
313 @param[in] ResourceCount Count of resource descriptors.\r
8db6a82c
RN
314**/\r
315VOID\r
316DumpResourceMap (\r
317 IN PCI_IO_DEVICE *Bridge,\r
f67bd32d
RN
318 IN PCI_RESOURCE_NODE **Resources,\r
319 IN UINTN ResourceCount\r
8db6a82c
RN
320 )\r
321{\r
f67bd32d
RN
322 EFI_STATUS Status;\r
323 LIST_ENTRY *Link;\r
324 PCI_IO_DEVICE *Device;\r
325 UINTN Index;\r
326 CHAR16 *Str;\r
327 PCI_RESOURCE_NODE **ChildResources;\r
328 UINTN ChildResourceCount;\r
8db6a82c
RN
329\r
330 DEBUG ((EFI_D_INFO, "PciBus: Resource Map for "));\r
331\r
332 Status = gBS->OpenProtocol (\r
333 Bridge->Handle,\r
334 &gEfiPciRootBridgeIoProtocolGuid,\r
335 NULL,\r
336 NULL,\r
337 NULL,\r
338 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
339 );\r
340 if (EFI_ERROR (Status)) {\r
341 DEBUG ((\r
342 EFI_D_INFO, "Bridge [%02x|%02x|%02x]\n",\r
343 Bridge->BusNumber, Bridge->DeviceNumber, Bridge->FunctionNumber\r
344 ));\r
345 } else {\r
863986b3
RN
346 Str = ConvertDevicePathToText (\r
347 DevicePathFromHandle (Bridge->Handle),\r
348 FALSE,\r
349 FALSE\r
350 );\r
8db6a82c
RN
351 DEBUG ((EFI_D_INFO, "Root Bridge %s\n", Str != NULL ? Str : L""));\r
352 if (Str != NULL) {\r
353 FreePool (Str);\r
354 }\r
355 }\r
356\r
f67bd32d
RN
357 for (Index = 0; Index < ResourceCount; Index++) {\r
358 DumpBridgeResource (Resources[Index]);\r
359 }\r
8db6a82c
RN
360 DEBUG ((EFI_D_INFO, "\n"));\r
361\r
362 for ( Link = Bridge->ChildList.ForwardLink\r
363 ; Link != &Bridge->ChildList\r
364 ; Link = Link->ForwardLink\r
365 ) {\r
366 Device = PCI_IO_DEVICE_FROM_LINK (Link);\r
367 if (IS_PCI_BRIDGE (&Device->Pci)) {\r
368\r
f67bd32d
RN
369 ChildResourceCount = 0;\r
370 for (Index = 0; Index < ResourceCount; Index++) {\r
371 ChildResourceCount += FindResourceNode (Device, Resources[Index], NULL);\r
372 }\r
373 ChildResources = AllocatePool (sizeof (PCI_RESOURCE_NODE *) * ChildResourceCount);\r
374 ASSERT (ChildResources != NULL);\r
375 ChildResourceCount = 0;\r
376 for (Index = 0; Index < ResourceCount; Index++) {\r
377 ChildResourceCount += FindResourceNode (Device, Resources[Index], &ChildResources[ChildResourceCount]);\r
378 }\r
379\r
380 DumpResourceMap (Device, ChildResources, ChildResourceCount);\r
381 FreePool (ChildResources);\r
8db6a82c
RN
382 }\r
383 }\r
384}\r
385\r
9060e3ec 386/**\r
387 Submits the I/O and memory resource requirements for the specified PCI Host Bridge.\r
388\r
389 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.\r
390\r
391 @retval EFI_SUCCESS Successfully finished resource allocation.\r
392 @retval EFI_NOT_FOUND Cannot get root bridge instance.\r
393 @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.\r
394 @retval other Some error occurred when allocating resources for the PCI Host Bridge.\r
395\r
396 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.\r
397\r
398**/\r
399EFI_STATUS\r
400PciHostBridgeResourceAllocator (\r
401 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
402 )\r
403{\r
404 PCI_IO_DEVICE *RootBridgeDev;\r
405 EFI_HANDLE RootBridgeHandle;\r
406 VOID *AcpiConfig;\r
407 EFI_STATUS Status;\r
408 UINT64 IoBase;\r
409 UINT64 Mem32Base;\r
410 UINT64 PMem32Base;\r
411 UINT64 Mem64Base;\r
412 UINT64 PMem64Base;\r
413 UINT64 IoResStatus;\r
414 UINT64 Mem32ResStatus;\r
415 UINT64 PMem32ResStatus;\r
416 UINT64 Mem64ResStatus;\r
417 UINT64 PMem64ResStatus;\r
418 UINT64 MaxOptionRomSize;\r
419 PCI_RESOURCE_NODE *IoBridge;\r
420 PCI_RESOURCE_NODE *Mem32Bridge;\r
421 PCI_RESOURCE_NODE *PMem32Bridge;\r
422 PCI_RESOURCE_NODE *Mem64Bridge;\r
423 PCI_RESOURCE_NODE *PMem64Bridge;\r
424 PCI_RESOURCE_NODE IoPool;\r
425 PCI_RESOURCE_NODE Mem32Pool;\r
426 PCI_RESOURCE_NODE PMem32Pool;\r
427 PCI_RESOURCE_NODE Mem64Pool;\r
428 PCI_RESOURCE_NODE PMem64Pool;\r
9060e3ec 429 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;\r
430 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;\r
431\r
9060e3ec 432 //\r
433 // It may try several times if the resource allocation fails\r
434 //\r
435 while (TRUE) {\r
436 //\r
437 // Initialize resource pool\r
438 //\r
439 InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
440 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
441 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
442 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);\r
443 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);\r
444\r
445 RootBridgeDev = NULL;\r
446 RootBridgeHandle = 0;\r
447\r
448 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
449 //\r
450 // Get Root Bridge Device by handle\r
451 //\r
452 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
453\r
454 if (RootBridgeDev == NULL) {\r
455 return EFI_NOT_FOUND;\r
456 }\r
457\r
458 //\r
459 // Create the entire system resource map from the information collected by\r
460 // enumerator. Several resource tree was created\r
461 //\r
462\r
1ef26783 463 //\r
ed356b9e 464 // If non-standard PCI Bridge I/O window alignment is supported,\r
1ef26783 465 // set I/O aligment to minimum possible alignment for root bridge.\r
466 //\r
9060e3ec 467 IoBridge = CreateResourceNode (\r
468 RootBridgeDev,\r
469 0,\r
1ef26783 470 FeaturePcdGet (PcdPciBridgeIoAlignmentProbe) ? 0x1FF: 0xFFF,\r
8db6a82c 471 RB_IO_RANGE,\r
9060e3ec 472 PciBarTypeIo16,\r
473 PciResUsageTypical\r
474 );\r
475\r
476 Mem32Bridge = CreateResourceNode (\r
477 RootBridgeDev,\r
478 0,\r
479 0xFFFFF,\r
8db6a82c 480 RB_MEM32_RANGE,\r
9060e3ec 481 PciBarTypeMem32,\r
482 PciResUsageTypical\r
483 );\r
484\r
485 PMem32Bridge = CreateResourceNode (\r
486 RootBridgeDev,\r
487 0,\r
488 0xFFFFF,\r
8db6a82c 489 RB_PMEM32_RANGE,\r
9060e3ec 490 PciBarTypePMem32,\r
491 PciResUsageTypical\r
492 );\r
493\r
494 Mem64Bridge = CreateResourceNode (\r
495 RootBridgeDev,\r
496 0,\r
497 0xFFFFF,\r
8db6a82c 498 RB_MEM64_RANGE,\r
9060e3ec 499 PciBarTypeMem64,\r
500 PciResUsageTypical\r
501 );\r
502\r
503 PMem64Bridge = CreateResourceNode (\r
504 RootBridgeDev,\r
505 0,\r
506 0xFFFFF,\r
8db6a82c 507 RB_PMEM64_RANGE,\r
9060e3ec 508 PciBarTypePMem64,\r
509 PciResUsageTypical\r
510 );\r
511\r
0176af14
RN
512 //\r
513 // Get the max ROM size that the root bridge can process\r
514 // Insert to resource map so that there will be dedicate MEM32 resource range for Option ROM.\r
515 // All devices' Option ROM share the same MEM32 resource.\r
516 //\r
517 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
518 RootBridgeDev->PciBar[0].BarType = PciBarTypeOpRom;\r
519 RootBridgeDev->PciBar[0].Length = MaxOptionRomSize;\r
520 RootBridgeDev->PciBar[0].Alignment = MaxOptionRomSize - 1;\r
521 GetResourceFromDevice (RootBridgeDev, IoBridge, Mem32Bridge, PMem32Bridge, Mem64Bridge, PMem64Bridge);\r
522\r
9060e3ec 523 //\r
524 // Create resourcemap by going through all the devices subject to this root bridge\r
525 //\r
526 CreateResourceMap (\r
527 RootBridgeDev,\r
528 IoBridge,\r
529 Mem32Bridge,\r
530 PMem32Bridge,\r
531 Mem64Bridge,\r
532 PMem64Bridge\r
533 );\r
534\r
9060e3ec 535 //\r
2048c585 536 // Based on the all the resource tree, construct ACPI resource node to\r
9060e3ec 537 // submit the resource aperture to pci host bridge protocol\r
538 //\r
539 Status = ConstructAcpiResourceRequestor (\r
540 RootBridgeDev,\r
541 IoBridge,\r
542 Mem32Bridge,\r
543 PMem32Bridge,\r
544 Mem64Bridge,\r
545 PMem64Bridge,\r
546 &AcpiConfig\r
547 );\r
548\r
549 //\r
550 // Insert these resource nodes into the database\r
551 //\r
552 InsertResourceNode (&IoPool, IoBridge);\r
553 InsertResourceNode (&Mem32Pool, Mem32Bridge);\r
554 InsertResourceNode (&PMem32Pool, PMem32Bridge);\r
555 InsertResourceNode (&Mem64Pool, Mem64Bridge);\r
556 InsertResourceNode (&PMem64Pool, PMem64Bridge);\r
557\r
558 if (Status == EFI_SUCCESS) {\r
559 //\r
560 // Submit the resource requirement\r
561 //\r
562 Status = PciResAlloc->SubmitResources (\r
563 PciResAlloc,\r
564 RootBridgeDev->Handle,\r
565 AcpiConfig\r
566 );\r
724f26a9
RN
567 //\r
568 // If SubmitResources returns error, PciBus isn't able to start.\r
569 // It's a fatal error so assertion is added.\r
570 //\r
571 DEBUG ((EFI_D_INFO, "PciBus: HostBridge->SubmitResources() - %r\n", Status));\r
572 ASSERT_EFI_ERROR (Status);\r
9060e3ec 573 }\r
574\r
575 //\r
576 // Free acpi resource node\r
577 //\r
578 if (AcpiConfig != NULL) {\r
579 FreePool (AcpiConfig);\r
580 }\r
581\r
582 if (EFI_ERROR (Status)) {\r
583 //\r
584 // Destroy all the resource tree\r
585 //\r
586 DestroyResourceTree (&IoPool);\r
587 DestroyResourceTree (&Mem32Pool);\r
588 DestroyResourceTree (&PMem32Pool);\r
589 DestroyResourceTree (&Mem64Pool);\r
590 DestroyResourceTree (&PMem64Pool);\r
591 return Status;\r
592 }\r
593 }\r
594 //\r
595 // End while, at least one Root Bridge should be found.\r
596 //\r
597 ASSERT (RootBridgeDev != NULL);\r
598\r
599 //\r
600 // Notify platform to start to program the resource\r
601 //\r
602 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);\r
724f26a9 603 DEBUG ((EFI_D_INFO, "PciBus: HostBridge->NotifyPhase(AllocateResources) - %r\n", Status));\r
9060e3ec 604 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
605 //\r
606 // If Hot Plug is not supported\r
607 //\r
608 if (EFI_ERROR (Status)) {\r
609 //\r
610 // Allocation failed, then return\r
611 //\r
612 return EFI_OUT_OF_RESOURCES;\r
613 }\r
614 //\r
615 // Allocation succeed.\r
616 // Get host bridge handle for status report, and then skip the main while\r
617 //\r
618 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;\r
619\r
620 break;\r
621\r
622 } else {\r
623 //\r
624 // If Hot Plug is supported\r
625 //\r
626 if (!EFI_ERROR (Status)) {\r
627 //\r
628 // Allocation succeed, then continue the following\r
629 //\r
630 break;\r
631 }\r
632\r
633 //\r
634 // If the resource allocation is unsuccessful, free resources on bridge\r
635 //\r
636\r
637 RootBridgeDev = NULL;\r
638 RootBridgeHandle = 0;\r
639\r
640 IoResStatus = EFI_RESOURCE_SATISFIED;\r
641 Mem32ResStatus = EFI_RESOURCE_SATISFIED;\r
642 PMem32ResStatus = EFI_RESOURCE_SATISFIED;\r
643 Mem64ResStatus = EFI_RESOURCE_SATISFIED;\r
644 PMem64ResStatus = EFI_RESOURCE_SATISFIED;\r
645\r
646 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
647 //\r
648 // Get RootBridg Device by handle\r
649 //\r
650 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
651 if (RootBridgeDev == NULL) {\r
652 return EFI_NOT_FOUND;\r
653 }\r
654\r
655 //\r
656 // Get host bridge handle for status report\r
657 //\r
658 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;\r
659\r
660 //\r
661 // Get acpi resource node for all the resource types\r
662 //\r
663 AcpiConfig = NULL;\r
664\r
665 Status = PciResAlloc->GetProposedResources (\r
666 PciResAlloc,\r
667 RootBridgeDev->Handle,\r
668 &AcpiConfig\r
669 );\r
670\r
671 if (EFI_ERROR (Status)) {\r
672 return Status;\r
673 }\r
674\r
675 if (AcpiConfig != NULL) {\r
676 //\r
677 // Adjust resource allocation policy for each RB\r
678 //\r
679 GetResourceAllocationStatus (\r
680 AcpiConfig,\r
681 &IoResStatus,\r
682 &Mem32ResStatus,\r
683 &PMem32ResStatus,\r
684 &Mem64ResStatus,\r
685 &PMem64ResStatus\r
686 );\r
687 FreePool (AcpiConfig);\r
688 }\r
689 }\r
690 //\r
691 // End while\r
692 //\r
693\r
694 //\r
695 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code\r
696 //\r
697 //\r
698 // It is very difficult to follow the spec here\r
699 // Device path , Bar index can not be get here\r
700 //\r
701 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));\r
702\r
703 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
704 EFI_PROGRESS_CODE,\r
705 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,\r
706 (VOID *) &AllocFailExtendedData,\r
707 sizeof (AllocFailExtendedData)\r
708 );\r
709\r
710 Status = PciHostBridgeAdjustAllocation (\r
711 &IoPool,\r
712 &Mem32Pool,\r
713 &PMem32Pool,\r
714 &Mem64Pool,\r
715 &PMem64Pool,\r
716 IoResStatus,\r
717 Mem32ResStatus,\r
718 PMem32ResStatus,\r
719 Mem64ResStatus,\r
720 PMem64ResStatus\r
721 );\r
722\r
723 //\r
724 // Destroy all the resource tree\r
725 //\r
726 DestroyResourceTree (&IoPool);\r
727 DestroyResourceTree (&Mem32Pool);\r
728 DestroyResourceTree (&PMem32Pool);\r
729 DestroyResourceTree (&Mem64Pool);\r
730 DestroyResourceTree (&PMem64Pool);\r
731\r
732 NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);\r
733\r
734 if (EFI_ERROR (Status)) {\r
735 return Status;\r
736 }\r
9060e3ec 737 }\r
738 }\r
739 //\r
740 // End main while\r
741 //\r
742\r
743 //\r
744 // Raise the EFI_IOB_PCI_RES_ALLOC status code\r
745 //\r
746 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
747 EFI_PROGRESS_CODE,\r
fe91c992 748 EFI_IO_BUS_PCI | EFI_IOB_PCI_RES_ALLOC,\r
9060e3ec 749 (VOID *) &HandleExtendedData,\r
750 sizeof (HandleExtendedData)\r
751 );\r
752\r
753 //\r
754 // Notify pci bus driver starts to program the resource\r
755 //\r
ea8d98fa
OM
756 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);\r
757\r
758 if (EFI_ERROR (Status)) {\r
759 return Status;\r
760 }\r
9060e3ec 761\r
762 RootBridgeDev = NULL;\r
763\r
764 RootBridgeHandle = 0;\r
765\r
766 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
767 //\r
768 // Get RootBridg Device by handle\r
769 //\r
770 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
771\r
772 if (RootBridgeDev == NULL) {\r
773 return EFI_NOT_FOUND;\r
774 }\r
775\r
776 //\r
777 // Get acpi resource node for all the resource types\r
778 //\r
779 AcpiConfig = NULL;\r
780 Status = PciResAlloc->GetProposedResources (\r
781 PciResAlloc,\r
782 RootBridgeDev->Handle,\r
783 &AcpiConfig\r
784 );\r
785\r
786 if (EFI_ERROR (Status)) {\r
787 return Status;\r
788 }\r
789\r
790 //\r
791 // Get the resource base by interpreting acpi resource node\r
792 //\r
793 //\r
794 GetResourceBase (\r
795 AcpiConfig,\r
796 &IoBase,\r
797 &Mem32Base,\r
798 &PMem32Base,\r
799 &Mem64Base,\r
800 &PMem64Base\r
801 );\r
802\r
9060e3ec 803 //\r
804 // Create the entire system resource map from the information collected by\r
805 // enumerator. Several resource tree was created\r
806 //\r
f67bd32d
RN
807 FindResourceNode (RootBridgeDev, &IoPool, &IoBridge);\r
808 FindResourceNode (RootBridgeDev, &Mem32Pool, &Mem32Bridge);\r
809 FindResourceNode (RootBridgeDev, &PMem32Pool, &PMem32Bridge);\r
810 FindResourceNode (RootBridgeDev, &Mem64Pool, &Mem64Bridge);\r
811 FindResourceNode (RootBridgeDev, &PMem64Pool, &PMem64Bridge);\r
9060e3ec 812\r
9995c2e5
RN
813 ASSERT (IoBridge != NULL);\r
814 ASSERT (Mem32Bridge != NULL);\r
815 ASSERT (PMem32Bridge != NULL);\r
816 ASSERT (Mem64Bridge != NULL);\r
817 ASSERT (PMem64Bridge != NULL);\r
818\r
9060e3ec 819 //\r
820 // Program IO resources\r
821 //\r
822 ProgramResource (\r
823 IoBase,\r
824 IoBridge\r
825 );\r
826\r
827 //\r
828 // Program Mem32 resources\r
829 //\r
830 ProgramResource (\r
831 Mem32Base,\r
832 Mem32Bridge\r
833 );\r
834\r
835 //\r
836 // Program PMem32 resources\r
837 //\r
838 ProgramResource (\r
839 PMem32Base,\r
840 PMem32Bridge\r
841 );\r
842\r
843 //\r
844 // Program Mem64 resources\r
845 //\r
846 ProgramResource (\r
847 Mem64Base,\r
848 Mem64Bridge\r
849 );\r
850\r
851 //\r
852 // Program PMem64 resources\r
853 //\r
854 ProgramResource (\r
855 PMem64Base,\r
856 PMem64Bridge\r
857 );\r
858\r
0176af14
RN
859 //\r
860 // Process Option ROM for this root bridge after all BARs are programmed.\r
861 // The PPB's MEM32 RANGE BAR is re-programmed to the Option ROM BAR Base in order to\r
862 // shadow the Option ROM of the devices under the PPB.\r
863 // After the shadow, Option ROM BAR decoding is turned off and the PPB's MEM32 RANGE\r
864 // BAR is restored back to the original value.\r
865 // The original value is programmed by ProgramResource() above.\r
866 //\r
867 DEBUG ((\r
868 DEBUG_INFO, "Process Option ROM: BAR Base/Length = %lx/%lx\n",\r
869 RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length\r
870 ));\r
871 ProcessOptionRom (RootBridgeDev, RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length);\r
872\r
8db6a82c
RN
873 IoBridge ->PciDev->PciBar[IoBridge ->Bar].BaseAddress = IoBase;\r
874 Mem32Bridge ->PciDev->PciBar[Mem32Bridge ->Bar].BaseAddress = Mem32Base;\r
875 PMem32Bridge->PciDev->PciBar[PMem32Bridge->Bar].BaseAddress = PMem32Base;\r
876 Mem64Bridge ->PciDev->PciBar[Mem64Bridge ->Bar].BaseAddress = Mem64Base;\r
877 PMem64Bridge->PciDev->PciBar[PMem64Bridge->Bar].BaseAddress = PMem64Base;\r
878\r
879 //\r
880 // Dump the resource map for current root bridge\r
881 //\r
882 DEBUG_CODE (\r
f67bd32d
RN
883 PCI_RESOURCE_NODE *Resources[5];\r
884 Resources[0] = IoBridge;\r
885 Resources[1] = Mem32Bridge;\r
886 Resources[2] = PMem32Bridge;\r
887 Resources[3] = Mem64Bridge;\r
888 Resources[4] = PMem64Bridge;\r
0781e85f 889 DumpResourceMap (RootBridgeDev, Resources, ARRAY_SIZE (Resources));\r
8db6a82c
RN
890 );\r
891\r
9060e3ec 892 FreePool (AcpiConfig);\r
893 }\r
894\r
895 //\r
896 // Destroy all the resource tree\r
897 //\r
898 DestroyResourceTree (&IoPool);\r
899 DestroyResourceTree (&Mem32Pool);\r
900 DestroyResourceTree (&PMem32Pool);\r
901 DestroyResourceTree (&Mem64Pool);\r
902 DestroyResourceTree (&PMem64Pool);\r
903\r
904 //\r
905 // Notify the resource allocation phase is to end\r
906 //\r
ea8d98fa 907 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);\r
9060e3ec 908\r
ea8d98fa 909 return Status;\r
9060e3ec 910}\r
911\r
306bbe82 912/**\r
913 Allocate NumberOfBuses buses and return the next available PCI bus number.\r
914\r
915 @param Bridge Bridge device instance.\r
916 @param StartBusNumber Current available PCI bus number.\r
917 @param NumberOfBuses Number of buses enumerated below the StartBusNumber.\r
918 @param NextBusNumber Next available PCI bus number.\r
919\r
920 @retval EFI_SUCCESS Available bus number resource is enough. Next available PCI bus number\r
921 is returned in NextBusNumber.\r
922 @retval EFI_OUT_OF_RESOURCES Available bus number resource is not enough for allocation.\r
923\r
924**/\r
925EFI_STATUS\r
926PciAllocateBusNumber (\r
927 IN PCI_IO_DEVICE *Bridge,\r
928 IN UINT8 StartBusNumber,\r
929 IN UINT8 NumberOfBuses,\r
930 OUT UINT8 *NextBusNumber\r
931 )\r
932{\r
933 PCI_IO_DEVICE *RootBridge;\r
934 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;\r
935 UINT8 NextNumber;\r
936 UINT64 MaxNumberInRange;\r
937\r
938 //\r
939 // Get PCI Root Bridge device\r
940 //\r
941 RootBridge = Bridge;\r
942 while (RootBridge->Parent != NULL) {\r
943 RootBridge = RootBridge->Parent;\r
944 }\r
945\r
946 //\r
947 // Get next available PCI bus number\r
948 //\r
949 BusNumberRanges = RootBridge->BusNumberRanges;\r
950 while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
951 MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;\r
952 if (StartBusNumber >= BusNumberRanges->AddrRangeMin && StartBusNumber <= MaxNumberInRange) {\r
50bdaa05 953 NextNumber = (UINT8)(StartBusNumber + NumberOfBuses);\r
306bbe82 954 while (NextNumber > MaxNumberInRange) {\r
955 ++BusNumberRanges;\r
956 if (BusNumberRanges->Desc == ACPI_END_TAG_DESCRIPTOR) {\r
957 return EFI_OUT_OF_RESOURCES;\r
958 }\r
50bdaa05 959 NextNumber = (UINT8)(NextNumber + (BusNumberRanges->AddrRangeMin - (MaxNumberInRange + 1)));\r
306bbe82 960 MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;\r
961 }\r
962 *NextBusNumber = NextNumber;\r
963 return EFI_SUCCESS;\r
964 }\r
965 BusNumberRanges++;\r
966 }\r
967 return EFI_OUT_OF_RESOURCES;\r
968}\r
969\r
9060e3ec 970/**\r
971 Scan pci bus and assign bus number to the given PCI bus system.\r
972\r
973 @param Bridge Bridge device instance.\r
974 @param StartBusNumber start point.\r
975 @param SubBusNumber Point to sub bus number.\r
976 @param PaddedBusRange Customized bus number.\r
977\r
978 @retval EFI_SUCCESS Successfully scanned and assigned bus number.\r
979 @retval other Some error occurred when scanning pci bus.\r
980\r
981 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.\r
982\r
983**/\r
984EFI_STATUS\r
985PciScanBus (\r
986 IN PCI_IO_DEVICE *Bridge,\r
987 IN UINT8 StartBusNumber,\r
988 OUT UINT8 *SubBusNumber,\r
989 OUT UINT8 *PaddedBusRange\r
990 )\r
991{\r
992 EFI_STATUS Status;\r
993 PCI_TYPE00 Pci;\r
994 UINT8 Device;\r
995 UINT8 Func;\r
996 UINT64 Address;\r
c7e7613e
RN
997 UINT8 SecondBus;\r
998 UINT8 PaddedSubBus;\r
9060e3ec 999 UINT16 Register;\r
1000 UINTN HpIndex;\r
1001 PCI_IO_DEVICE *PciDevice;\r
1002 EFI_EVENT Event;\r
1003 EFI_HPC_STATE State;\r
1004 UINT64 PciAddress;\r
1005 EFI_HPC_PADDING_ATTRIBUTES Attributes;\r
1006 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
fff2623c 1007 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *NextDescriptors;\r
9060e3ec 1008 UINT16 BusRange;\r
1009 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1010 BOOLEAN BusPadding;\r
1011 UINT32 TempReservedBusNum;\r
1012\r
1013 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1014 SecondBus = 0;\r
1015 Register = 0;\r
1016 State = 0;\r
1017 Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;\r
1018 BusRange = 0;\r
1019 BusPadding = FALSE;\r
1020 PciDevice = NULL;\r
1021 PciAddress = 0;\r
1022\r
1023 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1024 TempReservedBusNum = 0;\r
1025 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1026\r
1027 //\r
1028 // Check to see whether a pci device is present\r
1029 //\r
1030 Status = PciDevicePresent (\r
1031 PciRootBridgeIo,\r
1032 &Pci,\r
1033 StartBusNumber,\r
1034 Device,\r
1035 Func\r
1036 );\r
1037\r
25a26646
JS
1038 if (EFI_ERROR (Status) && Func == 0) {\r
1039 //\r
1040 // go to next device if there is no Function 0\r
1041 //\r
1042 break;\r
1043 }\r
1044\r
9060e3ec 1045 if (EFI_ERROR (Status)) {\r
9060e3ec 1046 continue;\r
1047 }\r
1048\r
d4048391 1049 //\r
1050 // Get the PCI device information\r
1051 //\r
1052 Status = PciSearchDevice (\r
1053 Bridge,\r
1054 &Pci,\r
1055 StartBusNumber,\r
1056 Device,\r
1057 Func,\r
1058 &PciDevice\r
1059 );\r
9060e3ec 1060\r
d4048391 1061 ASSERT (!EFI_ERROR (Status));\r
9060e3ec 1062\r
d4048391 1063 PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);\r
9060e3ec 1064\r
d4048391 1065 if (!IS_PCI_BRIDGE (&Pci)) {\r
1066 //\r
1067 // PCI bridges will be called later\r
1068 // Here just need for PCI device or PCI to cardbus controller\r
1069 // EfiPciBeforeChildBusEnumeration for PCI Device Node\r
1070 //\r
1071 PreprocessController (\r
1072 PciDevice,\r
1073 PciDevice->BusNumber,\r
1074 PciDevice->DeviceNumber,\r
1075 PciDevice->FunctionNumber,\r
1076 EfiPciBeforeChildBusEnumeration\r
1077 );\r
1078 }\r
9060e3ec 1079\r
d4048391 1080 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
9060e3ec 1081 //\r
1082 // For Pci Hotplug controller devcie only\r
1083 //\r
1084 if (gPciHotPlugInit != NULL) {\r
1085 //\r
1086 // Check if it is a Hotplug PCI controller\r
1087 //\r
1088 if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {\r
55565b08 1089 gPciRootHpcData[HpIndex].Found = TRUE;\r
9060e3ec 1090\r
1091 if (!gPciRootHpcData[HpIndex].Initialized) {\r
1092\r
1093 Status = CreateEventForHpc (HpIndex, &Event);\r
1094\r
1095 ASSERT (!EFI_ERROR (Status));\r
1096\r
1097 Status = gPciHotPlugInit->InitializeRootHpc (\r
1098 gPciHotPlugInit,\r
1099 gPciRootHpcPool[HpIndex].HpcDevicePath,\r
1100 PciAddress,\r
1101 Event,\r
1102 &State\r
1103 );\r
1104\r
1105 PreprocessController (\r
1106 PciDevice,\r
1107 PciDevice->BusNumber,\r
1108 PciDevice->DeviceNumber,\r
1109 PciDevice->FunctionNumber,\r
1110 EfiPciBeforeChildBusEnumeration\r
1111 );\r
1112 }\r
1113 }\r
1114 }\r
1115 }\r
1116\r
1117 if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {\r
1118 //\r
1119 // For PPB\r
1120 //\r
1121 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1122 //\r
1123 // If Hot Plug is not supported,\r
1124 // get the bridge information\r
1125 //\r
1126 Status = PciSearchDevice (\r
1127 Bridge,\r
1128 &Pci,\r
1129 StartBusNumber,\r
1130 Device,\r
1131 Func,\r
1132 &PciDevice\r
1133 );\r
1134\r
1135 if (EFI_ERROR (Status)) {\r
1136 return Status;\r
1137 }\r
1138 } else {\r
1139 //\r
1140 // If Hot Plug is supported,\r
1141 // Get the bridge information\r
1142 //\r
1143 BusPadding = FALSE;\r
1144 if (gPciHotPlugInit != NULL) {\r
1145\r
cbbccf3c 1146 if (IsPciHotPlugBus (PciDevice)) {\r
9060e3ec 1147\r
1148 //\r
1149 // If it is initialized, get the padded bus range\r
1150 //\r
1151 Status = gPciHotPlugInit->GetResourcePadding (\r
1152 gPciHotPlugInit,\r
cbbccf3c 1153 PciDevice->DevicePath,\r
9060e3ec 1154 PciAddress,\r
1155 &State,\r
1156 (VOID **) &Descriptors,\r
1157 &Attributes\r
1158 );\r
1159\r
1160 if (EFI_ERROR (Status)) {\r
1161 return Status;\r
1162 }\r
1163\r
1164 BusRange = 0;\r
fff2623c 1165 NextDescriptors = Descriptors;\r
9060e3ec 1166 Status = PciGetBusRange (\r
fff2623c 1167 &NextDescriptors,\r
9060e3ec 1168 NULL,\r
1169 NULL,\r
1170 &BusRange\r
1171 );\r
1172\r
1173 FreePool (Descriptors);\r
1174\r
ada38584
RN
1175 if (!EFI_ERROR (Status)) {\r
1176 BusPadding = TRUE;\r
1177 } else if (Status != EFI_NOT_FOUND) {\r
1178 //\r
1179 // EFI_NOT_FOUND is not a real error. It indicates no bus number padding requested.\r
1180 //\r
1181 return Status;\r
2e94e412 1182 }\r
9060e3ec 1183 }\r
1184 }\r
1185 }\r
1186\r
306bbe82 1187 Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1, SubBusNumber);\r
1188 if (EFI_ERROR (Status)) {\r
1189 return Status;\r
9060e3ec 1190 }\r
9060e3ec 1191 SecondBus = *SubBusNumber;\r
1192\r
1193 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1194 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);\r
1195\r
1196 Status = PciRootBridgeIo->Pci.Write (\r
1197 PciRootBridgeIo,\r
1198 EfiPciWidthUint16,\r
1199 Address,\r
1200 1,\r
1201 &Register\r
1202 );\r
1203\r
1204\r
1205 //\r
1206 // If it is PPB, resursively search down this bridge\r
1207 //\r
1208 if (IS_PCI_BRIDGE (&Pci)) {\r
1209\r
1210 //\r
1211 // Temporarily initialize SubBusNumber to maximum bus number to ensure the\r
1212 // PCI configuration transaction to go through any PPB\r
1213 //\r
03ac238b 1214 Register = PciGetMaxBusNumber (Bridge);\r
9060e3ec 1215 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);\r
1216 Status = PciRootBridgeIo->Pci.Write (\r
1217 PciRootBridgeIo,\r
1218 EfiPciWidthUint8,\r
1219 Address,\r
1220 1,\r
1221 &Register\r
1222 );\r
1223\r
1224 //\r
1225 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige\r
1226 //\r
1227 PreprocessController (\r
1228 PciDevice,\r
1229 PciDevice->BusNumber,\r
1230 PciDevice->DeviceNumber,\r
1231 PciDevice->FunctionNumber,\r
1232 EfiPciBeforeChildBusEnumeration\r
1233 );\r
1234\r
9060e3ec 1235 Status = PciScanBus (\r
1236 PciDevice,\r
c7e7613e 1237 SecondBus,\r
9060e3ec 1238 SubBusNumber,\r
1239 PaddedBusRange\r
1240 );\r
1241 if (EFI_ERROR (Status)) {\r
1242 return Status;\r
1243 }\r
1244 }\r
1245\r
1246 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {\r
1247 //\r
1248 // Ensure the device is enabled and initialized\r
1249 //\r
1250 if ((Attributes == EfiPaddingPciRootBridge) &&\r
1251 (State & EFI_HPC_STATE_ENABLED) != 0 &&\r
1252 (State & EFI_HPC_STATE_INITIALIZED) != 0) {\r
c7e7613e 1253 *PaddedBusRange = (UINT8) ((UINT8) (BusRange) + *PaddedBusRange);\r
9060e3ec 1254 } else {\r
c7e7613e
RN
1255 //\r
1256 // Reserve the larger one between the actual occupied bus number and padded bus number\r
1257 //\r
f6830005 1258 Status = PciAllocateBusNumber (PciDevice, SecondBus, (UINT8) (BusRange), &PaddedSubBus);\r
306bbe82 1259 if (EFI_ERROR (Status)) {\r
1260 return Status;\r
1261 }\r
c7e7613e 1262 *SubBusNumber = MAX (PaddedSubBus, *SubBusNumber);\r
9060e3ec 1263 }\r
1264 }\r
1265\r
1266 //\r
1267 // Set the current maximum bus number under the PPB\r
1268 //\r
1269 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);\r
1270\r
1271 Status = PciRootBridgeIo->Pci.Write (\r
1272 PciRootBridgeIo,\r
1273 EfiPciWidthUint8,\r
1274 Address,\r
1275 1,\r
1276 SubBusNumber\r
1277 );\r
1278 } else {\r
1279 //\r
1280 // It is device. Check PCI IOV for Bus reservation\r
9060e3ec 1281 // Go through each function, just reserve the MAX ReservedBusNum for one device\r
1282 //\r
d4048391 1283 if (PcdGetBool (PcdSrIovSupport) && PciDevice->SrIovCapabilityOffset != 0) {\r
9060e3ec 1284 if (TempReservedBusNum < PciDevice->ReservedBusNum) {\r
1285\r
306bbe82 1286 Status = PciAllocateBusNumber (PciDevice, *SubBusNumber, (UINT8) (PciDevice->ReservedBusNum - TempReservedBusNum), SubBusNumber);\r
1287 if (EFI_ERROR (Status)) {\r
1288 return Status;\r
1289 }\r
9060e3ec 1290 TempReservedBusNum = PciDevice->ReservedBusNum;\r
1291\r
1292 if (Func == 0) {\r
1293 DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n", *SubBusNumber));\r
1294 } else {\r
1295 DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x (Update)\n", *SubBusNumber));\r
1296 }\r
1297 }\r
1298 }\r
1299 }\r
1300\r
1301 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1302\r
1303 //\r
1304 // Skip sub functions, this is not a multi function device\r
1305 //\r
1306\r
1307 Func = PCI_MAX_FUNC;\r
1308 }\r
1309 }\r
1310 }\r
1311\r
1312 return EFI_SUCCESS;\r
1313}\r
1314\r
1315/**\r
1316 Process Option Rom on the specified root bridge.\r
1317\r
1318 @param Bridge Pci root bridge device instance.\r
1319\r
1320 @retval EFI_SUCCESS Success process.\r
1321 @retval other Some error occurred when processing Option Rom on the root bridge.\r
1322\r
1323**/\r
1324EFI_STATUS\r
1325PciRootBridgeP2CProcess (\r
1326 IN PCI_IO_DEVICE *Bridge\r
1327 )\r
1328{\r
1329 LIST_ENTRY *CurrentLink;\r
1330 PCI_IO_DEVICE *Temp;\r
1331 EFI_HPC_STATE State;\r
1332 UINT64 PciAddress;\r
1333 EFI_STATUS Status;\r
1334\r
1335 CurrentLink = Bridge->ChildList.ForwardLink;\r
1336\r
1337 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
1338\r
1339 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1340\r
1341 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {\r
1342\r
1343 if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1344\r
1345 //\r
1346 // Raise the EFI_IOB_PCI_HPC_INIT status code\r
1347 //\r
1348 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1349 EFI_PROGRESS_CODE,\r
fe91c992 1350 EFI_IO_BUS_PCI | EFI_IOB_PCI_HPC_INIT,\r
9060e3ec 1351 Temp->DevicePath\r
1352 );\r
1353\r
1354 PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1355 Status = gPciHotPlugInit->InitializeRootHpc (\r
1356 gPciHotPlugInit,\r
1357 Temp->DevicePath,\r
1358 PciAddress,\r
1359 NULL,\r
1360 &State\r
1361 );\r
1362\r
1363 if (!EFI_ERROR (Status)) {\r
1364 Status = PciBridgeEnumerator (Temp);\r
1365\r
1366 if (EFI_ERROR (Status)) {\r
1367 return Status;\r
1368 }\r
1369 }\r
1370\r
1371 CurrentLink = CurrentLink->ForwardLink;\r
1372 continue;\r
1373\r
1374 }\r
1375 }\r
1376\r
1377 if (!IsListEmpty (&Temp->ChildList)) {\r
1378 Status = PciRootBridgeP2CProcess (Temp);\r
1379 }\r
1380\r
1381 CurrentLink = CurrentLink->ForwardLink;\r
1382 }\r
1383\r
1384 return EFI_SUCCESS;\r
1385}\r
1386\r
1387/**\r
1388 Process Option Rom on the specified host bridge.\r
1389\r
1390 @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.\r
1391\r
1392 @retval EFI_SUCCESS Success process.\r
1393 @retval EFI_NOT_FOUND Can not find the root bridge instance.\r
1394 @retval other Some error occurred when processing Option Rom on the host bridge.\r
1395\r
1396**/\r
1397EFI_STATUS\r
1398PciHostBridgeP2CProcess (\r
1399 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
1400 )\r
1401{\r
1402 EFI_HANDLE RootBridgeHandle;\r
1403 PCI_IO_DEVICE *RootBridgeDev;\r
1404 EFI_STATUS Status;\r
1405\r
1406 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1407 return EFI_SUCCESS;\r
1408 }\r
1409\r
1410 RootBridgeHandle = NULL;\r
1411\r
1412 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1413\r
1414 //\r
1415 // Get RootBridg Device by handle\r
1416 //\r
1417 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
1418\r
1419 if (RootBridgeDev == NULL) {\r
1420 return EFI_NOT_FOUND;\r
1421 }\r
1422\r
1423 Status = PciRootBridgeP2CProcess (RootBridgeDev);\r
1424 if (EFI_ERROR (Status)) {\r
1425 return Status;\r
1426 }\r
1427\r
1428 }\r
1429\r
1430 return EFI_SUCCESS;\r
1431}\r
1432\r
1433/**\r
1434 This function is used to enumerate the entire host bridge\r
1435 in a given platform.\r
1436\r
1437 @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.\r
1438\r
1439 @retval EFI_SUCCESS Successfully enumerated the host bridge.\r
1440 @retval EFI_OUT_OF_RESOURCES No enough memory available.\r
1441 @retval other Some error occurred when enumerating the host bridge.\r
1442\r
1443**/\r
1444EFI_STATUS\r
1445PciHostBridgeEnumerator (\r
1446 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
1447 )\r
1448{\r
1449 EFI_HANDLE RootBridgeHandle;\r
1450 PCI_IO_DEVICE *RootBridgeDev;\r
1451 EFI_STATUS Status;\r
1452 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1453 UINT16 MinBus;\r
1454 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1455 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;\r
1456 UINT8 StartBusNumber;\r
1457 LIST_ENTRY RootBridgeList;\r
1458 LIST_ENTRY *Link;\r
1459\r
1460 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1461 InitializeHotPlugSupport ();\r
1462 }\r
1463\r
1464 InitializeListHead (&RootBridgeList);\r
1465\r
1466 //\r
1467 // Notify the bus allocation phase is about to start\r
1468 //\r
ea8d98fa
OM
1469 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1470\r
1471 if (EFI_ERROR (Status)) {\r
1472 return Status;\r
1473 }\r
9060e3ec 1474\r
1475 DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n"));\r
1476 RootBridgeHandle = NULL;\r
1477 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1478\r
1479 //\r
1480 // if a root bridge instance is found, create root bridge device for it\r
1481 //\r
1482\r
1483 RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1484\r
1485 if (RootBridgeDev == NULL) {\r
1486 return EFI_OUT_OF_RESOURCES;\r
1487 }\r
1488\r
1489 //\r
1490 // Enumerate all the buses under this root bridge\r
1491 //\r
1492 Status = PciRootBridgeEnumerator (\r
1493 PciResAlloc,\r
1494 RootBridgeDev\r
1495 );\r
1496\r
1497 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1498 InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));\r
1499 } else {\r
1500 DestroyRootBridge (RootBridgeDev);\r
1501 }\r
1502 if (EFI_ERROR (Status)) {\r
1503 return Status;\r
1504 }\r
1505 }\r
1506\r
1507 //\r
1508 // Notify the bus allocation phase is finished for the first time\r
1509 //\r
1510 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1511\r
1512 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1513 //\r
1514 // Reset all assigned PCI bus number in all PPB\r
1515 //\r
1516 RootBridgeHandle = NULL;\r
1517 Link = GetFirstNode (&RootBridgeList);\r
1518 while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&\r
1519 (!IsNull (&RootBridgeList, Link))) {\r
1520 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);\r
1521 //\r
1522 // Get the Bus information\r
1523 //\r
1524 Status = PciResAlloc->StartBusEnumeration (\r
1525 PciResAlloc,\r
1526 RootBridgeHandle,\r
1527 (VOID **) &Configuration\r
1528 );\r
1529 if (EFI_ERROR (Status)) {\r
1530 return Status;\r
1531 }\r
1532\r
1533 //\r
1534 // Get the bus number to start with\r
1535 //\r
1536 StartBusNumber = (UINT8) (Configuration->AddrRangeMin);\r
1537\r
1538 ResetAllPpbBusNumber (\r
1539 RootBridgeDev,\r
1540 StartBusNumber\r
1541 );\r
1542\r
1543 FreePool (Configuration);\r
8063b47b 1544 Link = RemoveEntryList (Link);\r
9060e3ec 1545 DestroyRootBridge (RootBridgeDev);\r
1546 }\r
1547\r
1548 //\r
1549 // Wait for all HPC initialized\r
1550 //\r
1551 Status = AllRootHPCInitialized (STALL_1_SECOND * 15);\r
1552\r
1553 if (EFI_ERROR (Status)) {\r
55565b08 1554 DEBUG ((EFI_D_ERROR, "Some root HPC failed to initialize\n"));\r
9060e3ec 1555 return Status;\r
1556 }\r
1557\r
1558 //\r
1559 // Notify the bus allocation phase is about to start for the 2nd time\r
1560 //\r
ea8d98fa
OM
1561 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1562\r
1563 if (EFI_ERROR (Status)) {\r
1564 return Status;\r
1565 }\r
9060e3ec 1566\r
1567 DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n"));\r
1568 RootBridgeHandle = NULL;\r
1569 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1570\r
1571 //\r
1572 // if a root bridge instance is found, create root bridge device for it\r
1573 //\r
1574 RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1575\r
1576 if (RootBridgeDev == NULL) {\r
1577 return EFI_OUT_OF_RESOURCES;\r
1578 }\r
1579\r
1580 //\r
1581 // Enumerate all the buses under this root bridge\r
1582 //\r
1583 Status = PciRootBridgeEnumerator (\r
1584 PciResAlloc,\r
1585 RootBridgeDev\r
1586 );\r
1587\r
1588 DestroyRootBridge (RootBridgeDev);\r
1589 if (EFI_ERROR (Status)) {\r
1590 return Status;\r
1591 }\r
1592 }\r
1593\r
1594 //\r
1595 // Notify the bus allocation phase is to end for the 2nd time\r
1596 //\r
1597 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1598 }\r
1599\r
1600 //\r
1601 // Notify the resource allocation phase is to start\r
1602 //\r
ea8d98fa
OM
1603 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);\r
1604\r
1605 if (EFI_ERROR (Status)) {\r
1606 return Status;\r
1607 }\r
9060e3ec 1608\r
1609 RootBridgeHandle = NULL;\r
1610 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1611\r
1612 //\r
1613 // if a root bridge instance is found, create root bridge device for it\r
1614 //\r
1615 RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1616\r
1617 if (RootBridgeDev == NULL) {\r
1618 return EFI_OUT_OF_RESOURCES;\r
1619 }\r
1620\r
1621 Status = StartManagingRootBridge (RootBridgeDev);\r
1622\r
1623 if (EFI_ERROR (Status)) {\r
1624 return Status;\r
1625 }\r
1626\r
1627 PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;\r
1628 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1629\r
1630 if (EFI_ERROR (Status)) {\r
1631 return Status;\r
1632 }\r
1633\r
1634 Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);\r
1635\r
1636 if (EFI_ERROR (Status)) {\r
1637 return Status;\r
1638 }\r
1639\r
1640 //\r
1641 // Determine root bridge attribute by calling interface of Pcihostbridge\r
1642 // protocol\r
1643 //\r
1644 DetermineRootBridgeAttributes (\r
1645 PciResAlloc,\r
1646 RootBridgeDev\r
1647 );\r
1648\r
1649 //\r
1650 // Collect all the resource information under this root bridge\r
1651 // A database that records all the information about pci device subject to this\r
1652 // root bridge will then be created\r
1653 //\r
1654 Status = PciPciDeviceInfoCollector (\r
1655 RootBridgeDev,\r
1656 (UINT8) MinBus\r
1657 );\r
1658\r
1659 if (EFI_ERROR (Status)) {\r
1660 return Status;\r
1661 }\r
1662\r
1663 InsertRootBridge (RootBridgeDev);\r
1664\r
1665 //\r
1666 // Record the hostbridge handle\r
1667 //\r
1668 AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);\r
1669 }\r
1670\r
1671 return EFI_SUCCESS;\r
1672}\r