]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
MdePkg/PciExpress21.h: Fix typo in PCI_REG_PCIE_SLOT_CONTROL
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NonDiscoverablePciDeviceDxe / NonDiscoverablePciDeviceIo.c
CommitLineData
a42e6d44
AB
1/** @file\r
2\r
3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
4 Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>\r
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "NonDiscoverablePciDeviceIo.h"\r
17\r
16296a12
AB
18#include <Library/DxeServicesTableLib.h>\r
19\r
a42e6d44
AB
20#include <IndustryStandard/Acpi.h>\r
21\r
22#include <Protocol/PciRootBridgeIo.h>\r
23\r
24typedef struct {\r
25 EFI_PHYSICAL_ADDRESS AllocAddress;\r
26 VOID *HostAddress;\r
27 EFI_PCI_IO_PROTOCOL_OPERATION Operation;\r
28 UINTN NumberOfBytes;\r
29} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;\r
30\r
43b7cd61
DB
31/**\r
32 Get the resource associated with BAR number 'BarIndex'.\r
33\r
34 @param Dev Point to the NON_DISCOVERABLE_PCI_DEVICE instance.\r
35 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
36 base address for the memory operation to perform.\r
37 @param Descriptor Points to the address space descriptor\r
38**/\r
a42e6d44
AB
39STATIC\r
40EFI_STATUS\r
41GetBarResource (\r
42 IN NON_DISCOVERABLE_PCI_DEVICE *Dev,\r
43 IN UINT8 BarIndex,\r
44 OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptor\r
45 )\r
46{\r
47 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
48\r
49 if (BarIndex < Dev->BarOffset) {\r
50 return EFI_NOT_FOUND;\r
51 }\r
52\r
8b78de74 53 BarIndex -= (UINT8)Dev->BarOffset;\r
a42e6d44
AB
54\r
55 for (Desc = Dev->Device->Resources;\r
56 Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
57 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
58\r
59 if (BarIndex == 0) {\r
60 *Descriptor = Desc;\r
61 return EFI_SUCCESS;\r
62 }\r
63\r
64 BarIndex -= 1;\r
65 }\r
66 return EFI_NOT_FOUND;\r
67}\r
68\r
43b7cd61
DB
69/**\r
70 Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is\r
71 satisfied or after a defined duration.\r
72\r
73 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
74 @param Width Signifies the width of the memory or I/O operations.\r
75 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
76 base address for the memory operation to perform.\r
77 @param Offset The offset within the selected BAR to start the memory operation.\r
78 @param Mask Mask used for the polling criteria.\r
79 @param Value The comparison value used for the polling exit criteria.\r
80 @param Delay The number of 100 ns units to poll.\r
81 @param Result Pointer to the last value read from the memory location.\r
82\r
83**/\r
a42e6d44
AB
84STATIC\r
85EFI_STATUS\r
8b78de74 86EFIAPI\r
a42e6d44
AB
87PciIoPollMem (\r
88 IN EFI_PCI_IO_PROTOCOL *This,\r
89 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
90 IN UINT8 BarIndex,\r
91 IN UINT64 Offset,\r
92 IN UINT64 Mask,\r
93 IN UINT64 Value,\r
94 IN UINT64 Delay,\r
95 OUT UINT64 *Result\r
96 )\r
97{\r
98 ASSERT (FALSE);\r
99 return EFI_UNSUPPORTED;\r
100}\r
101\r
43b7cd61
DB
102/**\r
103 Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is\r
104 satisfied or after a defined duration.\r
105\r
106 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
107 @param Width Signifies the width of the memory or I/O operations.\r
108 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
109 base address for the memory operation to perform.\r
110 @param Offset The offset within the selected BAR to start the memory operation.\r
111 @param Mask Mask used for the polling criteria.\r
112 @param Value The comparison value used for the polling exit criteria.\r
113 @param Delay The number of 100 ns units to poll.\r
114 @param Result Pointer to the last value read from the memory location.\r
115\r
116**/\r
a42e6d44
AB
117STATIC\r
118EFI_STATUS\r
8b78de74 119EFIAPI\r
a42e6d44
AB
120PciIoPollIo (\r
121 IN EFI_PCI_IO_PROTOCOL *This,\r
122 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
123 IN UINT8 BarIndex,\r
124 IN UINT64 Offset,\r
125 IN UINT64 Mask,\r
126 IN UINT64 Value,\r
127 IN UINT64 Delay,\r
128 OUT UINT64 *Result\r
129 )\r
130{\r
131 ASSERT (FALSE);\r
132 return EFI_UNSUPPORTED;\r
133}\r
134\r
43b7cd61
DB
135/**\r
136 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
137\r
138 @param Width Signifies the width of the memory or I/O operations.\r
139 @param Count The number of memory or I/O operations to perform.\r
140 @param DstStride The stride of the destination buffer.\r
141 @param Dst For read operations, the destination buffer to store the results. For write\r
142 operations, the destination buffer to write data to.\r
143 @param SrcStride The stride of the source buffer.\r
144 @param Src For read operations, the source buffer to read data from. For write\r
145 operations, the source buffer to write data from.\r
146\r
147 @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
148 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
149\r
150**/\r
a42e6d44
AB
151STATIC\r
152EFI_STATUS\r
8b78de74 153EFIAPI\r
a42e6d44
AB
154PciIoMemRW (\r
155 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
156 IN UINTN Count,\r
157 IN UINTN DstStride,\r
158 IN VOID *Dst,\r
159 IN UINTN SrcStride,\r
160 OUT CONST VOID *Src\r
161 )\r
162{\r
163 volatile UINT8 *Dst8;\r
164 volatile UINT16 *Dst16;\r
165 volatile UINT32 *Dst32;\r
166 volatile CONST UINT8 *Src8;\r
167 volatile CONST UINT16 *Src16;\r
168 volatile CONST UINT32 *Src32;\r
169\r
170 //\r
171 // Loop for each iteration and move the data\r
172 //\r
173 switch (Width & 0x3) {\r
174 case EfiPciWidthUint8:\r
175 Dst8 = (UINT8 *)Dst;\r
176 Src8 = (UINT8 *)Src;\r
177 for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {\r
178 *Dst8 = *Src8;\r
179 }\r
180 break;\r
181 case EfiPciWidthUint16:\r
182 Dst16 = (UINT16 *)Dst;\r
183 Src16 = (UINT16 *)Src;\r
184 for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {\r
185 *Dst16 = *Src16;\r
186 }\r
187 break;\r
188 case EfiPciWidthUint32:\r
189 Dst32 = (UINT32 *)Dst;\r
190 Src32 = (UINT32 *)Src;\r
191 for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {\r
192 *Dst32 = *Src32;\r
193 }\r
194 break;\r
195 default:\r
196 return EFI_INVALID_PARAMETER;\r
197 }\r
198\r
199 return EFI_SUCCESS;\r
200}\r
201\r
43b7cd61
DB
202/**\r
203 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
204\r
205 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
206 @param Width Signifies the width of the memory or I/O operations.\r
207 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
208 base address for the memory or I/O operation to perform.\r
209 @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
210 @param Count The number of memory or I/O operations to perform.\r
211 @param Buffer For read operations, the destination buffer to store the results. For write\r
212 operations, the source buffer to write data from.\r
213\r
214 @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
215 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
216 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not\r
217 valid for the PCI BAR specified by BarIndex.\r
218 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
219 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
220\r
221**/\r
a42e6d44
AB
222STATIC\r
223EFI_STATUS\r
8b78de74 224EFIAPI\r
a42e6d44
AB
225PciIoMemRead (\r
226 IN EFI_PCI_IO_PROTOCOL *This,\r
227 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
228 IN UINT8 BarIndex,\r
229 IN UINT64 Offset,\r
230 IN UINTN Count,\r
231 IN OUT VOID *Buffer\r
232 )\r
233{\r
234 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
235 UINTN AlignMask;\r
236 VOID *Address;\r
237 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
238 EFI_STATUS Status;\r
239\r
240 if (Buffer == NULL) {\r
241 return EFI_INVALID_PARAMETER;\r
242 }\r
243\r
244 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
245\r
246 //\r
247 // Only allow accesses to the BARs we emulate\r
248 //\r
249 Status = GetBarResource (Dev, BarIndex, &Desc);\r
250 if (EFI_ERROR (Status)) {\r
251 return Status;\r
252 }\r
253\r
254 if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
255 return EFI_UNSUPPORTED;\r
256 }\r
257\r
258 Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
259 AlignMask = (1 << (Width & 0x03)) - 1;\r
260 if ((UINTN)Address & AlignMask) {\r
261 return EFI_INVALID_PARAMETER;\r
262 }\r
263\r
264 switch (Width) {\r
82bf462e
HW
265 case EfiPciIoWidthUint8:\r
266 case EfiPciIoWidthUint16:\r
267 case EfiPciIoWidthUint32:\r
268 case EfiPciIoWidthUint64:\r
a42e6d44
AB
269 return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
270\r
82bf462e
HW
271 case EfiPciIoWidthFifoUint8:\r
272 case EfiPciIoWidthFifoUint16:\r
273 case EfiPciIoWidthFifoUint32:\r
274 case EfiPciIoWidthFifoUint64:\r
a42e6d44
AB
275 return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);\r
276\r
82bf462e
HW
277 case EfiPciIoWidthFillUint8:\r
278 case EfiPciIoWidthFillUint16:\r
279 case EfiPciIoWidthFillUint32:\r
280 case EfiPciIoWidthFillUint64:\r
a42e6d44
AB
281 return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);\r
282\r
283 default:\r
284 break;\r
285 }\r
286 return EFI_INVALID_PARAMETER;\r
287}\r
288\r
43b7cd61
DB
289/**\r
290 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
291\r
292 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
293 @param Width Signifies the width of the memory or I/O operations.\r
294 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
295 base address for the memory or I/O operation to perform.\r
296 @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
297 @param Count The number of memory or I/O operations to perform.\r
298 @param Buffer For read operations, the destination buffer to store the results. For write\r
299 operations, the source buffer to write data from.\r
300\r
301 @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
302 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
303 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not\r
304 valid for the PCI BAR specified by BarIndex.\r
305 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
306 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
307\r
308**/\r
a42e6d44
AB
309STATIC\r
310EFI_STATUS\r
8b78de74 311EFIAPI\r
a42e6d44
AB
312PciIoMemWrite (\r
313 IN EFI_PCI_IO_PROTOCOL *This,\r
314 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
315 IN UINT8 BarIndex,\r
316 IN UINT64 Offset,\r
317 IN UINTN Count,\r
318 IN OUT VOID *Buffer\r
319 )\r
320{\r
321 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
322 UINTN AlignMask;\r
323 VOID *Address;\r
324 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
325 EFI_STATUS Status;\r
326\r
327 if (Buffer == NULL) {\r
328 return EFI_INVALID_PARAMETER;\r
329 }\r
330\r
331 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
332\r
333 //\r
334 // Only allow accesses to the BARs we emulate\r
335 //\r
336 Status = GetBarResource (Dev, BarIndex, &Desc);\r
337 if (EFI_ERROR (Status)) {\r
338 return Status;\r
339 }\r
340\r
341 if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
342 return EFI_UNSUPPORTED;\r
343 }\r
344\r
345 Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
346 AlignMask = (1 << (Width & 0x03)) - 1;\r
347 if ((UINTN)Address & AlignMask) {\r
348 return EFI_INVALID_PARAMETER;\r
349 }\r
350\r
351 switch (Width) {\r
82bf462e
HW
352 case EfiPciIoWidthUint8:\r
353 case EfiPciIoWidthUint16:\r
354 case EfiPciIoWidthUint32:\r
355 case EfiPciIoWidthUint64:\r
a42e6d44
AB
356 return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
357\r
82bf462e
HW
358 case EfiPciIoWidthFifoUint8:\r
359 case EfiPciIoWidthFifoUint16:\r
360 case EfiPciIoWidthFifoUint32:\r
361 case EfiPciIoWidthFifoUint64:\r
a42e6d44
AB
362 return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);\r
363\r
82bf462e
HW
364 case EfiPciIoWidthFillUint8:\r
365 case EfiPciIoWidthFillUint16:\r
366 case EfiPciIoWidthFillUint32:\r
367 case EfiPciIoWidthFillUint64:\r
a42e6d44
AB
368 return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);\r
369\r
370 default:\r
371 break;\r
372 }\r
373 return EFI_INVALID_PARAMETER;\r
374}\r
375\r
43b7cd61
DB
376/**\r
377 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
378\r
379 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
380 @param Width Signifies the width of the memory or I/O operations.\r
381 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
382 base address for the memory or I/O operation to perform.\r
383 @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
384 @param Count The number of memory or I/O operations to perform.\r
385 @param Buffer For read operations, the destination buffer to store the results. For write\r
386 operations, the source buffer to write data from.\r
387\r
388**/\r
a42e6d44
AB
389STATIC\r
390EFI_STATUS\r
8b78de74 391EFIAPI\r
a42e6d44
AB
392PciIoIoRead (\r
393 IN EFI_PCI_IO_PROTOCOL *This,\r
394 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
395 IN UINT8 BarIndex,\r
396 IN UINT64 Offset,\r
397 IN UINTN Count,\r
398 IN OUT VOID *Buffer\r
399 )\r
400{\r
401 ASSERT (FALSE);\r
402 return EFI_UNSUPPORTED;\r
403}\r
404\r
43b7cd61
DB
405/**\r
406 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
407\r
408 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
409 @param Width Signifies the width of the memory or I/O operations.\r
410 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
411 base address for the memory or I/O operation to perform.\r
412 @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
413 @param Count The number of memory or I/O operations to perform.\r
414 @param Buffer For read operations, the destination buffer to store the results. For write\r
415 operations, the source buffer to write data from.\r
416\r
417**/\r
a42e6d44
AB
418STATIC\r
419EFI_STATUS\r
8b78de74 420EFIAPI\r
a42e6d44
AB
421PciIoIoWrite (\r
422 IN EFI_PCI_IO_PROTOCOL *This,\r
423 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
424 IN UINT8 BarIndex,\r
425 IN UINT64 Offset,\r
426 IN UINTN Count,\r
427 IN OUT VOID *Buffer\r
428 )\r
429{\r
430 ASSERT (FALSE);\r
431 return EFI_UNSUPPORTED;\r
432}\r
433\r
43b7cd61
DB
434/**\r
435 Enable a PCI driver to access PCI config space.\r
436\r
437 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
438 @param Width Signifies the width of the memory or I/O operations.\r
439 @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
440 @param Count The number of memory or I/O operations to perform.\r
441 @param Buffer For read operations, the destination buffer to store the results. For write\r
442 operations, the source buffer to write data from.\r
443\r
444**/\r
a42e6d44
AB
445STATIC\r
446EFI_STATUS\r
8b78de74 447EFIAPI\r
a42e6d44
AB
448PciIoPciRead (\r
449 IN EFI_PCI_IO_PROTOCOL *This,\r
450 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
451 IN UINT32 Offset,\r
452 IN UINTN Count,\r
453 IN OUT VOID *Buffer\r
454 )\r
455{\r
456 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
457 VOID *Address;\r
458 UINTN Length;\r
459\r
460 if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
461 return EFI_INVALID_PARAMETER;\r
462 }\r
463\r
464 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
465 Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
466 Length = Count << ((UINTN)Width & 0x3);\r
467\r
468 if (Offset + Length > sizeof (Dev->ConfigSpace)) {\r
469 //\r
470 // Read all zeroes for config space accesses beyond the first\r
471 // 64 bytes\r
472 //\r
473 Length -= sizeof (Dev->ConfigSpace) - Offset;\r
474 ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);\r
475\r
476 Count -= Length >> ((UINTN)Width & 0x3);\r
477 }\r
478 return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
479}\r
480\r
43b7cd61
DB
481/**\r
482 Enable a PCI driver to access PCI config space.\r
483\r
484 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
485 @param Width Signifies the width of the memory or I/O operations.\r
486 @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
487 @param Count The number of memory or I/O operations to perform.\r
488 @param Buffer For read operations, the destination buffer to store the results. For write\r
489 operations, the source buffer to write data from\r
490\r
491 @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
492 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not\r
493 valid for the PCI BAR specified by BarIndex.\r
494 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
495\r
496**/\r
a42e6d44
AB
497STATIC\r
498EFI_STATUS\r
8b78de74 499EFIAPI\r
a42e6d44
AB
500PciIoPciWrite (\r
501 IN EFI_PCI_IO_PROTOCOL *This,\r
502 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
503 IN UINT32 Offset,\r
504 IN UINTN Count,\r
505 IN OUT VOID *Buffer\r
506 )\r
507{\r
508 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
509 VOID *Address;\r
510\r
511 if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
512 return EFI_INVALID_PARAMETER;\r
513 }\r
514\r
515 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
516 Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
517\r
518 if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {\r
519 return EFI_UNSUPPORTED;\r
520 }\r
521\r
522 return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
523}\r
524\r
43b7cd61
DB
525/**\r
526 Enables a PCI driver to copy one region of PCI memory space to another region of PCI\r
527 memory space.\r
528\r
529 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
530 @param Width Signifies the width of the memory operations.\r
531 @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the\r
532 base address for the memory operation to perform.\r
533 @param DestOffset The destination offset within the BAR specified by DestBarIndex to\r
534 start the memory writes for the copy operation.\r
535 @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the\r
536 base address for the memory operation to perform.\r
537 @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start\r
538 the memory reads for the copy operation.\r
539 @param Count The number of memory operations to perform. Bytes moved is Width\r
540 size * Count, starting at DestOffset and SrcOffset.\r
541\r
542**/\r
a42e6d44
AB
543STATIC\r
544EFI_STATUS\r
8b78de74 545EFIAPI\r
a42e6d44
AB
546PciIoCopyMem (\r
547 IN EFI_PCI_IO_PROTOCOL *This,\r
548 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
549 IN UINT8 DestBarIndex,\r
550 IN UINT64 DestOffset,\r
551 IN UINT8 SrcBarIndex,\r
552 IN UINT64 SrcOffset,\r
553 IN UINTN Count\r
554 )\r
555{\r
556 ASSERT (FALSE);\r
557 return EFI_UNSUPPORTED;\r
558}\r
559\r
43b7cd61
DB
560/**\r
561 Provides the PCI controller-specific addresses needed to access system memory.\r
562\r
563 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
564 @param Operation Indicates if the bus master is going to read or write to system memory.\r
565 @param HostAddress The system memory address to map to the PCI controller.\r
566 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
567 that were mapped.\r
568 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
569 access the hosts HostAddress.\r
570 @param Mapping A resulting value to pass to Unmap().\r
571\r
572 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
573 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
574 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
575 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
576 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
577\r
578**/\r
a42e6d44
AB
579STATIC\r
580EFI_STATUS\r
8b78de74 581EFIAPI\r
a42e6d44
AB
582CoherentPciIoMap (\r
583 IN EFI_PCI_IO_PROTOCOL *This,\r
584 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
585 IN VOID *HostAddress,\r
586 IN OUT UINTN *NumberOfBytes,\r
587 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
588 OUT VOID **Mapping\r
589 )\r
590{\r
591 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
592 EFI_STATUS Status;\r
593 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
594\r
595 //\r
596 // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA\r
597 // addressing, we need to allocate a bounce buffer and copy over the data.\r
598 //\r
599 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
600 if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
b494cf96 601 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {\r
a42e6d44
AB
602\r
603 //\r
604 // Bounce buffering is not possible for consistent mappings\r
605 //\r
606 if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
607 return EFI_UNSUPPORTED;\r
608 }\r
609\r
610 MapInfo = AllocatePool (sizeof *MapInfo);\r
611 if (MapInfo == NULL) {\r
612 return EFI_OUT_OF_RESOURCES;\r
613 }\r
614\r
615 MapInfo->AllocAddress = MAX_UINT32;\r
616 MapInfo->HostAddress = HostAddress;\r
617 MapInfo->Operation = Operation;\r
618 MapInfo->NumberOfBytes = *NumberOfBytes;\r
619\r
620 Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,\r
621 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
622 &MapInfo->AllocAddress);\r
623 if (EFI_ERROR (Status)) {\r
624 //\r
625 // If we fail here, it is likely because the system has no memory below\r
626 // 4 GB to begin with. There is not much we can do about that other than\r
627 // fail the map request.\r
628 //\r
629 FreePool (MapInfo);\r
630 return EFI_DEVICE_ERROR;\r
631 }\r
632 if (Operation == EfiPciIoOperationBusMasterRead) {\r
633 gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,\r
634 *NumberOfBytes);\r
635 }\r
636 *DeviceAddress = MapInfo->AllocAddress;\r
637 *Mapping = MapInfo;\r
638 } else {\r
639 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
640 *Mapping = NULL;\r
641 }\r
642 return EFI_SUCCESS;\r
643}\r
644\r
43b7cd61
DB
645/**\r
646 Completes the Map() operation and releases any corresponding resources.\r
647\r
648 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
649 @param Mapping The mapping value returned from Map().\r
650\r
651 @retval EFI_SUCCESS The range was unmapped.\r
652\r
653**/\r
a42e6d44
AB
654STATIC\r
655EFI_STATUS\r
8b78de74 656EFIAPI\r
a42e6d44
AB
657CoherentPciIoUnmap (\r
658 IN EFI_PCI_IO_PROTOCOL *This,\r
659 IN VOID *Mapping\r
660 )\r
661{\r
662 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
663\r
664 MapInfo = Mapping;\r
665 if (MapInfo != NULL) {\r
666 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
667 gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
668 MapInfo->NumberOfBytes);\r
669 }\r
670 gBS->FreePages (MapInfo->AllocAddress,\r
671 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));\r
672 FreePool (MapInfo);\r
673 }\r
674 return EFI_SUCCESS;\r
675}\r
676\r
43b7cd61
DB
677/**\r
678 Allocates pages.\r
679\r
680 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
681 @param Type This parameter is not used and must be ignored.\r
682 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
683 EfiRuntimeServicesData.\r
684 @param Pages The number of pages to allocate.\r
685 @param HostAddress A pointer to store the base system memory address of the\r
686 allocated range.\r
687 @param Attributes The requested bit mask of attributes for the allocated range.\r
688\r
689 @retval EFI_SUCCESS The requested memory pages were allocated.\r
690 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
691 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
692 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
693 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
694\r
695**/\r
a42e6d44
AB
696STATIC\r
697EFI_STATUS\r
8b78de74 698EFIAPI\r
a42e6d44
AB
699CoherentPciIoAllocateBuffer (\r
700 IN EFI_PCI_IO_PROTOCOL *This,\r
701 IN EFI_ALLOCATE_TYPE Type,\r
702 IN EFI_MEMORY_TYPE MemoryType,\r
703 IN UINTN Pages,\r
704 OUT VOID **HostAddress,\r
705 IN UINT64 Attributes\r
706 )\r
707{\r
708 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
709 EFI_PHYSICAL_ADDRESS AllocAddress;\r
710 EFI_ALLOCATE_TYPE AllocType;\r
711 EFI_STATUS Status;\r
712\r
713 if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
714 EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {\r
715 return EFI_UNSUPPORTED;\r
716 }\r
717\r
718 //\r
719 // Allocate below 4 GB if the dual address cycle attribute has not\r
720 // been set. If the system has no memory available below 4 GB, there\r
721 // is little we can do except propagate the error.\r
722 //\r
723 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
724 if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
725 AllocAddress = MAX_UINT32;\r
726 AllocType = AllocateMaxAddress;\r
727 } else {\r
728 AllocType = AllocateAnyPages;\r
729 }\r
730\r
731 Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);\r
732 if (!EFI_ERROR (Status)) {\r
733 *HostAddress = (VOID *)(UINTN)AllocAddress;\r
734 }\r
735 return Status;\r
736}\r
737\r
43b7cd61
DB
738/**\r
739 Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().\r
740\r
741 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
742 @param Pages The number of pages to free.\r
743 @param HostAddress The base system memory address of the allocated range.\r
744\r
745 @retval EFI_SUCCESS The requested memory pages were freed.\r
746\r
747**/\r
a42e6d44
AB
748STATIC\r
749EFI_STATUS\r
8b78de74 750EFIAPI\r
a42e6d44
AB
751CoherentPciIoFreeBuffer (\r
752 IN EFI_PCI_IO_PROTOCOL *This,\r
753 IN UINTN Pages,\r
754 IN VOID *HostAddress\r
755 )\r
756{\r
757 FreePages (HostAddress, Pages);\r
758 return EFI_SUCCESS;\r
759}\r
760\r
43b7cd61
DB
761/**\r
762 Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().\r
763\r
764 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
765 @param Pages The number of pages to free.\r
766 @param HostAddress The base system memory address of the allocated range.\r
767\r
768 @retval EFI_SUCCESS The requested memory pages were freed.\r
769 @retval others The operation contain some errors.\r
770\r
771**/\r
16296a12
AB
772STATIC\r
773EFI_STATUS\r
774EFIAPI\r
775NonCoherentPciIoFreeBuffer (\r
776 IN EFI_PCI_IO_PROTOCOL *This,\r
777 IN UINTN Pages,\r
778 IN VOID *HostAddress\r
779 )\r
780{\r
781 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
782 LIST_ENTRY *Entry;\r
783 EFI_STATUS Status;\r
784 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
785 BOOLEAN Found;\r
786\r
787 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
788\r
789 Found = FALSE;\r
1525ff38 790 Alloc = NULL;\r
16296a12
AB
791\r
792 //\r
793 // Find the uncached allocation list entry associated\r
794 // with this allocation\r
795 //\r
796 for (Entry = Dev->UncachedAllocationList.ForwardLink;\r
797 Entry != &Dev->UncachedAllocationList;\r
798 Entry = Entry->ForwardLink) {\r
799\r
800 Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);\r
801 if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {\r
802 //\r
803 // We are freeing the exact allocation we were given\r
804 // before by AllocateBuffer()\r
805 //\r
806 Found = TRUE;\r
807 break;\r
808 }\r
809 }\r
810\r
811 if (!Found) {\r
812 ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
813 return EFI_NOT_FOUND;\r
814 }\r
815\r
816 RemoveEntryList (&Alloc->List);\r
817\r
818 Status = gDS->SetMemorySpaceAttributes (\r
819 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
820 EFI_PAGES_TO_SIZE (Pages),\r
821 Alloc->Attributes);\r
822 if (EFI_ERROR (Status)) {\r
823 goto FreeAlloc;\r
824 }\r
825\r
826 //\r
827 // If we fail to restore the original attributes, it is better to leak the\r
828 // memory than to return it to the heap\r
829 //\r
830 FreePages (HostAddress, Pages);\r
831\r
832FreeAlloc:\r
833 FreePool (Alloc);\r
834 return Status;\r
835}\r
836\r
43b7cd61
DB
837/**\r
838 Allocates pages.\r
839\r
840 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
841 @param Type This parameter is not used and must be ignored.\r
842 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
843 EfiRuntimeServicesData.\r
844 @param Pages The number of pages to allocate.\r
845 @param HostAddress A pointer to store the base system memory address of the\r
846 allocated range.\r
847 @param Attributes The requested bit mask of attributes for the allocated range.\r
848\r
849 @retval EFI_SUCCESS The requested memory pages were allocated.\r
850 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
851 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
852 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
853 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
854\r
855**/\r
16296a12
AB
856STATIC\r
857EFI_STATUS\r
858EFIAPI\r
859NonCoherentPciIoAllocateBuffer (\r
860 IN EFI_PCI_IO_PROTOCOL *This,\r
861 IN EFI_ALLOCATE_TYPE Type,\r
862 IN EFI_MEMORY_TYPE MemoryType,\r
863 IN UINTN Pages,\r
864 OUT VOID **HostAddress,\r
865 IN UINT64 Attributes\r
866 )\r
867{\r
868 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
869 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
870 EFI_STATUS Status;\r
871 UINT64 MemType;\r
872 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
873 VOID *AllocAddress;\r
874\r
875 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
876\r
877 Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,\r
878 &AllocAddress, Attributes);\r
879 if (EFI_ERROR (Status)) {\r
880 return Status;\r
881 }\r
882\r
883 Status = gDS->GetMemorySpaceDescriptor (\r
884 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
885 &GcdDescriptor);\r
886 if (EFI_ERROR (Status)) {\r
887 goto FreeBuffer;\r
888 }\r
889\r
890 if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {\r
891 Status = EFI_UNSUPPORTED;\r
892 goto FreeBuffer;\r
893 }\r
894\r
895 //\r
896 // Set the preferred memory attributes\r
897 //\r
898 if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||\r
899 (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {\r
900 //\r
901 // Use write combining if it was requested, or if it is the only\r
902 // type supported by the region.\r
903 //\r
904 MemType = EFI_MEMORY_WC;\r
905 } else {\r
906 MemType = EFI_MEMORY_UC;\r
907 }\r
908\r
909 Alloc = AllocatePool (sizeof *Alloc);\r
910 if (Alloc == NULL) {\r
911 goto FreeBuffer;\r
912 }\r
913\r
914 Alloc->HostAddress = AllocAddress;\r
915 Alloc->NumPages = Pages;\r
916 Alloc->Attributes = GcdDescriptor.Attributes;\r
917\r
918 //\r
919 // Record this allocation in the linked list, so we\r
920 // can restore the memory space attributes later\r
921 //\r
922 InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);\r
923\r
924 Status = gDS->SetMemorySpaceAttributes (\r
925 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
926 EFI_PAGES_TO_SIZE (Pages),\r
927 MemType);\r
928 if (EFI_ERROR (Status)) {\r
929 goto RemoveList;\r
930 }\r
931\r
932 Status = mCpu->FlushDataCache (\r
933 mCpu,\r
934 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
935 EFI_PAGES_TO_SIZE (Pages),\r
936 EfiCpuFlushTypeInvalidate);\r
937 if (EFI_ERROR (Status)) {\r
938 goto RemoveList;\r
939 }\r
940\r
941 *HostAddress = AllocAddress;\r
942\r
943 return EFI_SUCCESS;\r
944\r
945RemoveList:\r
946 RemoveEntryList (&Alloc->List);\r
947 FreePool (Alloc);\r
948\r
949FreeBuffer:\r
950 CoherentPciIoFreeBuffer (This, Pages, AllocAddress);\r
951 return Status;\r
952}\r
953\r
43b7cd61
DB
954/**\r
955 Provides the PCI controller-specific addresses needed to access system memory.\r
956\r
957 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
958 @param Operation Indicates if the bus master is going to read or write to system memory.\r
959 @param HostAddress The system memory address to map to the PCI controller.\r
960 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
961 that were mapped.\r
962 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
963 access the hosts HostAddress.\r
964 @param Mapping A resulting value to pass to Unmap().\r
965\r
966 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
967 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
968 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
969 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
970 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
971\r
972**/\r
16296a12
AB
973STATIC\r
974EFI_STATUS\r
975EFIAPI\r
976NonCoherentPciIoMap (\r
977 IN EFI_PCI_IO_PROTOCOL *This,\r
978 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
979 IN VOID *HostAddress,\r
980 IN OUT UINTN *NumberOfBytes,\r
981 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
982 OUT VOID **Mapping\r
983 )\r
984{\r
985 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
986 EFI_STATUS Status;\r
987 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
988 UINTN AlignMask;\r
989 VOID *AllocAddress;\r
990 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
991 BOOLEAN Bounce;\r
992\r
993 MapInfo = AllocatePool (sizeof *MapInfo);\r
994 if (MapInfo == NULL) {\r
995 return EFI_OUT_OF_RESOURCES;\r
996 }\r
997\r
998 MapInfo->HostAddress = HostAddress;\r
999 MapInfo->Operation = Operation;\r
1000 MapInfo->NumberOfBytes = *NumberOfBytes;\r
1001\r
1002 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1003\r
1004 //\r
1005 // If this device does not support 64-bit DMA addressing, we need to allocate\r
1006 // a bounce buffer and copy over the data in case HostAddress >= 4 GB.\r
1007 //\r
1008 Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
b494cf96 1009 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);\r
16296a12
AB
1010\r
1011 if (!Bounce) {\r
1012 switch (Operation) {\r
1013 case EfiPciIoOperationBusMasterRead:\r
1014 case EfiPciIoOperationBusMasterWrite:\r
1015 //\r
1016 // For streaming DMA, it is sufficient if the buffer is aligned to\r
1017 // the CPUs DMA buffer alignment.\r
1018 //\r
1019 AlignMask = mCpu->DmaBufferAlignment - 1;\r
1020 if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {\r
1021 break;\r
1022 }\r
1023 // fall through\r
1024\r
1025 case EfiPciIoOperationBusMasterCommonBuffer:\r
1026 //\r
1027 // Check whether the host address refers to an uncached mapping.\r
1028 //\r
1029 Status = gDS->GetMemorySpaceDescriptor (\r
1030 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
1031 &GcdDescriptor);\r
1032 if (EFI_ERROR (Status) ||\r
1033 (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {\r
1034 Bounce = TRUE;\r
1035 }\r
1036 break;\r
1037\r
1038 default:\r
1039 ASSERT (FALSE);\r
1040 }\r
1041 }\r
1042\r
1043 if (Bounce) {\r
1044 if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
1045 Status = EFI_DEVICE_ERROR;\r
1046 goto FreeMapInfo;\r
1047 }\r
1048\r
1049 Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,\r
1050 EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
1051 &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);\r
1052 if (EFI_ERROR (Status)) {\r
1053 goto FreeMapInfo;\r
1054 }\r
1055 MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;\r
1056 if (Operation == EfiPciIoOperationBusMasterRead) {\r
1057 gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);\r
1058 }\r
1059 *DeviceAddress = MapInfo->AllocAddress;\r
1060 } else {\r
1061 MapInfo->AllocAddress = 0;\r
1062 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
1063\r
1064 //\r
1065 // We are not using a bounce buffer: the mapping is sufficiently\r
1066 // aligned to allow us to simply flush the caches. Note that cleaning\r
1067 // the caches is necessary for both data directions:\r
1068 // - for bus master read, we want the latest data to be present\r
1069 // in main memory\r
1070 // - for bus master write, we don't want any stale dirty cachelines that\r
1071 // may be written back unexpectedly, and clobber the data written to\r
1072 // main memory by the device.\r
1073 //\r
1074 mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
1075 *NumberOfBytes, EfiCpuFlushTypeWriteBack);\r
1076 }\r
1077\r
1078 *Mapping = MapInfo;\r
1079 return EFI_SUCCESS;\r
1080\r
1081FreeMapInfo:\r
1082 FreePool (MapInfo);\r
1083\r
1084 return Status;\r
1085}\r
1086\r
43b7cd61
DB
1087/**\r
1088 Completes the Map() operation and releases any corresponding resources.\r
1089\r
1090 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1091 @param Mapping The mapping value returned from Map().\r
1092\r
1093 @retval EFI_SUCCESS The range was unmapped.\r
1094\r
1095**/\r
16296a12
AB
1096STATIC\r
1097EFI_STATUS\r
1098EFIAPI\r
1099NonCoherentPciIoUnmap (\r
1100 IN EFI_PCI_IO_PROTOCOL *This,\r
1101 IN VOID *Mapping\r
1102 )\r
1103{\r
1104 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
1105\r
1106 if (Mapping == NULL) {\r
1107 return EFI_DEVICE_ERROR;\r
1108 }\r
1109\r
1110 MapInfo = Mapping;\r
1111 if (MapInfo->AllocAddress != 0) {\r
1112 //\r
1113 // We are using a bounce buffer: copy back the data if necessary,\r
1114 // and free the buffer.\r
1115 //\r
1116 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
1117 gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
1118 MapInfo->NumberOfBytes);\r
1119 }\r
1120 NonCoherentPciIoFreeBuffer (This,\r
1121 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
1122 (VOID *)(UINTN)MapInfo->AllocAddress);\r
1123 } else {\r
1124 //\r
1125 // We are *not* using a bounce buffer: if this is a bus master write,\r
1126 // we have to invalidate the caches so the CPU will see the uncached\r
1127 // data written by the device.\r
1128 //\r
1129 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
1130 mCpu->FlushDataCache (mCpu,\r
1131 (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,\r
1132 MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
1133 }\r
1134 }\r
1135 FreePool (MapInfo);\r
1136 return EFI_SUCCESS;\r
1137}\r
a42e6d44 1138\r
43b7cd61
DB
1139/**\r
1140 Flushes all PCI posted write transactions from a PCI host bridge to system memory.\r
1141\r
1142 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1143\r
1144**/\r
a42e6d44
AB
1145STATIC\r
1146EFI_STATUS\r
8b78de74 1147EFIAPI\r
a42e6d44
AB
1148PciIoFlush (\r
1149 IN EFI_PCI_IO_PROTOCOL *This\r
1150 )\r
1151{\r
1152 return EFI_SUCCESS;\r
1153}\r
1154\r
43b7cd61
DB
1155/**\r
1156 Retrieves this PCI controller's current PCI bus number, device number, and function number.\r
1157\r
1158 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1159 @param SegmentNumber The PCI controller's current PCI segment number.\r
1160 @param BusNumber The PCI controller's current PCI bus number.\r
1161 @param DeviceNumber The PCI controller's current PCI device number.\r
1162 @param FunctionNumber The PCI controller's current PCI function number.\r
1163\r
1164 @retval EFI_SUCCESS The PCI controller location was returned.\r
1165 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1166\r
1167**/\r
a42e6d44
AB
1168STATIC\r
1169EFI_STATUS\r
8b78de74 1170EFIAPI\r
a42e6d44
AB
1171PciIoGetLocation (\r
1172 IN EFI_PCI_IO_PROTOCOL *This,\r
1173 OUT UINTN *SegmentNumber,\r
1174 OUT UINTN *BusNumber,\r
1175 OUT UINTN *DeviceNumber,\r
1176 OUT UINTN *FunctionNumber\r
1177 )\r
1178{\r
1179 if (SegmentNumber == NULL ||\r
1180 BusNumber == NULL ||\r
1181 DeviceNumber == NULL ||\r
1182 FunctionNumber == NULL) {\r
1183 return EFI_INVALID_PARAMETER;\r
1184 }\r
1185\r
1186 *SegmentNumber = 0;\r
1187 *BusNumber = 0xff;\r
1188 *DeviceNumber = 0;\r
1189 *FunctionNumber = 0;\r
1190\r
1191 return EFI_SUCCESS;\r
1192}\r
1193\r
43b7cd61
DB
1194/**\r
1195 Performs an operation on the attributes that this PCI controller supports. The operations include\r
1196 getting the set of supported attributes, retrieving the current attributes, setting the current\r
1197 attributes, enabling attributes, and disabling attributes.\r
1198\r
1199 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1200 @param Operation The operation to perform on the attributes for this PCI controller.\r
1201 @param Attributes The mask of attributes that are used for Set, Enable, and Disable\r
1202 operations.\r
1203 @param Result A pointer to the result mask of attributes that are returned for the Get\r
1204 and Supported operations.\r
1205\r
1206 @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.\r
1207 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1208 @retval EFI_UNSUPPORTED one or more of the bits set in\r
1209 Attributes are not supported by this PCI controller or one of\r
1210 its parent bridges when Operation is Set, Enable or Disable.\r
1211\r
1212**/\r
a42e6d44
AB
1213STATIC\r
1214EFI_STATUS\r
8b78de74 1215EFIAPI\r
a42e6d44
AB
1216PciIoAttributes (\r
1217 IN EFI_PCI_IO_PROTOCOL *This,\r
1218 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,\r
1219 IN UINT64 Attributes,\r
1220 OUT UINT64 *Result OPTIONAL\r
1221 )\r
1222{\r
1223 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
1224 BOOLEAN Enable;\r
1225\r
1226 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1227\r
1228 Enable = FALSE;\r
1229 switch (Operation) {\r
1230 case EfiPciIoAttributeOperationGet:\r
1231 if (Result == NULL) {\r
1232 return EFI_INVALID_PARAMETER;\r
1233 }\r
1234 *Result = Dev->Attributes;\r
1235 break;\r
1236\r
1237 case EfiPciIoAttributeOperationSupported:\r
1238 if (Result == NULL) {\r
1239 return EFI_INVALID_PARAMETER;\r
1240 }\r
1241 *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
1242 break;\r
1243\r
1244 case EfiPciIoAttributeOperationEnable:\r
1245 Attributes |= Dev->Attributes;\r
1246 case EfiPciIoAttributeOperationSet:\r
1247 Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;\r
1248 Dev->Attributes = Attributes;\r
1249 break;\r
1250\r
1251 case EfiPciIoAttributeOperationDisable:\r
1252 Dev->Attributes &= ~Attributes;\r
1253 break;\r
1254\r
1255 default:\r
1256 return EFI_INVALID_PARAMETER;\r
1257 };\r
1258\r
1259 //\r
1260 // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform\r
1261 // the device specific initialization now.\r
1262 //\r
1263 if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {\r
1264 Dev->Device->Initialize (Dev->Device);\r
1265 Dev->Enabled = TRUE;\r
1266 }\r
1267 return EFI_SUCCESS;\r
1268}\r
1269\r
43b7cd61
DB
1270/**\r
1271 Gets the attributes that this PCI controller supports setting on a BAR using\r
1272 SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.\r
1273\r
1274 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1275 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
1276 base address for resource range. The legal range for this field is 0..5.\r
1277 @param Supports A pointer to the mask of attributes that this PCI controller supports\r
1278 setting for this BAR with SetBarAttributes().\r
1279 @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current\r
1280 configuration of this BAR of the PCI controller.\r
1281\r
1282 @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI\r
1283 controller supports are returned in Supports. If Resources\r
1284 is not NULL, then the ACPI 2.0 resource descriptors that the PCI\r
1285 controller is currently using are returned in Resources.\r
1286 @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.\r
1287 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
1288 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate\r
1289 Resources.\r
1290\r
1291**/\r
a42e6d44
AB
1292STATIC\r
1293EFI_STATUS\r
8b78de74 1294EFIAPI\r
a42e6d44
AB
1295PciIoGetBarAttributes (\r
1296 IN EFI_PCI_IO_PROTOCOL *This,\r
1297 IN UINT8 BarIndex,\r
1298 OUT UINT64 *Supports OPTIONAL,\r
1299 OUT VOID **Resources OPTIONAL\r
1300 )\r
1301{\r
1302 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
5f16ecdb
DB
1303 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1304 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;\r
a42e6d44
AB
1305 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1306 EFI_STATUS Status;\r
1307\r
1308 if (Supports == NULL && Resources == NULL) {\r
1309 return EFI_INVALID_PARAMETER;\r
1310 }\r
1311\r
1312 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1313\r
1314 Status = GetBarResource (Dev, BarIndex, &BarDesc);\r
1315 if (EFI_ERROR (Status)) {\r
1316 return Status;\r
1317 }\r
1318\r
1319 //\r
1320 // Don't expose any configurable attributes for our emulated BAR\r
1321 //\r
1322 if (Supports != NULL) {\r
1323 *Supports = 0;\r
1324 }\r
1325\r
1326 if (Resources != NULL) {\r
1327 Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +\r
1328 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1329 if (Descriptor == NULL) {\r
1330 return EFI_OUT_OF_RESOURCES;\r
1331 }\r
1332\r
1333 CopyMem (Descriptor, BarDesc, sizeof *Descriptor);\r
1334\r
1335 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1336 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1337 End->Checksum = 0;\r
1338\r
1339 *Resources = Descriptor;\r
1340 }\r
1341 return EFI_SUCCESS;\r
1342}\r
1343\r
43b7cd61
DB
1344/**\r
1345 Sets the attributes for a range of a BAR on a PCI controller.\r
1346\r
1347 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1348 @param Attributes The mask of attributes to set for the resource range specified by\r
1349 BarIndex, Offset, and Length.\r
1350 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
1351 base address for resource range. The legal range for this field is 0..5.\r
1352 @param Offset A pointer to the BAR relative base address of the resource range to be\r
1353 modified by the attributes specified by Attributes.\r
1354 @param Length A pointer to the length of the resource range to be modified by the\r
1355 attributes specified by Attributes.\r
1356**/\r
a42e6d44
AB
1357STATIC\r
1358EFI_STATUS\r
8b78de74 1359EFIAPI\r
a42e6d44
AB
1360PciIoSetBarAttributes (\r
1361 IN EFI_PCI_IO_PROTOCOL *This,\r
1362 IN UINT64 Attributes,\r
1363 IN UINT8 BarIndex,\r
1364 IN OUT UINT64 *Offset,\r
1365 IN OUT UINT64 *Length\r
1366 )\r
1367{\r
1368 ASSERT (FALSE);\r
1369 return EFI_UNSUPPORTED;\r
1370}\r
1371\r
1372STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =\r
1373{\r
1374 PciIoPollMem,\r
1375 PciIoPollIo,\r
1376 { PciIoMemRead, PciIoMemWrite },\r
1377 { PciIoIoRead, PciIoIoWrite },\r
1378 { PciIoPciRead, PciIoPciWrite },\r
1379 PciIoCopyMem,\r
1380 CoherentPciIoMap,\r
1381 CoherentPciIoUnmap,\r
1382 CoherentPciIoAllocateBuffer,\r
1383 CoherentPciIoFreeBuffer,\r
1384 PciIoFlush,\r
1385 PciIoGetLocation,\r
1386 PciIoAttributes,\r
1387 PciIoGetBarAttributes,\r
1388 PciIoSetBarAttributes,\r
1389 0,\r
1390 0\r
1391};\r
1392\r
43b7cd61
DB
1393/**\r
1394 Initialize PciIo Protocol.\r
1395\r
1396 @param Dev Point to NON_DISCOVERABLE_PCI_DEVICE instance.\r
1397\r
1398**/\r
a42e6d44
AB
1399VOID\r
1400InitializePciIoProtocol (\r
1401 NON_DISCOVERABLE_PCI_DEVICE *Dev\r
1402 )\r
1403{\r
1404 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
1405 INTN Idx;\r
1406\r
16296a12
AB
1407 InitializeListHead (&Dev->UncachedAllocationList);\r
1408\r
a42e6d44
AB
1409 Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;\r
1410 Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;\r
1411\r
1412 // Copy protocol structure\r
1413 CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);\r
1414\r
16296a12
AB
1415 if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {\r
1416 Dev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;\r
1417 Dev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;\r
1418 Dev->PciIo.Map = NonCoherentPciIoMap;\r
1419 Dev->PciIo.Unmap = NonCoherentPciIoUnmap;\r
1420 }\r
1421\r
a42e6d44
AB
1422 if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {\r
1423 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;\r
1424 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;\r
1425 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1426 Dev->BarOffset = 5;\r
1427 } else if (CompareGuid (Dev->Device->Type,\r
1428 &gEdkiiNonDiscoverableEhciDeviceGuid)) {\r
1429 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;\r
1430 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1431 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1432 Dev->BarOffset = 0;\r
1433 } else if (CompareGuid (Dev->Device->Type,\r
1434 &gEdkiiNonDiscoverableNvmeDeviceGuid)) {\r
1435 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI\r
1436 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM\r
1437 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1438 Dev->BarOffset = 0;\r
1439 } else if (CompareGuid (Dev->Device->Type,\r
1440 &gEdkiiNonDiscoverableOhciDeviceGuid)) {\r
1441 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;\r
1442 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1443 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1444 Dev->BarOffset = 0;\r
1445 } else if (CompareGuid (Dev->Device->Type,\r
1446 &gEdkiiNonDiscoverableSdhciDeviceGuid)) {\r
1447 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1448 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;\r
1449 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;\r
1450 Dev->BarOffset = 0;\r
1451 } else if (CompareGuid (Dev->Device->Type,\r
1452 &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
1453 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;\r
1454 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1455 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1456 Dev->BarOffset = 0;\r
1457 } else if (CompareGuid (Dev->Device->Type,\r
1458 &gEdkiiNonDiscoverableUhciDeviceGuid)) {\r
1459 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;\r
1460 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1461 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1462 Dev->BarOffset = 0;\r
1463 } else if (CompareGuid (Dev->Device->Type,\r
1464 &gEdkiiNonDiscoverableUfsDeviceGuid)) {\r
1465 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1466 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;\r
1467 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1468 Dev->BarOffset = 0;\r
1469 } else {\r
1470 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
1471 }\r
1472\r
1473 //\r
1474 // Iterate over the resources to populate the virtual BARs\r
1475 //\r
1476 Idx = Dev->BarOffset;\r
1477 for (Desc = Dev->Device->Resources, Dev->BarCount = 0;\r
1478 Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
1479 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
1480\r
1481 ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
1482 ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);\r
1483\r
1484 if (Idx >= PCI_MAX_BARS ||\r
1485 (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {\r
1486 DEBUG ((DEBUG_ERROR,\r
1487 "%a: resource count exceeds number of emulated BARs\n",\r
1488 __FUNCTION__));\r
1489 ASSERT (FALSE);\r
1490 break;\r
1491 }\r
1492\r
1493 Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;\r
1494 Dev->BarCount++;\r
1495\r
1496 if (Desc->AddrSpaceGranularity == 64) {\r
1497 Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;\r
1498 Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (\r
1499 Desc->AddrRangeMin, 32);\r
1500 }\r
1501 }\r
1502}\r