• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
PciOperateRegister(IN PCI_IO_DEVICE * PciIoDevice,IN UINT16 Command,IN UINT8 Offset,IN UINT8 Operation,OUT UINT16 * PtrCommand)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
PciCapabilitySupport(IN PCI_IO_DEVICE * PciIoDevice)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
LocateCapabilityRegBlock(IN PCI_IO_DEVICE * PciIoDevice,IN UINT8 CapId,IN OUT UINT8 * Offset,OUT UINT8 * NextRegBlock OPTIONAL)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
LocatePciExpressCapabilityRegBlock(IN PCI_IO_DEVICE * PciIoDevice,IN UINT16 CapId,IN OUT UINT32 * Offset,OUT UINT32 * NextRegBlock OPTIONAL)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