Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51ff1725 authored by Ram Amrani's avatar Ram Amrani Committed by David S. Miller
Browse files

qed: Add support for RoCE hw init



This adds the backbone required for the various HW initalizations
which are necessary for the qedr driver - FW notification, resource
initializations, etc.

Signed-off-by: default avatarRam Amrani <Ram.Amrani@caviumnetworks.com>
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@caviumnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cee9fbd8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,3 +5,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
	 qed_selftest.o qed_dcbx.o qed_debug.o
qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
qed-$(CONFIG_QED_LL2) += qed_ll2.o
qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
+32 −1
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ extern const struct qed_common_ops qed_common_ops_pass;

#define QED_WFQ_UNIT	100

#define QED_WID_SIZE            (1024)
#define QED_PF_DEMS_SIZE        (4)

/* cau states */
enum qed_coalescing_mode {
	QED_COAL_MODE_DISABLE,
@@ -48,6 +51,14 @@ enum qed_mcp_protocol_type;

/* helpers */
static inline u32 qed_db_addr(u32 cid, u32 DEMS)
{
	u32 db_addr = FIELD_VALUE(DB_LEGACY_ADDR_DEMS, DEMS) |
		      (cid * QED_PF_DEMS_SIZE);

	return db_addr;
}

static inline u32 qed_db_addr_vf(u32 cid, u32 DEMS)
{
	u32 db_addr = FIELD_VALUE(DB_LEGACY_ADDR_DEMS, DEMS) |
		      FIELD_VALUE(DB_LEGACY_ADDR_ICID, cid);
@@ -152,14 +163,17 @@ enum QED_RESOURCES {
	QED_RL,
	QED_MAC,
	QED_VLAN,
	QED_RDMA_CNQ_RAM,
	QED_ILT,
	QED_LL2_QUEUE,
	QED_RDMA_STATS_QUEUE,
	QED_MAX_RESC,
};

enum QED_FEATURE {
	QED_PF_L2_QUE,
	QED_VF,
	QED_RDMA_CNQ,
	QED_MAX_FEATURES,
};

@@ -364,6 +378,7 @@ struct qed_hwfn {
	/* Protocol related */
	bool				using_ll2;
	struct qed_ll2_info		*p_ll2_info;
	struct qed_rdma_info		*p_rdma_info;
	struct qed_pf_params		pf_params;

	bool b_rdma_enabled_in_prs;
@@ -402,6 +417,17 @@ struct qed_hwfn {

	struct dbg_tools_data		dbg_info;

	/* PWM region specific data */
	u32				dpi_size;
	u32				dpi_count;

	/* This is used to calculate the doorbell address */
	u32 dpi_start_offset;

	/* If one of the following is set then EDPM shouldn't be used */
	u8 dcbx_no_edpm;
	u8 db_bar_no_edpm;

	struct qed_simd_fp_handler	simd_proto_handler[64];

#ifdef CONFIG_QED_SRIOV
@@ -435,6 +461,8 @@ struct qed_int_params {
	bool			fp_initialized;
	u8			fp_msix_base;
	u8			fp_msix_cnt;
	u8			rdma_msix_base;
	u8			rdma_msix_cnt;
};

struct qed_dbg_feature {
@@ -541,7 +569,6 @@ struct qed_dev {

	bool				b_is_vf;
	u32				drv_type;

	struct qed_eth_stats		*reset_stats;
	struct qed_fw_data		*fw_data;

@@ -574,6 +601,10 @@ struct qed_dev {
#endif

	const struct firmware		*firmware;

	u32 rdma_max_sge;
	u32 rdma_max_inline;
	u32 rdma_max_srq_sge;
};

#define NUM_OF_VFS(dev)         MAX_NUM_VFS_BB
+6 −0
Original line number Diff line number Diff line
@@ -48,7 +48,13 @@
#define TM_ELEM_SIZE    4

/* ILT constants */
#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
/* For RoCE we configure to 64K to cover for RoCE max tasks 256K purpose. */
#define ILT_DEFAULT_HW_P_SIZE		4
#else
#define ILT_DEFAULT_HW_P_SIZE		3
#endif

#define ILT_PAGE_IN_BYTES(hw_p_size)	(1U << ((hw_p_size) + 12))
#define ILT_CFG_REG(cli, reg)	PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET

+6 −0
Original line number Diff line number Diff line
@@ -170,6 +170,12 @@ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 */
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn,
			 u32 cid);
int qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn,
			      enum qed_cxt_elem_type elem_type, u32 iid);
u32 qed_cxt_get_proto_tid_count(struct qed_hwfn *p_hwfn,
				enum protocol_type type);
u32 qed_cxt_get_proto_cid_start(struct qed_hwfn *p_hwfn,
				enum protocol_type type);

#define QED_CTX_WORKING_MEM 0
#define QED_CTX_FL_MEM 1
+154 −0
Original line number Diff line number Diff line
@@ -35,9 +35,13 @@
#include "qed_sp.h"
#include "qed_sriov.h"
#include "qed_vf.h"
#include "qed_roce.h"

static DEFINE_SPINLOCK(qm_lock);

#define QED_MIN_DPIS            (4)
#define QED_MIN_PWM_REGION      (QED_WID_SIZE * QED_MIN_DPIS)

/* API common to all protocols */
enum BAR_ID {
	BAR_ID_0,       /* used for GRC */
@@ -787,6 +791,136 @@ static int qed_hw_init_common(struct qed_hwfn *p_hwfn,
	return rc;
}

static int
qed_hw_init_dpi_size(struct qed_hwfn *p_hwfn,
		     struct qed_ptt *p_ptt, u32 pwm_region_size, u32 n_cpus)
{
	u32 dpi_page_size_1, dpi_page_size_2, dpi_page_size;
	u32 dpi_bit_shift, dpi_count;
	u32 min_dpis;

	/* Calculate DPI size */
	dpi_page_size_1 = QED_WID_SIZE * n_cpus;
	dpi_page_size_2 = max_t(u32, QED_WID_SIZE, PAGE_SIZE);
	dpi_page_size = max_t(u32, dpi_page_size_1, dpi_page_size_2);
	dpi_page_size = roundup_pow_of_two(dpi_page_size);
	dpi_bit_shift = ilog2(dpi_page_size / 4096);

	dpi_count = pwm_region_size / dpi_page_size;

	min_dpis = p_hwfn->pf_params.rdma_pf_params.min_dpis;
	min_dpis = max_t(u32, QED_MIN_DPIS, min_dpis);

	p_hwfn->dpi_size = dpi_page_size;
	p_hwfn->dpi_count = dpi_count;

	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPI_BIT_SHIFT, dpi_bit_shift);

	if (dpi_count < min_dpis)
		return -EINVAL;

	return 0;
}

enum QED_ROCE_EDPM_MODE {
	QED_ROCE_EDPM_MODE_ENABLE = 0,
	QED_ROCE_EDPM_MODE_FORCE_ON = 1,
	QED_ROCE_EDPM_MODE_DISABLE = 2,
};

static int
qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
	u32 pwm_regsize, norm_regsize;
	u32 non_pwm_conn, min_addr_reg1;
	u32 db_bar_size, n_cpus;
	u32 roce_edpm_mode;
	u32 pf_dems_shift;
	int rc = 0;
	u8 cond;

	db_bar_size = qed_hw_bar_size(p_hwfn, BAR_ID_1);
	if (p_hwfn->cdev->num_hwfns > 1)
		db_bar_size /= 2;

	/* Calculate doorbell regions */
	non_pwm_conn = qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_CORE) +
		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_CORE,
						   NULL) +
		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
						   NULL);
	norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, 4096);
	min_addr_reg1 = norm_regsize / 4096;
	pwm_regsize = db_bar_size - norm_regsize;

	/* Check that the normal and PWM sizes are valid */
	if (db_bar_size < norm_regsize) {
		DP_ERR(p_hwfn->cdev,
		       "Doorbell BAR size 0x%x is too small (normal region is 0x%0x )\n",
		       db_bar_size, norm_regsize);
		return -EINVAL;
	}

	if (pwm_regsize < QED_MIN_PWM_REGION) {
		DP_ERR(p_hwfn->cdev,
		       "PWM region size 0x%0x is too small. Should be at least 0x%0x (Doorbell BAR size is 0x%x and normal region size is 0x%0x)\n",
		       pwm_regsize,
		       QED_MIN_PWM_REGION, db_bar_size, norm_regsize);
		return -EINVAL;
	}

	/* Calculate number of DPIs */
	roce_edpm_mode = p_hwfn->pf_params.rdma_pf_params.roce_edpm_mode;
	if ((roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE) ||
	    ((roce_edpm_mode == QED_ROCE_EDPM_MODE_FORCE_ON))) {
		/* Either EDPM is mandatory, or we are attempting to allocate a
		 * WID per CPU.
		 */
		n_cpus = num_active_cpus();
		rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus);
	}

	cond = (rc && (roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE)) ||
	       (roce_edpm_mode == QED_ROCE_EDPM_MODE_DISABLE);
	if (cond || p_hwfn->dcbx_no_edpm) {
		/* Either EDPM is disabled from user configuration, or it is
		 * disabled via DCBx, or it is not mandatory and we failed to
		 * allocated a WID per CPU.
		 */
		n_cpus = 1;
		rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus);

		if (cond)
			qed_rdma_dpm_bar(p_hwfn, p_ptt);
	}

	DP_INFO(p_hwfn,
		"doorbell bar: normal_region_size=%d, pwm_region_size=%d, dpi_size=%d, dpi_count=%d, roce_edpm=%s\n",
		norm_regsize,
		pwm_regsize,
		p_hwfn->dpi_size,
		p_hwfn->dpi_count,
		((p_hwfn->dcbx_no_edpm) || (p_hwfn->db_bar_no_edpm)) ?
		"disabled" : "enabled");

	if (rc) {
		DP_ERR(p_hwfn,
		       "Failed to allocate enough DPIs. Allocated %d but the current minimum is %d.\n",
		       p_hwfn->dpi_count,
		       p_hwfn->pf_params.rdma_pf_params.min_dpis);
		return -EINVAL;
	}

	p_hwfn->dpi_start_offset = norm_regsize;

	/* DEMS size is configured log2 of DWORDs, hence the division by 4 */
	pf_dems_shift = ilog2(QED_PF_DEMS_SIZE / 4);
	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_ICID_BIT_SHIFT_NORM, pf_dems_shift);
	qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_MIN_ADDR_REG1, min_addr_reg1);

	return 0;
}

static int qed_hw_init_port(struct qed_hwfn *p_hwfn,
			    struct qed_ptt *p_ptt, int hw_mode)
{
@@ -860,6 +994,10 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
	/* Pure runtime initializations - directly to the HW  */
	qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true);

	rc = qed_hw_init_pf_doorbell_bar(p_hwfn, p_ptt);
	if (rc)
		return rc;

	if (b_hw_start) {
		/* enable interrupts */
		qed_int_igu_enable(p_hwfn, p_ptt, int_mode);
@@ -1284,6 +1422,19 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
	u32 *feat_num = p_hwfn->hw_info.feat_num;
	int num_features = 1;

#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
	/* Roce CNQ each requires: 1 status block + 1 CNQ. We divide the
	 * status blocks equally between L2 / RoCE but with consideration as
	 * to how many l2 queues / cnqs we have
	 */
	if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) {
		num_features++;

		feat_num[QED_RDMA_CNQ] =
			min_t(u32, RESC_NUM(p_hwfn, QED_SB) / num_features,
			      RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM));
	}
#endif
	feat_num[QED_PF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_SB) /
						num_features,
					RESC_NUM(p_hwfn, QED_L2_QUEUE));
@@ -1325,6 +1476,9 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
			     num_funcs;
	resc_num[QED_ILT] = PXP_NUM_ILT_RECORDS_BB / num_funcs;
	resc_num[QED_LL2_QUEUE] = MAX_NUM_LL2_RX_QUEUES / num_funcs;
	resc_num[QED_RDMA_CNQ_RAM] = NUM_OF_CMDQS_CQS / num_funcs;
	resc_num[QED_RDMA_STATS_QUEUE] = RDMA_NUM_STATISTIC_COUNTERS_BB /
					 num_funcs;

	for (i = 0; i < QED_MAX_RESC; i++)
		resc_start[i] = resc_num[i] * enabled_func_idx;
Loading