Skip to content

Commit 30c7291

Browse files
richardcochranJeff Kirsher
authored andcommitted
igb: implement high frequency periodic output signals
In addition to interrupt driven target time output events, the i210 also has two programmable clock outputs. These clocks support periods between 16 nanoseconds and 140 milliseconds. This patch implements the periodic output function using the clock outputs when possible, falling back to the target time for longer periods. Signed-off-by: Richard Cochran <[email protected]> Tested-by: Aaron Brown <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 6423fc3 commit 30c7291

File tree

2 files changed

+54
-20
lines changed

2 files changed

+54
-20
lines changed

drivers/net/ethernet/intel/igb/e1000_regs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
#define E1000_TRGTTIMH0 0x0B648 /* Target Time Register 0 High - RW */
105105
#define E1000_TRGTTIML1 0x0B64C /* Target Time Register 1 Low - RW */
106106
#define E1000_TRGTTIMH1 0x0B650 /* Target Time Register 1 High - RW */
107+
#define E1000_FREQOUT0 0x0B654 /* Frequency Out 0 Control Register - RW */
108+
#define E1000_FREQOUT1 0x0B658 /* Frequency Out 1 Control Register - RW */
107109
#define E1000_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
108110
#define E1000_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
109111
#define E1000_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */

drivers/net/ethernet/intel/igb/igb_ptp.c

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ static void igb_pin_extts(struct igb_adapter *igb, int chan, int pin)
405405
wr32(E1000_CTRL_EXT, ctrl_ext);
406406
}
407407

408-
static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin)
408+
static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin, int freq)
409409
{
410410
static const u32 aux0_sel_sdp[IGB_N_SDP] = {
411411
AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3,
@@ -424,6 +424,14 @@ static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin)
424424
TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1,
425425
TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1,
426426
};
427+
static const u32 ts_sdp_sel_fc0[IGB_N_SDP] = {
428+
TS_SDP0_SEL_FC0, TS_SDP1_SEL_FC0,
429+
TS_SDP2_SEL_FC0, TS_SDP3_SEL_FC0,
430+
};
431+
static const u32 ts_sdp_sel_fc1[IGB_N_SDP] = {
432+
TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1,
433+
TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1,
434+
};
427435
static const u32 ts_sdp_sel_clr[IGB_N_SDP] = {
428436
TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1,
429437
TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1,
@@ -445,11 +453,17 @@ static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin)
445453
tssdp &= ~AUX1_TS_SDP_EN;
446454

447455
tssdp &= ~ts_sdp_sel_clr[pin];
448-
if (chan == 1)
449-
tssdp |= ts_sdp_sel_tt1[pin];
450-
else
451-
tssdp |= ts_sdp_sel_tt0[pin];
452-
456+
if (freq) {
457+
if (chan == 1)
458+
tssdp |= ts_sdp_sel_fc1[pin];
459+
else
460+
tssdp |= ts_sdp_sel_fc0[pin];
461+
} else {
462+
if (chan == 1)
463+
tssdp |= ts_sdp_sel_tt1[pin];
464+
else
465+
tssdp |= ts_sdp_sel_tt0[pin];
466+
}
453467
tssdp |= ts_sdp_en[pin];
454468

455469
wr32(E1000_TSSDP, tssdp);
@@ -463,10 +477,10 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
463477
struct igb_adapter *igb =
464478
container_of(ptp, struct igb_adapter, ptp_caps);
465479
struct e1000_hw *hw = &igb->hw;
466-
u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh;
480+
u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh, freqout;
467481
unsigned long flags;
468482
struct timespec ts;
469-
int pin = -1;
483+
int use_freq = 0, pin = -1;
470484
s64 ns;
471485

472486
switch (rq->type) {
@@ -511,40 +525,58 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
511525
ts.tv_nsec = rq->perout.period.nsec;
512526
ns = timespec_to_ns(&ts);
513527
ns = ns >> 1;
514-
if (on && ns < 500000LL) {
515-
/* 2k interrupts per second is an awful lot. */
516-
return -EINVAL;
528+
if (on && ns <= 70000000LL) {
529+
if (ns < 8LL)
530+
return -EINVAL;
531+
use_freq = 1;
517532
}
518533
ts = ns_to_timespec(ns);
519534
if (rq->perout.index == 1) {
520-
tsauxc_mask = TSAUXC_EN_TT1;
521-
tsim_mask = TSINTR_TT1;
535+
if (use_freq) {
536+
tsauxc_mask = TSAUXC_EN_CLK1 | TSAUXC_ST1;
537+
tsim_mask = 0;
538+
} else {
539+
tsauxc_mask = TSAUXC_EN_TT1;
540+
tsim_mask = TSINTR_TT1;
541+
}
522542
trgttiml = E1000_TRGTTIML1;
523543
trgttimh = E1000_TRGTTIMH1;
544+
freqout = E1000_FREQOUT1;
524545
} else {
525-
tsauxc_mask = TSAUXC_EN_TT0;
526-
tsim_mask = TSINTR_TT0;
546+
if (use_freq) {
547+
tsauxc_mask = TSAUXC_EN_CLK0 | TSAUXC_ST0;
548+
tsim_mask = 0;
549+
} else {
550+
tsauxc_mask = TSAUXC_EN_TT0;
551+
tsim_mask = TSINTR_TT0;
552+
}
527553
trgttiml = E1000_TRGTTIML0;
528554
trgttimh = E1000_TRGTTIMH0;
555+
freqout = E1000_FREQOUT0;
529556
}
530557
spin_lock_irqsave(&igb->tmreg_lock, flags);
531558
tsauxc = rd32(E1000_TSAUXC);
532559
tsim = rd32(E1000_TSIM);
560+
if (rq->perout.index == 1) {
561+
tsauxc &= ~(TSAUXC_EN_TT1 | TSAUXC_EN_CLK1 | TSAUXC_ST1);
562+
tsim &= ~TSINTR_TT1;
563+
} else {
564+
tsauxc &= ~(TSAUXC_EN_TT0 | TSAUXC_EN_CLK0 | TSAUXC_ST0);
565+
tsim &= ~TSINTR_TT0;
566+
}
533567
if (on) {
534568
int i = rq->perout.index;
535-
536-
igb_pin_perout(igb, i, pin);
569+
igb_pin_perout(igb, i, pin, use_freq);
537570
igb->perout[i].start.tv_sec = rq->perout.start.sec;
538571
igb->perout[i].start.tv_nsec = rq->perout.start.nsec;
539572
igb->perout[i].period.tv_sec = ts.tv_sec;
540573
igb->perout[i].period.tv_nsec = ts.tv_nsec;
541574
wr32(trgttimh, rq->perout.start.sec);
542575
wr32(trgttiml, rq->perout.start.nsec);
576+
if (use_freq)
577+
wr32(freqout, ns);
543578
tsauxc |= tsauxc_mask;
544579
tsim |= tsim_mask;
545-
} else {
546-
tsauxc &= ~tsauxc_mask;
547-
tsim &= ~tsim_mask;
548580
}
549581
wr32(E1000_TSAUXC, tsauxc);
550582
wr32(E1000_TSIM, tsim);

0 commit comments

Comments
 (0)