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