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


Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2021-07-23

This series contains updates to i40e driver only.

Arkadiusz corrects the order of calls for disabling queues to resolve
a false error message and adds a better message to the user when
transitioning FW LLDP back on while the firmware is still processing
the off request.

Lukasz adds additional information regarding possible incorrect cable
use when a PHY type error occurs.

Jedrzej adds ndo_select_queue support to resolve incorrect queue
selection when SW DCB is used and adds a warning when there are not
enough queues for desired TC configuration.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1f22cf13 ea52faae
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -980,7 +980,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
	default:
		/* if we got here and link is up something bad is afoot */
		netdev_info(netdev,
			    "WARNING: Link is up but PHY type 0x%x is not recognized.\n",
			    "WARNING: Link is up but PHY type 0x%x is not recognized, or incorrect cable is in use\n",
			    hw_link_info->phy_type);
	}

@@ -5294,6 +5294,10 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
					dev_warn(&pf->pdev->dev,
						 "Device configuration forbids SW from starting the LLDP agent.\n");
					return -EINVAL;
				case I40E_AQ_RC_EAGAIN:
					dev_warn(&pf->pdev->dev,
						 "Stop FW LLDP agent command is still being processed, please try again in a second.\n");
					return -EBUSY;
				default:
					dev_warn(&pf->pdev->dev,
						 "Starting FW LLDP agent failed: error: %s, %s\n",
+37 −24
Original line number Diff line number Diff line
@@ -4454,11 +4454,10 @@ int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q,
}

/**
 * i40e_vsi_control_tx - Start or stop a VSI's rings
 * i40e_vsi_enable_tx - Start a VSI's rings
 * @vsi: the VSI being configured
 * @enable: start or stop the rings
 **/
static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
static int i40e_vsi_enable_tx(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	int i, pf_q, ret = 0;
@@ -4467,7 +4466,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
		ret = i40e_control_wait_tx_q(vsi->seid, pf,
					     pf_q,
					     false /*is xdp*/, enable);
					     false /*is xdp*/, true);
		if (ret)
			break;

@@ -4476,7 +4475,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)

		ret = i40e_control_wait_tx_q(vsi->seid, pf,
					     pf_q + vsi->alloc_queue_pairs,
					     true /*is xdp*/, enable);
					     true /*is xdp*/, true);
		if (ret)
			break;
	}
@@ -4574,32 +4573,25 @@ int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
}

/**
 * i40e_vsi_control_rx - Start or stop a VSI's rings
 * i40e_vsi_enable_rx - Start a VSI's rings
 * @vsi: the VSI being configured
 * @enable: start or stop the rings
 **/
static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
static int i40e_vsi_enable_rx(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	int i, pf_q, ret = 0;

	pf_q = vsi->base_queue;
	for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
		ret = i40e_control_wait_rx_q(pf, pf_q, enable);
		ret = i40e_control_wait_rx_q(pf, pf_q, true);
		if (ret) {
			dev_info(&pf->pdev->dev,
				 "VSI seid %d Rx ring %d %sable timeout\n",
				 vsi->seid, pf_q, (enable ? "en" : "dis"));
				 "VSI seid %d Rx ring %d enable timeout\n",
				 vsi->seid, pf_q);
			break;
		}
	}

	/* Due to HW errata, on Rx disable only, the register can indicate done
	 * before it really is. Needs 50ms to be sure
	 */
	if (!enable)
		mdelay(50);

	return ret;
}

@@ -4612,29 +4604,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
	int ret = 0;

	/* do rx first for enable and last for disable */
	ret = i40e_vsi_control_rx(vsi, true);
	ret = i40e_vsi_enable_rx(vsi);
	if (ret)
		return ret;
	ret = i40e_vsi_control_tx(vsi, true);
	ret = i40e_vsi_enable_tx(vsi);

	return ret;
}

#define I40E_DISABLE_TX_GAP_MSEC	50

/**
 * i40e_vsi_stop_rings - Stop a VSI's rings
 * @vsi: the VSI being configured
 **/
void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
{
	struct i40e_pf *pf = vsi->back;
	int pf_q, err, q_end;

	/* When port TX is suspended, don't wait */
	if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
		return i40e_vsi_stop_rings_no_wait(vsi);

	/* do rx first for enable and last for disable
	 * Ignore return value, we need to shutdown whatever we can
	 */
	i40e_vsi_control_tx(vsi, false);
	i40e_vsi_control_rx(vsi, false);
	q_end = vsi->base_queue + vsi->num_queue_pairs;
	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
		i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);

	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) {
		err = i40e_control_wait_rx_q(pf, pf_q, false);
		if (err)
			dev_info(&pf->pdev->dev,
				 "VSI seid %d Rx ring %d dissable timeout\n",
				 vsi->seid, pf_q);
	}

	msleep(I40E_DISABLE_TX_GAP_MSEC);
	pf_q = vsi->base_queue;
	for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
		wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0);

	i40e_vsi_wait_queues_disabled(vsi);
}

/**
@@ -7280,6 +7290,8 @@ static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
	}
	if (vsi->num_queue_pairs <
	    (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) {
		dev_err(&vsi->back->pdev->dev,
			"Failed to create traffic channel, insufficient number of queues.\n");
		return -EINVAL;
	}
	if (sum_max_rate > i40e_get_link_speed(vsi)) {
@@ -13261,6 +13273,7 @@ static const struct net_device_ops i40e_netdev_ops = {
	.ndo_poll_controller	= i40e_netpoll,
#endif
	.ndo_setup_tc		= __i40e_setup_tc,
	.ndo_select_queue	= i40e_lan_select_queue,
	.ndo_set_features	= i40e_set_features,
	.ndo_set_vf_mac		= i40e_ndo_set_vf_mac,
	.ndo_set_vf_vlan	= i40e_ndo_set_vf_port_vlan,
+50 −0
Original line number Diff line number Diff line
@@ -3631,6 +3631,56 @@ static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
	return -1;
}

static u16 i40e_swdcb_skb_tx_hash(struct net_device *dev,
				  const struct sk_buff *skb,
				  u16 num_tx_queues)
{
	u32 jhash_initval_salt = 0xd631614b;
	u32 hash;

	if (skb->sk && skb->sk->sk_hash)
		hash = skb->sk->sk_hash;
	else
		hash = (__force u16)skb->protocol ^ skb->hash;

	hash = jhash_1word(hash, jhash_initval_salt);

	return (u16)(((u64)hash * num_tx_queues) >> 32);
}

u16 i40e_lan_select_queue(struct net_device *netdev,
			  struct sk_buff *skb,
			  struct net_device __always_unused *sb_dev)
{
	struct i40e_netdev_priv *np = netdev_priv(netdev);
	struct i40e_vsi *vsi = np->vsi;
	struct i40e_hw *hw;
	u16 qoffset;
	u16 qcount;
	u8 tclass;
	u16 hash;
	u8 prio;

	/* is DCB enabled at all? */
	if (vsi->tc_config.numtc == 1)
		return i40e_swdcb_skb_tx_hash(netdev, skb,
					      netdev->real_num_tx_queues);

	prio = skb->priority;
	hw = &vsi->back->hw;
	tclass = hw->local_dcbx_config.etscfg.prioritytable[prio];
	/* sanity check */
	if (unlikely(!(vsi->tc_config.enabled_tc & BIT(tclass))))
		tclass = 0;

	/* select a queue assigned for the given TC */
	qcount = vsi->tc_config.tc_info[tclass].qcount;
	hash = i40e_swdcb_skb_tx_hash(netdev, skb, qcount);

	qoffset = vsi->tc_config.tc_info[tclass].qoffset;
	return qoffset + hash;
}

/**
 * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring
 * @xdpf: data to transmit
+2 −0
Original line number Diff line number Diff line
@@ -451,6 +451,8 @@ static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring)

bool i40e_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
u16 i40e_lan_select_queue(struct net_device *netdev, struct sk_buff *skb,
			  struct net_device *sb_dev);
void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
void i40e_clean_rx_ring(struct i40e_ring *rx_ring);
int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring);