File Index
Files and directories
Sign in
FILE

fw.c

File preview with syntax highlighting.

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