From 2c2d06d5126e62e90aee71da9b85c9d95de6bbe2 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 24 Apr 2013 01:44:58 +0000 Subject: bnx2x: prevent GRO false checksum claims This patch introduces a more robust error handling flow in case of incorrect behaviour by the FW when passing on GRO aggregations. Although this should never happen (i.e., this is merely a theoretical fix), if the bnx2x driver was to receive a GRO from FW with protocol other than IPv4/IPv6, the driver would falsely claim to have performed partial checksum and set various incorrect fields in the skb header. Current behaviour of the bnx2x driver (i.e., print an error) is insufficient. This patch remedies this by simply preventing the false claims. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index d72bd8c40aa1..5a815ce7dee0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -642,6 +642,14 @@ static void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb) th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), &iph->saddr, &iph->daddr, 0); } + +static void bnx2x_gro_csum(struct bnx2x *bp, struct sk_buff *skb, + void (*gro_func)(struct bnx2x*, struct sk_buff*)) +{ + skb_set_network_header(skb, 0); + gro_func(bp, skb); + tcp_gro_complete(skb); +} #endif static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp, @@ -649,19 +657,17 @@ static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp, { #ifdef CONFIG_INET if (skb_shinfo(skb)->gso_size) { - skb_set_network_header(skb, 0); switch (be16_to_cpu(skb->protocol)) { case ETH_P_IP: - bnx2x_gro_ip_csum(bp, skb); + bnx2x_gro_csum(bp, skb, bnx2x_gro_ip_csum); break; case ETH_P_IPV6: - bnx2x_gro_ipv6_csum(bp, skb); + bnx2x_gro_csum(bp, skb, bnx2x_gro_ipv6_csum); break; default: - BNX2X_ERR("FW GRO supports only IPv4/IPv6, not 0x%04x\n", + BNX2X_ERR("Error: FW GRO supports only IPv4/IPv6, not 0x%04x\n", be16_to_cpu(skb->protocol)); } - tcp_gro_complete(skb); } #endif napi_gro_receive(&fp->napi, skb); -- cgit v1.2.1 From ba35a0fd1ff7b5e91a6eee145e56887edffa194c Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 24 Apr 2013 01:44:59 +0000 Subject: bnx2x: Allow RX/TX pause control in autoneg Currently, when link is configured to auto-negotiate the flow control, disabling RX/TX pause via ethtool doesn't work. This fixes the behaviour, advertising asymmetric pause in case either one is exclusively enabled. Signed-off-by: Yaniv Rosner Signed-off-by: Yuval Mintz Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 5 ++++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 88e9b47a3eb6..397537bb4448 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1889,12 +1889,15 @@ static int bnx2x_set_pauseparam(struct net_device *dev, bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO; } - bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_NONE; + bp->link_params.req_fc_auto_adv = 0; if (epause->rx_pause) bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_RX; if (epause->tx_pause) bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_TX; + + if (!bp->link_params.req_fc_auto_adv) + bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_NONE; } DP(BNX2X_MSG_ETHTOOL, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 40f58d73de78..9d64b988ab34 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -3426,13 +3426,19 @@ static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, switch (phy->req_flow_ctrl) { case BNX2X_FLOW_CTRL_AUTO: - if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) + switch (params->req_fc_auto_adv) { + case BNX2X_FLOW_CTRL_BOTH: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - else + break; + case BNX2X_FLOW_CTRL_RX: + case BNX2X_FLOW_CTRL_TX: *ieee_fc |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + default: + break; + } break; - case BNX2X_FLOW_CTRL_TX: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; break; -- cgit v1.2.1 From f8f4f61a5a358841c5acf144f6fa13a6b475ec2c Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 24 Apr 2013 01:45:00 +0000 Subject: bnx2x: Enhance MAC configuration for VFs Improved support for adding/removing vf mac addresses. This includes the case where HyperVisor forced the address (sampled from bulletin board), and the case where it did not in which the VF can configure its own mac address. Signed-off-by: Dmitry Kravkov Signed-off-by: Ariel Elior Signed-off-by: Yuval Mintz Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 18 +++++++++++------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 5 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 19 ++++++++++++++----- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 5a815ce7dee0..e8ed78f64007 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2664,7 +2664,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) if (IS_PF(bp)) rc = bnx2x_set_eth_mac(bp, true); else /* vf */ - rc = bnx2x_vfpf_set_mac(bp); + rc = bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, bp->fp->index, + true); if (rc) { BNX2X_ERR("Setting Ethernet MAC failed\n"); LOAD_ERROR_EXIT(bp, load_error3); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 86d13870399e..a46bc720b992 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -7930,8 +7930,6 @@ int bnx2x_del_all_macs(struct bnx2x *bp, int bnx2x_set_eth_mac(struct bnx2x *bp, bool set) { - unsigned long ramrod_flags = 0; - if (is_zero_ether_addr(bp->dev->dev_addr) && (IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp))) { DP(NETIF_MSG_IFUP | NETIF_MSG_IFDOWN, @@ -7939,12 +7937,18 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set) return 0; } - DP(NETIF_MSG_IFUP, "Adding Eth MAC\n"); + if (IS_PF(bp)) { + unsigned long ramrod_flags = 0; - __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); - /* Eth MAC is set on RSS leading client (fp[0]) */ - return bnx2x_set_mac_one(bp, bp->dev->dev_addr, &bp->sp_objs->mac_obj, - set, BNX2X_ETH_MAC, &ramrod_flags); + DP(NETIF_MSG_IFUP, "Adding Eth MAC\n"); + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + return bnx2x_set_mac_one(bp, bp->dev->dev_addr, + &bp->sp_objs->mac_obj, set, + BNX2X_ETH_MAC, &ramrod_flags); + } else { /* vf */ + return bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, + bp->fp->index, true); + } } int bnx2x_setup_leading(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index d4b17b7a774e..d67ddc554c0f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -733,7 +733,7 @@ int bnx2x_vfpf_init(struct bnx2x *bp); void bnx2x_vfpf_close_vf(struct bnx2x *bp); int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx); int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx); -int bnx2x_vfpf_set_mac(struct bnx2x *bp); +int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set); int bnx2x_vfpf_set_mcast(struct net_device *dev); int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp); @@ -794,7 +794,8 @@ static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; } static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {} static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) {return 0; } static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; } -static inline int bnx2x_vfpf_set_mac(struct bnx2x *bp) {return 0; } +static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, + u8 vf_qid, bool set) {return 0; } static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; } static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; } static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 90fbf9cc2c2c..928b074d7d80 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -406,6 +406,9 @@ void bnx2x_vfpf_close_vf(struct bnx2x *bp) for_each_queue(bp, i) bnx2x_vfpf_teardown_queue(bp, i); + /* remove mac */ + bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, bp->fp->index, false); + /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req)); @@ -561,10 +564,11 @@ out: } /* request pf to add a mac for the vf */ -int bnx2x_vfpf_set_mac(struct bnx2x *bp) +int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set) { struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; + struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content; int rc = 0; /* clear mailbox and prep first tlv */ @@ -572,16 +576,18 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp) sizeof(*req)); req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED; - req->vf_qid = 0; + req->vf_qid = vf_qid; req->n_mac_vlan_filters = 1; - req->filters[0].flags = - VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC; + + req->filters[0].flags = VFPF_Q_FILTER_DEST_MAC_VALID; + if (set) + req->filters[0].flags |= VFPF_Q_FILTER_SET_MAC; /* sample bulletin board for new mac */ bnx2x_sample_bulletin(bp); /* copy mac from device to request */ - memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN); + memcpy(req->filters[0].mac, addr, ETH_ALEN); /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, @@ -602,6 +608,9 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp) DP(BNX2X_MSG_IOV, "vfpf SET MAC failed. Check bulletin board for new posts\n"); + /* copy mac from bulletin to device */ + memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN); + /* check if bulletin board was updated */ if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) { /* copy mac from device to request */ -- cgit v1.2.1 From 2f7a312230e0d24e8913e7eff7b24d34b7092fcd Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 24 Apr 2013 01:45:01 +0000 Subject: bnx2x: Fix memory leak There exists an `allocation race' between the CNIC and bnx2x drivers, in which both drivers allocate the same t2 memory while disregarding a possible previous allocation. Additionally, due to the current order of memory releases, some of the ILT memory in the driver is not released correctly when unloading the driver. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e8ed78f64007..fd20a4ff0150 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2934,9 +2934,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) bnx2x_free_fp_mem_cnic(bp); if (IS_PF(bp)) { - bnx2x_free_mem(bp); if (CNIC_LOADED(bp)) bnx2x_free_mem_cnic(bp); + bnx2x_free_mem(bp); } bp->state = BNX2X_STATE_CLOSED; bp->cnic_loaded = false; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index a46bc720b992..dedf68377e74 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -7786,7 +7786,7 @@ int bnx2x_alloc_mem_cnic(struct bnx2x *bp) sizeof(struct host_hc_status_block_e1x)); - if (CONFIGURE_NIC_MODE(bp)) + if (CONFIGURE_NIC_MODE(bp) && !bp->t2) /* allocate searcher T2 table, as it wan't allocated before */ BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ); @@ -7809,7 +7809,7 @@ int bnx2x_alloc_mem(struct bnx2x *bp) { int i, allocated, context_size; - if (!CONFIGURE_NIC_MODE(bp)) + if (!CONFIGURE_NIC_MODE(bp) && !bp->t2) /* allocate searcher T2 table */ BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ); -- cgit v1.2.1 From 70632d0afe749c44562c1112eea0839774bcf578 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 24 Apr 2013 01:45:02 +0000 Subject: bnx2x: Allow recovery from second slot reset As part of PCIe Advanced Error Reporting flow, if a fatal PCI error occurs, the AER driver will cause bnx2x's PCI-core to reset. The driver's PCI error handlers will in turn restore the PCI configuration space values by calling `pci_restore_state'. However, as bnx2x does not save the PCI configuration after restoration, An additional fatal PCI error will leave the function in an unstable state until reboot, as the registers in the PCI configuration space will contain reset values. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index dedf68377e74..fbfff1b3365e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12807,6 +12807,7 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); + pci_save_state(pdev); if (netif_running(dev)) bnx2x_set_power_state(bp, PCI_D0); -- cgit v1.2.1