Home | History | Annotate | Download | only in PciBusDxe
      1 /** @file
      2   PCI command register operations supporting functions implementation for PCI Bus module.
      3 
      4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PciBus.h"
     16 
     17 /**
     18   Operate the PCI register via PciIo function interface.
     19 
     20   @param PciIoDevice    Pointer to instance of PCI_IO_DEVICE.
     21   @param Command        Operator command.
     22   @param Offset         The address within the PCI configuration space for the PCI controller.
     23   @param Operation      Type of Operation.
     24   @param PtrCommand     Return buffer holding old PCI command, if operation is not EFI_SET_REGISTER.
     25 
     26   @return Status of PciIo operation.
     27 
     28 **/
     29 EFI_STATUS
     30 PciOperateRegister (
     31   IN  PCI_IO_DEVICE *PciIoDevice,
     32   IN  UINT16        Command,
     33   IN  UINT8         Offset,
     34   IN  UINT8         Operation,
     35   OUT UINT16        *PtrCommand
     36   )
     37 {
     38   UINT16              OldCommand;
     39   EFI_STATUS          Status;
     40   EFI_PCI_IO_PROTOCOL *PciIo;
     41 
     42   OldCommand  = 0;
     43   PciIo       = &PciIoDevice->PciIo;
     44 
     45   if (Operation != EFI_SET_REGISTER) {
     46     Status = PciIo->Pci.Read (
     47                           PciIo,
     48                           EfiPciIoWidthUint16,
     49                           Offset,
     50                           1,
     51                           &OldCommand
     52                           );
     53 
     54     if (Operation == EFI_GET_REGISTER) {
     55       *PtrCommand = OldCommand;
     56       return Status;
     57     }
     58   }
     59 
     60   if (Operation == EFI_ENABLE_REGISTER) {
     61     OldCommand = (UINT16) (OldCommand | Command);
     62   } else if (Operation == EFI_DISABLE_REGISTER) {
     63     OldCommand = (UINT16) (OldCommand & ~(Command));
     64   } else {
     65     OldCommand = Command;
     66   }
     67 
     68   return PciIo->Pci.Write (
     69                       PciIo,
     70                       EfiPciIoWidthUint16,
     71                       Offset,
     72                       1,
     73                       &OldCommand
     74                       );
     75 }
     76 
     77 /**
     78   Check the cpability supporting by given device.
     79 
     80   @param PciIoDevice   Pointer to instance of PCI_IO_DEVICE.
     81 
     82   @retval TRUE         Cpability supportted.
     83   @retval FALSE        Cpability not supportted.
     84 
     85 **/
     86 BOOLEAN
     87 PciCapabilitySupport (
     88   IN PCI_IO_DEVICE  *PciIoDevice
     89   )
     90 {
     91   if ((PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
     92     return TRUE;
     93   }
     94 
     95   return FALSE;
     96 }
     97 
     98 /**
     99   Locate capability register block per capability ID.
    100 
    101   @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
    102   @param CapId             The capability ID.
    103   @param Offset            A pointer to the offset returned.
    104   @param NextRegBlock      A pointer to the next block returned.
    105 
    106   @retval EFI_SUCCESS      Successfuly located capability register block.
    107   @retval EFI_UNSUPPORTED  Pci device does not support capability.
    108   @retval EFI_NOT_FOUND    Pci device support but can not find register block.
    109 
    110 **/
    111 EFI_STATUS
    112 LocateCapabilityRegBlock (
    113   IN PCI_IO_DEVICE  *PciIoDevice,
    114   IN UINT8          CapId,
    115   IN OUT UINT8      *Offset,
    116   OUT UINT8         *NextRegBlock OPTIONAL
    117   )
    118 {
    119   UINT8   CapabilityPtr;
    120   UINT16  CapabilityEntry;
    121   UINT8   CapabilityID;
    122 
    123   //
    124   // To check the cpability of this device supports
    125   //
    126   if (!PciCapabilitySupport (PciIoDevice)) {
    127     return EFI_UNSUPPORTED;
    128   }
    129 
    130   if (*Offset != 0) {
    131     CapabilityPtr = *Offset;
    132   } else {
    133 
    134     CapabilityPtr = 0;
    135     if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
    136 
    137       PciIoDevice->PciIo.Pci.Read (
    138                                &PciIoDevice->PciIo,
    139                                EfiPciIoWidthUint8,
    140                                EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR,
    141                                1,
    142                                &CapabilityPtr
    143                                );
    144     } else {
    145 
    146       PciIoDevice->PciIo.Pci.Read (
    147                                &PciIoDevice->PciIo,
    148                                EfiPciIoWidthUint8,
    149                                PCI_CAPBILITY_POINTER_OFFSET,
    150                                1,
    151                                &CapabilityPtr
    152                                );
    153     }
    154   }
    155 
    156   while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) {
    157     PciIoDevice->PciIo.Pci.Read (
    158                              &PciIoDevice->PciIo,
    159                              EfiPciIoWidthUint16,
    160                              CapabilityPtr,
    161                              1,
    162                              &CapabilityEntry
    163                              );
    164 
    165     CapabilityID = (UINT8) CapabilityEntry;
    166 
    167     if (CapabilityID == CapId) {
    168       *Offset = CapabilityPtr;
    169       if (NextRegBlock != NULL) {
    170         *NextRegBlock = (UINT8) (CapabilityEntry >> 8);
    171       }
    172 
    173       return EFI_SUCCESS;
    174     }
    175 
    176     //
    177     // Certain PCI device may incorrectly have capability pointing to itself,
    178     // break to avoid dead loop.
    179     //
    180     if (CapabilityPtr == (UINT8) (CapabilityEntry >> 8)) {
    181       break;
    182     }
    183 
    184     CapabilityPtr = (UINT8) (CapabilityEntry >> 8);
    185   }
    186 
    187   return EFI_NOT_FOUND;
    188 }
    189 
    190 /**
    191   Locate PciExpress capability register block per capability ID.
    192 
    193   @param PciIoDevice       A pointer to the PCI_IO_DEVICE.
    194   @param CapId             The capability ID.
    195   @param Offset            A pointer to the offset returned.
    196   @param NextRegBlock      A pointer to the next block returned.
    197 
    198   @retval EFI_SUCCESS      Successfuly located capability register block.
    199   @retval EFI_UNSUPPORTED  Pci device does not support capability.
    200   @retval EFI_NOT_FOUND    Pci device support but can not find register block.
    201 
    202 **/
    203 EFI_STATUS
    204 LocatePciExpressCapabilityRegBlock (
    205   IN     PCI_IO_DEVICE *PciIoDevice,
    206   IN     UINT16        CapId,
    207   IN OUT UINT32        *Offset,
    208      OUT UINT32        *NextRegBlock OPTIONAL
    209   )
    210 {
    211   EFI_STATUS           Status;
    212   UINT32               CapabilityPtr;
    213   UINT32               CapabilityEntry;
    214   UINT16               CapabilityID;
    215 
    216   //
    217   // To check the capability of this device supports
    218   //
    219   if (!PciIoDevice->IsPciExp) {
    220     return EFI_UNSUPPORTED;
    221   }
    222 
    223   if (*Offset != 0) {
    224     CapabilityPtr = *Offset;
    225   } else {
    226     CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET;
    227   }
    228 
    229   while (CapabilityPtr != 0) {
    230     //
    231     // Mask it to DWORD alignment per PCI spec
    232     //
    233     CapabilityPtr &= 0xFFC;
    234     Status = PciIoDevice->PciIo.Pci.Read (
    235                                       &PciIoDevice->PciIo,
    236                                       EfiPciIoWidthUint32,
    237                                       CapabilityPtr,
    238                                       1,
    239                                       &CapabilityEntry
    240                                       );
    241     if (EFI_ERROR (Status)) {
    242       break;
    243     }
    244 
    245     CapabilityID = (UINT16) CapabilityEntry;
    246 
    247     if (CapabilityID == CapId) {
    248       *Offset = CapabilityPtr;
    249       if (NextRegBlock != NULL) {
    250         *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF;
    251       }
    252 
    253       return EFI_SUCCESS;
    254     }
    255 
    256     CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF;
    257   }
    258 
    259   return EFI_NOT_FOUND;
    260 }
    261