|
@@ -334,7 +334,7 @@ static int ixgbe_ptp_settime(struct ptp_clock_info *ptp,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * ixgbe_ptp_enable
|
|
|
+ * ixgbe_ptp_feature_enable
|
|
|
* @ptp: the ptp clock structure
|
|
|
* @rq: the requested feature to change
|
|
|
* @on: whether to enable or disable the feature
|
|
@@ -342,8 +342,8 @@ static int ixgbe_ptp_settime(struct ptp_clock_info *ptp,
|
|
|
* enable (or disable) ancillary features of the phc subsystem.
|
|
|
* our driver only supports the PPS feature on the X540
|
|
|
*/
|
|
|
-static int ixgbe_ptp_enable(struct ptp_clock_info *ptp,
|
|
|
- struct ptp_clock_request *rq, int on)
|
|
|
+static int ixgbe_ptp_feature_enable(struct ptp_clock_info *ptp,
|
|
|
+ struct ptp_clock_request *rq, int on)
|
|
|
{
|
|
|
struct ixgbe_adapter *adapter =
|
|
|
container_of(ptp, struct ixgbe_adapter, ptp_caps);
|
|
@@ -570,9 +570,9 @@ int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * ixgbe_ptp_set_ts_config - control hardware time stamping
|
|
|
- * @adapter: pointer to adapter struct
|
|
|
- * @ifreq: ioctl data
|
|
|
+ * ixgbe_ptp_set_timestamp_mode - setup the hardware for the requested mode
|
|
|
+ * @adapter: the private ixgbe adapter structure
|
|
|
+ * @config: the hwtstamp configuration requested
|
|
|
*
|
|
|
* Outgoing time stamping can be enabled and disabled. Play nice and
|
|
|
* disable it when requested, although it shouldn't cause any overhead
|
|
@@ -590,25 +590,25 @@ int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
* packets, regardless of the type specified in the register, only use V2
|
|
|
* Event mode. This more accurately tells the user what the hardware is going
|
|
|
* to do anyways.
|
|
|
+ *
|
|
|
+ * Note: this may modify the hwtstamp configuration towards a more general
|
|
|
+ * mode, if required to support the specifically requested mode.
|
|
|
*/
|
|
|
-int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
+static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter,
|
|
|
+ struct hwtstamp_config *config)
|
|
|
{
|
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
- struct hwtstamp_config config;
|
|
|
u32 tsync_tx_ctl = IXGBE_TSYNCTXCTL_ENABLED;
|
|
|
u32 tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED;
|
|
|
u32 tsync_rx_mtrl = PTP_EV_PORT << 16;
|
|
|
bool is_l2 = false;
|
|
|
u32 regval;
|
|
|
|
|
|
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
/* reserved for future extensions */
|
|
|
- if (config.flags)
|
|
|
+ if (config->flags)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- switch (config.tx_type) {
|
|
|
+ switch (config->tx_type) {
|
|
|
case HWTSTAMP_TX_OFF:
|
|
|
tsync_tx_ctl = 0;
|
|
|
case HWTSTAMP_TX_ON:
|
|
@@ -617,7 +617,7 @@ int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
return -ERANGE;
|
|
|
}
|
|
|
|
|
|
- switch (config.rx_filter) {
|
|
|
+ switch (config->rx_filter) {
|
|
|
case HWTSTAMP_FILTER_NONE:
|
|
|
tsync_rx_ctl = 0;
|
|
|
tsync_rx_mtrl = 0;
|
|
@@ -641,7 +641,7 @@ int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
|
|
|
tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2;
|
|
|
is_l2 = true;
|
|
|
- config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
|
|
+ config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
|
|
break;
|
|
|
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
|
|
|
case HWTSTAMP_FILTER_ALL:
|
|
@@ -652,7 +652,7 @@ int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
* Delay_Req messages and hardware does not support
|
|
|
* timestamping all packets => return error
|
|
|
*/
|
|
|
- config.rx_filter = HWTSTAMP_FILTER_NONE;
|
|
|
+ config->rx_filter = HWTSTAMP_FILTER_NONE;
|
|
|
return -ERANGE;
|
|
|
}
|
|
|
|
|
@@ -671,7 +671,6 @@ int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
else
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588), 0);
|
|
|
|
|
|
-
|
|
|
/* enable/disable TX */
|
|
|
regval = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
|
|
|
regval &= ~IXGBE_TSYNCTXCTL_ENABLED;
|
|
@@ -693,6 +692,29 @@ int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH);
|
|
|
regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_ptp_set_ts_config - user entry point for timestamp mode
|
|
|
+ * @adapter: pointer to adapter struct
|
|
|
+ * @ifreq: ioctl data
|
|
|
+ *
|
|
|
+ * Set hardware to requested mode. If unsupported, return an error with no
|
|
|
+ * changes. Otherwise, store the mode for future reference.
|
|
|
+ */
|
|
|
+int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
|
|
|
+{
|
|
|
+ struct hwtstamp_config config;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ err = ixgbe_ptp_set_timestamp_mode(adapter, &config);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
/* save these settings for future reference */
|
|
|
memcpy(&adapter->tstamp_config, &config,
|
|
|
sizeof(adapter->tstamp_config));
|
|
@@ -790,9 +812,13 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
|
|
|
* ixgbe_ptp_reset
|
|
|
* @adapter: the ixgbe private board structure
|
|
|
*
|
|
|
- * When the MAC resets, all timesync features are reset. This function should be
|
|
|
- * called to re-enable the PTP clock structure. It will re-init the timecounter
|
|
|
- * structure based on the kernel time as well as setup the cycle counter data.
|
|
|
+ * When the MAC resets, all the hardware bits for timesync are reset. This
|
|
|
+ * function is used to re-enable the device for PTP based on current settings.
|
|
|
+ * We do lose the current clock time, so just reset the cyclecounter to the
|
|
|
+ * system real clock time.
|
|
|
+ *
|
|
|
+ * This function will maintain hwtstamp_config settings, and resets the SDP
|
|
|
+ * output if it was enabled.
|
|
|
*/
|
|
|
void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
@@ -804,8 +830,8 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000);
|
|
|
IXGBE_WRITE_FLUSH(hw);
|
|
|
|
|
|
- /* Reset the saved tstamp_config */
|
|
|
- memset(&adapter->tstamp_config, 0, sizeof(adapter->tstamp_config));
|
|
|
+ /* reset the hardware timestamping mode */
|
|
|
+ ixgbe_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
|
|
|
|
|
|
ixgbe_ptp_start_cyclecounter(adapter);
|
|
|
|
|
@@ -825,16 +851,23 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * ixgbe_ptp_init
|
|
|
+ * ixgbe_ptp_create_clock
|
|
|
* @adapter: the ixgbe private adapter structure
|
|
|
*
|
|
|
- * This function performs the required steps for enabling ptp
|
|
|
- * support. If ptp support has already been loaded it simply calls the
|
|
|
- * cyclecounter init routine and exits.
|
|
|
+ * This function performs setup of the user entry point function table and
|
|
|
+ * initializes the PTP clock device, which is used to access the clock-like
|
|
|
+ * features of the PTP core. It will be called by ixgbe_ptp_init, only if
|
|
|
+ * there isn't already a clock device (such as after a suspend/resume cycle,
|
|
|
+ * where the clock device wasn't destroyed).
|
|
|
*/
|
|
|
-void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
|
|
|
+static int ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
|
struct net_device *netdev = adapter->netdev;
|
|
|
+ long err;
|
|
|
+
|
|
|
+ /* do nothing if we already have a clock device */
|
|
|
+ if (!IS_ERR_OR_NULL(adapter->ptp_clock))
|
|
|
+ return 0;
|
|
|
|
|
|
switch (adapter->hw.mac.type) {
|
|
|
case ixgbe_mac_X540:
|
|
@@ -851,7 +884,7 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
|
|
|
adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
|
|
|
adapter->ptp_caps.gettime = ixgbe_ptp_gettime;
|
|
|
adapter->ptp_caps.settime = ixgbe_ptp_settime;
|
|
|
- adapter->ptp_caps.enable = ixgbe_ptp_enable;
|
|
|
+ adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
|
|
|
break;
|
|
|
case ixgbe_mac_82599EB:
|
|
|
snprintf(adapter->ptp_caps.name,
|
|
@@ -867,24 +900,57 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
|
|
|
adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
|
|
|
adapter->ptp_caps.gettime = ixgbe_ptp_gettime;
|
|
|
adapter->ptp_caps.settime = ixgbe_ptp_settime;
|
|
|
- adapter->ptp_caps.enable = ixgbe_ptp_enable;
|
|
|
+ adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
|
|
|
break;
|
|
|
default:
|
|
|
adapter->ptp_clock = NULL;
|
|
|
- return;
|
|
|
+ return -EOPNOTSUPP;
|
|
|
}
|
|
|
|
|
|
- spin_lock_init(&adapter->tmreg_lock);
|
|
|
- INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work);
|
|
|
-
|
|
|
adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
|
|
|
&adapter->pdev->dev);
|
|
|
if (IS_ERR(adapter->ptp_clock)) {
|
|
|
+ err = PTR_ERR(adapter->ptp_clock);
|
|
|
adapter->ptp_clock = NULL;
|
|
|
e_dev_err("ptp_clock_register failed\n");
|
|
|
+ return err;
|
|
|
} else
|
|
|
e_dev_info("registered PHC device on %s\n", netdev->name);
|
|
|
|
|
|
+ /* set default timestamp mode to disabled here. We do this in
|
|
|
+ * create_clock instead of init, because we don't want to override the
|
|
|
+ * previous settings during a resume cycle.
|
|
|
+ */
|
|
|
+ adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
|
|
+ adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_ptp_init
|
|
|
+ * @adapter: the ixgbe private adapter structure
|
|
|
+ *
|
|
|
+ * This function performs the required steps for enabling PTP
|
|
|
+ * support. If PTP support has already been loaded it simply calls the
|
|
|
+ * cyclecounter init routine and exits.
|
|
|
+ */
|
|
|
+void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ /* initialize the spin lock first since we can't control when a user
|
|
|
+ * will call the entry functions once we have initialized the clock
|
|
|
+ * device
|
|
|
+ */
|
|
|
+ spin_lock_init(&adapter->tmreg_lock);
|
|
|
+
|
|
|
+ /* obtain a PTP device, or re-use an existing device */
|
|
|
+ if (ixgbe_ptp_create_clock(adapter))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* we have a clock so we can initialize work now */
|
|
|
+ INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work);
|
|
|
+
|
|
|
+ /* reset the PTP related hardware bits */
|
|
|
ixgbe_ptp_reset(adapter);
|
|
|
|
|
|
/* enter the IXGBE_PTP_RUNNING state */
|
|
@@ -894,28 +960,45 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * ixgbe_ptp_stop - disable ptp device and stop the overflow check
|
|
|
- * @adapter: pointer to adapter struct
|
|
|
+ * ixgbe_ptp_suspend - stop PTP work items
|
|
|
+ * @ adapter: pointer to adapter struct
|
|
|
*
|
|
|
- * this function stops the ptp support, and cancels the delayed work.
|
|
|
+ * this function suspends PTP activity, and prevents more PTP work from being
|
|
|
+ * generated, but does not destroy the PTP clock device.
|
|
|
*/
|
|
|
-void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
|
|
|
+void ixgbe_ptp_suspend(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
|
/* Leave the IXGBE_PTP_RUNNING state. */
|
|
|
if (!test_and_clear_bit(__IXGBE_PTP_RUNNING, &adapter->state))
|
|
|
return;
|
|
|
|
|
|
- /* stop the PPS signal */
|
|
|
- adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED;
|
|
|
- ixgbe_ptp_setup_sdp(adapter);
|
|
|
+ /* since this might be called in suspend, we don't clear the state,
|
|
|
+ * but simply reset the auxiliary PPS signal control register
|
|
|
+ */
|
|
|
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_TSAUXC, 0x0);
|
|
|
|
|
|
+ /* ensure that we cancel any pending PTP Tx work item in progress */
|
|
|
cancel_work_sync(&adapter->ptp_tx_work);
|
|
|
if (adapter->ptp_tx_skb) {
|
|
|
dev_kfree_skb_any(adapter->ptp_tx_skb);
|
|
|
adapter->ptp_tx_skb = NULL;
|
|
|
clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_ptp_stop - close the PTP device
|
|
|
+ * @adapter: pointer to adapter struct
|
|
|
+ *
|
|
|
+ * completely destroy the PTP device, should only be called when the device is
|
|
|
+ * being fully closed.
|
|
|
+ */
|
|
|
+void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ /* first, suspend PTP activity */
|
|
|
+ ixgbe_ptp_suspend(adapter);
|
|
|
|
|
|
+ /* disable the PTP clock device */
|
|
|
if (adapter->ptp_clock) {
|
|
|
ptp_clock_unregister(adapter->ptp_clock);
|
|
|
adapter->ptp_clock = NULL;
|