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