blob: 97857c298186e7ef1a41895647d9e815afd7cd3a [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/*++
2
3Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution. The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13 PcatPciRootBridgeIo.c
14
15Abstract:
16
17 EFI PC AT PCI Root Bridge Io Protocol
18
19Revision History
20
21--*/
22
23#include "PcatPciRootBridge.h"
24#include <IndustryStandard/Pci.h>
25#include "SalProc.h"
26
27#include EFI_GUID_DEFINITION (SalSystemTable)
28
29//
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.
33//
34#define PORT_TO_MEM(_Port) ( ((_Port) & 0xffffffffffff0000) | (((_Port) & 0xfffc) << 10) | ((_Port) & 0x0fff) )
35
36//
37// Macro's with casts make this much easier to use and read.
38//
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)))
42
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)) )
45
46//
47// Local variables for performing SAL Proc calls
48//
49PLABEL mSalProcPlabel;
50CALL_SAL_PROC mGlobalSalProc;
51
52EFI_STATUS
53PcatRootBridgeIoIoRead (
54 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
55 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
56 IN UINT64 UserAddress,
57 IN UINTN Count,
58 IN OUT VOID *UserBuffer
59 )
60{
61 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
62 UINTN InStride;
63 UINTN OutStride;
64 UINTN AlignMask;
65 UINTN Address;
66 PTR Buffer;
67 UINT16 Data16;
68 UINT32 Data32;
69
70
71 if ( UserBuffer == NULL ) {
72 return EFI_INVALID_PARAMETER;
73 }
74
75 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
76
77 Address = (UINTN) UserAddress;
78 Buffer.buf = (UINT8 *)UserBuffer;
79
80 if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) {
81 return EFI_INVALID_PARAMETER;
82 }
83
84 if ((UINT32)Width >= EfiPciWidthMaximum) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 if ((Width & 0x03) == EfiPciWidthUint64) {
89 return EFI_INVALID_PARAMETER;
90 }
91
92 AlignMask = (1 << (Width & 0x03)) - 1;
93 if ( Address & AlignMask ) {
94 return EFI_INVALID_PARAMETER;
95 }
96
97 InStride = 1 << (Width & 0x03);
98 OutStride = InStride;
99 if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
100 InStride = 0;
101 }
102 if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
103 OutStride = 0;
104 }
105 Width = Width & 0x03;
106
107 Address += PrivateData->PhysicalIoBase;
108
109 //
110 // Loop for each iteration and move the data
111 //
112
113 switch (Width) {
114 case EfiPciWidthUint8:
115 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
116 MEMORY_FENCE();
117 *Buffer.ui8 = PORT_TO_MEM8(Address);
118 MEMORY_FENCE();
119 }
120 break;
121
122 case EfiPciWidthUint16:
123 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
124 MEMORY_FENCE();
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);
129 } else {
130 *Buffer.ui16 = PORT_TO_MEM16(Address);
131 }
132 MEMORY_FENCE();
133 }
134 break;
135
136 case EfiPciWidthUint32:
137 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
138 MEMORY_FENCE();
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);
145 } else {
146 *Buffer.ui32 = PORT_TO_MEM32(Address);
147 }
148 MEMORY_FENCE();
149 }
150 break;
151 }
152
153 return EFI_SUCCESS;
154}
155
156EFI_STATUS
157PcatRootBridgeIoIoWrite (
158 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
159 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
160 IN UINT64 UserAddress,
161 IN UINTN Count,
162 IN OUT VOID *UserBuffer
163 )
164{
165 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
166 UINTN InStride;
167 UINTN OutStride;
168 UINTN AlignMask;
169 UINTN Address;
170 PTR Buffer;
171 UINT16 Data16;
172 UINT32 Data32;
173
174 if ( UserBuffer == NULL ) {
175 return EFI_INVALID_PARAMETER;
176 }
177
178 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
179
180 Address = (UINTN) UserAddress;
181 Buffer.buf = (UINT8 *)UserBuffer;
182
183 if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) {
184 return EFI_INVALID_PARAMETER;
185 }
186
187 if (Width < 0 || Width >= EfiPciWidthMaximum) {
188 return EFI_INVALID_PARAMETER;
189 }
190
191 if ((Width & 0x03) == EfiPciWidthUint64) {
192 return EFI_INVALID_PARAMETER;
193 }
194
195 AlignMask = (1 << (Width & 0x03)) - 1;
196 if ( Address & AlignMask ) {
197 return EFI_INVALID_PARAMETER;
198 }
199
200 InStride = 1 << (Width & 0x03);
201 OutStride = InStride;
202 if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
203 InStride = 0;
204 }
205 if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
206 OutStride = 0;
207 }
208 Width = Width & 0x03;
209
210 Address += PrivateData->PhysicalIoBase;
211
212 //
213 // Loop for each iteration and move the data
214 //
215
216 switch (Width) {
217 case EfiPciWidthUint8:
218 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
219 MEMORY_FENCE();
220 PORT_TO_MEM8(Address) = *Buffer.ui8;
221 MEMORY_FENCE();
222 }
223 break;
224
225 case EfiPciWidthUint16:
226 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
227 MEMORY_FENCE();
228 if (Buffer.ui & 0x1) {
229 Data16 = *Buffer.ui8;
230 Data16 = Data16 | (*(Buffer.ui8+1) << 8);
231 PORT_TO_MEM16(Address) = Data16;
232 } else {
233 PORT_TO_MEM16(Address) = *Buffer.ui16;
234 }
235 MEMORY_FENCE();
236 }
237 break;
238 case EfiPciWidthUint32:
239 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {
240 MEMORY_FENCE();
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;
247 } else {
248 PORT_TO_MEM32(Address) = *Buffer.ui32;
249 }
250 MEMORY_FENCE();
251 }
252 break;
253 }
254
255 return EFI_SUCCESS;
256}
257
258EFI_STATUS
259PcatRootBridgeIoGetIoPortMapping (
260 OUT EFI_PHYSICAL_ADDRESS *IoPortMapping,
261 OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping
262 )
263/*++
264
265 Get the IO Port Map from the SAL System Table.
266
267--*/
268{
269 SAL_SYSTEM_TABLE_ASCENDING_ORDER *SalSystemTable;
270 SAL_ST_MEMORY_DESCRIPTOR_ENTRY *SalMemDesc;
271 EFI_STATUS Status;
272
273 //
274 // On all Itanium architectures, bit 63 is the I/O bit for performming Memory Mapped I/O operations
275 //
276 *MemoryPortMapping = 0x8000000000000000;
277
278 Status = EfiLibGetSystemConfigurationTable(&gEfiSalSystemTableGuid, &SalSystemTable);
279 if (EFI_ERROR(Status)) {
280 return EFI_NOT_FOUND;
281 }
282
283 //
284 // BugBug: Add code to test checksum on the Sal System Table
285 //
286 if (SalSystemTable->Entry0.Type != 0) {
287 return EFI_UNSUPPORTED;
288 }
289
290 mSalProcPlabel.ProcEntryPoint = SalSystemTable->Entry0.SalProcEntry;
291 mSalProcPlabel.GP = SalSystemTable->Entry0.GlobalDataPointer;
292 mGlobalSalProc = (CALL_SAL_PROC)&mSalProcPlabel.ProcEntryPoint;
293
294 //
295 // The SalSystemTable pointer includes the Type 0 entry.
296 // The SalMemDesc is Type 1 so it comes next.
297 //
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;
303 return EFI_SUCCESS;
304 }
305 SalMemDesc++;
306 }
307 return EFI_UNSUPPORTED;
308}
309
310EFI_STATUS
311PcatRootBridgeIoPciRW (
312 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
313 IN BOOLEAN Write,
314 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
315 IN UINT64 UserAddress,
316 IN UINTN Count,
317 IN OUT UINT8 *UserBuffer
318 )
319{
320 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
321 UINTN AlignMask;
322 UINTN InStride;
323 UINTN OutStride;
324 UINT64 Address;
325 DEFIO_PCI_ADDR *Defio;
326 PTR Buffer;
327 UINT32 Data32;
328 UINT16 Data16;
329 rArg Return;
330
331 if (Width < 0 || Width >= EfiPciWidthMaximum) {
332 return EFI_INVALID_PARAMETER;
333 }
334
335 if ((Width & 0x03) == EfiPciWidthUint64) {
336 return EFI_INVALID_PARAMETER;
337 }
338
339 AlignMask = (1 << (Width & 0x03)) - 1;
340 if ( UserAddress & AlignMask ) {
341 return EFI_INVALID_PARAMETER;
342 }
343
344 InStride = 1 << (Width & 0x03);
345 OutStride = InStride;
346 if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
347 InStride = 0;
348 }
349 if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
350 OutStride = 0;
351 }
352 Width = Width & 0x03;
353
354 Defio = (DEFIO_PCI_ADDR *)&UserAddress;
355
356 if ((Defio->Function > PCI_MAX_FUNC) || (Defio->Device > PCI_MAX_DEVICE)) {
357 return EFI_UNSUPPORTED;
358 }
359
360 Buffer.buf = (UINT8 *)UserBuffer;
361
362 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
363
364 Address = EFI_PCI_ADDRESS_IA64(
365 This->SegmentNumber,
366 Defio->Bus,
367 Defio->Device,
368 Defio->Function,
369 Defio->Register
370 );
371
372 //
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.
376 //
377 // SalProc takes care of reading the proper register depending on stride
378 //
379
380 EfiAcquireLock(&PrivateData->PciLock);
381
382 while (Count) {
383
384 if(Write) {
385
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);
391 } else {
392 Data32 = *Buffer.ui32;
393 }
394
395 Return.p0 = -3;
396 Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_WRITE,
397 Address, 1 << Width, Data32, 0, 0, 0, 0);
398
399 if(Return.p0) {
400 EfiReleaseLock(&PrivateData->PciLock);
401 return EFI_UNSUPPORTED;
402 }
403
404 } else {
405
406 Return.p0 = -3;
407 Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_READ,
408 Address, 1 << Width, 0, 0, 0, 0, 0);
409
410 if(Return.p0) {
411 EfiReleaseLock(&PrivateData->PciLock);
412 return EFI_UNSUPPORTED;
413 }
414
415 switch (Width) {
416 case EfiPciWidthUint8:
417 *Buffer.ui8 = (UINT8)Return.p1;
418 break;
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;
424 } else {
425 *Buffer.ui16 = (UINT16)Return.p1;
426 }
427 break;
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);
435 } else {
436 *Buffer.ui32 = (UINT32)Return.p1;
437 }
438 break;
439 }
440 }
441
442 Address += InStride;
443 Buffer.buf += OutStride;
444 Count -= 1;
445 }
446
447 EfiReleaseLock(&PrivateData->PciLock);
448
449 return EFI_SUCCESS;
450}
451
452EFI_STATUS
453ScanPciRootBridgeForRoms(
454 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev
455 )
456
457{
458 return EFI_UNSUPPORTED;
459}