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