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