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