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