i40e: fix bug in return from get_link_status and avoid spurious link messages
authorJesse Brandeburg <jesse.brandeburg@intel.com>
Wed, 26 Aug 2015 19:14:19 +0000 (15:14 -0400)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 7 Oct 2015 21:23:09 +0000 (14:23 -0700)
Previously, the driver could call this function and have only true/false
returned, but false could mean multiple things like failure to read
or link was down. This change allows the caller to get all return values
in the call chain bubbled back to the source, which keeps information about
failures from being lost.

Also, in some unlikely scenarios, the firmware can become slow to respond
to admin queue (AQ) queries for link state.  Should the AQ time out,
the driver can detect the state and avoid a link change when there
may have been none.

Change-ID: Ib2ac38407b7880750fb891b392fa77457fe6c21c
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h

index 7a70abcafbbb5644f549cdba3a2f1c1950caa2eb..2839ea53234d3699e9e1f602a96599b579bf4fc5 100644 (file)
@@ -2235,27 +2235,28 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
 /**
  * i40e_get_link_status - get status of the HW network link
  * @hw: pointer to the hw struct
+ * @link_up: pointer to bool (true/false = linkup/linkdown)
  *
- * Returns true if link is up, false if link is down.
+ * Variable link_up true if link is up, false if link is down.
+ * The variable link_up is invalid if returned value of status != 0
  *
  * Side effect: LinkStatusEvent reporting becomes enabled
  **/
-bool i40e_get_link_status(struct i40e_hw *hw)
+i40e_status i40e_get_link_status(struct i40e_hw *hw, bool *link_up)
 {
        i40e_status status = 0;
-       bool link_status = false;
 
        if (hw->phy.get_link_info) {
                status = i40e_aq_get_link_info(hw, true, NULL, NULL);
 
                if (status)
-                       goto i40e_get_link_status_exit;
+                       i40e_debug(hw, I40E_DEBUG_LINK, "get link failed: status %d\n",
+                                  status);
        }
 
-       link_status = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
+       *link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
 
-i40e_get_link_status_exit:
-       return link_status;
+       return status;
 }
 
 /**
index 930369c4882b63fe1085c304d1839bb20fe173c5..1fa38f6e0e194fc46511f0b297b020cf309bcd75 100644 (file)
@@ -1516,9 +1516,18 @@ static int i40e_link_test(struct net_device *netdev, u64 *data)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_pf *pf = np->vsi->back;
+       i40e_status status;
+       bool link_up = false;
 
        netif_info(pf, hw, netdev, "link test\n");
-       if (i40e_get_link_status(&pf->hw))
+       status = i40e_get_link_status(&pf->hw, &link_up);
+       if (status) {
+               netif_err(pf, drv, netdev, "link query timed out, please retry test\n");
+               *data = 1;
+               return *data;
+       }
+
+       if (link_up)
                *data = 0;
        else
                *data = 1;
index 1fa1ebab9e92016dca33e00a84fdae850fecbbf0..f205e18a8530deb6c150d253d12499b60d86752d 100644 (file)
@@ -5836,15 +5836,23 @@ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up)
  **/
 static void i40e_link_event(struct i40e_pf *pf)
 {
-       bool new_link, old_link;
        struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        u8 new_link_speed, old_link_speed;
+       i40e_status status;
+       bool new_link, old_link;
 
        /* set this to force the get_link_status call to refresh state */
        pf->hw.phy.get_link_info = true;
 
        old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
-       new_link = i40e_get_link_status(&pf->hw);
+
+       status = i40e_get_link_status(&pf->hw, &new_link);
+       if (status) {
+               dev_dbg(&pf->pdev->dev, "couldn't get link state, status: %d\n",
+                       status);
+               return;
+       }
+
        old_link_speed = pf->hw.phy.link_info_old.link_speed;
        new_link_speed = pf->hw.phy.link_info.link_speed;
 
index dcb72a8ee8e590dfa390b43691cdbb3b39b9933d..e51e1567837c76f85591879e64b3bfa0cfd562f0 100644 (file)
@@ -258,7 +258,7 @@ i40e_status i40e_init_shared_code(struct i40e_hw *hw);
 i40e_status i40e_pf_reset(struct i40e_hw *hw);
 void i40e_clear_hw(struct i40e_hw *hw);
 void i40e_clear_pxe_mode(struct i40e_hw *hw);
-bool i40e_get_link_status(struct i40e_hw *hw);
+i40e_status i40e_get_link_status(struct i40e_hw *hw, bool *link_up);
 i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
 i40e_status i40e_read_bw_from_alt_ram(struct i40e_hw *hw,
                                      u32 *max_bw, u32 *min_bw, bool *min_valid,