Commit 03c7f70b authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'qed-roce-iscsi'



Yuval Mintz says:

====================
qed: RocE & iSCSI infrastructure

We plan on sending 2 new protocol drivers in the imminent future -
both our RoCE [qedr] and iSCSI [qedi] drivers. As both submissions
would be rather massive and in order to avoid collisions between them,
the common infrastructure on the qed side was prepared as an independent
patch-series to be sent ahead of those 2 submissions.

This patch series introduces in QED 2 new 'ids' - one for iscsi and
one for roce. It then goes and adds logic required for configuring
said protocols in HW. Notice it *doesn't* actually add any client using
said ids, but rather only the infrastructure to allow their later usage.

What this patch doesn't contain is the slowpath protocol-configuration
toward the firmware. I.e., it contains register-setting logic, memory
allocations, etc., but not actual flow-related configuration specific
to the protocl. Those would be sent as part of the protocol driver
submissions.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 330348d9 dbb799c3
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -127,6 +127,8 @@ struct qed_tunn_update_params {
 */
enum qed_pci_personality {
	QED_PCI_ETH,
	QED_PCI_ISCSI,
	QED_PCI_ETH_ROCE,
	QED_PCI_DEFAULT /* default in shmem */
};

@@ -170,6 +172,8 @@ enum QED_PORT_MODE {

enum qed_dev_cap {
	QED_DEV_CAP_ETH,
	QED_DEV_CAP_ISCSI,
	QED_DEV_CAP_ROCE,
};

struct qed_hw_info {
@@ -183,6 +187,8 @@ struct qed_hw_info {

#define RESC_START(_p_hwfn, resc) ((_p_hwfn)->hw_info.resc_start[resc])
#define RESC_NUM(_p_hwfn, resc) ((_p_hwfn)->hw_info.resc_num[resc])
#define RESC_END(_p_hwfn, resc) (RESC_START(_p_hwfn, resc) + \
				 RESC_NUM(_p_hwfn, resc))
#define FEAT_NUM(_p_hwfn, resc) ((_p_hwfn)->hw_info.feat_num[resc])

	u8				num_tc;
@@ -255,6 +261,7 @@ struct qed_qm_info {
	u8				pure_lb_pq;
	u8				offload_pq;
	u8				pure_ack_pq;
	u8 ooo_pq;
	u8				vf_queues_offset;
	u16				num_pqs;
	u16				num_vf_pqs;
@@ -267,6 +274,7 @@ struct qed_qm_info {
	u8				pf_wfq;
	u32				pf_rl;
	struct qed_wfq_data		*wfq_data;
	u8 num_pf_rls;
};

struct storm_stats {
@@ -312,6 +320,7 @@ struct qed_hwfn {
	bool				hw_init_done;

	u8				num_funcs_on_engine;
	u8 enabled_func_idx;

	/* BAR access */
	void __iomem			*regview;
@@ -350,6 +359,9 @@ struct qed_hwfn {
	/* Protocol related */
	struct qed_pf_params		pf_params;

	bool b_rdma_enabled_in_prs;
	u32 rdma_prs_search_reg;

	/* Array of sb_info of all status blocks */
	struct qed_sb_info		*sbs_info[MAX_SB_PER_PF_MIMD];
	u16				num_sbs;
@@ -555,6 +567,7 @@ static inline u8 qed_concrete_to_sw_fid(struct qed_dev *cdev,
}

#define PURE_LB_TC 8
#define OOO_LB_TC 9

int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate);
void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev, u32 min_pf_rate);
+1310 −37

File changed.

Preview size limit exceeded, changes collapsed.

+24 −0
Original line number Diff line number Diff line
@@ -21,6 +21,14 @@ struct qed_cxt_info {
	enum protocol_type	type;
};

#define MAX_TID_BLOCKS                  512
struct qed_tid_mem {
	u32 tid_size;
	u32 num_tids_per_block;
	u32 waste;
	u8 *blocks[MAX_TID_BLOCKS];	/* 4K */
};

/**
 * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type
 *
@@ -46,8 +54,22 @@ int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn,
			 struct qed_cxt_info *p_info);

/**
 * @brief qed_cxt_get_tid_mem_info
 *
 * @param p_hwfn
 * @param p_info
 *
 * @return int
 */
int qed_cxt_get_tid_mem_info(struct qed_hwfn *p_hwfn,
			     struct qed_tid_mem *p_info);

#define QED_CXT_ISCSI_TID_SEG	PROTOCOLID_ISCSI
#define QED_CXT_ROCE_TID_SEG	PROTOCOLID_ROCE
enum qed_cxt_elem_type {
	QED_ELEM_CXT,
	QED_ELEM_SRQ,
	QED_ELEM_TASK
};

@@ -149,4 +171,6 @@ 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);

#define QED_CTX_WORKING_MEM 0
#define QED_CTX_FL_MEM 1
#endif
+389 −85
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/etherdevice.h>
#include <linux/qed/qed_chain.h>
#include <linux/qed/qed_if.h>
@@ -160,9 +161,13 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable)
	u8 num_vports, vf_offset = 0, i, vport_id, num_ports, curr_queue = 0;
	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
	struct init_qm_port_params *p_qm_port;
	bool init_rdma_offload_pq = false;
	bool init_pure_ack_pq = false;
	bool init_ooo_pq = false;
	u16 num_pqs, multi_cos_tcs = 1;
	u8 pf_wfq = qm_info->pf_wfq;
	u32 pf_rl = qm_info->pf_rl;
	u16 num_pf_rls = 0;
	u16 num_vfs = 0;

#ifdef CONFIG_QED_SRIOV
@@ -174,6 +179,25 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable)
	num_pqs = multi_cos_tcs + num_vfs + 1;	/* The '1' is for pure-LB */
	num_vports = (u8)RESC_NUM(p_hwfn, QED_VPORT);

	if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) {
		num_pqs++;	/* for RoCE queue */
		init_rdma_offload_pq = true;
		/* we subtract num_vfs because each require a rate limiter,
		 * and one default rate limiter
		 */
		if (p_hwfn->pf_params.rdma_pf_params.enable_dcqcn)
			num_pf_rls = RESC_NUM(p_hwfn, QED_RL) - num_vfs - 1;

		num_pqs += num_pf_rls;
		qm_info->num_pf_rls = (u8) num_pf_rls;
	}

	if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
		num_pqs += 2;	/* for iSCSI pure-ACK / OOO queue */
		init_pure_ack_pq = true;
		init_ooo_pq = true;
	}

	/* Sanity checking that setup requires legal number of resources */
	if (num_pqs > RESC_NUM(p_hwfn, QED_PQ)) {
		DP_ERR(p_hwfn,
@@ -211,12 +235,22 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable)

	vport_id = (u8)RESC_START(p_hwfn, QED_VPORT);

	/* First init rate limited queues */
	for (curr_queue = 0; curr_queue < num_pf_rls; curr_queue++) {
		qm_info->qm_pq_params[curr_queue].vport_id = vport_id++;
		qm_info->qm_pq_params[curr_queue].tc_id =
		    p_hwfn->hw_info.non_offload_tc;
		qm_info->qm_pq_params[curr_queue].wrr_group = 1;
		qm_info->qm_pq_params[curr_queue].rl_valid = 1;
	}

	/* First init per-TC PQs */
	for (i = 0; i < multi_cos_tcs; i++) {
		struct init_qm_pq_params *params =
		    &qm_info->qm_pq_params[curr_queue++];

		if (p_hwfn->hw_info.personality == QED_PCI_ETH) {
		if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE ||
		    p_hwfn->hw_info.personality == QED_PCI_ETH) {
			params->vport_id = vport_id;
			params->tc_id = p_hwfn->hw_info.non_offload_tc;
			params->wrr_group = 1;
@@ -236,6 +270,32 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable)
	curr_queue++;

	qm_info->offload_pq = 0;
	if (init_rdma_offload_pq) {
		qm_info->offload_pq = curr_queue;
		qm_info->qm_pq_params[curr_queue].vport_id = vport_id;
		qm_info->qm_pq_params[curr_queue].tc_id =
		    p_hwfn->hw_info.offload_tc;
		qm_info->qm_pq_params[curr_queue].wrr_group = 1;
		curr_queue++;
	}

	if (init_pure_ack_pq) {
		qm_info->pure_ack_pq = curr_queue;
		qm_info->qm_pq_params[curr_queue].vport_id = vport_id;
		qm_info->qm_pq_params[curr_queue].tc_id =
		    p_hwfn->hw_info.offload_tc;
		qm_info->qm_pq_params[curr_queue].wrr_group = 1;
		curr_queue++;
	}

	if (init_ooo_pq) {
		qm_info->ooo_pq = curr_queue;
		qm_info->qm_pq_params[curr_queue].vport_id = vport_id;
		qm_info->qm_pq_params[curr_queue].tc_id = DCBX_ISCSI_OOO_TC;
		qm_info->qm_pq_params[curr_queue].wrr_group = 1;
		curr_queue++;
	}

	/* Then init per-VF PQs */
	vf_offset = curr_queue;
	for (i = 0; i < num_vfs; i++) {
@@ -370,21 +430,20 @@ int qed_resc_alloc(struct qed_dev *cdev)
		if (!p_hwfn->p_tx_cids) {
			DP_NOTICE(p_hwfn,
				  "Failed to allocate memory for Tx Cids\n");
			rc = -ENOMEM;
			goto alloc_err;
			goto alloc_no_mem;
		}

		p_hwfn->p_rx_cids = kzalloc(rx_size, GFP_KERNEL);
		if (!p_hwfn->p_rx_cids) {
			DP_NOTICE(p_hwfn,
				  "Failed to allocate memory for Rx Cids\n");
			rc = -ENOMEM;
			goto alloc_err;
			goto alloc_no_mem;
		}
	}

	for_each_hwfn(cdev, i) {
		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
		u32 n_eqes, num_cons;

		/* First allocate the context manager structure */
		rc = qed_cxt_mngr_alloc(p_hwfn);
@@ -433,18 +492,34 @@ int qed_resc_alloc(struct qed_dev *cdev)
			goto alloc_err;

		/* EQ */
		p_eq = qed_eq_alloc(p_hwfn, 256);
		if (!p_eq) {
			rc = -ENOMEM;
		n_eqes = qed_chain_get_capacity(&p_hwfn->p_spq->chain);
		if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) {
			num_cons = qed_cxt_get_proto_cid_count(p_hwfn,
							       PROTOCOLID_ROCE,
							       0) * 2;
			n_eqes += num_cons + 2 * MAX_NUM_VFS_BB;
		} else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
			num_cons =
			    qed_cxt_get_proto_cid_count(p_hwfn,
							PROTOCOLID_ISCSI, 0);
			n_eqes += 2 * num_cons;
		}

		if (n_eqes > 0xFFFF) {
			DP_ERR(p_hwfn,
			       "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n",
			       n_eqes, 0xFFFF);
			goto alloc_err;
		}

		p_eq = qed_eq_alloc(p_hwfn, (u16) n_eqes);
		if (!p_eq)
			goto alloc_no_mem;
		p_hwfn->p_eq = p_eq;

		p_consq = qed_consq_alloc(p_hwfn);
		if (!p_consq) {
			rc = -ENOMEM;
			goto alloc_err;
		}
		if (!p_consq)
			goto alloc_no_mem;
		p_hwfn->p_consq = p_consq;

		/* DMA info initialization */
@@ -473,6 +548,8 @@ int qed_resc_alloc(struct qed_dev *cdev)

	return 0;

alloc_no_mem:
	rc = -ENOMEM;
alloc_err:
	qed_resc_free(cdev);
	return rc;
@@ -638,6 +715,7 @@ static int qed_hw_init_common(struct qed_hwfn *p_hwfn,
	struct qed_qm_info *qm_info = &p_hwfn->qm_info;
	struct qed_qm_common_rt_init_params params;
	struct qed_dev *cdev = p_hwfn->cdev;
	u16 num_pfs, pf_id;
	u32 concrete_fid;
	int rc = 0;
	u8 vf_id;
@@ -686,9 +764,16 @@ static int qed_hw_init_common(struct qed_hwfn *p_hwfn,
	qed_wr(p_hwfn, p_ptt, PSWRQ2_REG_L2P_VALIDATE_VFID, 0);
	qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_USE_CLIENTID_IN_TAG, 1);

	/* Disable relaxed ordering in the PCI config space */
	qed_wr(p_hwfn, p_ptt, 0x20b4,
	       qed_rd(p_hwfn, p_ptt, 0x20b4) & ~0x10);
	if (QED_IS_BB(p_hwfn->cdev)) {
		num_pfs = NUM_OF_ENG_PFS(p_hwfn->cdev);
		for (pf_id = 0; pf_id < num_pfs; pf_id++) {
			qed_fid_pretend(p_hwfn, p_ptt, pf_id);
			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
			qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0);
		}
		/* pretend to original PF */
		qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id);
	}

	for (vf_id = 0; vf_id < MAX_NUM_VFS_BB; vf_id++) {
		concrete_fid = qed_vfid_to_concrete(p_hwfn, vf_id);
@@ -778,7 +863,8 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
	}

	/* Protocl Configuration  */
	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET, 0);
	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET,
		     (p_hwfn->hw_info.personality == QED_PCI_ISCSI) ? 1 : 0);
	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET, 0);
	STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0);

@@ -1255,8 +1341,9 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
		   num_features);
}

static void qed_hw_get_resc(struct qed_hwfn *p_hwfn)
static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
{
	u8 enabled_func_idx = p_hwfn->enabled_func_idx;
	u32 *resc_start = p_hwfn->hw_info.resc_start;
	u8 num_funcs = p_hwfn->num_funcs_on_engine;
	u32 *resc_num = p_hwfn->hw_info.resc_num;
@@ -1280,14 +1367,22 @@ static void qed_hw_get_resc(struct qed_hwfn *p_hwfn)
	resc_num[QED_VPORT] = MAX_NUM_VPORTS_BB / num_funcs;
	resc_num[QED_RSS_ENG] = ETH_RSS_ENGINE_NUM_BB / num_funcs;
	resc_num[QED_PQ] = MAX_QM_TX_QUEUES_BB / num_funcs;
	resc_num[QED_RL] = 8;
	resc_num[QED_RL] = min_t(u32, 64, resc_num[QED_VPORT]);
	resc_num[QED_MAC] = ETH_NUM_MAC_FILTERS / num_funcs;
	resc_num[QED_VLAN] = (ETH_NUM_VLAN_FILTERS - 1 /*For vlan0*/) /
			     num_funcs;
	resc_num[QED_ILT] = 950;
	resc_num[QED_ILT] = PXP_NUM_ILT_RECORDS_BB / num_funcs;

	for (i = 0; i < QED_MAX_RESC; i++)
		resc_start[i] = resc_num[i] * p_hwfn->rel_pf_id;
		resc_start[i] = resc_num[i] * enabled_func_idx;

	/* Sanity for ILT */
	if (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_BB) {
		DP_NOTICE(p_hwfn, "Can't assign ILT pages [%08x,...,%08x]\n",
			  RESC_START(p_hwfn, QED_ILT),
			  RESC_END(p_hwfn, QED_ILT) - 1);
		return -EINVAL;
	}

	qed_hw_set_feat(p_hwfn);

@@ -1317,6 +1412,8 @@ static void qed_hw_get_resc(struct qed_hwfn *p_hwfn)
		   p_hwfn->hw_info.resc_start[QED_VLAN],
		   p_hwfn->hw_info.resc_num[QED_ILT],
		   p_hwfn->hw_info.resc_start[QED_ILT]);

	return 0;
}

static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn,
@@ -1471,14 +1568,20 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn,
	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET)
		__set_bit(QED_DEV_CAP_ETH,
			  &p_hwfn->hw_info.device_capabilities);
	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI)
		__set_bit(QED_DEV_CAP_ISCSI,
			  &p_hwfn->hw_info.device_capabilities);
	if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE)
		__set_bit(QED_DEV_CAP_ROCE,
			  &p_hwfn->hw_info.device_capabilities);

	return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt);
}

static void qed_get_num_funcs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
	u32 reg_function_hide, tmp, eng_mask;
	u8 num_funcs;
	u8 num_funcs, enabled_func_idx = p_hwfn->rel_pf_id;
	u32 reg_function_hide, tmp, eng_mask, low_pfs_mask;

	num_funcs = MAX_NUM_PFS_BB;

@@ -1508,9 +1611,19 @@ static void qed_get_num_funcs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
				num_funcs++;
			tmp >>= 0x1;
		}

		/* Get the PF index within the enabled functions */
		low_pfs_mask = (0x1 << p_hwfn->abs_pf_id) - 1;
		tmp = reg_function_hide & eng_mask & low_pfs_mask;
		while (tmp) {
			if (tmp & 0x1)
				enabled_func_idx--;
			tmp >>= 0x1;
		}
	}

	p_hwfn->num_funcs_on_engine = num_funcs;
	p_hwfn->enabled_func_idx = enabled_func_idx;

	DP_VERBOSE(p_hwfn,
		   NETIF_MSG_PROBE,
@@ -1580,9 +1693,7 @@ qed_get_hw_info(struct qed_hwfn *p_hwfn,

	qed_get_num_funcs(p_hwfn, p_ptt);

	qed_hw_get_resc(p_hwfn);

	return rc;
	return qed_hw_get_resc(p_hwfn);
}

static int qed_get_dev_info(struct qed_dev *cdev)
@@ -1779,87 +1890,280 @@ void qed_hw_remove(struct qed_dev *cdev)
	qed_iov_free_hw_info(cdev);
}

int qed_chain_alloc(struct qed_dev *cdev,
		    enum qed_chain_use_mode intended_use,
		    enum qed_chain_mode mode,
		    u16 num_elems,
		    size_t elem_size,
static void qed_chain_free_next_ptr(struct qed_dev *cdev,
				    struct qed_chain *p_chain)
{
	dma_addr_t p_pbl_phys = 0;
	void *p_pbl_virt = NULL;
	void *p_virt = p_chain->p_virt_addr, *p_virt_next = NULL;
	dma_addr_t p_phys = p_chain->p_phys_addr, p_phys_next = 0;
	struct qed_chain_next *p_next;
	u32 size, i;

	if (!p_virt)
		return;

	size = p_chain->elem_size * p_chain->usable_per_page;

	for (i = 0; i < p_chain->page_cnt; i++) {
		if (!p_virt)
			break;

		p_next = (struct qed_chain_next *)((u8 *)p_virt + size);
		p_virt_next = p_next->next_virt;
		p_phys_next = HILO_DMA_REGPAIR(p_next->next_phys);

		dma_free_coherent(&cdev->pdev->dev,
				  QED_CHAIN_PAGE_SIZE, p_virt, p_phys);

		p_virt = p_virt_next;
		p_phys = p_phys_next;
	}
}

static void qed_chain_free_single(struct qed_dev *cdev,
				  struct qed_chain *p_chain)
{
	if (!p_chain->p_virt_addr)
		return;

	dma_free_coherent(&cdev->pdev->dev,
			  QED_CHAIN_PAGE_SIZE,
			  p_chain->p_virt_addr, p_chain->p_phys_addr);
}

static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
{
	void **pp_virt_addr_tbl = p_chain->pbl.pp_virt_addr_tbl;
	u32 page_cnt = p_chain->page_cnt, i, pbl_size;
	u8 *p_pbl_virt = p_chain->pbl.p_virt_table;

	if (!pp_virt_addr_tbl)
		return;

	if (!p_chain->pbl.p_virt_table)
		goto out;

	for (i = 0; i < page_cnt; i++) {
		if (!pp_virt_addr_tbl[i])
			break;

		dma_free_coherent(&cdev->pdev->dev,
				  QED_CHAIN_PAGE_SIZE,
				  pp_virt_addr_tbl[i],
				  *(dma_addr_t *)p_pbl_virt);

		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
	}

	pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
	dma_free_coherent(&cdev->pdev->dev,
			  pbl_size,
			  p_chain->pbl.p_virt_table, p_chain->pbl.p_phys_table);
out:
	vfree(p_chain->pbl.pp_virt_addr_tbl);
}

void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain)
{
	switch (p_chain->mode) {
	case QED_CHAIN_MODE_NEXT_PTR:
		qed_chain_free_next_ptr(cdev, p_chain);
		break;
	case QED_CHAIN_MODE_SINGLE:
		qed_chain_free_single(cdev, p_chain);
		break;
	case QED_CHAIN_MODE_PBL:
		qed_chain_free_pbl(cdev, p_chain);
		break;
	}
}

static int
qed_chain_alloc_sanity_check(struct qed_dev *cdev,
			     enum qed_chain_cnt_type cnt_type,
			     size_t elem_size, u32 page_cnt)
{
	u64 chain_size = ELEMS_PER_PAGE(elem_size) * page_cnt;

	/* The actual chain size can be larger than the maximal possible value
	 * after rounding up the requested elements number to pages, and after
	 * taking into acount the unusuable elements (next-ptr elements).
	 * The size of a "u16" chain can be (U16_MAX + 1) since the chain
	 * size/capacity fields are of a u32 type.
	 */
	if ((cnt_type == QED_CHAIN_CNT_TYPE_U16 &&
	     chain_size > 0x10000) ||
	    (cnt_type == QED_CHAIN_CNT_TYPE_U32 &&
	     chain_size > 0x100000000ULL)) {
		DP_NOTICE(cdev,
			  "The actual chain size (0x%llx) is larger than the maximal possible value\n",
			  chain_size);
		return -EINVAL;
	}

	return 0;
}

static int
qed_chain_alloc_next_ptr(struct qed_dev *cdev, struct qed_chain *p_chain)
{
	void *p_virt = NULL, *p_virt_prev = NULL;
	dma_addr_t p_phys = 0;
	void *p_virt = NULL;
	u16 page_cnt = 0;
	size_t size;
	u32 i;

	if (mode == QED_CHAIN_MODE_SINGLE)
		page_cnt = 1;
	else
		page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode);
	for (i = 0; i < p_chain->page_cnt; i++) {
		p_virt = dma_alloc_coherent(&cdev->pdev->dev,
					    QED_CHAIN_PAGE_SIZE,
					    &p_phys, GFP_KERNEL);
		if (!p_virt) {
			DP_NOTICE(cdev, "Failed to allocate chain memory\n");
			return -ENOMEM;
		}

		if (i == 0) {
			qed_chain_init_mem(p_chain, p_virt, p_phys);
			qed_chain_reset(p_chain);
		} else {
			qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
						     p_virt, p_phys);
		}

		p_virt_prev = p_virt;
	}
	/* Last page's next element should point to the beginning of the
	 * chain.
	 */
	qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
				     p_chain->p_virt_addr,
				     p_chain->p_phys_addr);

	return 0;
}

static int
qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain)
{
	dma_addr_t p_phys = 0;
	void *p_virt = NULL;

	size = page_cnt * QED_CHAIN_PAGE_SIZE;
	p_virt = dma_alloc_coherent(&cdev->pdev->dev,
				    size, &p_phys, GFP_KERNEL);
				    QED_CHAIN_PAGE_SIZE, &p_phys, GFP_KERNEL);
	if (!p_virt) {
		DP_NOTICE(cdev, "Failed to allocate chain mem\n");
		goto nomem;
		DP_NOTICE(cdev, "Failed to allocate chain memory\n");
		return -ENOMEM;
	}

	qed_chain_init_mem(p_chain, p_virt, p_phys);
	qed_chain_reset(p_chain);

	return 0;
}

	if (mode == QED_CHAIN_MODE_PBL) {
static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
{
	u32 page_cnt = p_chain->page_cnt, size, i;
	dma_addr_t p_phys = 0, p_pbl_phys = 0;
	void **pp_virt_addr_tbl = NULL;
	u8 *p_pbl_virt = NULL;
	void *p_virt = NULL;

	size = page_cnt * sizeof(*pp_virt_addr_tbl);
	pp_virt_addr_tbl = vmalloc(size);
	if (!pp_virt_addr_tbl) {
		DP_NOTICE(cdev,
			  "Failed to allocate memory for the chain virtual addresses table\n");
		return -ENOMEM;
	}
	memset(pp_virt_addr_tbl, 0, size);

	/* The allocation of the PBL table is done with its full size, since it
	 * is expected to be successive.
	 * qed_chain_init_pbl_mem() is called even in a case of an allocation
	 * failure, since pp_virt_addr_tbl was previously allocated, and it
	 * should be saved to allow its freeing during the error flow.
	 */
	size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
	p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev,
						size, &p_pbl_phys,
						GFP_KERNEL);
					size, &p_pbl_phys, GFP_KERNEL);
	qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys,
			       pp_virt_addr_tbl);
	if (!p_pbl_virt) {
			DP_NOTICE(cdev, "Failed to allocate chain pbl mem\n");
			goto nomem;
		DP_NOTICE(cdev, "Failed to allocate chain pbl memory\n");
		return -ENOMEM;
	}

		qed_chain_pbl_init(p_chain, p_virt, p_phys, page_cnt,
				   (u8)elem_size, intended_use,
				   p_pbl_phys, p_pbl_virt);
	} else {
		qed_chain_init(p_chain, p_virt, p_phys, page_cnt,
			       (u8)elem_size, intended_use, mode);
	for (i = 0; i < page_cnt; i++) {
		p_virt = dma_alloc_coherent(&cdev->pdev->dev,
					    QED_CHAIN_PAGE_SIZE,
					    &p_phys, GFP_KERNEL);
		if (!p_virt) {
			DP_NOTICE(cdev, "Failed to allocate chain memory\n");
			return -ENOMEM;
		}

	return 0;
		if (i == 0) {
			qed_chain_init_mem(p_chain, p_virt, p_phys);
			qed_chain_reset(p_chain);
		}

nomem:
	dma_free_coherent(&cdev->pdev->dev,
			  page_cnt * QED_CHAIN_PAGE_SIZE,
			  p_virt, p_phys);
	dma_free_coherent(&cdev->pdev->dev,
			  page_cnt * QED_CHAIN_PBL_ENTRY_SIZE,
			  p_pbl_virt, p_pbl_phys);
		/* Fill the PBL table with the physical address of the page */
		*(dma_addr_t *)p_pbl_virt = p_phys;
		/* Keep the virtual address of the page */
		p_chain->pbl.pp_virt_addr_tbl[i] = p_virt;

	return -ENOMEM;
		p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
	}

void qed_chain_free(struct qed_dev *cdev,
		    struct qed_chain *p_chain)
	return 0;
}

int qed_chain_alloc(struct qed_dev *cdev,
		    enum qed_chain_use_mode intended_use,
		    enum qed_chain_mode mode,
		    enum qed_chain_cnt_type cnt_type,
		    u32 num_elems, size_t elem_size, struct qed_chain *p_chain)
{
	size_t size;
	u32 page_cnt;
	int rc = 0;

	if (!p_chain->p_virt_addr)
		return;
	if (mode == QED_CHAIN_MODE_SINGLE)
		page_cnt = 1;
	else
		page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode);

	if (p_chain->mode == QED_CHAIN_MODE_PBL) {
		size = p_chain->page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
		dma_free_coherent(&cdev->pdev->dev, size,
				  p_chain->pbl.p_virt_table,
				  p_chain->pbl.p_phys_table);
	rc = qed_chain_alloc_sanity_check(cdev, cnt_type, elem_size, page_cnt);
	if (rc) {
		DP_NOTICE(cdev,
			  "Cannot allocate a chain with the given arguments:\n"
			  "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n",
			  intended_use, mode, cnt_type, num_elems, elem_size);
		return rc;
	}

	size = p_chain->page_cnt * QED_CHAIN_PAGE_SIZE;
	dma_free_coherent(&cdev->pdev->dev, size,
			  p_chain->p_virt_addr,
			  p_chain->p_phys_addr);
	qed_chain_init_params(p_chain, page_cnt, (u8) elem_size, intended_use,
			      mode, cnt_type);

	switch (mode) {
	case QED_CHAIN_MODE_NEXT_PTR:
		rc = qed_chain_alloc_next_ptr(cdev, p_chain);
		break;
	case QED_CHAIN_MODE_SINGLE:
		rc = qed_chain_alloc_single(cdev, p_chain);
		break;
	case QED_CHAIN_MODE_PBL:
		rc = qed_chain_alloc_pbl(cdev, p_chain);
		break;
	}
	if (rc)
		goto nomem;

	return 0;

nomem:
	qed_chain_free(cdev, p_chain);
	return rc;
}

int qed_fw_l2_queue(struct qed_hwfn *p_hwfn,
		    u16 src_id, u16 *dst_id)
int qed_fw_l2_queue(struct qed_hwfn *p_hwfn, u16 src_id, u16 *dst_id)
{
	if (src_id >= RESC_NUM(p_hwfn, QED_L2_QUEUE)) {
		u16 min, max;
+3 −5
Original line number Diff line number Diff line
@@ -245,9 +245,8 @@ int
qed_chain_alloc(struct qed_dev *cdev,
		enum qed_chain_use_mode intended_use,
		enum qed_chain_mode mode,
		u16 num_elems,
		size_t elem_size,
		struct qed_chain *p_chain);
		enum qed_chain_cnt_type cnt_type,
		u32 num_elems, size_t elem_size, struct qed_chain *p_chain);

/**
 * @brief qed_chain_free - Free chain DMA memory
@@ -255,8 +254,7 @@ qed_chain_alloc(struct qed_dev *cdev,
 * @param p_hwfn
 * @param p_chain
 */
void qed_chain_free(struct qed_dev *cdev,
		    struct qed_chain *p_chain);
void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain);

/**
 * @@brief qed_fw_l2_queue - Get absolute L2 queue ID
Loading