GNU Linux-libre 4.14.332-gnu1
[releases.git] / drivers / net / ethernet / mellanox / mlx5 / core / fw.c
1 /*
2  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32
33 #include <linux/mlx5/driver.h>
34 #include <linux/mlx5/cmd.h>
35 #include <linux/module.h>
36 #include "mlx5_core.h"
37 #include "eswitch.h"
38 #include "../../mlxfw/mlxfw.h"
39
40 static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
41                                   int outlen)
42 {
43         u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {0};
44
45         MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
46         return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
47 }
48
49 int mlx5_query_board_id(struct mlx5_core_dev *dev)
50 {
51         u32 *out;
52         int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
53         int err;
54
55         out = kzalloc(outlen, GFP_KERNEL);
56         if (!out)
57                 return -ENOMEM;
58
59         err = mlx5_cmd_query_adapter(dev, out, outlen);
60         if (err)
61                 goto out;
62
63         memcpy(dev->board_id,
64                MLX5_ADDR_OF(query_adapter_out, out,
65                             query_adapter_struct.vsd_contd_psid),
66                MLX5_FLD_SZ_BYTES(query_adapter_out,
67                                  query_adapter_struct.vsd_contd_psid));
68
69 out:
70         kfree(out);
71         return err;
72 }
73
74 int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)
75 {
76         u32 *out;
77         int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
78         int err;
79
80         out = kzalloc(outlen, GFP_KERNEL);
81         if (!out)
82                 return -ENOMEM;
83
84         err = mlx5_cmd_query_adapter(mdev, out, outlen);
85         if (err)
86                 goto out;
87
88         *vendor_id = MLX5_GET(query_adapter_out, out,
89                               query_adapter_struct.ieee_vendor_id);
90 out:
91         kfree(out);
92         return err;
93 }
94 EXPORT_SYMBOL(mlx5_core_query_vendor_id);
95
96 static int mlx5_get_pcam_reg(struct mlx5_core_dev *dev)
97 {
98         return mlx5_query_pcam_reg(dev, dev->caps.pcam,
99                                    MLX5_PCAM_FEATURE_ENHANCED_FEATURES,
100                                    MLX5_PCAM_REGS_5000_TO_507F);
101 }
102
103 static int mlx5_get_mcam_reg(struct mlx5_core_dev *dev)
104 {
105         return mlx5_query_mcam_reg(dev, dev->caps.mcam,
106                                    MLX5_MCAM_FEATURE_ENHANCED_FEATURES,
107                                    MLX5_MCAM_REGS_FIRST_128);
108 }
109
110 int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
111 {
112         int err;
113
114         err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
115         if (err)
116                 return err;
117
118         if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
119                 err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
120                 if (err)
121                         return err;
122         }
123
124         if (MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
125                 err = mlx5_core_get_caps(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS);
126                 if (err)
127                         return err;
128         }
129
130         if (MLX5_CAP_GEN(dev, pg)) {
131                 err = mlx5_core_get_caps(dev, MLX5_CAP_ODP);
132                 if (err)
133                         return err;
134         }
135
136         if (MLX5_CAP_GEN(dev, atomic)) {
137                 err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
138                 if (err)
139                         return err;
140         }
141
142         if (MLX5_CAP_GEN(dev, roce)) {
143                 err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE);
144                 if (err)
145                         return err;
146         }
147
148         if (MLX5_CAP_GEN(dev, nic_flow_table) ||
149             MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
150                 err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
151                 if (err)
152                         return err;
153         }
154
155         if (MLX5_CAP_GEN(dev, vport_group_manager) &&
156             MLX5_ESWITCH_MANAGER(dev)) {
157                 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
158                 if (err)
159                         return err;
160         }
161
162         if (MLX5_ESWITCH_MANAGER(dev)) {
163                 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
164                 if (err)
165                         return err;
166         }
167
168         if (MLX5_CAP_GEN(dev, vector_calc)) {
169                 err = mlx5_core_get_caps(dev, MLX5_CAP_VECTOR_CALC);
170                 if (err)
171                         return err;
172         }
173
174         if (MLX5_CAP_GEN(dev, qos)) {
175                 err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
176                 if (err)
177                         return err;
178         }
179
180         if (MLX5_CAP_GEN(dev, pcam_reg))
181                 mlx5_get_pcam_reg(dev);
182
183         if (MLX5_CAP_GEN(dev, mcam_reg))
184                 mlx5_get_mcam_reg(dev);
185
186         return 0;
187 }
188
189 int mlx5_cmd_init_hca(struct mlx5_core_dev *dev)
190 {
191         u32 out[MLX5_ST_SZ_DW(init_hca_out)] = {0};
192         u32 in[MLX5_ST_SZ_DW(init_hca_in)]   = {0};
193
194         MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);
195         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
196 }
197
198 int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
199 {
200         u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
201         u32 in[MLX5_ST_SZ_DW(teardown_hca_in)]   = {0};
202
203         MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
204         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
205 }
206
207 int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
208 {
209         u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
210         u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
211         int force_state;
212         int ret;
213
214         if (!MLX5_CAP_GEN(dev, force_teardown)) {
215                 mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
216                 return -EOPNOTSUPP;
217         }
218
219         MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
220         MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);
221
222         ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));
223         if (ret)
224                 return ret;
225
226         force_state = MLX5_GET(teardown_hca_out, out, force_state);
227         if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
228                 mlx5_core_err(dev, "teardown with force mode failed\n");
229                 return -EIO;
230         }
231
232         return 0;
233 }
234
235 enum mlxsw_reg_mcc_instruction {
236         MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
237         MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
238         MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,
239         MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,
240         MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,
241         MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,
242 };
243
244 static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,
245                             enum mlxsw_reg_mcc_instruction instr,
246                             u16 component_index, u32 update_handle,
247                             u32 component_size)
248 {
249         u32 out[MLX5_ST_SZ_DW(mcc_reg)];
250         u32 in[MLX5_ST_SZ_DW(mcc_reg)];
251
252         memset(in, 0, sizeof(in));
253
254         MLX5_SET(mcc_reg, in, instruction, instr);
255         MLX5_SET(mcc_reg, in, component_index, component_index);
256         MLX5_SET(mcc_reg, in, update_handle, update_handle);
257         MLX5_SET(mcc_reg, in, component_size, component_size);
258
259         return mlx5_core_access_reg(dev, in, sizeof(in), out,
260                                     sizeof(out), MLX5_REG_MCC, 0, 1);
261 }
262
263 static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,
264                               u32 *update_handle, u8 *error_code,
265                               u8 *control_state)
266 {
267         u32 out[MLX5_ST_SZ_DW(mcc_reg)];
268         u32 in[MLX5_ST_SZ_DW(mcc_reg)];
269         int err;
270
271         memset(in, 0, sizeof(in));
272         memset(out, 0, sizeof(out));
273         MLX5_SET(mcc_reg, in, update_handle, *update_handle);
274
275         err = mlx5_core_access_reg(dev, in, sizeof(in), out,
276                                    sizeof(out), MLX5_REG_MCC, 0, 0);
277         if (err)
278                 goto out;
279
280         *update_handle = MLX5_GET(mcc_reg, out, update_handle);
281         *error_code = MLX5_GET(mcc_reg, out, error_code);
282         *control_state = MLX5_GET(mcc_reg, out, control_state);
283
284 out:
285         return err;
286 }
287
288 static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
289                              u32 update_handle,
290                              u32 offset, u16 size,
291                              u8 *data)
292 {
293         int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;
294         u32 out[MLX5_ST_SZ_DW(mcda_reg)];
295         int i, j, dw_size = size >> 2;
296         __be32 data_element;
297         u32 *in;
298
299         in = kzalloc(in_size, GFP_KERNEL);
300         if (!in)
301                 return -ENOMEM;
302
303         MLX5_SET(mcda_reg, in, update_handle, update_handle);
304         MLX5_SET(mcda_reg, in, offset, offset);
305         MLX5_SET(mcda_reg, in, size, size);
306
307         for (i = 0; i < dw_size; i++) {
308                 j = i * 4;
309                 data_element = htonl(*(u32 *)&data[j]);
310                 memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);
311         }
312
313         err = mlx5_core_access_reg(dev, in, in_size, out,
314                                    sizeof(out), MLX5_REG_MCDA, 0, 1);
315         kfree(in);
316         return err;
317 }
318
319 static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
320                                u16 component_index,
321                                u32 *max_component_size,
322                                u8 *log_mcda_word_size,
323                                u16 *mcda_max_write_size)
324 {
325         u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_ST_SZ_DW(mcqi_cap)];
326         int offset = MLX5_ST_SZ_DW(mcqi_reg);
327         u32 in[MLX5_ST_SZ_DW(mcqi_reg)];
328         int err;
329
330         memset(in, 0, sizeof(in));
331         memset(out, 0, sizeof(out));
332
333         MLX5_SET(mcqi_reg, in, component_index, component_index);
334         MLX5_SET(mcqi_reg, in, data_size, MLX5_ST_SZ_BYTES(mcqi_cap));
335
336         err = mlx5_core_access_reg(dev, in, sizeof(in), out,
337                                    sizeof(out), MLX5_REG_MCQI, 0, 0);
338         if (err)
339                 goto out;
340
341         *max_component_size = MLX5_GET(mcqi_cap, out + offset, max_component_size);
342         *log_mcda_word_size = MLX5_GET(mcqi_cap, out + offset, log_mcda_word_size);
343         *mcda_max_write_size = MLX5_GET(mcqi_cap, out + offset, mcda_max_write_size);
344
345 out:
346         return err;
347 }
348
349 struct mlx5_mlxfw_dev {
350         struct mlxfw_dev mlxfw_dev;
351         struct mlx5_core_dev *mlx5_core_dev;
352 };
353
354 static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
355                                 u16 component_index, u32 *p_max_size,
356                                 u8 *p_align_bits, u16 *p_max_write_size)
357 {
358         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
359                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
360         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
361
362         return mlx5_reg_mcqi_query(dev, component_index, p_max_size,
363                                    p_align_bits, p_max_write_size);
364 }
365
366 static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
367 {
368         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
369                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
370         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
371         u8 control_state, error_code;
372         int err;
373
374         *fwhandle = 0;
375         err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);
376         if (err)
377                 return err;
378
379         if (control_state != MLXFW_FSM_STATE_IDLE)
380                 return -EBUSY;
381
382         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,
383                                 0, *fwhandle, 0);
384 }
385
386 static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
387                                      u16 component_index, u32 component_size)
388 {
389         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
390                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
391         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
392
393         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
394                                 component_index, fwhandle, component_size);
395 }
396
397 static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
398                                    u8 *data, u16 size, u32 offset)
399 {
400         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
401                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
402         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
403
404         return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);
405 }
406
407 static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
408                                      u16 component_index)
409 {
410         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
411                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
412         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
413
414         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
415                                 component_index, fwhandle, 0);
416 }
417
418 static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
419 {
420         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
421                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
422         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
423
424         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0,
425                                 fwhandle, 0);
426 }
427
428 static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
429                                 enum mlxfw_fsm_state *fsm_state,
430                                 enum mlxfw_fsm_state_err *fsm_state_err)
431 {
432         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
433                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
434         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
435         u8 control_state, error_code;
436         int err;
437
438         err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);
439         if (err)
440                 return err;
441
442         *fsm_state = control_state;
443         *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,
444                                MLXFW_FSM_STATE_ERR_MAX);
445         return 0;
446 }
447
448 static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
449 {
450         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
451                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
452         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
453
454         mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
455 }
456
457 static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
458 {
459         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
460                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
461         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
462
463         mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,
464                          fwhandle, 0);
465 }
466
467 static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {
468         .component_query        = mlx5_component_query,
469         .fsm_lock               = mlx5_fsm_lock,
470         .fsm_component_update   = mlx5_fsm_component_update,
471         .fsm_block_download     = mlx5_fsm_block_download,
472         .fsm_component_verify   = mlx5_fsm_component_verify,
473         .fsm_activate           = mlx5_fsm_activate,
474         .fsm_query_state        = mlx5_fsm_query_state,
475         .fsm_cancel             = mlx5_fsm_cancel,
476         .fsm_release            = mlx5_fsm_release
477 };
478
479 int mlx5_firmware_flash(struct mlx5_core_dev *dev,
480                         const struct firmware *firmware)
481 {
482         struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {
483                 .mlxfw_dev = {
484                         .ops = &mlx5_mlxfw_dev_ops,
485                         .psid = dev->board_id,
486                         .psid_size = strlen(dev->board_id),
487                 },
488                 .mlx5_core_dev = dev
489         };
490
491         if (!MLX5_CAP_GEN(dev, mcam_reg)  ||
492             !MLX5_CAP_MCAM_REG(dev, mcqi) ||
493             !MLX5_CAP_MCAM_REG(dev, mcc)  ||
494             !MLX5_CAP_MCAM_REG(dev, mcda)) {
495                 pr_info("%s flashing isn't supported by the running FW\n", __func__);
496                 return -EOPNOTSUPP;
497         }
498
499         return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, firmware);
500 }