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