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