Merge branch 'drm-tda998x-devel' of git://git.armlinux.org.uk/~rmk/linux-arm into...
[sfrench/cifs-2.6.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 "../../mlxfw/mlxfw.h"
38
39 static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
40                                   int outlen)
41 {
42         u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {0};
43
44         MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
45         return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
46 }
47
48 int mlx5_query_board_id(struct mlx5_core_dev *dev)
49 {
50         u32 *out;
51         int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
52         int err;
53
54         out = kzalloc(outlen, GFP_KERNEL);
55         if (!out)
56                 return -ENOMEM;
57
58         err = mlx5_cmd_query_adapter(dev, out, outlen);
59         if (err)
60                 goto out;
61
62         memcpy(dev->board_id,
63                MLX5_ADDR_OF(query_adapter_out, out,
64                             query_adapter_struct.vsd_contd_psid),
65                MLX5_FLD_SZ_BYTES(query_adapter_out,
66                                  query_adapter_struct.vsd_contd_psid));
67
68 out:
69         kfree(out);
70         return err;
71 }
72
73 int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)
74 {
75         u32 *out;
76         int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
77         int err;
78
79         out = kzalloc(outlen, GFP_KERNEL);
80         if (!out)
81                 return -ENOMEM;
82
83         err = mlx5_cmd_query_adapter(mdev, out, outlen);
84         if (err)
85                 goto out;
86
87         *vendor_id = MLX5_GET(query_adapter_out, out,
88                               query_adapter_struct.ieee_vendor_id);
89 out:
90         kfree(out);
91         return err;
92 }
93 EXPORT_SYMBOL(mlx5_core_query_vendor_id);
94
95 static int mlx5_get_pcam_reg(struct mlx5_core_dev *dev)
96 {
97         return mlx5_query_pcam_reg(dev, dev->caps.pcam,
98                                    MLX5_PCAM_FEATURE_ENHANCED_FEATURES,
99                                    MLX5_PCAM_REGS_5000_TO_507F);
100 }
101
102 static int mlx5_get_mcam_reg(struct mlx5_core_dev *dev)
103 {
104         return mlx5_query_mcam_reg(dev, dev->caps.mcam,
105                                    MLX5_MCAM_FEATURE_ENHANCED_FEATURES,
106                                    MLX5_MCAM_REGS_FIRST_128);
107 }
108
109 static int mlx5_get_qcam_reg(struct mlx5_core_dev *dev)
110 {
111         return mlx5_query_qcam_reg(dev, dev->caps.qcam,
112                                    MLX5_QCAM_FEATURE_ENHANCED_FEATURES,
113                                    MLX5_QCAM_REGS_FIRST_128);
114 }
115
116 int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
117 {
118         int err;
119
120         err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
121         if (err)
122                 return err;
123
124         if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
125                 err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
126                 if (err)
127                         return err;
128         }
129
130         if (MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
131                 err = mlx5_core_get_caps(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS);
132                 if (err)
133                         return err;
134         }
135
136         if (MLX5_CAP_GEN(dev, pg)) {
137                 err = mlx5_core_get_caps(dev, MLX5_CAP_ODP);
138                 if (err)
139                         return err;
140         }
141
142         if (MLX5_CAP_GEN(dev, atomic)) {
143                 err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
144                 if (err)
145                         return err;
146         }
147
148         if (MLX5_CAP_GEN(dev, roce)) {
149                 err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE);
150                 if (err)
151                         return err;
152         }
153
154         if (MLX5_CAP_GEN(dev, nic_flow_table) ||
155             MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
156                 err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
157                 if (err)
158                         return err;
159         }
160
161         if (MLX5_CAP_GEN(dev, vport_group_manager) &&
162             MLX5_CAP_GEN(dev, eswitch_flow_table)) {
163                 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
164                 if (err)
165                         return err;
166         }
167
168         if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
169                 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
170                 if (err)
171                         return err;
172         }
173
174         if (MLX5_CAP_GEN(dev, vector_calc)) {
175                 err = mlx5_core_get_caps(dev, MLX5_CAP_VECTOR_CALC);
176                 if (err)
177                         return err;
178         }
179
180         if (MLX5_CAP_GEN(dev, qos)) {
181                 err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
182                 if (err)
183                         return err;
184         }
185
186         if (MLX5_CAP_GEN(dev, debug))
187                 mlx5_core_get_caps(dev, MLX5_CAP_DEBUG);
188
189         if (MLX5_CAP_GEN(dev, pcam_reg))
190                 mlx5_get_pcam_reg(dev);
191
192         if (MLX5_CAP_GEN(dev, mcam_reg))
193                 mlx5_get_mcam_reg(dev);
194
195         if (MLX5_CAP_GEN(dev, qcam_reg))
196                 mlx5_get_qcam_reg(dev);
197
198         if (MLX5_CAP_GEN(dev, device_memory)) {
199                 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_MEM);
200                 if (err)
201                         return err;
202         }
203
204         return 0;
205 }
206
207 int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id)
208 {
209         u32 out[MLX5_ST_SZ_DW(init_hca_out)] = {0};
210         u32 in[MLX5_ST_SZ_DW(init_hca_in)]   = {0};
211         int i;
212
213         MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);
214
215         if (MLX5_CAP_GEN(dev, sw_owner_id)) {
216                 for (i = 0; i < 4; i++)
217                         MLX5_ARRAY_SET(init_hca_in, in, sw_owner_id, i,
218                                        sw_owner_id[i]);
219         }
220
221         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
222 }
223
224 int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
225 {
226         u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
227         u32 in[MLX5_ST_SZ_DW(teardown_hca_in)]   = {0};
228
229         MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
230         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
231 }
232
233 int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
234 {
235         u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
236         u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
237         int force_state;
238         int ret;
239
240         if (!MLX5_CAP_GEN(dev, force_teardown)) {
241                 mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
242                 return -EOPNOTSUPP;
243         }
244
245         MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
246         MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);
247
248         ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));
249         if (ret)
250                 return ret;
251
252         force_state = MLX5_GET(teardown_hca_out, out, force_state);
253         if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
254                 mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");
255                 return -EIO;
256         }
257
258         return 0;
259 }
260
261 enum mlxsw_reg_mcc_instruction {
262         MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
263         MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
264         MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,
265         MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,
266         MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,
267         MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,
268 };
269
270 static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,
271                             enum mlxsw_reg_mcc_instruction instr,
272                             u16 component_index, u32 update_handle,
273                             u32 component_size)
274 {
275         u32 out[MLX5_ST_SZ_DW(mcc_reg)];
276         u32 in[MLX5_ST_SZ_DW(mcc_reg)];
277
278         memset(in, 0, sizeof(in));
279
280         MLX5_SET(mcc_reg, in, instruction, instr);
281         MLX5_SET(mcc_reg, in, component_index, component_index);
282         MLX5_SET(mcc_reg, in, update_handle, update_handle);
283         MLX5_SET(mcc_reg, in, component_size, component_size);
284
285         return mlx5_core_access_reg(dev, in, sizeof(in), out,
286                                     sizeof(out), MLX5_REG_MCC, 0, 1);
287 }
288
289 static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,
290                               u32 *update_handle, u8 *error_code,
291                               u8 *control_state)
292 {
293         u32 out[MLX5_ST_SZ_DW(mcc_reg)];
294         u32 in[MLX5_ST_SZ_DW(mcc_reg)];
295         int err;
296
297         memset(in, 0, sizeof(in));
298         memset(out, 0, sizeof(out));
299         MLX5_SET(mcc_reg, in, update_handle, *update_handle);
300
301         err = mlx5_core_access_reg(dev, in, sizeof(in), out,
302                                    sizeof(out), MLX5_REG_MCC, 0, 0);
303         if (err)
304                 goto out;
305
306         *update_handle = MLX5_GET(mcc_reg, out, update_handle);
307         *error_code = MLX5_GET(mcc_reg, out, error_code);
308         *control_state = MLX5_GET(mcc_reg, out, control_state);
309
310 out:
311         return err;
312 }
313
314 static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
315                              u32 update_handle,
316                              u32 offset, u16 size,
317                              u8 *data)
318 {
319         int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;
320         u32 out[MLX5_ST_SZ_DW(mcda_reg)];
321         int i, j, dw_size = size >> 2;
322         __be32 data_element;
323         u32 *in;
324
325         in = kzalloc(in_size, GFP_KERNEL);
326         if (!in)
327                 return -ENOMEM;
328
329         MLX5_SET(mcda_reg, in, update_handle, update_handle);
330         MLX5_SET(mcda_reg, in, offset, offset);
331         MLX5_SET(mcda_reg, in, size, size);
332
333         for (i = 0; i < dw_size; i++) {
334                 j = i * 4;
335                 data_element = htonl(*(u32 *)&data[j]);
336                 memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);
337         }
338
339         err = mlx5_core_access_reg(dev, in, in_size, out,
340                                    sizeof(out), MLX5_REG_MCDA, 0, 1);
341         kfree(in);
342         return err;
343 }
344
345 static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
346                                u16 component_index,
347                                u32 *max_component_size,
348                                u8 *log_mcda_word_size,
349                                u16 *mcda_max_write_size)
350 {
351         u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_ST_SZ_DW(mcqi_cap)];
352         int offset = MLX5_ST_SZ_DW(mcqi_reg);
353         u32 in[MLX5_ST_SZ_DW(mcqi_reg)];
354         int err;
355
356         memset(in, 0, sizeof(in));
357         memset(out, 0, sizeof(out));
358
359         MLX5_SET(mcqi_reg, in, component_index, component_index);
360         MLX5_SET(mcqi_reg, in, data_size, MLX5_ST_SZ_BYTES(mcqi_cap));
361
362         err = mlx5_core_access_reg(dev, in, sizeof(in), out,
363                                    sizeof(out), MLX5_REG_MCQI, 0, 0);
364         if (err)
365                 goto out;
366
367         *max_component_size = MLX5_GET(mcqi_cap, out + offset, max_component_size);
368         *log_mcda_word_size = MLX5_GET(mcqi_cap, out + offset, log_mcda_word_size);
369         *mcda_max_write_size = MLX5_GET(mcqi_cap, out + offset, mcda_max_write_size);
370
371 out:
372         return err;
373 }
374
375 struct mlx5_mlxfw_dev {
376         struct mlxfw_dev mlxfw_dev;
377         struct mlx5_core_dev *mlx5_core_dev;
378 };
379
380 static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
381                                 u16 component_index, u32 *p_max_size,
382                                 u8 *p_align_bits, u16 *p_max_write_size)
383 {
384         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
385                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
386         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
387
388         return mlx5_reg_mcqi_query(dev, component_index, p_max_size,
389                                    p_align_bits, p_max_write_size);
390 }
391
392 static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
393 {
394         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
395                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
396         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
397         u8 control_state, error_code;
398         int err;
399
400         *fwhandle = 0;
401         err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);
402         if (err)
403                 return err;
404
405         if (control_state != MLXFW_FSM_STATE_IDLE)
406                 return -EBUSY;
407
408         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,
409                                 0, *fwhandle, 0);
410 }
411
412 static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
413                                      u16 component_index, u32 component_size)
414 {
415         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
416                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
417         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
418
419         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
420                                 component_index, fwhandle, component_size);
421 }
422
423 static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
424                                    u8 *data, u16 size, u32 offset)
425 {
426         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
427                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
428         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
429
430         return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);
431 }
432
433 static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
434                                      u16 component_index)
435 {
436         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
437                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
438         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
439
440         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
441                                 component_index, fwhandle, 0);
442 }
443
444 static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
445 {
446         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
447                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
448         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
449
450         return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0,
451                                 fwhandle, 0);
452 }
453
454 static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
455                                 enum mlxfw_fsm_state *fsm_state,
456                                 enum mlxfw_fsm_state_err *fsm_state_err)
457 {
458         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
459                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
460         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
461         u8 control_state, error_code;
462         int err;
463
464         err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);
465         if (err)
466                 return err;
467
468         *fsm_state = control_state;
469         *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,
470                                MLXFW_FSM_STATE_ERR_MAX);
471         return 0;
472 }
473
474 static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
475 {
476         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
477                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
478         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
479
480         mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
481 }
482
483 static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
484 {
485         struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
486                 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
487         struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
488
489         mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,
490                          fwhandle, 0);
491 }
492
493 static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {
494         .component_query        = mlx5_component_query,
495         .fsm_lock               = mlx5_fsm_lock,
496         .fsm_component_update   = mlx5_fsm_component_update,
497         .fsm_block_download     = mlx5_fsm_block_download,
498         .fsm_component_verify   = mlx5_fsm_component_verify,
499         .fsm_activate           = mlx5_fsm_activate,
500         .fsm_query_state        = mlx5_fsm_query_state,
501         .fsm_cancel             = mlx5_fsm_cancel,
502         .fsm_release            = mlx5_fsm_release
503 };
504
505 int mlx5_firmware_flash(struct mlx5_core_dev *dev,
506                         const struct firmware *firmware)
507 {
508         struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {
509                 .mlxfw_dev = {
510                         .ops = &mlx5_mlxfw_dev_ops,
511                         .psid = dev->board_id,
512                         .psid_size = strlen(dev->board_id),
513                 },
514                 .mlx5_core_dev = dev
515         };
516
517         if (!MLX5_CAP_GEN(dev, mcam_reg)  ||
518             !MLX5_CAP_MCAM_REG(dev, mcqi) ||
519             !MLX5_CAP_MCAM_REG(dev, mcc)  ||
520             !MLX5_CAP_MCAM_REG(dev, mcda)) {
521                 pr_info("%s flashing isn't supported by the running FW\n", __func__);
522                 return -EOPNOTSUPP;
523         }
524
525         return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, firmware);
526 }