[golan] Add Connect-IB, ConnectX-4 and ConnectX-4 Lx (Infiniband) support
[ipxe.git] / src / drivers / infiniband / mlx_utils / src / public / mlx_pci_gw.c
1 /*
2 * Copyright (C) 2015 Mellanox Technologies Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include "../../include/public/mlx_pci_gw.h"
23 #include "../../include/public/mlx_bail.h"
24 #include "../../include/public/mlx_pci.h"
25 #include "../../include/public/mlx_logging.h"
26
27 /* Lock/unlock GW on each VSEC access */
28 #undef VSEC_DEBUG
29
30 static
31 mlx_status
32 mlx_pci_gw_check_capability_id(
33 IN mlx_utils *utils,
34 IN mlx_uint8 cap_pointer,
35 OUT mlx_boolean *bool
36 )
37 {
38 mlx_status status = MLX_SUCCESS;
39 mlx_uint8 offset = cap_pointer + PCI_GW_CAPABILITY_ID_OFFSET;
40 mlx_uint8 id = 0;
41 status = mlx_pci_read(utils, MlxPciWidthUint8, offset,
42 1, &id);
43 MLX_CHECK_STATUS(utils, status, read_err,"failed to read capability id");
44 *bool = ( id == PCI_GW_CAPABILITY_ID );
45 read_err:
46 return status;
47 }
48
49 static
50 mlx_status
51 mlx_pci_gw_get_ownership(
52 IN mlx_utils *utils
53 )
54 {
55 mlx_status status = MLX_SUCCESS;
56 mlx_uint32 cap_offset = utils->pci_gw.pci_cmd_offset;
57 mlx_uint32 semaphore = 0;
58 mlx_uint32 counter = 0;
59 mlx_uint32 get_semaphore_try = 0;
60 mlx_uint32 get_ownership_try = 0;
61
62 for( ; get_ownership_try < PCI_GW_GET_OWNERSHIP_TRIES; get_ownership_try ++){
63 for( ; get_semaphore_try <= PCI_GW_SEMPHORE_TRIES ; get_semaphore_try++){
64 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
65 1, &semaphore);
66 MLX_CHECK_STATUS(utils, status, read_err,"failed to read semaphore");
67 if( semaphore == 0 ){
68 break;
69 }
70 mlx_utils_delay_in_us(10);
71 }
72 if( semaphore != 0 ){
73 status = MLX_FAILED;
74 goto semaphore_err;
75 }
76
77 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_COUNTER_OFFSET,
78 1, &counter);
79 MLX_CHECK_STATUS(utils, status, read_err, "failed to read counter");
80
81 status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
82 1, &counter);
83 MLX_CHECK_STATUS(utils, status, write_err,"failed to write semaphore");
84
85 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
86 1, &semaphore);
87 MLX_CHECK_STATUS(utils, status, read_err,"failed to read semaphore");
88 if( counter == semaphore ){
89 break;
90 }
91 }
92 if( counter != semaphore ){
93 status = MLX_FAILED;
94 }
95 write_err:
96 read_err:
97 semaphore_err:
98 return status;
99 }
100
101 static
102 mlx_status
103 mlx_pci_gw_free_ownership(
104 IN mlx_utils *utils
105 )
106 {
107 mlx_status status = MLX_SUCCESS;
108 mlx_uint32 cap_offset = utils->pci_gw.pci_cmd_offset;
109 mlx_uint32 value = 0;
110
111 status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
112 1, &value);
113 MLX_CHECK_STATUS(utils, status, write_err,"failed to write semaphore");
114 write_err:
115 return status;
116 }
117
118 static
119 mlx_status
120 mlx_pci_gw_set_space(
121 IN mlx_utils *utils,
122 IN mlx_pci_gw_space space
123 )
124 {
125 mlx_status status = MLX_SUCCESS;
126 mlx_uint32 cap_offset = utils->pci_gw.pci_cmd_offset;;
127 mlx_uint8 space_status = 0;
128
129 /* set nodnic*/
130 status = mlx_pci_write(utils, MlxPciWidthUint16, cap_offset + PCI_GW_CAPABILITY_SPACE_OFFSET, 1, &space);
131 MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability space");
132
133 status = mlx_pci_read(utils, MlxPciWidthUint8, cap_offset + PCI_GW_CAPABILITY_STATUS_OFFSET, 1, &space_status);
134 MLX_CHECK_STATUS(utils, status, read_error,"failed to read capability status");
135 if( (space_status & 0x20) == 0){
136 status = MLX_FAILED;
137 goto space_unsupported;
138 }
139 read_error:
140 space_unsupported:
141 return status;
142 }
143
144 static
145 mlx_status
146 mlx_pci_gw_wait_for_flag_value(
147 IN mlx_utils *utils,
148 IN mlx_boolean value
149 )
150 {
151 mlx_status status = MLX_SUCCESS;
152 mlx_uint32 try = 0;
153 mlx_uint32 cap_offset = utils->pci_gw.pci_cmd_offset;
154 mlx_uint32 flag = 0;
155
156 for(; try < PCI_GW_READ_FLAG_TRIES ; try ++ ) {
157 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_FLAG_OFFSET, 1, &flag);
158 MLX_CHECK_STATUS(utils, status, read_error, "failed to read capability flag");
159 if( ((flag & 0x80000000) != 0) == value ){
160 goto flag_valid;
161 }
162 mlx_utils_delay_in_us(10);
163 }
164 status = MLX_FAILED;
165 flag_valid:
166 read_error:
167 return status;
168 }
169 static
170 mlx_status
171 mlx_pci_gw_search_capability(
172 IN mlx_utils *utils,
173 OUT mlx_uint32 *cap_offset
174 )
175 {
176 mlx_status status = MLX_SUCCESS;
177 mlx_uint8 cap_pointer = 0;
178 mlx_boolean is_capability = FALSE;
179
180 if( cap_offset == NULL || utils == NULL){
181 status = MLX_INVALID_PARAMETER;
182 goto bad_param;
183 }
184
185 //get first capability pointer
186 status = mlx_pci_read(utils, MlxPciWidthUint8, PCI_GW_FIRST_CAPABILITY_POINTER_OFFSET,
187 1, &cap_pointer);
188 MLX_CHECK_STATUS(utils, status, read_err,
189 "failed to read capability pointer");
190
191 //search the right capability
192 while( cap_pointer != 0 ){
193 status = mlx_pci_gw_check_capability_id(utils, cap_pointer, &is_capability);
194 MLX_CHECK_STATUS(utils, status, check_err
195 ,"failed to check capability id");
196
197 if( is_capability == TRUE ){
198 *cap_offset = cap_pointer;
199 break;
200 }
201
202 status = mlx_pci_read(utils, MlxPciWidthUint8, cap_pointer +
203 PCI_GW_CAPABILITY_NEXT_POINTER_OFFSET ,
204 1, &cap_pointer);
205 MLX_CHECK_STATUS(utils, status, read_err,
206 "failed to read capability pointer");
207 }
208 if( is_capability != TRUE ){
209 status = MLX_NOT_FOUND;
210 }
211 check_err:
212 read_err:
213 bad_param:
214 return status;
215 }
216
217 mlx_status
218 mlx_pci_gw_init(
219 IN mlx_utils *utils
220 )
221 {
222 mlx_status status = MLX_SUCCESS;
223 mlx_pci_gw *pci_gw = NULL;
224
225 if( utils == NULL){
226 status = MLX_INVALID_PARAMETER;
227 goto bad_param;
228 }
229
230 pci_gw = &utils->pci_gw;
231
232 status = mlx_pci_gw_search_capability(utils, &pci_gw->pci_cmd_offset);
233 MLX_CHECK_STATUS(utils, status, cap_err,
234 "mlx_pci_gw_search_capability failed");
235
236 #if ! defined ( VSEC_DEBUG )
237 status = mlx_pci_gw_get_ownership(utils);
238 MLX_CHECK_STATUS(utils, status, ownership_err,"failed to get ownership");
239 ownership_err:
240 #endif
241 cap_err:
242 bad_param:
243 return status;
244 }
245
246 mlx_status
247 mlx_pci_gw_teardown(
248 IN mlx_utils *utils __attribute__ ((unused))
249 )
250 {
251 #if ! defined ( VSEC_DEBUG )
252 mlx_pci_gw_free_ownership(utils);
253 #endif
254 return MLX_SUCCESS;
255 }
256
257 mlx_status
258 mlx_pci_gw_read(
259 IN mlx_utils *utils,
260 IN mlx_pci_gw_space space,
261 IN mlx_uint32 address,
262 OUT mlx_pci_gw_buffer *buffer
263 )
264 {
265 mlx_status status = MLX_SUCCESS;
266 mlx_pci_gw *pci_gw = NULL;
267 mlx_uint32 cap_offset = 0;
268
269 if (utils == NULL || buffer == NULL || utils->pci_gw.pci_cmd_offset == 0) {
270 status = MLX_INVALID_PARAMETER;
271 goto bad_param;
272 }
273
274 mlx_utils_acquire_lock(utils);
275
276 pci_gw = &utils->pci_gw;
277 cap_offset = pci_gw->pci_cmd_offset;
278
279 #if ! defined ( VSEC_DEBUG )
280 if (pci_gw->space != space) {
281 status = mlx_pci_gw_set_space(utils, space);
282 MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
283 pci_gw->space = space;
284 }
285 #else
286 status = mlx_pci_gw_get_ownership(utils);
287 MLX_CHECK_STATUS(utils, status, ownership_err,"failed to get ownership");
288
289 status = mlx_pci_gw_set_space(utils, space);
290 MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
291 pci_gw->space = space;
292 #endif
293
294 status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_ADDRESS_OFFSET, 1, &address);
295 MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability address");
296
297 #if defined ( DEVICE_CX3 )
298 /* WA for PCI issue (race) */
299 mlx_utils_delay_in_us ( 10 );
300 #endif
301
302 status = mlx_pci_gw_wait_for_flag_value(utils, TRUE);
303 MLX_CHECK_STATUS(utils, status, read_error, "flag failed to change");
304
305 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_DATA_OFFSET, 1, buffer);
306 MLX_CHECK_STATUS(utils, status, read_error,"failed to read capability data");
307
308 #if defined ( VSEC_DEBUG )
309 status = mlx_pci_gw_free_ownership(utils);
310 MLX_CHECK_STATUS(utils, status, free_err,
311 "mlx_pci_gw_free_ownership failed");
312 free_err:
313 mlx_utils_release_lock(utils);
314 return status;
315 #endif
316 read_error:
317 space_error:
318 #if defined ( VSEC_DEBUG )
319 mlx_pci_gw_free_ownership(utils);
320 ownership_err:
321 #endif
322 mlx_utils_release_lock(utils);
323 bad_param:
324 return status;
325 }
326
327 mlx_status
328 mlx_pci_gw_write(
329 IN mlx_utils *utils,
330 IN mlx_pci_gw_space space,
331 IN mlx_uint32 address,
332 IN mlx_pci_gw_buffer buffer
333 )
334 {
335 mlx_status status = MLX_SUCCESS;
336 mlx_pci_gw *pci_gw = NULL;
337 mlx_uint32 cap_offset = 0;
338 mlx_uint32 fixed_address = address | PCI_GW_WRITE_FLAG;
339
340 if (utils == NULL || utils->pci_gw.pci_cmd_offset == 0) {
341 status = MLX_INVALID_PARAMETER;
342 goto bad_param;
343 }
344
345 mlx_utils_acquire_lock(utils);
346
347 pci_gw = &utils->pci_gw;
348 cap_offset = pci_gw->pci_cmd_offset;
349
350 #if ! defined ( VSEC_DEBUG )
351 if (pci_gw->space != space) {
352 status = mlx_pci_gw_set_space(utils, space);
353 MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
354 pci_gw->space = space;
355 }
356 #else
357 status = mlx_pci_gw_get_ownership(utils);
358 MLX_CHECK_STATUS(utils, status, ownership_err,"failed to get ownership");
359
360 status = mlx_pci_gw_set_space(utils, space);
361 MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
362 pci_gw->space = space;
363 #endif
364 status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_DATA_OFFSET, 1, &buffer);
365 MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability data");
366
367 status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_ADDRESS_OFFSET, 1, &fixed_address);
368 MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability address");
369
370 status = mlx_pci_gw_wait_for_flag_value(utils, FALSE);
371 MLX_CHECK_STATUS(utils, status, read_error, "flag failed to change");
372 #if defined ( VSEC_DEBUG )
373 status = mlx_pci_gw_free_ownership(utils);
374 MLX_CHECK_STATUS(utils, status, free_err,
375 "mlx_pci_gw_free_ownership failed");
376 free_err:
377 mlx_utils_release_lock(utils);
378 return status;
379 #endif
380 read_error:
381 space_error:
382 #if defined ( VSEC_DEBUG )
383 mlx_pci_gw_free_ownership(utils);
384 ownership_err:
385 #endif
386 mlx_utils_release_lock(utils);
387 bad_param:
388 return status;
389 }
390
391
392