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