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