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