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