mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0506c93fba
4 changed files with 94 additions and 25 deletions
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue