i40e: rtnl_lock in reset path fixes
authorAnjali Singhai Jain <anjali.singhai@intel.com>
Tue, 26 Nov 2013 10:49:22 +0000 (10:49 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Mon, 16 Dec 2013 09:07:31 +0000 (01:07 -0800)
Any user-initiated path which eventually calls reset needs
to hold the rtnl_lock, so add functionality to do that.

Be careful not to use the safe reset when cleaning up
from the diagnostic tests, which avoids rtnl_lock
recursion from ethtool.

Protect the reset_task with rtnl_lock, since it runs from a work item.

Change-Id: Ib6e7a3fb2966809db2daf35fd5a123ccdf6f6f0f
Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_main.c

index eb1a3aa2c67cd099d08f07c1eb36664f103996a8..24a47ee43098d2ae652d6982bdd71251dd50e001 100644 (file)
@@ -502,6 +502,7 @@ int i40e_up(struct i40e_vsi *vsi);
 void i40e_down(struct i40e_vsi *vsi);
 extern const char i40e_driver_name[];
 extern const char i40e_driver_version_str[];
+void i40e_do_reset_safe(struct i40e_pf *pf, u32 reset_flags);
 void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags);
 void i40e_update_stats(struct i40e_vsi *vsi);
 void i40e_update_eth_stats(struct i40e_vsi *vsi);
index 9c675b5f1466cfa0446eec8d65b5419c2276ab5e..9a59dda6b5ce20b5b16b943eda7e8d06ce46f849 100644 (file)
@@ -1462,19 +1462,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                }
        } else if (strncmp(cmd_buf, "pfr", 3) == 0) {
                dev_info(&pf->pdev->dev, "forcing PFR\n");
-               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+               i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "corer", 5) == 0) {
                dev_info(&pf->pdev->dev, "forcing CoreR\n");
-               i40e_do_reset(pf, (1 << __I40E_CORE_RESET_REQUESTED));
+               i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "globr", 5) == 0) {
                dev_info(&pf->pdev->dev, "forcing GlobR\n");
-               i40e_do_reset(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED));
+               i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "empr", 4) == 0) {
                dev_info(&pf->pdev->dev, "forcing EMPR\n");
-               i40e_do_reset(pf, (1 << __I40E_EMP_RESET_REQUESTED));
+               i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "read", 4) == 0) {
                u32 address;
index 73c9a20694a9edeb0951517e1421aab7a9cea070..19ad3c02a7d01ae488e2f6360446fb1c99fdab1a 100644 (file)
@@ -4131,6 +4131,19 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
        }
 }
 
+/**
+ * i40e_do_reset_safe - Protected reset path for userland calls.
+ * @pf: board private structure
+ * @reset_flags: which reset is requested
+ *
+ **/
+void i40e_do_reset_safe(struct i40e_pf *pf, u32 reset_flags)
+{
+       rtnl_lock();
+       i40e_do_reset(pf, reset_flags);
+       rtnl_unlock();
+}
+
 /**
  * i40e_handle_lan_overflow_event - Handler for LAN queue overflow event
  * @pf: board private structure
@@ -4376,6 +4389,7 @@ static void i40e_reset_subtask(struct i40e_pf *pf)
 {
        u32 reset_flags = 0;
 
+       rtnl_lock();
        if (test_bit(__I40E_REINIT_REQUESTED, &pf->state)) {
                reset_flags |= (1 << __I40E_REINIT_REQUESTED);
                clear_bit(__I40E_REINIT_REQUESTED, &pf->state);
@@ -4398,7 +4412,7 @@ static void i40e_reset_subtask(struct i40e_pf *pf)
         */
        if (test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state)) {
                i40e_handle_reset_warning(pf);
-               return;
+               goto unlock;
        }
 
        /* If we're already down or resetting, just bail */
@@ -4406,6 +4420,9 @@ static void i40e_reset_subtask(struct i40e_pf *pf)
            !test_bit(__I40E_DOWN, &pf->state) &&
            !test_bit(__I40E_CONFIG_BUSY, &pf->state))
                i40e_do_reset(pf, reset_flags);
+
+unlock:
+       rtnl_unlock();
 }
 
 /**