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