1 /*++
2
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
8
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.
11
12 Module Name:
13 PcatPciRootBridgeIo.c
14
15 Abstract:
16
17 EFI PC AT PCI Root Bridge Io Protocol
18
19 Revision 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 //
49 PLABEL mSalProcPlabel;
50 CALL_SAL_PROC mGlobalSalProc;
51
52 EFI_STATUS
PcatRootBridgeIoIoRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)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,
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
156 EFI_STATUS
PcatRootBridgeIoIoWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT VOID * UserBuffer)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,
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
258 EFI_STATUS
PcatRootBridgeIoGetIoPortMapping(OUT EFI_PHYSICAL_ADDRESS * IoPortMapping,OUT EFI_PHYSICAL_ADDRESS * MemoryPortMapping)259 PcatRootBridgeIoGetIoPortMapping (
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
310 EFI_STATUS
PcatRootBridgeIoPciRW(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN BOOLEAN Write,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 UserAddress,IN UINTN Count,IN OUT UINT8 * UserBuffer)311 PcatRootBridgeIoPciRW (
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
452 EFI_STATUS
ScanPciRootBridgeForRoms(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * IoDev)453 ScanPciRootBridgeForRoms(
454 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev
455 )
456
457 {
458 return EFI_UNSUPPORTED;
459 }
460