| From foo@baz Tue Oct 16 16:47:53 CEST 2018 |
| From: Shahed Shaikh <shahed.shaikh@cavium.com> |
| Date: Wed, 26 Sep 2018 12:41:10 -0700 |
| Subject: qlcnic: fix Tx descriptor corruption on 82xx devices |
| |
| From: Shahed Shaikh <shahed.shaikh@cavium.com> |
| |
| [ Upstream commit c333fa0c4f220f8f7ea5acd6b0ebf3bf13fd684d ] |
| |
| In regular NIC transmission flow, driver always configures MAC using |
| Tx queue zero descriptor as a part of MAC learning flow. |
| But with multi Tx queue supported NIC, regular transmission can occur on |
| any non-zero Tx queue and from that context it uses |
| Tx queue zero descriptor to configure MAC, at the same time TX queue |
| zero could be used by another CPU for regular transmission |
| which could lead to Tx queue zero descriptor corruption and cause FW |
| abort. |
| |
| This patch fixes this in such a way that driver always configures |
| learned MAC address from the same Tx queue which is used for |
| regular transmission. |
| |
| Fixes: 7e2cf4feba05 ("qlcnic: change driver hardware interface mechanism") |
| Signed-off-by: Shahed Shaikh <shahed.shaikh@cavium.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 8 +++++--- |
| drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 3 ++- |
| drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 3 ++- |
| drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 3 ++- |
| drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 12 ++++++------ |
| 5 files changed, 17 insertions(+), 12 deletions(-) |
| |
| --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h |
| +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h |
| @@ -1802,7 +1802,8 @@ struct qlcnic_hardware_ops { |
| int (*config_loopback) (struct qlcnic_adapter *, u8); |
| int (*clear_loopback) (struct qlcnic_adapter *, u8); |
| int (*config_promisc_mode) (struct qlcnic_adapter *, u32); |
| - void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16); |
| + void (*change_l2_filter)(struct qlcnic_adapter *adapter, u64 *addr, |
| + u16 vlan, struct qlcnic_host_tx_ring *tx_ring); |
| int (*get_board_info) (struct qlcnic_adapter *); |
| void (*set_mac_filter_count) (struct qlcnic_adapter *); |
| void (*free_mac_list) (struct qlcnic_adapter *); |
| @@ -2044,9 +2045,10 @@ static inline int qlcnic_nic_set_promisc |
| } |
| |
| static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter, |
| - u64 *addr, u16 id) |
| + u64 *addr, u16 vlan, |
| + struct qlcnic_host_tx_ring *tx_ring) |
| { |
| - adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id); |
| + adapter->ahw->hw_ops->change_l2_filter(adapter, addr, vlan, tx_ring); |
| } |
| |
| static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter) |
| --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c |
| +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c |
| @@ -2132,7 +2132,8 @@ out: |
| } |
| |
| void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr, |
| - u16 vlan_id) |
| + u16 vlan_id, |
| + struct qlcnic_host_tx_ring *tx_ring) |
| { |
| u8 mac[ETH_ALEN]; |
| memcpy(&mac, addr, ETH_ALEN); |
| --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h |
| +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h |
| @@ -550,7 +550,8 @@ int qlcnic_83xx_wrt_reg_indirect(struct |
| int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32); |
| int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int); |
| int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int); |
| -void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16); |
| +void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr, |
| + u16 vlan, struct qlcnic_host_tx_ring *ring); |
| int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *); |
| int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); |
| void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *, int); |
| --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h |
| +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h |
| @@ -173,7 +173,8 @@ int qlcnic_82xx_napi_add(struct qlcnic_a |
| struct net_device *netdev); |
| void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *); |
| void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, |
| - u64 *uaddr, u16 vlan_id); |
| + u64 *uaddr, u16 vlan_id, |
| + struct qlcnic_host_tx_ring *tx_ring); |
| int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *, |
| struct ethtool_coalesce *); |
| int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *); |
| --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c |
| +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c |
| @@ -269,13 +269,12 @@ static void qlcnic_add_lb_filter(struct |
| } |
| |
| void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, |
| - u16 vlan_id) |
| + u16 vlan_id, struct qlcnic_host_tx_ring *tx_ring) |
| { |
| struct cmd_desc_type0 *hwdesc; |
| struct qlcnic_nic_req *req; |
| struct qlcnic_mac_req *mac_req; |
| struct qlcnic_vlan_req *vlan_req; |
| - struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; |
| u32 producer; |
| u64 word; |
| |
| @@ -302,7 +301,8 @@ void qlcnic_82xx_change_filter(struct ql |
| |
| static void qlcnic_send_filter(struct qlcnic_adapter *adapter, |
| struct cmd_desc_type0 *first_desc, |
| - struct sk_buff *skb) |
| + struct sk_buff *skb, |
| + struct qlcnic_host_tx_ring *tx_ring) |
| { |
| struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); |
| struct ethhdr *phdr = (struct ethhdr *)(skb->data); |
| @@ -336,7 +336,7 @@ static void qlcnic_send_filter(struct ql |
| tmp_fil->vlan_id == vlan_id) { |
| if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime)) |
| qlcnic_change_filter(adapter, &src_addr, |
| - vlan_id); |
| + vlan_id, tx_ring); |
| tmp_fil->ftime = jiffies; |
| return; |
| } |
| @@ -351,7 +351,7 @@ static void qlcnic_send_filter(struct ql |
| if (!fil) |
| return; |
| |
| - qlcnic_change_filter(adapter, &src_addr, vlan_id); |
| + qlcnic_change_filter(adapter, &src_addr, vlan_id, tx_ring); |
| fil->ftime = jiffies; |
| fil->vlan_id = vlan_id; |
| memcpy(fil->faddr, &src_addr, ETH_ALEN); |
| @@ -767,7 +767,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_ |
| } |
| |
| if (adapter->drv_mac_learn) |
| - qlcnic_send_filter(adapter, first_desc, skb); |
| + qlcnic_send_filter(adapter, first_desc, skb, tx_ring); |
| |
| tx_ring->tx_stats.tx_bytes += skb->len; |
| tx_ring->tx_stats.xmit_called++; |