]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
MdeModulePkg/PciHostBridge: Add IOMMU support.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciRootBridgeIo.c
CommitLineData
4a50cf4e
RN
1/** @file\r
2\r
3 PCI Root Bridge Io Protocol code.\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
c15da8eb
JY
20extern EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;\r
21\r
ccf66016 22#define NO_MAPPING (VOID *) (UINTN) -1\r
4a50cf4e
RN
23\r
24//\r
25// Lookup table for increment values based on transfer widths\r
26//\r
27UINT8 mInStride[] = {\r
28 1, // EfiPciWidthUint8\r
29 2, // EfiPciWidthUint16\r
30 4, // EfiPciWidthUint32\r
31 8, // EfiPciWidthUint64\r
32 0, // EfiPciWidthFifoUint8\r
33 0, // EfiPciWidthFifoUint16\r
34 0, // EfiPciWidthFifoUint32\r
35 0, // EfiPciWidthFifoUint64\r
36 1, // EfiPciWidthFillUint8\r
37 2, // EfiPciWidthFillUint16\r
38 4, // EfiPciWidthFillUint32\r
39 8 // EfiPciWidthFillUint64\r
40};\r
41\r
42//\r
43// Lookup table for increment values based on transfer widths\r
44//\r
45UINT8 mOutStride[] = {\r
46 1, // EfiPciWidthUint8\r
47 2, // EfiPciWidthUint16\r
48 4, // EfiPciWidthUint32\r
49 8, // EfiPciWidthUint64\r
50 1, // EfiPciWidthFifoUint8\r
51 2, // EfiPciWidthFifoUint16\r
52 4, // EfiPciWidthFifoUint32\r
53 8, // EfiPciWidthFifoUint64\r
54 0, // EfiPciWidthFillUint8\r
55 0, // EfiPciWidthFillUint16\r
56 0, // EfiPciWidthFillUint32\r
57 0 // EfiPciWidthFillUint64\r
58};\r
59\r
60/**\r
61 Construct the Pci Root Bridge instance.\r
62\r
63 @param Bridge The root bridge instance.\r
4a50cf4e
RN
64\r
65 @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created\r
66 or NULL if creation fails.\r
67**/\r
68PCI_ROOT_BRIDGE_INSTANCE *\r
69CreateRootBridge (\r
401f8cd1 70 IN PCI_ROOT_BRIDGE *Bridge\r
4a50cf4e
RN
71 )\r
72{\r
73 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
74 PCI_RESOURCE_TYPE Index;\r
75 CHAR16 *DevicePathStr;\r
401f8cd1 76 PCI_ROOT_BRIDGE_APERTURE *Aperture;\r
4a50cf4e
RN
77\r
78 DevicePathStr = NULL;\r
79\r
80 DEBUG ((EFI_D_INFO, "RootBridge: "));\r
81 DEBUG ((EFI_D_INFO, "%s\n", DevicePathStr = ConvertDevicePathToText (Bridge->DevicePath, FALSE, FALSE)));\r
3da82965
LE
82 DEBUG ((EFI_D_INFO, " Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes));\r
83 DEBUG ((EFI_D_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No"));\r
014b4720 84 DEBUG ((EFI_D_INFO, "NoExtConfSpace: %s\n", Bridge->NoExtendedConfigSpace ? L"Yes" : L"No"));\r
3da82965 85 DEBUG ((EFI_D_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes,\r
4a50cf4e
RN
86 (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"",\r
87 (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L""\r
88 ));\r
3da82965
LE
89 DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit));\r
90 DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit));\r
91 DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit));\r
92 DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit));\r
93 DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit));\r
94 DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit));\r
4a50cf4e
RN
95\r
96 //\r
97 // Make sure Mem and MemAbove4G apertures are valid\r
98 //\r
f9607bef 99 if (Bridge->Mem.Base <= Bridge->Mem.Limit) {\r
4a50cf4e
RN
100 ASSERT (Bridge->Mem.Limit < SIZE_4GB);\r
101 if (Bridge->Mem.Limit >= SIZE_4GB) {\r
102 return NULL;\r
103 }\r
104 }\r
f9607bef 105 if (Bridge->MemAbove4G.Base <= Bridge->MemAbove4G.Limit) {\r
4a50cf4e
RN
106 ASSERT (Bridge->MemAbove4G.Base >= SIZE_4GB);\r
107 if (Bridge->MemAbove4G.Base < SIZE_4GB) {\r
108 return NULL;\r
109 }\r
110 }\r
f9607bef 111 if (Bridge->PMem.Base <= Bridge->PMem.Limit) {\r
4a50cf4e
RN
112 ASSERT (Bridge->PMem.Limit < SIZE_4GB);\r
113 if (Bridge->PMem.Limit >= SIZE_4GB) {\r
114 return NULL;\r
115 }\r
116 }\r
f9607bef 117 if (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit) {\r
4a50cf4e
RN
118 ASSERT (Bridge->PMemAbove4G.Base >= SIZE_4GB);\r
119 if (Bridge->PMemAbove4G.Base < SIZE_4GB) {\r
120 return NULL;\r
121 }\r
122 }\r
123\r
401f8cd1
RN
124 //\r
125 // Ignore AllocationAttributes when resources were already assigned.\r
126 //\r
127 if (!Bridge->ResourceAssigned) {\r
128 if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {\r
129 //\r
130 // If this bit is set, then the PCI Root Bridge does not\r
131 // support separate windows for Non-prefetchable and Prefetchable\r
132 // memory.\r
133 //\r
134 ASSERT (Bridge->PMem.Base > Bridge->PMem.Limit);\r
135 ASSERT (Bridge->PMemAbove4G.Base > Bridge->PMemAbove4G.Limit);\r
136 if ((Bridge->PMem.Base <= Bridge->PMem.Limit) ||\r
137 (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit)\r
138 ) {\r
139 return NULL;\r
140 }\r
4a50cf4e 141 }\r
4a50cf4e 142\r
401f8cd1
RN
143 if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) {\r
144 //\r
145 // If this bit is not set, then the PCI Root Bridge does not support\r
146 // 64 bit memory windows.\r
147 //\r
148 ASSERT (Bridge->MemAbove4G.Base > Bridge->MemAbove4G.Limit);\r
149 ASSERT (Bridge->PMemAbove4G.Base > Bridge->PMemAbove4G.Limit);\r
150 if ((Bridge->MemAbove4G.Base <= Bridge->MemAbove4G.Limit) ||\r
151 (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit)\r
152 ) {\r
153 return NULL;\r
154 }\r
4a50cf4e
RN
155 }\r
156 }\r
157\r
158 RootBridge = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE));\r
159 ASSERT (RootBridge != NULL);\r
160\r
161 RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE;\r
162 RootBridge->Supports = Bridge->Supports;\r
163 RootBridge->Attributes = Bridge->Attributes;\r
164 RootBridge->DmaAbove4G = Bridge->DmaAbove4G;\r
014b4720 165 RootBridge->NoExtendedConfigSpace = Bridge->NoExtendedConfigSpace;\r
4a50cf4e
RN
166 RootBridge->AllocationAttributes = Bridge->AllocationAttributes;\r
167 RootBridge->DevicePath = DuplicateDevicePath (Bridge->DevicePath);\r
168 RootBridge->DevicePathStr = DevicePathStr;\r
169 RootBridge->ConfigBuffer = AllocatePool (\r
170 TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)\r
171 );\r
172 ASSERT (RootBridge->ConfigBuffer != NULL);\r
173 InitializeListHead (&RootBridge->Maps);\r
174\r
175 CopyMem (&RootBridge->Bus, &Bridge->Bus, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
176 CopyMem (&RootBridge->Io, &Bridge->Io, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
177 CopyMem (&RootBridge->Mem, &Bridge->Mem, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
178 CopyMem (&RootBridge->MemAbove4G, &Bridge->MemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
814f4306
RN
179 CopyMem (&RootBridge->PMem, &Bridge->PMem, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
180 CopyMem (&RootBridge->PMemAbove4G, &Bridge->PMemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
4a50cf4e
RN
181\r
182 for (Index = TypeIo; Index < TypeMax; Index++) {\r
401f8cd1
RN
183 switch (Index) {\r
184 case TypeBus:\r
185 Aperture = &RootBridge->Bus;\r
186 break;\r
187 case TypeIo:\r
188 Aperture = &RootBridge->Io;\r
189 break;\r
190 case TypeMem32:\r
191 Aperture = &RootBridge->Mem;\r
192 break;\r
193 case TypeMem64:\r
194 Aperture = &RootBridge->MemAbove4G;\r
195 break;\r
196 case TypePMem32:\r
197 Aperture = &RootBridge->PMem;\r
198 break;\r
199 case TypePMem64:\r
200 Aperture = &RootBridge->PMemAbove4G;\r
201 break;\r
202 default:\r
203 ASSERT (FALSE);\r
26bd6437 204 Aperture = NULL;\r
401f8cd1
RN
205 break;\r
206 }\r
207 RootBridge->ResAllocNode[Index].Type = Index;\r
208 if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) {\r
209 RootBridge->ResAllocNode[Index].Base = Aperture->Base;\r
210 RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1;\r
211 RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
212 } else {\r
213 RootBridge->ResAllocNode[Index].Base = 0;\r
214 RootBridge->ResAllocNode[Index].Length = 0;\r
215 RootBridge->ResAllocNode[Index].Status = ResNone;\r
216 }\r
4a50cf4e
RN
217 }\r
218\r
219 RootBridge->RootBridgeIo.SegmentNumber = Bridge->Segment;\r
4a50cf4e
RN
220 RootBridge->RootBridgeIo.PollMem = RootBridgeIoPollMem;\r
221 RootBridge->RootBridgeIo.PollIo = RootBridgeIoPollIo;\r
222 RootBridge->RootBridgeIo.Mem.Read = RootBridgeIoMemRead;\r
223 RootBridge->RootBridgeIo.Mem.Write = RootBridgeIoMemWrite;\r
224 RootBridge->RootBridgeIo.Io.Read = RootBridgeIoIoRead;\r
225 RootBridge->RootBridgeIo.Io.Write = RootBridgeIoIoWrite;\r
226 RootBridge->RootBridgeIo.CopyMem = RootBridgeIoCopyMem;\r
227 RootBridge->RootBridgeIo.Pci.Read = RootBridgeIoPciRead;\r
228 RootBridge->RootBridgeIo.Pci.Write = RootBridgeIoPciWrite;\r
229 RootBridge->RootBridgeIo.Map = RootBridgeIoMap;\r
230 RootBridge->RootBridgeIo.Unmap = RootBridgeIoUnmap;\r
231 RootBridge->RootBridgeIo.AllocateBuffer = RootBridgeIoAllocateBuffer;\r
232 RootBridge->RootBridgeIo.FreeBuffer = RootBridgeIoFreeBuffer;\r
233 RootBridge->RootBridgeIo.Flush = RootBridgeIoFlush;\r
234 RootBridge->RootBridgeIo.GetAttributes = RootBridgeIoGetAttributes;\r
235 RootBridge->RootBridgeIo.SetAttributes = RootBridgeIoSetAttributes;\r
236 RootBridge->RootBridgeIo.Configuration = RootBridgeIoConfiguration;\r
237\r
238 return RootBridge;\r
239}\r
240\r
241/**\r
242 Check parameters for IO,MMIO,PCI read/write services of PCI Root Bridge IO.\r
243\r
244 The I/O operations are carried out exactly as requested. The caller is\r
245 responsible for satisfying any alignment and I/O width restrictions that a PI\r
246 System on a platform might require. For example on some platforms, width\r
247 requests of EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other\r
248 hand, will be handled by the driver.\r
249\r
250 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
251\r
252 @param[in] OperationType I/O operation type: IO/MMIO/PCI.\r
253\r
254 @param[in] Width Signifies the width of the I/O or Memory operation.\r
255\r
256 @param[in] Address The base address of the I/O operation.\r
257\r
258 @param[in] Count The number of I/O operations to perform. The number\r
259 of bytes moved is Width size * Count, starting at\r
260 Address.\r
261\r
262 @param[in] Buffer For read operations, the destination buffer to\r
263 store the results. For write operations, the source\r
264 buffer from which to write data.\r
265\r
266 @retval EFI_SUCCESS The parameters for this request pass the\r
267 checks.\r
268\r
269 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.\r
270\r
271 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
272\r
273 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.\r
274\r
275 @retval EFI_UNSUPPORTED The address range specified by Address, Width,\r
276 and Count is not valid for this PI system.\r
277**/\r
278EFI_STATUS\r
279RootBridgeIoCheckParameter (\r
280 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
281 IN OPERATION_TYPE OperationType,\r
282 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
283 IN UINT64 Address,\r
284 IN UINTN Count,\r
285 IN VOID *Buffer\r
286 )\r
287{\r
288 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
289 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr;\r
290 UINT64 Base;\r
291 UINT64 Limit;\r
292 UINT32 Size;\r
293\r
294 //\r
295 // Check to see if Buffer is NULL\r
296 //\r
297 if (Buffer == NULL) {\r
298 return EFI_INVALID_PARAMETER;\r
299 }\r
300\r
301 //\r
302 // Check to see if Width is in the valid range\r
303 //\r
304 if ((UINT32) Width >= EfiPciWidthMaximum) {\r
305 return EFI_INVALID_PARAMETER;\r
306 }\r
307\r
308 //\r
309 // For FIFO type, the target address won't increase during the access,\r
310 // so treat Count as 1\r
311 //\r
312 if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
313 Count = 1;\r
314 }\r
315\r
316 Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
317 Size = 1 << Width;\r
318\r
319 //\r
320 // Check to see if Address is aligned\r
321 //\r
322 if ((Address & (Size - 1)) != 0) {\r
323 return EFI_UNSUPPORTED;\r
324 }\r
325\r
326 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
327\r
328 //\r
329 // Check to see if any address associated with this transfer exceeds the\r
330 // maximum allowed address. The maximum address implied by the parameters\r
331 // passed in is Address + Size * Count. If the following condition is met,\r
332 // then the transfer is not supported.\r
333 //\r
334 // Address + Size * Count > Limit + 1\r
335 //\r
336 // Since Limit can be the maximum integer value supported by the CPU and\r
337 // Count can also be the maximum integer value supported by the CPU, this\r
338 // range check must be adjusted to avoid all oveflow conditions.\r
339 //\r
340 if (OperationType == IoOperation) {\r
341 //\r
342 // Allow Legacy IO access\r
343 //\r
344 if (Address + MultU64x32 (Count, Size) <= 0x1000) {\r
345 if ((RootBridge->Attributes & (\r
346 EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE_VGA_IO |\r
347 EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |\r
348 EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_ATTRIBUTE_VGA_IO_16)) != 0) {\r
349 return EFI_SUCCESS;\r
350 }\r
351 }\r
352 Base = RootBridge->Io.Base;\r
353 Limit = RootBridge->Io.Limit;\r
354 } else if (OperationType == MemOperation) {\r
355 //\r
356 // Allow Legacy MMIO access\r
357 //\r
358 if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {\r
359 if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {\r
360 return EFI_SUCCESS;\r
361 }\r
362 }\r
363 //\r
364 // By comparing the Address against Limit we know which range to be used\r
365 // for checking\r
366 //\r
367 if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {\r
368 Base = RootBridge->Mem.Base;\r
369 Limit = RootBridge->Mem.Limit;\r
370 } else {\r
371 Base = RootBridge->MemAbove4G.Base;\r
372 Limit = RootBridge->MemAbove4G.Limit;\r
373 }\r
374 } else {\r
375 PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &Address;\r
376 if (PciRbAddr->Bus < RootBridge->Bus.Base ||\r
377 PciRbAddr->Bus > RootBridge->Bus.Limit) {\r
378 return EFI_INVALID_PARAMETER;\r
379 }\r
380\r
381 if (PciRbAddr->Device > PCI_MAX_DEVICE ||\r
382 PciRbAddr->Function > PCI_MAX_FUNC) {\r
383 return EFI_INVALID_PARAMETER;\r
384 }\r
385\r
386 if (PciRbAddr->ExtendedRegister != 0) {\r
387 Address = PciRbAddr->ExtendedRegister;\r
388 } else {\r
389 Address = PciRbAddr->Register;\r
390 }\r
391 Base = 0;\r
014b4720 392 Limit = RootBridge->NoExtendedConfigSpace ? 0xFF : 0xFFF;\r
4a50cf4e
RN
393 }\r
394\r
395 if (Address < Base) {\r
396 return EFI_INVALID_PARAMETER;\r
397 }\r
398\r
399 if (Address + MultU64x32 (Count, Size) > Limit + 1) {\r
400 return EFI_INVALID_PARAMETER;\r
401 }\r
402\r
403 return EFI_SUCCESS;\r
404}\r
405\r
406/**\r
407 Polls an address in memory mapped I/O space until an exit condition is met,\r
408 or a timeout occurs.\r
409\r
410 This function provides a standard way to poll a PCI memory location. A PCI\r
411 memory read operation is performed at the PCI memory address specified by\r
412 Address for the width specified by Width. The result of this PCI memory read\r
413 operation is stored in Result. This PCI memory read operation is repeated\r
414 until either a timeout of Delay 100 ns units has expired, or (Result & Mask)\r
415 is equal to Value.\r
416\r
417 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
418 @param[in] Width Signifies the width of the memory operations.\r
419 @param[in] Address The base address of the memory operations. The caller\r
420 is responsible for aligning Address if required.\r
421 @param[in] Mask Mask used for the polling criteria. Bytes above Width\r
422 in Mask are ignored. The bits in the bytes below Width\r
423 which are zero in Mask are ignored when polling the\r
424 memory address.\r
425 @param[in] Value The comparison value used for the polling exit\r
426 criteria.\r
427 @param[in] Delay The number of 100 ns units to poll. Note that timer\r
428 available may be of poorer granularity.\r
429 @param[out] Result Pointer to the last value read from the memory\r
430 location.\r
431\r
432 @retval EFI_SUCCESS The last data returned from the access matched\r
433 the poll exit criteria.\r
434 @retval EFI_INVALID_PARAMETER Width is invalid.\r
435 @retval EFI_INVALID_PARAMETER Result is NULL.\r
436 @retval EFI_TIMEOUT Delay expired before a match occurred.\r
437 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
438 lack of resources.\r
439**/\r
4a50cf4e
RN
440EFI_STATUS\r
441EFIAPI\r
442RootBridgeIoPollMem (\r
443 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
444 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
445 IN UINT64 Address,\r
446 IN UINT64 Mask,\r
447 IN UINT64 Value,\r
448 IN UINT64 Delay,\r
449 OUT UINT64 *Result\r
450 )\r
451{\r
452 EFI_STATUS Status;\r
453 UINT64 NumberOfTicks;\r
454 UINT32 Remainder;\r
455\r
456 if (Result == NULL) {\r
457 return EFI_INVALID_PARAMETER;\r
458 }\r
459\r
460 if ((UINT32)Width > EfiPciWidthUint64) {\r
461 return EFI_INVALID_PARAMETER;\r
462 }\r
463\r
464 //\r
465 // No matter what, always do a single poll.\r
466 //\r
467 Status = This->Mem.Read (This, Width, Address, 1, Result);\r
468 if (EFI_ERROR (Status)) {\r
469 return Status;\r
470 }\r
471\r
472 if ((*Result & Mask) == Value) {\r
473 return EFI_SUCCESS;\r
474 }\r
475\r
476 if (Delay == 0) {\r
477 return EFI_SUCCESS;\r
478\r
479 } else {\r
480\r
481 //\r
482 // Determine the proper # of metronome ticks to wait for polling the\r
483 // location. The nuber of ticks is Roundup (Delay /\r
484 // mMetronome->TickPeriod)+1\r
485 // The "+1" to account for the possibility of the first tick being short\r
486 // because we started in the middle of a tick.\r
487 //\r
488 // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome\r
489 // protocol definition is updated.\r
490 //\r
491 NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod,\r
492 &Remainder);\r
493 if (Remainder != 0) {\r
494 NumberOfTicks += 1;\r
495 }\r
496 NumberOfTicks += 1;\r
497\r
498 while (NumberOfTicks != 0) {\r
499\r
500 mMetronome->WaitForTick (mMetronome, 1);\r
501\r
502 Status = This->Mem.Read (This, Width, Address, 1, Result);\r
503 if (EFI_ERROR (Status)) {\r
504 return Status;\r
505 }\r
506\r
507 if ((*Result & Mask) == Value) {\r
508 return EFI_SUCCESS;\r
509 }\r
510\r
511 NumberOfTicks -= 1;\r
512 }\r
513 }\r
514 return EFI_TIMEOUT;\r
515}\r
516\r
517/**\r
518 Reads from the I/O space of a PCI Root Bridge. Returns when either the\r
519 polling exit criteria is satisfied or after a defined duration.\r
520\r
521 This function provides a standard way to poll a PCI I/O location. A PCI I/O\r
522 read operation is performed at the PCI I/O address specified by Address for\r
523 the width specified by Width.\r
524 The result of this PCI I/O read operation is stored in Result. This PCI I/O\r
525 read operation is repeated until either a timeout of Delay 100 ns units has\r
526 expired, or (Result & Mask) is equal to Value.\r
527\r
528 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
529 @param[in] Width Signifies the width of the I/O operations.\r
530 @param[in] Address The base address of the I/O operations. The caller is\r
531 responsible for aligning Address if required.\r
532 @param[in] Mask Mask used for the polling criteria. Bytes above Width in\r
533 Mask are ignored. The bits in the bytes below Width\r
534 which are zero in Mask are ignored when polling the I/O\r
535 address.\r
536 @param[in] Value The comparison value used for the polling exit criteria.\r
537 @param[in] Delay The number of 100 ns units to poll. Note that timer\r
538 available may be of poorer granularity.\r
539 @param[out] Result Pointer to the last value read from the memory location.\r
540\r
541 @retval EFI_SUCCESS The last data returned from the access matched\r
542 the poll exit criteria.\r
543 @retval EFI_INVALID_PARAMETER Width is invalid.\r
544 @retval EFI_INVALID_PARAMETER Result is NULL.\r
545 @retval EFI_TIMEOUT Delay expired before a match occurred.\r
546 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
547 lack of resources.\r
548**/\r
549EFI_STATUS\r
550EFIAPI\r
551RootBridgeIoPollIo (\r
552 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
553 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
554 IN UINT64 Address,\r
555 IN UINT64 Mask,\r
556 IN UINT64 Value,\r
557 IN UINT64 Delay,\r
558 OUT UINT64 *Result\r
559 )\r
560{\r
561 EFI_STATUS Status;\r
562 UINT64 NumberOfTicks;\r
563 UINT32 Remainder;\r
564\r
565 //\r
566 // No matter what, always do a single poll.\r
567 //\r
568\r
569 if (Result == NULL) {\r
570 return EFI_INVALID_PARAMETER;\r
571 }\r
572\r
573 if ((UINT32)Width > EfiPciWidthUint64) {\r
574 return EFI_INVALID_PARAMETER;\r
575 }\r
576\r
577 Status = This->Io.Read (This, Width, Address, 1, Result);\r
578 if (EFI_ERROR (Status)) {\r
579 return Status;\r
580 }\r
581 if ((*Result & Mask) == Value) {\r
582 return EFI_SUCCESS;\r
583 }\r
584\r
585 if (Delay == 0) {\r
586 return EFI_SUCCESS;\r
587\r
588 } else {\r
589\r
590 //\r
591 // Determine the proper # of metronome ticks to wait for polling the\r
592 // location. The number of ticks is Roundup (Delay /\r
593 // mMetronome->TickPeriod)+1\r
594 // The "+1" to account for the possibility of the first tick being short\r
595 // because we started in the middle of a tick.\r
596 //\r
597 NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod,\r
598 &Remainder);\r
599 if (Remainder != 0) {\r
600 NumberOfTicks += 1;\r
601 }\r
602 NumberOfTicks += 1;\r
603\r
604 while (NumberOfTicks != 0) {\r
605\r
606 mMetronome->WaitForTick (mMetronome, 1);\r
607\r
608 Status = This->Io.Read (This, Width, Address, 1, Result);\r
609 if (EFI_ERROR (Status)) {\r
610 return Status;\r
611 }\r
612\r
613 if ((*Result & Mask) == Value) {\r
614 return EFI_SUCCESS;\r
615 }\r
616\r
617 NumberOfTicks -= 1;\r
618 }\r
619 }\r
620 return EFI_TIMEOUT;\r
621}\r
622\r
623/**\r
624 Enables a PCI driver to access PCI controller registers in the PCI root\r
625 bridge memory space.\r
626\r
627 The Mem.Read(), and Mem.Write() functions enable a driver to access PCI\r
628 controller registers in the PCI root bridge memory space.\r
629 The memory operations are carried out exactly as requested. The caller is\r
630 responsible for satisfying any alignment and memory width restrictions that a\r
631 PCI Root Bridge on a platform might require.\r
632\r
633 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
634 @param[in] Width Signifies the width of the memory operation.\r
635 @param[in] Address The base address of the memory operation. The caller\r
636 is responsible for aligning the Address if required.\r
637 @param[in] Count The number of memory operations to perform. Bytes\r
638 moved is Width size * Count, starting at Address.\r
639 @param[out] Buffer For read operations, the destination buffer to store\r
640 the results. For write operations, the source buffer\r
641 to write data from.\r
642\r
643 @retval EFI_SUCCESS The data was read from or written to the PCI\r
644 root bridge.\r
645 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
646 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
647 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
648 lack of resources.\r
649**/\r
650EFI_STATUS\r
651EFIAPI\r
652RootBridgeIoMemRead (\r
653 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
654 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
655 IN UINT64 Address,\r
656 IN UINTN Count,\r
657 OUT VOID *Buffer\r
658 )\r
659{\r
660 EFI_STATUS Status;\r
661\r
662 Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,\r
663 Count, Buffer);\r
664 if (EFI_ERROR (Status)) {\r
665 return Status;\r
666 }\r
667 return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
668}\r
669\r
670/**\r
671 Enables a PCI driver to access PCI controller registers in the PCI root\r
672 bridge memory space.\r
673\r
674 The Mem.Read(), and Mem.Write() functions enable a driver to access PCI\r
675 controller registers in the PCI root bridge memory space.\r
676 The memory operations are carried out exactly as requested. The caller is\r
677 responsible for satisfying any alignment and memory width restrictions that a\r
678 PCI Root Bridge on a platform might require.\r
679\r
680 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
681 @param[in] Width Signifies the width of the memory operation.\r
682 @param[in] Address The base address of the memory operation. The caller\r
683 is responsible for aligning the Address if required.\r
684 @param[in] Count The number of memory operations to perform. Bytes\r
685 moved is Width size * Count, starting at Address.\r
686 @param[in] Buffer For read operations, the destination buffer to store\r
687 the results. For write operations, the source buffer\r
688 to write data from.\r
689\r
690 @retval EFI_SUCCESS The data was read from or written to the PCI\r
691 root bridge.\r
692 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
693 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
694 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
695 lack of resources.\r
696**/\r
697EFI_STATUS\r
698EFIAPI\r
699RootBridgeIoMemWrite (\r
700 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
701 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
702 IN UINT64 Address,\r
703 IN UINTN Count,\r
704 IN VOID *Buffer\r
705 )\r
706{\r
707 EFI_STATUS Status;\r
708\r
709 Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,\r
710 Count, Buffer);\r
711 if (EFI_ERROR (Status)) {\r
712 return Status;\r
713 }\r
714 return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
715}\r
716\r
717/**\r
718 Enables a PCI driver to access PCI controller registers in the PCI root\r
719 bridge I/O space.\r
720\r
721 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
722 @param[in] Width Signifies the width of the memory operations.\r
723 @param[in] Address The base address of the I/O operation. The caller is\r
724 responsible for aligning the Address if required.\r
725 @param[in] Count The number of I/O operations to perform. Bytes moved\r
726 is Width size * Count, starting at Address.\r
727 @param[out] Buffer For read operations, the destination buffer to store\r
728 the results. For write operations, the source buffer\r
729 to write data from.\r
730\r
731 @retval EFI_SUCCESS The data was read from or written to the PCI\r
732 root bridge.\r
733 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
734 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
735 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
736 lack of resources.\r
737**/\r
738EFI_STATUS\r
739EFIAPI\r
740RootBridgeIoIoRead (\r
741 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
742 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
743 IN UINT64 Address,\r
744 IN UINTN Count,\r
745 OUT VOID *Buffer\r
746 )\r
747{\r
748 EFI_STATUS Status;\r
749 Status = RootBridgeIoCheckParameter (\r
750 This, IoOperation, Width,\r
751 Address, Count, Buffer\r
752 );\r
753 if (EFI_ERROR (Status)) {\r
754 return Status;\r
755 }\r
756 return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
757}\r
758\r
759/**\r
760 Enables a PCI driver to access PCI controller registers in the PCI root\r
761 bridge I/O space.\r
762\r
763 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
764 @param[in] Width Signifies the width of the memory operations.\r
765 @param[in] Address The base address of the I/O operation. The caller is\r
766 responsible for aligning the Address if required.\r
767 @param[in] Count The number of I/O operations to perform. Bytes moved\r
768 is Width size * Count, starting at Address.\r
769 @param[in] Buffer For read operations, the destination buffer to store\r
770 the results. For write operations, the source buffer\r
771 to write data from.\r
772\r
773 @retval EFI_SUCCESS The data was read from or written to the PCI\r
774 root bridge.\r
775 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
776 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
777 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
778 lack of resources.\r
779**/\r
780EFI_STATUS\r
781EFIAPI\r
782RootBridgeIoIoWrite (\r
783 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
784 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
785 IN UINT64 Address,\r
786 IN UINTN Count,\r
787 IN VOID *Buffer\r
788 )\r
789{\r
790 EFI_STATUS Status;\r
791 Status = RootBridgeIoCheckParameter (\r
792 This, IoOperation, Width,\r
793 Address, Count, Buffer\r
794 );\r
795 if (EFI_ERROR (Status)) {\r
796 return Status;\r
797 }\r
798 return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
799}\r
800\r
801/**\r
802 Enables a PCI driver to copy one region of PCI root bridge memory space to\r
803 another region of PCI root bridge memory space.\r
804\r
805 The CopyMem() function enables a PCI driver to copy one region of PCI root\r
806 bridge memory space to another region of PCI root bridge memory space. This\r
807 is especially useful for video scroll operation on a memory mapped video\r
808 buffer.\r
809 The memory operations are carried out exactly as requested. The caller is\r
810 responsible for satisfying any alignment and memory width restrictions that a\r
811 PCI root bridge on a platform might require.\r
812\r
813 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL\r
814 instance.\r
815 @param[in] Width Signifies the width of the memory operations.\r
816 @param[in] DestAddress The destination address of the memory operation. The\r
817 caller is responsible for aligning the DestAddress if\r
818 required.\r
819 @param[in] SrcAddress The source address of the memory operation. The caller\r
820 is responsible for aligning the SrcAddress if\r
821 required.\r
822 @param[in] Count The number of memory operations to perform. Bytes\r
823 moved is Width size * Count, starting at DestAddress\r
824 and SrcAddress.\r
825\r
826 @retval EFI_SUCCESS The data was copied from one memory region\r
827 to another memory region.\r
828 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
829 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
830 lack of resources.\r
831**/\r
832EFI_STATUS\r
833EFIAPI\r
834RootBridgeIoCopyMem (\r
835 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
836 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
837 IN UINT64 DestAddress,\r
838 IN UINT64 SrcAddress,\r
839 IN UINTN Count\r
840 )\r
841{\r
842 EFI_STATUS Status;\r
843 BOOLEAN Forward;\r
844 UINTN Stride;\r
845 UINTN Index;\r
846 UINT64 Result;\r
847\r
848 if ((UINT32) Width > EfiPciWidthUint64) {\r
849 return EFI_INVALID_PARAMETER;\r
850 }\r
851\r
852 if (DestAddress == SrcAddress) {\r
853 return EFI_SUCCESS;\r
854 }\r
855\r
856 Stride = (UINTN) (1 << Width);\r
857\r
858 Forward = TRUE;\r
859 if ((DestAddress > SrcAddress) &&\r
860 (DestAddress < (SrcAddress + Count * Stride))) {\r
861 Forward = FALSE;\r
862 SrcAddress = SrcAddress + (Count - 1) * Stride;\r
863 DestAddress = DestAddress + (Count - 1) * Stride;\r
864 }\r
865\r
866 for (Index = 0; Index < Count; Index++) {\r
867 Status = RootBridgeIoMemRead (\r
868 This,\r
869 Width,\r
870 SrcAddress,\r
871 1,\r
872 &Result\r
873 );\r
874 if (EFI_ERROR (Status)) {\r
875 return Status;\r
876 }\r
877 Status = RootBridgeIoMemWrite (\r
878 This,\r
879 Width,\r
880 DestAddress,\r
881 1,\r
882 &Result\r
883 );\r
884 if (EFI_ERROR (Status)) {\r
885 return Status;\r
886 }\r
887 if (Forward) {\r
888 SrcAddress += Stride;\r
889 DestAddress += Stride;\r
890 } else {\r
891 SrcAddress -= Stride;\r
892 DestAddress -= Stride;\r
893 }\r
894 }\r
895 return EFI_SUCCESS;\r
896}\r
897\r
898\r
899/**\r
900 PCI configuration space access.\r
901\r
902 @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL\r
903 @param Read TRUE indicating it's a read operation.\r
904 @param Width Signifies the width of the memory operation.\r
905 @param Address The address within the PCI configuration space\r
906 for the PCI controller.\r
907 @param Count The number of PCI configuration operations\r
908 to perform.\r
909 @param Buffer The destination buffer to store the results.\r
910\r
911 @retval EFI_SUCCESS The data was read/written from/to the PCI root bridge.\r
912 @retval EFI_INVALID_PARAMETER Invalid parameters found.\r
913**/\r
914EFI_STATUS\r
915EFIAPI\r
916RootBridgeIoPciAccess (\r
917 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
918 IN BOOLEAN Read,\r
919 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
920 IN UINT64 Address,\r
921 IN UINTN Count,\r
922 IN OUT VOID *Buffer\r
923 )\r
924{\r
925 EFI_STATUS Status;\r
926 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
927 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;\r
928 UINT8 *Uint8Buffer;\r
929 UINT8 InStride;\r
930 UINT8 OutStride;\r
931 UINTN Size;\r
932\r
933 Status = RootBridgeIoCheckParameter (This, PciOperation, Width, Address, Count, Buffer);\r
934 if (EFI_ERROR (Status)) {\r
935 return Status;\r
936 }\r
937\r
938 //\r
939 // Read Pci configuration space\r
940 //\r
941 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
942 CopyMem (&PciAddress, &Address, sizeof (PciAddress));\r
943\r
944 if (PciAddress.ExtendedRegister == 0) {\r
945 PciAddress.ExtendedRegister = PciAddress.Register;\r
946 }\r
947\r
948 Address = PCI_SEGMENT_LIB_ADDRESS (\r
949 RootBridge->RootBridgeIo.SegmentNumber,\r
950 PciAddress.Bus,\r
951 PciAddress.Device,\r
952 PciAddress.Function,\r
953 PciAddress.ExtendedRegister\r
954 );\r
955\r
956 //\r
957 // Select loop based on the width of the transfer\r
958 //\r
959 InStride = mInStride[Width];\r
960 OutStride = mOutStride[Width];\r
961 Size = (UINTN) (1 << (Width & 0x03));\r
962 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
963 if (Read) {\r
964 PciSegmentReadBuffer (Address, Size, Uint8Buffer);\r
965 } else {\r
966 PciSegmentWriteBuffer (Address, Size, Uint8Buffer);\r
967 }\r
968 }\r
969 return EFI_SUCCESS;\r
970}\r
971\r
972/**\r
973 Allows read from PCI configuration space.\r
974\r
975 @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL\r
976 @param Width Signifies the width of the memory operation.\r
977 @param Address The address within the PCI configuration space\r
978 for the PCI controller.\r
979 @param Count The number of PCI configuration operations\r
980 to perform.\r
981 @param Buffer The destination buffer to store the results.\r
982\r
983 @retval EFI_SUCCESS The data was read from the PCI root bridge.\r
984 @retval EFI_INVALID_PARAMETER Invalid parameters found.\r
985**/\r
986EFI_STATUS\r
987EFIAPI\r
988RootBridgeIoPciRead (\r
989 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
990 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
991 IN UINT64 Address,\r
992 IN UINTN Count,\r
993 IN OUT VOID *Buffer\r
994 )\r
995{\r
996 return RootBridgeIoPciAccess (This, TRUE, Width, Address, Count, Buffer);\r
997}\r
998\r
999/**\r
1000 Allows write to PCI configuration space.\r
1001\r
1002 @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL\r
1003 @param Width Signifies the width of the memory operation.\r
1004 @param Address The address within the PCI configuration space\r
1005 for the PCI controller.\r
1006 @param Count The number of PCI configuration operations\r
1007 to perform.\r
1008 @param Buffer The source buffer to get the results.\r
1009\r
1010 @retval EFI_SUCCESS The data was written to the PCI root bridge.\r
1011 @retval EFI_INVALID_PARAMETER Invalid parameters found.\r
1012**/\r
1013EFI_STATUS\r
1014EFIAPI\r
1015RootBridgeIoPciWrite (\r
1016 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1017 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
1018 IN UINT64 Address,\r
1019 IN UINTN Count,\r
1020 IN OUT VOID *Buffer\r
1021 )\r
1022{\r
1023 return RootBridgeIoPciAccess (This, FALSE, Width, Address, Count, Buffer);\r
1024}\r
1025\r
1026/**\r
4a50cf4e
RN
1027 Provides the PCI controller-specific address needed to access\r
1028 system memory for DMA.\r
1029\r
1030 @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1031 @param Operation Indicate if the bus master is going to read or write\r
1032 to system memory.\r
1033 @param HostAddress The system memory address to map on the PCI controller.\r
1034 @param NumberOfBytes On input the number of bytes to map.\r
1035 On output the number of bytes that were mapped.\r
1036 @param DeviceAddress The resulting map address for the bus master PCI\r
1037 controller to use to access the system memory's HostAddress.\r
1038 @param Mapping The value to pass to Unmap() when the bus master DMA\r
1039 operation is complete.\r
1040\r
1041 @retval EFI_SUCCESS Success.\r
1042 @retval EFI_INVALID_PARAMETER Invalid parameters found.\r
1043 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
1044 @retval EFI_DEVICE_ERROR The System hardware could not map the requested address.\r
1045 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of resources.\r
4a50cf4e
RN
1046**/\r
1047EFI_STATUS\r
1048EFIAPI\r
1049RootBridgeIoMap (\r
1050 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1051 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,\r
1052 IN VOID *HostAddress,\r
1053 IN OUT UINTN *NumberOfBytes,\r
1054 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
1055 OUT VOID **Mapping\r
1056 )\r
1057{\r
1058 EFI_STATUS Status;\r
1059 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1060 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1061 MAP_INFO *MapInfo;\r
1062\r
1063 if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||\r
1064 Mapping == NULL) {\r
1065 return EFI_INVALID_PARAMETER;\r
1066 }\r
1067\r
1068 //\r
1069 // Make sure that Operation is valid\r
1070 //\r
1071 if ((UINT32) Operation >= EfiPciOperationMaximum) {\r
1072 return EFI_INVALID_PARAMETER;\r
1073 }\r
1074\r
1075 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
1076\r
c15da8eb
JY
1077 if (mIoMmuProtocol != NULL) {\r
1078 if (!RootBridge->DmaAbove4G) {\r
1079 //\r
1080 // Clear 64bit support\r
1081 //\r
1082 if (Operation > EfiPciOperationBusMasterCommonBuffer) {\r
1083 Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);\r
1084 }\r
1085 }\r
1086 Status = mIoMmuProtocol->Map (\r
1087 mIoMmuProtocol,\r
1088 Operation,\r
1089 HostAddress,\r
1090 NumberOfBytes,\r
1091 DeviceAddress,\r
1092 Mapping\r
1093 );\r
1094 return Status;\r
1095 }\r
1096\r
4a50cf4e 1097 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
e58a71d9
AB
1098 if ((!RootBridge->DmaAbove4G ||\r
1099 (Operation != EfiPciOperationBusMasterRead64 &&\r
1100 Operation != EfiPciOperationBusMasterWrite64 &&\r
1101 Operation != EfiPciOperationBusMasterCommonBuffer64)) &&\r
1102 ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
1103\r
4a50cf4e 1104 //\r
e58a71d9
AB
1105 // If the root bridge or the device cannot handle performing DMA above\r
1106 // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
4a50cf4e
RN
1107 // map the DMA transfer to a buffer below 4GB.\r
1108 //\r
1109\r
1110 if (Operation == EfiPciOperationBusMasterCommonBuffer ||\r
1111 Operation == EfiPciOperationBusMasterCommonBuffer64) {\r
1112 //\r
1113 // Common Buffer operations can not be remapped. If the common buffer\r
1114 // if above 4GB, then it is not possible to generate a mapping, so return\r
1115 // an error.\r
1116 //\r
1117 return EFI_UNSUPPORTED;\r
1118 }\r
1119\r
1120 //\r
1121 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
1122 // called later.\r
1123 //\r
1124 MapInfo = AllocatePool (sizeof (MAP_INFO));\r
1125 if (MapInfo == NULL) {\r
1126 *NumberOfBytes = 0;\r
1127 return EFI_OUT_OF_RESOURCES;\r
1128 }\r
1129\r
1130 //\r
1131 // Initialize the MAP_INFO structure\r
1132 //\r
1133 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
1134 MapInfo->Operation = Operation;\r
1135 MapInfo->NumberOfBytes = *NumberOfBytes;\r
1136 MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
1137 MapInfo->HostAddress = PhysicalAddress;\r
1138 MapInfo->MappedHostAddress = SIZE_4GB - 1;\r
1139\r
1140 //\r
1141 // Allocate a buffer below 4GB to map the transfer to.\r
1142 //\r
1143 Status = gBS->AllocatePages (\r
1144 AllocateMaxAddress,\r
1145 EfiBootServicesData,\r
1146 MapInfo->NumberOfPages,\r
1147 &MapInfo->MappedHostAddress\r
1148 );\r
1149 if (EFI_ERROR (Status)) {\r
1150 FreePool (MapInfo);\r
1151 *NumberOfBytes = 0;\r
1152 return Status;\r
1153 }\r
1154\r
1155 //\r
1156 // If this is a read operation from the Bus Master's point of view,\r
1157 // then copy the contents of the real buffer into the mapped buffer\r
1158 // so the Bus Master can read the contents of the real buffer.\r
1159 //\r
1160 if (Operation == EfiPciOperationBusMasterRead ||\r
1161 Operation == EfiPciOperationBusMasterRead64) {\r
1162 CopyMem (\r
1163 (VOID *) (UINTN) MapInfo->MappedHostAddress,\r
1164 (VOID *) (UINTN) MapInfo->HostAddress,\r
1165 MapInfo->NumberOfBytes\r
1166 );\r
1167 }\r
1168\r
1169 InsertTailList (&RootBridge->Maps, &MapInfo->Link);\r
1170\r
1171 //\r
1172 // The DeviceAddress is the address of the maped buffer below 4GB\r
1173 //\r
1174 *DeviceAddress = MapInfo->MappedHostAddress;\r
1175 //\r
1176 // Return a pointer to the MAP_INFO structure in Mapping\r
1177 //\r
1178 *Mapping = MapInfo;\r
1179 } else {\r
1180 //\r
1181 // If the root bridge CAN handle performing DMA above 4GB or\r
1182 // the transfer is below 4GB, so the DeviceAddress is simply the\r
1183 // HostAddress\r
1184 //\r
1185 *DeviceAddress = PhysicalAddress;\r
1186 *Mapping = NO_MAPPING;\r
1187 }\r
1188\r
1189 return EFI_SUCCESS;\r
1190}\r
1191\r
1192/**\r
1193 Completes the Map() operation and releases any corresponding resources.\r
1194\r
1195 The Unmap() function completes the Map() operation and releases any\r
1196 corresponding resources.\r
1197 If the operation was an EfiPciOperationBusMasterWrite or\r
1198 EfiPciOperationBusMasterWrite64, the data is committed to the target system\r
1199 memory.\r
1200 Any resources used for the mapping are freed.\r
1201\r
1202 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1203 @param[in] Mapping The mapping value returned from Map().\r
1204\r
1205 @retval EFI_SUCCESS The range was unmapped.\r
1206 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
1207 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
1208**/\r
1209EFI_STATUS\r
1210EFIAPI\r
1211RootBridgeIoUnmap (\r
1212 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1213 IN VOID *Mapping\r
1214 )\r
1215{\r
1216 MAP_INFO *MapInfo;\r
1217 LIST_ENTRY *Link;\r
1218 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
c15da8eb
JY
1219 EFI_STATUS Status;\r
1220\r
1221 if (mIoMmuProtocol != NULL) {\r
1222 Status = mIoMmuProtocol->Unmap (\r
1223 mIoMmuProtocol,\r
1224 Mapping\r
1225 );\r
1226 return Status;\r
1227 }\r
4a50cf4e
RN
1228\r
1229 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
c15da8eb 1230\r
4a50cf4e
RN
1231 //\r
1232 // See if the Map() operation associated with this Unmap() required a mapping\r
1233 // buffer. If a mapping buffer was not required, then this function simply\r
1234 // returns EFI_SUCCESS.\r
1235 //\r
1236 if (Mapping == NO_MAPPING) {\r
1237 return EFI_SUCCESS;\r
1238 }\r
1239\r
1240 MapInfo = NO_MAPPING;\r
1241 for (Link = GetFirstNode (&RootBridge->Maps)\r
1242 ; !IsNull (&RootBridge->Maps, Link)\r
1243 ; Link = GetNextNode (&RootBridge->Maps, Link)\r
1244 ) {\r
1245 MapInfo = MAP_INFO_FROM_LINK (Link);\r
1246 if (MapInfo == Mapping) {\r
1247 break;\r
1248 }\r
1249 }\r
1250 //\r
1251 // Mapping is not a valid value returned by Map()\r
1252 //\r
1253 if (MapInfo != Mapping) {\r
1254 return EFI_INVALID_PARAMETER;\r
1255 }\r
1256 RemoveEntryList (&MapInfo->Link);\r
1257\r
1258 //\r
1259 // If this is a write operation from the Bus Master's point of view,\r
1260 // then copy the contents of the mapped buffer into the real buffer\r
1261 // so the processor can read the contents of the real buffer.\r
1262 //\r
1263 if (MapInfo->Operation == EfiPciOperationBusMasterWrite ||\r
1264 MapInfo->Operation == EfiPciOperationBusMasterWrite64) {\r
1265 CopyMem (\r
1266 (VOID *) (UINTN) MapInfo->HostAddress,\r
1267 (VOID *) (UINTN) MapInfo->MappedHostAddress,\r
1268 MapInfo->NumberOfBytes\r
1269 );\r
1270 }\r
1271\r
1272 //\r
1273 // Free the mapped buffer and the MAP_INFO structure.\r
1274 //\r
1275 gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages);\r
1276 FreePool (Mapping);\r
1277 return EFI_SUCCESS;\r
1278}\r
1279\r
1280/**\r
1281 Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer\r
1282 or EfiPciOperationBusMasterCommonBuffer64 mapping.\r
1283\r
1284 @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1285 @param Type This parameter is not used and must be ignored.\r
1286 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
1287 EfiRuntimeServicesData.\r
1288 @param Pages The number of pages to allocate.\r
1289 @param HostAddress A pointer to store the base system memory address of the\r
1290 allocated range.\r
1291 @param Attributes The requested bit mask of attributes for the allocated\r
1292 range. Only the attributes\r
1293 EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,\r
1294 EFI_PCI_ATTRIBUTE_MEMORY_CACHED, and\r
1295 EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this\r
1296 function.\r
1297\r
1298 @retval EFI_SUCCESS The requested memory pages were allocated.\r
1299 @retval EFI_INVALID_PARAMETER MemoryType is invalid.\r
1300 @retval EFI_INVALID_PARAMETER HostAddress is NULL.\r
1301 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal\r
1302 attribute bits are MEMORY_WRITE_COMBINE,\r
1303 MEMORY_CACHED, and DUAL_ADDRESS_CYCLE.\r
1304 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
1305**/\r
1306EFI_STATUS\r
1307EFIAPI\r
1308RootBridgeIoAllocateBuffer (\r
1309 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1310 IN EFI_ALLOCATE_TYPE Type,\r
1311 IN EFI_MEMORY_TYPE MemoryType,\r
1312 IN UINTN Pages,\r
1313 OUT VOID **HostAddress,\r
1314 IN UINT64 Attributes\r
1315 )\r
1316{\r
1317 EFI_STATUS Status;\r
1318 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1319 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1320 EFI_ALLOCATE_TYPE AllocateType;\r
1321\r
1322 //\r
1323 // Validate Attributes\r
1324 //\r
1325 if ((Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {\r
1326 return EFI_UNSUPPORTED;\r
1327 }\r
1328\r
1329 //\r
1330 // Check for invalid inputs\r
1331 //\r
1332 if (HostAddress == NULL) {\r
1333 return EFI_INVALID_PARAMETER;\r
1334 }\r
1335\r
1336 //\r
1337 // The only valid memory types are EfiBootServicesData and\r
1338 // EfiRuntimeServicesData\r
1339 //\r
1340 if (MemoryType != EfiBootServicesData &&\r
1341 MemoryType != EfiRuntimeServicesData) {\r
1342 return EFI_INVALID_PARAMETER;\r
1343 }\r
1344\r
1345 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
1346\r
c15da8eb
JY
1347 if (mIoMmuProtocol != NULL) {\r
1348 if (!RootBridge->DmaAbove4G) {\r
1349 //\r
1350 // Clear DUAL_ADDRESS_CYCLE\r
1351 //\r
1352 Attributes &= ~EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
1353 }\r
1354 Status = mIoMmuProtocol->AllocateBuffer (\r
1355 mIoMmuProtocol,\r
1356 Type,\r
1357 MemoryType,\r
1358 Pages,\r
1359 HostAddress,\r
1360 Attributes\r
1361 );\r
1362 return Status;\r
1363 }\r
1364\r
4a50cf4e 1365 AllocateType = AllocateAnyPages;\r
e58a71d9
AB
1366 if (!RootBridge->DmaAbove4G ||\r
1367 (Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
4a50cf4e
RN
1368 //\r
1369 // Limit allocations to memory below 4GB\r
1370 //\r
1371 AllocateType = AllocateMaxAddress;\r
1372 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1);\r
1373 }\r
1374 Status = gBS->AllocatePages (\r
1375 AllocateType,\r
1376 MemoryType,\r
1377 Pages,\r
1378 &PhysicalAddress\r
1379 );\r
1380 if (!EFI_ERROR (Status)) {\r
1381 *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
1382 }\r
1383\r
1384 return Status;\r
1385}\r
1386\r
1387/**\r
1388 Frees memory that was allocated with AllocateBuffer().\r
1389\r
1390 The FreeBuffer() function frees memory that was allocated with\r
1391 AllocateBuffer().\r
1392\r
1393 @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1394 @param Pages The number of pages to free.\r
1395 @param HostAddress The base system memory address of the allocated range.\r
1396\r
1397 @retval EFI_SUCCESS The requested memory pages were freed.\r
1398 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and\r
1399 Pages was not allocated with AllocateBuffer().\r
1400**/\r
1401EFI_STATUS\r
1402EFIAPI\r
1403RootBridgeIoFreeBuffer (\r
1404 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1405 IN UINTN Pages,\r
1406 OUT VOID *HostAddress\r
1407 )\r
1408{\r
c15da8eb
JY
1409 EFI_STATUS Status;\r
1410\r
1411 if (mIoMmuProtocol != NULL) {\r
1412 Status = mIoMmuProtocol->FreeBuffer (\r
1413 mIoMmuProtocol,\r
1414 Pages,\r
1415 HostAddress\r
1416 );\r
1417 return Status;\r
1418 }\r
1419\r
4a50cf4e
RN
1420 return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\r
1421}\r
1422\r
1423/**\r
1424 Flushes all PCI posted write transactions from a PCI host bridge to system\r
1425 memory.\r
1426\r
1427 The Flush() function flushes any PCI posted write transactions from a PCI\r
1428 host bridge to system memory. Posted write transactions are generated by PCI\r
1429 bus masters when they perform write transactions to target addresses in\r
1430 system memory.\r
1431 This function does not flush posted write transactions from any PCI bridges.\r
1432 A PCI controller specific action must be taken to guarantee that the posted\r
1433 write transactions have been flushed from the PCI controller and from all the\r
1434 PCI bridges into the PCI host bridge. This is typically done with a PCI read\r
1435 transaction from the PCI controller prior to calling Flush().\r
1436\r
1437 @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1438\r
1439 @retval EFI_SUCCESS The PCI posted write transactions were flushed\r
1440 from the PCI host bridge to system memory.\r
1441 @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed\r
1442 from the PCI host bridge due to a hardware error.\r
1443**/\r
1444EFI_STATUS\r
1445EFIAPI\r
1446RootBridgeIoFlush (\r
1447 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This\r
1448 )\r
1449{\r
1450 return EFI_SUCCESS;\r
1451}\r
1452\r
1453/**\r
1454 Gets the attributes that a PCI root bridge supports setting with\r
1455 SetAttributes(), and the attributes that a PCI root bridge is currently\r
1456 using.\r
1457\r
1458 The GetAttributes() function returns the mask of attributes that this PCI\r
1459 root bridge supports and the mask of attributes that the PCI root bridge is\r
1460 currently using.\r
1461\r
1462 @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1463 @param Supported A pointer to the mask of attributes that this PCI root\r
1464 bridge supports setting with SetAttributes().\r
1465 @param Attributes A pointer to the mask of attributes that this PCI root\r
1466 bridge is currently using.\r
1467\r
1468 @retval EFI_SUCCESS If Supports is not NULL, then the attributes\r
1469 that the PCI root bridge supports is returned\r
1470 in Supports. If Attributes is not NULL, then\r
1471 the attributes that the PCI root bridge is\r
1472 currently using is returned in Attributes.\r
1473 @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.\r
1474**/\r
1475EFI_STATUS\r
1476EFIAPI\r
1477RootBridgeIoGetAttributes (\r
1478 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1479 OUT UINT64 *Supported,\r
1480 OUT UINT64 *Attributes\r
1481 )\r
1482{\r
1483 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1484\r
1485 if (Attributes == NULL && Supported == NULL) {\r
1486 return EFI_INVALID_PARAMETER;\r
1487 }\r
1488\r
1489 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
1490 //\r
1491 // Set the return value for Supported and Attributes\r
1492 //\r
1493 if (Supported != NULL) {\r
1494 *Supported = RootBridge->Supports;\r
1495 }\r
1496\r
1497 if (Attributes != NULL) {\r
1498 *Attributes = RootBridge->Attributes;\r
1499 }\r
1500\r
1501 return EFI_SUCCESS;\r
1502}\r
1503\r
1504/**\r
1505 Sets attributes for a resource range on a PCI root bridge.\r
1506\r
1507 The SetAttributes() function sets the attributes specified in Attributes for\r
1508 the PCI root bridge on the resource range specified by ResourceBase and\r
1509 ResourceLength. Since the granularity of setting these attributes may vary\r
1510 from resource type to resource type, and from platform to platform, the\r
1511 actual resource range and the one passed in by the caller may differ. As a\r
1512 result, this function may set the attributes specified by Attributes on a\r
1513 larger resource range than the caller requested. The actual range is returned\r
1514 in ResourceBase and ResourceLength. The caller is responsible for verifying\r
1515 that the actual range for which the attributes were set is acceptable.\r
1516\r
1517 @param This A pointer to the\r
1518 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1519 @param Attributes The mask of attributes to set. If the\r
1520 attribute bit MEMORY_WRITE_COMBINE,\r
1521 MEMORY_CACHED, or MEMORY_DISABLE is set,\r
1522 then the resource range is specified by\r
1523 ResourceBase and ResourceLength. If\r
1524 MEMORY_WRITE_COMBINE, MEMORY_CACHED, and\r
1525 MEMORY_DISABLE are not set, then\r
1526 ResourceBase and ResourceLength are ignored,\r
1527 and may be NULL.\r
1528 @param ResourceBase A pointer to the base address of the\r
1529 resource range to be modified by the\r
1530 attributes specified by Attributes.\r
1531 @param ResourceLength A pointer to the length of the resource\r
1532 range to be modified by the attributes\r
1533 specified by Attributes.\r
1534\r
1535 @retval EFI_SUCCESS The current configuration of this PCI root bridge\r
1536 was returned in Resources.\r
1537 @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge\r
1538 could not be retrieved.\r
1539**/\r
1540EFI_STATUS\r
1541EFIAPI\r
1542RootBridgeIoSetAttributes (\r
1543 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1544 IN UINT64 Attributes,\r
1545 IN OUT UINT64 *ResourceBase,\r
1546 IN OUT UINT64 *ResourceLength\r
1547 )\r
1548{\r
1549 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1550\r
1551 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
1552\r
1553 if ((Attributes & (~RootBridge->Supports)) != 0) {\r
1554 return EFI_UNSUPPORTED;\r
1555 }\r
1556\r
1557 RootBridge->Attributes = Attributes;\r
1558 return EFI_SUCCESS;\r
1559}\r
1560\r
1561/**\r
1562 Retrieves the current resource settings of this PCI root bridge in the form\r
1563 of a set of ACPI 2.0 resource descriptors.\r
1564\r
1565 There are only two resource descriptor types from the ACPI Specification that\r
1566 may be used to describe the current resources allocated to a PCI root bridge.\r
1567 These are the QWORD Address Space Descriptor (ACPI 2.0 Section 6.4.3.5.1),\r
1568 and the End Tag (ACPI 2.0 Section 6.4.2.8). The QWORD Address Space\r
1569 Descriptor can describe memory, I/O, and bus number ranges for dynamic or\r
1570 fixed resources. The configuration of a PCI root bridge is described with one\r
1571 or more QWORD Address Space Descriptors followed by an End Tag.\r
1572\r
1573 @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1574 @param[out] Resources A pointer to the ACPI 2.0 resource descriptors that\r
1575 describe the current configuration of this PCI root\r
1576 bridge. The storage for the ACPI 2.0 resource\r
1577 descriptors is allocated by this function. The\r
1578 caller must treat the return buffer as read-only\r
1579 data, and the buffer must not be freed by the\r
1580 caller.\r
1581\r
1582 @retval EFI_SUCCESS The current configuration of this PCI root bridge\r
1583 was returned in Resources.\r
1584 @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge\r
1585 could not be retrieved.\r
1586**/\r
1587EFI_STATUS\r
1588EFIAPI\r
1589RootBridgeIoConfiguration (\r
1590 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
1591 OUT VOID **Resources\r
1592 )\r
1593{\r
1594 PCI_RESOURCE_TYPE Index;\r
1595 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1596 PCI_RES_NODE *ResAllocNode;\r
1597 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1598 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1599\r
1600 //\r
1601 // Get this instance of the Root Bridge.\r
1602 //\r
1603 RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
1604 ZeroMem (\r
1605 RootBridge->ConfigBuffer,\r
1606 TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)\r
1607 );\r
1608 Descriptor = RootBridge->ConfigBuffer;\r
1609 for (Index = TypeIo; Index < TypeMax; Index++) {\r
1610\r
1611 ResAllocNode = &RootBridge->ResAllocNode[Index];\r
1612\r
1613 if (ResAllocNode->Status != ResAllocated) {\r
1614 continue;\r
1615 }\r
1616\r
1617 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1618 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
1619 Descriptor->AddrRangeMin = ResAllocNode->Base;\r
1620 Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;\r
1621 Descriptor->AddrLen = ResAllocNode->Length;\r
1622 switch (ResAllocNode->Type) {\r
1623\r
1624 case TypeIo:\r
1625 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
1626 break;\r
1627\r
1628 case TypePMem32:\r
1629 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1630 case TypeMem32:\r
1631 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1632 Descriptor->AddrSpaceGranularity = 32;\r
1633 break;\r
1634\r
1635 case TypePMem64:\r
1636 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1637 case TypeMem64:\r
1638 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1639 Descriptor->AddrSpaceGranularity = 64;\r
1640 break;\r
1641\r
1642 case TypeBus:\r
1643 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
1644 break;\r
1645\r
1646 default:\r
1647 break;\r
1648 }\r
1649\r
1650 Descriptor++;\r
1651 }\r
1652 //\r
1653 // Terminate the entries.\r
1654 //\r
1655 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;\r
1656 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1657 End->Checksum = 0x0;\r
1658\r
1659 *Resources = RootBridge->ConfigBuffer;\r
1660 return EFI_SUCCESS;\r
1661}\r