Skip to content

Commit 00c6557

Browse files
richardcochranJeff Kirsher
authored andcommitted
igb: enable internal PPS for the i210
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 <[email protected]> Tested-by: Aaron Brown <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 8298c1e commit 00c6557

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5387,14 +5387,26 @@ void igb_update_stats(struct igb_adapter *adapter,
53875387
static void igb_tsync_interrupt(struct igb_adapter *adapter)
53885388
{
53895389
struct e1000_hw *hw = &adapter->hw;
5390-
u32 tsicr = rd32(E1000_TSICR);
5390+
struct ptp_clock_event event;
5391+
u32 ack = 0, tsicr = rd32(E1000_TSICR);
5392+
5393+
if (tsicr & TSINTR_SYS_WRAP) {
5394+
event.type = PTP_CLOCK_PPS;
5395+
if (adapter->ptp_caps.pps)
5396+
ptp_clock_event(adapter->ptp_clock, &event);
5397+
else
5398+
dev_err(&adapter->pdev->dev, "unexpected SYS WRAP");
5399+
ack |= TSINTR_SYS_WRAP;
5400+
}
53915401

53925402
if (tsicr & E1000_TSICR_TXTS) {
5393-
/* acknowledge the interrupt */
5394-
wr32(E1000_TSICR, E1000_TSICR_TXTS);
53955403
/* retrieve hardware timestamp */
53965404
schedule_work(&adapter->ptp_tx_work);
5405+
ack |= E1000_TSICR_TXTS;
53975406
}
5407+
5408+
/* acknowledge the interrupts */
5409+
wr32(E1000_TSICR, ack);
53985410
}
53995411

54005412
static irqreturn_t igb_msix_other(int irq, void *data)

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,34 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,
355355
return 0;
356356
}
357357

358+
static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
359+
struct ptp_clock_request *rq, int on)
360+
{
361+
struct igb_adapter *igb =
362+
container_of(ptp, struct igb_adapter, ptp_caps);
363+
struct e1000_hw *hw = &igb->hw;
364+
unsigned long flags;
365+
u32 tsim;
366+
367+
switch (rq->type) {
368+
case PTP_CLK_REQ_PPS:
369+
spin_lock_irqsave(&igb->tmreg_lock, flags);
370+
tsim = rd32(E1000_TSIM);
371+
if (on)
372+
tsim |= TSINTR_SYS_WRAP;
373+
else
374+
tsim &= ~TSINTR_SYS_WRAP;
375+
wr32(E1000_TSIM, tsim);
376+
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
377+
return 0;
378+
379+
default:
380+
break;
381+
}
382+
383+
return -EOPNOTSUPP;
384+
}
385+
358386
static int igb_ptp_feature_enable(struct ptp_clock_info *ptp,
359387
struct ptp_clock_request *rq, int on)
360388
{
@@ -797,12 +825,12 @@ void igb_ptp_init(struct igb_adapter *adapter)
797825
adapter->ptp_caps.owner = THIS_MODULE;
798826
adapter->ptp_caps.max_adj = 62499999;
799827
adapter->ptp_caps.n_ext_ts = 0;
800-
adapter->ptp_caps.pps = 0;
828+
adapter->ptp_caps.pps = 1;
801829
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
802830
adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210;
803831
adapter->ptp_caps.gettime = igb_ptp_gettime_i210;
804832
adapter->ptp_caps.settime = igb_ptp_settime_i210;
805-
adapter->ptp_caps.enable = igb_ptp_feature_enable;
833+
adapter->ptp_caps.enable = igb_ptp_feature_enable_i210;
806834
/* Enable the timer functions by clearing bit 31. */
807835
wr32(E1000_TSAUXC, 0x0);
808836
break;

0 commit comments

Comments
 (0)