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