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