]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciIo.c
1 /** @file
2 EFI PCI IO protocol functions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PciBus.h"
10
11 extern EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
12
13 //
14 // Pci Io Protocol Interface
15 //
16 EFI_PCI_IO_PROTOCOL mPciIoInterface = {
17 PciIoPollMem,
18 PciIoPollIo,
19 {
20 PciIoMemRead,
21 PciIoMemWrite
22 },
23 {
24 PciIoIoRead,
25 PciIoIoWrite
26 },
27 {
28 PciIoConfigRead,
29 PciIoConfigWrite
30 },
31 PciIoCopyMem,
32 PciIoMap,
33 PciIoUnmap,
34 PciIoAllocateBuffer,
35 PciIoFreeBuffer,
36 PciIoFlush,
37 PciIoGetLocation,
38 PciIoAttributes,
39 PciIoGetBarAttributes,
40 PciIoSetBarAttributes,
41 0,
42 NULL
43 };
44
45 /**
46 Initializes a PCI I/O Instance.
47
48 @param PciIoDevice Pci device instance.
49
50 **/
51 VOID
52 InitializePciIoInstance (
53 IN PCI_IO_DEVICE *PciIoDevice
54 )
55 {
56 CopyMem (&PciIoDevice->PciIo, &mPciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
57 }
58
59 /**
60 Verifies access to a PCI Base Address Register (BAR).
61
62 @param PciIoDevice Pci device instance.
63 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
64 base address for the memory or I/O operation to perform.
65 @param Type Operation type could be memory or I/O.
66 @param Width Signifies the width of the memory or I/O operations.
67 @param Count The number of memory or I/O operations to perform.
68 @param Offset The offset within the PCI configuration space for the PCI controller.
69
70 @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.
71 @retval EFI_SUCCESS Successfully verified.
72
73 **/
74 EFI_STATUS
75 PciIoVerifyBarAccess (
76 IN PCI_IO_DEVICE *PciIoDevice,
77 IN UINT8 BarIndex,
78 IN PCI_BAR_TYPE Type,
79 IN IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
80 IN IN UINTN Count,
81 IN UINT64 *Offset
82 )
83 {
84 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
89 return EFI_SUCCESS;
90 }
91
92 //
93 // BarIndex 0-5 is legal
94 //
95 if (BarIndex >= PCI_MAX_BAR) {
96 return EFI_INVALID_PARAMETER;
97 }
98
99 if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
100 return EFI_INVALID_PARAMETER;
101 }
102
103 //
104 // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
105 // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
106 //
107 if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
108 Count = 1;
109 }
110
111 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
112
113 if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
114 return EFI_INVALID_PARAMETER;
115 }
116
117 *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
118
119 return EFI_SUCCESS;
120 }
121
122 /**
123 Verifies access to a PCI Configuration Header.
124
125 @param PciIoDevice Pci device instance.
126 @param Width Signifies the width of the memory or I/O operations.
127 @param Count The number of memory or I/O operations to perform.
128 @param Offset The offset within the PCI configuration space for the PCI controller.
129
130 @retval EFI_INVALID_PARAMETER Invalid Width
131 @retval EFI_UNSUPPORTED Offset overflowed.
132 @retval EFI_SUCCESS Successfully verified.
133
134 **/
135 EFI_STATUS
136 PciIoVerifyConfigAccess (
137 IN PCI_IO_DEVICE *PciIoDevice,
138 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
139 IN UINTN Count,
140 IN UINT64 *Offset
141 )
142 {
143 UINT64 ExtendOffset;
144
145 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
146 return EFI_INVALID_PARAMETER;
147 }
148
149 //
150 // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
151 //
152 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
153
154 if (PciIoDevice->IsPciExp) {
155 if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
156 return EFI_UNSUPPORTED;
157 }
158
159 ExtendOffset = LShiftU64 (*Offset, 32);
160 *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
161 *Offset = (*Offset) | ExtendOffset;
162
163 } else {
164 if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
165 return EFI_UNSUPPORTED;
166 }
167
168 *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
169 }
170
171 return EFI_SUCCESS;
172 }
173
174 /**
175 Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
176 satisfied or after a defined duration.
177
178 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
179 @param Width Signifies the width of the memory or I/O operations.
180 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
181 base address for the memory operation to perform.
182 @param Offset The offset within the selected BAR to start the memory operation.
183 @param Mask Mask used for the polling criteria.
184 @param Value The comparison value used for the polling exit criteria.
185 @param Delay The number of 100 ns units to poll.
186 @param Result Pointer to the last value read from the memory location.
187
188 @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
189 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
190 @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
191 @retval EFI_TIMEOUT Delay expired before a match occurred.
192 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
193 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
194
195 **/
196 EFI_STATUS
197 EFIAPI
198 PciIoPollMem (
199 IN EFI_PCI_IO_PROTOCOL *This,
200 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
201 IN UINT8 BarIndex,
202 IN UINT64 Offset,
203 IN UINT64 Mask,
204 IN UINT64 Value,
205 IN UINT64 Delay,
206 OUT UINT64 *Result
207 )
208 {
209 EFI_STATUS Status;
210 PCI_IO_DEVICE *PciIoDevice;
211
212 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
213
214 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
215 return EFI_INVALID_PARAMETER;
216 }
217
218 Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
219 if (EFI_ERROR (Status)) {
220 return EFI_UNSUPPORTED;
221 }
222
223 if (Width > EfiPciIoWidthUint64) {
224 return EFI_INVALID_PARAMETER;
225 }
226
227 //
228 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
229 //
230 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
231 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
232 Status = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
233 if (EFI_ERROR (Status)) {
234 return Status;
235 }
236 if ((*Result & Mask) == Value || Delay == 0) {
237 return EFI_SUCCESS;
238 }
239 do {
240 //
241 // Stall 10 us = 100 * 100ns
242 //
243 gBS->Stall (10);
244
245 Status = PciIoMemRead (This, Width, BarIndex, Offset, 1, Result);
246 if (EFI_ERROR (Status)) {
247 return Status;
248 }
249 if ((*Result & Mask) == Value) {
250 return EFI_SUCCESS;
251 }
252 if (Delay <= 100) {
253 return EFI_TIMEOUT;
254 }
255 Delay -= 100;
256 } while (TRUE);
257 }
258 }
259
260 Status = PciIoDevice->PciRootBridgeIo->PollMem (
261 PciIoDevice->PciRootBridgeIo,
262 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
263 Offset,
264 Mask,
265 Value,
266 Delay,
267 Result
268 );
269
270 if (EFI_ERROR (Status)) {
271 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
272 EFI_ERROR_CODE | EFI_ERROR_MINOR,
273 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
274 PciIoDevice->DevicePath
275 );
276 }
277
278 return Status;
279 }
280
281 /**
282 Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
283 satisfied or after a defined duration.
284
285 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
286 @param Width Signifies the width of the memory or I/O operations.
287 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
288 base address for the memory operation to perform.
289 @param Offset The offset within the selected BAR to start the memory operation.
290 @param Mask Mask used for the polling criteria.
291 @param Value The comparison value used for the polling exit criteria.
292 @param Delay The number of 100 ns units to poll.
293 @param Result Pointer to the last value read from the memory location.
294
295 @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
296 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
297 @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
298 @retval EFI_TIMEOUT Delay expired before a match occurred.
299 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
300 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
301
302 **/
303 EFI_STATUS
304 EFIAPI
305 PciIoPollIo (
306 IN EFI_PCI_IO_PROTOCOL *This,
307 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
308 IN UINT8 BarIndex,
309 IN UINT64 Offset,
310 IN UINT64 Mask,
311 IN UINT64 Value,
312 IN UINT64 Delay,
313 OUT UINT64 *Result
314 )
315 {
316 EFI_STATUS Status;
317 PCI_IO_DEVICE *PciIoDevice;
318
319 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
320
321 if ((UINT32)Width > EfiPciIoWidthUint64) {
322 return EFI_INVALID_PARAMETER;
323 }
324
325 Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
326 if (EFI_ERROR (Status)) {
327 return EFI_UNSUPPORTED;
328 }
329
330 //
331 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
332 //
333 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
334 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
335 Status = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
336 if (EFI_ERROR (Status)) {
337 return Status;
338 }
339 if ((*Result & Mask) == Value || Delay == 0) {
340 return EFI_SUCCESS;
341 }
342 do {
343 //
344 // Stall 10 us = 100 * 100ns
345 //
346 gBS->Stall (10);
347
348 Status = PciIoIoRead (This, Width, BarIndex, Offset, 1, Result);
349 if (EFI_ERROR (Status)) {
350 return Status;
351 }
352 if ((*Result & Mask) == Value) {
353 return EFI_SUCCESS;
354 }
355 if (Delay <= 100) {
356 return EFI_TIMEOUT;
357 }
358 Delay -= 100;
359 } while (TRUE);
360 }
361 }
362
363 Status = PciIoDevice->PciRootBridgeIo->PollIo (
364 PciIoDevice->PciRootBridgeIo,
365 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
366 Offset,
367 Mask,
368 Value,
369 Delay,
370 Result
371 );
372
373 if (EFI_ERROR (Status)) {
374 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
375 EFI_ERROR_CODE | EFI_ERROR_MINOR,
376 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
377 PciIoDevice->DevicePath
378 );
379 }
380
381 return Status;
382 }
383
384 /**
385 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
386
387 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
388 @param Width Signifies the width of the memory or I/O operations.
389 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
390 base address for the memory or I/O operation to perform.
391 @param Offset The offset within the selected BAR to start the memory or I/O operation.
392 @param Count The number of memory or I/O operations to perform.
393 @param Buffer For read operations, the destination buffer to store the results. For write
394 operations, the source buffer to write data from.
395
396 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
397 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
398 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
399 valid for the PCI BAR specified by BarIndex.
400 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
401 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
402
403 **/
404 EFI_STATUS
405 EFIAPI
406 PciIoMemRead (
407 IN EFI_PCI_IO_PROTOCOL *This,
408 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
409 IN UINT8 BarIndex,
410 IN UINT64 Offset,
411 IN UINTN Count,
412 IN OUT VOID *Buffer
413 )
414 {
415 EFI_STATUS Status;
416 PCI_IO_DEVICE *PciIoDevice;
417
418 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
419
420 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
421 return EFI_INVALID_PARAMETER;
422 }
423
424 if (Buffer == NULL) {
425 return EFI_INVALID_PARAMETER;
426 }
427
428 Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
429 if (EFI_ERROR (Status)) {
430 return EFI_UNSUPPORTED;
431 }
432
433 //
434 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
435 //
436 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
437 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
438 Count *= (UINTN)(1 << (Width & 0x03));
439 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
440 }
441 }
442
443
444 Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
445 PciIoDevice->PciRootBridgeIo,
446 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
447 Offset,
448 Count,
449 Buffer
450 );
451
452 if (EFI_ERROR (Status)) {
453 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
454 EFI_ERROR_CODE | EFI_ERROR_MINOR,
455 EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
456 PciIoDevice->DevicePath
457 );
458 }
459
460 return Status;
461 }
462
463 /**
464 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
465
466 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
467 @param Width Signifies the width of the memory or I/O operations.
468 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
469 base address for the memory or I/O operation to perform.
470 @param Offset The offset within the selected BAR to start the memory or I/O operation.
471 @param Count The number of memory or I/O operations to perform.
472 @param Buffer For read operations, the destination buffer to store the results. For write
473 operations, the source buffer to write data from.
474
475 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
476 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
477 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
478 valid for the PCI BAR specified by BarIndex.
479 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
480 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
481
482 **/
483 EFI_STATUS
484 EFIAPI
485 PciIoMemWrite (
486 IN EFI_PCI_IO_PROTOCOL *This,
487 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
488 IN UINT8 BarIndex,
489 IN UINT64 Offset,
490 IN UINTN Count,
491 IN OUT VOID *Buffer
492 )
493 {
494 EFI_STATUS Status;
495 PCI_IO_DEVICE *PciIoDevice;
496
497 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
498
499 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
500 return EFI_INVALID_PARAMETER;
501 }
502
503 if (Buffer == NULL) {
504 return EFI_INVALID_PARAMETER;
505 }
506
507 Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
508 if (EFI_ERROR (Status)) {
509 return EFI_UNSUPPORTED;
510 }
511
512 //
513 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
514 //
515 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
516 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
517 Count *= (UINTN)(1 << (Width & 0x03));
518 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
519 }
520 }
521
522 Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
523 PciIoDevice->PciRootBridgeIo,
524 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
525 Offset,
526 Count,
527 Buffer
528 );
529
530 if (EFI_ERROR (Status)) {
531 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
532 EFI_ERROR_CODE | EFI_ERROR_MINOR,
533 EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
534 PciIoDevice->DevicePath
535 );
536 }
537
538 return Status;
539 }
540
541 /**
542 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
543
544 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
545 @param Width Signifies the width of the memory or I/O operations.
546 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
547 base address for the memory or I/O operation to perform.
548 @param Offset The offset within the selected BAR to start the memory or I/O operation.
549 @param Count The number of memory or I/O operations to perform.
550 @param Buffer For read operations, the destination buffer to store the results. For write
551 operations, the source buffer to write data from.
552
553 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
554 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
555 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
556 valid for the PCI BAR specified by BarIndex.
557 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
558 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
559
560 **/
561 EFI_STATUS
562 EFIAPI
563 PciIoIoRead (
564 IN EFI_PCI_IO_PROTOCOL *This,
565 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
566 IN UINT8 BarIndex,
567 IN UINT64 Offset,
568 IN UINTN Count,
569 IN OUT VOID *Buffer
570 )
571 {
572 EFI_STATUS Status;
573 PCI_IO_DEVICE *PciIoDevice;
574
575 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
576
577 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
578 return EFI_INVALID_PARAMETER;
579 }
580
581 if (Buffer == NULL) {
582 return EFI_INVALID_PARAMETER;
583 }
584
585 Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
586 if (EFI_ERROR (Status)) {
587 return EFI_UNSUPPORTED;
588 }
589
590 //
591 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
592 //
593 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
594 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
595 Count *= (UINTN)(1 << (Width & 0x03));
596 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
597 }
598 }
599
600 Status = PciIoDevice->PciRootBridgeIo->Io.Read (
601 PciIoDevice->PciRootBridgeIo,
602 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
603 Offset,
604 Count,
605 Buffer
606 );
607
608 if (EFI_ERROR (Status)) {
609 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
610 EFI_ERROR_CODE | EFI_ERROR_MINOR,
611 EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
612 PciIoDevice->DevicePath
613 );
614 }
615
616 return Status;
617 }
618
619 /**
620 Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
621
622 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
623 @param Width Signifies the width of the memory or I/O operations.
624 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
625 base address for the memory or I/O operation to perform.
626 @param Offset The offset within the selected BAR to start the memory or I/O operation.
627 @param Count The number of memory or I/O operations to perform.
628 @param Buffer For read operations, the destination buffer to store the results. For write
629 operations, the source buffer to write data from.
630
631 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
632 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
633 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
634 valid for the PCI BAR specified by BarIndex.
635 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
636 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
637
638 **/
639 EFI_STATUS
640 EFIAPI
641 PciIoIoWrite (
642 IN EFI_PCI_IO_PROTOCOL *This,
643 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
644 IN UINT8 BarIndex,
645 IN UINT64 Offset,
646 IN UINTN Count,
647 IN OUT VOID *Buffer
648 )
649 {
650 EFI_STATUS Status;
651 PCI_IO_DEVICE *PciIoDevice;
652
653 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
654
655 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
656 return EFI_INVALID_PARAMETER;
657 }
658
659 if (Buffer == NULL) {
660 return EFI_INVALID_PARAMETER;
661 }
662
663 Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
664 if (EFI_ERROR (Status)) {
665 return EFI_UNSUPPORTED;
666 }
667
668 //
669 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
670 //
671 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
672 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
673 Count *= (UINTN)(1 << (Width & 0x03));
674 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
675 }
676 }
677
678 Status = PciIoDevice->PciRootBridgeIo->Io.Write (
679 PciIoDevice->PciRootBridgeIo,
680 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
681 Offset,
682 Count,
683 Buffer
684 );
685
686 if (EFI_ERROR (Status)) {
687 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
688 EFI_ERROR_CODE | EFI_ERROR_MINOR,
689 EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
690 PciIoDevice->DevicePath
691 );
692 }
693
694 return Status;
695 }
696
697 /**
698 Enable a PCI driver to access PCI controller registers in PCI configuration space.
699
700 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
701 @param Width Signifies the width of the memory operations.
702 @param Offset The offset within the PCI configuration space for the PCI controller.
703 @param Count The number of PCI configuration operations to perform.
704 @param Buffer For read operations, the destination buffer to store the results. For write
705 operations, the source buffer to write data from.
706
707
708 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
709 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
710 valid for the PCI configuration header of the PCI controller.
711 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
712 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
713
714 **/
715 EFI_STATUS
716 EFIAPI
717 PciIoConfigRead (
718 IN EFI_PCI_IO_PROTOCOL *This,
719 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
720 IN UINT32 Offset,
721 IN UINTN Count,
722 IN OUT VOID *Buffer
723 )
724 {
725 EFI_STATUS Status;
726 PCI_IO_DEVICE *PciIoDevice;
727 UINT64 Address;
728
729 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
730
731 Address = Offset;
732 Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
733 if (EFI_ERROR (Status)) {
734 return Status;
735 }
736
737 //
738 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
739 //
740 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
741 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
742 Count *= (UINTN)(1 << (Width & 0x03));
743 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
744 }
745 }
746
747 Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
748 PciIoDevice->PciRootBridgeIo,
749 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
750 Address,
751 Count,
752 Buffer
753 );
754
755 if (EFI_ERROR (Status)) {
756 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
757 EFI_ERROR_CODE | EFI_ERROR_MINOR,
758 EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR,
759 PciIoDevice->DevicePath
760 );
761 }
762
763 return Status;
764 }
765
766 /**
767 Enable a PCI driver to access PCI controller registers in PCI configuration space.
768
769 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
770 @param Width Signifies the width of the memory operations.
771 @param Offset The offset within the PCI configuration space for the PCI controller.
772 @param Count The number of PCI configuration operations to perform.
773 @param Buffer For read operations, the destination buffer to store the results. For write
774 operations, the source buffer to write data from.
775
776
777 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
778 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
779 valid for the PCI configuration header of the PCI controller.
780 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
781 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
782
783 **/
784 EFI_STATUS
785 EFIAPI
786 PciIoConfigWrite (
787 IN EFI_PCI_IO_PROTOCOL *This,
788 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
789 IN UINT32 Offset,
790 IN UINTN Count,
791 IN OUT VOID *Buffer
792 )
793 {
794 EFI_STATUS Status;
795 PCI_IO_DEVICE *PciIoDevice;
796 UINT64 Address;
797
798 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
799
800 Address = Offset;
801 Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
802 if (EFI_ERROR (Status)) {
803 return Status;
804 }
805
806 //
807 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
808 //
809 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
810 if ((Offset & ((1 << (Width & 0x03)) - 1)) != 0) {
811 Count *= (UINTN)(1 << (Width & 0x03));
812 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
813 }
814 }
815
816 Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
817 PciIoDevice->PciRootBridgeIo,
818 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
819 Address,
820 Count,
821 Buffer
822 );
823
824 if (EFI_ERROR (Status)) {
825 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
826 EFI_ERROR_CODE | EFI_ERROR_MINOR,
827 EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR,
828 PciIoDevice->DevicePath
829 );
830 }
831
832 return Status;
833 }
834
835 /**
836 Enables a PCI driver to copy one region of PCI memory space to another region of PCI
837 memory space.
838
839 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
840 @param Width Signifies the width of the memory operations.
841 @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
842 base address for the memory operation to perform.
843 @param DestOffset The destination offset within the BAR specified by DestBarIndex to
844 start the memory writes for the copy operation.
845 @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
846 base address for the memory operation to perform.
847 @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
848 the memory reads for the copy operation.
849 @param Count The number of memory operations to perform. Bytes moved is Width
850 size * Count, starting at DestOffset and SrcOffset.
851
852 @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
853 @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
854 @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
855 @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
856 is not valid for the PCI BAR specified by DestBarIndex.
857 @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
858 not valid for the PCI BAR specified by SrcBarIndex.
859 @retval EFI_INVALID_PARAMETER Width is invalid.
860 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
861
862 **/
863 EFI_STATUS
864 EFIAPI
865 PciIoCopyMem (
866 IN EFI_PCI_IO_PROTOCOL *This,
867 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
868 IN UINT8 DestBarIndex,
869 IN UINT64 DestOffset,
870 IN UINT8 SrcBarIndex,
871 IN UINT64 SrcOffset,
872 IN UINTN Count
873 )
874 {
875 EFI_STATUS Status;
876 PCI_IO_DEVICE *PciIoDevice;
877
878 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
879
880 if ((UINT32)Width >= EfiPciIoWidthMaximum) {
881 return EFI_INVALID_PARAMETER;
882 }
883
884 if (Width == EfiPciIoWidthFifoUint8 ||
885 Width == EfiPciIoWidthFifoUint16 ||
886 Width == EfiPciIoWidthFifoUint32 ||
887 Width == EfiPciIoWidthFifoUint64 ||
888 Width == EfiPciIoWidthFillUint8 ||
889 Width == EfiPciIoWidthFillUint16 ||
890 Width == EfiPciIoWidthFillUint32 ||
891 Width == EfiPciIoWidthFillUint64) {
892 return EFI_INVALID_PARAMETER;
893 }
894
895 Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
896 if (EFI_ERROR (Status)) {
897 return EFI_UNSUPPORTED;
898 }
899
900 Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
901 if (EFI_ERROR (Status)) {
902 return EFI_UNSUPPORTED;
903 }
904
905 //
906 // If request is not aligned, then convert request to EfiPciIoWithXXXUint8
907 //
908 if (FeaturePcdGet (PcdUnalignedPciIoEnable)) {
909 if ((SrcOffset & ((1 << (Width & 0x03)) - 1)) != 0 || (DestOffset & ((1 << (Width & 0x03)) - 1)) != 0) {
910 Count *= (UINTN)(1 << (Width & 0x03));
911 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & (~0x03));
912 }
913 }
914
915 Status = PciIoDevice->PciRootBridgeIo->CopyMem (
916 PciIoDevice->PciRootBridgeIo,
917 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
918 DestOffset,
919 SrcOffset,
920 Count
921 );
922
923 if (EFI_ERROR (Status)) {
924 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
925 EFI_ERROR_CODE | EFI_ERROR_MINOR,
926 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
927 PciIoDevice->DevicePath
928 );
929 }
930
931 return Status;
932 }
933
934 /**
935 Provides the PCI controller-specific addresses needed to access system memory.
936
937 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
938 @param Operation Indicates if the bus master is going to read or write to system memory.
939 @param HostAddress The system memory address to map to the PCI controller.
940 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
941 that were mapped.
942 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
943 access the hosts HostAddress.
944 @param Mapping A resulting value to pass to Unmap().
945
946 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
947 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
948 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
949 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
950 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
951
952 **/
953 EFI_STATUS
954 EFIAPI
955 PciIoMap (
956 IN EFI_PCI_IO_PROTOCOL *This,
957 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
958 IN VOID *HostAddress,
959 IN OUT UINTN *NumberOfBytes,
960 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
961 OUT VOID **Mapping
962 )
963 {
964 EFI_STATUS Status;
965 PCI_IO_DEVICE *PciIoDevice;
966 UINT64 IoMmuAttribute;
967 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION RootBridgeIoOperation;
968
969 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
970
971 if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
972 return EFI_INVALID_PARAMETER;
973 }
974
975 if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
976 return EFI_INVALID_PARAMETER;
977 }
978
979 RootBridgeIoOperation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)Operation;
980 if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
981 RootBridgeIoOperation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION)(Operation + EfiPciOperationBusMasterRead64);
982 }
983
984 Status = PciIoDevice->PciRootBridgeIo->Map (
985 PciIoDevice->PciRootBridgeIo,
986 RootBridgeIoOperation,
987 HostAddress,
988 NumberOfBytes,
989 DeviceAddress,
990 Mapping
991 );
992
993 if (EFI_ERROR (Status)) {
994 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
995 EFI_ERROR_CODE | EFI_ERROR_MINOR,
996 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
997 PciIoDevice->DevicePath
998 );
999 }
1000
1001 if (mIoMmuProtocol != NULL) {
1002 if (!EFI_ERROR (Status)) {
1003 switch (Operation) {
1004 case EfiPciIoOperationBusMasterRead:
1005 IoMmuAttribute = EDKII_IOMMU_ACCESS_READ;
1006 break;
1007 case EfiPciIoOperationBusMasterWrite:
1008 IoMmuAttribute = EDKII_IOMMU_ACCESS_WRITE;
1009 break;
1010 case EfiPciIoOperationBusMasterCommonBuffer:
1011 IoMmuAttribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
1012 break;
1013 default:
1014 ASSERT(FALSE);
1015 return EFI_INVALID_PARAMETER;
1016 }
1017 mIoMmuProtocol->SetAttribute (
1018 mIoMmuProtocol,
1019 PciIoDevice->Handle,
1020 *Mapping,
1021 IoMmuAttribute
1022 );
1023 }
1024 }
1025
1026 return Status;
1027 }
1028
1029 /**
1030 Completes the Map() operation and releases any corresponding resources.
1031
1032 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1033 @param Mapping The mapping value returned from Map().
1034
1035 @retval EFI_SUCCESS The range was unmapped.
1036 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
1037
1038 **/
1039 EFI_STATUS
1040 EFIAPI
1041 PciIoUnmap (
1042 IN EFI_PCI_IO_PROTOCOL *This,
1043 IN VOID *Mapping
1044 )
1045 {
1046 EFI_STATUS Status;
1047 PCI_IO_DEVICE *PciIoDevice;
1048
1049 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1050
1051 if (mIoMmuProtocol != NULL) {
1052 mIoMmuProtocol->SetAttribute (
1053 mIoMmuProtocol,
1054 PciIoDevice->Handle,
1055 Mapping,
1056 0
1057 );
1058 }
1059
1060 Status = PciIoDevice->PciRootBridgeIo->Unmap (
1061 PciIoDevice->PciRootBridgeIo,
1062 Mapping
1063 );
1064
1065 if (EFI_ERROR (Status)) {
1066 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1067 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1068 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
1069 PciIoDevice->DevicePath
1070 );
1071 }
1072
1073 return Status;
1074 }
1075
1076 /**
1077 Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
1078 or EfiPciOperationBusMasterCommonBuffer64 mapping.
1079
1080 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1081 @param Type This parameter is not used and must be ignored.
1082 @param MemoryType The type of memory to allocate, EfiBootServicesData or
1083 EfiRuntimeServicesData.
1084 @param Pages The number of pages to allocate.
1085 @param HostAddress A pointer to store the base system memory address of the
1086 allocated range.
1087 @param Attributes The requested bit mask of attributes for the allocated range.
1088
1089 @retval EFI_SUCCESS The requested memory pages were allocated.
1090 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
1091 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
1092 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1093 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1094
1095 **/
1096 EFI_STATUS
1097 EFIAPI
1098 PciIoAllocateBuffer (
1099 IN EFI_PCI_IO_PROTOCOL *This,
1100 IN EFI_ALLOCATE_TYPE Type,
1101 IN EFI_MEMORY_TYPE MemoryType,
1102 IN UINTN Pages,
1103 OUT VOID **HostAddress,
1104 IN UINT64 Attributes
1105 )
1106 {
1107 EFI_STATUS Status;
1108 PCI_IO_DEVICE *PciIoDevice;
1109
1110 if ((Attributes &
1111 (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) != 0){
1112 return EFI_UNSUPPORTED;
1113 }
1114
1115 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1116
1117 if ((PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) != 0) {
1118 Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
1119 }
1120
1121 Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
1122 PciIoDevice->PciRootBridgeIo,
1123 Type,
1124 MemoryType,
1125 Pages,
1126 HostAddress,
1127 Attributes
1128 );
1129
1130 if (EFI_ERROR (Status)) {
1131 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1132 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1133 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
1134 PciIoDevice->DevicePath
1135 );
1136 }
1137
1138 return Status;
1139 }
1140
1141 /**
1142 Frees memory that was allocated with AllocateBuffer().
1143
1144 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1145 @param Pages The number of pages to free.
1146 @param HostAddress The base system memory address of the allocated range.
1147
1148 @retval EFI_SUCCESS The requested memory pages were freed.
1149 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
1150 was not allocated with AllocateBuffer().
1151
1152 **/
1153 EFI_STATUS
1154 EFIAPI
1155 PciIoFreeBuffer (
1156 IN EFI_PCI_IO_PROTOCOL *This,
1157 IN UINTN Pages,
1158 IN VOID *HostAddress
1159 )
1160 {
1161 EFI_STATUS Status;
1162 PCI_IO_DEVICE *PciIoDevice;
1163
1164 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1165
1166 Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
1167 PciIoDevice->PciRootBridgeIo,
1168 Pages,
1169 HostAddress
1170 );
1171
1172 if (EFI_ERROR (Status)) {
1173 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1174 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1175 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
1176 PciIoDevice->DevicePath
1177 );
1178 }
1179
1180 return Status;
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 @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
1189 bridge to system memory.
1190 @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
1191 host bridge due to a hardware error.
1192
1193 **/
1194 EFI_STATUS
1195 EFIAPI
1196 PciIoFlush (
1197 IN EFI_PCI_IO_PROTOCOL *This
1198 )
1199 {
1200 EFI_STATUS Status;
1201 PCI_IO_DEVICE *PciIoDevice;
1202
1203 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1204
1205 Status = PciIoDevice->PciRootBridgeIo->Flush (
1206 PciIoDevice->PciRootBridgeIo
1207 );
1208 if (EFI_ERROR (Status)) {
1209 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1210 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1211 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
1212 PciIoDevice->DevicePath
1213 );
1214 }
1215
1216 return Status;
1217 }
1218
1219 /**
1220 Retrieves this PCI controller's current PCI bus number, device number, and function number.
1221
1222 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1223 @param SegmentNumber The PCI controller's current PCI segment number.
1224 @param BusNumber The PCI controller's current PCI bus number.
1225 @param DeviceNumber The PCI controller's current PCI device number.
1226 @param FunctionNumber The PCI controller's current PCI function number.
1227
1228 @retval EFI_SUCCESS The PCI controller location was returned.
1229 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1230
1231 **/
1232 EFI_STATUS
1233 EFIAPI
1234 PciIoGetLocation (
1235 IN EFI_PCI_IO_PROTOCOL *This,
1236 OUT UINTN *Segment,
1237 OUT UINTN *Bus,
1238 OUT UINTN *Device,
1239 OUT UINTN *Function
1240 )
1241 {
1242 PCI_IO_DEVICE *PciIoDevice;
1243
1244 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1245
1246 if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
1247 return EFI_INVALID_PARAMETER;
1248 }
1249
1250 *Segment = PciIoDevice->PciRootBridgeIo->SegmentNumber;
1251 *Bus = PciIoDevice->BusNumber;
1252 *Device = PciIoDevice->DeviceNumber;
1253 *Function = PciIoDevice->FunctionNumber;
1254
1255 return EFI_SUCCESS;
1256 }
1257
1258 /**
1259 Check BAR type for PCI resource.
1260
1261 @param PciIoDevice PCI device instance.
1262 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
1263 base address for the memory or I/O operation to perform.
1264 @param BarType Memory or I/O.
1265
1266 @retval TRUE Pci device's bar type is same with input BarType.
1267 @retval TRUE Pci device's bar type is not same with input BarType.
1268
1269 **/
1270 BOOLEAN
1271 CheckBarType (
1272 IN PCI_IO_DEVICE *PciIoDevice,
1273 IN UINT8 BarIndex,
1274 IN PCI_BAR_TYPE BarType
1275 )
1276 {
1277 switch (BarType) {
1278
1279 case PciBarTypeMem:
1280
1281 if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32 &&
1282 PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
1283 PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
1284 PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64 ) {
1285 return FALSE;
1286 }
1287
1288 return TRUE;
1289
1290 case PciBarTypeIo:
1291 if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
1292 PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
1293 return FALSE;
1294 }
1295
1296 return TRUE;
1297
1298 default:
1299 break;
1300 }
1301
1302 return FALSE;
1303 }
1304
1305 /**
1306 Set/Disable new attributes to a Root Bridge.
1307
1308 @param PciIoDevice Pci device instance.
1309 @param Attributes New attribute want to be set.
1310 @param Operation Set or Disable.
1311
1312 @retval EFI_UNSUPPORTED If root bridge does not support change attribute.
1313 @retval EFI_SUCCESS Successfully set new attributes.
1314
1315 **/
1316 EFI_STATUS
1317 ModifyRootBridgeAttributes (
1318 IN PCI_IO_DEVICE *PciIoDevice,
1319 IN UINT64 Attributes,
1320 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
1321 )
1322 {
1323 UINT64 PciRootBridgeSupports;
1324 UINT64 PciRootBridgeAttributes;
1325 UINT64 NewPciRootBridgeAttributes;
1326 EFI_STATUS Status;
1327
1328 //
1329 // Get the current attributes of this PCI device's PCI Root Bridge
1330 //
1331 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
1332 PciIoDevice->PciRootBridgeIo,
1333 &PciRootBridgeSupports,
1334 &PciRootBridgeAttributes
1335 );
1336 if (EFI_ERROR (Status)) {
1337 return EFI_UNSUPPORTED;
1338 }
1339
1340 //
1341 // Mask off attributes not supported by PCI root bridge.
1342 //
1343 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
1344 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
1345 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
1346
1347 //
1348 // Record the new attribute of the Root Bridge
1349 //
1350 if (Operation == EfiPciIoAttributeOperationEnable) {
1351 NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;
1352 } else {
1353 NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);
1354 }
1355
1356 //
1357 // Call the PCI Root Bridge to attempt to modify the attributes
1358 //
1359 if ((NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) != 0) {
1360
1361 Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
1362 PciIoDevice->PciRootBridgeIo,
1363 NewPciRootBridgeAttributes,
1364 NULL,
1365 NULL
1366 );
1367 if (EFI_ERROR (Status)) {
1368 //
1369 // The PCI Root Bridge could not modify the attributes, so return the error.
1370 //
1371 return EFI_UNSUPPORTED;
1372 }
1373 }
1374
1375 //
1376 // Also update the attributes for this Root Bridge structure
1377 //
1378 PciIoDevice->Attributes = NewPciRootBridgeAttributes;
1379
1380 return EFI_SUCCESS;
1381 }
1382
1383 /**
1384 Check whether this device can be enable/disable to snoop.
1385
1386 @param PciIoDevice Pci device instance.
1387 @param Operation Enable/Disable.
1388
1389 @retval EFI_UNSUPPORTED Pci device is not GFX device or not support snoop.
1390 @retval EFI_SUCCESS Snoop can be supported.
1391
1392 **/
1393 EFI_STATUS
1394 SupportPaletteSnoopAttributes (
1395 IN PCI_IO_DEVICE *PciIoDevice,
1396 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
1397 )
1398 {
1399 PCI_IO_DEVICE *Temp;
1400 UINT16 VGACommand;
1401
1402 //
1403 // Snoop attribute can be only modified by GFX
1404 //
1405 if (!IS_PCI_GFX (&PciIoDevice->Pci)) {
1406 return EFI_UNSUPPORTED;
1407 }
1408
1409 //
1410 // Get the boot VGA on the same Host Bridge
1411 //
1412 Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo->ParentHandle);
1413
1414 if (Temp == NULL) {
1415 //
1416 // If there is no VGA device on the segment, set
1417 // this graphics card to decode the palette range
1418 //
1419 return EFI_SUCCESS;
1420 }
1421
1422 //
1423 // Check these two agents are on the same path
1424 //
1425 if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {
1426 //
1427 // they are not on the same path, so snoop can be enabled or disabled
1428 //
1429 return EFI_SUCCESS;
1430 }
1431 //
1432 // Check if they are on the same bus
1433 //
1434 if (Temp->Parent == PciIoDevice->Parent) {
1435
1436 PCI_READ_COMMAND_REGISTER (Temp, &VGACommand);
1437
1438 //
1439 // If they are on the same bus, either one can
1440 // be set to snoop, the other set to decode
1441 //
1442 if ((VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
1443 //
1444 // VGA has set to snoop, so GFX can be only set to disable snoop
1445 //
1446 if (Operation == EfiPciIoAttributeOperationEnable) {
1447 return EFI_UNSUPPORTED;
1448 }
1449 } else {
1450 //
1451 // VGA has disabled to snoop, so GFX can be only enabled
1452 //
1453 if (Operation == EfiPciIoAttributeOperationDisable) {
1454 return EFI_UNSUPPORTED;
1455 }
1456 }
1457
1458 return EFI_SUCCESS;
1459 }
1460
1461 //
1462 // If they are on the same path but on the different bus
1463 // The first agent is set to snoop, the second one set to
1464 // decode
1465 //
1466
1467 if (Temp->BusNumber < PciIoDevice->BusNumber) {
1468 //
1469 // GFX should be set to decode
1470 //
1471 if (Operation == EfiPciIoAttributeOperationDisable) {
1472 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
1473 Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1474 } else {
1475 return EFI_UNSUPPORTED;
1476 }
1477
1478 } else {
1479 //
1480 // GFX should be set to snoop
1481 //
1482 if (Operation == EfiPciIoAttributeOperationEnable) {
1483 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
1484 Temp->Attributes &= (~(UINT64)EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
1485 } else {
1486 return EFI_UNSUPPORTED;
1487 }
1488
1489 }
1490
1491 return EFI_SUCCESS;
1492 }
1493
1494 /**
1495 Performs an operation on the attributes that this PCI controller supports. The operations include
1496 getting the set of supported attributes, retrieving the current attributes, setting the current
1497 attributes, enabling attributes, and disabling attributes.
1498
1499 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1500 @param Operation The operation to perform on the attributes for this PCI controller.
1501 @param Attributes The mask of attributes that are used for Set, Enable, and Disable
1502 operations.
1503 @param Result A pointer to the result mask of attributes that are returned for the Get
1504 and Supported operations.
1505
1506 @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
1507 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1508 @retval EFI_UNSUPPORTED one or more of the bits set in
1509 Attributes are not supported by this PCI controller or one of
1510 its parent bridges when Operation is Set, Enable or Disable.
1511
1512 **/
1513 EFI_STATUS
1514 EFIAPI
1515 PciIoAttributes (
1516 IN EFI_PCI_IO_PROTOCOL * This,
1517 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
1518 IN UINT64 Attributes,
1519 OUT UINT64 *Result OPTIONAL
1520 )
1521 {
1522 EFI_STATUS Status;
1523
1524 PCI_IO_DEVICE *PciIoDevice;
1525 PCI_IO_DEVICE *UpStreamBridge;
1526 PCI_IO_DEVICE *Temp;
1527
1528 UINT64 Supports;
1529 UINT64 UpStreamAttributes;
1530 UINT16 BridgeControl;
1531 UINT16 Command;
1532
1533 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1534
1535 switch (Operation) {
1536 case EfiPciIoAttributeOperationGet:
1537 if (Result == NULL) {
1538 return EFI_INVALID_PARAMETER;
1539 }
1540
1541 *Result = PciIoDevice->Attributes;
1542 return EFI_SUCCESS;
1543
1544 case EfiPciIoAttributeOperationSupported:
1545 if (Result == NULL) {
1546 return EFI_INVALID_PARAMETER;
1547 }
1548
1549 *Result = PciIoDevice->Supports;
1550 return EFI_SUCCESS;
1551
1552 case EfiPciIoAttributeOperationSet:
1553 Status = PciIoDevice->PciIo.Attributes (
1554 &(PciIoDevice->PciIo),
1555 EfiPciIoAttributeOperationEnable,
1556 Attributes,
1557 NULL
1558 );
1559 if (EFI_ERROR (Status)) {
1560 return EFI_UNSUPPORTED;
1561 }
1562
1563 Status = PciIoDevice->PciIo.Attributes (
1564 &(PciIoDevice->PciIo),
1565 EfiPciIoAttributeOperationDisable,
1566 (~Attributes) & (PciIoDevice->Supports),
1567 NULL
1568 );
1569 if (EFI_ERROR (Status)) {
1570 return EFI_UNSUPPORTED;
1571 }
1572
1573 return EFI_SUCCESS;
1574
1575 case EfiPciIoAttributeOperationEnable:
1576 case EfiPciIoAttributeOperationDisable:
1577 break;
1578
1579 default:
1580 return EFI_INVALID_PARAMETER;
1581 }
1582 //
1583 // Just a trick for ENABLE attribute
1584 // EFI_PCI_DEVICE_ENABLE is not defined in UEFI spec, which is the internal usage.
1585 // So, this logic doesn't conform to UEFI spec, which should be removed.
1586 // But this trick logic is still kept for some binary drivers that depend on it.
1587 //
1588 if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {
1589 Attributes &= (PciIoDevice->Supports);
1590
1591 //
1592 // Raise the EFI_P_PC_ENABLE Status code
1593 //
1594 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1595 EFI_PROGRESS_CODE,
1596 EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,
1597 PciIoDevice->DevicePath
1598 );
1599 }
1600
1601 //
1602 // Check VGA and VGA16, they can not be set at the same time
1603 //
1604 if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) != 0) {
1605 if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
1606 return EFI_UNSUPPORTED;
1607 }
1608 }
1609
1610 //
1611 // If no attributes can be supported, then return.
1612 // Otherwise, set the attributes that it can support.
1613 //
1614 Supports = (PciIoDevice->Supports) & Attributes;
1615 if (Supports != Attributes) {
1616 return EFI_UNSUPPORTED;
1617 }
1618
1619 //
1620 // For Root Bridge, just call RootBridgeIo to set attributes;
1621 //
1622 if (PciIoDevice->Parent == NULL) {
1623 Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes, Operation);
1624 return Status;
1625 }
1626
1627 Command = 0;
1628 BridgeControl = 0;
1629
1630 //
1631 // For PPB & P2C, set relevant attribute bits
1632 //
1633 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1634
1635 if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
1636 BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;
1637 }
1638
1639 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) != 0) {
1640 BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;
1641 }
1642
1643 if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
1644 Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
1645 }
1646
1647 if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
1648 BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA_16;
1649 }
1650
1651 } else {
1652 //
1653 // Do with the attributes on VGA
1654 // Only for VGA's legacy resource, we just can enable once.
1655 //
1656 if ((Attributes &
1657 (EFI_PCI_IO_ATTRIBUTE_VGA_IO |
1658 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |
1659 EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY)) != 0) {
1660 //
1661 // Check if a VGA has been enabled before enabling a new one
1662 //
1663 if (Operation == EfiPciIoAttributeOperationEnable) {
1664 //
1665 // Check if there have been an active VGA device on the same Host Bridge
1666 //
1667 Temp = LocateVgaDeviceOnHostBridge (PciIoDevice->PciRootBridgeIo->ParentHandle);
1668 if (Temp != NULL && Temp != PciIoDevice) {
1669 //
1670 // An active VGA has been detected, so can not enable another
1671 //
1672 return EFI_UNSUPPORTED;
1673 }
1674 }
1675 }
1676
1677 //
1678 // Do with the attributes on GFX
1679 //
1680 if ((Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) != 0) {
1681
1682 if (Operation == EfiPciIoAttributeOperationEnable) {
1683 //
1684 // Check if snoop can be enabled in current configuration
1685 //
1686 Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);
1687
1688 if (EFI_ERROR (Status)) {
1689
1690 //
1691 // Enable operation is forbidden, so mask the bit in attributes
1692 // so as to keep consistent with the actual Status
1693 //
1694 // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
1695 //
1696 //
1697 //
1698 return EFI_UNSUPPORTED;
1699
1700 }
1701 }
1702
1703 //
1704 // It can be supported, so get ready to set the bit
1705 //
1706 Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1707 }
1708 }
1709
1710 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
1711 Command |= EFI_PCI_COMMAND_IO_SPACE;
1712 }
1713
1714 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) != 0) {
1715 Command |= EFI_PCI_COMMAND_MEMORY_SPACE;
1716 }
1717
1718 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) != 0) {
1719 Command |= EFI_PCI_COMMAND_BUS_MASTER;
1720 }
1721 //
1722 // The upstream bridge should be also set to relevant attribute
1723 // expect for IO, Mem and BusMaster
1724 //
1725 UpStreamAttributes = Attributes &
1726 (~(EFI_PCI_IO_ATTRIBUTE_IO |
1727 EFI_PCI_IO_ATTRIBUTE_MEMORY |
1728 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
1729 )
1730 );
1731 UpStreamBridge = PciIoDevice->Parent;
1732
1733 if (Operation == EfiPciIoAttributeOperationEnable) {
1734 //
1735 // Enable relevant attributes to command register and bridge control register
1736 //
1737 Status = PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, Command);
1738 if (BridgeControl != 0) {
1739 Status = PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
1740 }
1741
1742 PciIoDevice->Attributes |= Attributes;
1743
1744 //
1745 // Enable attributes of the upstream bridge
1746 //
1747 Status = UpStreamBridge->PciIo.Attributes (
1748 &(UpStreamBridge->PciIo),
1749 EfiPciIoAttributeOperationEnable,
1750 UpStreamAttributes,
1751 NULL
1752 );
1753 } else {
1754
1755 //
1756 // Disable relevant attributes to command register and bridge control register
1757 //
1758 Status = PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, Command);
1759 if (BridgeControl != 0) {
1760 Status = PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
1761 }
1762
1763 PciIoDevice->Attributes &= (~Attributes);
1764 Status = EFI_SUCCESS;
1765
1766 }
1767
1768 if (EFI_ERROR (Status)) {
1769 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1770 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1771 EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR,
1772 PciIoDevice->DevicePath
1773 );
1774 }
1775
1776 return Status;
1777 }
1778
1779 /**
1780 Retrieve the AddrTranslationOffset from RootBridgeIo for the
1781 specified range.
1782
1783 @param RootBridgeIo Root Bridge IO instance.
1784 @param AddrRangeMin The base address of the MMIO.
1785 @param AddrLen The length of the MMIO.
1786
1787 @retval The AddrTranslationOffset from RootBridgeIo for the
1788 specified range, or (UINT64) -1 if the range is not
1789 found in RootBridgeIo.
1790 **/
1791 UINT64
1792 GetMmioAddressTranslationOffset (
1793 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo,
1794 UINT64 AddrRangeMin,
1795 UINT64 AddrLen
1796 )
1797 {
1798 EFI_STATUS Status;
1799 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
1800
1801 Status = RootBridgeIo->Configuration (
1802 RootBridgeIo,
1803 (VOID **) &Configuration
1804 );
1805 if (EFI_ERROR (Status)) {
1806 return (UINT64) -1;
1807 }
1808
1809 // According to UEFI 2.7, EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration()
1810 // returns host address instead of device address, while AddrTranslationOffset
1811 // is not zero, and device address = host address + AddrTranslationOffset, so
1812 // we convert host address to device address for range compare.
1813 while (Configuration->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1814 if ((Configuration->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
1815 (Configuration->AddrRangeMin + Configuration->AddrTranslationOffset <= AddrRangeMin) &&
1816 (Configuration->AddrRangeMin + Configuration->AddrLen + Configuration->AddrTranslationOffset >= AddrRangeMin + AddrLen)
1817 ) {
1818 return Configuration->AddrTranslationOffset;
1819 }
1820 Configuration++;
1821 }
1822
1823 //
1824 // The resource occupied by BAR should be in the range reported by RootBridge.
1825 //
1826 ASSERT (FALSE);
1827 return (UINT64) -1;
1828 }
1829
1830 /**
1831 Gets the attributes that this PCI controller supports setting on a BAR using
1832 SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
1833
1834 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1835 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
1836 base address for resource range. The legal range for this field is 0..5.
1837 @param Supports A pointer to the mask of attributes that this PCI controller supports
1838 setting for this BAR with SetBarAttributes().
1839 @param Resources A pointer to the resource descriptors that describe the current
1840 configuration of this BAR of the PCI controller.
1841
1842 @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
1843 controller supports are returned in Supports. If Resources
1844 is not NULL, then the resource descriptors that the PCI
1845 controller is currently using are returned in Resources.
1846 @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
1847 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
1848 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
1849 Resources.
1850
1851 **/
1852 EFI_STATUS
1853 EFIAPI
1854 PciIoGetBarAttributes (
1855 IN EFI_PCI_IO_PROTOCOL * This,
1856 IN UINT8 BarIndex,
1857 OUT UINT64 *Supports, OPTIONAL
1858 OUT VOID **Resources OPTIONAL
1859 )
1860 {
1861 PCI_IO_DEVICE *PciIoDevice;
1862 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
1863 EFI_ACPI_END_TAG_DESCRIPTOR *End;
1864
1865 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1866
1867 if (Supports == NULL && Resources == NULL) {
1868 return EFI_INVALID_PARAMETER;
1869 }
1870
1871 if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
1872 return EFI_UNSUPPORTED;
1873 }
1874
1875 //
1876 // This driver does not support modifications to the WRITE_COMBINE or
1877 // CACHED attributes for BAR ranges.
1878 //
1879 if (Supports != NULL) {
1880 *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
1881 }
1882
1883 if (Resources != NULL) {
1884 Descriptor = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
1885 if (Descriptor == NULL) {
1886 return EFI_OUT_OF_RESOURCES;
1887 }
1888
1889 *Resources = Descriptor;
1890
1891 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
1892 Descriptor->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
1893 Descriptor->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
1894 Descriptor->AddrLen = PciIoDevice->PciBar[BarIndex].Length;
1895 Descriptor->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
1896
1897 switch (PciIoDevice->PciBar[BarIndex].BarType) {
1898 case PciBarTypeIo16:
1899 case PciBarTypeIo32:
1900 //
1901 // Io
1902 //
1903 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
1904 break;
1905
1906 case PciBarTypePMem32:
1907 //
1908 // prefetchable
1909 //
1910 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
1911 //
1912 // Fall through
1913 //
1914 case PciBarTypeMem32:
1915 //
1916 // Mem
1917 //
1918 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1919 //
1920 // 32 bit
1921 //
1922 Descriptor->AddrSpaceGranularity = 32;
1923 break;
1924
1925 case PciBarTypePMem64:
1926 //
1927 // prefetchable
1928 //
1929 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
1930 //
1931 // Fall through
1932 //
1933 case PciBarTypeMem64:
1934 //
1935 // Mem
1936 //
1937 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1938 //
1939 // 64 bit
1940 //
1941 Descriptor->AddrSpaceGranularity = 64;
1942 break;
1943
1944 default:
1945 break;
1946 }
1947
1948 //
1949 // put the checksum
1950 //
1951 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
1952 End->Desc = ACPI_END_TAG_DESCRIPTOR;
1953 End->Checksum = 0;
1954
1955 //
1956 // Get the Address Translation Offset
1957 //
1958 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
1959 Descriptor->AddrTranslationOffset = GetMmioAddressTranslationOffset (
1960 PciIoDevice->PciRootBridgeIo,
1961 Descriptor->AddrRangeMin,
1962 Descriptor->AddrLen
1963 );
1964 if (Descriptor->AddrTranslationOffset == (UINT64) -1) {
1965 FreePool (Descriptor);
1966 return EFI_UNSUPPORTED;
1967 }
1968 }
1969
1970 // According to UEFI spec 2.7, we need return host address for
1971 // PciIo->GetBarAttributes, and host address = device address - translation.
1972 Descriptor->AddrRangeMin -= Descriptor->AddrTranslationOffset;
1973 }
1974
1975 return EFI_SUCCESS;
1976 }
1977
1978 /**
1979 Sets the attributes for a range of a BAR on a PCI controller.
1980
1981 @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
1982 @param Attributes The mask of attributes to set for the resource range specified by
1983 BarIndex, Offset, and Length.
1984 @param BarIndex The BAR index of the standard PCI Configuration header to use as the
1985 base address for resource range. The legal range for this field is 0..5.
1986 @param Offset A pointer to the BAR relative base address of the resource range to be
1987 modified by the attributes specified by Attributes.
1988 @param Length A pointer to the length of the resource range to be modified by the
1989 attributes specified by Attributes.
1990
1991 @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
1992 range specified by BarIndex, Offset, and Length were
1993 set on the PCI controller, and the actual resource range is returned
1994 in Offset and Length.
1995 @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
1996 @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
1997 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
1998 resource range specified by BarIndex, Offset, and
1999 Length.
2000
2001 **/
2002 EFI_STATUS
2003 EFIAPI
2004 PciIoSetBarAttributes (
2005 IN EFI_PCI_IO_PROTOCOL *This,
2006 IN UINT64 Attributes,
2007 IN UINT8 BarIndex,
2008 IN OUT UINT64 *Offset,
2009 IN OUT UINT64 *Length
2010 )
2011 {
2012 EFI_STATUS Status;
2013 PCI_IO_DEVICE *PciIoDevice;
2014 UINT64 NonRelativeOffset;
2015 UINT64 Supports;
2016
2017 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
2018
2019 //
2020 // Make sure Offset and Length are not NULL
2021 //
2022 if (Offset == NULL || Length == NULL) {
2023 return EFI_INVALID_PARAMETER;
2024 }
2025
2026 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
2027 return EFI_UNSUPPORTED;
2028 }
2029 //
2030 // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
2031 // If Attributes is not 0, then return EFI_UNSUPPORTED.
2032 //
2033 Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
2034
2035 if (Attributes != (Attributes & Supports)) {
2036 return EFI_UNSUPPORTED;
2037 }
2038 //
2039 // Attributes must be supported. Make sure the BAR range described by BarIndex, Offset, and
2040 // Length are valid for this PCI device.
2041 //
2042 NonRelativeOffset = *Offset;
2043 Status = PciIoVerifyBarAccess (
2044 PciIoDevice,
2045 BarIndex,
2046 PciBarTypeMem,
2047 EfiPciIoWidthUint8,
2048 (UINT32) *Length,
2049 &NonRelativeOffset
2050 );
2051 if (EFI_ERROR (Status)) {
2052 return EFI_UNSUPPORTED;
2053 }
2054
2055 return EFI_SUCCESS;
2056 }
2057
2058
2059 /**
2060 Test whether two Pci devices has same parent bridge.
2061
2062 @param PciDevice1 The first pci device for testing.
2063 @param PciDevice2 The second pci device for testing.
2064
2065 @retval TRUE Two Pci device has the same parent bridge.
2066 @retval FALSE Two Pci device has not the same parent bridge.
2067
2068 **/
2069 BOOLEAN
2070 PciDevicesOnTheSamePath (
2071 IN PCI_IO_DEVICE *PciDevice1,
2072 IN PCI_IO_DEVICE *PciDevice2
2073 )
2074 {
2075 BOOLEAN Existed1;
2076 BOOLEAN Existed2;
2077
2078 if (PciDevice1->Parent == PciDevice2->Parent) {
2079 return TRUE;
2080 }
2081
2082 Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);
2083 Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);
2084
2085 return (BOOLEAN) (Existed1 || Existed2);
2086 }
2087