Commit fd2162a5 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Tony Nguyen says:

====================
ice: use less resources in switchdev

Michal Swiatkowski says:

Switchdev is using one queue per created port representor. This can
quickly lead to Rx queue shortage, as with subfunction support user
can create high number of PRs.

Save one MSI-X and 'number of PRs' * 1 queues.
Refactor switchdev slow-path to use less resources (even no additional
resources). Do this by removing control plane VSI and move its
functionality to PF VSI. Even with current solution PF is acting like
uplink and can't be used simultaneously for other use cases (adding
filters can break slow-path).

In short, do Tx via PF VSI and Rx packets using PF resources. Rx needs
additional code in interrupt handler to choose correct PR netdev.
Previous solution had to queue filters, it was way more elegant but
needed one queue per PRs. Beside that this refactor mostly simplifies
switchdev configuration.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  ice: count representor stats
  ice: do switchdev slow-path Rx using PF VSI
  ice: change repr::id values
  ice: remove switchdev control plane VSI
  ice: control default Tx rule in lag
  ice: default Tx rule instead of to queue
  ice: do Tx through PF netdev in slow-path
  ice: remove eswitch changing queues algorithm
====================

Link: https://lore.kernel.org/r/20240325202623.1012287-1-anthony.l.nguyen@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents b3f4c329 4498159a
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -522,17 +522,10 @@ enum ice_misc_thread_tasks {
};

struct ice_eswitch {
	struct ice_vsi *control_vsi;
	struct ice_vsi *uplink_vsi;
	struct ice_esw_br_offloads *br_offloads;
	struct xarray reprs;
	bool is_running;
	/* struct to allow cp queues management optimization */
	struct {
		int to_reach;
		int value;
		bool is_reaching;
	} qs;
};

struct ice_agg_node {
+9 −35
Original line number Diff line number Diff line
@@ -263,30 +263,6 @@ static u16 ice_calc_txq_handle(struct ice_vsi *vsi, struct ice_tx_ring *ring, u8
	return ring->q_index - vsi->tc_cfg.tc_info[tc].qoffset;
}

/**
 * ice_eswitch_calc_txq_handle
 * @ring: pointer to ring which unique index is needed
 *
 * To correctly work with many netdevs ring->q_index of Tx rings on switchdev
 * VSI can repeat. Hardware ring setup requires unique q_index. Calculate it
 * here by finding index in vsi->tx_rings of this ring.
 *
 * Return ICE_INVAL_Q_INDEX when index wasn't found. Should never happen,
 * because VSI is get from ring->vsi, so it has to be present in this VSI.
 */
static u16 ice_eswitch_calc_txq_handle(struct ice_tx_ring *ring)
{
	const struct ice_vsi *vsi = ring->vsi;
	int i;

	ice_for_each_txq(vsi, i) {
		if (vsi->tx_rings[i] == ring)
			return i;
	}

	return ICE_INVAL_Q_INDEX;
}

/**
 * ice_cfg_xps_tx_ring - Configure XPS for a Tx ring
 * @ring: The Tx ring to configure
@@ -353,9 +329,6 @@ ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf
		tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf->vf_id;
		tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF;
		break;
	case ICE_VSI_SWITCHDEV_CTRL:
		tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ;
		break;
	default:
		return;
	}
@@ -479,6 +452,14 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
	/* Rx queue threshold in units of 64 */
	rlan_ctx.lrxqthresh = 1;

	/* PF acts as uplink for switchdev; set flex descriptor with src_vsi
	 * metadata and flags to allow redirecting to PR netdev
	 */
	if (ice_is_eswitch_mode_switchdev(vsi->back)) {
		ring->flags |= ICE_RX_FLAGS_MULTIDEV;
		rxdid = ICE_RXDID_FLEX_NIC_2;
	}

	/* Enable Flexible Descriptors in the queue context which
	 * allows this driver to select a specific receive descriptor format
	 * increasing context priority to pick up profile ID; default is 0x01;
@@ -919,14 +900,7 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
	/* Add unique software queue handle of the Tx queue per
	 * TC into the VSI Tx ring
	 */
	if (vsi->type == ICE_VSI_SWITCHDEV_CTRL) {
		ring->q_handle = ice_eswitch_calc_txq_handle(ring);

		if (ring->q_handle == ICE_INVAL_Q_INDEX)
			return -ENODEV;
	} else {
	ring->q_handle = ice_calc_txq_handle(vsi, ring, tc);
	}

	if (ch)
		status = ice_ena_vsi_txq(vsi->port_info, ch->ch_vsi->idx, 0,
+1 −3
Original line number Diff line number Diff line
@@ -291,7 +291,6 @@ static void ice_dcb_ena_dis_vsi(struct ice_pf *pf, bool ena, bool locked)

		switch (vsi->type) {
		case ICE_VSI_CHNL:
		case ICE_VSI_SWITCHDEV_CTRL:
		case ICE_VSI_PF:
			if (ena)
				ice_ena_vsi(vsi, locked);
@@ -776,8 +775,7 @@ void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked)
		/* no need to proceed with remaining cfg if it is CHNL
		 * or switchdev VSI
		 */
		if (vsi->type == ICE_VSI_CHNL ||
		    vsi->type == ICE_VSI_SWITCHDEV_CTRL)
		if (vsi->type == ICE_VSI_CHNL)
			continue;

		ice_vsi_map_rings_to_vectors(vsi);
+62 −300
Original line number Diff line number Diff line
@@ -10,85 +10,6 @@
#include "ice_devlink.h"
#include "ice_tc_lib.h"

/**
 * ice_eswitch_del_sp_rules - delete adv rules added on PRs
 * @pf: pointer to the PF struct
 *
 * Delete all advanced rules that were used to forward packets with the
 * device's VSI index to the corresponding eswitch ctrl VSI queue.
 */
static void ice_eswitch_del_sp_rules(struct ice_pf *pf)
{
	struct ice_repr *repr;
	unsigned long id;

	xa_for_each(&pf->eswitch.reprs, id, repr) {
		if (repr->sp_rule.rid)
			ice_rem_adv_rule_by_id(&pf->hw, &repr->sp_rule);
	}
}

/**
 * ice_eswitch_add_sp_rule - add adv rule with device's VSI index
 * @pf: pointer to PF struct
 * @repr: pointer to the repr struct
 *
 * This function adds advanced rule that forwards packets with
 * device's VSI index to the corresponding eswitch ctrl VSI queue.
 */
static int ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr)
{
	struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
	struct ice_adv_rule_info rule_info = { 0 };
	struct ice_adv_lkup_elem *list;
	struct ice_hw *hw = &pf->hw;
	const u16 lkups_cnt = 1;
	int err;

	list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
	if (!list)
		return -ENOMEM;

	ice_rule_add_src_vsi_metadata(list);

	rule_info.sw_act.flag = ICE_FLTR_TX;
	rule_info.sw_act.vsi_handle = ctrl_vsi->idx;
	rule_info.sw_act.fltr_act = ICE_FWD_TO_Q;
	rule_info.sw_act.fwd_id.q_id = hw->func_caps.common_cap.rxq_first_id +
				       ctrl_vsi->rxq_map[repr->q_id];
	rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE;
	rule_info.flags_info.act_valid = true;
	rule_info.tun_type = ICE_SW_TUN_AND_NON_TUN;
	rule_info.src_vsi = repr->src_vsi->idx;

	err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info,
			       &repr->sp_rule);
	if (err)
		dev_err(ice_pf_to_dev(pf), "Unable to add slow-path rule for eswitch for PR %d",
			repr->id);

	kfree(list);
	return err;
}

static int
ice_eswitch_add_sp_rules(struct ice_pf *pf)
{
	struct ice_repr *repr;
	unsigned long id;
	int err;

	xa_for_each(&pf->eswitch.reprs, id, repr) {
		err = ice_eswitch_add_sp_rule(pf, repr);
		if (err) {
			ice_eswitch_del_sp_rules(pf);
			return err;
		}
	}

	return 0;
}

/**
 * ice_eswitch_setup_env - configure eswitch HW filters
 * @pf: pointer to PF struct
@@ -99,10 +20,13 @@ ice_eswitch_add_sp_rules(struct ice_pf *pf)
static int ice_eswitch_setup_env(struct ice_pf *pf)
{
	struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi;
	struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
	struct net_device *netdev = uplink_vsi->netdev;
	bool if_running = netif_running(netdev);
	struct ice_vsi_vlan_ops *vlan_ops;
	bool rule_added = false;

	if (if_running && !test_and_set_bit(ICE_VSI_DOWN, uplink_vsi->state))
		if (ice_down(uplink_vsi))
			return -ENODEV;

	ice_remove_vsi_fltr(&pf->hw, uplink_vsi->idx);

@@ -112,98 +36,53 @@ static int ice_eswitch_setup_env(struct ice_pf *pf)
	netif_addr_unlock_bh(netdev);

	if (ice_vsi_add_vlan_zero(uplink_vsi))
		goto err_def_rx;
		goto err_vlan_zero;

	if (!ice_is_dflt_vsi_in_use(uplink_vsi->port_info)) {
		if (ice_set_dflt_vsi(uplink_vsi))
	if (ice_cfg_dflt_vsi(uplink_vsi->port_info, uplink_vsi->idx, true,
			     ICE_FLTR_RX))
		goto err_def_rx;
		rule_added = true;
	}

	if (ice_cfg_dflt_vsi(uplink_vsi->port_info, uplink_vsi->idx, true,
			     ICE_FLTR_TX))
		goto err_def_tx;

	vlan_ops = ice_get_compat_vsi_vlan_ops(uplink_vsi);
	if (vlan_ops->dis_rx_filtering(uplink_vsi))
		goto err_dis_rx;
		goto err_vlan_filtering;

	if (ice_vsi_update_security(uplink_vsi, ice_vsi_ctx_set_allow_override))
		goto err_override_uplink;

	if (ice_vsi_update_security(ctrl_vsi, ice_vsi_ctx_set_allow_override))
		goto err_override_control;

	if (ice_vsi_update_local_lb(uplink_vsi, true))
		goto err_override_local_lb;

	if (if_running && ice_up(uplink_vsi))
		goto err_up;

	return 0;

err_up:
	ice_vsi_update_local_lb(uplink_vsi, false);
err_override_local_lb:
	ice_vsi_update_security(ctrl_vsi, ice_vsi_ctx_clear_allow_override);
err_override_control:
	ice_vsi_update_security(uplink_vsi, ice_vsi_ctx_clear_allow_override);
err_override_uplink:
	vlan_ops->ena_rx_filtering(uplink_vsi);
err_dis_rx:
	if (rule_added)
		ice_clear_dflt_vsi(uplink_vsi);
err_vlan_filtering:
	ice_cfg_dflt_vsi(uplink_vsi->port_info, uplink_vsi->idx, false,
			 ICE_FLTR_TX);
err_def_tx:
	ice_cfg_dflt_vsi(uplink_vsi->port_info, uplink_vsi->idx, false,
			 ICE_FLTR_RX);
err_def_rx:
	ice_vsi_del_vlan_zero(uplink_vsi);
err_vlan_zero:
	ice_fltr_add_mac_and_broadcast(uplink_vsi,
				       uplink_vsi->port_info->mac.perm_addr,
				       ICE_FWD_TO_VSI);
	return -ENODEV;
}
	if (if_running)
		ice_up(uplink_vsi);

/**
 * ice_eswitch_remap_rings_to_vectors - reconfigure rings of eswitch ctrl VSI
 * @eswitch: pointer to eswitch struct
 *
 * In eswitch number of allocated Tx/Rx rings is equal.
 *
 * This function fills q_vectors structures associated with representor and
 * move each ring pairs to port representor netdevs. Each port representor
 * will have dedicated 1 Tx/Rx ring pair, so number of rings pair is equal to
 * number of VFs.
 */
static void ice_eswitch_remap_rings_to_vectors(struct ice_eswitch *eswitch)
{
	struct ice_vsi *vsi = eswitch->control_vsi;
	unsigned long repr_id = 0;
	int q_id;

	ice_for_each_txq(vsi, q_id) {
		struct ice_q_vector *q_vector;
		struct ice_tx_ring *tx_ring;
		struct ice_rx_ring *rx_ring;
		struct ice_repr *repr;

		repr = xa_find(&eswitch->reprs, &repr_id, U32_MAX,
			       XA_PRESENT);
		if (!repr)
			break;

		repr_id += 1;
		repr->q_id = q_id;
		q_vector = repr->q_vector;
		tx_ring = vsi->tx_rings[q_id];
		rx_ring = vsi->rx_rings[q_id];

		q_vector->vsi = vsi;
		q_vector->reg_idx = vsi->q_vectors[0]->reg_idx;

		q_vector->num_ring_tx = 1;
		q_vector->tx.tx_ring = tx_ring;
		tx_ring->q_vector = q_vector;
		tx_ring->next = NULL;
		tx_ring->netdev = repr->netdev;
		/* In switchdev mode, from OS stack perspective, there is only
		 * one queue for given netdev, so it needs to be indexed as 0.
		 */
		tx_ring->q_index = 0;

		q_vector->num_ring_rx = 1;
		q_vector->rx.rx_ring = rx_ring;
		rx_ring->q_vector = q_vector;
		rx_ring->next = NULL;
		rx_ring->netdev = repr->netdev;
	}
	return -ENODEV;
}

/**
@@ -225,8 +104,6 @@ ice_eswitch_release_repr(struct ice_pf *pf, struct ice_repr *repr)
	repr->dst = NULL;
	ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac,
				       ICE_FWD_TO_VSI);

	netif_napi_del(&repr->q_vector->napi);
}

/**
@@ -236,7 +113,7 @@ ice_eswitch_release_repr(struct ice_pf *pf, struct ice_repr *repr)
 */
static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr)
{
	struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
	struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi;
	struct ice_vsi *vsi = repr->src_vsi;
	struct metadata_dst *dst;

@@ -252,15 +129,11 @@ static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr)
	if (ice_vsi_add_vlan_zero(vsi))
		goto err_update_security;

	netif_napi_add(repr->netdev, &repr->q_vector->napi,
		       ice_napi_poll);

	netif_keep_dst(repr->netdev);
	netif_keep_dst(uplink_vsi->netdev);

	dst = repr->dst;
	dst->u.port_info.port_id = vsi->vsi_num;
	dst->u.port_info.lower_dev = repr->netdev;
	ice_repr_set_traffic_vsi(repr, ctrl_vsi);
	dst->u.port_info.lower_dev = uplink_vsi->netdev;

	return 0;

@@ -318,27 +191,19 @@ void ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi)
netdev_tx_t
ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
	struct ice_netdev_priv *np;
	struct ice_repr *repr;
	struct ice_vsi *vsi;

	np = netdev_priv(netdev);
	vsi = np->vsi;

	if (!vsi || !ice_is_switchdev_running(vsi->back))
		return NETDEV_TX_BUSY;

	if (ice_is_reset_in_progress(vsi->back->state) ||
	    test_bit(ICE_VF_DIS, vsi->back->state))
		return NETDEV_TX_BUSY;
	struct ice_repr *repr = ice_netdev_to_repr(netdev);
	unsigned int len = skb->len;
	int ret;

	repr = ice_netdev_to_repr(netdev);
	skb_dst_drop(skb);
	dst_hold((struct dst_entry *)repr->dst);
	skb_dst_set(skb, (struct dst_entry *)repr->dst);
	skb->queue_mapping = repr->q_id;
	skb->dev = repr->dst->u.port_info.lower_dev;

	ret = dev_queue_xmit(skb);
	ice_repr_inc_tx_stats(repr, len, ret);

	return ice_start_xmit(skb, netdev);
	return ret;
}

/**
@@ -374,13 +239,11 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb,
static void ice_eswitch_release_env(struct ice_pf *pf)
{
	struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi;
	struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
	struct ice_vsi_vlan_ops *vlan_ops;

	vlan_ops = ice_get_compat_vsi_vlan_ops(uplink_vsi);

	ice_vsi_update_local_lb(uplink_vsi, false);
	ice_vsi_update_security(ctrl_vsi, ice_vsi_ctx_clear_allow_override);
	ice_vsi_update_security(uplink_vsi, ice_vsi_ctx_clear_allow_override);
	vlan_ops->ena_rx_filtering(uplink_vsi);
	ice_clear_dflt_vsi(uplink_vsi);
@@ -389,56 +252,13 @@ static void ice_eswitch_release_env(struct ice_pf *pf)
				       ICE_FWD_TO_VSI);
}

/**
 * ice_eswitch_vsi_setup - configure eswitch control VSI
 * @pf: pointer to PF structure
 * @pi: pointer to port_info structure
 */
static struct ice_vsi *
ice_eswitch_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
{
	struct ice_vsi_cfg_params params = {};

	params.type = ICE_VSI_SWITCHDEV_CTRL;
	params.pi = pi;
	params.flags = ICE_VSI_FLAG_INIT;

	return ice_vsi_setup(pf, &params);
}

/**
 * ice_eswitch_napi_enable - enable NAPI for all port representors
 * @reprs: xarray of reprs
 */
static void ice_eswitch_napi_enable(struct xarray *reprs)
{
	struct ice_repr *repr;
	unsigned long id;

	xa_for_each(reprs, id, repr)
		napi_enable(&repr->q_vector->napi);
}

/**
 * ice_eswitch_napi_disable - disable NAPI for all port representors
 * @reprs: xarray of reprs
 */
static void ice_eswitch_napi_disable(struct xarray *reprs)
{
	struct ice_repr *repr;
	unsigned long id;

	xa_for_each(reprs, id, repr)
		napi_disable(&repr->q_vector->napi);
}

/**
 * ice_eswitch_enable_switchdev - configure eswitch in switchdev mode
 * @pf: pointer to PF structure
 */
static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
{
	struct ice_vsi *ctrl_vsi, *uplink_vsi;
	struct ice_vsi *uplink_vsi;

	uplink_vsi = ice_get_main_vsi(pf);
	if (!uplink_vsi)
@@ -450,17 +270,10 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
		return -EINVAL;
	}

	pf->eswitch.control_vsi = ice_eswitch_vsi_setup(pf, pf->hw.port_info);
	if (!pf->eswitch.control_vsi)
		return -ENODEV;

	ctrl_vsi = pf->eswitch.control_vsi;
	/* cp VSI is createad with 1 queue as default */
	pf->eswitch.qs.value = 1;
	pf->eswitch.uplink_vsi = uplink_vsi;

	if (ice_eswitch_setup_env(pf))
		goto err_vsi;
		return -ENODEV;

	if (ice_eswitch_br_offloads_init(pf))
		goto err_br_offloads;
@@ -471,8 +284,6 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)

err_br_offloads:
	ice_eswitch_release_env(pf);
err_vsi:
	ice_vsi_release(ctrl_vsi);
	return -ENODEV;
}

@@ -482,14 +293,10 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
 */
static void ice_eswitch_disable_switchdev(struct ice_pf *pf)
{
	struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;

	ice_eswitch_br_offloads_deinit(pf);
	ice_eswitch_release_env(pf);
	ice_vsi_release(ctrl_vsi);

	pf->eswitch.is_running = false;
	pf->eswitch.qs.is_reaching = false;
}

/**
@@ -530,7 +337,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode,

		dev_info(ice_pf_to_dev(pf), "PF %d changed eswitch mode to switchdev",
			 pf->hw.pf_id);
		xa_init_flags(&pf->eswitch.reprs, XA_FLAGS_ALLOC);
		xa_init(&pf->eswitch.reprs);
		NL_SET_ERR_MSG_MOD(extack, "Changed eswitch mode to switchdev");
		break;
	}
@@ -602,56 +409,18 @@ void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf)

static void ice_eswitch_stop_reprs(struct ice_pf *pf)
{
	ice_eswitch_del_sp_rules(pf);
	ice_eswitch_stop_all_tx_queues(pf);
	ice_eswitch_napi_disable(&pf->eswitch.reprs);
}

static void ice_eswitch_start_reprs(struct ice_pf *pf)
{
	ice_eswitch_napi_enable(&pf->eswitch.reprs);
	ice_eswitch_start_all_tx_queues(pf);
	ice_eswitch_add_sp_rules(pf);
}

static void
ice_eswitch_cp_change_queues(struct ice_eswitch *eswitch, int change)
{
	struct ice_vsi *cp = eswitch->control_vsi;
	int queues = 0;

	if (eswitch->qs.is_reaching) {
		if (eswitch->qs.to_reach >= eswitch->qs.value + change) {
			queues = eswitch->qs.to_reach;
			eswitch->qs.is_reaching = false;
		} else {
			queues = 0;
		}
	} else if ((change > 0 && cp->alloc_txq <= eswitch->qs.value) ||
		   change < 0) {
		queues = cp->alloc_txq + change;
	}

	if (queues) {
		cp->req_txq = queues;
		cp->req_rxq = queues;
		ice_vsi_close(cp);
		ice_vsi_rebuild(cp, ICE_VSI_FLAG_NO_INIT);
		ice_vsi_open(cp);
	} else if (!change) {
		/* change == 0 means that VSI wasn't open, open it here */
		ice_vsi_open(cp);
	}

	eswitch->qs.value += change;
	ice_eswitch_remap_rings_to_vectors(eswitch);
}

int
ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
{
	struct ice_repr *repr;
	int change = 1;
	int err;

	if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY)
@@ -661,9 +430,6 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
		err = ice_eswitch_enable_switchdev(pf);
		if (err)
			return err;
		/* Control plane VSI is created with 1 queue as default */
		pf->eswitch.qs.to_reach -= 1;
		change = 0;
	}

	ice_eswitch_stop_reprs(pf);
@@ -678,14 +444,12 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
	if (err)
		goto err_setup_repr;

	err = xa_alloc(&pf->eswitch.reprs, &repr->id, repr,
		       XA_LIMIT(1, INT_MAX), GFP_KERNEL);
	err = xa_insert(&pf->eswitch.reprs, repr->id, repr, GFP_KERNEL);
	if (err)
		goto err_xa_alloc;

	vf->repr_id = repr->id;

	ice_eswitch_cp_change_queues(&pf->eswitch, change);
	ice_eswitch_start_reprs(pf);

	return 0;
@@ -715,8 +479,6 @@ void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf)

	if (xa_empty(&pf->eswitch.reprs))
		ice_eswitch_disable_switchdev(pf);
	else
		ice_eswitch_cp_change_queues(&pf->eswitch, -1);

	ice_eswitch_release_repr(pf, repr);
	ice_repr_rem_vf(repr);
@@ -738,37 +500,37 @@ void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf)
 * ice_eswitch_rebuild - rebuild eswitch
 * @pf: pointer to PF structure
 */
int ice_eswitch_rebuild(struct ice_pf *pf)
void ice_eswitch_rebuild(struct ice_pf *pf)
{
	struct ice_repr *repr;
	unsigned long id;
	int err;

	if (!ice_is_switchdev_running(pf))
		return 0;

	err = ice_vsi_rebuild(pf->eswitch.control_vsi, ICE_VSI_FLAG_INIT);
	if (err)
		return err;
		return;

	xa_for_each(&pf->eswitch.reprs, id, repr)
		ice_eswitch_detach(pf, repr->vf);

	return 0;
}

/**
 * ice_eswitch_reserve_cp_queues - reserve control plane VSI queues
 * @pf: pointer to PF structure
 * @change: how many more (or less) queues is needed
 * ice_eswitch_get_target - get netdev based on src_vsi from descriptor
 * @rx_ring: ring used to receive the packet
 * @rx_desc: descriptor used to get src_vsi value
 *
 * Remember to call ice_eswitch_attach/detach() the "change" times.
 * Get src_vsi value from descriptor and load correct representor. If it isn't
 * found return rx_ring->netdev.
 */
void ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change)
struct net_device *ice_eswitch_get_target(struct ice_rx_ring *rx_ring,
					  union ice_32b_rx_flex_desc *rx_desc)
{
	if (pf->eswitch.qs.value + change < 0)
		return;
	struct ice_eswitch *eswitch = &rx_ring->vsi->back->eswitch;
	struct ice_32b_rx_flex_desc_nic_2 *desc;
	struct ice_repr *repr;

	desc = (struct ice_32b_rx_flex_desc_nic_2 *)rx_desc;
	repr = xa_load(&eswitch->reprs, le16_to_cpu(desc->src_vsi));
	if (!repr)
		return rx_ring->netdev;

	pf->eswitch.qs.to_reach = pf->eswitch.qs.value + change;
	pf->eswitch.qs.is_reaching = true;
	return repr->netdev;
}
+9 −4
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf);
int
ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf);
int ice_eswitch_rebuild(struct ice_pf *pf);
void ice_eswitch_rebuild(struct ice_pf *pf);

int ice_eswitch_mode_get(struct devlink *devlink, u16 *mode);
int
@@ -26,7 +26,8 @@ void ice_eswitch_set_target_vsi(struct sk_buff *skb,
				struct ice_tx_offload_params *off);
netdev_tx_t
ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev);
void ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change);
struct net_device *ice_eswitch_get_target(struct ice_rx_ring *rx_ring,
					  union ice_32b_rx_flex_desc *rx_desc);
#else /* CONFIG_ICE_SWITCHDEV */
static inline void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) { }

@@ -78,7 +79,11 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev)
	return NETDEV_TX_BUSY;
}

static inline void
ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change) { }
static inline struct net_device *
ice_eswitch_get_target(struct ice_rx_ring *rx_ring,
		       union ice_32b_rx_flex_desc *rx_desc)
{
	return rx_ring->netdev;
}
#endif /* CONFIG_ICE_SWITCHDEV */
#endif /* _ICE_ESWITCH_H_ */
Loading