Home | History | Annotate | Download | only in Ipf
      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
     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
    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
    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
    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
    453 ScanPciRootBridgeForRoms(
    454   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev
    455   )
    456 
    457 {
    458   return EFI_UNSUPPORTED;
    459 }
    460