Merge branch 'hns3-fixes'

Huazhong Tan says:

====================
net: hns3: fixes for -net

This patchset includes misc fixes for the HNS3 ethernet driver.

[patch 1/3] fixes a TX queue not restarted problem.

[patch 2/3] fixes a use-after-free issue.

[patch 3/3] fixes a VF ID issue for setting VF VLAN.

change log:
V1->V2: keeps 'ring' as parameter in hns3_nic_maybe_stop_tx()
	in [patch 1/3], suggestted by David.
	rewrites [patch 2/3]'s commit log to make it be easier
	to understand, suggestted by David.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-12-05 14:42:43 -08:00
commit a116f4e238
2 changed files with 32 additions and 36 deletions

View File

@ -1287,30 +1287,25 @@ static bool hns3_skb_need_linearized(struct sk_buff *skb, unsigned int *bd_size,
}
static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
struct sk_buff **out_skb)
struct net_device *netdev,
struct sk_buff *skb)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
unsigned int bd_size[HNS3_MAX_TSO_BD_NUM + 1U];
struct sk_buff *skb = *out_skb;
unsigned int bd_num;
bd_num = hns3_tx_bd_num(skb, bd_size);
if (unlikely(bd_num > HNS3_MAX_NON_TSO_BD_NUM)) {
struct sk_buff *new_skb;
if (bd_num <= HNS3_MAX_TSO_BD_NUM && skb_is_gso(skb) &&
!hns3_skb_need_linearized(skb, bd_size, bd_num))
goto out;
/* manual split the send packet */
new_skb = skb_copy(skb, GFP_ATOMIC);
if (!new_skb)
if (__skb_linearize(skb))
return -ENOMEM;
dev_kfree_skb_any(skb);
*out_skb = new_skb;
bd_num = hns3_tx_bd_count(new_skb->len);
if ((skb_is_gso(new_skb) && bd_num > HNS3_MAX_TSO_BD_NUM) ||
(!skb_is_gso(new_skb) &&
bd_num = hns3_tx_bd_count(skb->len);
if ((skb_is_gso(skb) && bd_num > HNS3_MAX_TSO_BD_NUM) ||
(!skb_is_gso(skb) &&
bd_num > HNS3_MAX_NON_TSO_BD_NUM))
return -ENOMEM;
@ -1320,10 +1315,23 @@ static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
}
out:
if (unlikely(ring_space(ring) < bd_num))
return -EBUSY;
if (likely(ring_space(ring) >= bd_num))
return bd_num;
return bd_num;
netif_stop_subqueue(netdev, ring->queue_index);
smp_mb(); /* Memory barrier before checking ring_space */
/* Start queue in case hns3_clean_tx_ring has just made room
* available and has not seen the queue stopped state performed
* by netif_stop_subqueue above.
*/
if (ring_space(ring) >= bd_num && netif_carrier_ok(netdev) &&
!test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) {
netif_start_subqueue(netdev, ring->queue_index);
return bd_num;
}
return -EBUSY;
}
static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
@ -1400,13 +1408,13 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Prefetch the data used later */
prefetch(skb->data);
ret = hns3_nic_maybe_stop_tx(ring, &skb);
ret = hns3_nic_maybe_stop_tx(ring, netdev, skb);
if (unlikely(ret <= 0)) {
if (ret == -EBUSY) {
u64_stats_update_begin(&ring->syncp);
ring->stats.tx_busy++;
u64_stats_update_end(&ring->syncp);
goto out_net_tx_busy;
return NETDEV_TX_BUSY;
} else if (ret == -ENOMEM) {
u64_stats_update_begin(&ring->syncp);
ring->stats.sw_err_cnt++;
@ -1457,12 +1465,6 @@ fill_err:
out_err_tx_ok:
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
out_net_tx_busy:
netif_stop_subqueue(netdev, ring->queue_index);
smp_mb(); /* Commit all data before submit */
return NETDEV_TX_BUSY;
}
static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p)
@ -2519,7 +2521,7 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring)
dev_queue = netdev_get_tx_queue(netdev, ring->tqp->tqp_index);
netdev_tx_completed_queue(dev_queue, pkts, bytes);
if (unlikely(pkts && netif_carrier_ok(netdev) &&
if (unlikely(netif_carrier_ok(netdev) &&
ring_space(ring) > HNS3_MAX_TSO_BD_NUM)) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.

View File

@ -8438,13 +8438,16 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
if (hdev->pdev->revision == 0x20)
return -EOPNOTSUPP;
vport = hclge_get_vf_vport(hdev, vfid);
if (!vport)
return -EINVAL;
/* qos is a 3 bits value, so can not be bigger than 7 */
if (vfid >= hdev->num_alloc_vfs || vlan > VLAN_N_VID - 1 || qos > 7)
if (vlan > VLAN_N_VID - 1 || qos > 7)
return -EINVAL;
if (proto != htons(ETH_P_8021Q))
return -EPROTONOSUPPORT;
vport = &hdev->vport[vfid];
state = hclge_get_port_base_vlan_state(vport,
vport->port_base_vlan_cfg.state,
vlan);
@ -8455,21 +8458,12 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
vlan_info.qos = qos;
vlan_info.vlan_proto = ntohs(proto);
/* update port based VLAN for PF */
if (!vfid) {
hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
ret = hclge_update_port_base_vlan_cfg(vport, state, &vlan_info);
hclge_notify_client(hdev, HNAE3_UP_CLIENT);
return ret;
}
if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) {
return hclge_update_port_base_vlan_cfg(vport, state,
&vlan_info);
} else {
ret = hclge_push_vf_port_base_vlan_info(&hdev->vport[0],
(u8)vfid, state,
vport->vport_id, state,
vlan, qos,
ntohs(proto));
return ret;