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