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