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