MdeModulePkg/PciHostBridge: Add IOMMU support.
[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
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
577 Descriptor->AddrLen = ResAllocNode->Length;\r
578 switch (ResAllocNode->Type) {\r
579\r
580 case TypeIo:\r
581 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
582 break;\r
583\r
584 case TypePMem32:\r
585 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
586 case TypeMem32:\r
587 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
588 Descriptor->AddrSpaceGranularity = 32;\r
589 break;\r
590\r
591 case TypePMem64:\r
592 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
593 case TypeMem64:\r
594 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
595 Descriptor->AddrSpaceGranularity = 64;\r
596 break;\r
597\r
598 case TypeBus:\r
599 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
600 break;\r
601\r
602 default:\r
603 break;\r
604 }\r
605\r
606 Descriptor++;\r
607 }\r
608 //\r
609 // Terminate the root bridge resources.\r
610 //\r
611 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
612 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
613 End->Checksum = 0x0;\r
614\r
615 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (End + 1);\r
616 }\r
617 //\r
618 // Terminate the host bridge resources.\r
619 //\r
620 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
621 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
622 End->Checksum = 0x0;\r
623\r
624 DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));\r
625 PciHostBridgeResourceConflict (HostBridge->Handle, Resources);\r
626 FreePool (Resources);\r
627}\r
628\r
63b90643
RN
629/**\r
630 Allocate Length of MMIO or IO resource with alignment BitsOfAlignment\r
631 from GCD range [BaseAddress, Limit).\r
632\r
633 @param Mmio TRUE for MMIO and FALSE for IO.\r
634 @param Length Length of the resource to allocate.\r
635 @param BitsOfAlignment Alignment of the resource to allocate.\r
636 @param BaseAddress The starting address the allocation is from.\r
637 @param Limit The ending address the allocation is to.\r
638\r
639 @retval The base address of the allocated resource or MAX_UINT64 if allocation\r
640 fails.\r
641**/\r
4a50cf4e
RN
642UINT64\r
643AllocateResource (\r
644 BOOLEAN Mmio,\r
645 UINT64 Length,\r
646 UINTN BitsOfAlignment,\r
647 UINT64 BaseAddress,\r
648 UINT64 Limit\r
649 )\r
650{\r
651 EFI_STATUS Status;\r
652\r
653 if (BaseAddress < Limit) {\r
654 //\r
655 // Have to make sure Aligment is handled since we are doing direct address allocation\r
656 //\r
657 BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));\r
658\r
659 while (BaseAddress + Length <= Limit + 1) {\r
660 if (Mmio) {\r
661 Status = gDS->AllocateMemorySpace (\r
662 EfiGcdAllocateAddress,\r
663 EfiGcdMemoryTypeMemoryMappedIo,\r
664 BitsOfAlignment,\r
665 Length,\r
666 &BaseAddress,\r
667 gImageHandle,\r
668 NULL\r
669 );\r
670 } else {\r
671 Status = gDS->AllocateIoSpace (\r
672 EfiGcdAllocateAddress,\r
673 EfiGcdIoTypeIo,\r
674 BitsOfAlignment,\r
675 Length,\r
676 &BaseAddress,\r
677 gImageHandle,\r
678 NULL\r
679 );\r
680 }\r
681\r
682 if (!EFI_ERROR (Status)) {\r
683 return BaseAddress;\r
684 }\r
685 BaseAddress += LShiftU64 (1, BitsOfAlignment);\r
686 }\r
687 }\r
688 return MAX_UINT64;\r
689}\r
63b90643 690\r
4a50cf4e
RN
691/**\r
692\r
693 Enter a certain phase of the PCI enumeration process.\r
694\r
695 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.\r
696 @param Phase The phase during enumeration.\r
697\r
698 @retval EFI_SUCCESS Succeed.\r
699 @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.\r
700 @retval EFI_NOT_READY Resources have not been submitted yet.\r
701\r
702**/\r
703EFI_STATUS\r
704EFIAPI\r
705NotifyPhase (\r
706 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
707 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase\r
708 )\r
709{\r
710 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
711 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
712 LIST_ENTRY *Link;\r
713 EFI_PHYSICAL_ADDRESS BaseAddress;\r
4a50cf4e
RN
714 UINTN BitsOfAlignment;\r
715 UINT64 Alignment;\r
716 EFI_STATUS Status;\r
717 EFI_STATUS ReturnStatus;\r
718 PCI_RESOURCE_TYPE Index;\r
719 PCI_RESOURCE_TYPE Index1;\r
720 PCI_RESOURCE_TYPE Index2;\r
721 BOOLEAN ResNodeHandled[TypeMax];\r
722 UINT64 MaxAlignment;\r
723\r
724 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
725\r
726 switch (Phase) {\r
727 case EfiPciHostBridgeBeginEnumeration:\r
728 if (!HostBridge->CanRestarted) {\r
729 return EFI_NOT_READY;\r
730 }\r
731 //\r
732 // Reset Root Bridge\r
733 //\r
734 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
735 ; !IsNull (&HostBridge->RootBridges, Link)\r
736 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
737 ) {\r
738 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
739 for (Index = TypeIo; Index < TypeMax; Index++) {\r
740 RootBridge->ResAllocNode[Index].Type = Index;\r
741 RootBridge->ResAllocNode[Index].Base = 0;\r
742 RootBridge->ResAllocNode[Index].Length = 0;\r
743 RootBridge->ResAllocNode[Index].Status = ResNone;\r
744\r
745 RootBridge->ResourceSubmitted = FALSE;\r
746 }\r
747 }\r
748\r
749 HostBridge->CanRestarted = TRUE;\r
750 break;\r
751\r
752 case EfiPciHostBridgeBeginBusAllocation:\r
753 //\r
754 // No specific action is required here, can perform any chipset specific programing\r
755 //\r
756 HostBridge->CanRestarted = FALSE;\r
757 break;\r
758\r
759 case EfiPciHostBridgeEndBusAllocation:\r
760 //\r
761 // No specific action is required here, can perform any chipset specific programing\r
762 //\r
763 break;\r
764\r
765 case EfiPciHostBridgeBeginResourceAllocation:\r
766 //\r
767 // No specific action is required here, can perform any chipset specific programing\r
768 //\r
769 break;\r
770\r
771 case EfiPciHostBridgeAllocateResources:\r
772 ReturnStatus = EFI_SUCCESS;\r
773\r
774 //\r
775 // Make sure the resource for all root bridges has been submitted.\r
776 //\r
777 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
778 ; !IsNull (&HostBridge->RootBridges, Link)\r
779 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
780 ) {\r
781 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
782 if (!RootBridge->ResourceSubmitted) {\r
783 return EFI_NOT_READY;\r
784 }\r
785 }\r
786\r
787 DEBUG ((EFI_D_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));\r
788 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
789 ; !IsNull (&HostBridge->RootBridges, Link)\r
790 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
791 ) {\r
792 for (Index = TypeIo; Index < TypeBus; Index++) {\r
793 ResNodeHandled[Index] = FALSE;\r
794 }\r
795\r
796 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
797 DEBUG ((EFI_D_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));\r
798\r
799 for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {\r
800 if (RootBridge->ResAllocNode[Index1].Status == ResNone) {\r
801 ResNodeHandled[Index1] = TRUE;\r
802 } else {\r
803 //\r
804 // Allocate the resource node with max alignment at first\r
805 //\r
806 MaxAlignment = 0;\r
807 Index = TypeMax;\r
808 for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {\r
809 if (ResNodeHandled[Index2]) {\r
810 continue;\r
811 }\r
812 if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {\r
813 MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;\r
814 Index = Index2;\r
815 }\r
816 }\r
817\r
818 ASSERT (Index < TypeMax);\r
819 ResNodeHandled[Index] = TRUE;\r
4a50cf4e
RN
820 Alignment = RootBridge->ResAllocNode[Index].Alignment;\r
821 BitsOfAlignment = LowBitSet64 (Alignment + 1);\r
822 BaseAddress = MAX_UINT64;\r
823\r
824 switch (Index) {\r
825 case TypeIo:\r
826 BaseAddress = AllocateResource (\r
827 FALSE,\r
828 RootBridge->ResAllocNode[Index].Length,\r
829 MIN (15, BitsOfAlignment),\r
830 ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
831 RootBridge->Io.Limit\r
832 );\r
833 break;\r
834\r
835 case TypeMem64:\r
836 BaseAddress = AllocateResource (\r
837 TRUE,\r
838 RootBridge->ResAllocNode[Index].Length,\r
839 MIN (63, BitsOfAlignment),\r
840 ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
841 RootBridge->MemAbove4G.Limit\r
842 );\r
843 if (BaseAddress != MAX_UINT64) {\r
844 break;\r
845 }\r
846 //\r
847 // If memory above 4GB is not available, try memory below 4GB\r
848 //\r
849\r
850 case TypeMem32:\r
851 BaseAddress = AllocateResource (\r
852 TRUE,\r
853 RootBridge->ResAllocNode[Index].Length,\r
854 MIN (31, BitsOfAlignment),\r
855 ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
856 RootBridge->Mem.Limit\r
857 );\r
858 break;\r
859\r
860 case TypePMem64:\r
861 BaseAddress = AllocateResource (\r
862 TRUE,\r
863 RootBridge->ResAllocNode[Index].Length,\r
864 MIN (63, BitsOfAlignment),\r
865 ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
866 RootBridge->PMemAbove4G.Limit\r
867 );\r
868 if (BaseAddress != MAX_UINT64) {\r
869 break;\r
870 }\r
871 //\r
872 // If memory above 4GB is not available, try memory below 4GB\r
873 //\r
874 case TypePMem32:\r
875 BaseAddress = AllocateResource (\r
876 TRUE,\r
877 RootBridge->ResAllocNode[Index].Length,\r
878 MIN (31, BitsOfAlignment),\r
879 ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
880 RootBridge->PMem.Limit\r
881 );\r
882 break;\r
883\r
884 default:\r
885 ASSERT (FALSE);\r
886 break;\r
887 }\r
888\r
889 DEBUG ((DEBUG_INFO, " %s: Base/Length/Alignment = %lx/%lx/%lx - ",\r
890 mPciResourceTypeStr[Index], BaseAddress, RootBridge->ResAllocNode[Index].Length, Alignment));\r
891 if (BaseAddress != MAX_UINT64) {\r
892 RootBridge->ResAllocNode[Index].Base = BaseAddress;\r
893 RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
894 DEBUG ((DEBUG_INFO, "Success\n"));\r
895 } else {\r
896 ReturnStatus = EFI_OUT_OF_RESOURCES;\r
897 DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));\r
898 }\r
899 }\r
900 }\r
901 }\r
902\r
903 if (ReturnStatus == EFI_OUT_OF_RESOURCES) {\r
904 ResourceConflict (HostBridge);\r
905 }\r
906\r
907 //\r
908 // Set resource to zero for nodes where allocation fails\r
909 //\r
910 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
911 ; !IsNull (&HostBridge->RootBridges, Link)\r
912 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
913 ) {\r
914 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
915 for (Index = TypeIo; Index < TypeBus; Index++) {\r
916 if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {\r
917 RootBridge->ResAllocNode[Index].Length = 0;\r
918 }\r
919 }\r
920 }\r
921 return ReturnStatus;\r
922\r
923 case EfiPciHostBridgeSetResources:\r
924 //\r
925 // HostBridgeInstance->CanRestarted = FALSE;\r
926 //\r
927 break;\r
928\r
929 case EfiPciHostBridgeFreeResources:\r
930 //\r
931 // HostBridgeInstance->CanRestarted = FALSE;\r
932 //\r
933 ReturnStatus = EFI_SUCCESS;\r
934 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
935 ; !IsNull (&HostBridge->RootBridges, Link)\r
936 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
937 ) {\r
938 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
939 for (Index = TypeIo; Index < TypeBus; Index++) {\r
940 if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {\r
941 switch (Index) {\r
942 case TypeIo:\r
943 Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);\r
944 if (EFI_ERROR (Status)) {\r
945 ReturnStatus = Status;\r
946 }\r
947 break;\r
948\r
949 case TypeMem32:\r
950 case TypePMem32:\r
951 case TypeMem64:\r
952 case TypePMem64:\r
953 Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);\r
954 if (EFI_ERROR (Status)) {\r
955 ReturnStatus = Status;\r
956 }\r
957 break;\r
958\r
959 default:\r
960 ASSERT (FALSE);\r
961 break;\r
962 }\r
963\r
964 RootBridge->ResAllocNode[Index].Type = Index;\r
965 RootBridge->ResAllocNode[Index].Base = 0;\r
966 RootBridge->ResAllocNode[Index].Length = 0;\r
967 RootBridge->ResAllocNode[Index].Status = ResNone;\r
968 }\r
969 }\r
970\r
971 RootBridge->ResourceSubmitted = FALSE;\r
972 }\r
973\r
974 HostBridge->CanRestarted = TRUE;\r
975 return ReturnStatus;\r
976\r
977 case EfiPciHostBridgeEndResourceAllocation:\r
978 //\r
979 // The resource allocation phase is completed. No specific action is required\r
980 // here. This notification can be used to perform any chipset specific programming.\r
981 //\r
982 break;\r
983\r
984 case EfiPciHostBridgeEndEnumeration:\r
985 //\r
986 // The Host Bridge Enumeration is completed. No specific action is required here.\r
987 // This notification can be used to perform any chipset specific programming.\r
988 //\r
989 break;\r
990\r
991 default:\r
992 return EFI_INVALID_PARAMETER;\r
993 }\r
994\r
995 return EFI_SUCCESS;\r
996}\r
997\r
998/**\r
999\r
1000 Return the device handle of the next PCI root bridge that is associated with\r
1001 this Host Bridge.\r
1002\r
1003 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1004 @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.\r
1005 On input, it holds the RootBridgeHandle returned by the most\r
1006 recent call to GetNextRootBridge().The handle for the first\r
1007 PCI Root Bridge is returned if RootBridgeHandle is NULL on input.\r
1008\r
1009 @retval EFI_SUCCESS Succeed.\r
1010 @retval EFI_NOT_FOUND Next PCI root bridge not found.\r
1011 @retval EFI_INVALID_PARAMETER Wrong parameter passed in.\r
1012\r
1013**/\r
1014EFI_STATUS\r
1015EFIAPI\r
1016GetNextRootBridge (\r
1017 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1018 IN OUT EFI_HANDLE *RootBridgeHandle\r
1019 )\r
1020{\r
1021 BOOLEAN ReturnNext;\r
1022 LIST_ENTRY *Link;\r
1023 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1024 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1025\r
1026 if (RootBridgeHandle == NULL) {\r
1027 return EFI_INVALID_PARAMETER;\r
1028 }\r
1029\r
1030 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1031 ReturnNext = (BOOLEAN) (*RootBridgeHandle == NULL);\r
1032\r
1033 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1034 ; !IsNull (&HostBridge->RootBridges, Link)\r
1035 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1036 ) {\r
1037 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1038 if (ReturnNext) {\r
1039 *RootBridgeHandle = RootBridge->Handle;\r
1040 return EFI_SUCCESS;\r
1041 }\r
1042\r
1043 ReturnNext = (BOOLEAN) (*RootBridgeHandle == RootBridge->Handle);\r
1044 }\r
1045\r
1046 if (ReturnNext) {\r
1047 ASSERT (IsNull (&HostBridge->RootBridges, Link));\r
1048 return EFI_NOT_FOUND;\r
1049 } else {\r
1050 return EFI_INVALID_PARAMETER;\r
1051 }\r
1052}\r
1053\r
1054/**\r
1055\r
1056 Returns the attributes of a PCI Root Bridge.\r
1057\r
1058 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1059 @param RootBridgeHandle The device handle of the PCI Root Bridge\r
1060 that the caller is interested in.\r
1061 @param Attributes The pointer to attributes of the PCI Root Bridge.\r
1062\r
1063 @retval EFI_SUCCESS Succeed.\r
1064 @retval EFI_INVALID_PARAMETER Attributes parameter passed in is NULL or\r
1065 RootBridgeHandle is not an EFI_HANDLE\r
1066 that was returned on a previous call to\r
1067 GetNextRootBridge().\r
1068\r
1069**/\r
1070EFI_STATUS\r
1071EFIAPI\r
1072GetAttributes (\r
1073 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1074 IN EFI_HANDLE RootBridgeHandle,\r
1075 OUT UINT64 *Attributes\r
1076 )\r
1077{\r
1078 LIST_ENTRY *Link;\r
1079 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1080 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1081\r
1082 if (Attributes == NULL) {\r
1083 return EFI_INVALID_PARAMETER;\r
1084 }\r
1085\r
1086 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1087 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1088 ; !IsNull (&HostBridge->RootBridges, Link)\r
1089 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1090 ) {\r
1091 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1092 if (RootBridgeHandle == RootBridge->Handle) {\r
1093 *Attributes = RootBridge->AllocationAttributes;\r
1094 return EFI_SUCCESS;\r
1095 }\r
1096 }\r
1097\r
1098 return EFI_INVALID_PARAMETER;\r
1099}\r
1100\r
1101/**\r
1102\r
1103 This is the request from the PCI enumerator to set up\r
1104 the specified PCI Root Bridge for bus enumeration process.\r
1105\r
1106 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1107 @param RootBridgeHandle The PCI Root Bridge to be set up.\r
1108 @param Configuration Pointer to the pointer to the PCI bus resource descriptor.\r
1109\r
1110 @retval EFI_SUCCESS Succeed.\r
1111 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.\r
1112 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1113\r
1114**/\r
1115EFI_STATUS\r
1116EFIAPI\r
1117StartBusEnumeration (\r
1118 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1119 IN EFI_HANDLE RootBridgeHandle,\r
1120 OUT VOID **Configuration\r
1121 )\r
1122{\r
1123 LIST_ENTRY *Link;\r
1124 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1125 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1126 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1127 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1128\r
1129 if (Configuration == NULL) {\r
1130 return EFI_INVALID_PARAMETER;\r
1131 }\r
1132\r
1133 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1134 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1135 ; !IsNull (&HostBridge->RootBridges, Link)\r
1136 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1137 ) {\r
1138 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1139 if (RootBridgeHandle == RootBridge->Handle) {\r
1140 *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1141 if (*Configuration == NULL) {\r
1142 return EFI_OUT_OF_RESOURCES;\r
1143 }\r
1144\r
1145 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) *Configuration;\r
1146 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1147 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
1148 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
1149 Descriptor->GenFlag = 0;\r
1150 Descriptor->SpecificFlag = 0;\r
1151 Descriptor->AddrSpaceGranularity = 0;\r
1152 Descriptor->AddrRangeMin = RootBridge->Bus.Base;\r
1153 Descriptor->AddrRangeMax = 0;\r
1154 Descriptor->AddrTranslationOffset = 0;\r
1155 Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;\r
1156\r
1157 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1158 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1159 End->Checksum = 0x0;\r
1160\r
1161 return EFI_SUCCESS;\r
1162 }\r
1163 }\r
1164\r
1165 return EFI_INVALID_PARAMETER;\r
1166}\r
1167\r
1168/**\r
1169\r
1170 This function programs the PCI Root Bridge hardware so that\r
1171 it decodes the specified PCI bus range.\r
1172\r
1173 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1174 @param RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed.\r
1175 @param Configuration The pointer to the PCI bus resource descriptor.\r
1176\r
1177 @retval EFI_SUCCESS Succeed.\r
1178 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.\r
1179\r
1180**/\r
1181EFI_STATUS\r
1182EFIAPI\r
1183SetBusNumbers (\r
1184 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1185 IN EFI_HANDLE RootBridgeHandle,\r
1186 IN VOID *Configuration\r
1187 )\r
1188{\r
1189 LIST_ENTRY *Link;\r
1190 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1191 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1192 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1193 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
4a50cf4e
RN
1194\r
1195 if (Configuration == NULL) {\r
1196 return EFI_INVALID_PARAMETER;\r
1197 }\r
1198\r
1199 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1200 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1201\r
1202 //\r
1203 // Check the Configuration is valid\r
1204 //\r
1205 if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||\r
1206 (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||\r
1207 (End->Desc != ACPI_END_TAG_DESCRIPTOR)\r
1208 ) {\r
1209 return EFI_INVALID_PARAMETER;\r
1210 }\r
1211\r
1212 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1213 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1214 ; !IsNull (&HostBridge->RootBridges, Link)\r
1215 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1216 ) {\r
1217 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1218 if (RootBridgeHandle == RootBridge->Handle) {\r
4a50cf4e
RN
1219\r
1220 if (Descriptor->AddrLen == 0) {\r
1221 return EFI_INVALID_PARAMETER;\r
1222 }\r
1223\r
1224 if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||\r
1225 (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)\r
1226 ) {\r
1227 return EFI_INVALID_PARAMETER;\r
1228 }\r
1229 //\r
1230 // Update the Bus Range\r
1231 //\r
1232 RootBridge->ResAllocNode[TypeBus].Base = Descriptor->AddrRangeMin;\r
1233 RootBridge->ResAllocNode[TypeBus].Length = Descriptor->AddrLen;\r
1234 RootBridge->ResAllocNode[TypeBus].Status = ResAllocated;\r
1235 return EFI_SUCCESS;\r
1236 }\r
1237 }\r
1238\r
1239 return EFI_INVALID_PARAMETER;\r
1240}\r
1241\r
1242/**\r
1243\r
1244 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.\r
1245\r
1246 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1247 @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements.\r
1248 are being submitted.\r
1249 @param Configuration The pointer to the PCI I/O and PCI memory resource descriptor.\r
1250\r
1251 @retval EFI_SUCCESS Succeed.\r
1252 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.\r
1253**/\r
1254EFI_STATUS\r
1255EFIAPI\r
1256SubmitResources (\r
1257 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1258 IN EFI_HANDLE RootBridgeHandle,\r
1259 IN VOID *Configuration\r
1260 )\r
1261{\r
1262 LIST_ENTRY *Link;\r
1263 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1264 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1265 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1266 PCI_RESOURCE_TYPE Type;\r
1267\r
1268 //\r
1269 // Check the input parameter: Configuration\r
1270 //\r
1271 if (Configuration == NULL) {\r
1272 return EFI_INVALID_PARAMETER;\r
1273 }\r
1274\r
1275 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1276 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1277 ; !IsNull (&HostBridge->RootBridges, Link)\r
1278 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1279 ) {\r
1280 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1281 if (RootBridgeHandle == RootBridge->Handle) {\r
1282 DEBUG ((EFI_D_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));\r
1283 //\r
1284 // Check the resource descriptors.\r
1285 // If the Configuration includes one or more invalid resource descriptors, all the resource\r
1286 // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.\r
1287 //\r
1288 for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
1289 if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1290 return EFI_INVALID_PARAMETER;\r
1291 }\r
1292\r
1293 DEBUG ((EFI_D_INFO, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",\r
1294 mAcpiAddressSpaceTypeStr[Descriptor->ResType], Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,\r
1295 (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""\r
1296 ));\r
1297 DEBUG ((EFI_D_INFO, " Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));\r
1298 switch (Descriptor->ResType) {\r
1299 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1300 if (Descriptor->AddrSpaceGranularity != 32 && Descriptor->AddrSpaceGranularity != 64) {\r
1301 return EFI_INVALID_PARAMETER;\r
1302 }\r
1303 if (Descriptor->AddrSpaceGranularity == 32 && Descriptor->AddrLen >= SIZE_4GB) {\r
1304 return EFI_INVALID_PARAMETER;\r
1305 }\r
1306 //\r
1307 // If the PCI root bridge does not support separate windows for nonprefetchable and\r
1308 // prefetchable memory, then the PCI bus driver needs to include requests for\r
1309 // prefetchable memory in the nonprefetchable memory pool.\r
1310 //\r
1311 if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&\r
1312 ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)\r
1313 ) {\r
1314 return EFI_INVALID_PARAMETER;\r
1315 }\r
1316 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1317 //\r
1318 // Check aligment, it should be of the form 2^n-1\r
1319 //\r
1320 if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {\r
1321 return EFI_INVALID_PARAMETER;\r
1322 }\r
1323 break;\r
1324 default:\r
1325 ASSERT (FALSE);\r
1326 break;\r
1327 }\r
1328 }\r
1329 if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1330 return EFI_INVALID_PARAMETER;\r
1331 }\r
1332\r
1333 for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
1334 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
1335 if (Descriptor->AddrSpaceGranularity == 32) {\r
1336 if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {\r
1337 Type = TypePMem32;\r
1338 } else {\r
1339 Type = TypeMem32;\r
1340 }\r
1341 } else {\r
1342 ASSERT (Descriptor->AddrSpaceGranularity == 64);\r
1343 if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {\r
1344 Type = TypePMem64;\r
1345 } else {\r
1346 Type = TypeMem64;\r
1347 }\r
1348 }\r
1349 } else {\r
1350 ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);\r
1351 Type = TypeIo;\r
1352 }\r
1353 RootBridge->ResAllocNode[Type].Length = Descriptor->AddrLen;\r
1354 RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;\r
1355 RootBridge->ResAllocNode[Type].Status = ResSubmitted;\r
1356 }\r
1357 RootBridge->ResourceSubmitted = TRUE;\r
1358 return EFI_SUCCESS;\r
1359 }\r
1360 }\r
1361\r
1362 return EFI_INVALID_PARAMETER;\r
1363}\r
1364\r
1365/**\r
1366\r
1367 This function returns the proposed resource settings for the specified\r
1368 PCI Root Bridge.\r
1369\r
1370 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1371 @param RootBridgeHandle The PCI Root Bridge handle.\r
1372 @param Configuration The pointer to the pointer to the PCI I/O\r
1373 and memory resource descriptor.\r
1374\r
1375 @retval EFI_SUCCESS Succeed.\r
1376 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.\r
1377 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1378\r
1379**/\r
1380EFI_STATUS\r
1381EFIAPI\r
1382GetProposedResources (\r
1383 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1384 IN EFI_HANDLE RootBridgeHandle,\r
1385 OUT VOID **Configuration\r
1386 )\r
1387{\r
1388 LIST_ENTRY *Link;\r
1389 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1390 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1391 UINTN Index;\r
1392 UINTN Number;\r
1393 VOID *Buffer;\r
1394 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1395 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1396 UINT64 ResStatus;\r
1397\r
1398 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1399 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1400 ; !IsNull (&HostBridge->RootBridges, Link)\r
1401 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1402 ) {\r
1403 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1404 if (RootBridgeHandle == RootBridge->Handle) {\r
1405 for (Index = 0, Number = 0; Index < TypeBus; Index++) {\r
1406 if (RootBridge->ResAllocNode[Index].Status != ResNone) {\r
1407 Number++;\r
1408 }\r
1409 }\r
1410\r
1411 Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1412 if (Buffer == NULL) {\r
1413 return EFI_OUT_OF_RESOURCES;\r
1414 }\r
1415\r
1416 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Buffer;\r
1417 for (Index = 0; Index < TypeBus; Index++) {\r
1418 ResStatus = RootBridge->ResAllocNode[Index].Status;\r
1419 if (ResStatus != ResNone) {\r
1420 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1421 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;\r
1422 Descriptor->GenFlag = 0;\r
1423 Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;\r
1424 Descriptor->AddrRangeMax = 0;\r
1425 Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;\r
1426 Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length;\r
1427\r
1428 switch (Index) {\r
1429\r
1430 case TypeIo:\r
1431 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
1432 break;\r
1433\r
1434 case TypePMem32:\r
1435 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1436 case TypeMem32:\r
1437 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1438 Descriptor->AddrSpaceGranularity = 32;\r
1439 break;\r
1440\r
1441 case TypePMem64:\r
1442 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1443 case TypeMem64:\r
1444 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1445 Descriptor->AddrSpaceGranularity = 64;\r
1446 break;\r
1447 }\r
1448\r
1449 Descriptor++;\r
1450 }\r
1451 }\r
1452 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
1453 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1454 End->Checksum = 0;\r
1455\r
1456 *Configuration = Buffer;\r
1457\r
1458 return EFI_SUCCESS;\r
1459 }\r
1460 }\r
1461\r
1462 return EFI_INVALID_PARAMETER;\r
1463}\r
1464\r
1465/**\r
1466\r
1467 This function is called for all the PCI controllers that the PCI\r
1468 bus driver finds. Can be used to Preprogram the controller.\r
1469\r
1470 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1471 @param RootBridgeHandle The PCI Root Bridge handle.\r
1472 @param PciAddress Address of the controller on the PCI bus.\r
1473 @param Phase The Phase during resource allocation.\r
1474\r
1475 @retval EFI_SUCCESS Succeed.\r
1476 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1477\r
1478**/\r
1479EFI_STATUS\r
1480EFIAPI\r
1481PreprocessController (\r
1482 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1483 IN EFI_HANDLE RootBridgeHandle,\r
1484 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,\r
1485 IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase\r
1486 )\r
1487{\r
1488 LIST_ENTRY *Link;\r
1489 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1490 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1491\r
1492 if ((UINT32) Phase > EfiPciBeforeResourceCollection) {\r
1493 return EFI_INVALID_PARAMETER;\r
1494 }\r
1495\r
1496 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1497 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1498 ; !IsNull (&HostBridge->RootBridges, Link)\r
1499 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1500 ) {\r
1501 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1502 if (RootBridgeHandle == RootBridge->Handle) {\r
1503 return EFI_SUCCESS;\r
1504 }\r
1505 }\r
1506\r
1507 return EFI_INVALID_PARAMETER;\r
1508}\r