]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
MdeModulePkg/NonDiscoverablePciDeviceDxe: Add NULL pointer check
[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
698d3d77
JB
859 if (HostAddress == NULL) {\r
860 return EFI_INVALID_PARAMETER;\r
861 }\r
862\r
c8c3c536
VO
863 if ((MemoryType != EfiBootServicesData) &&\r
864 (MemoryType != EfiRuntimeServicesData)) {\r
865 return EFI_INVALID_PARAMETER;\r
866 }\r
867\r
a42e6d44
AB
868 //\r
869 // Allocate below 4 GB if the dual address cycle attribute has not\r
870 // been set. If the system has no memory available below 4 GB, there\r
871 // is little we can do except propagate the error.\r
872 //\r
873 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
874 if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
875 AllocAddress = MAX_UINT32;\r
876 AllocType = AllocateMaxAddress;\r
877 } else {\r
878 AllocType = AllocateAnyPages;\r
879 }\r
880\r
881 Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);\r
882 if (!EFI_ERROR (Status)) {\r
883 *HostAddress = (VOID *)(UINTN)AllocAddress;\r
884 }\r
885 return Status;\r
886}\r
887\r
43b7cd61
DB
888/**\r
889 Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().\r
890\r
891 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
892 @param Pages The number of pages to free.\r
893 @param HostAddress The base system memory address of the allocated range.\r
894\r
895 @retval EFI_SUCCESS The requested memory pages were freed.\r
896\r
897**/\r
a42e6d44
AB
898STATIC\r
899EFI_STATUS\r
8b78de74 900EFIAPI\r
a42e6d44
AB
901CoherentPciIoFreeBuffer (\r
902 IN EFI_PCI_IO_PROTOCOL *This,\r
903 IN UINTN Pages,\r
904 IN VOID *HostAddress\r
905 )\r
906{\r
907 FreePages (HostAddress, Pages);\r
908 return EFI_SUCCESS;\r
909}\r
910\r
43b7cd61
DB
911/**\r
912 Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().\r
913\r
914 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
915 @param Pages The number of pages to free.\r
916 @param HostAddress The base system memory address of the allocated range.\r
917\r
918 @retval EFI_SUCCESS The requested memory pages were freed.\r
919 @retval others The operation contain some errors.\r
920\r
921**/\r
16296a12
AB
922STATIC\r
923EFI_STATUS\r
924EFIAPI\r
925NonCoherentPciIoFreeBuffer (\r
926 IN EFI_PCI_IO_PROTOCOL *This,\r
927 IN UINTN Pages,\r
928 IN VOID *HostAddress\r
929 )\r
930{\r
931 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
932 LIST_ENTRY *Entry;\r
933 EFI_STATUS Status;\r
934 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
935 BOOLEAN Found;\r
936\r
937 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
938\r
939 Found = FALSE;\r
1525ff38 940 Alloc = NULL;\r
16296a12
AB
941\r
942 //\r
943 // Find the uncached allocation list entry associated\r
944 // with this allocation\r
945 //\r
946 for (Entry = Dev->UncachedAllocationList.ForwardLink;\r
947 Entry != &Dev->UncachedAllocationList;\r
948 Entry = Entry->ForwardLink) {\r
949\r
950 Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);\r
951 if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {\r
952 //\r
953 // We are freeing the exact allocation we were given\r
954 // before by AllocateBuffer()\r
955 //\r
956 Found = TRUE;\r
957 break;\r
958 }\r
959 }\r
960\r
961 if (!Found) {\r
962 ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
963 return EFI_NOT_FOUND;\r
964 }\r
965\r
966 RemoveEntryList (&Alloc->List);\r
967\r
968 Status = gDS->SetMemorySpaceAttributes (\r
969 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
970 EFI_PAGES_TO_SIZE (Pages),\r
971 Alloc->Attributes);\r
972 if (EFI_ERROR (Status)) {\r
973 goto FreeAlloc;\r
974 }\r
975\r
976 //\r
977 // If we fail to restore the original attributes, it is better to leak the\r
978 // memory than to return it to the heap\r
979 //\r
980 FreePages (HostAddress, Pages);\r
981\r
982FreeAlloc:\r
983 FreePool (Alloc);\r
984 return Status;\r
985}\r
986\r
43b7cd61
DB
987/**\r
988 Allocates pages.\r
989\r
990 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
991 @param Type This parameter is not used and must be ignored.\r
992 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
993 EfiRuntimeServicesData.\r
994 @param Pages The number of pages to allocate.\r
995 @param HostAddress A pointer to store the base system memory address of the\r
996 allocated range.\r
997 @param Attributes The requested bit mask of attributes for the allocated range.\r
998\r
999 @retval EFI_SUCCESS The requested memory pages were allocated.\r
1000 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
1001 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
1002 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1003 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
1004\r
1005**/\r
16296a12
AB
1006STATIC\r
1007EFI_STATUS\r
1008EFIAPI\r
1009NonCoherentPciIoAllocateBuffer (\r
1010 IN EFI_PCI_IO_PROTOCOL *This,\r
1011 IN EFI_ALLOCATE_TYPE Type,\r
1012 IN EFI_MEMORY_TYPE MemoryType,\r
1013 IN UINTN Pages,\r
1014 OUT VOID **HostAddress,\r
1015 IN UINT64 Attributes\r
1016 )\r
1017{\r
1018 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
1019 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
1020 EFI_STATUS Status;\r
1021 UINT64 MemType;\r
1022 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
1023 VOID *AllocAddress;\r
1024\r
c8c3c536
VO
1025 if (HostAddress == NULL) {\r
1026 return EFI_INVALID_PARAMETER;\r
1027 }\r
1028\r
16296a12
AB
1029 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1030\r
1031 Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,\r
1032 &AllocAddress, Attributes);\r
1033 if (EFI_ERROR (Status)) {\r
1034 return Status;\r
1035 }\r
1036\r
1037 Status = gDS->GetMemorySpaceDescriptor (\r
1038 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
1039 &GcdDescriptor);\r
1040 if (EFI_ERROR (Status)) {\r
1041 goto FreeBuffer;\r
1042 }\r
1043\r
1044 if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {\r
1045 Status = EFI_UNSUPPORTED;\r
1046 goto FreeBuffer;\r
1047 }\r
1048\r
1049 //\r
1050 // Set the preferred memory attributes\r
1051 //\r
1052 if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||\r
1053 (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {\r
1054 //\r
1055 // Use write combining if it was requested, or if it is the only\r
1056 // type supported by the region.\r
1057 //\r
1058 MemType = EFI_MEMORY_WC;\r
1059 } else {\r
1060 MemType = EFI_MEMORY_UC;\r
1061 }\r
1062\r
1063 Alloc = AllocatePool (sizeof *Alloc);\r
1064 if (Alloc == NULL) {\r
1065 goto FreeBuffer;\r
1066 }\r
1067\r
1068 Alloc->HostAddress = AllocAddress;\r
1069 Alloc->NumPages = Pages;\r
1070 Alloc->Attributes = GcdDescriptor.Attributes;\r
1071\r
1072 //\r
1073 // Record this allocation in the linked list, so we\r
1074 // can restore the memory space attributes later\r
1075 //\r
1076 InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);\r
1077\r
1078 Status = gDS->SetMemorySpaceAttributes (\r
1079 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
1080 EFI_PAGES_TO_SIZE (Pages),\r
1081 MemType);\r
1082 if (EFI_ERROR (Status)) {\r
1083 goto RemoveList;\r
1084 }\r
1085\r
1086 Status = mCpu->FlushDataCache (\r
1087 mCpu,\r
1088 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
1089 EFI_PAGES_TO_SIZE (Pages),\r
1090 EfiCpuFlushTypeInvalidate);\r
1091 if (EFI_ERROR (Status)) {\r
1092 goto RemoveList;\r
1093 }\r
1094\r
1095 *HostAddress = AllocAddress;\r
1096\r
1097 return EFI_SUCCESS;\r
1098\r
1099RemoveList:\r
1100 RemoveEntryList (&Alloc->List);\r
1101 FreePool (Alloc);\r
1102\r
1103FreeBuffer:\r
1104 CoherentPciIoFreeBuffer (This, Pages, AllocAddress);\r
1105 return Status;\r
1106}\r
1107\r
43b7cd61
DB
1108/**\r
1109 Provides the PCI controller-specific addresses needed to access system memory.\r
1110\r
1111 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1112 @param Operation Indicates if the bus master is going to read or write to system memory.\r
1113 @param HostAddress The system memory address to map to the PCI controller.\r
1114 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
1115 that were mapped.\r
1116 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
1117 access the hosts HostAddress.\r
1118 @param Mapping A resulting value to pass to Unmap().\r
1119\r
1120 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
1121 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
1122 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1123 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1124 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
1125\r
1126**/\r
16296a12
AB
1127STATIC\r
1128EFI_STATUS\r
1129EFIAPI\r
1130NonCoherentPciIoMap (\r
1131 IN EFI_PCI_IO_PROTOCOL *This,\r
1132 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
1133 IN VOID *HostAddress,\r
1134 IN OUT UINTN *NumberOfBytes,\r
1135 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
1136 OUT VOID **Mapping\r
1137 )\r
1138{\r
1139 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
1140 EFI_STATUS Status;\r
1141 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
1142 UINTN AlignMask;\r
1143 VOID *AllocAddress;\r
1144 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
1145 BOOLEAN Bounce;\r
1146\r
c8c3c536
VO
1147 if (HostAddress == NULL ||\r
1148 NumberOfBytes == NULL ||\r
1149 DeviceAddress == NULL ||\r
1150 Mapping == NULL) {\r
1151 return EFI_INVALID_PARAMETER;\r
1152 }\r
1153\r
1154 if (Operation != EfiPciIoOperationBusMasterRead &&\r
1155 Operation != EfiPciIoOperationBusMasterWrite &&\r
1156 Operation != EfiPciIoOperationBusMasterCommonBuffer) {\r
1157 return EFI_INVALID_PARAMETER;\r
1158 }\r
1159\r
16296a12
AB
1160 MapInfo = AllocatePool (sizeof *MapInfo);\r
1161 if (MapInfo == NULL) {\r
1162 return EFI_OUT_OF_RESOURCES;\r
1163 }\r
1164\r
1165 MapInfo->HostAddress = HostAddress;\r
1166 MapInfo->Operation = Operation;\r
1167 MapInfo->NumberOfBytes = *NumberOfBytes;\r
1168\r
1169 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1170\r
1171 //\r
1172 // If this device does not support 64-bit DMA addressing, we need to allocate\r
1173 // a bounce buffer and copy over the data in case HostAddress >= 4 GB.\r
1174 //\r
1175 Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
b494cf96 1176 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);\r
16296a12
AB
1177\r
1178 if (!Bounce) {\r
1179 switch (Operation) {\r
1180 case EfiPciIoOperationBusMasterRead:\r
1181 case EfiPciIoOperationBusMasterWrite:\r
1182 //\r
1183 // For streaming DMA, it is sufficient if the buffer is aligned to\r
1184 // the CPUs DMA buffer alignment.\r
1185 //\r
1186 AlignMask = mCpu->DmaBufferAlignment - 1;\r
1187 if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {\r
1188 break;\r
1189 }\r
1190 // fall through\r
1191\r
1192 case EfiPciIoOperationBusMasterCommonBuffer:\r
1193 //\r
1194 // Check whether the host address refers to an uncached mapping.\r
1195 //\r
1196 Status = gDS->GetMemorySpaceDescriptor (\r
1197 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
1198 &GcdDescriptor);\r
1199 if (EFI_ERROR (Status) ||\r
1200 (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {\r
1201 Bounce = TRUE;\r
1202 }\r
1203 break;\r
1204\r
1205 default:\r
1206 ASSERT (FALSE);\r
1207 }\r
1208 }\r
1209\r
1210 if (Bounce) {\r
1211 if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
1212 Status = EFI_DEVICE_ERROR;\r
1213 goto FreeMapInfo;\r
1214 }\r
1215\r
1216 Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,\r
1217 EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
1218 &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);\r
1219 if (EFI_ERROR (Status)) {\r
1220 goto FreeMapInfo;\r
1221 }\r
1222 MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;\r
1223 if (Operation == EfiPciIoOperationBusMasterRead) {\r
1224 gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);\r
1225 }\r
1226 *DeviceAddress = MapInfo->AllocAddress;\r
1227 } else {\r
1228 MapInfo->AllocAddress = 0;\r
1229 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
1230\r
1231 //\r
1232 // We are not using a bounce buffer: the mapping is sufficiently\r
1233 // aligned to allow us to simply flush the caches. Note that cleaning\r
1234 // the caches is necessary for both data directions:\r
1235 // - for bus master read, we want the latest data to be present\r
1236 // in main memory\r
1237 // - for bus master write, we don't want any stale dirty cachelines that\r
1238 // may be written back unexpectedly, and clobber the data written to\r
1239 // main memory by the device.\r
1240 //\r
1241 mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
1242 *NumberOfBytes, EfiCpuFlushTypeWriteBack);\r
1243 }\r
1244\r
1245 *Mapping = MapInfo;\r
1246 return EFI_SUCCESS;\r
1247\r
1248FreeMapInfo:\r
1249 FreePool (MapInfo);\r
1250\r
1251 return Status;\r
1252}\r
1253\r
43b7cd61
DB
1254/**\r
1255 Completes the Map() operation and releases any corresponding resources.\r
1256\r
1257 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1258 @param Mapping The mapping value returned from Map().\r
1259\r
1260 @retval EFI_SUCCESS The range was unmapped.\r
1261\r
1262**/\r
16296a12
AB
1263STATIC\r
1264EFI_STATUS\r
1265EFIAPI\r
1266NonCoherentPciIoUnmap (\r
1267 IN EFI_PCI_IO_PROTOCOL *This,\r
1268 IN VOID *Mapping\r
1269 )\r
1270{\r
1271 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
1272\r
1273 if (Mapping == NULL) {\r
1274 return EFI_DEVICE_ERROR;\r
1275 }\r
1276\r
1277 MapInfo = Mapping;\r
1278 if (MapInfo->AllocAddress != 0) {\r
1279 //\r
1280 // We are using a bounce buffer: copy back the data if necessary,\r
1281 // and free the buffer.\r
1282 //\r
1283 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
1284 gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
1285 MapInfo->NumberOfBytes);\r
1286 }\r
1287 NonCoherentPciIoFreeBuffer (This,\r
1288 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
1289 (VOID *)(UINTN)MapInfo->AllocAddress);\r
1290 } else {\r
1291 //\r
1292 // We are *not* using a bounce buffer: if this is a bus master write,\r
1293 // we have to invalidate the caches so the CPU will see the uncached\r
1294 // data written by the device.\r
1295 //\r
1296 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
1297 mCpu->FlushDataCache (mCpu,\r
1298 (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,\r
1299 MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
1300 }\r
1301 }\r
1302 FreePool (MapInfo);\r
1303 return EFI_SUCCESS;\r
1304}\r
a42e6d44 1305\r
43b7cd61
DB
1306/**\r
1307 Flushes all PCI posted write transactions from a PCI host bridge to system memory.\r
1308\r
1309 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1310\r
1311**/\r
a42e6d44
AB
1312STATIC\r
1313EFI_STATUS\r
8b78de74 1314EFIAPI\r
a42e6d44
AB
1315PciIoFlush (\r
1316 IN EFI_PCI_IO_PROTOCOL *This\r
1317 )\r
1318{\r
1319 return EFI_SUCCESS;\r
1320}\r
1321\r
43b7cd61
DB
1322/**\r
1323 Retrieves this PCI controller's current PCI bus number, device number, and function number.\r
1324\r
1325 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1326 @param SegmentNumber The PCI controller's current PCI segment number.\r
1327 @param BusNumber The PCI controller's current PCI bus number.\r
1328 @param DeviceNumber The PCI controller's current PCI device number.\r
1329 @param FunctionNumber The PCI controller's current PCI function number.\r
1330\r
1331 @retval EFI_SUCCESS The PCI controller location was returned.\r
1332 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1333\r
1334**/\r
a42e6d44
AB
1335STATIC\r
1336EFI_STATUS\r
8b78de74 1337EFIAPI\r
a42e6d44
AB
1338PciIoGetLocation (\r
1339 IN EFI_PCI_IO_PROTOCOL *This,\r
1340 OUT UINTN *SegmentNumber,\r
1341 OUT UINTN *BusNumber,\r
1342 OUT UINTN *DeviceNumber,\r
1343 OUT UINTN *FunctionNumber\r
1344 )\r
1345{\r
1a3bee20
AB
1346 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
1347\r
a42e6d44
AB
1348 if (SegmentNumber == NULL ||\r
1349 BusNumber == NULL ||\r
1350 DeviceNumber == NULL ||\r
1351 FunctionNumber == NULL) {\r
1352 return EFI_INVALID_PARAMETER;\r
1353 }\r
1354\r
1a3bee20
AB
1355 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1356\r
1357 *SegmentNumber = 0xff;\r
1358 *BusNumber = Dev->UniqueId >> 5;\r
1359 *DeviceNumber = Dev->UniqueId & 0x1f;\r
a42e6d44
AB
1360 *FunctionNumber = 0;\r
1361\r
1362 return EFI_SUCCESS;\r
1363}\r
1364\r
43b7cd61
DB
1365/**\r
1366 Performs an operation on the attributes that this PCI controller supports. The operations include\r
1367 getting the set of supported attributes, retrieving the current attributes, setting the current\r
1368 attributes, enabling attributes, and disabling attributes.\r
1369\r
1370 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1371 @param Operation The operation to perform on the attributes for this PCI controller.\r
1372 @param Attributes The mask of attributes that are used for Set, Enable, and Disable\r
1373 operations.\r
1374 @param Result A pointer to the result mask of attributes that are returned for the Get\r
1375 and Supported operations.\r
1376\r
1377 @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.\r
1378 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1379 @retval EFI_UNSUPPORTED one or more of the bits set in\r
1380 Attributes are not supported by this PCI controller or one of\r
1381 its parent bridges when Operation is Set, Enable or Disable.\r
1382\r
1383**/\r
a42e6d44
AB
1384STATIC\r
1385EFI_STATUS\r
8b78de74 1386EFIAPI\r
a42e6d44
AB
1387PciIoAttributes (\r
1388 IN EFI_PCI_IO_PROTOCOL *This,\r
1389 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,\r
1390 IN UINT64 Attributes,\r
1391 OUT UINT64 *Result OPTIONAL\r
1392 )\r
1393{\r
1394 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
1395 BOOLEAN Enable;\r
1396\r
1397 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1398\r
a53a888d
DB
1399 if ((Attributes & (~(DEV_SUPPORTED_ATTRIBUTES))) != 0) {\r
1400 return EFI_UNSUPPORTED;\r
1401 }\r
c8c3c536 1402\r
a42e6d44
AB
1403 Enable = FALSE;\r
1404 switch (Operation) {\r
1405 case EfiPciIoAttributeOperationGet:\r
1406 if (Result == NULL) {\r
1407 return EFI_INVALID_PARAMETER;\r
1408 }\r
1409 *Result = Dev->Attributes;\r
1410 break;\r
1411\r
1412 case EfiPciIoAttributeOperationSupported:\r
1413 if (Result == NULL) {\r
1414 return EFI_INVALID_PARAMETER;\r
1415 }\r
c8c3c536 1416 *Result = DEV_SUPPORTED_ATTRIBUTES;\r
a42e6d44
AB
1417 break;\r
1418\r
1419 case EfiPciIoAttributeOperationEnable:\r
1420 Attributes |= Dev->Attributes;\r
1421 case EfiPciIoAttributeOperationSet:\r
1422 Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;\r
1423 Dev->Attributes = Attributes;\r
1424 break;\r
1425\r
1426 case EfiPciIoAttributeOperationDisable:\r
1427 Dev->Attributes &= ~Attributes;\r
1428 break;\r
1429\r
1430 default:\r
1431 return EFI_INVALID_PARAMETER;\r
1432 };\r
1433\r
1434 //\r
1435 // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform\r
1436 // the device specific initialization now.\r
1437 //\r
1438 if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {\r
1439 Dev->Device->Initialize (Dev->Device);\r
1440 Dev->Enabled = TRUE;\r
1441 }\r
1442 return EFI_SUCCESS;\r
1443}\r
1444\r
43b7cd61
DB
1445/**\r
1446 Gets the attributes that this PCI controller supports setting on a BAR using\r
1447 SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.\r
1448\r
1449 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1450 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
1451 base address for resource range. The legal range for this field is 0..5.\r
1452 @param Supports A pointer to the mask of attributes that this PCI controller supports\r
1453 setting for this BAR with SetBarAttributes().\r
1454 @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current\r
1455 configuration of this BAR of the PCI controller.\r
1456\r
1457 @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI\r
1458 controller supports are returned in Supports. If Resources\r
1459 is not NULL, then the ACPI 2.0 resource descriptors that the PCI\r
1460 controller is currently using are returned in Resources.\r
1461 @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.\r
1462 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
1463 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate\r
1464 Resources.\r
1465\r
1466**/\r
a42e6d44
AB
1467STATIC\r
1468EFI_STATUS\r
8b78de74 1469EFIAPI\r
a42e6d44
AB
1470PciIoGetBarAttributes (\r
1471 IN EFI_PCI_IO_PROTOCOL *This,\r
1472 IN UINT8 BarIndex,\r
1473 OUT UINT64 *Supports OPTIONAL,\r
1474 OUT VOID **Resources OPTIONAL\r
1475 )\r
1476{\r
1477 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
5f16ecdb
DB
1478 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1479 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;\r
a42e6d44
AB
1480 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1481 EFI_STATUS Status;\r
1482\r
1483 if (Supports == NULL && Resources == NULL) {\r
1484 return EFI_INVALID_PARAMETER;\r
1485 }\r
1486\r
1487 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1488\r
1489 Status = GetBarResource (Dev, BarIndex, &BarDesc);\r
1490 if (EFI_ERROR (Status)) {\r
1491 return Status;\r
1492 }\r
1493\r
1494 //\r
1495 // Don't expose any configurable attributes for our emulated BAR\r
1496 //\r
1497 if (Supports != NULL) {\r
1498 *Supports = 0;\r
1499 }\r
1500\r
1501 if (Resources != NULL) {\r
1502 Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +\r
1503 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1504 if (Descriptor == NULL) {\r
1505 return EFI_OUT_OF_RESOURCES;\r
1506 }\r
1507\r
1508 CopyMem (Descriptor, BarDesc, sizeof *Descriptor);\r
1509\r
1510 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1511 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1512 End->Checksum = 0;\r
1513\r
1514 *Resources = Descriptor;\r
1515 }\r
1516 return EFI_SUCCESS;\r
1517}\r
1518\r
43b7cd61
DB
1519/**\r
1520 Sets the attributes for a range of a BAR on a PCI controller.\r
1521\r
1522 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1523 @param Attributes The mask of attributes to set for the resource range specified by\r
1524 BarIndex, Offset, and Length.\r
1525 @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
1526 base address for resource range. The legal range for this field is 0..5.\r
1527 @param Offset A pointer to the BAR relative base address of the resource range to be\r
1528 modified by the attributes specified by Attributes.\r
1529 @param Length A pointer to the length of the resource range to be modified by the\r
1530 attributes specified by Attributes.\r
1531**/\r
a42e6d44
AB
1532STATIC\r
1533EFI_STATUS\r
8b78de74 1534EFIAPI\r
a42e6d44
AB
1535PciIoSetBarAttributes (\r
1536 IN EFI_PCI_IO_PROTOCOL *This,\r
1537 IN UINT64 Attributes,\r
1538 IN UINT8 BarIndex,\r
1539 IN OUT UINT64 *Offset,\r
1540 IN OUT UINT64 *Length\r
1541 )\r
1542{\r
3b9cd714
GJ
1543 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
1544 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
1545 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
1546 UINTN Count;\r
1547 EFI_STATUS Status;\r
1548\r
1549 if ((Attributes & (~DEV_SUPPORTED_ATTRIBUTES)) != 0) {\r
1550 return EFI_UNSUPPORTED;\r
1551 }\r
1552\r
1553 if (Offset == NULL || Length == NULL) {\r
1554 return EFI_INVALID_PARAMETER;\r
1555 }\r
1556\r
1557 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1558 Width = EfiPciIoWidthUint8;\r
1559 Count = (UINT32) *Length;\r
1560\r
1561 Status = GetBarResource(Dev, BarIndex, &Desc);\r
1562 if (EFI_ERROR (Status)) {\r
1563 return Status;\r
1564 }\r
1565\r
1566 if (*Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
1567 return EFI_UNSUPPORTED;\r
1568 }\r
1569\r
a42e6d44
AB
1570 ASSERT (FALSE);\r
1571 return EFI_UNSUPPORTED;\r
1572}\r
1573\r
1574STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =\r
1575{\r
1576 PciIoPollMem,\r
1577 PciIoPollIo,\r
1578 { PciIoMemRead, PciIoMemWrite },\r
1579 { PciIoIoRead, PciIoIoWrite },\r
1580 { PciIoPciRead, PciIoPciWrite },\r
1581 PciIoCopyMem,\r
1582 CoherentPciIoMap,\r
1583 CoherentPciIoUnmap,\r
1584 CoherentPciIoAllocateBuffer,\r
1585 CoherentPciIoFreeBuffer,\r
1586 PciIoFlush,\r
1587 PciIoGetLocation,\r
1588 PciIoAttributes,\r
1589 PciIoGetBarAttributes,\r
1590 PciIoSetBarAttributes,\r
1591 0,\r
1592 0\r
1593};\r
1594\r
43b7cd61
DB
1595/**\r
1596 Initialize PciIo Protocol.\r
1597\r
1598 @param Dev Point to NON_DISCOVERABLE_PCI_DEVICE instance.\r
1599\r
1600**/\r
a42e6d44
AB
1601VOID\r
1602InitializePciIoProtocol (\r
1603 NON_DISCOVERABLE_PCI_DEVICE *Dev\r
1604 )\r
1605{\r
1606 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
1607 INTN Idx;\r
1608\r
16296a12
AB
1609 InitializeListHead (&Dev->UncachedAllocationList);\r
1610\r
a42e6d44
AB
1611 Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;\r
1612 Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;\r
1613\r
1614 // Copy protocol structure\r
1615 CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);\r
1616\r
16296a12
AB
1617 if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {\r
1618 Dev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;\r
1619 Dev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;\r
1620 Dev->PciIo.Map = NonCoherentPciIoMap;\r
1621 Dev->PciIo.Unmap = NonCoherentPciIoUnmap;\r
1622 }\r
1623\r
a42e6d44
AB
1624 if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {\r
1625 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;\r
1626 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;\r
1627 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1628 Dev->BarOffset = 5;\r
1629 } else if (CompareGuid (Dev->Device->Type,\r
1630 &gEdkiiNonDiscoverableEhciDeviceGuid)) {\r
1631 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;\r
1632 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1633 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1634 Dev->BarOffset = 0;\r
1635 } else if (CompareGuid (Dev->Device->Type,\r
1636 &gEdkiiNonDiscoverableNvmeDeviceGuid)) {\r
1637 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI\r
1638 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM\r
1639 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1640 Dev->BarOffset = 0;\r
1641 } else if (CompareGuid (Dev->Device->Type,\r
1642 &gEdkiiNonDiscoverableOhciDeviceGuid)) {\r
1643 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;\r
1644 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1645 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1646 Dev->BarOffset = 0;\r
1647 } else if (CompareGuid (Dev->Device->Type,\r
1648 &gEdkiiNonDiscoverableSdhciDeviceGuid)) {\r
1649 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1650 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;\r
1651 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;\r
1652 Dev->BarOffset = 0;\r
1653 } else if (CompareGuid (Dev->Device->Type,\r
1654 &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
1655 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;\r
1656 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1657 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1658 Dev->BarOffset = 0;\r
1659 } else if (CompareGuid (Dev->Device->Type,\r
1660 &gEdkiiNonDiscoverableUhciDeviceGuid)) {\r
1661 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;\r
1662 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1663 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1664 Dev->BarOffset = 0;\r
1665 } else if (CompareGuid (Dev->Device->Type,\r
1666 &gEdkiiNonDiscoverableUfsDeviceGuid)) {\r
1667 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1668 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;\r
1669 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1670 Dev->BarOffset = 0;\r
1671 } else {\r
1672 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
1673 }\r
1674\r
1675 //\r
1676 // Iterate over the resources to populate the virtual BARs\r
1677 //\r
1678 Idx = Dev->BarOffset;\r
1679 for (Desc = Dev->Device->Resources, Dev->BarCount = 0;\r
1680 Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
1681 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
1682\r
1683 ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
1684 ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);\r
1685\r
a7947b63
LE
1686 if (Idx >= PCI_MAX_BAR ||\r
1687 (Idx == PCI_MAX_BAR - 1 && Desc->AddrSpaceGranularity == 64)) {\r
a42e6d44
AB
1688 DEBUG ((DEBUG_ERROR,\r
1689 "%a: resource count exceeds number of emulated BARs\n",\r
1690 __FUNCTION__));\r
1691 ASSERT (FALSE);\r
1692 break;\r
1693 }\r
1694\r
1695 Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;\r
1696 Dev->BarCount++;\r
1697\r
1698 if (Desc->AddrSpaceGranularity == 64) {\r
1699 Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;\r
1700 Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (\r
1701 Desc->AddrRangeMin, 32);\r
1702 }\r
1703 }\r
1704}\r