Commit 822cd092 authored by Pavan Kumar Linga's avatar Pavan Kumar Linga Committed by Tony Nguyen
Browse files

idpf: avoid calling get_rx_ptypes for each vport



RX ptypes received from device control plane doesn't depend on vport
info, but might vary based on the queue model. When the driver requests
for ptypes, control plane fills both ptype_id_10 (used for splitq) and
ptype_id_8 (used for singleq) fields of the virtchnl2_ptype response
structure. This allows to call get_rx_ptypes once at the adapter level
instead of each vport.

Parse and store the received ptypes of both splitq and singleq in a
separate lookup table. Respective lookup table is used based on the
queue model info. As part of the changes, pull the ptype protocol
parsing code into a separate function.

Reviewed-by: default avatarMadhu Chittim <madhu.chittim@intel.com>
Signed-off-by: default avatarPavan Kumar Linga <pavan.kumar.linga@intel.com>
Signed-off-by: default avatarJoshua Hay <joshua.a.hay@intel.com>
Reviewed-by: default avatarAleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: default avatarSamuel Salin <Samuel.salin@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 60164340
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -370,7 +370,6 @@ struct idpf_q_vec_rsrc {
 * @default_mac_addr: device will give a default MAC to use
 * @rx_itr_profile: RX profiles for Dynamic Interrupt Moderation
 * @tx_itr_profile: TX profiles for Dynamic Interrupt Moderation
 * @rx_ptype_lkup: Lookup table for ptypes on RX
 * @port_stats: per port csum, header split, and other offload stats
 * @default_vport: Use this vport if one isn't specified
 * @crc_enable: Enable CRC insertion offload
@@ -403,7 +402,6 @@ struct idpf_vport {
	u16 rx_itr_profile[IDPF_DIM_PROFILE_SLOTS];
	u16 tx_itr_profile[IDPF_DIM_PROFILE_SLOTS];

	struct libeth_rx_pt *rx_ptype_lkup;
	struct idpf_port_stats port_stats;
	bool default_vport;
	bool crc_enable;
@@ -643,6 +641,8 @@ struct idpf_vc_xn_manager;
 * @vport_params_reqd: Vport params requested
 * @vport_params_recvd: Vport params received
 * @vport_ids: Array of device given vport identifiers
 * @singleq_pt_lkup: Lookup table for singleq RX ptypes
 * @splitq_pt_lkup: Lookup table for splitq RX ptypes
 * @vport_config: Vport config parameters
 * @max_vports: Maximum vports that can be allocated
 * @num_alloc_vports: Current number of vports allocated
@@ -701,6 +701,9 @@ struct idpf_adapter {
	struct virtchnl2_create_vport **vport_params_recvd;
	u32 *vport_ids;

	struct libeth_rx_pt *singleq_pt_lkup;
	struct libeth_rx_pt *splitq_pt_lkup;

	struct idpf_vport_config **vport_config;
	u16 max_vports;
	u16 num_alloc_vports;
+0 −9
Original line number Diff line number Diff line
@@ -1058,9 +1058,6 @@ static void idpf_decfg_netdev(struct idpf_vport *vport)
	struct idpf_adapter *adapter = vport->adapter;
	u16 idx = vport->idx;

	kfree(vport->rx_ptype_lkup);
	vport->rx_ptype_lkup = NULL;

	if (test_and_clear_bit(IDPF_VPORT_REG_NETDEV,
			       adapter->vport_config[idx]->flags)) {
		unregister_netdev(vport->netdev);
@@ -1116,8 +1113,6 @@ static void idpf_vport_rel(struct idpf_vport *vport)
	adapter->vport_params_recvd[idx] = NULL;
	kfree(adapter->vport_params_reqd[idx]);
	adapter->vport_params_reqd[idx] = NULL;
	kfree(vport->rx_ptype_lkup);
	vport->rx_ptype_lkup = NULL;

	kfree(vport);
	adapter->num_alloc_vports--;
@@ -1687,10 +1682,6 @@ void idpf_init_task(struct work_struct *work)
		goto unwind_vports;
	}

	err = idpf_send_get_rx_ptype_msg(vport);
	if (err)
		goto unwind_vports;

	index = vport->idx;
	vport_config = adapter->vport_config[index];

+3 −1
Original line number Diff line number Diff line
@@ -1802,6 +1802,7 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport,
				struct idpf_q_vec_rsrc *rsrc,
				u16 num_rxq)
{
	struct idpf_adapter *adapter = vport->adapter;
	bool hs, rsc;
	int err = 0;

@@ -1895,6 +1896,7 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport,

			if (!idpf_is_queue_model_split(rsrc->rxq_model)) {
				q = rx_qgrp->singleq.rxqs[j];
				q->rx_ptype_lkup = adapter->singleq_pt_lkup;
				goto setup_rxq;
			}
			q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
@@ -1906,10 +1908,10 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport,

			idpf_queue_assign(HSPLIT_EN, q, hs);
			idpf_queue_assign(RSC_EN, q, rsc);
			q->rx_ptype_lkup = adapter->splitq_pt_lkup;

setup_rxq:
			q->desc_count = rsrc->rxq_desc_count;
			q->rx_ptype_lkup = vport->rx_ptype_lkup;
			q->bufq_sets = rx_qgrp->splitq.bufq_sets;
			q->idx = (i * num_rxq) + j;
			q->rx_buffer_low_watermark = IDPF_LOW_WATERMARK;
+170 −146
Original line number Diff line number Diff line
@@ -3065,159 +3065,62 @@ static void idpf_finalize_ptype_lookup(struct libeth_rx_pt *ptype)
}

/**
 * idpf_send_get_rx_ptype_msg - Send virtchnl for ptype info
 * @vport: virtual port data structure
 *
 * Returns 0 on success, negative on failure.
 * idpf_parse_protocol_ids - parse protocol IDs for a given packet type
 * @ptype: packet type to parse
 * @rx_pt: store the parsed packet type info into
 */
int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport)
static void idpf_parse_protocol_ids(struct virtchnl2_ptype *ptype,
				    struct libeth_rx_pt *rx_pt)
{
	struct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL;
	struct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL;
	struct libeth_rx_pt *ptype_lkup __free(kfree) = NULL;
	int max_ptype, ptypes_recvd = 0, ptype_offset;
	struct idpf_adapter *adapter = vport->adapter;
	struct idpf_vc_xn_params xn_params = {};
	u16 next_ptype_id = 0;
	ssize_t reply_sz;
	bool is_splitq;
	int i, j, k;

	if (vport->rx_ptype_lkup)
		return 0;

	is_splitq = idpf_is_queue_model_split(vport->dflt_qv_rsrc.rxq_model);
	if (is_splitq)
		max_ptype = IDPF_RX_MAX_PTYPE;
	else
		max_ptype = IDPF_RX_MAX_BASE_PTYPE;

	ptype_lkup = kcalloc(max_ptype, sizeof(*ptype_lkup), GFP_KERNEL);
	if (!ptype_lkup)
		return -ENOMEM;

	get_ptype_info = kzalloc(sizeof(*get_ptype_info), GFP_KERNEL);
	if (!get_ptype_info)
		return -ENOMEM;

	ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
	if (!ptype_info)
		return -ENOMEM;

	xn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO;
	xn_params.send_buf.iov_base = get_ptype_info;
	xn_params.send_buf.iov_len = sizeof(*get_ptype_info);
	xn_params.recv_buf.iov_base = ptype_info;
	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;

	while (next_ptype_id < max_ptype) {
		get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id);

		if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype)
			get_ptype_info->num_ptypes =
				cpu_to_le16(max_ptype - next_ptype_id);
		else
			get_ptype_info->num_ptypes =
				cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);

		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
		if (reply_sz < 0)
			return reply_sz;

		ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes);
		if (ptypes_recvd > max_ptype)
			return -EINVAL;

		next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) +
				le16_to_cpu(get_ptype_info->num_ptypes);

		ptype_offset = IDPF_RX_PTYPE_HDR_SZ;

		for (i = 0; i < le16_to_cpu(ptype_info->num_ptypes); i++) {
	struct idpf_ptype_state pstate = {};
			struct virtchnl2_ptype *ptype;
			u16 id;

			ptype = (struct virtchnl2_ptype *)
					((u8 *)ptype_info + ptype_offset);

			ptype_offset += IDPF_GET_PTYPE_SIZE(ptype);
			if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN)
				return -EINVAL;

			/* 0xFFFF indicates end of ptypes */
			if (le16_to_cpu(ptype->ptype_id_10) ==
							IDPF_INVALID_PTYPE_ID)
				goto out;

			if (is_splitq)
				k = le16_to_cpu(ptype->ptype_id_10);
			else
				k = ptype->ptype_id_8;
	for (u32 j = 0; j < ptype->proto_id_count; j++) {
		u16 id = le16_to_cpu(ptype->proto_id[j]);

			for (j = 0; j < ptype->proto_id_count; j++) {
				id = le16_to_cpu(ptype->proto_id[j]);
		switch (id) {
		case VIRTCHNL2_PROTO_HDR_GRE:
					if (pstate.tunnel_state ==
							IDPF_PTYPE_TUNNEL_IP) {
						ptype_lkup[k].tunnel_type =
			if (pstate.tunnel_state == IDPF_PTYPE_TUNNEL_IP) {
				rx_pt->tunnel_type =
					LIBETH_RX_PT_TUNNEL_IP_GRENAT;
				pstate.tunnel_state |=
					IDPF_PTYPE_TUNNEL_IP_GRENAT;
			}
			break;
		case VIRTCHNL2_PROTO_HDR_MAC:
					ptype_lkup[k].outer_ip =
						LIBETH_RX_PT_OUTER_L2;
					if (pstate.tunnel_state ==
							IDPF_TUN_IP_GRE) {
						ptype_lkup[k].tunnel_type =
			rx_pt->outer_ip = LIBETH_RX_PT_OUTER_L2;
			if (pstate.tunnel_state == IDPF_TUN_IP_GRE) {
				rx_pt->tunnel_type =
					LIBETH_RX_PT_TUNNEL_IP_GRENAT_MAC;
				pstate.tunnel_state |=
					IDPF_PTYPE_TUNNEL_IP_GRENAT_MAC;
			}
			break;
		case VIRTCHNL2_PROTO_HDR_IPV4:
					idpf_fill_ptype_lookup(&ptype_lkup[k],
							       &pstate, true,
							       false);
			idpf_fill_ptype_lookup(rx_pt, &pstate, true, false);
			break;
		case VIRTCHNL2_PROTO_HDR_IPV6:
					idpf_fill_ptype_lookup(&ptype_lkup[k],
							       &pstate, false,
							       false);
			idpf_fill_ptype_lookup(rx_pt, &pstate, false, false);
			break;
		case VIRTCHNL2_PROTO_HDR_IPV4_FRAG:
					idpf_fill_ptype_lookup(&ptype_lkup[k],
							       &pstate, true,
							       true);
			idpf_fill_ptype_lookup(rx_pt, &pstate, true, true);
			break;
		case VIRTCHNL2_PROTO_HDR_IPV6_FRAG:
					idpf_fill_ptype_lookup(&ptype_lkup[k],
							       &pstate, false,
							       true);
			idpf_fill_ptype_lookup(rx_pt, &pstate, false, true);
			break;
		case VIRTCHNL2_PROTO_HDR_UDP:
					ptype_lkup[k].inner_prot =
					LIBETH_RX_PT_INNER_UDP;
			rx_pt->inner_prot = LIBETH_RX_PT_INNER_UDP;
			break;
		case VIRTCHNL2_PROTO_HDR_TCP:
					ptype_lkup[k].inner_prot =
					LIBETH_RX_PT_INNER_TCP;
			rx_pt->inner_prot = LIBETH_RX_PT_INNER_TCP;
			break;
		case VIRTCHNL2_PROTO_HDR_SCTP:
					ptype_lkup[k].inner_prot =
					LIBETH_RX_PT_INNER_SCTP;
			rx_pt->inner_prot = LIBETH_RX_PT_INNER_SCTP;
			break;
		case VIRTCHNL2_PROTO_HDR_ICMP:
					ptype_lkup[k].inner_prot =
					LIBETH_RX_PT_INNER_ICMP;
			rx_pt->inner_prot = LIBETH_RX_PT_INNER_ICMP;
			break;
		case VIRTCHNL2_PROTO_HDR_PAY:
					ptype_lkup[k].payload_layer =
						LIBETH_RX_PT_PAYLOAD_L2;
			rx_pt->payload_layer = LIBETH_RX_PT_PAYLOAD_L2;
			break;
		case VIRTCHNL2_PROTO_HDR_ICMPV6:
		case VIRTCHNL2_PROTO_HDR_IPV6_EH:
@@ -3271,17 +3174,128 @@ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport)
			break;
		}
	}
}

			idpf_finalize_ptype_lookup(&ptype_lkup[k]);
/**
 * idpf_send_get_rx_ptype_msg - Send virtchnl for ptype info
 * @adapter: driver specific private structure
 *
 * Return: 0 on success, negative on failure.
 */
static int idpf_send_get_rx_ptype_msg(struct idpf_adapter *adapter)
{
	struct virtchnl2_get_ptype_info *get_ptype_info __free(kfree) = NULL;
	struct virtchnl2_get_ptype_info *ptype_info __free(kfree) = NULL;
	struct libeth_rx_pt *singleq_pt_lkup __free(kfree) = NULL;
	struct libeth_rx_pt *splitq_pt_lkup __free(kfree) = NULL;
	struct idpf_vc_xn_params xn_params = {};
	int ptypes_recvd = 0, ptype_offset;
	u32 max_ptype = IDPF_RX_MAX_PTYPE;
	u16 next_ptype_id = 0;
	ssize_t reply_sz;

	singleq_pt_lkup = kcalloc(IDPF_RX_MAX_BASE_PTYPE,
				  sizeof(*singleq_pt_lkup), GFP_KERNEL);
	if (!singleq_pt_lkup)
		return -ENOMEM;

	splitq_pt_lkup = kcalloc(max_ptype, sizeof(*splitq_pt_lkup), GFP_KERNEL);
	if (!splitq_pt_lkup)
		return -ENOMEM;

	get_ptype_info = kzalloc(sizeof(*get_ptype_info), GFP_KERNEL);
	if (!get_ptype_info)
		return -ENOMEM;

	ptype_info = kzalloc(IDPF_CTLQ_MAX_BUF_LEN, GFP_KERNEL);
	if (!ptype_info)
		return -ENOMEM;

	xn_params.vc_op = VIRTCHNL2_OP_GET_PTYPE_INFO;
	xn_params.send_buf.iov_base = get_ptype_info;
	xn_params.send_buf.iov_len = sizeof(*get_ptype_info);
	xn_params.recv_buf.iov_base = ptype_info;
	xn_params.recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN;
	xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;

	while (next_ptype_id < max_ptype) {
		get_ptype_info->start_ptype_id = cpu_to_le16(next_ptype_id);

		if ((next_ptype_id + IDPF_RX_MAX_PTYPES_PER_BUF) > max_ptype)
			get_ptype_info->num_ptypes =
				cpu_to_le16(max_ptype - next_ptype_id);
		else
			get_ptype_info->num_ptypes =
				cpu_to_le16(IDPF_RX_MAX_PTYPES_PER_BUF);

		reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
		if (reply_sz < 0)
			return reply_sz;

		ptypes_recvd += le16_to_cpu(ptype_info->num_ptypes);
		if (ptypes_recvd > max_ptype)
			return -EINVAL;

		next_ptype_id = le16_to_cpu(get_ptype_info->start_ptype_id) +
				le16_to_cpu(get_ptype_info->num_ptypes);

		ptype_offset = IDPF_RX_PTYPE_HDR_SZ;

		for (u16 i = 0; i < le16_to_cpu(ptype_info->num_ptypes); i++) {
			struct libeth_rx_pt rx_pt = {};
			struct virtchnl2_ptype *ptype;
			u16 pt_10, pt_8;

			ptype = (struct virtchnl2_ptype *)
					((u8 *)ptype_info + ptype_offset);

			pt_10 = le16_to_cpu(ptype->ptype_id_10);
			pt_8 = ptype->ptype_id_8;

			ptype_offset += IDPF_GET_PTYPE_SIZE(ptype);
			if (ptype_offset > IDPF_CTLQ_MAX_BUF_LEN)
				return -EINVAL;

			/* 0xFFFF indicates end of ptypes */
			if (pt_10 == IDPF_INVALID_PTYPE_ID)
				goto out;
			if (pt_10 >= max_ptype)
				return -EINVAL;

			idpf_parse_protocol_ids(ptype, &rx_pt);
			idpf_finalize_ptype_lookup(&rx_pt);

			/* For a given protocol ID stack, the ptype value might
			 * vary between ptype_id_10 and ptype_id_8. So store
			 * them separately for splitq and singleq. Also skip
			 * the repeated ptypes in case of singleq.
			 */
			splitq_pt_lkup[pt_10] = rx_pt;
			if (!singleq_pt_lkup[pt_8].outer_ip)
				singleq_pt_lkup[pt_8] = rx_pt;
		}
	}

out:
	vport->rx_ptype_lkup = no_free_ptr(ptype_lkup);
	adapter->splitq_pt_lkup = no_free_ptr(splitq_pt_lkup);
	adapter->singleq_pt_lkup = no_free_ptr(singleq_pt_lkup);

	return 0;
}

/**
 * idpf_rel_rx_pt_lkup - release RX ptype lookup table
 * @adapter: adapter pointer to get the lookup table
 */
static void idpf_rel_rx_pt_lkup(struct idpf_adapter *adapter)
{
	kfree(adapter->splitq_pt_lkup);
	adapter->splitq_pt_lkup = NULL;

	kfree(adapter->singleq_pt_lkup);
	adapter->singleq_pt_lkup = NULL;
}

/**
 * idpf_send_ena_dis_loopback_msg - Send virtchnl enable/disable loopback
 *				    message
@@ -3579,6 +3593,13 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
		goto err_intr_req;
	}

	err = idpf_send_get_rx_ptype_msg(adapter);
	if (err) {
		dev_err(&adapter->pdev->dev, "failed to get RX ptypes: %d\n",
			err);
		goto intr_rel;
	}

	err = idpf_ptp_init(adapter);
	if (err)
		pci_err(adapter->pdev, "PTP init failed, err=%pe\n",
@@ -3596,6 +3617,8 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)

	return 0;

intr_rel:
	idpf_intr_rel(adapter);
err_intr_req:
	cancel_delayed_work_sync(&adapter->serv_task);
	cancel_delayed_work_sync(&adapter->mbx_task);
@@ -3650,6 +3673,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
	idpf_ptp_release(adapter);
	idpf_deinit_task(adapter);
	idpf_idc_deinit_core_aux_device(adapter->cdev_info);
	idpf_rel_rx_pt_lkup(adapter);
	idpf_intr_rel(adapter);

	if (remove_in_prog)
+0 −1
Original line number Diff line number Diff line
@@ -202,7 +202,6 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
			 struct idpf_vport_user_config_data *config_data,
			 u32 vport_id);
int idpf_check_supported_desc_ids(struct idpf_vport *vport);
int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport);
int idpf_send_ena_dis_loopback_msg(struct idpf_adapter *adapter, u32 vport_id,
				   bool loopback_ena);
int idpf_send_get_stats_msg(struct idpf_netdev_priv *np,