diff options
author | Matthew Vick <matthew.vick@intel.com> | 2012-08-17 01:30:37 (GMT) |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2012-09-17 09:04:27 (GMT) |
commit | e57b8bdb4833366fd23d03a066c7eb8acc5736c7 (patch) | |
tree | a4dd980249535f34b15bbfdb83d8fd728447fc68 /drivers/net/ethernet/intel/igb/igb_ptp.c | |
parent | 1f6e8178d6851951876ad8524f4de7a0e6b111be (diff) | |
download | linux-fsl-qoriq-e57b8bdb4833366fd23d03a066c7eb8acc5736c7.tar.xz |
igb: Add 1588 support to I210/I211.
Previously I210/I211 followed the same code flow as 82580/I350 for 1588.
However, since the register sets have changed, we must update the
implementation to accommodate the register changes.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Acked-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igb/igb_ptp.c')
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ptp.c | 216 |
1 files changed, 171 insertions, 45 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index d57060c..e13ba1d 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -121,6 +121,41 @@ static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc) return val; } +/* + * SYSTIM read access for I210/I211 + */ + +static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts) +{ + struct e1000_hw *hw = &adapter->hw; + u32 sec, nsec, jk; + + /* + * The timestamp latches on lowest register read. For I210/I211, the + * lowest register is SYSTIMR. Since we only need to provide nanosecond + * resolution, we can ignore it. + */ + jk = rd32(E1000_SYSTIMR); + nsec = rd32(E1000_SYSTIML); + sec = rd32(E1000_SYSTIMH); + + ts->tv_sec = sec; + ts->tv_nsec = nsec; +} + +static void igb_ptp_write_i210(struct igb_adapter *adapter, + const struct timespec *ts) +{ + struct e1000_hw *hw = &adapter->hw; + + /* + * Writing the SYSTIMR register is not necessary as it only provides + * sub-nanosecond resolution. + */ + wr32(E1000_SYSTIML, ts->tv_nsec); + wr32(E1000_SYSTIMH, ts->tv_sec); +} + /** * igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp * @adapter: board private structure @@ -146,24 +181,28 @@ static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter, u64 ns; switch (adapter->hw.mac.type) { + case e1000_82576: + case e1000_82580: + case e1000_i350: + spin_lock_irqsave(&adapter->tmreg_lock, flags); + + ns = timecounter_cyc2time(&adapter->tc, systim); + + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = ns_to_ktime(ns); + break; case e1000_i210: case e1000_i211: - case e1000_i350: - case e1000_82580: - case e1000_82576: + memset(hwtstamps, 0, sizeof(*hwtstamps)); + /* Upper 32 bits contain s, lower 32 bits contain ns. */ + hwtstamps->hwtstamp = ktime_set(systim >> 32, + systim & 0xFFFFFFFF); break; default: - return; + break; } - - spin_lock_irqsave(&adapter->tmreg_lock, flags); - - ns = timecounter_cyc2time(&adapter->tc, systim); - - spin_unlock_irqrestore(&adapter->tmreg_lock, flags); - - memset(hwtstamps, 0, sizeof(*hwtstamps)); - hwtstamps->hwtstamp = ns_to_ktime(ns); } /* @@ -225,7 +264,7 @@ static int igb_ptp_adjfreq_82580(struct ptp_clock_info *ptp, s32 ppb) return 0; } -static int igb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta) { struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps); @@ -243,7 +282,26 @@ static int igb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) return 0; } -static int igb_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +static int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta) +{ + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, + ptp_caps); + unsigned long flags; + struct timespec now, then = ns_to_timespec(delta); + + spin_lock_irqsave(&igb->tmreg_lock, flags); + + igb_ptp_read_i210(igb, &now); + now = timespec_add(now, then); + igb_ptp_write_i210(igb, (const struct timespec *)&now); + + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + + return 0; +} + +static int igb_ptp_gettime_82576(struct ptp_clock_info *ptp, + struct timespec *ts) { struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps); @@ -263,8 +321,24 @@ static int igb_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) return 0; } -static int igb_ptp_settime(struct ptp_clock_info *ptp, - const struct timespec *ts) +static int igb_ptp_gettime_i210(struct ptp_clock_info *ptp, + struct timespec *ts) +{ + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, + ptp_caps); + unsigned long flags; + + spin_lock_irqsave(&igb->tmreg_lock, flags); + + igb_ptp_read_i210(igb, ts); + + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + + return 0; +} + +static int igb_ptp_settime_82576(struct ptp_clock_info *ptp, + const struct timespec *ts) { struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps); @@ -283,6 +357,22 @@ static int igb_ptp_settime(struct ptp_clock_info *ptp, return 0; } +static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, + const struct timespec *ts) +{ + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, + ptp_caps); + unsigned long flags; + + spin_lock_irqsave(&igb->tmreg_lock, flags); + + igb_ptp_write_i210(igb, ts); + + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + + return 0; +} + static int igb_ptp_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { @@ -320,7 +410,7 @@ static void igb_ptp_overflow_check(struct work_struct *work) container_of(work, struct igb_adapter, ptp_overflow_work.work); struct timespec ts; - igb_ptp_gettime(&igb->ptp_caps, &ts); + igb->ptp_caps.gettime(&igb->ptp_caps, &ts); pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec); @@ -506,6 +596,13 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev, if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) { tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; + + if ((hw->mac.type == e1000_i210) || + (hw->mac.type == e1000_i211)) { + regval = rd32(E1000_RXPBS); + regval |= E1000_RXPBS_CFG_TS_EN; + wr32(E1000_RXPBS, regval); + } } /* enable/disable TX */ @@ -556,7 +653,9 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev, wrfl(); /* clear TX/RX time stamp registers, just to be sure */ + regval = rd32(E1000_TXSTMPL); regval = rd32(E1000_TXSTMPH); + regval = rd32(E1000_RXSTMPL); regval = rd32(E1000_RXSTMPH); return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? @@ -569,19 +668,35 @@ void igb_ptp_init(struct igb_adapter *adapter) struct net_device *netdev = adapter->netdev; switch (hw->mac.type) { - case e1000_i210: - case e1000_i211: - case e1000_i350: + case e1000_82576: + snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); + adapter->ptp_caps.owner = THIS_MODULE; + adapter->ptp_caps.max_adj = 1000000000; + adapter->ptp_caps.n_ext_ts = 0; + adapter->ptp_caps.pps = 0; + adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; + adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; + adapter->ptp_caps.gettime = igb_ptp_gettime_82576; + adapter->ptp_caps.settime = igb_ptp_settime_82576; + adapter->ptp_caps.enable = igb_ptp_enable; + adapter->cc.read = igb_ptp_read_82576; + adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mult = 1; + adapter->cc.shift = IGB_82576_TSYNC_SHIFT; + /* Dial the nominal frequency. */ + wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); + break; case e1000_82580: + case e1000_i350: 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.pps = 0; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580; - adapter->ptp_caps.adjtime = igb_ptp_adjtime; - adapter->ptp_caps.gettime = igb_ptp_gettime; - adapter->ptp_caps.settime = igb_ptp_settime; + adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; + adapter->ptp_caps.gettime = igb_ptp_gettime_82576; + adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_enable; adapter->cc.read = igb_ptp_read_82580; adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580); @@ -590,23 +705,20 @@ void igb_ptp_init(struct igb_adapter *adapter) /* Enable the timer functions by clearing bit 31. */ wr32(E1000_TSAUXC, 0x0); break; - case e1000_82576: + case e1000_i210: + case e1000_i211: snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); adapter->ptp_caps.owner = THIS_MODULE; - adapter->ptp_caps.max_adj = 1000000000; + adapter->ptp_caps.max_adj = 62499999; adapter->ptp_caps.n_ext_ts = 0; adapter->ptp_caps.pps = 0; - adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; - adapter->ptp_caps.adjtime = igb_ptp_adjtime; - adapter->ptp_caps.gettime = igb_ptp_gettime; - adapter->ptp_caps.settime = igb_ptp_settime; + 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_enable; - adapter->cc.read = igb_ptp_read_82576; - adapter->cc.mask = CLOCKSOURCE_MASK(64); - adapter->cc.mult = 1; - adapter->cc.shift = IGB_82576_TSYNC_SHIFT; - /* Dial the nominal frequency. */ - wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); + /* Enable the timer functions by clearing bit 31. */ + wr32(E1000_TSAUXC, 0x0); break; default: adapter->ptp_clock = NULL; @@ -615,17 +727,24 @@ void igb_ptp_init(struct igb_adapter *adapter) wrfl(); - timecounter_init(&adapter->tc, &adapter->cc, - ktime_to_ns(ktime_get_real())); + spin_lock_init(&adapter->tmreg_lock); + INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); - INIT_DELAYED_WORK(&adapter->ptp_overflow_work, igb_ptp_overflow_check); + /* Initialize the clock and overflow work for devices that need it. */ + if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { + struct timespec ts = ktime_to_timespec(ktime_get_real()); - spin_lock_init(&adapter->tmreg_lock); + igb_ptp_settime_i210(&adapter->ptp_caps, &ts); + } else { + timecounter_init(&adapter->tc, &adapter->cc, + ktime_to_ns(ktime_get_real())); - INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); + INIT_DELAYED_WORK(&adapter->ptp_overflow_work, + igb_ptp_overflow_check); - schedule_delayed_work(&adapter->ptp_overflow_work, - IGB_SYSTIM_OVERFLOW_PERIOD); + schedule_delayed_work(&adapter->ptp_overflow_work, + IGB_SYSTIM_OVERFLOW_PERIOD); + } /* Initialize the time sync interrupts for devices that support it. */ if (hw->mac.type >= e1000_82580) { @@ -708,6 +827,13 @@ void igb_ptp_reset(struct igb_adapter *adapter) return; } - timecounter_init(&adapter->tc, &adapter->cc, - ktime_to_ns(ktime_get_real())); + /* 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); + } else { + timecounter_init(&adapter->tc, &adapter->cc, + ktime_to_ns(ktime_get_real())); + } } |