aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel
diff options
context:
space:
mode:
authorJacob Keller <jacob.e.keller@intel.com>2012-08-01 03:12:25 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2012-10-03 10:47:46 -0400
commit8208367371b7f581dd13fe8bf28f8d7f17f4bf32 (patch)
tree8e397b7a0323758483cabfffb604331b1f4469f8 /drivers/net/ethernet/intel
parent864499449f256e32815575a9b860267ebefa6d70 (diff)
ixgbe: Fix PTP X540 SDP alignment code for PPS signal
This patch fixes a bug in the method used for calculating the trigger alignment for SDP0 when enabling a PPS output on the X540. The alignment math wasn't properly taking into account the overflow cyclecounter, and was misaligning the pin triggers so that two X540 devices synced properly had mis-aligned SDP pins. This patch fixes the math to calculate the correct seconds alignment for the PPS signal. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel')
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c188
1 files changed, 99 insertions, 89 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 39881cb17a4b..58d930dc6766 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -106,6 +106,94 @@ static struct sock_filter ptp_filter[] = {
106}; 106};
107 107
108/** 108/**
109 * ixgbe_ptp_enable_sdp
110 * @hw: the hardware private structure
111 * @shift: the clock shift for calculating nanoseconds
112 *
113 * this function enables the clock out feature on the sdp0 for the
114 * X540 device. It will create a 1second periodic output that can be
115 * used as the PPS (via an interrupt).
116 *
117 * It calculates when the systime will be on an exact second, and then
118 * aligns the start of the PPS signal to that value. The shift is
119 * necessary because it can change based on the link speed.
120 */
121static void ixgbe_ptp_enable_sdp(struct ixgbe_adapter *adapter)
122{
123 struct ixgbe_hw *hw = &adapter->hw;
124 int shift = adapter->cc.shift;
125 u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh, rem;
126 u64 ns = 0, clock_edge = 0;
127
128 switch (hw->mac.type) {
129 case ixgbe_mac_X540:
130 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
131
132 /*
133 * enable the SDP0 pin as output, and connected to the native
134 * function for Timesync (ClockOut)
135 */
136 esdp |= (IXGBE_ESDP_SDP0_DIR |
137 IXGBE_ESDP_SDP0_NATIVE);
138
139 /*
140 * enable the Clock Out feature on SDP0, and allow interrupts
141 * to occur when the pin changes
142 */
143 tsauxc = (IXGBE_TSAUXC_EN_CLK |
144 IXGBE_TSAUXC_SYNCLK |
145 IXGBE_TSAUXC_SDP0_INT);
146
147 /* clock period (or pulse length) */
148 clktiml = (u32)(NSECS_PER_SEC << shift);
149 clktimh = (u32)((NSECS_PER_SEC << shift) >> 32);
150
151 /*
152 * Account for the cyclecounter wrap-around value by
153 * using the converted ns value of the current time to
154 * check for when the next aligned second would occur.
155 */
156 clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
157 clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
158 ns = timecounter_cyc2time(&adapter->tc, clock_edge);
159
160 div_u64_rem(ns, NSECS_PER_SEC, &rem);
161 clock_edge += ((NSECS_PER_SEC - (u64)rem) << shift);
162
163 /* specify the initial clock start time */
164 trgttiml = (u32)clock_edge;
165 trgttimh = (u32)(clock_edge >> 32);
166
167 IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml);
168 IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh);
169 IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
170 IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
171
172 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
173 IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
174
175 IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_TIMESYNC);
176 IXGBE_WRITE_FLUSH(hw);
177 break;
178 default:
179 break;
180 }
181}
182
183/**
184 * ixgbe_ptp_disable_sdp
185 * @hw: the private hardware structure
186 *
187 * this function disables the auxiliary SDP clock out feature
188 */
189static void ixgbe_ptp_disable_sdp(struct ixgbe_hw *hw)
190{
191 IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_TIMESYNC);
192 IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0);
193 IXGBE_WRITE_FLUSH(hw);
194}
195
196/**
109 * ixgbe_ptp_read - read raw cycle counter (to be used by time counter) 197 * ixgbe_ptp_read - read raw cycle counter (to be used by time counter)
110 * @cc: the cyclecounter structure 198 * @cc: the cyclecounter structure
111 * 199 *
@@ -187,6 +275,7 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
187 unsigned long flags; 275 unsigned long flags;
188 u64 now; 276 u64 now;
189 277
278 ixgbe_ptp_disable_sdp(&adapter->hw);
190 spin_lock_irqsave(&adapter->tmreg_lock, flags); 279 spin_lock_irqsave(&adapter->tmreg_lock, flags);
191 280
192 now = timecounter_read(&adapter->tc); 281 now = timecounter_read(&adapter->tc);
@@ -198,6 +287,8 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
198 now); 287 now);
199 288
200 spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 289 spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
290 ixgbe_ptp_enable_sdp(adapter);
291
201 return 0; 292 return 0;
202} 293}
203 294
@@ -246,11 +337,14 @@ static int ixgbe_ptp_settime(struct ptp_clock_info *ptp,
246 ns = ts->tv_sec * 1000000000ULL; 337 ns = ts->tv_sec * 1000000000ULL;
247 ns += ts->tv_nsec; 338 ns += ts->tv_nsec;
248 339
340 ixgbe_ptp_disable_sdp(&adapter->hw);
341
249 /* reset the timecounter */ 342 /* reset the timecounter */
250 spin_lock_irqsave(&adapter->tmreg_lock, flags); 343 spin_lock_irqsave(&adapter->tmreg_lock, flags);
251 timecounter_init(&adapter->tc, &adapter->cc, ns); 344 timecounter_init(&adapter->tc, &adapter->cc, ns);
252 spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 345 spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
253 346
347 ixgbe_ptp_enable_sdp(adapter);
254 return 0; 348 return 0;
255} 349}
256 350
@@ -323,91 +417,6 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
323 } 417 }
324} 418}
325 419
326/**
327 * ixgbe_ptp_enable_sdp
328 * @hw: the hardware private structure
329 * @shift: the clock shift for calculating nanoseconds
330 *
331 * this function enables the clock out feature on the sdp0 for the
332 * X540 device. It will create a 1second periodic output that can be
333 * used as the PPS (via an interrupt).
334 *
335 * It calculates when the systime will be on an exact second, and then
336 * aligns the start of the PPS signal to that value. The shift is
337 * necessary because it can change based on the link speed.
338 */
339static void ixgbe_ptp_enable_sdp(struct ixgbe_hw *hw, int shift)
340{
341 u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh;
342 u64 clock_edge = 0;
343 u32 rem;
344
345 switch (hw->mac.type) {
346 case ixgbe_mac_X540:
347 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
348
349 /*
350 * enable the SDP0 pin as output, and connected to the native
351 * function for Timesync (ClockOut)
352 */
353 esdp |= (IXGBE_ESDP_SDP0_DIR |
354 IXGBE_ESDP_SDP0_NATIVE);
355
356 /*
357 * enable the Clock Out feature on SDP0, and allow interrupts
358 * to occur when the pin changes
359 */
360 tsauxc = (IXGBE_TSAUXC_EN_CLK |
361 IXGBE_TSAUXC_SYNCLK |
362 IXGBE_TSAUXC_SDP0_INT);
363
364 /* clock period (or pulse length) */
365 clktiml = (u32)(NSECS_PER_SEC << shift);
366 clktimh = (u32)((NSECS_PER_SEC << shift) >> 32);
367
368 clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
369 clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
370
371 /*
372 * account for the fact that we can't do u64 division
373 * with remainder, by converting the clock values into
374 * nanoseconds first
375 */
376 clock_edge >>= shift;
377 div_u64_rem(clock_edge, NSECS_PER_SEC, &rem);
378 clock_edge += (NSECS_PER_SEC - rem);
379 clock_edge <<= shift;
380
381 /* specify the initial clock start time */
382 trgttiml = (u32)clock_edge;
383 trgttimh = (u32)(clock_edge >> 32);
384
385 IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml);
386 IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh);
387 IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
388 IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
389
390 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
391 IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
392
393 IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_TIMESYNC);
394 break;
395 default:
396 break;
397 }
398}
399
400/**
401 * ixgbe_ptp_disable_sdp
402 * @hw: the private hardware structure
403 *
404 * this function disables the auxiliary SDP clock out feature
405 */
406static void ixgbe_ptp_disable_sdp(struct ixgbe_hw *hw)
407{
408 IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_TIMESYNC);
409 IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0);
410}
411 420
412/** 421/**
413 * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow 422 * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow
@@ -877,10 +886,6 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
877 IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000); 886 IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000);
878 IXGBE_WRITE_FLUSH(hw); 887 IXGBE_WRITE_FLUSH(hw);
879 888
880 /* now that the shift has been calculated and the systime
881 * registers reset, (re-)enable the Clock out feature*/
882 ixgbe_ptp_enable_sdp(hw, shift);
883
884 /* store the new cycle speed */ 889 /* store the new cycle speed */
885 adapter->cycle_speed = cycle_speed; 890 adapter->cycle_speed = cycle_speed;
886 891
@@ -901,6 +906,11 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
901 ktime_to_ns(ktime_get_real())); 906 ktime_to_ns(ktime_get_real()));
902 907
903 spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 908 spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
909
910 /* Now that the shift has been calculated and the systime
911 * registers reset, (re-)enable the Clock out feature
912 */
913 ixgbe_ptp_enable_sdp(adapter);
904} 914}
905 915
906/** 916/**