3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 EFI PC AT PCI Root Bridge Io Protocol
23 #include "PcatPciRootBridge.h"
24 #include <IndustryStandard/Pci.h>
27 #include EFI_GUID_DEFINITION (SalSystemTable)
30 // Might be good to put this in an include file, but people may start
31 // using it! They should always access the EFI abstraction that is
32 // contained in this file. Just a little information hiding.
34 #define PORT_TO_MEM(_Port) ( ((_Port) & 0xffffffffffff0000) | (((_Port) & 0xfffc) << 10) | ((_Port) & 0x0fff) )
37 // Macro's with casts make this much easier to use and read.
39 #define PORT_TO_MEM8(_Port) (*(UINT8 *)(PORT_TO_MEM(_Port)))
40 #define PORT_TO_MEM16(_Port) (*(UINT16 *)(PORT_TO_MEM(_Port)))
41 #define PORT_TO_MEM32(_Port) (*(UINT32 *)(PORT_TO_MEM(_Port)))
43 #define EFI_PCI_ADDRESS_IA64(_seg, _bus,_dev,_func,_reg) \
44 ( (UINT64) ( (((UINTN)_seg) << 24) + (((UINTN)_bus) << 16) + (((UINTN)_dev) << 11) + (((UINTN)_func) << 8) + ((UINTN)_reg)) )
47 // Local variables for performing SAL Proc calls
49 PLABEL mSalProcPlabel
;
50 CALL_SAL_PROC mGlobalSalProc
;
53 PcatRootBridgeIoIoRead (
54 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
55 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
56 IN UINT64 UserAddress
,
58 IN OUT VOID
*UserBuffer
61 PCAT_PCI_ROOT_BRIDGE_INSTANCE
*PrivateData
;
71 if ( UserBuffer
== NULL
) {
72 return EFI_INVALID_PARAMETER
;
75 PrivateData
= DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This
);
77 Address
= (UINTN
) UserAddress
;
78 Buffer
.buf
= (UINT8
*)UserBuffer
;
80 if ( Address
< PrivateData
->IoBase
|| Address
> PrivateData
->IoLimit
) {
81 return EFI_INVALID_PARAMETER
;
84 if ((UINT32
)Width
>= EfiPciWidthMaximum
) {
85 return EFI_INVALID_PARAMETER
;
88 if ((Width
& 0x03) == EfiPciWidthUint64
) {
89 return EFI_INVALID_PARAMETER
;
92 AlignMask
= (1 << (Width
& 0x03)) - 1;
93 if ( Address
& AlignMask
) {
94 return EFI_INVALID_PARAMETER
;
97 InStride
= 1 << (Width
& 0x03);
99 if (Width
>=EfiPciWidthFifoUint8
&& Width
<= EfiPciWidthFifoUint64
) {
102 if (Width
>=EfiPciWidthFillUint8
&& Width
<= EfiPciWidthFillUint64
) {
105 Width
= Width
& 0x03;
107 Address
+= PrivateData
->PhysicalIoBase
;
110 // Loop for each iteration and move the data
114 case EfiPciWidthUint8
:
115 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
117 *Buffer
.ui8
= PORT_TO_MEM8(Address
);
122 case EfiPciWidthUint16
:
123 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
125 if (Buffer
.ui
& 0x1) {
126 Data16
= PORT_TO_MEM16(Address
);
127 *Buffer
.ui8
= (UINT8
)(Data16
& 0xff);
128 *(Buffer
.ui8
+1) = (UINT8
)((Data16
>> 8) & 0xff);
130 *Buffer
.ui16
= PORT_TO_MEM16(Address
);
136 case EfiPciWidthUint32
:
137 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
139 if (Buffer
.ui
& 0x3) {
140 Data32
= PORT_TO_MEM32(Address
);
141 *Buffer
.ui8
= (UINT8
)(Data32
& 0xff);
142 *(Buffer
.ui8
+1) = (UINT8
)((Data32
>> 8) & 0xff);
143 *(Buffer
.ui8
+2) = (UINT8
)((Data32
>> 16) & 0xff);
144 *(Buffer
.ui8
+3) = (UINT8
)((Data32
>> 24) & 0xff);
146 *Buffer
.ui32
= PORT_TO_MEM32(Address
);
157 PcatRootBridgeIoIoWrite (
158 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
159 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
160 IN UINT64 UserAddress
,
162 IN OUT VOID
*UserBuffer
165 PCAT_PCI_ROOT_BRIDGE_INSTANCE
*PrivateData
;
174 if ( UserBuffer
== NULL
) {
175 return EFI_INVALID_PARAMETER
;
178 PrivateData
= DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This
);
180 Address
= (UINTN
) UserAddress
;
181 Buffer
.buf
= (UINT8
*)UserBuffer
;
183 if ( Address
< PrivateData
->IoBase
|| Address
> PrivateData
->IoLimit
) {
184 return EFI_INVALID_PARAMETER
;
187 if (Width
< 0 || Width
>= EfiPciWidthMaximum
) {
188 return EFI_INVALID_PARAMETER
;
191 if ((Width
& 0x03) == EfiPciWidthUint64
) {
192 return EFI_INVALID_PARAMETER
;
195 AlignMask
= (1 << (Width
& 0x03)) - 1;
196 if ( Address
& AlignMask
) {
197 return EFI_INVALID_PARAMETER
;
200 InStride
= 1 << (Width
& 0x03);
201 OutStride
= InStride
;
202 if (Width
>=EfiPciWidthFifoUint8
&& Width
<= EfiPciWidthFifoUint64
) {
205 if (Width
>=EfiPciWidthFillUint8
&& Width
<= EfiPciWidthFillUint64
) {
208 Width
= Width
& 0x03;
210 Address
+= PrivateData
->PhysicalIoBase
;
213 // Loop for each iteration and move the data
217 case EfiPciWidthUint8
:
218 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
220 PORT_TO_MEM8(Address
) = *Buffer
.ui8
;
225 case EfiPciWidthUint16
:
226 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
228 if (Buffer
.ui
& 0x1) {
229 Data16
= *Buffer
.ui8
;
230 Data16
= Data16
| (*(Buffer
.ui8
+1) << 8);
231 PORT_TO_MEM16(Address
) = Data16
;
233 PORT_TO_MEM16(Address
) = *Buffer
.ui16
;
238 case EfiPciWidthUint32
:
239 for (; Count
> 0; Count
--, Buffer
.buf
+= OutStride
, Address
+= InStride
) {
241 if (Buffer
.ui
& 0x3) {
242 Data32
= *Buffer
.ui8
;
243 Data32
= Data32
| (*(Buffer
.ui8
+1) << 8);
244 Data32
= Data32
| (*(Buffer
.ui8
+2) << 16);
245 Data32
= Data32
| (*(Buffer
.ui8
+3) << 24);
246 PORT_TO_MEM32(Address
) = Data32
;
248 PORT_TO_MEM32(Address
) = *Buffer
.ui32
;
259 PcatRootBridgeIoGetIoPortMapping (
260 OUT EFI_PHYSICAL_ADDRESS
*IoPortMapping
,
261 OUT EFI_PHYSICAL_ADDRESS
*MemoryPortMapping
265 Get the IO Port Map from the SAL System Table.
269 SAL_SYSTEM_TABLE_ASCENDING_ORDER
*SalSystemTable
;
270 SAL_ST_MEMORY_DESCRIPTOR_ENTRY
*SalMemDesc
;
274 // On all Itanium architectures, bit 63 is the I/O bit for performming Memory Mapped I/O operations
276 *MemoryPortMapping
= 0x8000000000000000;
278 Status
= EfiLibGetSystemConfigurationTable(&gEfiSalSystemTableGuid
, &SalSystemTable
);
279 if (EFI_ERROR(Status
)) {
280 return EFI_NOT_FOUND
;
284 // BugBug: Add code to test checksum on the Sal System Table
286 if (SalSystemTable
->Entry0
.Type
!= 0) {
287 return EFI_UNSUPPORTED
;
290 mSalProcPlabel
.ProcEntryPoint
= SalSystemTable
->Entry0
.SalProcEntry
;
291 mSalProcPlabel
.GP
= SalSystemTable
->Entry0
.GlobalDataPointer
;
292 mGlobalSalProc
= (CALL_SAL_PROC
)&mSalProcPlabel
.ProcEntryPoint
;
295 // The SalSystemTable pointer includes the Type 0 entry.
296 // The SalMemDesc is Type 1 so it comes next.
298 SalMemDesc
= (SAL_ST_MEMORY_DESCRIPTOR_ENTRY
*)(SalSystemTable
+ 1);
299 while (SalMemDesc
->Type
== SAL_ST_MEMORY_DESCRIPTOR
) {
300 if (SalMemDesc
->MemoryType
== SAL_IO_PORT_MAPPING
) {
301 *IoPortMapping
= SalMemDesc
->PhysicalMemoryAddress
;
302 *IoPortMapping
|= 0x8000000000000000;
307 return EFI_UNSUPPORTED
;
311 PcatRootBridgeIoPciRW (
312 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
314 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
315 IN UINT64 UserAddress
,
317 IN OUT UINT8
*UserBuffer
320 PCAT_PCI_ROOT_BRIDGE_INSTANCE
*PrivateData
;
325 DEFIO_PCI_ADDR
*Defio
;
331 if (Width
< 0 || Width
>= EfiPciWidthMaximum
) {
332 return EFI_INVALID_PARAMETER
;
335 if ((Width
& 0x03) == EfiPciWidthUint64
) {
336 return EFI_INVALID_PARAMETER
;
339 AlignMask
= (1 << (Width
& 0x03)) - 1;
340 if ( UserAddress
& AlignMask
) {
341 return EFI_INVALID_PARAMETER
;
344 InStride
= 1 << (Width
& 0x03);
345 OutStride
= InStride
;
346 if (Width
>=EfiPciWidthFifoUint8
&& Width
<= EfiPciWidthFifoUint64
) {
349 if (Width
>=EfiPciWidthFillUint8
&& Width
<= EfiPciWidthFillUint64
) {
352 Width
= Width
& 0x03;
354 Defio
= (DEFIO_PCI_ADDR
*)&UserAddress
;
356 if ((Defio
->Function
> PCI_MAX_FUNC
) || (Defio
->Device
> PCI_MAX_DEVICE
)) {
357 return EFI_UNSUPPORTED
;
360 Buffer
.buf
= (UINT8
*)UserBuffer
;
362 PrivateData
= DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This
);
364 Address
= EFI_PCI_ADDRESS_IA64(
373 // PCI Config access are all 32-bit alligned, but by accessing the
374 // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types
375 // are possible on PCI.
377 // SalProc takes care of reading the proper register depending on stride
380 EfiAcquireLock(&PrivateData
->PciLock
);
386 if (Buffer
.ui
& 0x3) {
387 Data32
= (*(Buffer
.ui8
+0) << 0);
388 Data32
|= (*(Buffer
.ui8
+1) << 8);
389 Data32
|= (*(Buffer
.ui8
+2) << 16);
390 Data32
|= (*(Buffer
.ui8
+3) << 24);
392 Data32
= *Buffer
.ui32
;
396 Return
= mGlobalSalProc((UINT64
) SAL_PCI_CONFIG_WRITE
,
397 Address
, 1 << Width
, Data32
, 0, 0, 0, 0);
400 EfiReleaseLock(&PrivateData
->PciLock
);
401 return EFI_UNSUPPORTED
;
407 Return
= mGlobalSalProc((UINT64
) SAL_PCI_CONFIG_READ
,
408 Address
, 1 << Width
, 0, 0, 0, 0, 0);
411 EfiReleaseLock(&PrivateData
->PciLock
);
412 return EFI_UNSUPPORTED
;
416 case EfiPciWidthUint8
:
417 *Buffer
.ui8
= (UINT8
)Return
.p1
;
419 case EfiPciWidthUint16
:
420 if (Buffer
.ui
& 0x1) {
421 Data16
= (UINT16
)Return
.p1
;
422 *(Buffer
.ui8
+ 0) = Data16
& 0xff;
423 *(Buffer
.ui8
+ 1) = (Data16
>> 8) & 0xff;
425 *Buffer
.ui16
= (UINT16
)Return
.p1
;
428 case EfiPciWidthUint32
:
429 if (Buffer
.ui
& 0x3) {
430 Data32
= (UINT32
)Return
.p1
;
431 *(Buffer
.ui8
+ 0) = (UINT8
)(Data32
& 0xff);
432 *(Buffer
.ui8
+ 1) = (UINT8
)((Data32
>> 8) & 0xff);
433 *(Buffer
.ui8
+ 2) = (UINT8
)((Data32
>> 16) & 0xff);
434 *(Buffer
.ui8
+ 3) = (UINT8
)((Data32
>> 24) & 0xff);
436 *Buffer
.ui32
= (UINT32
)Return
.p1
;
443 Buffer
.buf
+= OutStride
;
447 EfiReleaseLock(&PrivateData
->PciLock
);
453 ScanPciRootBridgeForRoms(
454 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*IoDev
458 return EFI_UNSUPPORTED
;