Commit 4b34e23f authored by Sindhu, Devale's avatar Sindhu, Devale Committed by Jason Gunthorpe
Browse files

i40iw: Report correct firmware version

The driver uses a hard-coded value for FW version and reports an
inconsistent FW version between ibv_devinfo and
/sys/class/infiniband/i40iw/fw_ver.

Retrieve the FW version via a Control QP (CQP) operation and report it
consistently across sysfs and query device.

Fixes: d3749841 ("i40iw: add files for iwarp interface")
Link: https://lore.kernel.org/r/20200313214406.2159-1-shiraz.saleem@intel.com


Reported-by: default avatarJarod Wilson <jarod@redhat.com>
Signed-off-by: default avatarSindhu, Devale <sindhu.devale@intel.com>
Signed-off-by: default avatarShiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent d6a3627e
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@
#include "i40iw_user.h"
#include "i40iw_puda.h"

#define I40IW_FW_VERSION  2
#define I40IW_FW_VER_DEFAULT 2
#define I40IW_HW_VERSION  2

#define I40IW_ARP_ADD     1
@@ -325,6 +325,26 @@ struct i40iw_handler {
	struct i40e_info ldev;
};

/**
 * i40iw_fw_major_ver - get firmware major version
 * @dev: iwarp device
 **/
static inline u64 i40iw_fw_major_ver(struct i40iw_sc_dev *dev)
{
	return RS_64(dev->feature_info[I40IW_FEATURE_FW_INFO],
		     I40IW_FW_VER_MAJOR);
}

/**
 * i40iw_fw_minor_ver - get firmware minor version
 * @dev: iwarp device
 **/
static inline u64 i40iw_fw_minor_ver(struct i40iw_sc_dev *dev)
{
	return RS_64(dev->feature_info[I40IW_FEATURE_FW_INFO],
		     I40IW_FW_VER_MINOR);
}

/**
 * to_iwdev - get device
 * @ibdev: ib device
+96 −0
Original line number Diff line number Diff line
@@ -1021,6 +1021,95 @@ static enum i40iw_status_code i40iw_sc_commit_fpm_values(
	return ret_code;
}

/**
 * i40iw_sc_query_rdma_features_done - poll cqp for query features done
 * @cqp: struct for cqp hw
 */
static enum i40iw_status_code
i40iw_sc_query_rdma_features_done(struct i40iw_sc_cqp *cqp)
{
	return i40iw_sc_poll_for_cqp_op_done(
		cqp, I40IW_CQP_OP_QUERY_RDMA_FEATURES, NULL);
}

/**
 * i40iw_sc_query_rdma_features - query rdma features
 * @cqp: struct for cqp hw
 * @feat_mem: holds PA for HW to use
 * @scratch: u64 saved to be used during cqp completion
 */
static enum i40iw_status_code
i40iw_sc_query_rdma_features(struct i40iw_sc_cqp *cqp,
			     struct i40iw_dma_mem *feat_mem, u64 scratch)
{
	u64 *wqe;
	u64 header;

	wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
	if (wqe)
		return I40IW_ERR_RING_FULL;

	set_64bit_val(wqe, 32, feat_mem->pa);

	header = LS_64(I40IW_CQP_OP_QUERY_RDMA_FEATURES, I40IW_CQPSQ_OPCODE) |
		 LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID) | feat_mem->size;

	i40iw_insert_wqe_hdr(wqe, header);

	i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QUERY RDMA FEATURES WQE",
			wqe, I40IW_CQP_WQE_SIZE * 8);

	i40iw_sc_cqp_post_sq(cqp);

	return 0;
}

/**
 * i40iw_get_rdma_features - get RDMA features
 * @dev - sc device struct
 */
enum i40iw_status_code i40iw_get_rdma_features(struct i40iw_sc_dev *dev)
{
	enum i40iw_status_code ret_code;
	struct i40iw_dma_mem feat_buf;
	u64 temp;
	u16 byte_idx, feat_type, feat_cnt;

	ret_code = i40iw_allocate_dma_mem(dev->hw, &feat_buf,
					  I40IW_FEATURE_BUF_SIZE,
					  I40IW_FEATURE_BUF_ALIGNMENT);

	if (ret_code)
		return I40IW_ERR_NO_MEMORY;

	ret_code = i40iw_sc_query_rdma_features(dev->cqp, &feat_buf, 0);
	if (!ret_code)
		ret_code = i40iw_sc_query_rdma_features_done(dev->cqp);

	if (ret_code)
		goto exit;

	get_64bit_val(feat_buf.va, 0, &temp);
	feat_cnt = RS_64(temp, I40IW_FEATURE_CNT);
	if (feat_cnt < I40IW_MAX_FEATURES) {
		ret_code = I40IW_ERR_INVALID_FEAT_CNT;
		goto exit;
	} else if (feat_cnt > I40IW_MAX_FEATURES) {
		i40iw_debug(dev, I40IW_DEBUG_CQP,
			    "features buf size insufficient\n");
	}

	for (byte_idx = 0, feat_type = 0; feat_type < I40IW_MAX_FEATURES;
	     feat_type++, byte_idx += 8) {
		get_64bit_val((u64 *)feat_buf.va, byte_idx, &temp);
		dev->feature_info[feat_type] = RS_64(temp, I40IW_FEATURE_INFO);
	}
exit:
	i40iw_free_dma_mem(dev->hw, &feat_buf);

	return ret_code;
}

/**
 * i40iw_sc_query_fpm_values_done - poll for cqp wqe completion for query fpm
 * @cqp: struct for cqp hw
@@ -4265,6 +4354,13 @@ static enum i40iw_status_code i40iw_exec_cqp_cmd(struct i40iw_sc_dev *dev,
				true,
				I40IW_CQP_WAIT_EVENT);
		break;
	case OP_QUERY_RDMA_FEATURES:
		values_mem.pa = pcmdinfo->in.u.query_rdma_features.cap_pa;
		values_mem.va = pcmdinfo->in.u.query_rdma_features.cap_va;
		status = i40iw_sc_query_rdma_features(
			pcmdinfo->in.u.query_rdma_features.cqp, &values_mem,
			pcmdinfo->in.u.query_rdma_features.scratch);
		break;
	default:
		status = I40IW_NOT_SUPPORTED;
		break;
+23 −3
Original line number Diff line number Diff line
@@ -403,7 +403,7 @@
#define I40IW_CQP_OP_MANAGE_ARP                 0x0f
#define I40IW_CQP_OP_MANAGE_VF_PBLE_BP          0x10
#define I40IW_CQP_OP_MANAGE_PUSH_PAGES          0x11
#define I40IW_CQP_OP_MANAGE_PE_TEAM             0x12
#define I40IW_CQP_OP_QUERY_RDMA_FEATURES	0x12
#define I40IW_CQP_OP_UPLOAD_CONTEXT             0x13
#define I40IW_CQP_OP_ALLOCATE_LOC_MAC_IP_TABLE_ENTRY 0x14
#define I40IW_CQP_OP_MANAGE_HMC_PM_FUNC_TABLE   0x15
@@ -431,6 +431,24 @@
#define I40IW_CQP_OP_SHMC_PAGES_ALLOCATED       0x2b
#define I40IW_CQP_OP_SET_HMC_RESOURCE_PROFILE   0x2d

#define I40IW_FEATURE_BUF_SIZE                  (8 * I40IW_MAX_FEATURES)

#define I40IW_FW_VER_MINOR_SHIFT        0
#define I40IW_FW_VER_MINOR_MASK         \
	(0xffffULL << I40IW_FW_VER_MINOR_SHIFT)

#define I40IW_FW_VER_MAJOR_SHIFT        16
#define I40IW_FW_VER_MAJOR_MASK	        \
	(0xffffULL << I40IW_FW_VER_MAJOR_SHIFT)

#define I40IW_FEATURE_INFO_SHIFT        0
#define I40IW_FEATURE_INFO_MASK         \
	(0xffffULL << I40IW_FEATURE_INFO_SHIFT)

#define I40IW_FEATURE_CNT_SHIFT         32
#define I40IW_FEATURE_CNT_MASK          \
	(0xffffULL << I40IW_FEATURE_CNT_SHIFT)

#define I40IW_UDA_QPSQ_NEXT_HEADER_SHIFT 16
#define I40IW_UDA_QPSQ_NEXT_HEADER_MASK ((u64)0xff << I40IW_UDA_QPSQ_NEXT_HEADER_SHIFT)

@@ -1529,7 +1547,8 @@ enum i40iw_alignment {
	I40IW_AEQ_ALIGNMENT =		0x100,
	I40IW_CEQ_ALIGNMENT =		0x100,
	I40IW_CQ0_ALIGNMENT =		0x100,
	I40IW_SD_BUF_ALIGNMENT =	0x80
	I40IW_SD_BUF_ALIGNMENT =	0x80,
	I40IW_FEATURE_BUF_ALIGNMENT =	0x8
};

#define I40IW_WQE_SIZE_64	64
@@ -1732,6 +1751,7 @@ enum i40iw_alignment {
#define OP_REQUESTED_COMMANDS                   31
#define OP_COMPLETED_COMMANDS                   32
#define OP_GEN_AE                               33
#define OP_SIZE_CQP_STAT_ARRAY                  34
#define OP_QUERY_RDMA_FEATURES                  34
#define OP_SIZE_CQP_STAT_ARRAY			35

#endif
+6 −0
Original line number Diff line number Diff line
@@ -1683,6 +1683,12 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client)
		status = i40iw_setup_ceqs(iwdev, ldev);
		if (status)
			break;

		status = i40iw_get_rdma_features(dev);
		if (status)
			dev->feature_info[I40IW_FEATURE_FW_INFO] =
				I40IW_FW_VER_DEFAULT;

		iwdev->init_state = CEQ_CREATED;
		status = i40iw_initialize_hw_resources(iwdev);
		if (status)
+1 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ enum i40iw_status_code i40iw_sc_static_hmc_pages_allocated(struct i40iw_sc_cqp *
							   bool poll_registers);

enum i40iw_status_code i40iw_config_fpm_values(struct i40iw_sc_dev *dev, u32 qp_count);
enum i40iw_status_code i40iw_get_rdma_features(struct i40iw_sc_dev *dev);

void free_sd_mem(struct i40iw_sc_dev *dev);

Loading