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