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