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