]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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 (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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }