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