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