Message ID | 20190207124422.21952-2-gpiccoli@canonical.com |
---|---|
State | New |
Headers | show |
Series | qlcnic: Firmware aborts/hangs in QLogic NIC | expand |
On 07.02.19 13:44, Guilherme G. Piccoli wrote: > From: Shahed Shaikh <shahed.shaikh@cavium.com> > > BugLink: http://bugs.launchpad.net/bugs/1815033 > > 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> > (cherry picked from commit c333fa0c4f220f8f7ea5acd6b0ebf3bf13fd684d) > Signed-off-by: Guilherme G. Piccoli <gpiccoli@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> > --- In Xenial and Cosmic already. > 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(-) > > diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h > index 81312924df14..0c443ea98479 100644 > --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h > +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h > @@ -1800,7 +1800,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 *); > @@ -2064,9 +2065,10 @@ static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, > } > > 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) > diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c > index 46b0372dd032..1fc84d8f891b 100644 > --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c > +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c > @@ -2134,7 +2134,8 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, > } > > 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); > diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h > index b75a81246856..73fe2f64491d 100644 > --- 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 qlcnic_adapter *, ulong, u32); > 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); > diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h > index 4bb33af8e2b3..56a3bd9e37dc 100644 > --- 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_adapter *adapter, > 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 *); > diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c > index 84dd83031a1b..9647578cbe6a 100644 > --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c > +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c > @@ -268,13 +268,12 @@ static void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, > } > > 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; > > @@ -301,7 +300,8 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, > > 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); > @@ -335,7 +335,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, > 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; > } > @@ -350,7 +350,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, > 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); > @@ -766,7 +766,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) > } > > 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++; >
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 81312924df14..0c443ea98479 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1800,7 +1800,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 *); @@ -2064,9 +2065,10 @@ static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, } 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) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 46b0372dd032..1fc84d8f891b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -2134,7 +2134,8 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, } 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); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index b75a81246856..73fe2f64491d 100644 --- 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 qlcnic_adapter *, ulong, u32); 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); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 4bb33af8e2b3..56a3bd9e37dc 100644 --- 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_adapter *adapter, 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 *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 84dd83031a1b..9647578cbe6a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -268,13 +268,12 @@ static void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, } 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; @@ -301,7 +300,8 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, 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); @@ -335,7 +335,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, 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; } @@ -350,7 +350,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, 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); @@ -766,7 +766,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } 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++;