brintos

brintos / linux-shallow public Read only

0
0
Text · 23.3 KiB · 76ad46b Raw
851 lines · 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 two5 * licenses.  You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 *     Redistribution and use in source and binary forms, with or11 *     without modification, are permitted provided that the following12 *     conditions are met:13 *14 *      - Redistributions of source code must retain the above15 *        copyright notice, this list of conditions and the following16 *        disclaimer.17 *18 *      - Redistributions in binary form must reproduce the above19 *        copyright notice, this list of conditions and the following20 *        disclaimer in the documentation and/or other materials21 *        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 OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * 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	return 0;285}286 287int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, u32 *sw_owner_id)288{289	u32 in[MLX5_ST_SZ_DW(init_hca_in)] = {};290	int i;291 292	MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);293 294	if (MLX5_CAP_GEN(dev, sw_owner_id)) {295		for (i = 0; i < 4; i++)296			MLX5_ARRAY_SET(init_hca_in, in, sw_owner_id, i,297				       sw_owner_id[i]);298	}299 300	if (MLX5_CAP_GEN_2_MAX(dev, sw_vhca_id_valid) &&301	    dev->priv.sw_vhca_id > 0)302		MLX5_SET(init_hca_in, in, sw_vhca_id, dev->priv.sw_vhca_id);303 304	return mlx5_cmd_exec_in(dev, init_hca, in);305}306 307int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)308{309	u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};310 311	MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);312	return mlx5_cmd_exec_in(dev, teardown_hca, in);313}314 315int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)316{317	u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};318	u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};319	int force_state;320	int ret;321 322	if (!MLX5_CAP_GEN(dev, force_teardown)) {323		mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");324		return -EOPNOTSUPP;325	}326 327	MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);328	MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);329 330	ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));331	if (ret)332		return ret;333 334	force_state = MLX5_GET(teardown_hca_out, out, state);335	if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {336		mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");337		return -EIO;338	}339 340	return 0;341}342 343int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev)344{345	unsigned long end, delay_ms = mlx5_tout_ms(dev, TEARDOWN);346	u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {};347	u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};348	int state;349	int ret;350 351	if (!MLX5_CAP_GEN(dev, fast_teardown)) {352		mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n");353		return -EOPNOTSUPP;354	}355 356	MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);357	MLX5_SET(teardown_hca_in, in, profile,358		 MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN);359 360	ret = mlx5_cmd_exec_inout(dev, teardown_hca, in, out);361	if (ret)362		return ret;363 364	state = MLX5_GET(teardown_hca_out, out, state);365	if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {366		mlx5_core_warn(dev, "teardown with fast mode failed\n");367		return -EIO;368	}369 370	mlx5_set_nic_state(dev, MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED);371 372	/* Loop until device state turns to disable */373	end = jiffies + msecs_to_jiffies(delay_ms);374	do {375		if (mlx5_get_nic_state(dev) == MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED)376			break;377		if (pci_channel_offline(dev->pdev)) {378			mlx5_core_err(dev, "PCI channel offline, stop waiting for NIC IFC\n");379			return -EACCES;380		}381 382		cond_resched();383	} while (!time_after(jiffies, end));384 385	if (mlx5_get_nic_state(dev) != MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) {386		dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",387			mlx5_get_nic_state(dev), delay_ms);388		return -EIO;389	}390 391	return 0;392}393 394enum mlxsw_reg_mcc_instruction {395	MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,396	MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,397	MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,398	MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,399	MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,400	MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,401};402 403static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,404			    enum mlxsw_reg_mcc_instruction instr,405			    u16 component_index, u32 update_handle,406			    u32 component_size)407{408	u32 out[MLX5_ST_SZ_DW(mcc_reg)];409	u32 in[MLX5_ST_SZ_DW(mcc_reg)];410 411	memset(in, 0, sizeof(in));412 413	MLX5_SET(mcc_reg, in, instruction, instr);414	MLX5_SET(mcc_reg, in, component_index, component_index);415	MLX5_SET(mcc_reg, in, update_handle, update_handle);416	MLX5_SET(mcc_reg, in, component_size, component_size);417 418	return mlx5_core_access_reg(dev, in, sizeof(in), out,419				    sizeof(out), MLX5_REG_MCC, 0, 1);420}421 422static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,423			      u32 *update_handle, u8 *error_code,424			      u8 *control_state)425{426	u32 out[MLX5_ST_SZ_DW(mcc_reg)];427	u32 in[MLX5_ST_SZ_DW(mcc_reg)];428	int err;429 430	memset(in, 0, sizeof(in));431	memset(out, 0, sizeof(out));432	MLX5_SET(mcc_reg, in, update_handle, *update_handle);433 434	err = mlx5_core_access_reg(dev, in, sizeof(in), out,435				   sizeof(out), MLX5_REG_MCC, 0, 0);436	if (err)437		goto out;438 439	*update_handle = MLX5_GET(mcc_reg, out, update_handle);440	*error_code = MLX5_GET(mcc_reg, out, error_code);441	*control_state = MLX5_GET(mcc_reg, out, control_state);442 443out:444	return err;445}446 447static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,448			     u32 update_handle,449			     u32 offset, u16 size,450			     u8 *data)451{452	int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;453	u32 out[MLX5_ST_SZ_DW(mcda_reg)];454	int i, j, dw_size = size >> 2;455	__be32 data_element;456	u32 *in;457 458	in = kzalloc(in_size, GFP_KERNEL);459	if (!in)460		return -ENOMEM;461 462	MLX5_SET(mcda_reg, in, update_handle, update_handle);463	MLX5_SET(mcda_reg, in, offset, offset);464	MLX5_SET(mcda_reg, in, size, size);465 466	for (i = 0; i < dw_size; i++) {467		j = i * 4;468		data_element = htonl(*(u32 *)&data[j]);469		memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);470	}471 472	err = mlx5_core_access_reg(dev, in, in_size, out,473				   sizeof(out), MLX5_REG_MCDA, 0, 1);474	kfree(in);475	return err;476}477 478static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,479			       u16 component_index, bool read_pending,480			       u8 info_type, u16 data_size, void *mcqi_data)481{482	u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_UN_SZ_DW(mcqi_reg_data)] = {};483	u32 in[MLX5_ST_SZ_DW(mcqi_reg)] = {};484	void *data;485	int err;486 487	MLX5_SET(mcqi_reg, in, component_index, component_index);488	MLX5_SET(mcqi_reg, in, read_pending_component, read_pending);489	MLX5_SET(mcqi_reg, in, info_type, info_type);490	MLX5_SET(mcqi_reg, in, data_size, data_size);491 492	err = mlx5_core_access_reg(dev, in, sizeof(in), out,493				   MLX5_ST_SZ_BYTES(mcqi_reg) + data_size,494				   MLX5_REG_MCQI, 0, 0);495	if (err)496		return err;497 498	data = MLX5_ADDR_OF(mcqi_reg, out, data);499	memcpy(mcqi_data, data, data_size);500 501	return 0;502}503 504static int mlx5_reg_mcqi_caps_query(struct mlx5_core_dev *dev, u16 component_index,505				    u32 *max_component_size, u8 *log_mcda_word_size,506				    u16 *mcda_max_write_size)507{508	u32 mcqi_reg[MLX5_ST_SZ_DW(mcqi_cap)] = {};509	int err;510 511	err = mlx5_reg_mcqi_query(dev, component_index, 0,512				  MCQI_INFO_TYPE_CAPABILITIES,513				  MLX5_ST_SZ_BYTES(mcqi_cap), mcqi_reg);514	if (err)515		return err;516 517	*max_component_size = MLX5_GET(mcqi_cap, mcqi_reg, max_component_size);518	*log_mcda_word_size = MLX5_GET(mcqi_cap, mcqi_reg, log_mcda_word_size);519	*mcda_max_write_size = MLX5_GET(mcqi_cap, mcqi_reg, mcda_max_write_size);520 521	return 0;522}523 524struct mlx5_mlxfw_dev {525	struct mlxfw_dev mlxfw_dev;526	struct mlx5_core_dev *mlx5_core_dev;527};528 529static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,530				u16 component_index, u32 *p_max_size,531				u8 *p_align_bits, u16 *p_max_write_size)532{533	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =534		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);535	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;536 537	if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi)) {538		mlx5_core_warn(dev, "caps query isn't supported by running FW\n");539		return -EOPNOTSUPP;540	}541 542	return mlx5_reg_mcqi_caps_query(dev, component_index, p_max_size,543					p_align_bits, p_max_write_size);544}545 546static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)547{548	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =549		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);550	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;551	u8 control_state, error_code;552	int err;553 554	*fwhandle = 0;555	err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);556	if (err)557		return err;558 559	if (control_state != MLXFW_FSM_STATE_IDLE)560		return -EBUSY;561 562	return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,563				0, *fwhandle, 0);564}565 566static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,567				     u16 component_index, u32 component_size)568{569	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =570		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);571	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;572 573	return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,574				component_index, fwhandle, component_size);575}576 577static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,578				   u8 *data, u16 size, u32 offset)579{580	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =581		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);582	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;583 584	return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);585}586 587static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,588				     u16 component_index)589{590	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =591		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);592	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;593 594	return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,595				component_index, fwhandle, 0);596}597 598static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)599{600	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =601		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);602	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;603 604	return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE,	0,605				fwhandle, 0);606}607 608static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,609				enum mlxfw_fsm_state *fsm_state,610				enum mlxfw_fsm_state_err *fsm_state_err)611{612	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =613		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);614	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;615	u8 control_state, error_code;616	int err;617 618	err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);619	if (err)620		return err;621 622	*fsm_state = control_state;623	*fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,624			       MLXFW_FSM_STATE_ERR_MAX);625	return 0;626}627 628static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)629{630	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =631		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);632	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;633 634	mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);635}636 637static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)638{639	struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =640		container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);641	struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;642 643	mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,644			 fwhandle, 0);645}646 647static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status)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	u32 out[MLX5_ST_SZ_DW(mirc_reg)];653	u32 in[MLX5_ST_SZ_DW(mirc_reg)];654	unsigned long exp_time;655	int err;656 657	exp_time = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, FSM_REACTIVATE));658 659	if (!MLX5_CAP_MCAM_REG2(dev, mirc))660		return -EOPNOTSUPP;661 662	memset(in, 0, sizeof(in));663 664	err = mlx5_core_access_reg(dev, in, sizeof(in), out,665				   sizeof(out), MLX5_REG_MIRC, 0, 1);666	if (err)667		return err;668 669	do {670		memset(out, 0, sizeof(out));671		err = mlx5_core_access_reg(dev, in, sizeof(in), out,672					   sizeof(out), MLX5_REG_MIRC, 0, 0);673		if (err)674			return err;675 676		*status = MLX5_GET(mirc_reg, out, status_code);677		if (*status != MLXFW_FSM_REACTIVATE_STATUS_BUSY)678			return 0;679 680		msleep(20);681	} while (time_before(jiffies, exp_time));682 683	return 0;684}685 686static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {687	.component_query	= mlx5_component_query,688	.fsm_lock		= mlx5_fsm_lock,689	.fsm_component_update	= mlx5_fsm_component_update,690	.fsm_block_download	= mlx5_fsm_block_download,691	.fsm_component_verify	= mlx5_fsm_component_verify,692	.fsm_activate		= mlx5_fsm_activate,693	.fsm_reactivate		= mlx5_fsm_reactivate,694	.fsm_query_state	= mlx5_fsm_query_state,695	.fsm_cancel		= mlx5_fsm_cancel,696	.fsm_release		= mlx5_fsm_release697};698 699int mlx5_firmware_flash(struct mlx5_core_dev *dev,700			const struct firmware *firmware,701			struct netlink_ext_ack *extack)702{703	struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {704		.mlxfw_dev = {705			.ops = &mlx5_mlxfw_dev_ops,706			.psid = dev->board_id,707			.psid_size = strlen(dev->board_id),708			.devlink = priv_to_devlink(dev),709		},710		.mlx5_core_dev = dev711	};712 713	if (!MLX5_CAP_GEN(dev, mcam_reg)  ||714	    !MLX5_CAP_MCAM_REG(dev, mcqi) ||715	    !MLX5_CAP_MCAM_REG(dev, mcc)  ||716	    !MLX5_CAP_MCAM_REG(dev, mcda)) {717		pr_info("%s flashing isn't supported by the running FW\n", __func__);718		return -EOPNOTSUPP;719	}720 721	return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev,722				    firmware, extack);723}724 725static int mlx5_reg_mcqi_version_query(struct mlx5_core_dev *dev,726				       u16 component_index, bool read_pending,727				       u32 *mcqi_version_out)728{729	return mlx5_reg_mcqi_query(dev, component_index, read_pending,730				   MCQI_INFO_TYPE_VERSION,731				   MLX5_ST_SZ_BYTES(mcqi_version),732				   mcqi_version_out);733}734 735static int mlx5_reg_mcqs_query(struct mlx5_core_dev *dev, u32 *out,736			       u16 component_index)737{738	u8 out_sz = MLX5_ST_SZ_BYTES(mcqs_reg);739	u32 in[MLX5_ST_SZ_DW(mcqs_reg)] = {};740	int err;741 742	memset(out, 0, out_sz);743 744	MLX5_SET(mcqs_reg, in, component_index, component_index);745 746	err = mlx5_core_access_reg(dev, in, sizeof(in), out,747				   out_sz, MLX5_REG_MCQS, 0, 0);748	return err;749}750 751/* scans component index sequentially, to find the boot img index */752static int mlx5_get_boot_img_component_index(struct mlx5_core_dev *dev)753{754	u32 out[MLX5_ST_SZ_DW(mcqs_reg)] = {};755	u16 identifier, component_idx = 0;756	bool quit;757	int err;758 759	do {760		err = mlx5_reg_mcqs_query(dev, out, component_idx);761		if (err)762			return err;763 764		identifier = MLX5_GET(mcqs_reg, out, identifier);765		quit = !!MLX5_GET(mcqs_reg, out, last_index_flag);766		quit |= identifier == MCQS_IDENTIFIER_BOOT_IMG;767	} while (!quit && ++component_idx);768 769	if (identifier != MCQS_IDENTIFIER_BOOT_IMG) {770		mlx5_core_warn(dev, "mcqs: can't find boot_img component ix, last scanned idx %d\n",771			       component_idx);772		return -EOPNOTSUPP;773	}774 775	return component_idx;776}777 778static int779mlx5_fw_image_pending(struct mlx5_core_dev *dev,780		      int component_index,781		      bool *pending_version_exists)782{783	u32 out[MLX5_ST_SZ_DW(mcqs_reg)];784	u8 component_update_state;785	int err;786 787	err = mlx5_reg_mcqs_query(dev, out, component_index);788	if (err)789		return err;790 791	component_update_state = MLX5_GET(mcqs_reg, out, component_update_state);792 793	if (component_update_state == MCQS_UPDATE_STATE_IDLE) {794		*pending_version_exists = false;795	} else if (component_update_state == MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET) {796		*pending_version_exists = true;797	} else {798		mlx5_core_warn(dev,799			       "mcqs: can't read pending fw version while fw state is %d\n",800			       component_update_state);801		return -ENODATA;802	}803	return 0;804}805 806int mlx5_fw_version_query(struct mlx5_core_dev *dev,807			  u32 *running_ver, u32 *pending_ver)808{809	u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};810	bool pending_version_exists;811	int component_index;812	int err;813 814	if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||815	    !MLX5_CAP_MCAM_REG(dev, mcqs)) {816		mlx5_core_warn(dev, "fw query isn't supported by the FW\n");817		return -EOPNOTSUPP;818	}819 820	component_index = mlx5_get_boot_img_component_index(dev);821	if (component_index < 0)822		return component_index;823 824	err = mlx5_reg_mcqi_version_query(dev, component_index,825					  MCQI_FW_RUNNING_VERSION,826					  reg_mcqi_version);827	if (err)828		return err;829 830	*running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);831 832	err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);833	if (err)834		return err;835 836	if (!pending_version_exists) {837		*pending_ver = 0;838		return 0;839	}840 841	err = mlx5_reg_mcqi_version_query(dev, component_index,842					  MCQI_FW_STORED_VERSION,843					  reg_mcqi_version);844	if (err)845		return err;846 847	*pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);848 849	return 0;850}851