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