* [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210.
@ 2014-11-21 9:41 Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 1/4] igb: refactor time sync interrupt handling Richard Cochran
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Richard Cochran @ 2014-11-21 9:41 UTC (permalink / raw)
To: netdev
Cc: David Miller, bruce.w.allan, Jacob Keller, Jeff Kirsher,
John Ronciak, Matthew Vick, Jian Yu, Richard Cochran
From: Richard Cochran <rcochran@linutronix.de>
* 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(-)
--
1.7.10.4
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net-next V2 1/4] igb: refactor time sync interrupt handling
2014-11-21 9:41 [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210 Richard Cochran
@ 2014-11-21 9:41 ` Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 2/4] igb: serialize access to the time sync interrupt registers Richard Cochran
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Richard Cochran @ 2014-11-21 9:41 UTC (permalink / raw)
To: netdev
Cc: David Miller, bruce.w.allan, Jacob Keller, Jeff Kirsher,
John Ronciak, Matthew Vick, Jian Yu
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.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 49 +++++++++++------------------
1 file changed, 19 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index b0e12e7..7183a56 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net-next V2 2/4] igb: serialize access to the time sync interrupt registers.
2014-11-21 9:41 [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210 Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 1/4] igb: refactor time sync interrupt handling Richard Cochran
@ 2014-11-21 9:41 ` Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 3/4] igb: enable internal PPS for the i210 Richard Cochran
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Richard Cochran @ 2014-11-21 9:41 UTC (permalink / raw)
To: netdev
Cc: David Miller, bruce.w.allan, Jacob Keller, Jeff Kirsher,
John Ronciak, Matthew Vick, Jian Yu
The 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.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/net/ethernet/intel/igb/igb_ptp.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 794c139..d33252f 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -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);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net-next V2 3/4] igb: enable internal PPS for the i210.
2014-11-21 9:41 [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210 Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 1/4] igb: refactor time sync interrupt handling Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 2/4] igb: serialize access to the time sync interrupt registers Richard Cochran
@ 2014-11-21 9:41 ` Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions " Richard Cochran
2014-11-21 12:37 ` [PATCH net-next V2 0/4] igb: " Jeff Kirsher
4 siblings, 0 replies; 8+ messages in thread
From: Richard Cochran @ 2014-11-21 9:41 UTC (permalink / raw)
To: netdev
Cc: David Miller, bruce.w.allan, Jacob Keller, Jeff Kirsher,
John Ronciak, Matthew Vick, Jian Yu
The 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.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
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(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 7183a56..5fe6e17 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -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)
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index d33252f..526f4a6 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -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;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions for the i210.
2014-11-21 9:41 [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210 Richard Cochran
` (2 preceding siblings ...)
2014-11-21 9:41 ` [PATCH net-next V2 3/4] igb: enable internal PPS for the i210 Richard Cochran
@ 2014-11-21 9:41 ` Richard Cochran
2014-11-21 12:46 ` Jeff Kirsher
2014-11-21 12:37 ` [PATCH net-next V2 0/4] igb: " Jeff Kirsher
4 siblings, 1 reply; 8+ messages in thread
From: Richard Cochran @ 2014-11-21 9:41 UTC (permalink / raw)
To: netdev
Cc: David Miller, bruce.w.allan, Jacob Keller, Jeff Kirsher,
John Ronciak, Matthew Vick, Jian Yu
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 <richardcochran@gmail.com>
---
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(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 82d891e..f6aca7c 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -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;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 5fe6e17..b003a68 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -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);
}
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 526f4a6..2609044 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -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,
+ };
+ 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. */
+ 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 {
+ 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;
+ 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:
@@ -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];
+ 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;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210.
2014-11-21 9:41 [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210 Richard Cochran
` (3 preceding siblings ...)
2014-11-21 9:41 ` [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions " Richard Cochran
@ 2014-11-21 12:37 ` Jeff Kirsher
4 siblings, 0 replies; 8+ messages in thread
From: Jeff Kirsher @ 2014-11-21 12:37 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, David Miller, bruce.w.allan, Jacob Keller, John Ronciak,
Matthew Vick, Jian Yu, Richard Cochran
[-- Attachment #1: Type: text/plain, Size: 1464 bytes --]
On Fri, 2014-11-21 at 10:41 +0100, Richard Cochran wrote:
> From: Richard Cochran <rcochran@linutronix.de>
>
> * 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(-)
Thanks Richard, I have added your series to my queue.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions for the i210.
2014-11-21 9:41 ` [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions " Richard Cochran
@ 2014-11-21 12:46 ` Jeff Kirsher
2014-11-21 12:59 ` Richard Cochran
0 siblings, 1 reply; 8+ messages in thread
From: Jeff Kirsher @ 2014-11-21 12:46 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, David Miller, bruce.w.allan, Jacob Keller, John Ronciak,
Matthew Vick, Jian Yu
[-- Attachment #1: Type: text/plain, Size: 12927 bytes --]
On Fri, 2014-11-21 at 10:41 +0100, Richard Cochran wrote:
> 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 <richardcochran@gmail.com>
> ---
> 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(-)
>
> diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
> index 82d891e..f6aca7c 100644
> --- a/drivers/net/ethernet/intel/igb/igb.h
> +++ b/drivers/net/ethernet/intel/igb/igb.h
> @@ -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;
> diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
> index 5fe6e17..b003a68 100644
> --- a/drivers/net/ethernet/intel/igb/igb_main.c
> +++ b/drivers/net/ethernet/intel/igb/igb_main.c
> @@ -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);
> }
> diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
> index 526f4a6..2609044 100644
> --- a/drivers/net/ethernet/intel/igb/igb_ptp.c
> +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
> @@ -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,
> + };
> + 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)
> + 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 {
> + 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.
> + 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:
> @@ -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.
> + 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;
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions for the i210.
2014-11-21 12:46 ` Jeff Kirsher
@ 2014-11-21 12:59 ` Richard Cochran
0 siblings, 0 replies; 8+ messages in thread
From: Richard Cochran @ 2014-11-21 12:59 UTC (permalink / raw)
To: Jeff Kirsher
Cc: netdev, David Miller, bruce.w.allan, Jacob Keller, John Ronciak,
Matthew Vick, Jian Yu
On Fri, Nov 21, 2014 at 04:46:09AM -0800, Jeff Kirsher wrote:
> On Fri, 2014-11-21 at 10:41 +0100, Richard Cochran wrote:
> > + /* 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.
> Probably should have a blank line after the local variable declaration.
> Again, I can fix this up for ya.
Okay.
Thanks,
Richard
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-11-21 12:59 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-21 9:41 [PATCH net-next V2 0/4] igb: auxiliary PHC functions for the i210 Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 1/4] igb: refactor time sync interrupt handling Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 2/4] igb: serialize access to the time sync interrupt registers Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 3/4] igb: enable internal PPS for the i210 Richard Cochran
2014-11-21 9:41 ` [PATCH net-next V2 4/4] igb: enable auxiliary PHC functions " Richard Cochran
2014-11-21 12:46 ` Jeff Kirsher
2014-11-21 12:59 ` Richard Cochran
2014-11-21 12:37 ` [PATCH net-next V2 0/4] igb: " Jeff Kirsher
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).