]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumerator.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciEnumerator.c
CommitLineData
9060e3ec 1/** @file\r
2 PCI eunmeration implementation on entire PCI bus system 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
12/**\r
13 This routine is used to enumerate entire pci bus system\r
14 in a given platform.\r
15\r
26329817
RN
16 @param Controller Parent controller handle.\r
17 @param HostBridgeHandle Host bridge handle.\r
9060e3ec 18\r
19 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
20 @retval other Some error occurred when enumerating the pci bus system.\r
21\r
22**/\r
23EFI_STATUS\r
24PciEnumerator (\r
1436aea4
MK
25 IN EFI_HANDLE Controller,\r
26 IN EFI_HANDLE HostBridgeHandle\r
9060e3ec 27 )\r
28{\r
9060e3ec 29 EFI_STATUS Status;\r
30 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc;\r
9060e3ec 31\r
32 //\r
33 // Get the pci host bridge resource allocation protocol\r
34 //\r
35 Status = gBS->OpenProtocol (\r
36 HostBridgeHandle,\r
37 &gEfiPciHostBridgeResourceAllocationProtocolGuid,\r
1436aea4 38 (VOID **)&PciResAlloc,\r
9060e3ec 39 gPciBusDriverBinding.DriverBindingHandle,\r
40 Controller,\r
41 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
42 );\r
43\r
44 if (EFI_ERROR (Status)) {\r
45 return Status;\r
46 }\r
47\r
48 //\r
49 // Notify the pci bus enumeration is about to begin\r
50 //\r
ea8d98fa
OM
51 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginEnumeration);\r
52\r
53 if (EFI_ERROR (Status)) {\r
54 return Status;\r
55 }\r
9060e3ec 56\r
57 //\r
58 // Start the bus allocation phase\r
59 //\r
60 Status = PciHostBridgeEnumerator (PciResAlloc);\r
61\r
62 if (EFI_ERROR (Status)) {\r
63 return Status;\r
64 }\r
65\r
66 //\r
67 // Submit the resource request\r
68 //\r
69 Status = PciHostBridgeResourceAllocator (PciResAlloc);\r
70\r
71 if (EFI_ERROR (Status)) {\r
72 return Status;\r
73 }\r
74\r
75 //\r
76 // Notify the pci bus enumeration is about to complete\r
77 //\r
ea8d98fa
OM
78 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndEnumeration);\r
79\r
80 if (EFI_ERROR (Status)) {\r
81 return Status;\r
82 }\r
9060e3ec 83\r
84 //\r
85 // Process P2C\r
86 //\r
87 Status = PciHostBridgeP2CProcess (PciResAlloc);\r
88\r
89 if (EFI_ERROR (Status)) {\r
90 return Status;\r
91 }\r
92\r
93 //\r
94 // Process attributes for devices on this host bridge\r
95 //\r
96 Status = PciHostBridgeDeviceAttribute (PciResAlloc);\r
97 if (EFI_ERROR (Status)) {\r
98 return Status;\r
99 }\r
100\r
9060e3ec 101 return EFI_SUCCESS;\r
102}\r
103\r
104/**\r
105 Enumerate PCI root bridge.\r
106\r
107 @param PciResAlloc Pointer to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.\r
108 @param RootBridgeDev Instance of root bridge device.\r
109\r
110 @retval EFI_SUCCESS Successfully enumerated root bridge.\r
111 @retval other Failed to enumerate root bridge.\r
112\r
113**/\r
114EFI_STATUS\r
115PciRootBridgeEnumerator (\r
116 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,\r
117 IN PCI_IO_DEVICE *RootBridgeDev\r
118 )\r
119{\r
1436aea4
MK
120 EFI_STATUS Status;\r
121 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;\r
122 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration1;\r
123 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration2;\r
124 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration3;\r
125 UINT8 SubBusNumber;\r
126 UINT8 StartBusNumber;\r
127 UINT8 PaddedBusRange;\r
128 EFI_HANDLE RootBridgeHandle;\r
129 UINT8 Desc;\r
130 UINT64 AddrLen;\r
131 UINT64 AddrRangeMin;\r
132\r
133 SubBusNumber = 0;\r
134 StartBusNumber = 0;\r
135 PaddedBusRange = 0;\r
9060e3ec 136\r
137 //\r
138 // Get the root bridge handle\r
139 //\r
140 RootBridgeHandle = RootBridgeDev->Handle;\r
141\r
142 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
143 EFI_PROGRESS_CODE,\r
fe91c992 144 EFI_IO_BUS_PCI | EFI_IOB_PCI_BUS_ENUM,\r
9060e3ec 145 RootBridgeDev->DevicePath\r
146 );\r
147\r
148 //\r
149 // Get the Bus information\r
150 //\r
151 Status = PciResAlloc->StartBusEnumeration (\r
152 PciResAlloc,\r
153 RootBridgeHandle,\r
1436aea4 154 (VOID **)&Configuration\r
9060e3ec 155 );\r
156\r
157 if (EFI_ERROR (Status)) {\r
158 return Status;\r
159 }\r
160\r
1436aea4 161 if ((Configuration == NULL) || (Configuration->Desc == ACPI_END_TAG_DESCRIPTOR)) {\r
306bbe82 162 return EFI_INVALID_PARAMETER;\r
163 }\r
1436aea4 164\r
306bbe82 165 RootBridgeDev->BusNumberRanges = Configuration;\r
166\r
167 //\r
168 // Sort the descriptors in ascending order\r
169 //\r
170 for (Configuration1 = Configuration; Configuration1->Desc != ACPI_END_TAG_DESCRIPTOR; Configuration1++) {\r
171 Configuration2 = Configuration1;\r
172 for (Configuration3 = Configuration1 + 1; Configuration3->Desc != ACPI_END_TAG_DESCRIPTOR; Configuration3++) {\r
173 if (Configuration2->AddrRangeMin > Configuration3->AddrRangeMin) {\r
174 Configuration2 = Configuration3;\r
175 }\r
176 }\r
1436aea4 177\r
306bbe82 178 //\r
179 // All other fields other than AddrRangeMin and AddrLen are ignored in a descriptor,\r
180 // so only need to swap these two fields.\r
181 //\r
182 if (Configuration2 != Configuration1) {\r
1436aea4 183 AddrRangeMin = Configuration1->AddrRangeMin;\r
306bbe82 184 Configuration1->AddrRangeMin = Configuration2->AddrRangeMin;\r
185 Configuration2->AddrRangeMin = AddrRangeMin;\r
d1102dba 186\r
1436aea4 187 AddrLen = Configuration1->AddrLen;\r
306bbe82 188 Configuration1->AddrLen = Configuration2->AddrLen;\r
189 Configuration2->AddrLen = AddrLen;\r
190 }\r
191 }\r
192\r
9060e3ec 193 //\r
194 // Get the bus number to start with\r
195 //\r
1436aea4 196 StartBusNumber = (UINT8)(Configuration->AddrRangeMin);\r
9060e3ec 197\r
198 //\r
199 // Initialize the subordinate bus number\r
200 //\r
201 SubBusNumber = StartBusNumber;\r
202\r
203 //\r
204 // Reset all assigned PCI bus number\r
205 //\r
206 ResetAllPpbBusNumber (\r
207 RootBridgeDev,\r
208 StartBusNumber\r
1436aea4 209 );\r
9060e3ec 210\r
211 //\r
212 // Assign bus number\r
213 //\r
214 Status = PciScanBus (\r
1436aea4
MK
215 RootBridgeDev,\r
216 StartBusNumber,\r
217 &SubBusNumber,\r
218 &PaddedBusRange\r
219 );\r
9060e3ec 220\r
221 if (EFI_ERROR (Status)) {\r
222 return Status;\r
223 }\r
224\r
9060e3ec 225 //\r
226 // Assign max bus number scanned\r
227 //\r
9060e3ec 228\r
306bbe82 229 Status = PciAllocateBusNumber (RootBridgeDev, SubBusNumber, PaddedBusRange, &SubBusNumber);\r
230 if (EFI_ERROR (Status)) {\r
231 return Status;\r
d1102dba 232 }\r
306bbe82 233\r
234 //\r
235 // Find the bus range which contains the higest bus number, then returns the number of buses\r
236 // that should be decoded.\r
237 //\r
238 while (Configuration->AddrRangeMin + Configuration->AddrLen - 1 < SubBusNumber) {\r
239 Configuration++;\r
240 }\r
1436aea4
MK
241\r
242 AddrLen = Configuration->AddrLen;\r
306bbe82 243 Configuration->AddrLen = SubBusNumber - Configuration->AddrRangeMin + 1;\r
244\r
245 //\r
246 // Save the Desc field of the next descriptor. Mark the next descriptor as an END descriptor.\r
247 //\r
248 Configuration++;\r
1436aea4 249 Desc = Configuration->Desc;\r
306bbe82 250 Configuration->Desc = ACPI_END_TAG_DESCRIPTOR;\r
d1102dba 251\r
9060e3ec 252 //\r
253 // Set bus number\r
254 //\r
255 Status = PciResAlloc->SetBusNumbers (\r
256 PciResAlloc,\r
257 RootBridgeHandle,\r
306bbe82 258 RootBridgeDev->BusNumberRanges\r
9060e3ec 259 );\r
260\r
306bbe82 261 //\r
262 // Restore changed fields\r
263 //\r
1436aea4 264 Configuration->Desc = Desc;\r
306bbe82 265 (Configuration - 1)->AddrLen = AddrLen;\r
d1102dba 266\r
306bbe82 267 return Status;\r
9060e3ec 268}\r
269\r
270/**\r
271 This routine is used to process all PCI devices' Option Rom\r
272 on a certain root bridge.\r
273\r
274 @param Bridge Given parent's root bridge.\r
275 @param RomBase Base address of ROM driver loaded from.\r
276 @param MaxLength Maximum rom size.\r
277\r
278**/\r
279VOID\r
280ProcessOptionRom (\r
1436aea4
MK
281 IN PCI_IO_DEVICE *Bridge,\r
282 IN UINT64 RomBase,\r
283 IN UINT64 MaxLength\r
9060e3ec 284 )\r
285{\r
1436aea4
MK
286 LIST_ENTRY *CurrentLink;\r
287 PCI_IO_DEVICE *Temp;\r
9060e3ec 288\r
289 //\r
290 // Go through bridges to reach all devices\r
291 //\r
292 CurrentLink = Bridge->ChildList.ForwardLink;\r
293 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
294 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
295 if (!IsListEmpty (&Temp->ChildList)) {\r
9060e3ec 296 //\r
297 // Go further to process the option rom under this bridge\r
298 //\r
299 ProcessOptionRom (Temp, RomBase, MaxLength);\r
300 }\r
301\r
1436aea4 302 if ((Temp->RomSize != 0) && (Temp->RomSize <= MaxLength)) {\r
9060e3ec 303 //\r
304 // Load and process the option rom\r
305 //\r
306 LoadOpRomImage (Temp, RomBase);\r
307 }\r
308\r
309 CurrentLink = CurrentLink->ForwardLink;\r
310 }\r
311}\r
312\r
313/**\r
314 This routine is used to assign bus number to the given PCI bus system\r
315\r
316 @param Bridge Parent root bridge instance.\r
317 @param StartBusNumber Number of beginning.\r
318 @param SubBusNumber The number of sub bus.\r
319\r
320 @retval EFI_SUCCESS Successfully assigned bus number.\r
321 @retval EFI_DEVICE_ERROR Failed to assign bus number.\r
322\r
323**/\r
324EFI_STATUS\r
325PciAssignBusNumber (\r
1436aea4
MK
326 IN PCI_IO_DEVICE *Bridge,\r
327 IN UINT8 StartBusNumber,\r
328 OUT UINT8 *SubBusNumber\r
9060e3ec 329 )\r
330{\r
1436aea4
MK
331 EFI_STATUS Status;\r
332 PCI_TYPE00 Pci;\r
333 UINT8 Device;\r
334 UINT8 Func;\r
335 UINT64 Address;\r
336 UINTN SecondBus;\r
337 UINT16 Register;\r
338 UINT8 Register8;\r
339 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 340\r
341 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
342\r
1436aea4
MK
343 SecondBus = 0;\r
344 Register = 0;\r
9060e3ec 345\r
346 *SubBusNumber = StartBusNumber;\r
347\r
348 //\r
349 // First check to see whether the parent is ppb\r
350 //\r
351 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
352 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
9060e3ec 353 //\r
354 // Check to see whether a pci device is present\r
355 //\r
356 Status = PciDevicePresent (\r
1436aea4
MK
357 PciRootBridgeIo,\r
358 &Pci,\r
359 StartBusNumber,\r
360 Device,\r
361 Func\r
362 );\r
363\r
364 if (EFI_ERROR (Status) && (Func == 0)) {\r
25a26646
JS
365 //\r
366 // go to next device if there is no Function 0\r
367 //\r
368 break;\r
369 }\r
370\r
9060e3ec 371 if (!EFI_ERROR (Status) &&\r
1436aea4
MK
372 (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)))\r
373 {\r
9060e3ec 374 //\r
375 // Reserved one bus for cardbus bridge\r
376 //\r
306bbe82 377 Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1, SubBusNumber);\r
378 if (EFI_ERROR (Status)) {\r
379 return Status;\r
380 }\r
1436aea4 381\r
306bbe82 382 SecondBus = *SubBusNumber;\r
9060e3ec 383\r
1436aea4 384 Register = (UINT16)((SecondBus << 8) | (UINT16)StartBusNumber);\r
9060e3ec 385\r
1436aea4 386 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
9060e3ec 387\r
388 Status = PciRootBridgeIo->Pci.Write (\r
389 PciRootBridgeIo,\r
390 EfiPciWidthUint16,\r
391 Address,\r
392 1,\r
393 &Register\r
394 );\r
395\r
396 //\r
397 // Initialize SubBusNumber to SecondBus\r
398 //\r
399 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1436aea4
MK
400 Status = PciRootBridgeIo->Pci.Write (\r
401 PciRootBridgeIo,\r
402 EfiPciWidthUint8,\r
403 Address,\r
404 1,\r
405 SubBusNumber\r
406 );\r
9060e3ec 407 //\r
408 // If it is PPB, resursively search down this bridge\r
409 //\r
410 if (IS_PCI_BRIDGE (&Pci)) {\r
9060e3ec 411 Register8 = 0xFF;\r
1436aea4
MK
412 Status = PciRootBridgeIo->Pci.Write (\r
413 PciRootBridgeIo,\r
414 EfiPciWidthUint8,\r
415 Address,\r
416 1,\r
417 &Register8\r
418 );\r
9060e3ec 419\r
420 Status = PciAssignBusNumber (\r
1436aea4
MK
421 Bridge,\r
422 (UINT8)(SecondBus),\r
423 SubBusNumber\r
424 );\r
9060e3ec 425\r
426 if (EFI_ERROR (Status)) {\r
427 return EFI_DEVICE_ERROR;\r
428 }\r
429 }\r
430\r
431 //\r
432 // Set the current maximum bus number under the PPB\r
433 //\r
434 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
435\r
436 Status = PciRootBridgeIo->Pci.Write (\r
437 PciRootBridgeIo,\r
438 EfiPciWidthUint8,\r
439 Address,\r
440 1,\r
441 SubBusNumber\r
442 );\r
9060e3ec 443 }\r
444\r
1436aea4 445 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {\r
9060e3ec 446 //\r
447 // Skip sub functions, this is not a multi function device\r
448 //\r
449 Func = PCI_MAX_FUNC;\r
450 }\r
451 }\r
452 }\r
453\r
454 return EFI_SUCCESS;\r
455}\r
456\r
457/**\r
458 This routine is used to determine the root bridge attribute by interfacing\r
459 the host bridge resource allocation protocol.\r
460\r
461 @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
462 @param RootBridgeDev Root bridge instance\r
463\r
464 @retval EFI_SUCCESS Successfully got root bridge's attribute.\r
465 @retval other Failed to get attribute.\r
466\r
467**/\r
468EFI_STATUS\r
469DetermineRootBridgeAttributes (\r
1436aea4
MK
470 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,\r
471 IN PCI_IO_DEVICE *RootBridgeDev\r
9060e3ec 472 )\r
473{\r
474 UINT64 Attributes;\r
475 EFI_STATUS Status;\r
476 EFI_HANDLE RootBridgeHandle;\r
477\r
1436aea4
MK
478 Attributes = 0;\r
479 RootBridgeHandle = RootBridgeDev->Handle;\r
9060e3ec 480\r
481 //\r
482 // Get root bridge attribute by calling into pci host bridge resource allocation protocol\r
483 //\r
484 Status = PciResAlloc->GetAllocAttributes (\r
485 PciResAlloc,\r
486 RootBridgeHandle,\r
487 &Attributes\r
488 );\r
489\r
490 if (EFI_ERROR (Status)) {\r
491 return Status;\r
492 }\r
493\r
494 //\r
495 // Here is the point where PCI bus driver calls HOST bridge allocation protocol\r
496 // Currently we hardcoded for ea815\r
497 //\r
498 if ((Attributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {\r
499 RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED;\r
500 }\r
501\r
502 if ((Attributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0) {\r
60516202 503 RootBridgeDev->Decodes |= EFI_BRIDGE_MEM64_DECODE_SUPPORTED;\r
9060e3ec 504 RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
505 }\r
506\r
507 RootBridgeDev->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
508 RootBridgeDev->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
509 RootBridgeDev->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
510\r
511 return EFI_SUCCESS;\r
512}\r
513\r
514/**\r
515 Get Max Option Rom size on specified bridge.\r
516\r
517 @param Bridge Given bridge device instance.\r
518\r
519 @return Max size of option rom needed.\r
520\r
521**/\r
1f6785c4 522UINT32\r
9060e3ec 523GetMaxOptionRomSize (\r
1436aea4 524 IN PCI_IO_DEVICE *Bridge\r
9060e3ec 525 )\r
526{\r
1436aea4
MK
527 LIST_ENTRY *CurrentLink;\r
528 PCI_IO_DEVICE *Temp;\r
529 UINT32 MaxOptionRomSize;\r
530 UINT32 TempOptionRomSize;\r
9060e3ec 531\r
532 MaxOptionRomSize = 0;\r
533\r
534 //\r
535 // Go through bridges to reach all devices\r
536 //\r
537 CurrentLink = Bridge->ChildList.ForwardLink;\r
538 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
539 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
540 if (!IsListEmpty (&Temp->ChildList)) {\r
9060e3ec 541 //\r
542 // Get max option rom size under this bridge\r
543 //\r
544 TempOptionRomSize = GetMaxOptionRomSize (Temp);\r
545\r
546 //\r
547 // Compare with the option rom size of the bridge\r
548 // Get the larger one\r
549 //\r
550 if (Temp->RomSize > TempOptionRomSize) {\r
551 TempOptionRomSize = Temp->RomSize;\r
552 }\r
9060e3ec 553 } else {\r
9060e3ec 554 //\r
555 // For devices get the rom size directly\r
556 //\r
557 TempOptionRomSize = Temp->RomSize;\r
558 }\r
559\r
560 //\r
561 // Get the largest rom size on this bridge\r
562 //\r
563 if (TempOptionRomSize > MaxOptionRomSize) {\r
564 MaxOptionRomSize = TempOptionRomSize;\r
565 }\r
566\r
567 CurrentLink = CurrentLink->ForwardLink;\r
568 }\r
569\r
570 return MaxOptionRomSize;\r
571}\r
572\r
573/**\r
574 Process attributes of devices on this host bridge\r
575\r
576 @param PciResAlloc Protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.\r
577\r
578 @retval EFI_SUCCESS Successfully process attribute.\r
579 @retval EFI_NOT_FOUND Can not find the specific root bridge device.\r
580 @retval other Failed to determine the root bridge device's attribute.\r
581\r
582**/\r
583EFI_STATUS\r
584PciHostBridgeDeviceAttribute (\r
1436aea4 585 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
9060e3ec 586 )\r
587{\r
1436aea4
MK
588 EFI_HANDLE RootBridgeHandle;\r
589 PCI_IO_DEVICE *RootBridgeDev;\r
590 EFI_STATUS Status;\r
9060e3ec 591\r
592 RootBridgeHandle = NULL;\r
593\r
594 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
9060e3ec 595 //\r
596 // Get RootBridg Device by handle\r
597 //\r
598 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
599\r
600 if (RootBridgeDev == NULL) {\r
601 return EFI_NOT_FOUND;\r
602 }\r
603\r
604 //\r
605 // Set the attributes for devcies behind the Root Bridge\r
606 //\r
607 Status = DetermineDeviceAttribute (RootBridgeDev);\r
608 if (EFI_ERROR (Status)) {\r
609 return Status;\r
610 }\r
9060e3ec 611 }\r
612\r
613 return EFI_SUCCESS;\r
614}\r
615\r
616/**\r
617 Get resource allocation status from the ACPI resource descriptor.\r
618\r
619 @param AcpiConfig Point to Acpi configuration table.\r
620 @param IoResStatus Return the status of I/O resource.\r
621 @param Mem32ResStatus Return the status of 32-bit Memory resource.\r
622 @param PMem32ResStatus Return the status of 32-bit Prefetchable Memory resource.\r
623 @param Mem64ResStatus Return the status of 64-bit Memory resource.\r
624 @param PMem64ResStatus Return the status of 64-bit Prefetchable Memory resource.\r
625\r
626**/\r
627VOID\r
628GetResourceAllocationStatus (\r
629 VOID *AcpiConfig,\r
630 OUT UINT64 *IoResStatus,\r
631 OUT UINT64 *Mem32ResStatus,\r
632 OUT UINT64 *PMem32ResStatus,\r
633 OUT UINT64 *Mem64ResStatus,\r
634 OUT UINT64 *PMem64ResStatus\r
635 )\r
636{\r
1436aea4
MK
637 UINT8 *Temp;\r
638 UINT64 ResStatus;\r
639 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ACPIAddressDesc;\r
9060e3ec 640\r
1436aea4 641 Temp = (UINT8 *)AcpiConfig;\r
9060e3ec 642\r
643 while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1436aea4
MK
644 ACPIAddressDesc = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp;\r
645 ResStatus = ACPIAddressDesc->AddrTranslationOffset;\r
9060e3ec 646\r
647 switch (ACPIAddressDesc->ResType) {\r
1436aea4
MK
648 case 0:\r
649 if (ACPIAddressDesc->AddrSpaceGranularity == 32) {\r
650 if (ACPIAddressDesc->SpecificFlag == 0x06) {\r
651 //\r
652 // Pmem32\r
653 //\r
654 *PMem32ResStatus = ResStatus;\r
655 } else {\r
656 //\r
657 // Mem32\r
658 //\r
659 *Mem32ResStatus = ResStatus;\r
660 }\r
9060e3ec 661 }\r
9060e3ec 662\r
1436aea4
MK
663 if (ACPIAddressDesc->AddrSpaceGranularity == 64) {\r
664 if (ACPIAddressDesc->SpecificFlag == 0x06) {\r
665 //\r
666 // PMem64\r
667 //\r
668 *PMem64ResStatus = ResStatus;\r
669 } else {\r
670 //\r
671 // Mem64\r
672 //\r
673 *Mem64ResStatus = ResStatus;\r
674 }\r
9060e3ec 675 }\r
9060e3ec 676\r
1436aea4 677 break;\r
9060e3ec 678\r
1436aea4
MK
679 case 1:\r
680 //\r
681 // Io\r
682 //\r
683 *IoResStatus = ResStatus;\r
684 break;\r
9060e3ec 685\r
1436aea4
MK
686 default:\r
687 break;\r
9060e3ec 688 }\r
689\r
690 Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
691 }\r
692}\r
693\r
694/**\r
695 Remove a PCI device from device pool and mark its bar.\r
696\r
697 @param PciDevice Instance of Pci device.\r
698\r
699 @retval EFI_SUCCESS Successfully remove the PCI device.\r
700 @retval EFI_ABORTED Pci device is a root bridge or a PCI-PCI bridge.\r
701\r
702**/\r
703EFI_STATUS\r
704RejectPciDevice (\r
1436aea4 705 IN PCI_IO_DEVICE *PciDevice\r
9060e3ec 706 )\r
707{\r
1436aea4
MK
708 PCI_IO_DEVICE *Bridge;\r
709 PCI_IO_DEVICE *Temp;\r
710 LIST_ENTRY *CurrentLink;\r
9060e3ec 711\r
712 //\r
713 // Remove the padding resource from a bridge\r
714 //\r
1436aea4
MK
715 if ( IS_PCI_BRIDGE (&PciDevice->Pci) &&\r
716 (PciDevice->ResourcePaddingDescriptors != NULL))\r
717 {\r
9060e3ec 718 FreePool (PciDevice->ResourcePaddingDescriptors);\r
719 PciDevice->ResourcePaddingDescriptors = NULL;\r
720 return EFI_SUCCESS;\r
721 }\r
722\r
723 //\r
724 // Skip RB and PPB\r
725 //\r
726 if (IS_PCI_BRIDGE (&PciDevice->Pci) || (PciDevice->Parent == NULL)) {\r
727 return EFI_ABORTED;\r
728 }\r
729\r
730 if (IS_CARDBUS_BRIDGE (&PciDevice->Pci)) {\r
731 //\r
732 // Get the root bridge device\r
733 //\r
734 Bridge = PciDevice;\r
735 while (Bridge->Parent != NULL) {\r
736 Bridge = Bridge->Parent;\r
737 }\r
738\r
739 RemoveAllPciDeviceOnBridge (Bridge->Handle, PciDevice);\r
740\r
741 //\r
742 // Mark its bar\r
743 //\r
744 InitializeP2C (PciDevice);\r
745 }\r
746\r
747 //\r
748 // Remove the device\r
749 //\r
750 Bridge = PciDevice->Parent;\r
751 CurrentLink = Bridge->ChildList.ForwardLink;\r
752 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
753 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
754 if (Temp == PciDevice) {\r
755 InitializePciDevice (Temp);\r
756 RemoveEntryList (CurrentLink);\r
9060e3ec 757 return EFI_SUCCESS;\r
758 }\r
759\r
760 CurrentLink = CurrentLink->ForwardLink;\r
761 }\r
762\r
763 return EFI_ABORTED;\r
764}\r
765\r
766/**\r
767 Determine whethter a PCI device can be rejected.\r
768\r
769 @param PciResNode Pointer to Pci resource node instance.\r
770\r
771 @retval TRUE The PCI device can be rejected.\r
772 @retval TRUE The PCI device cannot be rejected.\r
773\r
774**/\r
775BOOLEAN\r
776IsRejectiveDevice (\r
1436aea4 777 IN PCI_RESOURCE_NODE *PciResNode\r
9060e3ec 778 )\r
779{\r
1436aea4 780 PCI_IO_DEVICE *Temp;\r
9060e3ec 781\r
782 Temp = PciResNode->PciDev;\r
783\r
784 //\r
785 // Ensure the device is present\r
786 //\r
787 if (Temp == NULL) {\r
788 return FALSE;\r
789 }\r
790\r
791 //\r
792 // PPB and RB should go ahead\r
793 //\r
794 if (IS_PCI_BRIDGE (&Temp->Pci) || (Temp->Parent == NULL)) {\r
795 return TRUE;\r
796 }\r
797\r
798 //\r
799 // Skip device on Bus0\r
800 //\r
801 if ((Temp->Parent != NULL) && (Temp->BusNumber == 0)) {\r
802 return FALSE;\r
803 }\r
804\r
805 //\r
806 // Skip VGA\r
807 //\r
808 if (IS_PCI_VGA (&Temp->Pci)) {\r
809 return FALSE;\r
810 }\r
811\r
812 return TRUE;\r
813}\r
814\r
815/**\r
816 Compare two resource nodes and get the larger resource consumer.\r
817\r
818 @param PciResNode1 resource node 1 want to be compared\r
819 @param PciResNode2 resource node 2 want to be compared\r
820\r
821 @return Larger resource node.\r
822\r
823**/\r
824PCI_RESOURCE_NODE *\r
825GetLargerConsumerDevice (\r
1436aea4
MK
826 IN PCI_RESOURCE_NODE *PciResNode1,\r
827 IN PCI_RESOURCE_NODE *PciResNode2\r
9060e3ec 828 )\r
829{\r
830 if (PciResNode2 == NULL) {\r
831 return PciResNode1;\r
832 }\r
833\r
1436aea4
MK
834 if ( (IS_PCI_BRIDGE (&(PciResNode2->PciDev->Pci)) || (PciResNode2->PciDev->Parent == NULL)) \\r
835 && (PciResNode2->ResourceUsage != PciResUsagePadding))\r
9060e3ec 836 {\r
837 return PciResNode1;\r
838 }\r
839\r
840 if (PciResNode1 == NULL) {\r
841 return PciResNode2;\r
842 }\r
843\r
844 if ((PciResNode1->Length) > (PciResNode2->Length)) {\r
845 return PciResNode1;\r
846 }\r
847\r
848 return PciResNode2;\r
849}\r
850\r
9060e3ec 851/**\r
852 Get the max resource consumer in the host resource pool.\r
853\r
854 @param ResPool Pointer to resource pool node.\r
855\r
856 @return The max resource consumer in the host resource pool.\r
857\r
858**/\r
859PCI_RESOURCE_NODE *\r
860GetMaxResourceConsumerDevice (\r
1436aea4 861 IN PCI_RESOURCE_NODE *ResPool\r
9060e3ec 862 )\r
863{\r
1436aea4
MK
864 PCI_RESOURCE_NODE *Temp;\r
865 LIST_ENTRY *CurrentLink;\r
866 PCI_RESOURCE_NODE *PciResNode;\r
867 PCI_RESOURCE_NODE *PPBResNode;\r
9060e3ec 868\r
1436aea4 869 PciResNode = NULL;\r
9060e3ec 870\r
871 CurrentLink = ResPool->ChildList.ForwardLink;\r
872 while (CurrentLink != NULL && CurrentLink != &ResPool->ChildList) {\r
9060e3ec 873 Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
874\r
875 if (!IsRejectiveDevice (Temp)) {\r
876 CurrentLink = CurrentLink->ForwardLink;\r
877 continue;\r
878 }\r
879\r
1436aea4
MK
880 if ( (IS_PCI_BRIDGE (&(Temp->PciDev->Pci)) || (Temp->PciDev->Parent == NULL)) \\r
881 && (Temp->ResourceUsage != PciResUsagePadding))\r
9060e3ec 882 {\r
1436aea4
MK
883 PPBResNode = GetMaxResourceConsumerDevice (Temp);\r
884 PciResNode = GetLargerConsumerDevice (PciResNode, PPBResNode);\r
9060e3ec 885 } else {\r
886 PciResNode = GetLargerConsumerDevice (PciResNode, Temp);\r
887 }\r
888\r
889 CurrentLink = CurrentLink->ForwardLink;\r
890 }\r
891\r
892 return PciResNode;\r
893}\r
894\r
895/**\r
896 Adjust host bridge allocation so as to reduce resource requirement\r
897\r
898 @param IoPool Pointer to instance of I/O resource Node.\r
899 @param Mem32Pool Pointer to instance of 32-bit memory resource Node.\r
900 @param PMem32Pool Pointer to instance of 32-bit Prefetchable memory resource node.\r
901 @param Mem64Pool Pointer to instance of 64-bit memory resource node.\r
902 @param PMem64Pool Pointer to instance of 64-bit Prefetchable memory resource node.\r
903 @param IoResStatus Status of I/O resource Node.\r
904 @param Mem32ResStatus Status of 32-bit memory resource Node.\r
905 @param PMem32ResStatus Status of 32-bit Prefetchable memory resource node.\r
906 @param Mem64ResStatus Status of 64-bit memory resource node.\r
907 @param PMem64ResStatus Status of 64-bit Prefetchable memory resource node.\r
908\r
2048c585 909 @retval EFI_SUCCESS Successfully adjusted resource on host bridge.\r
9060e3ec 910 @retval EFI_ABORTED Host bridge hasn't this resource type or no resource be adjusted.\r
911\r
912**/\r
913EFI_STATUS\r
914PciHostBridgeAdjustAllocation (\r
1436aea4
MK
915 IN PCI_RESOURCE_NODE *IoPool,\r
916 IN PCI_RESOURCE_NODE *Mem32Pool,\r
917 IN PCI_RESOURCE_NODE *PMem32Pool,\r
918 IN PCI_RESOURCE_NODE *Mem64Pool,\r
919 IN PCI_RESOURCE_NODE *PMem64Pool,\r
920 IN UINT64 IoResStatus,\r
921 IN UINT64 Mem32ResStatus,\r
922 IN UINT64 PMem32ResStatus,\r
923 IN UINT64 Mem64ResStatus,\r
924 IN UINT64 PMem64ResStatus\r
9060e3ec 925 )\r
926{\r
1436aea4
MK
927 BOOLEAN AllocationAjusted;\r
928 PCI_RESOURCE_NODE *PciResNode;\r
929 PCI_RESOURCE_NODE *ResPool[5];\r
930 PCI_IO_DEVICE *RemovedPciDev[5];\r
931 UINT64 ResStatus[5];\r
932 UINTN RemovedPciDevNum;\r
933 UINTN DevIndex;\r
934 UINTN ResType;\r
935 EFI_STATUS Status;\r
936 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;\r
9060e3ec 937\r
938 PciResNode = NULL;\r
939 ZeroMem (RemovedPciDev, 5 * sizeof (PCI_IO_DEVICE *));\r
1436aea4 940 RemovedPciDevNum = 0;\r
9060e3ec 941\r
1436aea4
MK
942 ResPool[0] = IoPool;\r
943 ResPool[1] = Mem32Pool;\r
944 ResPool[2] = PMem32Pool;\r
945 ResPool[3] = Mem64Pool;\r
946 ResPool[4] = PMem64Pool;\r
9060e3ec 947\r
1436aea4
MK
948 ResStatus[0] = IoResStatus;\r
949 ResStatus[1] = Mem32ResStatus;\r
950 ResStatus[2] = PMem32ResStatus;\r
951 ResStatus[3] = Mem64ResStatus;\r
952 ResStatus[4] = PMem64ResStatus;\r
9060e3ec 953\r
954 AllocationAjusted = FALSE;\r
955\r
956 for (ResType = 0; ResType < 5; ResType++) {\r
9060e3ec 957 if (ResStatus[ResType] == EFI_RESOURCE_SATISFIED) {\r
958 continue;\r
959 }\r
960\r
961 if (ResStatus[ResType] == EFI_RESOURCE_NOT_SATISFIED) {\r
962 //\r
963 // Host bridge hasn't this resource type\r
964 //\r
965 return EFI_ABORTED;\r
966 }\r
967\r
968 //\r
969 // Hostbridge hasn't enough resource\r
970 //\r
971 PciResNode = GetMaxResourceConsumerDevice (ResPool[ResType]);\r
972 if (PciResNode == NULL) {\r
973 continue;\r
974 }\r
975\r
976 //\r
977 // Check if the device has been removed before\r
978 //\r
979 for (DevIndex = 0; DevIndex < RemovedPciDevNum; DevIndex++) {\r
980 if (PciResNode->PciDev == RemovedPciDev[DevIndex]) {\r
981 break;\r
982 }\r
983 }\r
984\r
985 if (DevIndex != RemovedPciDevNum) {\r
986 continue;\r
987 }\r
988\r
989 //\r
990 // Remove the device if it isn't in the array\r
991 //\r
992 Status = RejectPciDevice (PciResNode->PciDev);\r
993 if (Status == EFI_SUCCESS) {\r
724f26a9 994 DEBUG ((\r
87000d77 995 DEBUG_ERROR,\r
724f26a9 996 "PciBus: [%02x|%02x|%02x] was rejected due to resource confliction.\n",\r
1436aea4
MK
997 PciResNode->PciDev->BusNumber,\r
998 PciResNode->PciDev->DeviceNumber,\r
999 PciResNode->PciDev->FunctionNumber\r
724f26a9 1000 ));\r
9060e3ec 1001\r
1002 //\r
1003 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code\r
1004 //\r
1005 //\r
1006 // Have no way to get ReqRes, AllocRes & Bar here\r
1007 //\r
1008 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));\r
1436aea4
MK
1009 AllocFailExtendedData.DevicePathSize = (UINT16)sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
1010 AllocFailExtendedData.DevicePath = (UINT8 *)PciResNode->PciDev->DevicePath;\r
9060e3ec 1011 AllocFailExtendedData.Bar = PciResNode->Bar;\r
1012\r
1013 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1436aea4
MK
1014 EFI_PROGRESS_CODE,\r
1015 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,\r
1016 (VOID *)&AllocFailExtendedData,\r
1017 sizeof (AllocFailExtendedData)\r
1018 );\r
9060e3ec 1019\r
1020 //\r
1021 // Add it to the array and indicate at least a device has been rejected\r
1022 //\r
1023 RemovedPciDev[RemovedPciDevNum++] = PciResNode->PciDev;\r
1024 AllocationAjusted = TRUE;\r
1025 }\r
1026 }\r
1436aea4 1027\r
9060e3ec 1028 //\r
1029 // End for\r
1030 //\r
1031\r
1032 if (AllocationAjusted) {\r
1033 return EFI_SUCCESS;\r
1034 } else {\r
1035 return EFI_ABORTED;\r
1036 }\r
1037}\r
1038\r
1039/**\r
2048c585 1040 Summary requests for all resource type, and construct ACPI resource\r
9060e3ec 1041 requestor instance.\r
1042\r
1043 @param Bridge detecting bridge\r
1044 @param IoNode Pointer to instance of I/O resource Node\r
1045 @param Mem32Node Pointer to instance of 32-bit memory resource Node\r
1046 @param PMem32Node Pointer to instance of 32-bit Pmemory resource node\r
1047 @param Mem64Node Pointer to instance of 64-bit memory resource node\r
1048 @param PMem64Node Pointer to instance of 64-bit Pmemory resource node\r
1049 @param Config Output buffer holding new constructed APCI resource requestor\r
1050\r
1051 @retval EFI_SUCCESS Successfully constructed ACPI resource.\r
2048c585 1052 @retval EFI_OUT_OF_RESOURCES No memory available.\r
9060e3ec 1053\r
1054**/\r
1055EFI_STATUS\r
1056ConstructAcpiResourceRequestor (\r
1057 IN PCI_IO_DEVICE *Bridge,\r
1058 IN PCI_RESOURCE_NODE *IoNode,\r
1059 IN PCI_RESOURCE_NODE *Mem32Node,\r
1060 IN PCI_RESOURCE_NODE *PMem32Node,\r
1061 IN PCI_RESOURCE_NODE *Mem64Node,\r
1062 IN PCI_RESOURCE_NODE *PMem64Node,\r
1063 OUT VOID **Config\r
1064 )\r
1065{\r
1436aea4
MK
1066 UINT8 NumConfig;\r
1067 UINT8 Aperture;\r
1068 UINT8 *Configuration;\r
1069 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1070 EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd;\r
9060e3ec 1071\r
1072 NumConfig = 0;\r
1073 Aperture = 0;\r
1074\r
1436aea4 1075 *Config = NULL;\r
9060e3ec 1076\r
1077 //\r
1078 // if there is io request, add to the io aperture\r
1079 //\r
1080 if (ResourceRequestExisted (IoNode)) {\r
1081 NumConfig++;\r
1082 Aperture |= 0x01;\r
1083 }\r
1084\r
1085 //\r
1086 // if there is mem32 request, add to the mem32 aperture\r
1087 //\r
1088 if (ResourceRequestExisted (Mem32Node)) {\r
1089 NumConfig++;\r
1090 Aperture |= 0x02;\r
1091 }\r
1092\r
1093 //\r
1094 // if there is pmem32 request, add to the pmem32 aperture\r
1095 //\r
1096 if (ResourceRequestExisted (PMem32Node)) {\r
1097 NumConfig++;\r
1098 Aperture |= 0x04;\r
1099 }\r
1100\r
1101 //\r
1102 // if there is mem64 request, add to the mem64 aperture\r
1103 //\r
1104 if (ResourceRequestExisted (Mem64Node)) {\r
1105 NumConfig++;\r
1106 Aperture |= 0x08;\r
1107 }\r
1108\r
1109 //\r
1110 // if there is pmem64 request, add to the pmem64 aperture\r
1111 //\r
1112 if (ResourceRequestExisted (PMem64Node)) {\r
1113 NumConfig++;\r
1114 Aperture |= 0x10;\r
1115 }\r
1116\r
1117 if (NumConfig != 0) {\r
9060e3ec 1118 //\r
1119 // If there is at least one type of resource request,\r
1120 // allocate a acpi resource node\r
1121 //\r
1122 Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1123 if (Configuration == NULL) {\r
1124 return EFI_OUT_OF_RESOURCES;\r
1125 }\r
1126\r
1436aea4 1127 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r
9060e3ec 1128\r
1129 //\r
1130 // Deal with io aperture\r
1131 //\r
1132 if ((Aperture & 0x01) != 0) {\r
1436aea4
MK
1133 Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1134 Ptr->Len = (UINT16)(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);\r
9060e3ec 1135 //\r
1136 // Io\r
1137 //\r
1436aea4 1138 Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
9060e3ec 1139 //\r
1140 // non ISA range\r
1141 //\r
1142 Ptr->SpecificFlag = 1;\r
1143 Ptr->AddrLen = IoNode->Length;\r
1144 Ptr->AddrRangeMax = IoNode->Alignment;\r
1145\r
1146 Ptr++;\r
1147 }\r
1436aea4 1148\r
9060e3ec 1149 //\r
1150 // Deal with mem32 aperture\r
1151 //\r
1152 if ((Aperture & 0x02) != 0) {\r
1436aea4
MK
1153 Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1154 Ptr->Len = (UINT16)(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);\r
9060e3ec 1155 //\r
1156 // Mem\r
1157 //\r
1436aea4 1158 Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
9060e3ec 1159 //\r
1160 // Nonprefechable\r
1161 //\r
1162 Ptr->SpecificFlag = 0;\r
1163 //\r
1164 // 32 bit\r
1165 //\r
1166 Ptr->AddrSpaceGranularity = 32;\r
1436aea4
MK
1167 Ptr->AddrLen = Mem32Node->Length;\r
1168 Ptr->AddrRangeMax = Mem32Node->Alignment;\r
9060e3ec 1169\r
1170 Ptr++;\r
1171 }\r
1172\r
1173 //\r
1174 // Deal with Pmem32 aperture\r
1175 //\r
1176 if ((Aperture & 0x04) != 0) {\r
1436aea4
MK
1177 Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1178 Ptr->Len = (UINT16)(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);\r
9060e3ec 1179 //\r
1180 // Mem\r
1181 //\r
1436aea4 1182 Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
9060e3ec 1183 //\r
1184 // prefechable\r
1185 //\r
1186 Ptr->SpecificFlag = 0x6;\r
1187 //\r
1188 // 32 bit\r
1189 //\r
1190 Ptr->AddrSpaceGranularity = 32;\r
1436aea4
MK
1191 Ptr->AddrLen = PMem32Node->Length;\r
1192 Ptr->AddrRangeMax = PMem32Node->Alignment;\r
9060e3ec 1193\r
1194 Ptr++;\r
1195 }\r
1436aea4 1196\r
9060e3ec 1197 //\r
1198 // Deal with mem64 aperture\r
1199 //\r
1200 if ((Aperture & 0x08) != 0) {\r
1436aea4
MK
1201 Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1202 Ptr->Len = (UINT16)(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);\r
9060e3ec 1203 //\r
1204 // Mem\r
1205 //\r
1436aea4 1206 Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
9060e3ec 1207 //\r
1208 // nonprefechable\r
1209 //\r
1210 Ptr->SpecificFlag = 0;\r
1211 //\r
1212 // 64 bit\r
1213 //\r
1214 Ptr->AddrSpaceGranularity = 64;\r
1436aea4
MK
1215 Ptr->AddrLen = Mem64Node->Length;\r
1216 Ptr->AddrRangeMax = Mem64Node->Alignment;\r
9060e3ec 1217\r
1218 Ptr++;\r
1219 }\r
1436aea4 1220\r
9060e3ec 1221 //\r
1222 // Deal with Pmem64 aperture\r
1223 //\r
1224 if ((Aperture & 0x10) != 0) {\r
1436aea4
MK
1225 Ptr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1226 Ptr->Len = (UINT16)(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);\r
9060e3ec 1227 //\r
1228 // Mem\r
1229 //\r
1436aea4 1230 Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
9060e3ec 1231 //\r
1232 // prefechable\r
1233 //\r
1234 Ptr->SpecificFlag = 0x06;\r
1235 //\r
1236 // 64 bit\r
1237 //\r
1238 Ptr->AddrSpaceGranularity = 64;\r
1436aea4
MK
1239 Ptr->AddrLen = PMem64Node->Length;\r
1240 Ptr->AddrRangeMax = PMem64Node->Alignment;\r
9060e3ec 1241\r
1242 Ptr++;\r
1243 }\r
1244\r
1245 //\r
1246 // put the checksum\r
1247 //\r
1436aea4 1248 PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)Ptr;\r
9060e3ec 1249\r
1436aea4
MK
1250 PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1251 PtrEnd->Checksum = 0;\r
9060e3ec 1252 } else {\r
9060e3ec 1253 //\r
1254 // If there is no resource request\r
1255 //\r
b59e2427 1256 Configuration = AllocateZeroPool (sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
9060e3ec 1257 if (Configuration == NULL) {\r
1258 return EFI_OUT_OF_RESOURCES;\r
1259 }\r
1260\r
1436aea4
MK
1261 PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration);\r
1262 PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1263 PtrEnd->Checksum = 0;\r
9060e3ec 1264 }\r
1265\r
1266 *Config = Configuration;\r
1267\r
1268 return EFI_SUCCESS;\r
1269}\r
1270\r
1271/**\r
1272 Get resource base from an acpi configuration descriptor.\r
1273\r
1274 @param Config An acpi configuration descriptor.\r
1275 @param IoBase Output of I/O resource base address.\r
1276 @param Mem32Base Output of 32-bit memory base address.\r
1277 @param PMem32Base Output of 32-bit prefetchable memory base address.\r
1278 @param Mem64Base Output of 64-bit memory base address.\r
1279 @param PMem64Base Output of 64-bit prefetchable memory base address.\r
1280\r
1281**/\r
1282VOID\r
1283GetResourceBase (\r
1284 IN VOID *Config,\r
1285 OUT UINT64 *IoBase,\r
1286 OUT UINT64 *Mem32Base,\r
1287 OUT UINT64 *PMem32Base,\r
1288 OUT UINT64 *Mem64Base,\r
1289 OUT UINT64 *PMem64Base\r
1290 )\r
1291{\r
1436aea4
MK
1292 UINT8 *Temp;\r
1293 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1294 UINT64 ResStatus;\r
9060e3ec 1295\r
1296 ASSERT (Config != NULL);\r
1297\r
1298 *IoBase = 0xFFFFFFFFFFFFFFFFULL;\r
1299 *Mem32Base = 0xFFFFFFFFFFFFFFFFULL;\r
1300 *PMem32Base = 0xFFFFFFFFFFFFFFFFULL;\r
1301 *Mem64Base = 0xFFFFFFFFFFFFFFFFULL;\r
1302 *PMem64Base = 0xFFFFFFFFFFFFFFFFULL;\r
1303\r
1436aea4 1304 Temp = (UINT8 *)Config;\r
9060e3ec 1305\r
1306 while (*Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1436aea4 1307 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Temp;\r
9060e3ec 1308 ResStatus = Ptr->AddrTranslationOffset;\r
1309\r
1310 if (ResStatus == EFI_RESOURCE_SATISFIED) {\r
9060e3ec 1311 switch (Ptr->ResType) {\r
9060e3ec 1312 //\r
1436aea4 1313 // Memory type aperture\r
9060e3ec 1314 //\r
1436aea4
MK
1315 case 0:\r
1316\r
1317 //\r
1318 // Check to see the granularity\r
1319 //\r
1320 if (Ptr->AddrSpaceGranularity == 32) {\r
1321 if ((Ptr->SpecificFlag & 0x06) != 0) {\r
1322 *PMem32Base = Ptr->AddrRangeMin;\r
1323 } else {\r
1324 *Mem32Base = Ptr->AddrRangeMin;\r
1325 }\r
9060e3ec 1326 }\r
9060e3ec 1327\r
1436aea4
MK
1328 if (Ptr->AddrSpaceGranularity == 64) {\r
1329 if ((Ptr->SpecificFlag & 0x06) != 0) {\r
1330 *PMem64Base = Ptr->AddrRangeMin;\r
1331 } else {\r
1332 *Mem64Base = Ptr->AddrRangeMin;\r
1333 }\r
9060e3ec 1334 }\r
9060e3ec 1335\r
1436aea4 1336 break;\r
9060e3ec 1337\r
1436aea4 1338 case 1:\r
9060e3ec 1339\r
1436aea4
MK
1340 //\r
1341 // Io type aperture\r
1342 //\r
1343 *IoBase = Ptr->AddrRangeMin;\r
1344 break;\r
9060e3ec 1345\r
1436aea4
MK
1346 default:\r
1347 break;\r
9060e3ec 1348 }\r
1436aea4 1349\r
9060e3ec 1350 //\r
1351 // End switch\r
1352 //\r
1353 }\r
1436aea4 1354\r
9060e3ec 1355 //\r
1356 // End for\r
1357 //\r
1358 Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
1359 }\r
1360}\r
1361\r
1362/**\r
1363 Enumerate pci bridge, allocate resource and determine attribute\r
1364 for devices on this bridge.\r
1365\r
1366 @param BridgeDev Pointer to instance of bridge device.\r
1367\r
1368 @retval EFI_SUCCESS Successfully enumerated PCI bridge.\r
1369 @retval other Failed to enumerate.\r
1370\r
1371**/\r
1372EFI_STATUS\r
1373PciBridgeEnumerator (\r
1436aea4 1374 IN PCI_IO_DEVICE *BridgeDev\r
9060e3ec 1375 )\r
1376{\r
1436aea4
MK
1377 UINT8 SubBusNumber;\r
1378 UINT8 StartBusNumber;\r
1379 EFI_PCI_IO_PROTOCOL *PciIo;\r
1380 EFI_STATUS Status;\r
9060e3ec 1381\r
1436aea4
MK
1382 SubBusNumber = 0;\r
1383 StartBusNumber = 0;\r
1384 PciIo = &(BridgeDev->PciIo);\r
1385 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1, &StartBusNumber);\r
9060e3ec 1386\r
1387 if (EFI_ERROR (Status)) {\r
1388 return Status;\r
1389 }\r
1390\r
1391 Status = PciAssignBusNumber (\r
1436aea4
MK
1392 BridgeDev,\r
1393 StartBusNumber,\r
1394 &SubBusNumber\r
1395 );\r
9060e3ec 1396\r
1397 if (EFI_ERROR (Status)) {\r
1398 return Status;\r
1399 }\r
1400\r
1401 Status = PciPciDeviceInfoCollector (BridgeDev, StartBusNumber);\r
1402\r
1403 if (EFI_ERROR (Status)) {\r
1404 return Status;\r
1405 }\r
1406\r
1407 Status = PciBridgeResourceAllocator (BridgeDev);\r
1408\r
1409 if (EFI_ERROR (Status)) {\r
1410 return Status;\r
1411 }\r
1412\r
1413 Status = DetermineDeviceAttribute (BridgeDev);\r
1414\r
1415 if (EFI_ERROR (Status)) {\r
1416 return Status;\r
1417 }\r
1418\r
1419 return EFI_SUCCESS;\r
9060e3ec 1420}\r
1421\r
1422/**\r
1423 Allocate all kinds of resource for PCI bridge.\r
1424\r
1425 @param Bridge Pointer to bridge instance.\r
1426\r
1427 @retval EFI_SUCCESS Successfully allocated resource for PCI bridge.\r
1428 @retval other Failed to allocate resource for bridge.\r
1429\r
1430**/\r
1431EFI_STATUS\r
1432PciBridgeResourceAllocator (\r
1433 IN PCI_IO_DEVICE *Bridge\r
1434 )\r
1435{\r
1436aea4
MK
1436 PCI_RESOURCE_NODE *IoBridge;\r
1437 PCI_RESOURCE_NODE *Mem32Bridge;\r
1438 PCI_RESOURCE_NODE *PMem32Bridge;\r
1439 PCI_RESOURCE_NODE *Mem64Bridge;\r
1440 PCI_RESOURCE_NODE *PMem64Bridge;\r
1441 UINT64 IoBase;\r
1442 UINT64 Mem32Base;\r
1443 UINT64 PMem32Base;\r
1444 UINT64 Mem64Base;\r
1445 UINT64 PMem64Base;\r
1446 EFI_STATUS Status;\r
9060e3ec 1447\r
1448 IoBridge = CreateResourceNode (\r
1449 Bridge,\r
1450 0,\r
1ef26783 1451 Bridge->BridgeIoAlignment,\r
9060e3ec 1452 0,\r
1453 PciBarTypeIo16,\r
1454 PciResUsageTypical\r
1455 );\r
1456\r
1457 Mem32Bridge = CreateResourceNode (\r
1458 Bridge,\r
1459 0,\r
1460 0xFFFFF,\r
1461 0,\r
1462 PciBarTypeMem32,\r
1463 PciResUsageTypical\r
1464 );\r
1465\r
1466 PMem32Bridge = CreateResourceNode (\r
1467 Bridge,\r
1468 0,\r
1469 0xFFFFF,\r
1470 0,\r
1471 PciBarTypePMem32,\r
1472 PciResUsageTypical\r
1473 );\r
1474\r
1475 Mem64Bridge = CreateResourceNode (\r
1476 Bridge,\r
1477 0,\r
1478 0xFFFFF,\r
1479 0,\r
1480 PciBarTypeMem64,\r
1481 PciResUsageTypical\r
1482 );\r
1483\r
1484 PMem64Bridge = CreateResourceNode (\r
1485 Bridge,\r
1486 0,\r
1487 0xFFFFF,\r
1488 0,\r
1489 PciBarTypePMem64,\r
1490 PciResUsageTypical\r
1491 );\r
1492\r
1493 //\r
1494 // Create resourcemap by going through all the devices subject to this root bridge\r
1495 //\r
1496 CreateResourceMap (\r
1497 Bridge,\r
1498 IoBridge,\r
1499 Mem32Bridge,\r
1500 PMem32Bridge,\r
1501 Mem64Bridge,\r
1502 PMem64Bridge\r
1503 );\r
1504\r
1505 Status = GetResourceBaseFromBridge (\r
1506 Bridge,\r
1507 &IoBase,\r
1508 &Mem32Base,\r
1509 &PMem32Base,\r
1510 &Mem64Base,\r
1511 &PMem64Base\r
1512 );\r
1513\r
1514 if (EFI_ERROR (Status)) {\r
1515 return Status;\r
1516 }\r
1517\r
1518 //\r
1519 // Program IO resources\r
1520 //\r
1521 ProgramResource (\r
1522 IoBase,\r
1523 IoBridge\r
1524 );\r
1525\r
1526 //\r
1527 // Program Mem32 resources\r
1528 //\r
1529 ProgramResource (\r
1530 Mem32Base,\r
1531 Mem32Bridge\r
1532 );\r
1533\r
1534 //\r
1535 // Program PMem32 resources\r
1536 //\r
1537 ProgramResource (\r
1538 PMem32Base,\r
1539 PMem32Bridge\r
1540 );\r
1541\r
1542 //\r
1543 // Program Mem64 resources\r
1544 //\r
1545 ProgramResource (\r
1546 Mem64Base,\r
1547 Mem64Bridge\r
1548 );\r
1549\r
1550 //\r
1551 // Program PMem64 resources\r
1552 //\r
1553 ProgramResource (\r
1554 PMem64Base,\r
1555 PMem64Bridge\r
1556 );\r
1557\r
1558 DestroyResourceTree (IoBridge);\r
1559 DestroyResourceTree (Mem32Bridge);\r
1560 DestroyResourceTree (PMem32Bridge);\r
1561 DestroyResourceTree (PMem64Bridge);\r
1562 DestroyResourceTree (Mem64Bridge);\r
1563\r
1564 gBS->FreePool (IoBridge);\r
1565 gBS->FreePool (Mem32Bridge);\r
1566 gBS->FreePool (PMem32Bridge);\r
1567 gBS->FreePool (PMem64Bridge);\r
1568 gBS->FreePool (Mem64Bridge);\r
1569\r
1570 return EFI_SUCCESS;\r
1571}\r
1572\r
1573/**\r
1574 Get resource base address for a pci bridge device.\r
1575\r
1576 @param Bridge Given Pci driver instance.\r
1577 @param IoBase Output for base address of I/O type resource.\r
1578 @param Mem32Base Output for base address of 32-bit memory type resource.\r
1579 @param PMem32Base Ooutput for base address of 32-bit Pmemory type resource.\r
1580 @param Mem64Base Output for base address of 64-bit memory type resource.\r
1581 @param PMem64Base Output for base address of 64-bit Pmemory type resource.\r
1582\r
1583 @retval EFI_SUCCESS Successfully got resource base address.\r
1584 @retval EFI_OUT_OF_RESOURCES PCI bridge is not available.\r
1585\r
1586**/\r
1587EFI_STATUS\r
1588GetResourceBaseFromBridge (\r
1436aea4
MK
1589 IN PCI_IO_DEVICE *Bridge,\r
1590 OUT UINT64 *IoBase,\r
1591 OUT UINT64 *Mem32Base,\r
1592 OUT UINT64 *PMem32Base,\r
1593 OUT UINT64 *Mem64Base,\r
1594 OUT UINT64 *PMem64Base\r
9060e3ec 1595 )\r
1596{\r
1597 if (!Bridge->Allocated) {\r
1598 return EFI_OUT_OF_RESOURCES;\r
1599 }\r
1600\r
1601 *IoBase = gAllOne;\r
1602 *Mem32Base = gAllOne;\r
1603 *PMem32Base = gAllOne;\r
1604 *Mem64Base = gAllOne;\r
1605 *PMem64Base = gAllOne;\r
1606\r
1607 if (IS_PCI_BRIDGE (&Bridge->Pci)) {\r
9060e3ec 1608 if (Bridge->PciBar[PPB_IO_RANGE].Length > 0) {\r
1609 *IoBase = Bridge->PciBar[PPB_IO_RANGE].BaseAddress;\r
1610 }\r
1611\r
1612 if (Bridge->PciBar[PPB_MEM32_RANGE].Length > 0) {\r
1613 *Mem32Base = Bridge->PciBar[PPB_MEM32_RANGE].BaseAddress;\r
1614 }\r
1615\r
1616 if (Bridge->PciBar[PPB_PMEM32_RANGE].Length > 0) {\r
1617 *PMem32Base = Bridge->PciBar[PPB_PMEM32_RANGE].BaseAddress;\r
1618 }\r
1619\r
1620 if (Bridge->PciBar[PPB_PMEM64_RANGE].Length > 0) {\r
1621 *PMem64Base = Bridge->PciBar[PPB_PMEM64_RANGE].BaseAddress;\r
1622 } else {\r
1623 *PMem64Base = gAllOne;\r
1624 }\r
9060e3ec 1625 }\r
1626\r
1627 if (IS_CARDBUS_BRIDGE (&Bridge->Pci)) {\r
1628 if (Bridge->PciBar[P2C_IO_1].Length > 0) {\r
1629 *IoBase = Bridge->PciBar[P2C_IO_1].BaseAddress;\r
1630 } else {\r
1631 if (Bridge->PciBar[P2C_IO_2].Length > 0) {\r
1632 *IoBase = Bridge->PciBar[P2C_IO_2].BaseAddress;\r
1633 }\r
1634 }\r
1635\r
1636 if (Bridge->PciBar[P2C_MEM_1].Length > 0) {\r
1637 if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypePMem32) {\r
1638 *PMem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;\r
1639 }\r
1640\r
1641 if (Bridge->PciBar[P2C_MEM_1].BarType == PciBarTypeMem32) {\r
1642 *Mem32Base = Bridge->PciBar[P2C_MEM_1].BaseAddress;\r
1643 }\r
1644 }\r
1645\r
1646 if (Bridge->PciBar[P2C_MEM_2].Length > 0) {\r
1647 if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypePMem32) {\r
1648 *PMem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;\r
1649 }\r
1650\r
1651 if (Bridge->PciBar[P2C_MEM_2].BarType == PciBarTypeMem32) {\r
1652 *Mem32Base = Bridge->PciBar[P2C_MEM_2].BaseAddress;\r
1653 }\r
1654 }\r
1655 }\r
1656\r
1657 return EFI_SUCCESS;\r
1658}\r
1659\r
1660/**\r
1661 These are the notifications from the PCI bus driver that it is about to enter a certain\r
1662 phase of the PCI enumeration process.\r
1663\r
1664 This member function can be used to notify the host bridge driver to perform specific actions,\r
1665 including any chipset-specific initialization, so that the chipset is ready to enter the next phase.\r
1666 Eight notification points are defined at this time. See belows:\r
1667 EfiPciHostBridgeBeginEnumeration Resets the host bridge PCI apertures and internal data\r
1668 structures. The PCI enumerator should issue this notification\r
1669 before starting a fresh enumeration process. Enumeration cannot\r
1670 be restarted after sending any other notification such as\r
1671 EfiPciHostBridgeBeginBusAllocation.\r
1672 EfiPciHostBridgeBeginBusAllocation The bus allocation phase is about to begin. No specific action is\r
1673 required here. This notification can be used to perform any\r
1674 chipset-specific programming.\r
1675 EfiPciHostBridgeEndBusAllocation The bus allocation and bus programming phase is complete. No\r
1676 specific action is required here. This notification can be used to\r
1677 perform any chipset-specific programming.\r
1678 EfiPciHostBridgeBeginResourceAllocation\r
1679 The resource allocation phase is about to begin. No specific\r
1680 action is required here. This notification can be used to perform\r
1681 any chipset-specific programming.\r
1682 EfiPciHostBridgeAllocateResources Allocates resources per previously submitted requests for all the PCI\r
1683 root bridges. These resource settings are returned on the next call to\r
1684 GetProposedResources(). Before calling NotifyPhase() with a Phase of\r
1685 EfiPciHostBridgeAllocateResource, the PCI bus enumerator is responsible\r
1686 for gathering I/O and memory requests for\r
1687 all the PCI root bridges and submitting these requests using\r
1688 SubmitResources(). This function pads the resource amount\r
1689 to suit the root bridge hardware, takes care of dependencies between\r
1690 the PCI root bridges, and calls the Global Coherency Domain (GCD)\r
1691 with the allocation request. In the case of padding, the allocated range\r
1692 could be bigger than what was requested.\r
1693 EfiPciHostBridgeSetResources Programs the host bridge hardware to decode previously allocated\r
1694 resources (proposed resources) for all the PCI root bridges. After the\r
1695 hardware is programmed, reassigning resources will not be supported.\r
1696 The bus settings are not affected.\r
1697 EfiPciHostBridgeFreeResources Deallocates resources that were previously allocated for all the PCI\r
1698 root bridges and resets the I/O and memory apertures to their initial\r
1699 state. The bus settings are not affected. If the request to allocate\r
1700 resources fails, the PCI enumerator can use this notification to\r
1701 deallocate previous resources, adjust the requests, and retry\r
1702 allocation.\r
1703 EfiPciHostBridgeEndResourceAllocation The resource allocation phase is completed. No specific action is\r
1704 required here. This notification can be used to perform any chipsetspecific\r
1705 programming.\r
1706\r
1707 @param[in] PciResAlloc The instance pointer of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
1708 @param[in] Phase The phase during enumeration\r
1709\r
1710 @retval EFI_NOT_READY This phase cannot be entered at this time. For example, this error\r
1711 is valid for a Phase of EfiPciHostBridgeAllocateResources if\r
1712 SubmitResources() has not been called for one or more\r
1713 PCI root bridges before this call\r
1714 @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. This error is valid\r
1715 for a Phase of EfiPciHostBridgeSetResources.\r
1716 @retval EFI_INVALID_PARAMETER Invalid phase parameter\r
1717 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1718 This error is valid for a Phase of EfiPciHostBridgeAllocateResources if the\r
1719 previously submitted resource requests cannot be fulfilled or\r
1720 were only partially fulfilled.\r
1721 @retval EFI_SUCCESS The notification was accepted without any errors.\r
1722\r
1723**/\r
1724EFI_STATUS\r
1725NotifyPhase (\r
1436aea4
MK
1726 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc,\r
1727 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase\r
9060e3ec 1728 )\r
1729{\r
1436aea4
MK
1730 EFI_HANDLE HostBridgeHandle;\r
1731 EFI_HANDLE RootBridgeHandle;\r
1732 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1733 EFI_STATUS Status;\r
9060e3ec 1734\r
1436aea4
MK
1735 HostBridgeHandle = NULL;\r
1736 RootBridgeHandle = NULL;\r
9060e3ec 1737 if (gPciPlatformProtocol != NULL) {\r
1738 //\r
1739 // Get Host Bridge Handle.\r
1740 //\r
1741 PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);\r
1742\r
1743 //\r
1744 // Get the rootbridge Io protocol to find the host bridge handle\r
1745 //\r
1746 Status = gBS->HandleProtocol (\r
1747 RootBridgeHandle,\r
1748 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 1749 (VOID **)&PciRootBridgeIo\r
9060e3ec 1750 );\r
1751\r
1752 if (EFI_ERROR (Status)) {\r
1753 return EFI_NOT_FOUND;\r
1754 }\r
1755\r
1756 HostBridgeHandle = PciRootBridgeIo->ParentHandle;\r
1757\r
1758 //\r
1759 // Call PlatformPci::PlatformNotify() if the protocol is present.\r
1760 //\r
1761 gPciPlatformProtocol->PlatformNotify (\r
1762 gPciPlatformProtocol,\r
1763 HostBridgeHandle,\r
1764 Phase,\r
1765 ChipsetEntry\r
1766 );\r
1436aea4 1767 } else if (gPciOverrideProtocol != NULL) {\r
9060e3ec 1768 //\r
1769 // Get Host Bridge Handle.\r
1770 //\r
1771 PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle);\r
1772\r
1773 //\r
1774 // Get the rootbridge Io protocol to find the host bridge handle\r
1775 //\r
1776 Status = gBS->HandleProtocol (\r
1777 RootBridgeHandle,\r
1778 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 1779 (VOID **)&PciRootBridgeIo\r
9060e3ec 1780 );\r
1781\r
1782 if (EFI_ERROR (Status)) {\r
1783 return EFI_NOT_FOUND;\r
1784 }\r
1785\r
1786 HostBridgeHandle = PciRootBridgeIo->ParentHandle;\r
1787\r
1788 //\r
1789 // Call PlatformPci::PhaseNotify() if the protocol is present.\r
1790 //\r
1791 gPciOverrideProtocol->PlatformNotify (\r
1792 gPciOverrideProtocol,\r
1793 HostBridgeHandle,\r
1794 Phase,\r
1795 ChipsetEntry\r
1796 );\r
d1102dba 1797 }\r
9060e3ec 1798\r
1799 Status = PciResAlloc->NotifyPhase (\r
1800 PciResAlloc,\r
1801 Phase\r
1802 );\r
1803\r
1804 if (gPciPlatformProtocol != NULL) {\r
1805 //\r
1806 // Call PlatformPci::PlatformNotify() if the protocol is present.\r
1807 //\r
1808 gPciPlatformProtocol->PlatformNotify (\r
1809 gPciPlatformProtocol,\r
1810 HostBridgeHandle,\r
1811 Phase,\r
1812 ChipsetExit\r
1813 );\r
9060e3ec 1814 } else if (gPciOverrideProtocol != NULL) {\r
1815 //\r
1816 // Call PlatformPci::PhaseNotify() if the protocol is present.\r
1817 //\r
1818 gPciOverrideProtocol->PlatformNotify (\r
1819 gPciOverrideProtocol,\r
1820 HostBridgeHandle,\r
1821 Phase,\r
1822 ChipsetExit\r
1823 );\r
1824 }\r
1825\r
724f26a9 1826 return Status;\r
9060e3ec 1827}\r
1828\r
1829/**\r
1830 Provides the hooks from the PCI bus driver to every PCI controller (device/function) at various\r
1831 stages of the PCI enumeration process that allow the host bridge driver to preinitialize individual\r
1832 PCI controllers before enumeration.\r
1833\r
1834 This function is called during the PCI enumeration process. No specific action is expected from this\r
1835 member function. It allows the host bridge driver to preinitialize individual PCI controllers before\r
1836 enumeration.\r
1837\r
1838 @param Bridge Pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.\r
1839 @param Bus The bus number of the pci device.\r
1840 @param Device The device number of the pci device.\r
1841 @param Func The function number of the pci device.\r
1842 @param Phase The phase of the PCI device enumeration.\r
1843\r
1844 @retval EFI_SUCCESS The requested parameters were returned.\r
1845 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid root bridge handle.\r
1846 @retval EFI_INVALID_PARAMETER Phase is not a valid phase that is defined in\r
1847 EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE.\r
1848 @retval EFI_DEVICE_ERROR Programming failed due to a hardware error. The PCI enumerator should\r
1849 not enumerate this device, including its child devices if it is a PCI-to-PCI\r
1850 bridge.\r
1851\r
1852**/\r
1853EFI_STATUS\r
1854PreprocessController (\r
1436aea4
MK
1855 IN PCI_IO_DEVICE *Bridge,\r
1856 IN UINT8 Bus,\r
1857 IN UINT8 Device,\r
1858 IN UINT8 Func,\r
1859 IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase\r
9060e3ec 1860 )\r
1861{\r
1862 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS RootBridgePciAddress;\r
1863 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc;\r
1864 EFI_HANDLE RootBridgeHandle;\r
1865 EFI_HANDLE HostBridgeHandle;\r
1866 EFI_STATUS Status;\r
1867\r
1868 //\r
1869 // Get the host bridge handle\r
1870 //\r
1871 HostBridgeHandle = Bridge->PciRootBridgeIo->ParentHandle;\r
1872\r
1873 //\r
1874 // Get the pci host bridge resource allocation protocol\r
1875 //\r
1876 Status = gBS->OpenProtocol (\r
1877 HostBridgeHandle,\r
1878 &gEfiPciHostBridgeResourceAllocationProtocolGuid,\r
1436aea4 1879 (VOID **)&PciResAlloc,\r
9060e3ec 1880 NULL,\r
1881 NULL,\r
1882 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1883 );\r
1884\r
1885 if (EFI_ERROR (Status)) {\r
1886 return EFI_UNSUPPORTED;\r
1887 }\r
1888\r
1889 //\r
1890 // Get Root Brige Handle\r
1891 //\r
1892 while (Bridge->Parent != NULL) {\r
1893 Bridge = Bridge->Parent;\r
1894 }\r
1895\r
1436aea4 1896 RootBridgeHandle = Bridge->Handle;\r
9060e3ec 1897\r
1898 RootBridgePciAddress.Register = 0;\r
1899 RootBridgePciAddress.Function = Func;\r
1900 RootBridgePciAddress.Device = Device;\r
1901 RootBridgePciAddress.Bus = Bus;\r
1902 RootBridgePciAddress.ExtendedRegister = 0;\r
1903\r
1904 if (gPciPlatformProtocol != NULL) {\r
1905 //\r
1906 // Call PlatformPci::PrepController() if the protocol is present.\r
1907 //\r
1908 gPciPlatformProtocol->PlatformPrepController (\r
1909 gPciPlatformProtocol,\r
1910 HostBridgeHandle,\r
1911 RootBridgeHandle,\r
1912 RootBridgePciAddress,\r
1913 Phase,\r
1914 ChipsetEntry\r
1915 );\r
1916 } else if (gPciOverrideProtocol != NULL) {\r
1917 //\r
1918 // Call PlatformPci::PrepController() if the protocol is present.\r
1919 //\r
1920 gPciOverrideProtocol->PlatformPrepController (\r
1921 gPciOverrideProtocol,\r
1922 HostBridgeHandle,\r
1923 RootBridgeHandle,\r
1924 RootBridgePciAddress,\r
1925 Phase,\r
1926 ChipsetEntry\r
1927 );\r
1928 }\r
1929\r
1930 Status = PciResAlloc->PreprocessController (\r
1931 PciResAlloc,\r
1932 RootBridgeHandle,\r
1933 RootBridgePciAddress,\r
1934 Phase\r
1935 );\r
1936\r
1937 if (gPciPlatformProtocol != NULL) {\r
1938 //\r
1939 // Call PlatformPci::PrepController() if the protocol is present.\r
1940 //\r
1941 gPciPlatformProtocol->PlatformPrepController (\r
1942 gPciPlatformProtocol,\r
1943 HostBridgeHandle,\r
1944 RootBridgeHandle,\r
1945 RootBridgePciAddress,\r
1946 Phase,\r
1947 ChipsetExit\r
1948 );\r
1949 } else if (gPciOverrideProtocol != NULL) {\r
1950 //\r
1951 // Call PlatformPci::PrepController() if the protocol is present.\r
1952 //\r
1953 gPciOverrideProtocol->PlatformPrepController (\r
1954 gPciOverrideProtocol,\r
1955 HostBridgeHandle,\r
1956 RootBridgeHandle,\r
1957 RootBridgePciAddress,\r
1958 Phase,\r
1959 ChipsetExit\r
1960 );\r
1961 }\r
1962\r
1963 return EFI_SUCCESS;\r
1964}\r
1965\r
1966/**\r
1967 This function allows the PCI bus driver to be notified to act as requested when a hot-plug event has\r
1968 happened on the hot-plug controller. Currently, the operations include add operation and remove operation..\r
1969\r
1970 @param This A pointer to the hot plug request protocol.\r
1971 @param Operation The operation the PCI bus driver is requested to make.\r
1972 @param Controller The handle of the hot-plug controller.\r
1973 @param RemainingDevicePath The remaining device path for the PCI-like hot-plug device.\r
1974 @param NumberOfChildren The number of child handles.\r
1975 For a add operation, it is an output parameter.\r
1976 For a remove operation, it's an input parameter.\r
1977 @param ChildHandleBuffer The buffer which contains the child handles.\r
1978\r
1979 @retval EFI_INVALID_PARAMETER Operation is not a legal value.\r
1980 Controller is NULL or not a valid handle.\r
1981 NumberOfChildren is NULL.\r
1982 ChildHandleBuffer is NULL while Operation is add.\r
1983 @retval EFI_OUT_OF_RESOURCES There are no enough resources to start the devices.\r
1984 @retval EFI_NOT_FOUND Can not find bridge according to controller handle.\r
1985 @retval EFI_SUCCESS The handles for the specified device have been created or destroyed\r
1986 as requested, and for an add operation, the new handles are\r
1987 returned in ChildHandleBuffer.\r
1988**/\r
1989EFI_STATUS\r
1990EFIAPI\r
1991PciHotPlugRequestNotify (\r
1436aea4
MK
1992 IN EFI_PCI_HOTPLUG_REQUEST_PROTOCOL *This,\r
1993 IN EFI_PCI_HOTPLUG_OPERATION Operation,\r
1994 IN EFI_HANDLE Controller,\r
1995 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,\r
1996 IN OUT UINT8 *NumberOfChildren,\r
1997 IN OUT EFI_HANDLE *ChildHandleBuffer\r
9060e3ec 1998 )\r
1999{\r
1436aea4
MK
2000 PCI_IO_DEVICE *Bridge;\r
2001 PCI_IO_DEVICE *Temp;\r
2002 EFI_PCI_IO_PROTOCOL *PciIo;\r
2003 UINTN Index;\r
2004 EFI_HANDLE RootBridgeHandle;\r
2005 EFI_STATUS Status;\r
9060e3ec 2006\r
2007 //\r
2008 // Check input parameter validity\r
2009 //\r
1436aea4 2010 if ((Controller == NULL) || (NumberOfChildren == NULL)) {\r
9060e3ec 2011 return EFI_INVALID_PARAMETER;\r
2012 }\r
2013\r
2014 if ((Operation != EfiPciHotPlugRequestAdd) && (Operation != EfiPciHotplugRequestRemove)) {\r
2015 return EFI_INVALID_PARAMETER;\r
2016 }\r
2017\r
1436aea4 2018 if (Operation == EfiPciHotPlugRequestAdd) {\r
9060e3ec 2019 if (ChildHandleBuffer == NULL) {\r
2020 return EFI_INVALID_PARAMETER;\r
2021 }\r
2022 } else if ((Operation == EfiPciHotplugRequestRemove) && (*NumberOfChildren != 0)) {\r
2023 if (ChildHandleBuffer == NULL) {\r
2024 return EFI_INVALID_PARAMETER;\r
2025 }\r
2026 }\r
d1102dba 2027\r
9060e3ec 2028 Status = gBS->OpenProtocol (\r
2029 Controller,\r
2030 &gEfiPciIoProtocolGuid,\r
1436aea4 2031 (VOID **)&PciIo,\r
9060e3ec 2032 gPciBusDriverBinding.DriverBindingHandle,\r
2033 Controller,\r
2034 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2035 );\r
2036\r
2037 if (EFI_ERROR (Status)) {\r
2038 return EFI_NOT_FOUND;\r
2039 }\r
2040\r
2041 Bridge = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
2042\r
2043 //\r
2044 // Get root bridge handle\r
2045 //\r
2046 Temp = Bridge;\r
2047 while (Temp->Parent != NULL) {\r
2048 Temp = Temp->Parent;\r
2049 }\r
2050\r
2051 RootBridgeHandle = Temp->Handle;\r
2052\r
2053 if (Operation == EfiPciHotPlugRequestAdd) {\r
37623a5c 2054 //\r
2055 // Report Status Code to indicate hot plug happens\r
2056 //\r
2057 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
2058 EFI_PROGRESS_CODE,\r
2059 (EFI_IO_BUS_PCI | EFI_IOB_PC_HOTPLUG),\r
2060 Temp->DevicePath\r
2061 );\r
9060e3ec 2062\r
2063 if (NumberOfChildren != NULL) {\r
2064 *NumberOfChildren = 0;\r
2065 }\r
2066\r
2067 if (IsListEmpty (&Bridge->ChildList)) {\r
9060e3ec 2068 Status = PciBridgeEnumerator (Bridge);\r
2069\r
2070 if (EFI_ERROR (Status)) {\r
2071 return Status;\r
2072 }\r
2073 }\r
2074\r
2075 Status = StartPciDevicesOnBridge (\r
1436aea4
MK
2076 RootBridgeHandle,\r
2077 Bridge,\r
2078 RemainingDevicePath,\r
2079 NumberOfChildren,\r
2080 ChildHandleBuffer\r
2081 );\r
9060e3ec 2082\r
2083 return Status;\r
2084 }\r
2085\r
2086 if (Operation == EfiPciHotplugRequestRemove) {\r
9060e3ec 2087 if (*NumberOfChildren == 0) {\r
2088 //\r
2089 // Remove all devices on the bridge\r
2090 //\r
2091 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Bridge);\r
2092 return EFI_SUCCESS;\r
9060e3ec 2093 }\r
2094\r
2095 for (Index = 0; Index < *NumberOfChildren; Index++) {\r
2096 //\r
2097 // De register all the pci device\r
2098 //\r
2099 Status = DeRegisterPciDevice (RootBridgeHandle, ChildHandleBuffer[Index]);\r
2100\r
2101 if (EFI_ERROR (Status)) {\r
2102 return Status;\r
2103 }\r
9060e3ec 2104 }\r
1436aea4 2105\r
9060e3ec 2106 //\r
2107 // End for\r
2108 //\r
2109 return EFI_SUCCESS;\r
2110 }\r
2111\r
2112 return EFI_SUCCESS;\r
2113}\r
2114\r
2115/**\r
2116 Search hostbridge according to given handle\r
2117\r
2118 @param RootBridgeHandle Host bridge handle.\r
2119\r
2120 @retval TRUE Found host bridge handle.\r
2121 @retval FALSE Not found hot bridge handle.\r
2122\r
2123**/\r
2124BOOLEAN\r
2125SearchHostBridgeHandle (\r
1436aea4 2126 IN EFI_HANDLE RootBridgeHandle\r
9060e3ec 2127 )\r
2128{\r
1436aea4
MK
2129 EFI_HANDLE HostBridgeHandle;\r
2130 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2131 UINTN Index;\r
2132 EFI_STATUS Status;\r
9060e3ec 2133\r
2134 //\r
2135 // Get the rootbridge Io protocol to find the host bridge handle\r
2136 //\r
2137 Status = gBS->OpenProtocol (\r
2138 RootBridgeHandle,\r
2139 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 2140 (VOID **)&PciRootBridgeIo,\r
9060e3ec 2141 gPciBusDriverBinding.DriverBindingHandle,\r
2142 RootBridgeHandle,\r
2143 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2144 );\r
2145\r
2146 if (EFI_ERROR (Status)) {\r
2147 return FALSE;\r
2148 }\r
2149\r
2150 HostBridgeHandle = PciRootBridgeIo->ParentHandle;\r
2151 for (Index = 0; Index < gPciHostBridgeNumber; Index++) {\r
2152 if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {\r
2153 return TRUE;\r
2154 }\r
2155 }\r
2156\r
2157 return FALSE;\r
2158}\r
2159\r
2160/**\r
2161 Add host bridge handle to global variable for enumerating.\r
2162\r
2163 @param HostBridgeHandle Host bridge handle.\r
2164\r
2165 @retval EFI_SUCCESS Successfully added host bridge.\r
2166 @retval EFI_ABORTED Host bridge is NULL, or given host bridge\r
2167 has been in host bridge list.\r
2168\r
2169**/\r
2170EFI_STATUS\r
2171AddHostBridgeEnumerator (\r
1436aea4 2172 IN EFI_HANDLE HostBridgeHandle\r
9060e3ec 2173 )\r
2174{\r
1436aea4 2175 UINTN Index;\r
9060e3ec 2176\r
2177 if (HostBridgeHandle == NULL) {\r
2178 return EFI_ABORTED;\r
2179 }\r
2180\r
2181 for (Index = 0; Index < gPciHostBridgeNumber; Index++) {\r
2182 if (HostBridgeHandle == gPciHostBrigeHandles[Index]) {\r
2183 return EFI_ABORTED;\r
2184 }\r
2185 }\r
2186\r
2187 if (Index < PCI_MAX_HOST_BRIDGE_NUM) {\r
2188 gPciHostBrigeHandles[Index] = HostBridgeHandle;\r
2189 gPciHostBridgeNumber++;\r
2190 }\r
2191\r
2192 return EFI_SUCCESS;\r
2193}\r