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

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 1f22cf13 ea52faae
...@@ -980,7 +980,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw, ...@@ -980,7 +980,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
default: default:
/* if we got here and link is up something bad is afoot */ /* if we got here and link is up something bad is afoot */
netdev_info(netdev, 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); hw_link_info->phy_type);
} }
...@@ -5294,6 +5294,10 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) ...@@ -5294,6 +5294,10 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
dev_warn(&pf->pdev->dev, dev_warn(&pf->pdev->dev,
"Device configuration forbids SW from starting the LLDP agent.\n"); "Device configuration forbids SW from starting the LLDP agent.\n");
return -EINVAL; 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: default:
dev_warn(&pf->pdev->dev, dev_warn(&pf->pdev->dev,
"Starting FW LLDP agent failed: error: %s, %s\n", "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, ...@@ -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 * @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; struct i40e_pf *pf = vsi->back;
int i, pf_q, ret = 0; int i, pf_q, ret = 0;
...@@ -4467,7 +4466,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) ...@@ -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++) { for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
ret = i40e_control_wait_tx_q(vsi->seid, pf, ret = i40e_control_wait_tx_q(vsi->seid, pf,
pf_q, pf_q,
false /*is xdp*/, enable); false /*is xdp*/, true);
if (ret) if (ret)
break; break;
...@@ -4476,7 +4475,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) ...@@ -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, ret = i40e_control_wait_tx_q(vsi->seid, pf,
pf_q + vsi->alloc_queue_pairs, pf_q + vsi->alloc_queue_pairs,
true /*is xdp*/, enable); true /*is xdp*/, true);
if (ret) if (ret)
break; break;
} }
...@@ -4574,32 +4573,25 @@ int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable) ...@@ -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 * @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; struct i40e_pf *pf = vsi->back;
int i, pf_q, ret = 0; int i, pf_q, ret = 0;
pf_q = vsi->base_queue; pf_q = vsi->base_queue;
for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { 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) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"VSI seid %d Rx ring %d %sable timeout\n", "VSI seid %d Rx ring %d enable timeout\n",
vsi->seid, pf_q, (enable ? "en" : "dis")); vsi->seid, pf_q);
break; 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; return ret;
} }
...@@ -4612,29 +4604,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi) ...@@ -4612,29 +4604,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
int ret = 0; int ret = 0;
/* do rx first for enable and last for disable */ /* do rx first for enable and last for disable */
ret = i40e_vsi_control_rx(vsi, true); ret = i40e_vsi_enable_rx(vsi);
if (ret) if (ret)
return ret; return ret;
ret = i40e_vsi_control_tx(vsi, true); ret = i40e_vsi_enable_tx(vsi);
return ret; return ret;
} }
#define I40E_DISABLE_TX_GAP_MSEC 50
/** /**
* i40e_vsi_stop_rings - Stop a VSI's rings * i40e_vsi_stop_rings - Stop a VSI's rings
* @vsi: the VSI being configured * @vsi: the VSI being configured
**/ **/
void i40e_vsi_stop_rings(struct i40e_vsi *vsi) 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 */ /* When port TX is suspended, don't wait */
if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state)) if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
return i40e_vsi_stop_rings_no_wait(vsi); return i40e_vsi_stop_rings_no_wait(vsi);
/* do rx first for enable and last for disable q_end = vsi->base_queue + vsi->num_queue_pairs;
* Ignore return value, we need to shutdown whatever we can for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
*/ i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);
i40e_vsi_control_tx(vsi, false);
i40e_vsi_control_rx(vsi, 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, ...@@ -7280,6 +7290,8 @@ static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
} }
if (vsi->num_queue_pairs < if (vsi->num_queue_pairs <
(mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) { (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; return -EINVAL;
} }
if (sum_max_rate > i40e_get_link_speed(vsi)) { if (sum_max_rate > i40e_get_link_speed(vsi)) {
...@@ -13261,6 +13273,7 @@ static const struct net_device_ops i40e_netdev_ops = { ...@@ -13261,6 +13273,7 @@ static const struct net_device_ops i40e_netdev_ops = {
.ndo_poll_controller = i40e_netpoll, .ndo_poll_controller = i40e_netpoll,
#endif #endif
.ndo_setup_tc = __i40e_setup_tc, .ndo_setup_tc = __i40e_setup_tc,
.ndo_select_queue = i40e_lan_select_queue,
.ndo_set_features = i40e_set_features, .ndo_set_features = i40e_set_features,
.ndo_set_vf_mac = i40e_ndo_set_vf_mac, .ndo_set_vf_mac = i40e_ndo_set_vf_mac,
.ndo_set_vf_vlan = i40e_ndo_set_vf_port_vlan, .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, ...@@ -3631,6 +3631,56 @@ static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
return -1; 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 * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring
* @xdpf: data to transmit * @xdpf: data to transmit
......
...@@ -451,6 +451,8 @@ static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring) ...@@ -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); 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); 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_tx_ring(struct i40e_ring *tx_ring);
void i40e_clean_rx_ring(struct i40e_ring *rx_ring); void i40e_clean_rx_ring(struct i40e_ring *rx_ring);
int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring); int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment