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