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

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

Merge branch 'qed-vf-xdp'



Yuval Mintz says:

qed*: Support VF XDP attachment

====================
Each driver queue [Rx, Tx, XDP-forwarding] requires an allocated HW/FW
connection + configured queue-zone.

VF handling by the PF has several limitations that prevented adding the
capability to perform XDP at driver-level:

 - The VF assumes there's 1-to-1 correspondance between the VF queue and
   the used connection, meaning q<x> is always going to use cid<x>,
   whereas for its own queues the PF is acquiring a new cid per each new
   queue.

 - There's a 1-to-1 correspondate between the VF-queues and the HW queue
   zones. While this is necessary for Rx-queues [as the queue-zone
   contains the producer], transmission queues can share the underlaying
   queue-zone [only shared configuration is coalescing].
   But all VF<->PF communication mechanisms assume there's a single
   identifier that identify a queue [as queue-zone == queue], while
   sharing queue-zones requires passing additional information.

 - VFs currently don't try mapping a doorbell bar - there's a small
   doorbell window in the regview allowing VFs to doorbell up to 16
   connections; but this window isn's wide enough for the added XDP
   forwarding queues.

This series is going to add the necessary infrastrucutre to finally let
our VFs support XDP assuming both the PF and VF drivers are sufficiently
new [Legacy support would be retained both for older VFs and older PFs,
but both will be needed for this new support to work].
Basically, the various database driver maintains for its queue-cids
would be revised, and queue-cids would be identified using the
(queue-zone, unique index) pair. The TLV mechanism would then be
extended to allow VFs to communicate that unique-index as well as the
already provided queue-zone. Finally, the VFs would try to map their
doorbell bar and inform their PF that they're using it.

Almost all the changes are in qed, with exception of #3 [which does some
cleanup in qede as well] and #11 that actually enables the feature.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a619cc8b e7b80dec
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -412,6 +412,11 @@ struct qed_fw_data {
	u32			init_ops_size;
};

enum BAR_ID {
	BAR_ID_0,		/* used for GRC */
	BAR_ID_1		/* Used for doorbells */
};

#define DRV_MODULE_VERSION		      \
	__stringify(QED_MAJOR_VERSION) "."    \
	__stringify(QED_MINOR_VERSION) "."    \
@@ -533,6 +538,9 @@ struct qed_hwfn {
	u8 dcbx_no_edpm;
	u8 db_bar_no_edpm;

	/* L2-related */
	struct qed_l2_info *p_l2_info;

	struct qed_ptt *p_arfs_ptt;

	struct qed_simd_fp_handler	simd_proto_handler[64];
+169 −61
Original line number Diff line number Diff line
@@ -135,7 +135,6 @@ struct qed_tid_seg {

struct qed_conn_type_cfg {
	u32 cid_count;
	u32 cid_start;
	u32 cids_per_vf;
	struct qed_tid_seg tid_seg[TASK_SEGMENTS];
};
@@ -222,6 +221,9 @@ struct qed_cxt_mngr {
	/* Acquired CIDs */
	struct qed_cid_acquired_map	acquired[MAX_CONN_TYPES];

	struct qed_cid_acquired_map
	acquired_vf[MAX_CONN_TYPES][MAX_NUM_VFS];

	/* ILT  shadow table */
	struct qed_dma_mem		*ilt_shadow;
	u32				pf_start_line;
@@ -1121,45 +1123,76 @@ static int qed_ilt_shadow_alloc(struct qed_hwfn *p_hwfn)
static void qed_cid_map_free(struct qed_hwfn *p_hwfn)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	u32 type;
	u32 type, vf;

	for (type = 0; type < MAX_CONN_TYPES; type++) {
		kfree(p_mngr->acquired[type].cid_map);
		p_mngr->acquired[type].max_count = 0;
		p_mngr->acquired[type].start_cid = 0;

		for (vf = 0; vf < MAX_NUM_VFS; vf++) {
			kfree(p_mngr->acquired_vf[type][vf].cid_map);
			p_mngr->acquired_vf[type][vf].max_count = 0;
			p_mngr->acquired_vf[type][vf].start_cid = 0;
		}
	}
}

static int qed_cid_map_alloc(struct qed_hwfn *p_hwfn)
static int
qed_cid_map_alloc_single(struct qed_hwfn *p_hwfn,
			 u32 type,
			 u32 cid_start,
			 u32 cid_count, struct qed_cid_acquired_map *p_map)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	u32 start_cid = 0;
	u32 type;

	for (type = 0; type < MAX_CONN_TYPES; type++) {
		u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count;
	u32 size;

		if (cid_cnt == 0)
			continue;
	if (!cid_count)
		return 0;

		size = DIV_ROUND_UP(cid_cnt,
	size = DIV_ROUND_UP(cid_count,
			    sizeof(unsigned long) * BITS_PER_BYTE) *
	       sizeof(unsigned long);
		p_mngr->acquired[type].cid_map = kzalloc(size, GFP_KERNEL);
		if (!p_mngr->acquired[type].cid_map)
			goto cid_map_fail;

		p_mngr->acquired[type].max_count = cid_cnt;
		p_mngr->acquired[type].start_cid = start_cid;
	p_map->cid_map = kzalloc(size, GFP_KERNEL);
	if (!p_map->cid_map)
		return -ENOMEM;

		p_hwfn->p_cxt_mngr->conn_cfg[type].cid_start = start_cid;
	p_map->max_count = cid_count;
	p_map->start_cid = cid_start;

	DP_VERBOSE(p_hwfn, QED_MSG_CXT,
		   "Type %08x start: %08x count %08x\n",
			   type, p_mngr->acquired[type].start_cid,
			   p_mngr->acquired[type].max_count);
		start_cid += cid_cnt;
		   type, p_map->start_cid, p_map->max_count);

	return 0;
}

static int qed_cid_map_alloc(struct qed_hwfn *p_hwfn)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	u32 start_cid = 0, vf_start_cid = 0;
	u32 type, vf;

	for (type = 0; type < MAX_CONN_TYPES; type++) {
		struct qed_conn_type_cfg *p_cfg = &p_mngr->conn_cfg[type];
		struct qed_cid_acquired_map *p_map;

		/* Handle PF maps */
		p_map = &p_mngr->acquired[type];
		if (qed_cid_map_alloc_single(p_hwfn, type, start_cid,
					     p_cfg->cid_count, p_map))
			goto cid_map_fail;

		/* Handle VF maps */
		for (vf = 0; vf < MAX_NUM_VFS; vf++) {
			p_map = &p_mngr->acquired_vf[type][vf];
			if (qed_cid_map_alloc_single(p_hwfn, type,
						     vf_start_cid,
						     p_cfg->cids_per_vf, p_map))
				goto cid_map_fail;
		}

		start_cid += p_cfg->cid_count;
		vf_start_cid += p_cfg->cids_per_vf;
	}

	return 0;
@@ -1265,19 +1298,36 @@ void qed_cxt_mngr_free(struct qed_hwfn *p_hwfn)
void qed_cxt_mngr_setup(struct qed_hwfn *p_hwfn)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	struct qed_cid_acquired_map *p_map;
	struct qed_conn_type_cfg *p_cfg;
	int type;
	u32 len;

	/* Reset acquired cids */
	for (type = 0; type < MAX_CONN_TYPES; type++) {
		u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count;
		u32 vf;

		p_cfg = &p_mngr->conn_cfg[type];
		if (p_cfg->cid_count) {
			p_map = &p_mngr->acquired[type];
			len = DIV_ROUND_UP(p_map->max_count,
					   sizeof(unsigned long) *
					   BITS_PER_BYTE) *
			      sizeof(unsigned long);
			memset(p_map->cid_map, 0, len);
		}

		if (cid_cnt == 0)
		if (!p_cfg->cids_per_vf)
			continue;

		memset(p_mngr->acquired[type].cid_map, 0,
		       DIV_ROUND_UP(cid_cnt,
				    sizeof(unsigned long) * BITS_PER_BYTE) *
		       sizeof(unsigned long));
		for (vf = 0; vf < MAX_NUM_VFS; vf++) {
			p_map = &p_mngr->acquired_vf[type][vf];
			len = DIV_ROUND_UP(p_map->max_count,
					   sizeof(unsigned long) *
					   BITS_PER_BYTE) *
			      sizeof(unsigned long);
			memset(p_map->cid_map, 0, len);
		}
	}
}

@@ -1841,91 +1891,145 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
	qed_prs_init_pf(p_hwfn);
}

int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
			enum protocol_type type, u32 *p_cid)
int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
			 enum protocol_type type, u32 *p_cid, u8 vfid)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	struct qed_cid_acquired_map *p_map;
	u32 rel_cid;

	if (type >= MAX_CONN_TYPES || !p_mngr->acquired[type].cid_map) {
	if (type >= MAX_CONN_TYPES) {
		DP_NOTICE(p_hwfn, "Invalid protocol type %d", type);
		return -EINVAL;
	}

	if (vfid >= MAX_NUM_VFS && vfid != QED_CXT_PF_CID) {
		DP_NOTICE(p_hwfn, "VF [%02x] is out of range\n", vfid);
		return -EINVAL;
	}

	/* Determine the right map to take this CID from */
	if (vfid == QED_CXT_PF_CID)
		p_map = &p_mngr->acquired[type];
	else
		p_map = &p_mngr->acquired_vf[type][vfid];

	if (!p_map->cid_map) {
		DP_NOTICE(p_hwfn, "Invalid protocol type %d", type);
		return -EINVAL;
	}

	rel_cid = find_first_zero_bit(p_mngr->acquired[type].cid_map,
				      p_mngr->acquired[type].max_count);
	rel_cid = find_first_zero_bit(p_map->cid_map, p_map->max_count);

	if (rel_cid >= p_mngr->acquired[type].max_count) {
	if (rel_cid >= p_map->max_count) {
		DP_NOTICE(p_hwfn, "no CID available for protocol %d\n", type);
		return -EINVAL;
	}

	__set_bit(rel_cid, p_mngr->acquired[type].cid_map);
	__set_bit(rel_cid, p_map->cid_map);

	*p_cid = rel_cid + p_mngr->acquired[type].start_cid;
	*p_cid = rel_cid + p_map->start_cid;

	DP_VERBOSE(p_hwfn, QED_MSG_CXT,
		   "Acquired cid 0x%08x [rel. %08x] vfid %02x type %d\n",
		   *p_cid, rel_cid, vfid, type);

	return 0;
}

int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
			enum protocol_type type, u32 *p_cid)
{
	return _qed_cxt_acquire_cid(p_hwfn, type, p_cid, QED_CXT_PF_CID);
}

static bool qed_cxt_test_cid_acquired(struct qed_hwfn *p_hwfn,
				      u32 cid, enum protocol_type *p_type)
				      u32 cid,
				      u8 vfid,
				      enum protocol_type *p_type,
				      struct qed_cid_acquired_map **pp_map)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	struct qed_cid_acquired_map *p_map;
	enum protocol_type p;
	u32 rel_cid;

	/* Iterate over protocols and find matching cid range */
	for (p = 0; p < MAX_CONN_TYPES; p++) {
		p_map = &p_mngr->acquired[p];
	for (*p_type = 0; *p_type < MAX_CONN_TYPES; (*p_type)++) {
		if (vfid == QED_CXT_PF_CID)
			*pp_map = &p_mngr->acquired[*p_type];
		else
			*pp_map = &p_mngr->acquired_vf[*p_type][vfid];

		if (!p_map->cid_map)
		if (!((*pp_map)->cid_map))
			continue;
		if (cid >= p_map->start_cid &&
		    cid < p_map->start_cid + p_map->max_count)
		if (cid >= (*pp_map)->start_cid &&
		    cid < (*pp_map)->start_cid + (*pp_map)->max_count)
			break;
	}
	*p_type = p;

	if (p == MAX_CONN_TYPES) {
		DP_NOTICE(p_hwfn, "Invalid CID %d", cid);
		return false;
	if (*p_type == MAX_CONN_TYPES) {
		DP_NOTICE(p_hwfn, "Invalid CID %d vfid %02x", cid, vfid);
		goto fail;
	}

	rel_cid = cid - p_map->start_cid;
	if (!test_bit(rel_cid, p_map->cid_map)) {
		DP_NOTICE(p_hwfn, "CID %d not acquired", cid);
		return false;
	rel_cid = cid - (*pp_map)->start_cid;
	if (!test_bit(rel_cid, (*pp_map)->cid_map)) {
		DP_NOTICE(p_hwfn, "CID %d [vifd %02x] not acquired",
			  cid, vfid);
		goto fail;
	}

	return true;
fail:
	*p_type = MAX_CONN_TYPES;
	*pp_map = NULL;
	return false;
}

void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid)
void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	struct qed_cid_acquired_map *p_map = NULL;
	enum protocol_type type;
	bool b_acquired;
	u32 rel_cid;

	if (vfid != QED_CXT_PF_CID && vfid > MAX_NUM_VFS) {
		DP_NOTICE(p_hwfn,
			  "Trying to return incorrect CID belonging to VF %02x\n",
			  vfid);
		return;
	}

	/* Test acquired and find matching per-protocol map */
	b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, &type);
	b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, vfid,
					       &type, &p_map);

	if (!b_acquired)
		return;

	rel_cid = cid - p_mngr->acquired[type].start_cid;
	__clear_bit(rel_cid, p_mngr->acquired[type].cid_map);
	rel_cid = cid - p_map->start_cid;
	clear_bit(rel_cid, p_map->cid_map);

	DP_VERBOSE(p_hwfn, QED_MSG_CXT,
		   "Released CID 0x%08x [rel. %08x] vfid %02x type %d\n",
		   cid, rel_cid, vfid, type);
}

void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid)
{
	_qed_cxt_release_cid(p_hwfn, cid, QED_CXT_PF_CID);
}

int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, struct qed_cxt_info *p_info)
{
	struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
	struct qed_cid_acquired_map *p_map = NULL;
	u32 conn_cxt_size, hw_p_size, cxts_per_p, line;
	enum protocol_type type;
	bool b_acquired;

	/* Test acquired and find matching per-protocol map */
	b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, &type);
	b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid,
					       QED_CXT_PF_CID, &type, &p_map);

	if (!b_acquired)
		return -EINVAL;
@@ -2012,8 +2116,12 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks)
		struct qed_eth_pf_params *p_params =
		    &p_hwfn->pf_params.eth_pf_params;

			if (!p_params->num_vf_cons)
				p_params->num_vf_cons =
				    ETH_PF_PARAMS_VF_CONS_DEFAULT;
			qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
					    p_params->num_cons, 1);
						    p_params->num_cons,
						    p_params->num_vf_cons);
		p_hwfn->p_cxt_mngr->arfs_count = p_params->num_arfs_filters;
		break;
	}
+39 −15
Original line number Diff line number Diff line
@@ -53,19 +53,6 @@ struct qed_tid_mem {
	u8 *blocks[MAX_TID_BLOCKS];	/* 4K */
};

/**
 * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type
 *
 * @param p_hwfn
 * @param type
 * @param p_cid
 *
 * @return int
 */
int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
			enum protocol_type type,
			u32 *p_cid);

/**
 * @brief qedo_cid_get_cxt_info - Returns the context info for a specific cid
 *
@@ -195,14 +182,51 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 */
int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);

#define QED_CXT_PF_CID (0xff)

/**
 * @brief qed_cxt_release - Release a cid
 *
 * @param p_hwfn
 * @param cid
 */
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn,
			 u32 cid);
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid);

/**
 * @brief qed_cxt_release - Release a cid belonging to a vf-queue
 *
 * @param p_hwfn
 * @param cid
 * @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF
 */
void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid);

/**
 * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type
 *
 * @param p_hwfn
 * @param type
 * @param p_cid
 *
 * @return int
 */
int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
			enum protocol_type type, u32 *p_cid);

/**
 * @brief _qed_cxt_acquire - Acquire a new cid of a specific protocol type
 *                           for a vf-queue
 *
 * @param p_hwfn
 * @param type
 * @param p_cid
 * @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF
 *
 * @return int
 */
int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
			 enum protocol_type type, u32 *p_cid, u8 vfid);

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,
+22 −10
Original line number Diff line number Diff line
@@ -69,12 +69,6 @@ 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 */
	BAR_ID_1        /* Used for doorbells */
};

static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
			   struct qed_ptt *p_ptt, enum BAR_ID bar_id)
{
@@ -83,7 +77,7 @@ static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
	u32 val;

	if (IS_VF(p_hwfn->cdev))
		return 1 << 17;
		return qed_vf_hw_bar_size(p_hwfn, bar_id);

	val = qed_rd(p_hwfn, p_ptt, bar_reg);
	if (val)
@@ -154,8 +148,11 @@ void qed_resc_free(struct qed_dev *cdev)
{
	int i;

	if (IS_VF(cdev))
	if (IS_VF(cdev)) {
		for_each_hwfn(cdev, i)
			qed_l2_free(&cdev->hwfns[i]);
		return;
	}

	kfree(cdev->fw_data);
	cdev->fw_data = NULL;
@@ -183,6 +180,7 @@ void qed_resc_free(struct qed_dev *cdev)
			qed_ooo_free(p_hwfn);
		}
		qed_iov_free(p_hwfn);
		qed_l2_free(p_hwfn);
		qed_dmae_info_free(p_hwfn);
		qed_dcbx_info_free(p_hwfn);
	}
@@ -848,8 +846,14 @@ int qed_resc_alloc(struct qed_dev *cdev)
	u32 line_count;
	int i, rc = 0;

	if (IS_VF(cdev))
	if (IS_VF(cdev)) {
		for_each_hwfn(cdev, i) {
			rc = qed_l2_alloc(&cdev->hwfns[i]);
			if (rc)
				return rc;
		}
		return rc;
	}

	cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL);
	if (!cdev->fw_data)
@@ -960,6 +964,10 @@ int qed_resc_alloc(struct qed_dev *cdev)
		if (rc)
			goto alloc_err;

		rc = qed_l2_alloc(p_hwfn);
		if (rc)
			goto alloc_err;

#ifdef CONFIG_QED_LL2
		if (p_hwfn->using_ll2) {
			rc = qed_ll2_alloc(p_hwfn);
@@ -1011,8 +1019,11 @@ void qed_resc_setup(struct qed_dev *cdev)
{
	int i;

	if (IS_VF(cdev))
	if (IS_VF(cdev)) {
		for_each_hwfn(cdev, i)
			qed_l2_setup(&cdev->hwfns[i]);
		return;
	}

	for_each_hwfn(cdev, i) {
		struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
@@ -1030,6 +1041,7 @@ void qed_resc_setup(struct qed_dev *cdev)

		qed_int_setup(p_hwfn, p_hwfn->p_main_ptt);

		qed_l2_setup(p_hwfn);
		qed_iov_setup(p_hwfn);
#ifdef CONFIG_QED_LL2
		if (p_hwfn->using_ll2)
+247 −51

File changed.

Preview size limit exceeded, changes collapsed.

Loading