i40e: only create PTP device node once
authorJacob Keller <jacob.e.keller@intel.com>
Wed, 4 Jun 2014 04:22:45 +0000 (04:22 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 26 Jun 2014 11:45:00 +0000 (04:45 -0700)
Currently every time we run through the i40e_ptp_init routine, we create
a new device node. This function is called by i40e_reset_and_rebuild
which is used to handle reset of the device. Even though the 1588
registers only get cleared on a GLOBAL reset, this function is still
called to handle a CORE reset.

This causes a leak of PTP device nodes at every reset. To fix this,
break PTP device clock node creation out of i40e_ptp_init, and only call
this if we don't already have a device created. Further invocation of
i40e_ptp_init will not generate new PTP devices. Instead, only the
necessary work required to reconfigure 1588 will be done.

This change also fixes an issue where a reset can cause the
device to forget it's timestamp configuration, and revert to the default
mode.

Change-ID: I741d01c61d9fe1d24887859d1316e1a8a892909e
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_ptp.c

index f7dded9976e97bcb37fbe2944323d1934e97ebf4..0c935e8f3a6cf57dada9a987d86c96543a86a2bd 100644 (file)
@@ -567,18 +567,22 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
 }
 
 /**
- * i40e_ptp_init - Initialize the 1588 support and register the PHC
+ * i40e_ptp_create_clock - Create PTP clock device for userspace
  * @pf: Board private structure
  *
- * This function registers the device clock as a PHC. If it is successful, it
- * starts the clock in the hardware.
+ * This function creates a new PTP clock device. It only creates one if we
+ * don't already have one, so it is safe to call. Will return error if it
+ * can't create one, but success if we already have a device. Should be used
+ * by i40e_ptp_init to create clock initially, and prevent global resets from
+ * creating new clock devices.
  **/
-void i40e_ptp_init(struct i40e_pf *pf)
+static long i40e_ptp_create_clock(struct i40e_pf *pf)
 {
-       struct i40e_hw *hw = &pf->hw;
-       struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev;
+       /* no need to create a clock device if we already have one */
+       if (!IS_ERR_OR_NULL(pf->ptp_clock))
+               return 0;
 
-       strncpy(pf->ptp_caps.name, "i40e", sizeof(pf->ptp_caps.name));
+       strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name));
        pf->ptp_caps.owner = THIS_MODULE;
        pf->ptp_caps.max_adj = 999999999;
        pf->ptp_caps.n_ext_ts = 0;
@@ -592,6 +596,41 @@ void i40e_ptp_init(struct i40e_pf *pf)
        /* Attempt to register the clock before enabling the hardware. */
        pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev);
        if (IS_ERR(pf->ptp_clock)) {
+               return PTR_ERR(pf->ptp_clock);
+       }
+
+       /* clear the hwtstamp settings here during clock create, instead of
+        * during regular init, so that we can maintain settings across a
+        * reset or suspend.
+        */
+       pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+       pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
+
+       return 0;
+}
+
+/**
+ * i40e_ptp_init - Initialize the 1588 support after device probe or reset
+ * @pf: Board private structure
+ *
+ * This function sets device up for 1588 support. The first time it is run, it
+ * will create a PHC clock device. It does not create a clock device if one
+ * already exists. It also reconfigures the device after a reset.
+ **/
+void i40e_ptp_init(struct i40e_pf *pf)
+{
+       struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev;
+       struct i40e_hw *hw = &pf->hw;
+       long err;
+
+       /* we have to initialize the lock first, since we can't control
+        * when the user will enter the PHC device entry points
+        */
+       spin_lock_init(&pf->tmreg_lock);
+
+       /* ensure we have a clock device */
+       err = i40e_ptp_create_clock(pf);
+       if (err) {
                pf->ptp_clock = NULL;
                dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n",
                        __func__);
@@ -599,15 +638,10 @@ void i40e_ptp_init(struct i40e_pf *pf)
                struct timespec ts;
                u32 regval;
 
-               spin_lock_init(&pf->tmreg_lock);
-
                dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__,
                         netdev->name);
                pf->flags |= I40E_FLAG_PTP;
 
-               pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
-               pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
-
                /* Ensure the clocks are running. */
                regval = rd32(hw, I40E_PRTTSYN_CTL0);
                regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK;