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