9f3fcce6f71c4a24167ae9f383172e1cddb7383e
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciCommand.c
1 /** @file
2 PCI command register operations supporting functions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2009, 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 CapabilityPtr = (UINT8) (CapabilityEntry >> 8);
177 }
178
179 return EFI_NOT_FOUND;
180 }
181
182 /**
183 Locate PciExpress capability register block per capability ID.
184
185 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
186 @param CapId The capability ID.
187 @param Offset A pointer to the offset returned.
188 @param NextRegBlock A pointer to the next block returned.
189
190 @retval EFI_SUCCESS Successfuly located capability register block.
191 @retval EFI_UNSUPPORTED Pci device does not support capability.
192 @retval EFI_NOT_FOUND Pci device support but can not find register block.
193
194 **/
195 EFI_STATUS
196 LocatePciExpressCapabilityRegBlock (
197 IN PCI_IO_DEVICE *PciIoDevice,
198 IN UINT16 CapId,
199 IN OUT UINT32 *Offset,
200 OUT UINT32 *NextRegBlock OPTIONAL
201 )
202 {
203 UINT32 CapabilityPtr;
204 UINT32 CapabilityEntry;
205 UINT16 CapabilityID;
206
207 //
208 // To check the capability of this device supports
209 //
210 if (!PciIoDevice->IsPciExp) {
211 return EFI_UNSUPPORTED;
212 }
213
214 if (*Offset != 0) {
215 CapabilityPtr = *Offset;
216 } else {
217 CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET;
218 }
219
220 while (CapabilityPtr != 0) {
221 //
222 // Mask it to DWORD alignment per PCI spec
223 //
224 CapabilityPtr &= 0xFFC;
225 PciIoDevice->PciIo.Pci.Read (
226 &PciIoDevice->PciIo,
227 EfiPciIoWidthUint32,
228 CapabilityPtr,
229 1,
230 &CapabilityEntry
231 );
232
233 CapabilityID = (UINT16) CapabilityEntry;
234
235 if (CapabilityID == CapId) {
236 *Offset = CapabilityPtr;
237 if (NextRegBlock != NULL) {
238 *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF;
239 }
240
241 return EFI_SUCCESS;
242 }
243
244 CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF;
245 }
246
247 return EFI_NOT_FOUND;
248 }