]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
MdeModulePkg/PciHostBridge: Don't assert when setting UC to MMIO fails
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciHostBridge.c
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
341\r
342 RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);\r
343 if ((RootBridges == NULL) || (RootBridgeCount == 0)) {\r
344 return EFI_UNSUPPORTED;\r
345 }\r
346\r
347 Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);\r
348 ASSERT_EFI_ERROR (Status);\r
349 Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);\r
350 ASSERT_EFI_ERROR (Status);\r
351\r
352 //\r
353 // Most systems in the world including complex servers have only one Host Bridge.\r
354 //\r
355 HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));\r
356 ASSERT (HostBridge != NULL);\r
357\r
358 HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;\r
359 HostBridge->CanRestarted = TRUE;\r
360 InitializeListHead (&HostBridge->RootBridges);\r
361\r
362 HostBridge->ResAlloc.NotifyPhase = NotifyPhase;\r
363 HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;\r
364 HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;\r
365 HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;\r
366 HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;\r
367 HostBridge->ResAlloc.SubmitResources = SubmitResources;\r
368 HostBridge->ResAlloc.GetProposedResources = GetProposedResources;\r
369 HostBridge->ResAlloc.PreprocessController = PreprocessController;\r
370\r
371 Status = gBS->InstallMultipleProtocolInterfaces (\r
372 &HostBridge->Handle,\r
373 &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,\r
374 NULL\r
375 );\r
6474f1f1 376 ASSERT_EFI_ERROR (Status);\r
4a50cf4e
RN
377 if (EFI_ERROR (Status)) {\r
378 FreePool (HostBridge);\r
379 PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);\r
380 return Status;\r
381 }\r
382\r
383 //\r
384 // Create Root Bridge Device Handle in this Host Bridge\r
385 //\r
386 for (Index = 0; Index < RootBridgeCount; Index++) {\r
387 //\r
388 // Create Root Bridge Handle Instance\r
389 //\r
390 RootBridge = CreateRootBridge (&RootBridges[Index], HostBridge->Handle);\r
391 ASSERT (RootBridge != NULL);\r
392 if (RootBridge == NULL) {\r
393 continue;\r
394 }\r
395\r
396 if (RootBridges[Index].Io.Limit > RootBridges[Index].Io.Base) {\r
6474f1f1
RN
397 Status = AddIoSpace (\r
398 RootBridges[Index].Io.Base,\r
399 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1\r
400 );\r
4a50cf4e
RN
401 ASSERT_EFI_ERROR (Status);\r
402 }\r
403\r
404 //\r
405 // Add all the Mem/PMem aperture to GCD\r
406 // Mem/PMem shouldn't overlap with each other\r
407 // Root bridge which needs to combine MEM and PMEM should only report\r
408 // the MEM aperture in Mem\r
409 //\r
410 MemApertures[0] = &RootBridges[Index].Mem;\r
411 MemApertures[1] = &RootBridges[Index].MemAbove4G;\r
412 MemApertures[2] = &RootBridges[Index].PMem;\r
413 MemApertures[3] = &RootBridges[Index].PMemAbove4G;\r
414\r
415 for (MemApertureIndex = 0; MemApertureIndex < sizeof (MemApertures) / sizeof (MemApertures[0]); MemApertureIndex++) {\r
416 if (MemApertures[MemApertureIndex]->Limit > MemApertures[MemApertureIndex]->Base) {\r
6474f1f1
RN
417 Status = AddMemoryMappedIoSpace (\r
418 MemApertures[MemApertureIndex]->Base,\r
419 MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
420 EFI_MEMORY_UC\r
421 );\r
4a50cf4e
RN
422 ASSERT_EFI_ERROR (Status);\r
423 Status = gDS->SetMemorySpaceAttributes (\r
424 MemApertures[MemApertureIndex]->Base,\r
425 MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
426 EFI_MEMORY_UC\r
427 );\r
13be90fa
RN
428 if (EFI_ERROR (Status)) {\r
429 DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));\r
430 }\r
4a50cf4e
RN
431 }\r
432 }\r
433 //\r
434 // Insert Root Bridge Handle Instance\r
435 //\r
436 Status = gBS->InstallMultipleProtocolInterfaces (\r
437 &RootBridge->Handle,\r
438 &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,\r
439 &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,\r
440 NULL\r
441 );\r
442 ASSERT_EFI_ERROR (Status);\r
443 InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);\r
444 }\r
445 PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);\r
446 return Status;\r
447}\r
448\r
449/**\r
450 This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().\r
451\r
452 @param HostBridge The Host Bridge Instance where the resource adjustment happens.\r
453**/\r
454VOID\r
455ResourceConflict (\r
456 IN PCI_HOST_BRIDGE_INSTANCE *HostBridge\r
457 )\r
458{\r
459 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;\r
460 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
461 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
462 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
463 LIST_ENTRY *Link;\r
464 UINTN RootBridgeCount;\r
465 PCI_RESOURCE_TYPE Index;\r
466 PCI_RES_NODE *ResAllocNode;\r
467\r
468 RootBridgeCount = 0;\r
469 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
470 ; !IsNull (&HostBridge->RootBridges, Link)\r
471 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
472 ) {\r
473 RootBridgeCount++;\r
474 }\r
475\r
476 Resources = AllocatePool (\r
477 RootBridgeCount * (TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)) +\r
478 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)\r
479 );\r
480 ASSERT (Resources != NULL);\r
481\r
482 for (Link = GetFirstNode (&HostBridge->RootBridges), Descriptor = Resources\r
483 ; !IsNull (&HostBridge->RootBridges, Link)\r
484 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
485 ) {\r
486 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
487 for (Index = TypeIo; Index < TypeMax; Index++) {\r
488 ResAllocNode = &RootBridge->ResAllocNode[Index];\r
489\r
490 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
491 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
492 Descriptor->AddrRangeMin = ResAllocNode->Base;\r
493 Descriptor->AddrRangeMax = ResAllocNode->Alignment;\r
494 Descriptor->AddrLen = ResAllocNode->Length;\r
495 switch (ResAllocNode->Type) {\r
496\r
497 case TypeIo:\r
498 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
499 break;\r
500\r
501 case TypePMem32:\r
502 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
503 case TypeMem32:\r
504 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
505 Descriptor->AddrSpaceGranularity = 32;\r
506 break;\r
507\r
508 case TypePMem64:\r
509 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
510 case TypeMem64:\r
511 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
512 Descriptor->AddrSpaceGranularity = 64;\r
513 break;\r
514\r
515 case TypeBus:\r
516 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
517 break;\r
518\r
519 default:\r
520 break;\r
521 }\r
522\r
523 Descriptor++;\r
524 }\r
525 //\r
526 // Terminate the root bridge resources.\r
527 //\r
528 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
529 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
530 End->Checksum = 0x0;\r
531\r
532 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (End + 1);\r
533 }\r
534 //\r
535 // Terminate the host bridge resources.\r
536 //\r
537 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
538 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
539 End->Checksum = 0x0;\r
540\r
541 DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));\r
542 PciHostBridgeResourceConflict (HostBridge->Handle, Resources);\r
543 FreePool (Resources);\r
544}\r
545\r
63b90643
RN
546/**\r
547 Allocate Length of MMIO or IO resource with alignment BitsOfAlignment\r
548 from GCD range [BaseAddress, Limit).\r
549\r
550 @param Mmio TRUE for MMIO and FALSE for IO.\r
551 @param Length Length of the resource to allocate.\r
552 @param BitsOfAlignment Alignment of the resource to allocate.\r
553 @param BaseAddress The starting address the allocation is from.\r
554 @param Limit The ending address the allocation is to.\r
555\r
556 @retval The base address of the allocated resource or MAX_UINT64 if allocation\r
557 fails.\r
558**/\r
4a50cf4e
RN
559UINT64\r
560AllocateResource (\r
561 BOOLEAN Mmio,\r
562 UINT64 Length,\r
563 UINTN BitsOfAlignment,\r
564 UINT64 BaseAddress,\r
565 UINT64 Limit\r
566 )\r
567{\r
568 EFI_STATUS Status;\r
569\r
570 if (BaseAddress < Limit) {\r
571 //\r
572 // Have to make sure Aligment is handled since we are doing direct address allocation\r
573 //\r
574 BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));\r
575\r
576 while (BaseAddress + Length <= Limit + 1) {\r
577 if (Mmio) {\r
578 Status = gDS->AllocateMemorySpace (\r
579 EfiGcdAllocateAddress,\r
580 EfiGcdMemoryTypeMemoryMappedIo,\r
581 BitsOfAlignment,\r
582 Length,\r
583 &BaseAddress,\r
584 gImageHandle,\r
585 NULL\r
586 );\r
587 } else {\r
588 Status = gDS->AllocateIoSpace (\r
589 EfiGcdAllocateAddress,\r
590 EfiGcdIoTypeIo,\r
591 BitsOfAlignment,\r
592 Length,\r
593 &BaseAddress,\r
594 gImageHandle,\r
595 NULL\r
596 );\r
597 }\r
598\r
599 if (!EFI_ERROR (Status)) {\r
600 return BaseAddress;\r
601 }\r
602 BaseAddress += LShiftU64 (1, BitsOfAlignment);\r
603 }\r
604 }\r
605 return MAX_UINT64;\r
606}\r
63b90643 607\r
4a50cf4e
RN
608/**\r
609\r
610 Enter a certain phase of the PCI enumeration process.\r
611\r
612 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.\r
613 @param Phase The phase during enumeration.\r
614\r
615 @retval EFI_SUCCESS Succeed.\r
616 @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.\r
617 @retval EFI_NOT_READY Resources have not been submitted yet.\r
618\r
619**/\r
620EFI_STATUS\r
621EFIAPI\r
622NotifyPhase (\r
623 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
624 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase\r
625 )\r
626{\r
627 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
628 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
629 LIST_ENTRY *Link;\r
630 EFI_PHYSICAL_ADDRESS BaseAddress;\r
631 UINT64 AddrLen;\r
632 UINTN BitsOfAlignment;\r
633 UINT64 Alignment;\r
634 EFI_STATUS Status;\r
635 EFI_STATUS ReturnStatus;\r
636 PCI_RESOURCE_TYPE Index;\r
637 PCI_RESOURCE_TYPE Index1;\r
638 PCI_RESOURCE_TYPE Index2;\r
639 BOOLEAN ResNodeHandled[TypeMax];\r
640 UINT64 MaxAlignment;\r
641\r
642 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
643\r
644 switch (Phase) {\r
645 case EfiPciHostBridgeBeginEnumeration:\r
646 if (!HostBridge->CanRestarted) {\r
647 return EFI_NOT_READY;\r
648 }\r
649 //\r
650 // Reset Root Bridge\r
651 //\r
652 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
653 ; !IsNull (&HostBridge->RootBridges, Link)\r
654 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
655 ) {\r
656 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
657 for (Index = TypeIo; Index < TypeMax; Index++) {\r
658 RootBridge->ResAllocNode[Index].Type = Index;\r
659 RootBridge->ResAllocNode[Index].Base = 0;\r
660 RootBridge->ResAllocNode[Index].Length = 0;\r
661 RootBridge->ResAllocNode[Index].Status = ResNone;\r
662\r
663 RootBridge->ResourceSubmitted = FALSE;\r
664 }\r
665 }\r
666\r
667 HostBridge->CanRestarted = TRUE;\r
668 break;\r
669\r
670 case EfiPciHostBridgeBeginBusAllocation:\r
671 //\r
672 // No specific action is required here, can perform any chipset specific programing\r
673 //\r
674 HostBridge->CanRestarted = FALSE;\r
675 break;\r
676\r
677 case EfiPciHostBridgeEndBusAllocation:\r
678 //\r
679 // No specific action is required here, can perform any chipset specific programing\r
680 //\r
681 break;\r
682\r
683 case EfiPciHostBridgeBeginResourceAllocation:\r
684 //\r
685 // No specific action is required here, can perform any chipset specific programing\r
686 //\r
687 break;\r
688\r
689 case EfiPciHostBridgeAllocateResources:\r
690 ReturnStatus = EFI_SUCCESS;\r
691\r
692 //\r
693 // Make sure the resource for all root bridges has been submitted.\r
694 //\r
695 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
696 ; !IsNull (&HostBridge->RootBridges, Link)\r
697 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
698 ) {\r
699 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
700 if (!RootBridge->ResourceSubmitted) {\r
701 return EFI_NOT_READY;\r
702 }\r
703 }\r
704\r
705 DEBUG ((EFI_D_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));\r
706 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
707 ; !IsNull (&HostBridge->RootBridges, Link)\r
708 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
709 ) {\r
710 for (Index = TypeIo; Index < TypeBus; Index++) {\r
711 ResNodeHandled[Index] = FALSE;\r
712 }\r
713\r
714 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
715 DEBUG ((EFI_D_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));\r
716\r
717 for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {\r
718 if (RootBridge->ResAllocNode[Index1].Status == ResNone) {\r
719 ResNodeHandled[Index1] = TRUE;\r
720 } else {\r
721 //\r
722 // Allocate the resource node with max alignment at first\r
723 //\r
724 MaxAlignment = 0;\r
725 Index = TypeMax;\r
726 for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {\r
727 if (ResNodeHandled[Index2]) {\r
728 continue;\r
729 }\r
730 if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {\r
731 MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;\r
732 Index = Index2;\r
733 }\r
734 }\r
735\r
736 ASSERT (Index < TypeMax);\r
737 ResNodeHandled[Index] = TRUE;\r
738 AddrLen = RootBridge->ResAllocNode[Index].Length;\r
739 Alignment = RootBridge->ResAllocNode[Index].Alignment;\r
740 BitsOfAlignment = LowBitSet64 (Alignment + 1);\r
741 BaseAddress = MAX_UINT64;\r
742\r
743 switch (Index) {\r
744 case TypeIo:\r
745 BaseAddress = AllocateResource (\r
746 FALSE,\r
747 RootBridge->ResAllocNode[Index].Length,\r
748 MIN (15, BitsOfAlignment),\r
749 ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
750 RootBridge->Io.Limit\r
751 );\r
752 break;\r
753\r
754 case TypeMem64:\r
755 BaseAddress = AllocateResource (\r
756 TRUE,\r
757 RootBridge->ResAllocNode[Index].Length,\r
758 MIN (63, BitsOfAlignment),\r
759 ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
760 RootBridge->MemAbove4G.Limit\r
761 );\r
762 if (BaseAddress != MAX_UINT64) {\r
763 break;\r
764 }\r
765 //\r
766 // If memory above 4GB is not available, try memory below 4GB\r
767 //\r
768\r
769 case TypeMem32:\r
770 BaseAddress = AllocateResource (\r
771 TRUE,\r
772 RootBridge->ResAllocNode[Index].Length,\r
773 MIN (31, BitsOfAlignment),\r
774 ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
775 RootBridge->Mem.Limit\r
776 );\r
777 break;\r
778\r
779 case TypePMem64:\r
780 BaseAddress = AllocateResource (\r
781 TRUE,\r
782 RootBridge->ResAllocNode[Index].Length,\r
783 MIN (63, BitsOfAlignment),\r
784 ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
785 RootBridge->PMemAbove4G.Limit\r
786 );\r
787 if (BaseAddress != MAX_UINT64) {\r
788 break;\r
789 }\r
790 //\r
791 // If memory above 4GB is not available, try memory below 4GB\r
792 //\r
793 case TypePMem32:\r
794 BaseAddress = AllocateResource (\r
795 TRUE,\r
796 RootBridge->ResAllocNode[Index].Length,\r
797 MIN (31, BitsOfAlignment),\r
798 ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
799 RootBridge->PMem.Limit\r
800 );\r
801 break;\r
802\r
803 default:\r
804 ASSERT (FALSE);\r
805 break;\r
806 }\r
807\r
808 DEBUG ((DEBUG_INFO, " %s: Base/Length/Alignment = %lx/%lx/%lx - ",\r
809 mPciResourceTypeStr[Index], BaseAddress, RootBridge->ResAllocNode[Index].Length, Alignment));\r
810 if (BaseAddress != MAX_UINT64) {\r
811 RootBridge->ResAllocNode[Index].Base = BaseAddress;\r
812 RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
813 DEBUG ((DEBUG_INFO, "Success\n"));\r
814 } else {\r
815 ReturnStatus = EFI_OUT_OF_RESOURCES;\r
816 DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));\r
817 }\r
818 }\r
819 }\r
820 }\r
821\r
822 if (ReturnStatus == EFI_OUT_OF_RESOURCES) {\r
823 ResourceConflict (HostBridge);\r
824 }\r
825\r
826 //\r
827 // Set resource to zero for nodes where allocation fails\r
828 //\r
829 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
830 ; !IsNull (&HostBridge->RootBridges, Link)\r
831 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
832 ) {\r
833 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
834 for (Index = TypeIo; Index < TypeBus; Index++) {\r
835 if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {\r
836 RootBridge->ResAllocNode[Index].Length = 0;\r
837 }\r
838 }\r
839 }\r
840 return ReturnStatus;\r
841\r
842 case EfiPciHostBridgeSetResources:\r
843 //\r
844 // HostBridgeInstance->CanRestarted = FALSE;\r
845 //\r
846 break;\r
847\r
848 case EfiPciHostBridgeFreeResources:\r
849 //\r
850 // HostBridgeInstance->CanRestarted = FALSE;\r
851 //\r
852 ReturnStatus = EFI_SUCCESS;\r
853 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
854 ; !IsNull (&HostBridge->RootBridges, Link)\r
855 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
856 ) {\r
857 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
858 for (Index = TypeIo; Index < TypeBus; Index++) {\r
859 if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {\r
860 switch (Index) {\r
861 case TypeIo:\r
862 Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);\r
863 if (EFI_ERROR (Status)) {\r
864 ReturnStatus = Status;\r
865 }\r
866 break;\r
867\r
868 case TypeMem32:\r
869 case TypePMem32:\r
870 case TypeMem64:\r
871 case TypePMem64:\r
872 Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);\r
873 if (EFI_ERROR (Status)) {\r
874 ReturnStatus = Status;\r
875 }\r
876 break;\r
877\r
878 default:\r
879 ASSERT (FALSE);\r
880 break;\r
881 }\r
882\r
883 RootBridge->ResAllocNode[Index].Type = Index;\r
884 RootBridge->ResAllocNode[Index].Base = 0;\r
885 RootBridge->ResAllocNode[Index].Length = 0;\r
886 RootBridge->ResAllocNode[Index].Status = ResNone;\r
887 }\r
888 }\r
889\r
890 RootBridge->ResourceSubmitted = FALSE;\r
891 }\r
892\r
893 HostBridge->CanRestarted = TRUE;\r
894 return ReturnStatus;\r
895\r
896 case EfiPciHostBridgeEndResourceAllocation:\r
897 //\r
898 // The resource allocation phase is completed. No specific action is required\r
899 // here. This notification can be used to perform any chipset specific programming.\r
900 //\r
901 break;\r
902\r
903 case EfiPciHostBridgeEndEnumeration:\r
904 //\r
905 // The Host Bridge Enumeration is completed. No specific action is required here.\r
906 // This notification can be used to perform any chipset specific programming.\r
907 //\r
908 break;\r
909\r
910 default:\r
911 return EFI_INVALID_PARAMETER;\r
912 }\r
913\r
914 return EFI_SUCCESS;\r
915}\r
916\r
917/**\r
918\r
919 Return the device handle of the next PCI root bridge that is associated with\r
920 this Host Bridge.\r
921\r
922 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
923 @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.\r
924 On input, it holds the RootBridgeHandle returned by the most\r
925 recent call to GetNextRootBridge().The handle for the first\r
926 PCI Root Bridge is returned if RootBridgeHandle is NULL on input.\r
927\r
928 @retval EFI_SUCCESS Succeed.\r
929 @retval EFI_NOT_FOUND Next PCI root bridge not found.\r
930 @retval EFI_INVALID_PARAMETER Wrong parameter passed in.\r
931\r
932**/\r
933EFI_STATUS\r
934EFIAPI\r
935GetNextRootBridge (\r
936 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
937 IN OUT EFI_HANDLE *RootBridgeHandle\r
938 )\r
939{\r
940 BOOLEAN ReturnNext;\r
941 LIST_ENTRY *Link;\r
942 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
943 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
944\r
945 if (RootBridgeHandle == NULL) {\r
946 return EFI_INVALID_PARAMETER;\r
947 }\r
948\r
949 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
950 ReturnNext = (BOOLEAN) (*RootBridgeHandle == NULL);\r
951\r
952 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
953 ; !IsNull (&HostBridge->RootBridges, Link)\r
954 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
955 ) {\r
956 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
957 if (ReturnNext) {\r
958 *RootBridgeHandle = RootBridge->Handle;\r
959 return EFI_SUCCESS;\r
960 }\r
961\r
962 ReturnNext = (BOOLEAN) (*RootBridgeHandle == RootBridge->Handle);\r
963 }\r
964\r
965 if (ReturnNext) {\r
966 ASSERT (IsNull (&HostBridge->RootBridges, Link));\r
967 return EFI_NOT_FOUND;\r
968 } else {\r
969 return EFI_INVALID_PARAMETER;\r
970 }\r
971}\r
972\r
973/**\r
974\r
975 Returns the attributes of a PCI Root Bridge.\r
976\r
977 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
978 @param RootBridgeHandle The device handle of the PCI Root Bridge\r
979 that the caller is interested in.\r
980 @param Attributes The pointer to attributes of the PCI Root Bridge.\r
981\r
982 @retval EFI_SUCCESS Succeed.\r
983 @retval EFI_INVALID_PARAMETER Attributes parameter passed in is NULL or\r
984 RootBridgeHandle is not an EFI_HANDLE\r
985 that was returned on a previous call to\r
986 GetNextRootBridge().\r
987\r
988**/\r
989EFI_STATUS\r
990EFIAPI\r
991GetAttributes (\r
992 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
993 IN EFI_HANDLE RootBridgeHandle,\r
994 OUT UINT64 *Attributes\r
995 )\r
996{\r
997 LIST_ENTRY *Link;\r
998 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
999 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1000\r
1001 if (Attributes == NULL) {\r
1002 return EFI_INVALID_PARAMETER;\r
1003 }\r
1004\r
1005 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1006 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1007 ; !IsNull (&HostBridge->RootBridges, Link)\r
1008 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1009 ) {\r
1010 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1011 if (RootBridgeHandle == RootBridge->Handle) {\r
1012 *Attributes = RootBridge->AllocationAttributes;\r
1013 return EFI_SUCCESS;\r
1014 }\r
1015 }\r
1016\r
1017 return EFI_INVALID_PARAMETER;\r
1018}\r
1019\r
1020/**\r
1021\r
1022 This is the request from the PCI enumerator to set up\r
1023 the specified PCI Root Bridge for bus enumeration process.\r
1024\r
1025 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1026 @param RootBridgeHandle The PCI Root Bridge to be set up.\r
1027 @param Configuration Pointer to the pointer to the PCI bus resource descriptor.\r
1028\r
1029 @retval EFI_SUCCESS Succeed.\r
1030 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.\r
1031 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1032\r
1033**/\r
1034EFI_STATUS\r
1035EFIAPI\r
1036StartBusEnumeration (\r
1037 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1038 IN EFI_HANDLE RootBridgeHandle,\r
1039 OUT VOID **Configuration\r
1040 )\r
1041{\r
1042 LIST_ENTRY *Link;\r
1043 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1044 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1045 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1046 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1047\r
1048 if (Configuration == NULL) {\r
1049 return EFI_INVALID_PARAMETER;\r
1050 }\r
1051\r
1052 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1053 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1054 ; !IsNull (&HostBridge->RootBridges, Link)\r
1055 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1056 ) {\r
1057 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1058 if (RootBridgeHandle == RootBridge->Handle) {\r
1059 *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1060 if (*Configuration == NULL) {\r
1061 return EFI_OUT_OF_RESOURCES;\r
1062 }\r
1063\r
1064 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) *Configuration;\r
1065 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1066 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
1067 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
1068 Descriptor->GenFlag = 0;\r
1069 Descriptor->SpecificFlag = 0;\r
1070 Descriptor->AddrSpaceGranularity = 0;\r
1071 Descriptor->AddrRangeMin = RootBridge->Bus.Base;\r
1072 Descriptor->AddrRangeMax = 0;\r
1073 Descriptor->AddrTranslationOffset = 0;\r
1074 Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;\r
1075\r
1076 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1077 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1078 End->Checksum = 0x0;\r
1079\r
1080 return EFI_SUCCESS;\r
1081 }\r
1082 }\r
1083\r
1084 return EFI_INVALID_PARAMETER;\r
1085}\r
1086\r
1087/**\r
1088\r
1089 This function programs the PCI Root Bridge hardware so that\r
1090 it decodes the specified PCI bus range.\r
1091\r
1092 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1093 @param RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed.\r
1094 @param Configuration The pointer to the PCI bus resource descriptor.\r
1095\r
1096 @retval EFI_SUCCESS Succeed.\r
1097 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.\r
1098\r
1099**/\r
1100EFI_STATUS\r
1101EFIAPI\r
1102SetBusNumbers (\r
1103 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1104 IN EFI_HANDLE RootBridgeHandle,\r
1105 IN VOID *Configuration\r
1106 )\r
1107{\r
1108 LIST_ENTRY *Link;\r
1109 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1110 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1111 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1112 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1113 UINTN BusStart;\r
1114 UINTN BusEnd;\r
1115 UINTN BusLen;\r
1116\r
1117 if (Configuration == NULL) {\r
1118 return EFI_INVALID_PARAMETER;\r
1119 }\r
1120\r
1121 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1122 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1123\r
1124 //\r
1125 // Check the Configuration is valid\r
1126 //\r
1127 if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||\r
1128 (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||\r
1129 (End->Desc != ACPI_END_TAG_DESCRIPTOR)\r
1130 ) {\r
1131 return EFI_INVALID_PARAMETER;\r
1132 }\r
1133\r
1134 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1135 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1136 ; !IsNull (&HostBridge->RootBridges, Link)\r
1137 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1138 ) {\r
1139 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1140 if (RootBridgeHandle == RootBridge->Handle) {\r
1141 BusStart = (UINTN) Descriptor->AddrRangeMin;\r
1142 BusLen = (UINTN) Descriptor->AddrLen;\r
1143 BusEnd = BusStart + BusLen - 1;\r
1144\r
1145 if (Descriptor->AddrLen == 0) {\r
1146 return EFI_INVALID_PARAMETER;\r
1147 }\r
1148\r
1149 if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||\r
1150 (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)\r
1151 ) {\r
1152 return EFI_INVALID_PARAMETER;\r
1153 }\r
1154 //\r
1155 // Update the Bus Range\r
1156 //\r
1157 RootBridge->ResAllocNode[TypeBus].Base = Descriptor->AddrRangeMin;\r
1158 RootBridge->ResAllocNode[TypeBus].Length = Descriptor->AddrLen;\r
1159 RootBridge->ResAllocNode[TypeBus].Status = ResAllocated;\r
1160 return EFI_SUCCESS;\r
1161 }\r
1162 }\r
1163\r
1164 return EFI_INVALID_PARAMETER;\r
1165}\r
1166\r
1167/**\r
1168\r
1169 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.\r
1170\r
1171 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1172 @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements.\r
1173 are being submitted.\r
1174 @param Configuration The pointer to the PCI I/O and PCI memory resource descriptor.\r
1175\r
1176 @retval EFI_SUCCESS Succeed.\r
1177 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.\r
1178**/\r
1179EFI_STATUS\r
1180EFIAPI\r
1181SubmitResources (\r
1182 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1183 IN EFI_HANDLE RootBridgeHandle,\r
1184 IN VOID *Configuration\r
1185 )\r
1186{\r
1187 LIST_ENTRY *Link;\r
1188 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1189 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1190 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1191 PCI_RESOURCE_TYPE Type;\r
1192\r
1193 //\r
1194 // Check the input parameter: Configuration\r
1195 //\r
1196 if (Configuration == NULL) {\r
1197 return EFI_INVALID_PARAMETER;\r
1198 }\r
1199\r
1200 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1201 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1202 ; !IsNull (&HostBridge->RootBridges, Link)\r
1203 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1204 ) {\r
1205 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1206 if (RootBridgeHandle == RootBridge->Handle) {\r
1207 DEBUG ((EFI_D_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));\r
1208 //\r
1209 // Check the resource descriptors.\r
1210 // If the Configuration includes one or more invalid resource descriptors, all the resource\r
1211 // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.\r
1212 //\r
1213 for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
1214 if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1215 return EFI_INVALID_PARAMETER;\r
1216 }\r
1217\r
1218 DEBUG ((EFI_D_INFO, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",\r
1219 mAcpiAddressSpaceTypeStr[Descriptor->ResType], Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,\r
1220 (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""\r
1221 ));\r
1222 DEBUG ((EFI_D_INFO, " Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));\r
1223 switch (Descriptor->ResType) {\r
1224 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1225 if (Descriptor->AddrSpaceGranularity != 32 && Descriptor->AddrSpaceGranularity != 64) {\r
1226 return EFI_INVALID_PARAMETER;\r
1227 }\r
1228 if (Descriptor->AddrSpaceGranularity == 32 && Descriptor->AddrLen >= SIZE_4GB) {\r
1229 return EFI_INVALID_PARAMETER;\r
1230 }\r
1231 //\r
1232 // If the PCI root bridge does not support separate windows for nonprefetchable and\r
1233 // prefetchable memory, then the PCI bus driver needs to include requests for\r
1234 // prefetchable memory in the nonprefetchable memory pool.\r
1235 //\r
1236 if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&\r
1237 ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)\r
1238 ) {\r
1239 return EFI_INVALID_PARAMETER;\r
1240 }\r
1241 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1242 //\r
1243 // Check aligment, it should be of the form 2^n-1\r
1244 //\r
1245 if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {\r
1246 return EFI_INVALID_PARAMETER;\r
1247 }\r
1248 break;\r
1249 default:\r
1250 ASSERT (FALSE);\r
1251 break;\r
1252 }\r
1253 }\r
1254 if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1255 return EFI_INVALID_PARAMETER;\r
1256 }\r
1257\r
1258 for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
1259 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
1260 if (Descriptor->AddrSpaceGranularity == 32) {\r
1261 if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {\r
1262 Type = TypePMem32;\r
1263 } else {\r
1264 Type = TypeMem32;\r
1265 }\r
1266 } else {\r
1267 ASSERT (Descriptor->AddrSpaceGranularity == 64);\r
1268 if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {\r
1269 Type = TypePMem64;\r
1270 } else {\r
1271 Type = TypeMem64;\r
1272 }\r
1273 }\r
1274 } else {\r
1275 ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);\r
1276 Type = TypeIo;\r
1277 }\r
1278 RootBridge->ResAllocNode[Type].Length = Descriptor->AddrLen;\r
1279 RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;\r
1280 RootBridge->ResAllocNode[Type].Status = ResSubmitted;\r
1281 }\r
1282 RootBridge->ResourceSubmitted = TRUE;\r
1283 return EFI_SUCCESS;\r
1284 }\r
1285 }\r
1286\r
1287 return EFI_INVALID_PARAMETER;\r
1288}\r
1289\r
1290/**\r
1291\r
1292 This function returns the proposed resource settings for the specified\r
1293 PCI Root Bridge.\r
1294\r
1295 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1296 @param RootBridgeHandle The PCI Root Bridge handle.\r
1297 @param Configuration The pointer to the pointer to the PCI I/O\r
1298 and memory resource descriptor.\r
1299\r
1300 @retval EFI_SUCCESS Succeed.\r
1301 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.\r
1302 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1303\r
1304**/\r
1305EFI_STATUS\r
1306EFIAPI\r
1307GetProposedResources (\r
1308 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1309 IN EFI_HANDLE RootBridgeHandle,\r
1310 OUT VOID **Configuration\r
1311 )\r
1312{\r
1313 LIST_ENTRY *Link;\r
1314 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1315 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1316 UINTN Index;\r
1317 UINTN Number;\r
1318 VOID *Buffer;\r
1319 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1320 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1321 UINT64 ResStatus;\r
1322\r
1323 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1324 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1325 ; !IsNull (&HostBridge->RootBridges, Link)\r
1326 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1327 ) {\r
1328 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1329 if (RootBridgeHandle == RootBridge->Handle) {\r
1330 for (Index = 0, Number = 0; Index < TypeBus; Index++) {\r
1331 if (RootBridge->ResAllocNode[Index].Status != ResNone) {\r
1332 Number++;\r
1333 }\r
1334 }\r
1335\r
1336 Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1337 if (Buffer == NULL) {\r
1338 return EFI_OUT_OF_RESOURCES;\r
1339 }\r
1340\r
1341 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Buffer;\r
1342 for (Index = 0; Index < TypeBus; Index++) {\r
1343 ResStatus = RootBridge->ResAllocNode[Index].Status;\r
1344 if (ResStatus != ResNone) {\r
1345 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1346 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;\r
1347 Descriptor->GenFlag = 0;\r
1348 Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;\r
1349 Descriptor->AddrRangeMax = 0;\r
1350 Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;\r
1351 Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length;\r
1352\r
1353 switch (Index) {\r
1354\r
1355 case TypeIo:\r
1356 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
1357 break;\r
1358\r
1359 case TypePMem32:\r
1360 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1361 case TypeMem32:\r
1362 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1363 Descriptor->AddrSpaceGranularity = 32;\r
1364 break;\r
1365\r
1366 case TypePMem64:\r
1367 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1368 case TypeMem64:\r
1369 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1370 Descriptor->AddrSpaceGranularity = 64;\r
1371 break;\r
1372 }\r
1373\r
1374 Descriptor++;\r
1375 }\r
1376 }\r
1377 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
1378 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1379 End->Checksum = 0;\r
1380\r
1381 *Configuration = Buffer;\r
1382\r
1383 return EFI_SUCCESS;\r
1384 }\r
1385 }\r
1386\r
1387 return EFI_INVALID_PARAMETER;\r
1388}\r
1389\r
1390/**\r
1391\r
1392 This function is called for all the PCI controllers that the PCI\r
1393 bus driver finds. Can be used to Preprogram the controller.\r
1394\r
1395 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1396 @param RootBridgeHandle The PCI Root Bridge handle.\r
1397 @param PciAddress Address of the controller on the PCI bus.\r
1398 @param Phase The Phase during resource allocation.\r
1399\r
1400 @retval EFI_SUCCESS Succeed.\r
1401 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1402\r
1403**/\r
1404EFI_STATUS\r
1405EFIAPI\r
1406PreprocessController (\r
1407 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1408 IN EFI_HANDLE RootBridgeHandle,\r
1409 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,\r
1410 IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase\r
1411 )\r
1412{\r
1413 LIST_ENTRY *Link;\r
1414 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1415 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1416\r
1417 if ((UINT32) Phase > EfiPciBeforeResourceCollection) {\r
1418 return EFI_INVALID_PARAMETER;\r
1419 }\r
1420\r
1421 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1422 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1423 ; !IsNull (&HostBridge->RootBridges, Link)\r
1424 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1425 ) {\r
1426 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1427 if (RootBridgeHandle == RootBridge->Handle) {\r
1428 return EFI_SUCCESS;\r
1429 }\r
1430 }\r
1431\r
1432 return EFI_INVALID_PARAMETER;\r
1433}\r