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