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/eswitch.h>
35 #include <linux/module.h>
36 #include "mlx5_core.h"
37 #include "../../mlxfw/mlxfw.h"
38 #include "lib/tout.h"
39 #include "accel/tls.h"
40
41 enum {
42 MCQS_IDENTIFIER_BOOT_IMG = 0x1,
43 MCQS_IDENTIFIER_OEM_NVCONFIG = 0x4,
44 MCQS_IDENTIFIER_MLNX_NVCONFIG = 0x5,
45 MCQS_IDENTIFIER_CS_TOKEN = 0x6,
46 MCQS_IDENTIFIER_DBG_TOKEN = 0x7,
47 MCQS_IDENTIFIER_GEARBOX = 0xA,
48 };
49
50 enum {
51 MCQS_UPDATE_STATE_IDLE,
52 MCQS_UPDATE_STATE_IN_PROGRESS,
53 MCQS_UPDATE_STATE_APPLIED,
54 MCQS_UPDATE_STATE_ACTIVE,
55 MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET,
56 MCQS_UPDATE_STATE_FAILED,
57 MCQS_UPDATE_STATE_CANCELED,
58 MCQS_UPDATE_STATE_BUSY,
59 };
60
61 enum {
62 MCQI_INFO_TYPE_CAPABILITIES = 0x0,
63 MCQI_INFO_TYPE_VERSION = 0x1,
64 MCQI_INFO_TYPE_ACTIVATION_METHOD = 0x5,
65 };
66
67 enum {
68 MCQI_FW_RUNNING_VERSION = 0,
69 MCQI_FW_STORED_VERSION = 1,
70 };
71
mlx5_query_board_id(struct mlx5_core_dev * dev)72 int mlx5_query_board_id(struct mlx5_core_dev *dev)
73 {
74 u32 *out;
75 int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
76 u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {};
77 int err;
78
79 out = kzalloc(outlen, GFP_KERNEL);
80 if (!out)
81 return -ENOMEM;
82
83 MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
84 err = mlx5_cmd_exec_inout(dev, query_adapter, in, out);
85 if (err)
86 goto out;
87
88 memcpy(dev->board_id,
89 MLX5_ADDR_OF(query_adapter_out, out,
90 query_adapter_struct.vsd_contd_psid),
91 MLX5_FLD_SZ_BYTES(query_adapter_out,
92 query_adapter_struct.vsd_contd_psid));
93
94 out:
95 kfree(out);
96 return err;
97 }
98
mlx5_core_query_vendor_id(struct mlx5_core_dev * mdev,u32 * vendor_id)99 int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)
100 {
101 u32 *out;
102 int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
103 u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {};
104 int err;
105
106 out = kzalloc(outlen, GFP_KERNEL);
107 if (!out)
108 return -ENOMEM;
109
110 MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
111 err = mlx5_cmd_exec_inout(mdev, query_adapter, in, out);
112 if (err)
113 goto out;
114
115 *vendor_id = MLX5_GET(query_adapter_out, out,
116 query_adapter_struct.ieee_vendor_id);
117 out:
118 kfree(out);
119 return err;
120 }
121 EXPORT_SYMBOL(mlx5_core_query_vendor_id);
122
mlx5_get_pcam_reg(struct mlx5_core_dev * dev)123 static int mlx5_get_pcam_reg(struct mlx5_core_dev *dev)
124 {
125 return mlx5_query_pcam_reg(dev, dev->caps.pcam,
126 MLX5_PCAM_FEATURE_ENHANCED_FEATURES,
127 MLX5_PCAM_REGS_5000_TO_507F);
128 }
129
mlx5_get_mcam_access_reg_group(struct mlx5_core_dev * dev,enum mlx5_mcam_reg_groups group)130 static int mlx5_get_mcam_access_reg_group(struct mlx5_core_dev *dev,
131 enum mlx5_mcam_reg_groups group)
132 {
133 return mlx5_query_mcam_reg(dev, dev->caps.mcam[group],
134 MLX5_MCAM_FEATURE_ENHANCED_FEATURES, group);
135 }
136
mlx5_get_qcam_reg(struct mlx5_core_dev * dev)137 static int mlx5_get_qcam_reg(struct mlx5_core_dev *dev)
138 {
139 return mlx5_query_qcam_reg(dev, dev->caps.qcam,
140 MLX5_QCAM_FEATURE_ENHANCED_FEATURES,
141 MLX5_QCAM_REGS_FIRST_128);
142 }
143
mlx5_query_hca_caps(struct mlx5_core_dev * dev)144 int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
145 {
146 int err;
147
148 err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
149 if (err)
150 return err;
151
152 if (MLX5_CAP_GEN(dev, port_selection_cap)) {
153 err = mlx5_core_get_caps(dev, MLX5_CAP_PORT_SELECTION);
154 if (err)
155 return err;
156 }
157
158 if (MLX5_CAP_GEN(dev, hca_cap_2)) {
159 err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL_2);
160 if (err)
161 return err;
162 }
163
164 if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
165 err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
166 if (err)
167 return err;
168 }
169
170 if (MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
171 err = mlx5_core_get_caps(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS);
172 if (err)
173 return err;
174 }
175
176 if (MLX5_CAP_GEN(dev, pg)) {
177 err = mlx5_core_get_caps(dev, MLX5_CAP_ODP);
178 if (err)
179 return err;
180 }
181
182 if (MLX5_CAP_GEN(dev, atomic)) {
183 err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
184 if (err)
185 return err;
186 }
187
188 if (MLX5_CAP_GEN(dev, roce)) {
189 err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE);
190 if (err)
191 return err;
192 }
193
194 if (MLX5_CAP_GEN(dev, nic_flow_table) ||
195 MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
196 err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
197 if (err)
198 return err;
199 }
200
201 if (MLX5_CAP_GEN(dev, vport_group_manager) &&
202 MLX5_ESWITCH_MANAGER(dev)) {
203 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
204 if (err)
205 return err;
206 }
207
208 if (MLX5_ESWITCH_MANAGER(dev)) {
209 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
210 if (err)
211 return err;
212 }
213
214 if (MLX5_CAP_GEN(dev, vector_calc)) {
215 err = mlx5_core_get_caps(dev, MLX5_CAP_VECTOR_CALC);
216 if (err)
217 return err;
218 }
219
220 if (MLX5_CAP_GEN(dev, qos)) {
221 err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
222 if (err)
223 return err;
224 }
225
226 if (MLX5_CAP_GEN(dev, debug))
227 mlx5_core_get_caps(dev, MLX5_CAP_DEBUG);
228
229 if (MLX5_CAP_GEN(dev, pcam_reg))
230 mlx5_get_pcam_reg(dev);
231
232 if (MLX5_CAP_GEN(dev, mcam_reg)) {
233 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128);
234 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9080_0x90FF);
235 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F);
236 }
237
238 if (MLX5_CAP_GEN(dev, qcam_reg))
239 mlx5_get_qcam_reg(dev);
240
241 if (MLX5_CAP_GEN(dev, device_memory)) {
242 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_MEM);
243 if (err)
244 return err;
245 }
246
247 if (MLX5_CAP_GEN(dev, event_cap)) {
248 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_EVENT);
249 if (err)
250 return err;
251 }
252
253 if (mlx5_accel_is_ktls_tx(dev) || mlx5_accel_is_ktls_rx(dev)) {
254 err = mlx5_core_get_caps(dev, MLX5_CAP_TLS);
255 if (err)
256 return err;
257 }
258
259 if (MLX5_CAP_GEN_64(dev, general_obj_types) &
260 MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) {
261 err = mlx5_core_get_caps(dev, MLX5_CAP_VDPA_EMULATION);
262 if (err)
263 return err;
264 }
265
266 if (MLX5_CAP_GEN(dev, ipsec_offload)) {
267 err = mlx5_core_get_caps(dev, MLX5_CAP_IPSEC);
268 if (err)
269 return err;
270 }
271
272 if (MLX5_CAP_GEN(dev, shampo)) {
273 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_SHAMPO);
274 if (err)
275 return err;
276 }
277
278 return 0;
279 }
280
mlx5_cmd_init_hca(struct mlx5_core_dev * dev,uint32_t * sw_owner_id)281 int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id)
282 {
283 u32 in[MLX5_ST_SZ_DW(init_hca_in)] = {};
284 int i;
285
286 MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);
287
288 if (MLX5_CAP_GEN(dev, sw_owner_id)) {
289 for (i = 0; i < 4; i++)
290 MLX5_ARRAY_SET(init_hca_in, in, sw_owner_id, i,
291 sw_owner_id[i]);
292 }
293
294 return mlx5_cmd_exec_in(dev, init_hca, in);
295 }
296
mlx5_cmd_teardown_hca(struct mlx5_core_dev * dev)297 int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
298 {
299 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};
300
301 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
302 return mlx5_cmd_exec_in(dev, teardown_hca, in);
303 }
304
mlx5_cmd_force_teardown_hca(struct mlx5_core_dev * dev)305 int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
306 {
307 u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
308 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
309 int force_state;
310 int ret;
311
312 if (!MLX5_CAP_GEN(dev, force_teardown)) {
313 mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
314 return -EOPNOTSUPP;
315 }
316
317 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
318 MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);
319
320 ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));
321 if (ret)
322 return ret;
323
324 force_state = MLX5_GET(teardown_hca_out, out, state);
325 if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
326 mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");
327 return -EIO;
328 }
329
330 return 0;
331 }
332
mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev * dev)333 int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev)
334 {
335 unsigned long end, delay_ms = mlx5_tout_ms(dev, TEARDOWN);
336 u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {};
337 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};
338 int state;
339 int ret;
340
341 if (!MLX5_CAP_GEN(dev, fast_teardown)) {
342 mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n");
343 return -EOPNOTSUPP;
344 }
345
346 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
347 MLX5_SET(teardown_hca_in, in, profile,
348 MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN);
349
350 ret = mlx5_cmd_exec_inout(dev, teardown_hca, in, out);
351 if (ret)
352 return ret;
353
354 state = MLX5_GET(teardown_hca_out, out, state);
355 if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
356 mlx5_core_warn(dev, "teardown with fast mode failed\n");
357 return -EIO;
358 }
359
360 mlx5_set_nic_state(dev, MLX5_NIC_IFC_DISABLED);
361
362 /* Loop until device state turns to disable */
363 end = jiffies + msecs_to_jiffies(delay_ms);
364 do {
365 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
366 break;
367
368 cond_resched();
369 } while (!time_after(jiffies, end));
370
371 if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
372 dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
373 mlx5_get_nic_state(dev), delay_ms);
374 return -EIO;
375 }
376
377 return 0;
378 }
379
380 enum mlxsw_reg_mcc_instruction {
381 MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
382 MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
383 MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,
384 MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,
385 MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,
386 MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,
387 };
388
mlx5_reg_mcc_set(struct mlx5_core_dev * dev,enum mlxsw_reg_mcc_instruction instr,u16 component_index,u32 update_handle,u32 component_size)389 static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,
390 enum mlxsw_reg_mcc_instruction instr,
391 u16 component_index, u32 update_handle,
392 u32 component_size)
393 {
394 u32 out[MLX5_ST_SZ_DW(mcc_reg)];
395 u32 in[MLX5_ST_SZ_DW(mcc_reg)];
396
397 memset(in, 0, sizeof(in));
398
399 MLX5_SET(mcc_reg, in, instruction, instr);
400 MLX5_SET(mcc_reg, in, component_index, component_index);
401 MLX5_SET(mcc_reg, in, update_handle, update_handle);
402 MLX5_SET(mcc_reg, in, component_size, component_size);
403
404 return mlx5_core_access_reg(dev, in, sizeof(in), out,
405 sizeof(out), MLX5_REG_MCC, 0, 1);
406 }
407
mlx5_reg_mcc_query(struct mlx5_core_dev * dev,u32 * update_handle,u8 * error_code,u8 * control_state)408 static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,
409 u32 *update_handle, u8 *error_code,
410 u8 *control_state)
411 {
412 u32 out[MLX5_ST_SZ_DW(mcc_reg)];
413 u32 in[MLX5_ST_SZ_DW(mcc_reg)];
414 int err;
415
416 memset(in, 0, sizeof(in));
417 memset(out, 0, sizeof(out));
418 MLX5_SET(mcc_reg, in, update_handle, *update_handle);
419
420 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
421 sizeof(out), MLX5_REG_MCC, 0, 0);
422 if (err)
423 goto out;
424
425 *update_handle = MLX5_GET(mcc_reg, out, update_handle);
426 *error_code = MLX5_GET(mcc_reg, out, error_code);
427 *control_state = MLX5_GET(mcc_reg, out, control_state);
428
429 out:
430 return err;
431 }
432
mlx5_reg_mcda_set(struct mlx5_core_dev * dev,u32 update_handle,u32 offset,u16 size,u8 * data)433 static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
434 u32 update_handle,
435 u32 offset, u16 size,
436 u8 *data)
437 {
438 int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;
439 u32 out[MLX5_ST_SZ_DW(mcda_reg)];
440 int i, j, dw_size = size >> 2;
441 __be32 data_element;
442 u32 *in;
443
444 in = kzalloc(in_size, GFP_KERNEL);
445 if (!in)
446 return -ENOMEM;
447
448 MLX5_SET(mcda_reg, in, update_handle, update_handle);
449 MLX5_SET(mcda_reg, in, offset, offset);
450 MLX5_SET(mcda_reg, in, size, size);
451
452 for (i = 0; i < dw_size; i++) {
453 j = i * 4;
454 data_element = htonl(*(u32 *)&data[j]);
455 memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);
456 }
457
458 err = mlx5_core_access_reg(dev, in, in_size, out,
459 sizeof(out), MLX5_REG_MCDA, 0, 1);
460 kfree(in);
461 return err;
462 }
463
mlx5_reg_mcqi_query(struct mlx5_core_dev * dev,u16 component_index,bool read_pending,u8 info_type,u16 data_size,void * mcqi_data)464 static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
465 u16 component_index, bool read_pending,
466 u8 info_type, u16 data_size, void *mcqi_data)
467 {
468 u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_UN_SZ_DW(mcqi_reg_data)] = {};
469 u32 in[MLX5_ST_SZ_DW(mcqi_reg)] = {};
470 void *data;
471 int err;
472
473 MLX5_SET(mcqi_reg, in, component_index, component_index);
474 MLX5_SET(mcqi_reg, in, read_pending_component, read_pending);
475 MLX5_SET(mcqi_reg, in, info_type, info_type);
476 MLX5_SET(mcqi_reg, in, data_size, data_size);
477
478 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
479 MLX5_ST_SZ_BYTES(mcqi_reg) + data_size,
480 MLX5_REG_MCQI, 0, 0);
481 if (err)
482 return err;
483
484 data = MLX5_ADDR_OF(mcqi_reg, out, data);
485 memcpy(mcqi_data, data, data_size);
486
487 return 0;
488 }
489
mlx5_reg_mcqi_caps_query(struct mlx5_core_dev * dev,u16 component_index,u32 * max_component_size,u8 * log_mcda_word_size,u16 * mcda_max_write_size)490 static int mlx5_reg_mcqi_caps_query(struct mlx5_core_dev *dev, u16 component_index,
491 u32 *max_component_size, u8 *log_mcda_word_size,
492 u16 *mcda_max_write_size)
493 {
494 u32 mcqi_reg[MLX5_ST_SZ_DW(mcqi_cap)] = {};
495 int err;
496
497 err = mlx5_reg_mcqi_query(dev, component_index, 0,
498 MCQI_INFO_TYPE_CAPABILITIES,
499 MLX5_ST_SZ_BYTES(mcqi_cap), mcqi_reg);
500 if (err)
501 return err;
502
503 *max_component_size = MLX5_GET(mcqi_cap, mcqi_reg, max_component_size);
504 *log_mcda_word_size = MLX5_GET(mcqi_cap, mcqi_reg, log_mcda_word_size);
505 *mcda_max_write_size = MLX5_GET(mcqi_cap, mcqi_reg, mcda_max_write_size);
506
507 return 0;
508 }
509
510 struct mlx5_mlxfw_dev {
511 struct mlxfw_dev mlxfw_dev;
512 struct mlx5_core_dev *mlx5_core_dev;
513 };
514
mlx5_component_query(struct mlxfw_dev * mlxfw_dev,u16 component_index,u32 * p_max_size,u8 * p_align_bits,u16 * p_max_write_size)515 static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
516 u16 component_index, u32 *p_max_size,
517 u8 *p_align_bits, u16 *p_max_write_size)
518 {
519 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
520 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
521 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
522
523 if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi)) {
524 mlx5_core_warn(dev, "caps query isn't supported by running FW\n");
525 return -EOPNOTSUPP;
526 }
527
528 return mlx5_reg_mcqi_caps_query(dev, component_index, p_max_size,
529 p_align_bits, p_max_write_size);
530 }
531
mlx5_fsm_lock(struct mlxfw_dev * mlxfw_dev,u32 * fwhandle)532 static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
533 {
534 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
535 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
536 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
537 u8 control_state, error_code;
538 int err;
539
540 *fwhandle = 0;
541 err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);
542 if (err)
543 return err;
544
545 if (control_state != MLXFW_FSM_STATE_IDLE)
546 return -EBUSY;
547
548 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,
549 0, *fwhandle, 0);
550 }
551
mlx5_fsm_component_update(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,u16 component_index,u32 component_size)552 static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
553 u16 component_index, u32 component_size)
554 {
555 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
556 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
557 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
558
559 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
560 component_index, fwhandle, component_size);
561 }
562
mlx5_fsm_block_download(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,u8 * data,u16 size,u32 offset)563 static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
564 u8 *data, u16 size, u32 offset)
565 {
566 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
567 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
568 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
569
570 return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);
571 }
572
mlx5_fsm_component_verify(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,u16 component_index)573 static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
574 u16 component_index)
575 {
576 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
577 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
578 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
579
580 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
581 component_index, fwhandle, 0);
582 }
583
mlx5_fsm_activate(struct mlxfw_dev * mlxfw_dev,u32 fwhandle)584 static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
585 {
586 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
587 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
588 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
589
590 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0,
591 fwhandle, 0);
592 }
593
mlx5_fsm_query_state(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,enum mlxfw_fsm_state * fsm_state,enum mlxfw_fsm_state_err * fsm_state_err)594 static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
595 enum mlxfw_fsm_state *fsm_state,
596 enum mlxfw_fsm_state_err *fsm_state_err)
597 {
598 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
599 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
600 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
601 u8 control_state, error_code;
602 int err;
603
604 err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);
605 if (err)
606 return err;
607
608 *fsm_state = control_state;
609 *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,
610 MLXFW_FSM_STATE_ERR_MAX);
611 return 0;
612 }
613
mlx5_fsm_cancel(struct mlxfw_dev * mlxfw_dev,u32 fwhandle)614 static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
615 {
616 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
617 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
618 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
619
620 mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
621 }
622
mlx5_fsm_release(struct mlxfw_dev * mlxfw_dev,u32 fwhandle)623 static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
624 {
625 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
626 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
627 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
628
629 mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,
630 fwhandle, 0);
631 }
632
mlx5_fsm_reactivate(struct mlxfw_dev * mlxfw_dev,u8 * status)633 static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status)
634 {
635 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
636 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
637 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
638 u32 out[MLX5_ST_SZ_DW(mirc_reg)];
639 u32 in[MLX5_ST_SZ_DW(mirc_reg)];
640 unsigned long exp_time;
641 int err;
642
643 exp_time = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, FSM_REACTIVATE));
644
645 if (!MLX5_CAP_MCAM_REG2(dev, mirc))
646 return -EOPNOTSUPP;
647
648 memset(in, 0, sizeof(in));
649
650 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
651 sizeof(out), MLX5_REG_MIRC, 0, 1);
652 if (err)
653 return err;
654
655 do {
656 memset(out, 0, sizeof(out));
657 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
658 sizeof(out), MLX5_REG_MIRC, 0, 0);
659 if (err)
660 return err;
661
662 *status = MLX5_GET(mirc_reg, out, status_code);
663 if (*status != MLXFW_FSM_REACTIVATE_STATUS_BUSY)
664 return 0;
665
666 msleep(20);
667 } while (time_before(jiffies, exp_time));
668
669 return 0;
670 }
671
672 static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {
673 .component_query = mlx5_component_query,
674 .fsm_lock = mlx5_fsm_lock,
675 .fsm_component_update = mlx5_fsm_component_update,
676 .fsm_block_download = mlx5_fsm_block_download,
677 .fsm_component_verify = mlx5_fsm_component_verify,
678 .fsm_activate = mlx5_fsm_activate,
679 .fsm_reactivate = mlx5_fsm_reactivate,
680 .fsm_query_state = mlx5_fsm_query_state,
681 .fsm_cancel = mlx5_fsm_cancel,
682 .fsm_release = mlx5_fsm_release
683 };
684
mlx5_firmware_flash(struct mlx5_core_dev * dev,const struct firmware * firmware,struct netlink_ext_ack * extack)685 int mlx5_firmware_flash(struct mlx5_core_dev *dev,
686 const struct firmware *firmware,
687 struct netlink_ext_ack *extack)
688 {
689 struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {
690 .mlxfw_dev = {
691 .ops = &mlx5_mlxfw_dev_ops,
692 .psid = dev->board_id,
693 .psid_size = strlen(dev->board_id),
694 .devlink = priv_to_devlink(dev),
695 },
696 .mlx5_core_dev = dev
697 };
698
699 if (!MLX5_CAP_GEN(dev, mcam_reg) ||
700 !MLX5_CAP_MCAM_REG(dev, mcqi) ||
701 !MLX5_CAP_MCAM_REG(dev, mcc) ||
702 !MLX5_CAP_MCAM_REG(dev, mcda)) {
703 pr_info("%s flashing isn't supported by the running FW\n", __func__);
704 return -EOPNOTSUPP;
705 }
706
707 return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev,
708 firmware, extack);
709 }
710
mlx5_reg_mcqi_version_query(struct mlx5_core_dev * dev,u16 component_index,bool read_pending,u32 * mcqi_version_out)711 static int mlx5_reg_mcqi_version_query(struct mlx5_core_dev *dev,
712 u16 component_index, bool read_pending,
713 u32 *mcqi_version_out)
714 {
715 return mlx5_reg_mcqi_query(dev, component_index, read_pending,
716 MCQI_INFO_TYPE_VERSION,
717 MLX5_ST_SZ_BYTES(mcqi_version),
718 mcqi_version_out);
719 }
720
mlx5_reg_mcqs_query(struct mlx5_core_dev * dev,u32 * out,u16 component_index)721 static int mlx5_reg_mcqs_query(struct mlx5_core_dev *dev, u32 *out,
722 u16 component_index)
723 {
724 u8 out_sz = MLX5_ST_SZ_BYTES(mcqs_reg);
725 u32 in[MLX5_ST_SZ_DW(mcqs_reg)] = {};
726 int err;
727
728 memset(out, 0, out_sz);
729
730 MLX5_SET(mcqs_reg, in, component_index, component_index);
731
732 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
733 out_sz, MLX5_REG_MCQS, 0, 0);
734 return err;
735 }
736
737 /* scans component index sequentially, to find the boot img index */
mlx5_get_boot_img_component_index(struct mlx5_core_dev * dev)738 static int mlx5_get_boot_img_component_index(struct mlx5_core_dev *dev)
739 {
740 u32 out[MLX5_ST_SZ_DW(mcqs_reg)] = {};
741 u16 identifier, component_idx = 0;
742 bool quit;
743 int err;
744
745 do {
746 err = mlx5_reg_mcqs_query(dev, out, component_idx);
747 if (err)
748 return err;
749
750 identifier = MLX5_GET(mcqs_reg, out, identifier);
751 quit = !!MLX5_GET(mcqs_reg, out, last_index_flag);
752 quit |= identifier == MCQS_IDENTIFIER_BOOT_IMG;
753 } while (!quit && ++component_idx);
754
755 if (identifier != MCQS_IDENTIFIER_BOOT_IMG) {
756 mlx5_core_warn(dev, "mcqs: can't find boot_img component ix, last scanned idx %d\n",
757 component_idx);
758 return -EOPNOTSUPP;
759 }
760
761 return component_idx;
762 }
763
764 static int
mlx5_fw_image_pending(struct mlx5_core_dev * dev,int component_index,bool * pending_version_exists)765 mlx5_fw_image_pending(struct mlx5_core_dev *dev,
766 int component_index,
767 bool *pending_version_exists)
768 {
769 u32 out[MLX5_ST_SZ_DW(mcqs_reg)];
770 u8 component_update_state;
771 int err;
772
773 err = mlx5_reg_mcqs_query(dev, out, component_index);
774 if (err)
775 return err;
776
777 component_update_state = MLX5_GET(mcqs_reg, out, component_update_state);
778
779 if (component_update_state == MCQS_UPDATE_STATE_IDLE) {
780 *pending_version_exists = false;
781 } else if (component_update_state == MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET) {
782 *pending_version_exists = true;
783 } else {
784 mlx5_core_warn(dev,
785 "mcqs: can't read pending fw version while fw state is %d\n",
786 component_update_state);
787 return -ENODATA;
788 }
789 return 0;
790 }
791
mlx5_fw_version_query(struct mlx5_core_dev * dev,u32 * running_ver,u32 * pending_ver)792 int mlx5_fw_version_query(struct mlx5_core_dev *dev,
793 u32 *running_ver, u32 *pending_ver)
794 {
795 u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
796 bool pending_version_exists;
797 int component_index;
798 int err;
799
800 if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
801 !MLX5_CAP_MCAM_REG(dev, mcqs)) {
802 mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
803 return -EOPNOTSUPP;
804 }
805
806 component_index = mlx5_get_boot_img_component_index(dev);
807 if (component_index < 0)
808 return component_index;
809
810 err = mlx5_reg_mcqi_version_query(dev, component_index,
811 MCQI_FW_RUNNING_VERSION,
812 reg_mcqi_version);
813 if (err)
814 return err;
815
816 *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
817
818 err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
819 if (err)
820 return err;
821
822 if (!pending_version_exists) {
823 *pending_ver = 0;
824 return 0;
825 }
826
827 err = mlx5_reg_mcqi_version_query(dev, component_index,
828 MCQI_FW_STORED_VERSION,
829 reg_mcqi_version);
830 if (err)
831 return err;
832
833 *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
834
835 return 0;
836 }
837