• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
4 
5 Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "PciHostBridge.h"
17 #include "PciRootBridge.h"
18 #include "PciHostResource.h"
19 
20 
21 EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
22 EFI_CPU_IO2_PROTOCOL        *mCpuIo;
23 
24 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
25   L"Mem", L"I/O", L"Bus"
26 };
27 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
28   L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"
29 };
30 
31 /**
32   Ensure the compatibility of an IO space descriptor with the IO aperture.
33 
34   The IO space descriptor can come from the GCD IO space map, or it can
35   represent a gap between two neighboring IO space descriptors. In the latter
36   case, the GcdIoType field is expected to be EfiGcdIoTypeNonExistent.
37 
38   If the IO space descriptor already has type EfiGcdIoTypeIo, then no action is
39   taken -- it is by definition compatible with the aperture.
40 
41   Otherwise, the intersection of the IO space descriptor is calculated with the
42   aperture. If the intersection is the empty set (no overlap), no action is
43   taken; the IO space descriptor is compatible with the aperture.
44 
45   Otherwise, the type of the descriptor is investigated again. If the type is
46   EfiGcdIoTypeNonExistent (representing a gap, or a genuine descriptor with
47   such a type), then an attempt is made to add the intersection as IO space to
48   the GCD IO space map. This ensures continuity for the aperture, and the
49   descriptor is deemed compatible with the aperture.
50 
51   Otherwise, the IO space descriptor is incompatible with the IO aperture.
52 
53   @param[in] Base        Base address of the aperture.
54   @param[in] Length      Length of the aperture.
55   @param[in] Descriptor  The descriptor to ensure compatibility with the
56                          aperture for.
57 
58   @retval EFI_SUCCESS            The descriptor is compatible. The GCD IO space
59                                  map may have been updated, for continuity
60                                  within the aperture.
61   @retval EFI_INVALID_PARAMETER  The descriptor is incompatible.
62   @return                        Error codes from gDS->AddIoSpace().
63 **/
64 EFI_STATUS
IntersectIoDescriptor(IN UINT64 Base,IN UINT64 Length,IN CONST EFI_GCD_IO_SPACE_DESCRIPTOR * Descriptor)65 IntersectIoDescriptor (
66   IN  UINT64                            Base,
67   IN  UINT64                            Length,
68   IN  CONST EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
69   )
70 {
71   UINT64                                IntersectionBase;
72   UINT64                                IntersectionEnd;
73   EFI_STATUS                            Status;
74 
75   if (Descriptor->GcdIoType == EfiGcdIoTypeIo) {
76     return EFI_SUCCESS;
77   }
78 
79   IntersectionBase = MAX (Base, Descriptor->BaseAddress);
80   IntersectionEnd = MIN (Base + Length,
81                       Descriptor->BaseAddress + Descriptor->Length);
82   if (IntersectionBase >= IntersectionEnd) {
83     //
84     // The descriptor and the aperture don't overlap.
85     //
86     return EFI_SUCCESS;
87   }
88 
89   if (Descriptor->GcdIoType == EfiGcdIoTypeNonExistent) {
90     Status = gDS->AddIoSpace (EfiGcdIoTypeIo, IntersectionBase,
91                     IntersectionEnd - IntersectionBase);
92 
93     DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,
94       "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,
95       IntersectionBase, IntersectionEnd, Status));
96     return Status;
97   }
98 
99   DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u conflicts with "
100     "aperture [%Lx, %Lx)\n", gEfiCallerBaseName, __FUNCTION__,
101     Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,
102     (UINT32)Descriptor->GcdIoType, Base, Base + Length));
103   return EFI_INVALID_PARAMETER;
104 }
105 
106 /**
107   Add IO space to GCD.
108   The routine checks the GCD database and only adds those which are
109   not added in the specified range to GCD.
110 
111   @param Base   Base address of the IO space.
112   @param Length Length of the IO space.
113 
114   @retval EFI_SUCCES The IO space was added successfully.
115 **/
116 EFI_STATUS
AddIoSpace(IN UINT64 Base,IN UINT64 Length)117 AddIoSpace (
118   IN  UINT64                        Base,
119   IN  UINT64                        Length
120   )
121 {
122   EFI_STATUS                        Status;
123   UINTN                             Index;
124   UINTN                             NumberOfDescriptors;
125   EFI_GCD_IO_SPACE_DESCRIPTOR       *IoSpaceMap;
126 
127   Status = gDS->GetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
128   if (EFI_ERROR (Status)) {
129     DEBUG ((EFI_D_ERROR, "%a: %a: GetIoSpaceMap(): %r\n",
130       gEfiCallerBaseName, __FUNCTION__, Status));
131     return Status;
132   }
133 
134   for (Index = 0; Index < NumberOfDescriptors; Index++) {
135     Status = IntersectIoDescriptor (Base, Length, &IoSpaceMap[Index]);
136     if (EFI_ERROR (Status)) {
137       goto FreeIoSpaceMap;
138     }
139   }
140 
141   DEBUG_CODE (
142     //
143     // Make sure there are adjacent descriptors covering [Base, Base + Length).
144     // It is possible that they have not been merged; merging can be prevented
145     // by allocation.
146     //
147     UINT64                      CheckBase;
148     EFI_STATUS                  CheckStatus;
149     EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor;
150 
151     for (CheckBase = Base;
152          CheckBase < Base + Length;
153          CheckBase = Descriptor.BaseAddress + Descriptor.Length) {
154       CheckStatus = gDS->GetIoSpaceDescriptor (CheckBase, &Descriptor);
155       ASSERT_EFI_ERROR (CheckStatus);
156       ASSERT (Descriptor.GcdIoType == EfiGcdIoTypeIo);
157     }
158     );
159 
160 FreeIoSpaceMap:
161   FreePool (IoSpaceMap);
162 
163   return Status;
164 }
165 
166 /**
167   Ensure the compatibility of a memory space descriptor with the MMIO aperture.
168 
169   The memory space descriptor can come from the GCD memory space map, or it can
170   represent a gap between two neighboring memory space descriptors. In the
171   latter case, the GcdMemoryType field is expected to be
172   EfiGcdMemoryTypeNonExistent.
173 
174   If the memory space descriptor already has type
175   EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
176   required capabilities, then no action is taken -- it is by definition
177   compatible with the aperture.
178 
179   Otherwise, the intersection of the memory space descriptor is calculated with
180   the aperture. If the intersection is the empty set (no overlap), no action is
181   taken; the memory space descriptor is compatible with the aperture.
182 
183   Otherwise, the type of the descriptor is investigated again. If the type is
184   EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
185   such a type), then an attempt is made to add the intersection as MMIO space
186   to the GCD memory space map, with the specified capabilities. This ensures
187   continuity for the aperture, and the descriptor is deemed compatible with the
188   aperture.
189 
190   Otherwise, the memory space descriptor is incompatible with the MMIO
191   aperture.
192 
193   @param[in] Base         Base address of the aperture.
194   @param[in] Length       Length of the aperture.
195   @param[in] Capabilities Capabilities required by the aperture.
196   @param[in] Descriptor   The descriptor to ensure compatibility with the
197                           aperture for.
198 
199   @retval EFI_SUCCESS            The descriptor is compatible. The GCD memory
200                                  space map may have been updated, for
201                                  continuity within the aperture.
202   @retval EFI_INVALID_PARAMETER  The descriptor is incompatible.
203   @return                        Error codes from gDS->AddMemorySpace().
204 **/
205 EFI_STATUS
IntersectMemoryDescriptor(IN UINT64 Base,IN UINT64 Length,IN UINT64 Capabilities,IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR * Descriptor)206 IntersectMemoryDescriptor (
207   IN  UINT64                                Base,
208   IN  UINT64                                Length,
209   IN  UINT64                                Capabilities,
210   IN  CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
211   )
212 {
213   UINT64                                    IntersectionBase;
214   UINT64                                    IntersectionEnd;
215   EFI_STATUS                                Status;
216 
217   if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo &&
218       (Descriptor->Capabilities & Capabilities) == Capabilities) {
219     return EFI_SUCCESS;
220   }
221 
222   IntersectionBase = MAX (Base, Descriptor->BaseAddress);
223   IntersectionEnd = MIN (Base + Length,
224                       Descriptor->BaseAddress + Descriptor->Length);
225   if (IntersectionBase >= IntersectionEnd) {
226     //
227     // The descriptor and the aperture don't overlap.
228     //
229     return EFI_SUCCESS;
230   }
231 
232   if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
233     Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
234                     IntersectionBase, IntersectionEnd - IntersectionBase,
235                     Capabilities);
236 
237     DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE,
238       "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__,
239       IntersectionBase, IntersectionEnd, Status));
240     return Status;
241   }
242 
243   DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
244     "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName, __FUNCTION__,
245     Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length,
246     (UINT32)Descriptor->GcdMemoryType, Descriptor->Capabilities,
247     Base, Base + Length, Capabilities));
248   return EFI_INVALID_PARAMETER;
249 }
250 
251 /**
252   Add MMIO space to GCD.
253   The routine checks the GCD database and only adds those which are
254   not added in the specified range to GCD.
255 
256   @param Base         Base address of the MMIO space.
257   @param Length       Length of the MMIO space.
258   @param Capabilities Capabilities of the MMIO space.
259 
260   @retval EFI_SUCCES The MMIO space was added successfully.
261 **/
262 EFI_STATUS
AddMemoryMappedIoSpace(IN UINT64 Base,IN UINT64 Length,IN UINT64 Capabilities)263 AddMemoryMappedIoSpace (
264   IN  UINT64                            Base,
265   IN  UINT64                            Length,
266   IN  UINT64                            Capabilities
267   )
268 {
269   EFI_STATUS                            Status;
270   UINTN                                 Index;
271   UINTN                                 NumberOfDescriptors;
272   EFI_GCD_MEMORY_SPACE_DESCRIPTOR       *MemorySpaceMap;
273 
274   Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
275   if (EFI_ERROR (Status)) {
276     DEBUG ((EFI_D_ERROR, "%a: %a: GetMemorySpaceMap(): %r\n",
277       gEfiCallerBaseName, __FUNCTION__, Status));
278     return Status;
279   }
280 
281   for (Index = 0; Index < NumberOfDescriptors; Index++) {
282     Status = IntersectMemoryDescriptor (Base, Length, Capabilities,
283                &MemorySpaceMap[Index]);
284     if (EFI_ERROR (Status)) {
285       goto FreeMemorySpaceMap;
286     }
287   }
288 
289   DEBUG_CODE (
290     //
291     // Make sure there are adjacent descriptors covering [Base, Base + Length).
292     // It is possible that they have not been merged; merging can be prevented
293     // by allocation and different capabilities.
294     //
295     UINT64                          CheckBase;
296     EFI_STATUS                      CheckStatus;
297     EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
298 
299     for (CheckBase = Base;
300          CheckBase < Base + Length;
301          CheckBase = Descriptor.BaseAddress + Descriptor.Length) {
302       CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);
303       ASSERT_EFI_ERROR (CheckStatus);
304       ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
305       ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
306     }
307     );
308 
309 FreeMemorySpaceMap:
310   FreePool (MemorySpaceMap);
311 
312   return Status;
313 }
314 
315 /**
316 
317   Entry point of this driver.
318 
319   @param ImageHandle  Image handle of this driver.
320   @param SystemTable  Pointer to standard EFI system table.
321 
322   @retval EFI_SUCCESS       Succeed.
323   @retval EFI_DEVICE_ERROR  Fail to install PCI_ROOT_BRIDGE_IO protocol.
324 
325 **/
326 EFI_STATUS
327 EFIAPI
InitializePciHostBridge(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)328 InitializePciHostBridge (
329   IN EFI_HANDLE         ImageHandle,
330   IN EFI_SYSTEM_TABLE   *SystemTable
331   )
332 {
333   EFI_STATUS                  Status;
334   PCI_HOST_BRIDGE_INSTANCE    *HostBridge;
335   PCI_ROOT_BRIDGE_INSTANCE    *RootBridge;
336   PCI_ROOT_BRIDGE             *RootBridges;
337   UINTN                       RootBridgeCount;
338   UINTN                       Index;
339   PCI_ROOT_BRIDGE_APERTURE    *MemApertures[4];
340   UINTN                       MemApertureIndex;
341   BOOLEAN                     ResourceAssigned;
342   LIST_ENTRY                  *Link;
343 
344   RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
345   if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
346     return EFI_UNSUPPORTED;
347   }
348 
349   Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);
350   ASSERT_EFI_ERROR (Status);
351   Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
352   ASSERT_EFI_ERROR (Status);
353 
354   //
355   // Most systems in the world including complex servers have only one Host Bridge.
356   //
357   HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
358   ASSERT (HostBridge != NULL);
359 
360   HostBridge->Signature        = PCI_HOST_BRIDGE_SIGNATURE;
361   HostBridge->CanRestarted     = TRUE;
362   InitializeListHead (&HostBridge->RootBridges);
363   ResourceAssigned             = FALSE;
364 
365   //
366   // Create Root Bridge Device Handle in this Host Bridge
367   //
368   for (Index = 0; Index < RootBridgeCount; Index++) {
369     //
370     // Create Root Bridge Handle Instance
371     //
372     RootBridge = CreateRootBridge (&RootBridges[Index]);
373     ASSERT (RootBridge != NULL);
374     if (RootBridge == NULL) {
375       continue;
376     }
377 
378     //
379     // Make sure all root bridges share the same ResourceAssigned value.
380     //
381     if (Index == 0) {
382       ResourceAssigned = RootBridges[Index].ResourceAssigned;
383     } else {
384       ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
385     }
386 
387     if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {
388       Status = AddIoSpace (
389                  RootBridges[Index].Io.Base,
390                  RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1
391                  );
392       ASSERT_EFI_ERROR (Status);
393       if (ResourceAssigned) {
394         Status = gDS->AllocateIoSpace (
395                         EfiGcdAllocateAddress,
396                         EfiGcdIoTypeIo,
397                         0,
398                         RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,
399                         &RootBridges[Index].Io.Base,
400                         gImageHandle,
401                         NULL
402                         );
403         ASSERT_EFI_ERROR (Status);
404       }
405     }
406 
407     //
408     // Add all the Mem/PMem aperture to GCD
409     // Mem/PMem shouldn't overlap with each other
410     // Root bridge which needs to combine MEM and PMEM should only report
411     // the MEM aperture in Mem
412     //
413     MemApertures[0] = &RootBridges[Index].Mem;
414     MemApertures[1] = &RootBridges[Index].MemAbove4G;
415     MemApertures[2] = &RootBridges[Index].PMem;
416     MemApertures[3] = &RootBridges[Index].PMemAbove4G;
417 
418     for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
419       if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
420         Status = AddMemoryMappedIoSpace (
421                    MemApertures[MemApertureIndex]->Base,
422                    MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
423                    EFI_MEMORY_UC
424                    );
425         ASSERT_EFI_ERROR (Status);
426         Status = gDS->SetMemorySpaceAttributes (
427                         MemApertures[MemApertureIndex]->Base,
428                         MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
429                         EFI_MEMORY_UC
430                         );
431         if (EFI_ERROR (Status)) {
432           DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));
433         }
434         if (ResourceAssigned) {
435           Status = gDS->AllocateMemorySpace (
436                           EfiGcdAllocateAddress,
437                           EfiGcdMemoryTypeMemoryMappedIo,
438                           0,
439                           MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
440                           &MemApertures[MemApertureIndex]->Base,
441                           gImageHandle,
442                           NULL
443                           );
444           ASSERT_EFI_ERROR (Status);
445         }
446       }
447     }
448     //
449     // Insert Root Bridge Handle Instance
450     //
451     InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
452   }
453 
454   //
455   // When resources were assigned, it's not needed to expose
456   // PciHostBridgeResourceAllocation protocol.
457   //
458   if (!ResourceAssigned) {
459     HostBridge->ResAlloc.NotifyPhase = NotifyPhase;
460     HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;
461     HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;
462     HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;
463     HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;
464     HostBridge->ResAlloc.SubmitResources = SubmitResources;
465     HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
466     HostBridge->ResAlloc.PreprocessController = PreprocessController;
467 
468     Status = gBS->InstallMultipleProtocolInterfaces (
469                     &HostBridge->Handle,
470                     &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
471                     NULL
472                     );
473     ASSERT_EFI_ERROR (Status);
474   }
475 
476   for (Link = GetFirstNode (&HostBridge->RootBridges)
477        ; !IsNull (&HostBridge->RootBridges, Link)
478        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
479        ) {
480     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
481     RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;
482 
483     Status = gBS->InstallMultipleProtocolInterfaces (
484                     &RootBridge->Handle,
485                     &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,
486                     &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,
487                     NULL
488                     );
489     ASSERT_EFI_ERROR (Status);
490   }
491   PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
492   return Status;
493 }
494 
495 /**
496   This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
497 
498   @param HostBridge The Host Bridge Instance where the resource adjustment happens.
499 **/
500 VOID
ResourceConflict(IN PCI_HOST_BRIDGE_INSTANCE * HostBridge)501 ResourceConflict (
502   IN  PCI_HOST_BRIDGE_INSTANCE *HostBridge
503   )
504 {
505   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
506   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
507   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
508   PCI_ROOT_BRIDGE_INSTANCE          *RootBridge;
509   LIST_ENTRY                        *Link;
510   UINTN                             RootBridgeCount;
511   PCI_RESOURCE_TYPE                 Index;
512   PCI_RES_NODE                      *ResAllocNode;
513 
514   RootBridgeCount = 0;
515   for (Link = GetFirstNode (&HostBridge->RootBridges)
516        ; !IsNull (&HostBridge->RootBridges, Link)
517        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
518        ) {
519     RootBridgeCount++;
520   }
521 
522   Resources = AllocatePool (
523                 RootBridgeCount * (TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)) +
524                 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
525                 );
526   ASSERT (Resources != NULL);
527 
528   for (Link = GetFirstNode (&HostBridge->RootBridges), Descriptor = Resources
529        ; !IsNull (&HostBridge->RootBridges, Link)
530        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
531        ) {
532     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
533     for (Index = TypeIo; Index < TypeMax; Index++) {
534       ResAllocNode = &RootBridge->ResAllocNode[Index];
535 
536       Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
537       Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
538       Descriptor->AddrRangeMin = ResAllocNode->Base;
539       Descriptor->AddrRangeMax = ResAllocNode->Alignment;
540       Descriptor->AddrLen = ResAllocNode->Length;
541       switch (ResAllocNode->Type) {
542 
543       case TypeIo:
544         Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
545         break;
546 
547       case TypePMem32:
548         Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
549       case TypeMem32:
550         Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
551         Descriptor->AddrSpaceGranularity = 32;
552         break;
553 
554       case TypePMem64:
555         Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
556       case TypeMem64:
557         Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
558         Descriptor->AddrSpaceGranularity = 64;
559         break;
560 
561       case TypeBus:
562         Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
563         break;
564 
565       default:
566         break;
567       }
568 
569       Descriptor++;
570     }
571     //
572     // Terminate the root bridge resources.
573     //
574     End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
575     End->Desc = ACPI_END_TAG_DESCRIPTOR;
576     End->Checksum = 0x0;
577 
578     Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (End + 1);
579   }
580   //
581   // Terminate the host bridge resources.
582   //
583   End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
584   End->Desc = ACPI_END_TAG_DESCRIPTOR;
585   End->Checksum = 0x0;
586 
587   DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));
588   PciHostBridgeResourceConflict (HostBridge->Handle, Resources);
589   FreePool (Resources);
590 }
591 
592 /**
593   Allocate Length of MMIO or IO resource with alignment BitsOfAlignment
594   from GCD range [BaseAddress, Limit).
595 
596   @param Mmio            TRUE for MMIO and FALSE for IO.
597   @param Length          Length of the resource to allocate.
598   @param BitsOfAlignment Alignment of the resource to allocate.
599   @param BaseAddress     The starting address the allocation is from.
600   @param Limit           The ending address the allocation is to.
601 
602   @retval  The base address of the allocated resource or MAX_UINT64 if allocation
603            fails.
604 **/
605 UINT64
AllocateResource(BOOLEAN Mmio,UINT64 Length,UINTN BitsOfAlignment,UINT64 BaseAddress,UINT64 Limit)606 AllocateResource (
607   BOOLEAN Mmio,
608   UINT64  Length,
609   UINTN   BitsOfAlignment,
610   UINT64  BaseAddress,
611   UINT64  Limit
612   )
613 {
614   EFI_STATUS Status;
615 
616   if (BaseAddress < Limit) {
617     //
618     // Have to make sure Aligment is handled since we are doing direct address allocation
619     //
620     BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));
621 
622     while (BaseAddress + Length <= Limit + 1) {
623       if (Mmio) {
624         Status = gDS->AllocateMemorySpace (
625                         EfiGcdAllocateAddress,
626                         EfiGcdMemoryTypeMemoryMappedIo,
627                         BitsOfAlignment,
628                         Length,
629                         &BaseAddress,
630                         gImageHandle,
631                         NULL
632                         );
633       } else {
634         Status = gDS->AllocateIoSpace (
635                         EfiGcdAllocateAddress,
636                         EfiGcdIoTypeIo,
637                         BitsOfAlignment,
638                         Length,
639                         &BaseAddress,
640                         gImageHandle,
641                         NULL
642                         );
643       }
644 
645       if (!EFI_ERROR (Status)) {
646         return BaseAddress;
647       }
648       BaseAddress += LShiftU64 (1, BitsOfAlignment);
649     }
650   }
651   return MAX_UINT64;
652 }
653 
654 /**
655 
656   Enter a certain phase of the PCI enumeration process.
657 
658   @param This   The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
659   @param Phase  The phase during enumeration.
660 
661   @retval EFI_SUCCESS            Succeed.
662   @retval EFI_INVALID_PARAMETER  Wrong phase parameter passed in.
663   @retval EFI_NOT_READY          Resources have not been submitted yet.
664 
665 **/
666 EFI_STATUS
667 EFIAPI
NotifyPhase(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase)668 NotifyPhase (
669   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
670   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE    Phase
671   )
672 {
673   PCI_HOST_BRIDGE_INSTANCE              *HostBridge;
674   PCI_ROOT_BRIDGE_INSTANCE              *RootBridge;
675   LIST_ENTRY                            *Link;
676   EFI_PHYSICAL_ADDRESS                  BaseAddress;
677   UINTN                                 BitsOfAlignment;
678   UINT64                                Alignment;
679   EFI_STATUS                            Status;
680   EFI_STATUS                            ReturnStatus;
681   PCI_RESOURCE_TYPE                     Index;
682   PCI_RESOURCE_TYPE                     Index1;
683   PCI_RESOURCE_TYPE                     Index2;
684   BOOLEAN                               ResNodeHandled[TypeMax];
685   UINT64                                MaxAlignment;
686 
687   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
688 
689   switch (Phase) {
690   case EfiPciHostBridgeBeginEnumeration:
691     if (!HostBridge->CanRestarted) {
692       return EFI_NOT_READY;
693     }
694     //
695     // Reset Root Bridge
696     //
697     for (Link = GetFirstNode (&HostBridge->RootBridges)
698           ; !IsNull (&HostBridge->RootBridges, Link)
699           ; Link = GetNextNode (&HostBridge->RootBridges, Link)
700           ) {
701       RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
702       for (Index = TypeIo; Index < TypeMax; Index++) {
703         RootBridge->ResAllocNode[Index].Type   = Index;
704         RootBridge->ResAllocNode[Index].Base   = 0;
705         RootBridge->ResAllocNode[Index].Length = 0;
706         RootBridge->ResAllocNode[Index].Status = ResNone;
707 
708         RootBridge->ResourceSubmitted = FALSE;
709       }
710     }
711 
712     HostBridge->CanRestarted = TRUE;
713     break;
714 
715   case EfiPciHostBridgeBeginBusAllocation:
716     //
717     // No specific action is required here, can perform any chipset specific programing
718     //
719     HostBridge->CanRestarted = FALSE;
720     break;
721 
722   case EfiPciHostBridgeEndBusAllocation:
723     //
724     // No specific action is required here, can perform any chipset specific programing
725     //
726     break;
727 
728   case EfiPciHostBridgeBeginResourceAllocation:
729     //
730     // No specific action is required here, can perform any chipset specific programing
731     //
732     break;
733 
734   case EfiPciHostBridgeAllocateResources:
735     ReturnStatus = EFI_SUCCESS;
736 
737     //
738     // Make sure the resource for all root bridges has been submitted.
739     //
740     for (Link = GetFirstNode (&HostBridge->RootBridges)
741          ; !IsNull (&HostBridge->RootBridges, Link)
742          ; Link = GetNextNode (&HostBridge->RootBridges, Link)
743          ) {
744       RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
745       if (!RootBridge->ResourceSubmitted) {
746         return EFI_NOT_READY;
747       }
748     }
749 
750     DEBUG ((EFI_D_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));
751     for (Link = GetFirstNode (&HostBridge->RootBridges)
752          ; !IsNull (&HostBridge->RootBridges, Link)
753          ; Link = GetNextNode (&HostBridge->RootBridges, Link)
754          ) {
755       for (Index = TypeIo; Index < TypeBus; Index++) {
756         ResNodeHandled[Index] = FALSE;
757       }
758 
759       RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
760       DEBUG ((EFI_D_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));
761 
762       for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
763         if (RootBridge->ResAllocNode[Index1].Status == ResNone) {
764           ResNodeHandled[Index1] = TRUE;
765         } else {
766           //
767           // Allocate the resource node with max alignment at first
768           //
769           MaxAlignment = 0;
770           Index = TypeMax;
771           for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {
772             if (ResNodeHandled[Index2]) {
773               continue;
774             }
775             if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {
776               MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;
777               Index = Index2;
778             }
779           }
780 
781           ASSERT (Index < TypeMax);
782           ResNodeHandled[Index] = TRUE;
783           Alignment = RootBridge->ResAllocNode[Index].Alignment;
784           BitsOfAlignment = LowBitSet64 (Alignment + 1);
785           BaseAddress = MAX_UINT64;
786 
787           switch (Index) {
788           case TypeIo:
789             BaseAddress = AllocateResource (
790                             FALSE,
791                             RootBridge->ResAllocNode[Index].Length,
792                             MIN (15, BitsOfAlignment),
793                             ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),
794                             RootBridge->Io.Limit
795                             );
796             break;
797 
798           case TypeMem64:
799             BaseAddress = AllocateResource (
800                             TRUE,
801                             RootBridge->ResAllocNode[Index].Length,
802                             MIN (63, BitsOfAlignment),
803                             ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),
804                             RootBridge->MemAbove4G.Limit
805                             );
806             if (BaseAddress != MAX_UINT64) {
807               break;
808             }
809             //
810             // If memory above 4GB is not available, try memory below 4GB
811             //
812 
813           case TypeMem32:
814             BaseAddress = AllocateResource (
815                             TRUE,
816                             RootBridge->ResAllocNode[Index].Length,
817                             MIN (31, BitsOfAlignment),
818                             ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),
819                             RootBridge->Mem.Limit
820                             );
821             break;
822 
823           case TypePMem64:
824             BaseAddress = AllocateResource (
825                             TRUE,
826                             RootBridge->ResAllocNode[Index].Length,
827                             MIN (63, BitsOfAlignment),
828                             ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),
829                             RootBridge->PMemAbove4G.Limit
830                             );
831             if (BaseAddress != MAX_UINT64) {
832               break;
833             }
834             //
835             // If memory above 4GB is not available, try memory below 4GB
836             //
837           case TypePMem32:
838             BaseAddress = AllocateResource (
839                             TRUE,
840                             RootBridge->ResAllocNode[Index].Length,
841                             MIN (31, BitsOfAlignment),
842                             ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),
843                             RootBridge->PMem.Limit
844                             );
845             break;
846 
847           default:
848             ASSERT (FALSE);
849             break;
850           }
851 
852           DEBUG ((DEBUG_INFO, "  %s: Base/Length/Alignment = %lx/%lx/%lx - ",
853                   mPciResourceTypeStr[Index], BaseAddress, RootBridge->ResAllocNode[Index].Length, Alignment));
854           if (BaseAddress != MAX_UINT64) {
855             RootBridge->ResAllocNode[Index].Base = BaseAddress;
856             RootBridge->ResAllocNode[Index].Status = ResAllocated;
857             DEBUG ((DEBUG_INFO, "Success\n"));
858           } else {
859             ReturnStatus = EFI_OUT_OF_RESOURCES;
860             DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));
861           }
862         }
863       }
864     }
865 
866     if (ReturnStatus == EFI_OUT_OF_RESOURCES) {
867       ResourceConflict (HostBridge);
868     }
869 
870     //
871     // Set resource to zero for nodes where allocation fails
872     //
873     for (Link = GetFirstNode (&HostBridge->RootBridges)
874           ; !IsNull (&HostBridge->RootBridges, Link)
875           ; Link = GetNextNode (&HostBridge->RootBridges, Link)
876           ) {
877       RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
878       for (Index = TypeIo; Index < TypeBus; Index++) {
879         if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
880           RootBridge->ResAllocNode[Index].Length = 0;
881         }
882       }
883     }
884     return ReturnStatus;
885 
886   case EfiPciHostBridgeSetResources:
887     //
888     // HostBridgeInstance->CanRestarted = FALSE;
889     //
890     break;
891 
892   case EfiPciHostBridgeFreeResources:
893     //
894     // HostBridgeInstance->CanRestarted = FALSE;
895     //
896     ReturnStatus = EFI_SUCCESS;
897     for (Link = GetFirstNode (&HostBridge->RootBridges)
898          ; !IsNull (&HostBridge->RootBridges, Link)
899          ; Link = GetNextNode (&HostBridge->RootBridges, Link)
900          ) {
901       RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
902       for (Index = TypeIo; Index < TypeBus; Index++) {
903         if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {
904           switch (Index) {
905           case TypeIo:
906             Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
907             if (EFI_ERROR (Status)) {
908               ReturnStatus = Status;
909             }
910             break;
911 
912           case TypeMem32:
913           case TypePMem32:
914           case TypeMem64:
915           case TypePMem64:
916             Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
917             if (EFI_ERROR (Status)) {
918               ReturnStatus = Status;
919             }
920             break;
921 
922           default:
923             ASSERT (FALSE);
924             break;
925           }
926 
927           RootBridge->ResAllocNode[Index].Type = Index;
928           RootBridge->ResAllocNode[Index].Base = 0;
929           RootBridge->ResAllocNode[Index].Length = 0;
930           RootBridge->ResAllocNode[Index].Status = ResNone;
931         }
932       }
933 
934       RootBridge->ResourceSubmitted = FALSE;
935     }
936 
937     HostBridge->CanRestarted = TRUE;
938     return ReturnStatus;
939 
940   case EfiPciHostBridgeEndResourceAllocation:
941     //
942     // The resource allocation phase is completed.  No specific action is required
943     // here. This notification can be used to perform any chipset specific programming.
944     //
945     break;
946 
947   case EfiPciHostBridgeEndEnumeration:
948     //
949     // The Host Bridge Enumeration is completed. No specific action is required here.
950     // This notification can be used to perform any chipset specific programming.
951     //
952     break;
953 
954   default:
955     return EFI_INVALID_PARAMETER;
956   }
957 
958   return EFI_SUCCESS;
959 }
960 
961 /**
962 
963   Return the device handle of the next PCI root bridge that is associated with
964   this Host Bridge.
965 
966   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
967   @param RootBridgeHandle  Returns the device handle of the next PCI Root Bridge.
968                            On input, it holds the RootBridgeHandle returned by the most
969                            recent call to GetNextRootBridge().The handle for the first
970                            PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
971 
972   @retval EFI_SUCCESS            Succeed.
973   @retval EFI_NOT_FOUND          Next PCI root bridge not found.
974   @retval EFI_INVALID_PARAMETER  Wrong parameter passed in.
975 
976 **/
977 EFI_STATUS
978 EFIAPI
GetNextRootBridge(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN OUT EFI_HANDLE * RootBridgeHandle)979 GetNextRootBridge (
980   IN     EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
981   IN OUT EFI_HANDLE                                       *RootBridgeHandle
982   )
983 {
984   BOOLEAN                   ReturnNext;
985   LIST_ENTRY                *Link;
986   PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
987   PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
988 
989   if (RootBridgeHandle == NULL) {
990     return EFI_INVALID_PARAMETER;
991   }
992 
993   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
994   ReturnNext = (BOOLEAN) (*RootBridgeHandle == NULL);
995 
996   for (Link = GetFirstNode (&HostBridge->RootBridges)
997       ; !IsNull (&HostBridge->RootBridges, Link)
998       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
999       ) {
1000     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1001     if (ReturnNext) {
1002       *RootBridgeHandle = RootBridge->Handle;
1003       return EFI_SUCCESS;
1004     }
1005 
1006     ReturnNext = (BOOLEAN) (*RootBridgeHandle == RootBridge->Handle);
1007   }
1008 
1009   if (ReturnNext) {
1010     ASSERT (IsNull (&HostBridge->RootBridges, Link));
1011     return EFI_NOT_FOUND;
1012   } else {
1013     return EFI_INVALID_PARAMETER;
1014   }
1015 }
1016 
1017 /**
1018 
1019   Returns the attributes of a PCI Root Bridge.
1020 
1021   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1022   @param RootBridgeHandle  The device handle of the PCI Root Bridge
1023                            that the caller is interested in.
1024   @param Attributes        The pointer to attributes of the PCI Root Bridge.
1025 
1026   @retval EFI_SUCCESS            Succeed.
1027   @retval EFI_INVALID_PARAMETER  Attributes parameter passed in is NULL or
1028                                  RootBridgeHandle is not an EFI_HANDLE
1029                                  that was returned on a previous call to
1030                                  GetNextRootBridge().
1031 
1032 **/
1033 EFI_STATUS
1034 EFIAPI
GetAttributes(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_HANDLE RootBridgeHandle,OUT UINT64 * Attributes)1035 GetAttributes (
1036   IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
1037   IN  EFI_HANDLE                                       RootBridgeHandle,
1038   OUT UINT64                                           *Attributes
1039   )
1040 {
1041   LIST_ENTRY                *Link;
1042   PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
1043   PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
1044 
1045   if (Attributes == NULL) {
1046     return EFI_INVALID_PARAMETER;
1047   }
1048 
1049   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
1050   for (Link = GetFirstNode (&HostBridge->RootBridges)
1051       ; !IsNull (&HostBridge->RootBridges, Link)
1052       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
1053       ) {
1054     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1055     if (RootBridgeHandle == RootBridge->Handle) {
1056       *Attributes = RootBridge->AllocationAttributes;
1057       return EFI_SUCCESS;
1058     }
1059   }
1060 
1061   return EFI_INVALID_PARAMETER;
1062 }
1063 
1064 /**
1065 
1066   This is the request from the PCI enumerator to set up
1067   the specified PCI Root Bridge for bus enumeration process.
1068 
1069   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1070   @param RootBridgeHandle  The PCI Root Bridge to be set up.
1071   @param Configuration     Pointer to the pointer to the PCI bus resource descriptor.
1072 
1073   @retval EFI_SUCCESS            Succeed.
1074   @retval EFI_OUT_OF_RESOURCES   Not enough pool to be allocated.
1075   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid handle.
1076 
1077 **/
1078 EFI_STATUS
1079 EFIAPI
StartBusEnumeration(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_HANDLE RootBridgeHandle,OUT VOID ** Configuration)1080 StartBusEnumeration (
1081   IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
1082   IN  EFI_HANDLE                                       RootBridgeHandle,
1083   OUT VOID                                             **Configuration
1084   )
1085 {
1086   LIST_ENTRY                *Link;
1087   PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
1088   PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
1089   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
1090   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
1091 
1092   if (Configuration == NULL) {
1093     return EFI_INVALID_PARAMETER;
1094   }
1095 
1096   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
1097   for (Link = GetFirstNode (&HostBridge->RootBridges)
1098        ; !IsNull (&HostBridge->RootBridges, Link)
1099        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
1100        ) {
1101     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1102     if (RootBridgeHandle == RootBridge->Handle) {
1103       *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
1104       if (*Configuration == NULL) {
1105         return EFI_OUT_OF_RESOURCES;
1106       }
1107 
1108       Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) *Configuration;
1109       Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
1110       Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
1111       Descriptor->ResType               = ACPI_ADDRESS_SPACE_TYPE_BUS;
1112       Descriptor->GenFlag               = 0;
1113       Descriptor->SpecificFlag          = 0;
1114       Descriptor->AddrSpaceGranularity  = 0;
1115       Descriptor->AddrRangeMin          = RootBridge->Bus.Base;
1116       Descriptor->AddrRangeMax          = 0;
1117       Descriptor->AddrTranslationOffset = 0;
1118       Descriptor->AddrLen               = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;
1119 
1120       End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
1121       End->Desc = ACPI_END_TAG_DESCRIPTOR;
1122       End->Checksum = 0x0;
1123 
1124       return EFI_SUCCESS;
1125     }
1126   }
1127 
1128   return EFI_INVALID_PARAMETER;
1129 }
1130 
1131 /**
1132 
1133   This function programs the PCI Root Bridge hardware so that
1134   it decodes the specified PCI bus range.
1135 
1136   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1137   @param RootBridgeHandle  The PCI Root Bridge whose bus range is to be programmed.
1138   @param Configuration     The pointer to the PCI bus resource descriptor.
1139 
1140   @retval EFI_SUCCESS            Succeed.
1141   @retval EFI_INVALID_PARAMETER  Wrong parameters passed in.
1142 
1143 **/
1144 EFI_STATUS
1145 EFIAPI
SetBusNumbers(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_HANDLE RootBridgeHandle,IN VOID * Configuration)1146 SetBusNumbers (
1147   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
1148   IN EFI_HANDLE                                       RootBridgeHandle,
1149   IN VOID                                             *Configuration
1150   )
1151 {
1152   LIST_ENTRY                *Link;
1153   PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
1154   PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
1155   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
1156   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
1157 
1158   if (Configuration == NULL) {
1159     return EFI_INVALID_PARAMETER;
1160   }
1161 
1162   Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1163   End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
1164 
1165   //
1166   // Check the Configuration is valid
1167   //
1168   if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||
1169       (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||
1170       (End->Desc != ACPI_END_TAG_DESCRIPTOR)
1171      ) {
1172     return EFI_INVALID_PARAMETER;
1173   }
1174 
1175   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
1176   for (Link = GetFirstNode (&HostBridge->RootBridges)
1177        ; !IsNull (&HostBridge->RootBridges, Link)
1178        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
1179        ) {
1180     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1181     if (RootBridgeHandle == RootBridge->Handle) {
1182 
1183       if (Descriptor->AddrLen == 0) {
1184         return EFI_INVALID_PARAMETER;
1185       }
1186 
1187       if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||
1188           (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)
1189          ) {
1190         return EFI_INVALID_PARAMETER;
1191       }
1192       //
1193       // Update the Bus Range
1194       //
1195       RootBridge->ResAllocNode[TypeBus].Base    = Descriptor->AddrRangeMin;
1196       RootBridge->ResAllocNode[TypeBus].Length  = Descriptor->AddrLen;
1197       RootBridge->ResAllocNode[TypeBus].Status  = ResAllocated;
1198       return EFI_SUCCESS;
1199     }
1200   }
1201 
1202   return EFI_INVALID_PARAMETER;
1203 }
1204 
1205 /**
1206 
1207   Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
1208 
1209   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1210   @param RootBridgeHandle  The PCI Root Bridge whose I/O and memory resource requirements.
1211                            are being submitted.
1212   @param Configuration     The pointer to the PCI I/O and PCI memory resource descriptor.
1213 
1214   @retval EFI_SUCCESS            Succeed.
1215   @retval EFI_INVALID_PARAMETER  Wrong parameters passed in.
1216 **/
1217 EFI_STATUS
1218 EFIAPI
SubmitResources(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_HANDLE RootBridgeHandle,IN VOID * Configuration)1219 SubmitResources (
1220   IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
1221   IN EFI_HANDLE                                       RootBridgeHandle,
1222   IN VOID                                             *Configuration
1223   )
1224 {
1225   LIST_ENTRY                        *Link;
1226   PCI_HOST_BRIDGE_INSTANCE          *HostBridge;
1227   PCI_ROOT_BRIDGE_INSTANCE          *RootBridge;
1228   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
1229   PCI_RESOURCE_TYPE                 Type;
1230 
1231   //
1232   // Check the input parameter: Configuration
1233   //
1234   if (Configuration == NULL) {
1235     return EFI_INVALID_PARAMETER;
1236   }
1237 
1238   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
1239   for (Link = GetFirstNode (&HostBridge->RootBridges)
1240        ; !IsNull (&HostBridge->RootBridges, Link)
1241        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
1242        ) {
1243     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1244     if (RootBridgeHandle == RootBridge->Handle) {
1245       DEBUG ((EFI_D_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));
1246       //
1247       // Check the resource descriptors.
1248       // If the Configuration includes one or more invalid resource descriptors, all the resource
1249       // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.
1250       //
1251       for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
1252         if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {
1253           return EFI_INVALID_PARAMETER;
1254         }
1255 
1256         DEBUG ((EFI_D_INFO, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",
1257                 mAcpiAddressSpaceTypeStr[Descriptor->ResType], Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
1258                 (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""
1259                 ));
1260         DEBUG ((EFI_D_INFO, "      Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));
1261         switch (Descriptor->ResType) {
1262         case ACPI_ADDRESS_SPACE_TYPE_MEM:
1263           if (Descriptor->AddrSpaceGranularity != 32 && Descriptor->AddrSpaceGranularity != 64) {
1264             return EFI_INVALID_PARAMETER;
1265           }
1266           if (Descriptor->AddrSpaceGranularity == 32 && Descriptor->AddrLen >= SIZE_4GB) {
1267             return EFI_INVALID_PARAMETER;
1268           }
1269           //
1270           // If the PCI root bridge does not support separate windows for nonprefetchable and
1271           // prefetchable memory, then the PCI bus driver needs to include requests for
1272           // prefetchable memory in the nonprefetchable memory pool.
1273           //
1274           if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&
1275               ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)
1276              ) {
1277             return EFI_INVALID_PARAMETER;
1278           }
1279         case ACPI_ADDRESS_SPACE_TYPE_IO:
1280           //
1281           // Check aligment, it should be of the form 2^n-1
1282           //
1283           if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {
1284             return EFI_INVALID_PARAMETER;
1285           }
1286           break;
1287         default:
1288           ASSERT (FALSE);
1289           break;
1290         }
1291       }
1292       if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
1293         return EFI_INVALID_PARAMETER;
1294       }
1295 
1296       for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
1297         if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
1298           if (Descriptor->AddrSpaceGranularity == 32) {
1299             if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
1300               Type = TypePMem32;
1301             } else {
1302               Type = TypeMem32;
1303             }
1304           } else {
1305             ASSERT (Descriptor->AddrSpaceGranularity == 64);
1306             if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
1307               Type = TypePMem64;
1308             } else {
1309               Type = TypeMem64;
1310             }
1311           }
1312         } else {
1313           ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);
1314           Type = TypeIo;
1315         }
1316         RootBridge->ResAllocNode[Type].Length    = Descriptor->AddrLen;
1317         RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;
1318         RootBridge->ResAllocNode[Type].Status    = ResSubmitted;
1319       }
1320       RootBridge->ResourceSubmitted = TRUE;
1321       return EFI_SUCCESS;
1322     }
1323   }
1324 
1325   return EFI_INVALID_PARAMETER;
1326 }
1327 
1328 /**
1329 
1330   This function returns the proposed resource settings for the specified
1331   PCI Root Bridge.
1332 
1333   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1334   @param RootBridgeHandle  The PCI Root Bridge handle.
1335   @param Configuration     The pointer to the pointer to the PCI I/O
1336                            and memory resource descriptor.
1337 
1338   @retval EFI_SUCCESS            Succeed.
1339   @retval EFI_OUT_OF_RESOURCES   Not enough pool to be allocated.
1340   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid handle.
1341 
1342 **/
1343 EFI_STATUS
1344 EFIAPI
GetProposedResources(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_HANDLE RootBridgeHandle,OUT VOID ** Configuration)1345 GetProposedResources (
1346   IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
1347   IN  EFI_HANDLE                                       RootBridgeHandle,
1348   OUT VOID                                             **Configuration
1349   )
1350 {
1351   LIST_ENTRY                        *Link;
1352   PCI_HOST_BRIDGE_INSTANCE          *HostBridge;
1353   PCI_ROOT_BRIDGE_INSTANCE          *RootBridge;
1354   UINTN                             Index;
1355   UINTN                             Number;
1356   VOID                              *Buffer;
1357   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
1358   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
1359   UINT64                            ResStatus;
1360 
1361   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
1362   for (Link = GetFirstNode (&HostBridge->RootBridges)
1363       ; !IsNull (&HostBridge->RootBridges, Link)
1364       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
1365       ) {
1366     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1367     if (RootBridgeHandle == RootBridge->Handle) {
1368       for (Index = 0, Number = 0; Index < TypeBus; Index++) {
1369         if (RootBridge->ResAllocNode[Index].Status != ResNone) {
1370           Number++;
1371         }
1372       }
1373 
1374       Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
1375       if (Buffer == NULL) {
1376         return EFI_OUT_OF_RESOURCES;
1377       }
1378 
1379       Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Buffer;
1380       for (Index = 0; Index < TypeBus; Index++) {
1381         ResStatus = RootBridge->ResAllocNode[Index].Status;
1382         if (ResStatus != ResNone) {
1383           Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
1384           Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;
1385           Descriptor->GenFlag               = 0;
1386           Descriptor->AddrRangeMin          = RootBridge->ResAllocNode[Index].Base;
1387           Descriptor->AddrRangeMax          = 0;
1388           Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;
1389           Descriptor->AddrLen               = RootBridge->ResAllocNode[Index].Length;
1390 
1391           switch (Index) {
1392 
1393           case TypeIo:
1394             Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_IO;
1395             break;
1396 
1397           case TypePMem32:
1398             Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
1399           case TypeMem32:
1400             Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
1401             Descriptor->AddrSpaceGranularity = 32;
1402             break;
1403 
1404           case TypePMem64:
1405             Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
1406           case TypeMem64:
1407             Descriptor->ResType              = ACPI_ADDRESS_SPACE_TYPE_MEM;
1408             Descriptor->AddrSpaceGranularity = 64;
1409             break;
1410           }
1411 
1412           Descriptor++;
1413         }
1414       }
1415       End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
1416       End->Desc      = ACPI_END_TAG_DESCRIPTOR;
1417       End->Checksum  = 0;
1418 
1419       *Configuration = Buffer;
1420 
1421       return EFI_SUCCESS;
1422     }
1423   }
1424 
1425   return EFI_INVALID_PARAMETER;
1426 }
1427 
1428 /**
1429 
1430   This function is called for all the PCI controllers that the PCI
1431   bus driver finds. Can be used to Preprogram the controller.
1432 
1433   @param This              The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1434   @param RootBridgeHandle  The PCI Root Bridge handle.
1435   @param PciAddress        Address of the controller on the PCI bus.
1436   @param Phase             The Phase during resource allocation.
1437 
1438   @retval EFI_SUCCESS            Succeed.
1439   @retval EFI_INVALID_PARAMETER  RootBridgeHandle is not a valid handle.
1440 
1441 **/
1442 EFI_STATUS
1443 EFIAPI
PreprocessController(IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL * This,IN EFI_HANDLE RootBridgeHandle,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase)1444 PreprocessController (
1445   IN  EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL          *This,
1446   IN  EFI_HANDLE                                                RootBridgeHandle,
1447   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS               PciAddress,
1448   IN  EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE              Phase
1449   )
1450 {
1451   LIST_ENTRY                *Link;
1452   PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
1453   PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
1454 
1455   if ((UINT32) Phase > EfiPciBeforeResourceCollection) {
1456     return EFI_INVALID_PARAMETER;
1457   }
1458 
1459   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
1460   for (Link = GetFirstNode (&HostBridge->RootBridges)
1461        ; !IsNull (&HostBridge->RootBridges, Link)
1462        ; Link = GetNextNode (&HostBridge->RootBridges, Link)
1463        ) {
1464     RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
1465     if (RootBridgeHandle == RootBridge->Handle) {
1466       return EFI_SUCCESS;
1467     }
1468   }
1469 
1470   return EFI_INVALID_PARAMETER;
1471 }
1472