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