|
@@ -105,6 +105,94 @@ static struct sock_filter ptp_filter[] = {
|
|
|
PTP_FILTER
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * ixgbe_ptp_enable_sdp
|
|
|
+ * @hw: the hardware private structure
|
|
|
+ * @shift: the clock shift for calculating nanoseconds
|
|
|
+ *
|
|
|
+ * this function enables the clock out feature on the sdp0 for the
|
|
|
+ * X540 device. It will create a 1second periodic output that can be
|
|
|
+ * used as the PPS (via an interrupt).
|
|
|
+ *
|
|
|
+ * It calculates when the systime will be on an exact second, and then
|
|
|
+ * aligns the start of the PPS signal to that value. The shift is
|
|
|
+ * necessary because it can change based on the link speed.
|
|
|
+ */
|
|
|
+static void ixgbe_ptp_enable_sdp(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ int shift = adapter->cc.shift;
|
|
|
+ u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh, rem;
|
|
|
+ u64 ns = 0, clock_edge = 0;
|
|
|
+
|
|
|
+ switch (hw->mac.type) {
|
|
|
+ case ixgbe_mac_X540:
|
|
|
+ esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * enable the SDP0 pin as output, and connected to the native
|
|
|
+ * function for Timesync (ClockOut)
|
|
|
+ */
|
|
|
+ esdp |= (IXGBE_ESDP_SDP0_DIR |
|
|
|
+ IXGBE_ESDP_SDP0_NATIVE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * enable the Clock Out feature on SDP0, and allow interrupts
|
|
|
+ * to occur when the pin changes
|
|
|
+ */
|
|
|
+ tsauxc = (IXGBE_TSAUXC_EN_CLK |
|
|
|
+ IXGBE_TSAUXC_SYNCLK |
|
|
|
+ IXGBE_TSAUXC_SDP0_INT);
|
|
|
+
|
|
|
+ /* clock period (or pulse length) */
|
|
|
+ clktiml = (u32)(NSECS_PER_SEC << shift);
|
|
|
+ clktimh = (u32)((NSECS_PER_SEC << shift) >> 32);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Account for the cyclecounter wrap-around value by
|
|
|
+ * using the converted ns value of the current time to
|
|
|
+ * check for when the next aligned second would occur.
|
|
|
+ */
|
|
|
+ clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
|
|
|
+ clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
|
|
|
+ ns = timecounter_cyc2time(&adapter->tc, clock_edge);
|
|
|
+
|
|
|
+ div_u64_rem(ns, NSECS_PER_SEC, &rem);
|
|
|
+ clock_edge += ((NSECS_PER_SEC - (u64)rem) << shift);
|
|
|
+
|
|
|
+ /* specify the initial clock start time */
|
|
|
+ trgttiml = (u32)clock_edge;
|
|
|
+ trgttimh = (u32)(clock_edge >> 32);
|
|
|
+
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
|
|
|
+
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
|
|
|
+
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_TIMESYNC);
|
|
|
+ IXGBE_WRITE_FLUSH(hw);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_ptp_disable_sdp
|
|
|
+ * @hw: the private hardware structure
|
|
|
+ *
|
|
|
+ * this function disables the auxiliary SDP clock out feature
|
|
|
+ */
|
|
|
+static void ixgbe_ptp_disable_sdp(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_TIMESYNC);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0);
|
|
|
+ IXGBE_WRITE_FLUSH(hw);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ixgbe_ptp_read - read raw cycle counter (to be used by time counter)
|
|
|
* @cc: the cyclecounter structure
|
|
@@ -187,6 +275,7 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
|
unsigned long flags;
|
|
|
u64 now;
|
|
|
|
|
|
+ ixgbe_ptp_disable_sdp(&adapter->hw);
|
|
|
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
|
|
|
|
|
now = timecounter_read(&adapter->tc);
|
|
@@ -198,6 +287,8 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
|
now);
|
|
|
|
|
|
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
|
|
+ ixgbe_ptp_enable_sdp(adapter);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -246,11 +337,14 @@ static int ixgbe_ptp_settime(struct ptp_clock_info *ptp,
|
|
|
ns = ts->tv_sec * 1000000000ULL;
|
|
|
ns += ts->tv_nsec;
|
|
|
|
|
|
+ ixgbe_ptp_disable_sdp(&adapter->hw);
|
|
|
+
|
|
|
/* reset the timecounter */
|
|
|
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
|
|
timecounter_init(&adapter->tc, &adapter->cc, ns);
|
|
|
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
|
|
|
|
|
+ ixgbe_ptp_enable_sdp(adapter);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -323,91 +417,6 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * ixgbe_ptp_enable_sdp
|
|
|
- * @hw: the hardware private structure
|
|
|
- * @shift: the clock shift for calculating nanoseconds
|
|
|
- *
|
|
|
- * this function enables the clock out feature on the sdp0 for the
|
|
|
- * X540 device. It will create a 1second periodic output that can be
|
|
|
- * used as the PPS (via an interrupt).
|
|
|
- *
|
|
|
- * It calculates when the systime will be on an exact second, and then
|
|
|
- * aligns the start of the PPS signal to that value. The shift is
|
|
|
- * necessary because it can change based on the link speed.
|
|
|
- */
|
|
|
-static void ixgbe_ptp_enable_sdp(struct ixgbe_hw *hw, int shift)
|
|
|
-{
|
|
|
- u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh;
|
|
|
- u64 clock_edge = 0;
|
|
|
- u32 rem;
|
|
|
-
|
|
|
- switch (hw->mac.type) {
|
|
|
- case ixgbe_mac_X540:
|
|
|
- esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
|
|
|
-
|
|
|
- /*
|
|
|
- * enable the SDP0 pin as output, and connected to the native
|
|
|
- * function for Timesync (ClockOut)
|
|
|
- */
|
|
|
- esdp |= (IXGBE_ESDP_SDP0_DIR |
|
|
|
- IXGBE_ESDP_SDP0_NATIVE);
|
|
|
-
|
|
|
- /*
|
|
|
- * enable the Clock Out feature on SDP0, and allow interrupts
|
|
|
- * to occur when the pin changes
|
|
|
- */
|
|
|
- tsauxc = (IXGBE_TSAUXC_EN_CLK |
|
|
|
- IXGBE_TSAUXC_SYNCLK |
|
|
|
- IXGBE_TSAUXC_SDP0_INT);
|
|
|
-
|
|
|
- /* clock period (or pulse length) */
|
|
|
- clktiml = (u32)(NSECS_PER_SEC << shift);
|
|
|
- clktimh = (u32)((NSECS_PER_SEC << shift) >> 32);
|
|
|
-
|
|
|
- clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
|
|
|
- clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
|
|
|
-
|
|
|
- /*
|
|
|
- * account for the fact that we can't do u64 division
|
|
|
- * with remainder, by converting the clock values into
|
|
|
- * nanoseconds first
|
|
|
- */
|
|
|
- clock_edge >>= shift;
|
|
|
- div_u64_rem(clock_edge, NSECS_PER_SEC, &rem);
|
|
|
- clock_edge += (NSECS_PER_SEC - rem);
|
|
|
- clock_edge <<= shift;
|
|
|
-
|
|
|
- /* specify the initial clock start time */
|
|
|
- trgttiml = (u32)clock_edge;
|
|
|
- trgttimh = (u32)(clock_edge >> 32);
|
|
|
-
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
|
|
|
-
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
|
|
|
-
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_TIMESYNC);
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * ixgbe_ptp_disable_sdp
|
|
|
- * @hw: the private hardware structure
|
|
|
- *
|
|
|
- * this function disables the auxiliary SDP clock out feature
|
|
|
- */
|
|
|
-static void ixgbe_ptp_disable_sdp(struct ixgbe_hw *hw)
|
|
|
-{
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_TIMESYNC);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0);
|
|
|
-}
|
|
|
|
|
|
/**
|
|
|
* ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow
|
|
@@ -877,10 +886,6 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000);
|
|
|
IXGBE_WRITE_FLUSH(hw);
|
|
|
|
|
|
- /* now that the shift has been calculated and the systime
|
|
|
- * registers reset, (re-)enable the Clock out feature*/
|
|
|
- ixgbe_ptp_enable_sdp(hw, shift);
|
|
|
-
|
|
|
/* store the new cycle speed */
|
|
|
adapter->cycle_speed = cycle_speed;
|
|
|
|
|
@@ -901,6 +906,11 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
|
|
|
ktime_to_ns(ktime_get_real()));
|
|
|
|
|
|
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
|
|
+
|
|
|
+ /* Now that the shift has been calculated and the systime
|
|
|
+ * registers reset, (re-)enable the Clock out feature
|
|
|
+ */
|
|
|
+ ixgbe_ptp_enable_sdp(adapter);
|
|
|
}
|
|
|
|
|
|
/**
|