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