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