igb: auxiliary PHC functions for the i210.
Subsystems (3)
v2 cover igb: auxiliary PHC functions for the i210.
From: Richard Cochran <[email protected]>
* ChangeLog
** V2
- Add missing serialization in the reset function
- Reset the auxiliary functions along with the rest
- Guard against spurious SYS_WRAP interrupts (these occur in the 82580 device from time to time)
This patch series adds three features: time stamping external events, producing a periodic output signal, and an internal PPS event. The i210 PCIe card has a 6 pin header with SDP0-3, making it easy to try out this new functionality.
An earlier version of this series was posted way back in May, 2013, but that version lacked a good way to assign functions to the pins. In the mean time, the PHC core has a standard method to configure the pins, and this series makes use of it.
Thanks,
Richard
Richard Cochran (4):
igb: refactor time sync interrupt handling
igb: serialize access to the time sync interrupt registers.
igb: enable internal PPS for the i210.
igb: enable auxiliary PHC functions for the i210.
drivers/net/ethernet/intel/igb/igb.h | 9 + drivers/net/ethernet/intel/igb/igb_main.c | 110 +++++++++---- drivers/net/ethernet/intel/igb/igb_ptp.c | 254 ++++++++++++++++++++++++++++- 3 files changed, 337 insertions(+), 36 deletions(-)
Signature · 1 line
1.7.10.4
PATCH v2 1/4 igb: refactor time sync interrupt handling
The code that handles the time sync interrupt is repeated in three different places. This patch refactors the identical code blocks into a single helper function.
--- drivers/net/ethernet/intel/igb/igb_main.c | 49 +++++++++++------------------ 1 file changed, 19 insertions(+), 30 deletions(-)
drivers/net/ethernet/intel/igb/igb_main.c +19 -30
@@ -5383,6 +5383,19 @@ void igb_update_stats(struct igb_adapter *adapter, } } +static void igb_tsync_interrupt (struct igb_adapter *adapter) +{ +struct e1000_hw *hw = &adapter->hw; +u32 tsicr =rd32 (E1000_TSICR ); + +if (tsicr &E1000_TSICR_TXTS ) { +/* acknowledge the interrupt */ +wr32 (E1000_TSICR ,E1000_TSICR_TXTS ); +/* retrieve hardware timestamp */ +schedule_work (&adapter->ptp_tx_work); + } +} +static irqreturn_t igb_msix_other (int irq,void *data) {struct igb_adapter *adapter = data;
@@ -5414,16 +5427,8 @@ static irqreturn_t igb_msix_other(int irq, void *data)mod_timer (&adapter->watchdog_timer, jiffies +1 ); } -if (icr &E1000_ICR_TS ) { -u32 tsicr =rd32 (E1000_TSICR ); - -if (tsicr &E1000_TSICR_TXTS ) { -/* acknowledge the interrupt */ -wr32 (E1000_TSICR ,E1000_TSICR_TXTS ); -/* retrieve hardware timestamp */ -schedule_work (&adapter->ptp_tx_work); - } - } +if (icr &E1000_ICR_TS ) +igb_tsync_interrupt (adapter);wr32 (E1000_EIMS , adapter->eims_other);
@@ -6202,16 +6207,8 @@ static irqreturn_t igb_intr_msi(int irq, void *data)mod_timer (&adapter->watchdog_timer, jiffies +1 ); } -if (icr &E1000_ICR_TS ) { -u32 tsicr =rd32 (E1000_TSICR ); - -if (tsicr &E1000_TSICR_TXTS ) { -/* acknowledge the interrupt */ -wr32 (E1000_TSICR ,E1000_TSICR_TXTS ); -/* retrieve hardware timestamp */ -schedule_work (&adapter->ptp_tx_work); - } - } +if (icr &E1000_ICR_TS ) +igb_tsync_interrupt (adapter);napi_schedule (&q_vector->napi);
@@ -6256,16 +6253,8 @@ static irqreturn_t igb_intr(int irq, void *data)mod_timer (&adapter->watchdog_timer, jiffies +1 ); } -if (icr &E1000_ICR_TS ) { -u32 tsicr =rd32 (E1000_TSICR ); - -if (tsicr &E1000_TSICR_TXTS ) { -/* acknowledge the interrupt */ -wr32 (E1000_TSICR ,E1000_TSICR_TXTS ); -/* retrieve hardware timestamp */ -schedule_work (&adapter->ptp_tx_work); - } - } +if (icr &E1000_ICR_TS ) +igb_tsync_interrupt (adapter);napi_schedule (&q_vector->napi);
Signature · 1 line
1.7.10.4
PATCH v2 2/4 igb: serialize access to the time sync interrupt registers.
In reply to Richard CochranThe time sync related interrupt registers may be manipulated from different contexts. This patch protects the registers from being asynchronously changed by the reset function.
Also, the patch removes a misleading comment. The reset function is disabling a bunch of functions, not enabling them.
--- drivers/net/ethernet/intel/igb/igb_ptp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/ethernet/intel/igb/igb_ptp.c +7 -3
@@ -905,6 +905,7 @@ void igb_ptp_stop(struct igb_adapter *adapter)void igb_ptp_reset (struct igb_adapter *adapter) {struct e1000_hw *hw = &adapter->hw; +unsigned long flags;if (!(adapter->flags &IGB_FLAG_PTP ))return ;
@@ -912,6 +913,8 @@ void igb_ptp_reset(struct igb_adapter *adapter)/* reset the tstamp_config */ igb_ptp_set_timestamp_mode (adapter, &adapter->tstamp_config); +spin_lock_irqsave (&adapter->tmreg_lock, flags); +switch (adapter->hw.mac.type) {case e1000_82576:/* Dial the nominal frequency. */
@@ -922,23 +925,24 @@ void igb_ptp_reset(struct igb_adapter *adapter)case e1000_i350:case e1000_i210:case e1000_i211: -/* Enable the timer functions and interrupts. */ wr32 (E1000_TSAUXC ,0x0 );wr32 (E1000_TSIM ,TSYNC_INTERRUPTS );wr32 (E1000_IMS ,E1000_IMS_TS );break ;default :/* No work to do. */ -return ; + goto out; }/* Re-initialize the timer. */ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {struct timespec ts =ktime_to_timespec (ktime_get_real ()); -igb_ptp_settime_i210 (&adapter->ptp_caps, &ts); +igb_ptp_write_i210 (adapter, &ts); }else {timecounter_init (&adapter->tc, &adapter->cc,ktime_to_ns (ktime_get_real ())); } +out: +spin_unlock_irqrestore (&adapter->tmreg_lock, flags); }
Signature · 1 line
1.7.10.4
PATCH v2 3/4 igb: enable internal PPS for the i210.
In reply to Richard CochranThe i210 device can produce an interrupt on the full second. This patch allows using this interrupt to generate an internal PPS event for adjusting the kernel system time.
--- drivers/net/ethernet/intel/igb/igb_main.c | 18 +++++++++++++--- drivers/net/ethernet/intel/igb/igb_ptp.c | 32 +++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/igb/igb_main.c +15 -3
@@ -5386,14 +5386,26 @@ void igb_update_stats(struct igb_adapter *adapter,static void igb_tsync_interrupt (struct igb_adapter *adapter) {struct e1000_hw *hw = &adapter->hw; -u32 tsicr =rd32 (E1000_TSICR ); +struct ptp_clock_event event; +u32 ack =0 , tsicr =rd32 (E1000_TSICR ); + +if (tsicr &TSINTR_SYS_WRAP ) { + event.type =PTP_CLOCK_PPS ; +if (adapter->ptp_caps.pps) +ptp_clock_event (adapter->ptp_clock, &event); +else +dev_err (&adapter->pdev->dev,"unexpected SYS WRAP" ); + ack |=TSINTR_SYS_WRAP ; + }if (tsicr &E1000_TSICR_TXTS ) { -/* acknowledge the interrupt */ -wr32 (E1000_TSICR ,E1000_TSICR_TXTS );/* retrieve hardware timestamp */ schedule_work (&adapter->ptp_tx_work); + ack |=E1000_TSICR_TXTS ; } + +/* acknowledge the interrupts */ +wr32 (E1000_TSICR , ack); }static irqreturn_t igb_msix_other (int irq,void *data)
drivers/net/ethernet/intel/igb/igb_ptp.c +30 -2
@@ -360,6 +360,34 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,return 0 ; } +static int igb_ptp_feature_enable_i210 (struct ptp_clock_info *ptp, +struct ptp_clock_request *rq,int on) +{ +struct igb_adapter *igb = + container_of(ptp, struct igb_adapter, ptp_caps); +struct e1000_hw *hw = &igb->hw; +unsigned long flags; +u32 tsim; + +switch (rq->type) { +case PTP_CLK_REQ_PPS : +spin_lock_irqsave (&igb->tmreg_lock, flags); + tsim =rd32 (E1000_TSIM ); +if (on) + tsim |=TSINTR_SYS_WRAP ; +else + tsim &= ~TSINTR_SYS_WRAP ; +wr32 (E1000_TSIM , tsim); +spin_unlock_irqrestore (&igb->tmreg_lock, flags); +return 0 ; + +default : +break ; + } + +return -EOPNOTSUPP ; +} +static int igb_ptp_feature_enable (struct ptp_clock_info *ptp,struct ptp_clock_request *rq,int on) {
@@ -802,12 +830,12 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.owner =THIS_MODULE ; adapter->ptp_caps.max_adj =62499999 ; adapter->ptp_caps.n_ext_ts =0 ; - adapter->ptp_caps.pps =0 ; + adapter->ptp_caps.pps =1 ; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580; adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; adapter->ptp_caps.gettime = igb_ptp_gettime_i210; adapter->ptp_caps.settime = igb_ptp_settime_i210; - adapter->ptp_caps.enable = igb_ptp_feature_enable; + adapter->ptp_caps.enable = igb_ptp_feature_enable_i210;/* Enable the timer functions by clearing bit 31. */ wr32 (E1000_TSAUXC ,0x0 );break ;
Signature · 1 line
1.7.10.4
PATCH v2 4/4 igb: enable auxiliary PHC functions for the i210.
In reply to Richard CochranThe i210 device offers a number of special PTP Hardware Clock features on the Software Defined Pins (SDPs). This patch adds support for two of the possible functions, namely time stamping external events, and periodic output signals.
The assignment of PHC functions to the four SDP can be freely chosen by the user.
--- drivers/net/ethernet/intel/igb/igb.h | 9 ++ drivers/net/ethernet/intel/igb/igb_main.c | 51 ++++++- drivers/net/ethernet/intel/igb/igb_ptp.c | 220 ++++++++++++++++++++++++++++- 3 files changed, 274 insertions(+), 6 deletions(-)
drivers/net/ethernet/intel/igb/igb.h +9 -0
@@ -343,6 +343,9 @@ struct hwmon_buff { };#endif +#define IGB_N_EXTTS 2 +#define IGB_N_PEROUT 2 +#define IGB_N_SDP 4#define IGB_RETA_SIZE 128/* board specific private data structure */
@@ -439,6 +442,12 @@ struct igb_adapter {u32 tx_hwtstamp_timeouts;u32 rx_hwtstamp_cleared; +struct ptp_pin_desc sdp_config[IGB_N_SDP ]; +struct { +struct timespec start; +struct timespec period; + } perout[IGB_N_PEROUT ]; +char fw_version[32 ];#ifdef CONFIG_IGB_HWMON struct hwmon_buff *igb_hwmon_buff;
drivers/net/ethernet/intel/igb/igb_main.c +50 -1
63 lines not on this page · raw message
drivers/net/ethernet/intel/igb/igb_ptp.c +215 -5
274 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Re: [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions for the i210.
Quoted 146 lines · Richard Cochran
The i210 device offers a number of special PTP Hardware Clock features on the Software Defined Pins (SDPs). This patch adds support for two of the possible functions, namely time stamping external events, and periodic output signals.
The assignment of PHC functions to the four SDP can be freely chosen by the user.
Signed-off-by Richard Cochran <[email protected]>--- drivers/net/ethernet/intel/igb/igb.h | 9 ++ drivers/net/ethernet/intel/igb/igb_main.c | 51 ++++++- drivers/net/ethernet/intel/igb/igb_ptp.c | 220 ++++++++++++++++++++++++++++- 3 files changed, 274 insertions(+), 6 deletions(-)drivers/net/ethernet/intel/igb/igb.h +9
-0@@ -343,6 +343,9 @@ struct hwmon_buff { };#endif +#define IGB_N_EXTTS 2 +#define IGB_N_PEROUT 2 +#define IGB_N_SDP 4#define IGB_RETA_SIZE 128/* board specific private data structure */ @@ -439,6 +442,12 @@ struct igb_adapter {u32 tx_hwtstamp_timeouts;u32 rx_hwtstamp_cleared; +struct ptp_pin_desc sdp_config[IGB_N_SDP ]; +struct { +struct timespec start; +struct timespec period; + } perout[IGB_N_PEROUT ]; +char fw_version[32 ];#ifdef CONFIG_IGB_HWMON struct hwmon_buff *igb_hwmon_buff;drivers/net/ethernet/intel/igb/igb_main.c +50
-1@@ -5387,7 +5387,8 @@ static void igb_tsync_interrupt(struct igb_adapter *adapter) {struct e1000_hw *hw = &adapter->hw;struct ptp_clock_event event; -u32 ack =0 , tsicr =rd32 (E1000_TSICR ); +struct timespec ts; +u32 ack =0 , tsauxc, sec, nsec, tsicr =rd32 (E1000_TSICR );if (tsicr &TSINTR_SYS_WRAP ) { event.type =PTP_CLOCK_PPS ;@@ -5404,6 +5405,54 @@ static void igb_tsync_interrupt(struct igb_adapter *adapter) ack |=E1000_TSICR_TXTS ; } +if (tsicr &TSINTR_TT0 ) { +spin_lock (&adapter->tmreg_lock); + ts =timespec_add (adapter->perout[0 ].start, + adapter->perout[0 ].period); +wr32 (E1000_TRGTTIML0 , ts.tv_nsec); +wr32 (E1000_TRGTTIMH0 , ts.tv_sec); + tsauxc =rd32 (E1000_TSAUXC ); + tsauxc |=TSAUXC_EN_TT0 ; +wr32 (E1000_TSAUXC , tsauxc); + adapter->perout[0 ].start = ts; +spin_unlock (&adapter->tmreg_lock); + ack |=TSINTR_TT0 ; + } + +if (tsicr &TSINTR_TT1 ) { +spin_lock (&adapter->tmreg_lock); + ts =timespec_add (adapter->perout[1 ].start, + adapter->perout[1 ].period); +wr32 (E1000_TRGTTIML1 , ts.tv_nsec); +wr32 (E1000_TRGTTIMH1 , ts.tv_sec); + tsauxc =rd32 (E1000_TSAUXC ); + tsauxc |=TSAUXC_EN_TT1 ; +wr32 (E1000_TSAUXC , tsauxc); + adapter->perout[1 ].start = ts; +spin_unlock (&adapter->tmreg_lock); + ack |=TSINTR_TT1 ; + } + +if (tsicr &TSINTR_AUTT0 ) { + nsec =rd32 (E1000_AUXSTMPL0 ); + sec =rd32 (E1000_AUXSTMPH0 ); + event.type =PTP_CLOCK_EXTTS ; + event.index =0 ; + event.timestamp = sec *1000000000ULL + nsec; +ptp_clock_event (adapter->ptp_clock, &event); + ack |=TSINTR_AUTT0 ; + } + +if (tsicr &TSINTR_AUTT1 ) { + nsec =rd32 (E1000_AUXSTMPL1 ); + sec =rd32 (E1000_AUXSTMPH1 ); + event.type =PTP_CLOCK_EXTTS ; + event.index =1 ; + event.timestamp = sec *1000000000ULL + nsec; +ptp_clock_event (adapter->ptp_clock, &event); + ack |=TSINTR_AUTT1 ; + } +/* acknowledge the interrupts */ wr32 (E1000_TSICR , ack); }drivers/net/ethernet/intel/igb/igb_ptp.c +27
-0@@ -360,16 +360,203 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,return 0 ; } +static void igb_pin_direction (int pin,int input,u32 *ctrl,u32 *ctrl_ext) +{ +u32 *ptr = pin <2 ? ctrl : ctrl_ext; +u32 mask[IGB_N_SDP ] = { +E1000_CTRL_SDP0_DIR , +E1000_CTRL_SDP1_DIR , +E1000_CTRL_EXT_SDP2_DIR , +E1000_CTRL_EXT_SDP3_DIR , + }; + +if (input) + *ptr &= ~mask[pin]; +else + *ptr |= mask[pin]; +} + +static void igb_pin_extts (struct igb_adapter *igb,int chan,int pin) +{ +struct e1000_hw *hw = &igb->hw; +u32 aux0_sel_sdp[IGB_N_SDP ] = { +AUX0_SEL_SDP0 ,AUX0_SEL_SDP1 ,AUX0_SEL_SDP2 ,AUX0_SEL_SDP3 , + }; +u32 aux1_sel_sdp[IGB_N_SDP ] = { +AUX1_SEL_SDP0 ,AUX1_SEL_SDP1 ,AUX1_SEL_SDP2 ,AUX1_SEL_SDP3 , + }; +u32 ts_sdp_en[IGB_N_SDP ] = { +TS_SDP0_EN ,TS_SDP1_EN ,TS_SDP2_EN ,TS_SDP3_EN ,
drivers/net/ethernet/intel/igb/igb_ptp.c static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, · line 399
Quoted 10 lines
drivers/net/ethernet/intel/igb/igb_ptp.c +10
-0+ }; +u32 ctrl, ctrl_ext, tssdp =0 ; + + ctrl =rd32 (E1000_CTRL ); + ctrl_ext =rd32 (E1000_CTRL_EXT ); + tssdp =rd32 (E1000_TSSDP ); + +igb_pin_direction (pin,1 , &ctrl, &ctrl_ext); + +/* Make sure this pin is not enabled as an ouput. */
Minor nitpick, output is mis-spelled (I can fix that up for you)
Quoted 133 lines
drivers/net/ethernet/intel/igb/igb_ptp.c +123
-1+ tssdp &= ~ts_sdp_en[pin]; + +if (chan ==1 ) { + tssdp &= ~AUX1_SEL_SDP3 ; + tssdp |= aux1_sel_sdp[pin] |AUX1_TS_SDP_EN ; + }else { + tssdp &= ~AUX0_SEL_SDP3 ; + tssdp |= aux0_sel_sdp[pin] |AUX0_TS_SDP_EN ; + } + +wr32 (E1000_TSSDP , tssdp); +wr32 (E1000_CTRL , ctrl); +wr32 (E1000_CTRL_EXT , ctrl_ext); +} + +static void igb_pin_perout (struct igb_adapter *igb,int chan,int pin) +{ +struct e1000_hw *hw = &igb->hw; +u32 aux0_sel_sdp[IGB_N_SDP ] = { +AUX0_SEL_SDP0 ,AUX0_SEL_SDP1 ,AUX0_SEL_SDP2 ,AUX0_SEL_SDP3 , + }; +u32 aux1_sel_sdp[IGB_N_SDP ] = { +AUX1_SEL_SDP0 ,AUX1_SEL_SDP1 ,AUX1_SEL_SDP2 ,AUX1_SEL_SDP3 , + }; +u32 ts_sdp_en[IGB_N_SDP ] = { +TS_SDP0_EN ,TS_SDP1_EN ,TS_SDP2_EN ,TS_SDP3_EN , + }; +u32 ts_sdp_sel_tt0[IGB_N_SDP ] = { +TS_SDP0_SEL_TT0 ,TS_SDP1_SEL_TT0 , +TS_SDP2_SEL_TT0 ,TS_SDP3_SEL_TT0 , + }; +u32 ts_sdp_sel_tt1[IGB_N_SDP ] = { +TS_SDP0_SEL_TT1 ,TS_SDP1_SEL_TT1 , +TS_SDP2_SEL_TT1 ,TS_SDP3_SEL_TT1 , + }; +u32 ts_sdp_sel_clr[IGB_N_SDP ] = { +TS_SDP0_SEL_FC1 ,TS_SDP1_SEL_FC1 , +TS_SDP2_SEL_FC1 ,TS_SDP3_SEL_FC1 , + }; +u32 ctrl, ctrl_ext, tssdp =0 ; + + ctrl =rd32 (E1000_CTRL ); + ctrl_ext =rd32 (E1000_CTRL_EXT ); + tssdp =rd32 (E1000_TSSDP ); + +igb_pin_direction (pin,0 , &ctrl, &ctrl_ext); + +/* Make sure this pin is not enabled as an input. */ +if ((tssdp &AUX0_SEL_SDP3 ) == aux0_sel_sdp[pin]) + tssdp &= ~AUX0_TS_SDP_EN ; + +if ((tssdp &AUX1_SEL_SDP3 ) == aux1_sel_sdp[pin]) + tssdp &= ~AUX1_TS_SDP_EN ; + + tssdp &= ~ts_sdp_sel_clr[pin]; +if (chan ==1 ) + tssdp |= ts_sdp_sel_tt1[pin]; +else + tssdp |= ts_sdp_sel_tt0[pin]; + + tssdp |= ts_sdp_en[pin]; + +wr32 (E1000_TSSDP , tssdp); +wr32 (E1000_CTRL , ctrl); +wr32 (E1000_CTRL_EXT , ctrl_ext); +} +static int igb_ptp_feature_enable_i210 (struct ptp_clock_info *ptp,struct ptp_clock_request *rq,int on) {struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps);struct e1000_hw *hw = &igb->hw; +u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh;unsigned long flags; -u32 tsim; +struct timespec ts; +int pin; +s64 ns;switch (rq->type) { +case PTP_CLK_REQ_EXTTS : +if (on) { + pin =ptp_find_pin (igb->ptp_clock,PTP_PF_EXTTS , + rq->extts.index); +if (pin <0 ) +return -EBUSY ; + } +if (rq->extts.index ==1 ) { + tsauxc_mask =TSAUXC_EN_TS1 ; + tsim_mask =TSINTR_AUTT1 ; + }else { + tsauxc_mask =TSAUXC_EN_TS0 ; + tsim_mask =TSINTR_AUTT0 ; + } +spin_lock_irqsave (&igb->tmreg_lock, flags); + tsauxc =rd32 (E1000_TSAUXC ); + tsim =rd32 (E1000_TSIM ); +if (on) { +igb_pin_extts (igb, rq->extts.index, pin); + tsauxc |= tsauxc_mask; + tsim |= tsim_mask; + }else { + tsauxc &= ~tsauxc_mask; + tsim &= ~tsim_mask; + } +wr32 (E1000_TSAUXC , tsauxc); +wr32 (E1000_TSIM , tsim); +spin_unlock_irqrestore (&igb->tmreg_lock, flags); +return 0 ; + +case PTP_CLK_REQ_PEROUT : +if (on) { + pin =ptp_find_pin (igb->ptp_clock,PTP_PF_PEROUT , + rq->perout.index); +if (pin <0 ) +return -EBUSY ; + } + ts.tv_sec = rq->perout.period.sec; + ts.tv_nsec = rq->perout.period.nsec; + ns =timespec_to_ns (&ts); + ns = ns >>1 ; +if (on && ns <500000LL ) { +/* 2k interrupts per second is an awful lot. */ +return -EINVAL ; + } + ts =ns_to_timespec (ns); +if (rq->perout.index ==1 ) { + tsauxc_mask =TSAUXC_EN_TT1 ; + tsim_mask =TSINTR_TT1 ; + trgttiml =E1000_TRGTTIML1 ; + trgttimh =E1000_TRGTTIMH1 ; + }else {
drivers/net/ethernet/intel/igb/igb_ptp.c static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, · line 541
Quoted 10 lines
drivers/net/ethernet/intel/igb/igb_ptp.c +10
-0+ tsauxc_mask =TSAUXC_EN_TT0 ; + tsim_mask =TSINTR_TT0 ; + trgttiml =E1000_TRGTTIML0 ; + trgttimh =E1000_TRGTTIMH0 ; + } +spin_lock_irqsave (&igb->tmreg_lock, flags); + tsauxc =rd32 (E1000_TSAUXC ); + tsim =rd32 (E1000_TSIM ); +if (on) { +int i = rq->perout.index;
Probably should have a blank line after the local variable declaration. Again, I can fix this up for ya.
Quoted 61 lines
drivers/net/ethernet/intel/igb/igb_ptp.c +33
-3+igb_pin_perout (igb, i, pin); + igb->perout[i].start.tv_sec = rq->perout.start.sec; + igb->perout[i].start.tv_nsec = rq->perout.start.nsec; + igb->perout[i].period.tv_sec = ts.tv_sec; + igb->perout[i].period.tv_nsec = ts.tv_nsec; +wr32 (trgttiml, rq->perout.start.sec); +wr32 (trgttimh, rq->perout.start.nsec); + tsauxc |= tsauxc_mask; + tsim |= tsim_mask; + }else { + tsauxc &= ~tsauxc_mask; + tsim &= ~tsim_mask; + } +wr32 (E1000_TSAUXC , tsauxc); +wr32 (E1000_TSIM , tsim); +spin_unlock_irqrestore (&igb->tmreg_lock, flags); +return 0 ; +case PTP_CLK_REQ_PPS :spin_lock_irqsave (&igb->tmreg_lock, flags); tsim =rd32 (E1000_TSIM );@@ -380,9 +567,6 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,wr32 (E1000_TSIM , tsim);spin_unlock_irqrestore (&igb->tmreg_lock, flags);return 0 ; - -default : -break ; }return -EOPNOTSUPP ;@@ -394,6 +578,20 @@ static int igb_ptp_feature_enable(struct ptp_clock_info *ptp,return -EOPNOTSUPP ; } +static int igb_ptp_verify_pin (struct ptp_clock_info *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan) +{ +switch (func) { +case PTP_PF_NONE : +case PTP_PF_EXTTS : +case PTP_PF_PEROUT : +break ; +case PTP_PF_PHYSYNC : +return -1 ; + } +return 0 ; +} +/** * igb_ptp_tx_work * @work: pointer to work struct @@ -784,6 +982,7 @@ void igb_ptp_init(struct igb_adapter *adapter) {struct e1000_hw *hw = &adapter->hw;struct net_device *netdev = adapter->netdev; +int i;switch (hw->mac.type) {case e1000_82576:
drivers/net/ethernet/intel/igb/igb_ptp.c void igb_ptp_init(struct igb_adapter *adapter) · line 1029
Quoted 5 lines
drivers/net/ethernet/intel/igb/igb_ptp.c +2
-0@@ -826,16 +1025,26 @@ void igb_ptp_init(struct igb_adapter *adapter)break ;case e1000_i210:case e1000_i211: +for (i =0 ; i <IGB_N_SDP ; i++) { +struct ptp_pin_desc *ppd = &adapter->sdp_config[i];
Probably should have a blank line here as well, which I can fix up.
Quoted 30 lines
drivers/net/ethernet/intel/igb/igb_ptp.c +10
-1+snprintf (ppd->name,sizeof (ppd->name),"SDP%d" , i); + ppd->index = i; + ppd->func =PTP_PF_NONE ; + }snprintf (adapter->ptp_caps.name,16 ,"%pm" , netdev->dev_addr); adapter->ptp_caps.owner =THIS_MODULE ; adapter->ptp_caps.max_adj =62499999 ; - adapter->ptp_caps.n_ext_ts =0 ; + adapter->ptp_caps.n_ext_ts =IGB_N_EXTTS ; + adapter->ptp_caps.n_per_out =IGB_N_PEROUT ; + adapter->ptp_caps.n_pins =IGB_N_SDP ; adapter->ptp_caps.pps =1 ; + adapter->ptp_caps.pin_config = adapter->sdp_config; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580; adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; adapter->ptp_caps.gettime = igb_ptp_gettime_i210; adapter->ptp_caps.settime = igb_ptp_settime_i210; adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; + adapter->ptp_caps.verify = igb_ptp_verify_pin;/* Enable the timer functions by clearing bit 31. */ wr32 (E1000_TSAUXC ,0x0 );break ;@@ -954,6 +1163,7 @@ void igb_ptp_reset(struct igb_adapter *adapter)case e1000_i210:case e1000_i211:wr32 (E1000_TSAUXC ,0x0 ); +wr32 (E1000_TSSDP ,0x0 );wr32 (E1000_TSIM ,TSYNC_INTERRUPTS );wr32 (E1000_IMS ,E1000_IMS_TS );break ;
Re: [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions for the i210.
Quoted 4 lines · Jeff Kirsher
drivers/net/ethernet/intel/igb/igb_ptp.c static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, · line 399
Quoted 1 line · Richard Cochran
drivers/net/ethernet/intel/igb/igb_ptp.c +1
-0+/* Make sure this pin is not enabled as an ouput. */ Minor nitpick, output is mis-spelled (I can fix that up for you)
Yes please.
Quoted 2 lines
Probably should have a blank line after the local variable declaration. Again, I can fix this up for ya.
Okay.
Thanks,
Richard
Quoted 28 lines · Richard Cochran
From: Richard Cochran <[email protected]>
* ChangeLog
** V2
- Add missing serialization in the reset function
- Reset the auxiliary functions along with the rest
- Guard against spuriousSYS_WRAPinterrupts (these occur in the 82580 device from time to time)This patch series adds three features: time stamping external events, producing a periodic output signal, and an internal PPS event. The i210 PCIe card has a 6 pin header with SDP0-3, making it easy to try out this new functionality.
An earlier version of this series was posted way back in May, 2013, but that version lacked a good way to assign functions to the pins. In the mean time, the PHC core has a standard method to configure the pins, and this series makes use of it.
Thanks,
RichardRichard Cochran (4):
igb: refactor time sync interrupt handling
igb: serialize access to the time sync interrupt registers.
igb: enable internal PPS for the i210.
igb: enable auxiliary PHC functions for the i210.
Quoted 5 lines
drivers/net/ethernet/intel/igb/igb.h | 9 + drivers/net/ethernet/intel/igb/igb_main.c | 110 +++++++++---- drivers/net/ethernet/intel/igb/igb_ptp.c | 254 ++++++++++++++++++++++++++++- 3 files changed, 337 insertions(+), 36 deletions(-)
Thanks Richard, I have added your series to my queue.