Commit 7ebae817 authored by Richard Cochran's avatar Richard Cochran Committed by Jeff Kirsher

igb: offer a PTP Hardware Clock instead of the timecompare method

This commit removes the legacy timecompare code from the igb driver and
offers a tunable PHC instead.
Signed-off-by: default avatarRichard Cochran <richardcochran@gmail.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent d339b133
...@@ -120,6 +120,17 @@ config IGB_DCA ...@@ -120,6 +120,17 @@ config IGB_DCA
driver. DCA is a method for warming the CPU cache before data driver. DCA is a method for warming the CPU cache before data
is used, with the intent of lessening the impact of cache misses. is used, with the intent of lessening the impact of cache misses.
config IGB_PTP
bool "PTP Hardware Clock (PHC)"
default y
depends on IGB && PTP_1588_CLOCK
---help---
Say Y here if you want to use PTP Hardware Clock (PHC) in the
driver. Only the basic clock operations have been implemented.
Every timestamp and clock read operations must consult the
overflow counter to form a correct time value.
config IGBVF config IGBVF
tristate "Intel(R) 82576 Virtual Function Ethernet support" tristate "Intel(R) 82576 Virtual Function Ethernet support"
depends on PCI depends on PCI
......
...@@ -35,3 +35,4 @@ obj-$(CONFIG_IGB) += igb.o ...@@ -35,3 +35,4 @@ obj-$(CONFIG_IGB) += igb.o
igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o
igb-$(CONFIG_IGB_PTP) += igb_ptp.o
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include "e1000_82575.h" #include "e1000_82575.h"
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/timecompare.h>
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -329,9 +328,6 @@ struct igb_adapter { ...@@ -329,9 +328,6 @@ struct igb_adapter {
/* OS defined structs */ /* OS defined structs */
struct pci_dev *pdev; struct pci_dev *pdev;
struct cyclecounter cycles;
struct timecounter clock;
struct timecompare compare;
struct hwtstamp_config hwtstamp_config; struct hwtstamp_config hwtstamp_config;
spinlock_t stats64_lock; spinlock_t stats64_lock;
...@@ -386,7 +382,6 @@ struct igb_adapter { ...@@ -386,7 +382,6 @@ struct igb_adapter {
#define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coal Flush */ #define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coal Flush */
#define IGB_82576_TSYNC_SHIFT 19 #define IGB_82576_TSYNC_SHIFT 19
#define IGB_82580_TSYNC_SHIFT 24
#define IGB_TS_HDR_LEN 16 #define IGB_TS_HDR_LEN 16
enum e1000_state_t { enum e1000_state_t {
__IGB_TESTING, __IGB_TESTING,
...@@ -422,7 +417,15 @@ extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *); ...@@ -422,7 +417,15 @@ extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *);
extern bool igb_has_link(struct igb_adapter *adapter); extern bool igb_has_link(struct igb_adapter *adapter);
extern void igb_set_ethtool_ops(struct net_device *); extern void igb_set_ethtool_ops(struct net_device *);
extern void igb_power_up_link(struct igb_adapter *); extern void igb_power_up_link(struct igb_adapter *);
#ifdef CONFIG_IGB_PTP
extern void igb_ptp_init(struct igb_adapter *adapter);
extern void igb_ptp_remove(struct igb_adapter *adapter);
extern void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
struct skb_shared_hwtstamps *hwtstamps,
u64 systim);
#endif
static inline s32 igb_reset_phy(struct e1000_hw *hw) static inline s32 igb_reset_phy(struct e1000_hw *hw)
{ {
if (hw->phy.ops.reset) if (hw->phy.ops.reset)
......
...@@ -114,7 +114,6 @@ static void igb_free_all_rx_resources(struct igb_adapter *); ...@@ -114,7 +114,6 @@ static void igb_free_all_rx_resources(struct igb_adapter *);
static void igb_setup_mrqc(struct igb_adapter *); static void igb_setup_mrqc(struct igb_adapter *);
static int igb_probe(struct pci_dev *, const struct pci_device_id *); static int igb_probe(struct pci_dev *, const struct pci_device_id *);
static void __devexit igb_remove(struct pci_dev *pdev); static void __devexit igb_remove(struct pci_dev *pdev);
static void igb_init_hw_timer(struct igb_adapter *adapter);
static int igb_sw_init(struct igb_adapter *); static int igb_sw_init(struct igb_adapter *);
static int igb_open(struct net_device *); static int igb_open(struct net_device *);
static int igb_close(struct net_device *); static int igb_close(struct net_device *);
...@@ -565,33 +564,6 @@ static void igb_dump(struct igb_adapter *adapter) ...@@ -565,33 +564,6 @@ static void igb_dump(struct igb_adapter *adapter)
return; return;
} }
/**
* igb_read_clock - read raw cycle counter (to be used by time counter)
*/
static cycle_t igb_read_clock(const struct cyclecounter *tc)
{
struct igb_adapter *adapter =
container_of(tc, struct igb_adapter, cycles);
struct e1000_hw *hw = &adapter->hw;
u64 stamp = 0;
int shift = 0;
/*
* The timestamp latches on lowest register read. For the 82580
* the lowest register is SYSTIMR instead of SYSTIML. However we never
* adjusted TIMINCA so SYSTIMR will just read as all 0s so ignore it.
*/
if (hw->mac.type >= e1000_82580) {
stamp = rd32(E1000_SYSTIMR) >> 8;
shift = IGB_82580_TSYNC_SHIFT;
}
stamp |= (u64)rd32(E1000_SYSTIML) << shift;
stamp |= (u64)rd32(E1000_SYSTIMH) << (shift + 32);
return stamp;
}
/** /**
* igb_get_hw_dev - return device * igb_get_hw_dev - return device
* used by hardware layer to print debugging information * used by hardware layer to print debugging information
...@@ -2110,9 +2082,11 @@ static int __devinit igb_probe(struct pci_dev *pdev, ...@@ -2110,9 +2082,11 @@ static int __devinit igb_probe(struct pci_dev *pdev,
} }
#endif #endif
#ifdef CONFIG_IGB_PTP
/* do hw tstamp init after resetting */ /* do hw tstamp init after resetting */
igb_init_hw_timer(adapter); igb_ptp_init(adapter);
#endif
dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
/* print bus type/speed/width info */ /* print bus type/speed/width info */
dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n", dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
...@@ -2184,7 +2158,10 @@ static void __devexit igb_remove(struct pci_dev *pdev) ...@@ -2184,7 +2158,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
pm_runtime_get_noresume(&pdev->dev); pm_runtime_get_noresume(&pdev->dev);
#ifdef CONFIG_IGB_PTP
igb_ptp_remove(adapter);
#endif
/* /*
* The watchdog timer may be rescheduled, so explicitly * The watchdog timer may be rescheduled, so explicitly
* disable watchdog from being rescheduled. * disable watchdog from being rescheduled.
...@@ -2303,112 +2280,6 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter) ...@@ -2303,112 +2280,6 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)
#endif /* CONFIG_PCI_IOV */ #endif /* CONFIG_PCI_IOV */
} }
/**
* igb_init_hw_timer - Initialize hardware timer used with IEEE 1588 timestamp
* @adapter: board private structure to initialize
*
* igb_init_hw_timer initializes the function pointer and values for the hw
* timer found in hardware.
**/
static void igb_init_hw_timer(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
switch (hw->mac.type) {
case e1000_i350:
case e1000_82580:
memset(&adapter->cycles, 0, sizeof(adapter->cycles));
adapter->cycles.read = igb_read_clock;
adapter->cycles.mask = CLOCKSOURCE_MASK(64);
adapter->cycles.mult = 1;
/*
* The 82580 timesync updates the system timer every 8ns by 8ns
* and the value cannot be shifted. Instead we need to shift
* the registers to generate a 64bit timer value. As a result
* SYSTIMR/L/H, TXSTMPL/H, RXSTMPL/H all have to be shifted by
* 24 in order to generate a larger value for synchronization.
*/
adapter->cycles.shift = IGB_82580_TSYNC_SHIFT;
/* disable system timer temporarily by setting bit 31 */
wr32(E1000_TSAUXC, 0x80000000);
wrfl();
/* Set registers so that rollover occurs soon to test this. */
wr32(E1000_SYSTIMR, 0x00000000);
wr32(E1000_SYSTIML, 0x80000000);
wr32(E1000_SYSTIMH, 0x000000FF);
wrfl();
/* enable system timer by clearing bit 31 */
wr32(E1000_TSAUXC, 0x0);
wrfl();
timecounter_init(&adapter->clock,
&adapter->cycles,
ktime_to_ns(ktime_get_real()));
/*
* Synchronize our NIC clock against system wall clock. NIC
* time stamp reading requires ~3us per sample, each sample
* was pretty stable even under load => only require 10
* samples for each offset comparison.
*/
memset(&adapter->compare, 0, sizeof(adapter->compare));
adapter->compare.source = &adapter->clock;
adapter->compare.target = ktime_get_real;
adapter->compare.num_samples = 10;
timecompare_update(&adapter->compare, 0);
break;
case e1000_82576:
/*
* Initialize hardware timer: we keep it running just in case
* that some program needs it later on.
*/
memset(&adapter->cycles, 0, sizeof(adapter->cycles));
adapter->cycles.read = igb_read_clock;
adapter->cycles.mask = CLOCKSOURCE_MASK(64);
adapter->cycles.mult = 1;
/**
* Scale the NIC clock cycle by a large factor so that
* relatively small clock corrections can be added or
* subtracted at each clock tick. The drawbacks of a large
* factor are a) that the clock register overflows more quickly
* (not such a big deal) and b) that the increment per tick has
* to fit into 24 bits. As a result we need to use a shift of
* 19 so we can fit a value of 16 into the TIMINCA register.
*/
adapter->cycles.shift = IGB_82576_TSYNC_SHIFT;
wr32(E1000_TIMINCA,
(1 << E1000_TIMINCA_16NS_SHIFT) |
(16 << IGB_82576_TSYNC_SHIFT));
/* Set registers so that rollover occurs soon to test this. */
wr32(E1000_SYSTIML, 0x00000000);
wr32(E1000_SYSTIMH, 0xFF800000);
wrfl();
timecounter_init(&adapter->clock,
&adapter->cycles,
ktime_to_ns(ktime_get_real()));
/*
* Synchronize our NIC clock against system wall clock. NIC
* time stamp reading requires ~3us per sample, each sample
* was pretty stable even under load => only require 10
* samples for each offset comparison.
*/
memset(&adapter->compare, 0, sizeof(adapter->compare));
adapter->compare.source = &adapter->clock;
adapter->compare.target = ktime_get_real;
adapter->compare.num_samples = 10;
timecompare_update(&adapter->compare, 0);
break;
case e1000_82575:
/* 82575 does not support timesync */
default:
break;
}
}
/** /**
* igb_sw_init - Initialize general software structures (struct igb_adapter) * igb_sw_init - Initialize general software structures (struct igb_adapter)
* @adapter: board private structure to initialize * @adapter: board private structure to initialize
...@@ -5718,35 +5589,7 @@ static int igb_poll(struct napi_struct *napi, int budget) ...@@ -5718,35 +5589,7 @@ static int igb_poll(struct napi_struct *napi, int budget)
return 0; return 0;
} }
/** #ifdef CONFIG_IGB_PTP
* igb_systim_to_hwtstamp - convert system time value to hw timestamp
* @adapter: board private structure
* @shhwtstamps: timestamp structure to update
* @regval: unsigned 64bit system time value.
*
* We need to convert the system time value stored in the RX/TXSTMP registers
* into a hwtstamp which can be used by the upper level timestamping functions
*/
static void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
struct skb_shared_hwtstamps *shhwtstamps,
u64 regval)
{
u64 ns;
/*
* The 82580 starts with 1ns at bit 0 in RX/TXSTMPL, shift this up to
* 24 to match clock shift we setup earlier.
*/
if (adapter->hw.mac.type >= e1000_82580)
regval <<= IGB_82580_TSYNC_SHIFT;
ns = timecounter_cyc2time(&adapter->clock, regval);
timecompare_update(&adapter->compare, ns);
memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamps->hwtstamp = ns_to_ktime(ns);
shhwtstamps->syststamp = timecompare_transform(&adapter->compare, ns);
}
/** /**
* igb_tx_hwtstamp - utility function which checks for TX time stamp * igb_tx_hwtstamp - utility function which checks for TX time stamp
* @q_vector: pointer to q_vector containing needed info * @q_vector: pointer to q_vector containing needed info
...@@ -5776,6 +5619,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, ...@@ -5776,6 +5619,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector,
skb_tstamp_tx(buffer_info->skb, &shhwtstamps); skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
} }
#endif
/** /**
* igb_clean_tx_irq - Reclaim resources after transmit completes * igb_clean_tx_irq - Reclaim resources after transmit completes
* @q_vector: pointer to q_vector containing needed info * @q_vector: pointer to q_vector containing needed info
...@@ -5819,9 +5663,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) ...@@ -5819,9 +5663,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
total_bytes += tx_buffer->bytecount; total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs; total_packets += tx_buffer->gso_segs;
#ifdef CONFIG_IGB_PTP
/* retrieve hardware timestamp */ /* retrieve hardware timestamp */
igb_tx_hwtstamp(q_vector, tx_buffer); igb_tx_hwtstamp(q_vector, tx_buffer);
#endif
/* free the skb */ /* free the skb */
dev_kfree_skb_any(tx_buffer->skb); dev_kfree_skb_any(tx_buffer->skb);
tx_buffer->skb = NULL; tx_buffer->skb = NULL;
...@@ -5993,6 +5839,7 @@ static inline void igb_rx_hash(struct igb_ring *ring, ...@@ -5993,6 +5839,7 @@ static inline void igb_rx_hash(struct igb_ring *ring,
skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
} }
#ifdef CONFIG_IGB_PTP
static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,
union e1000_adv_rx_desc *rx_desc, union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -6032,6 +5879,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, ...@@ -6032,6 +5879,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,
igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
} }
#endif
static void igb_rx_vlan(struct igb_ring *ring, static void igb_rx_vlan(struct igb_ring *ring,
union e1000_adv_rx_desc *rx_desc, union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -6142,7 +5990,9 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget) ...@@ -6142,7 +5990,9 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
goto next_desc; goto next_desc;
} }
#ifdef CONFIG_IGB_PTP
igb_rx_hwtstamp(q_vector, rx_desc, skb); igb_rx_hwtstamp(q_vector, rx_desc, skb);
#endif
igb_rx_hash(rx_ring, rx_desc, skb); igb_rx_hash(rx_ring, rx_desc, skb);
igb_rx_checksum(rx_ring, rx_desc, skb); igb_rx_checksum(rx_ring, rx_desc, skb);
igb_rx_vlan(rx_ring, rx_desc, skb); igb_rx_vlan(rx_ring, rx_desc, skb);
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#define ISGN 0x80000000 #define ISGN 0x80000000
/* /*
* The 82580 timesync updates the system timer every 8ns by 8ns,
* and this update value cannot be reprogrammed.
*
* Neither the 82576 nor the 82580 offer registers wide enough to hold * Neither the 82576 nor the 82580 offer registers wide enough to hold
* nanoseconds time values for very long. For the 82580, SYSTIM always * nanoseconds time values for very long. For the 82580, SYSTIM always
* counts nanoseconds, but the upper 24 bits are not availible. The * counts nanoseconds, but the upper 24 bits are not availible. The
...@@ -38,6 +41,14 @@ ...@@ -38,6 +41,14 @@
* field are needed to provide the nominal 16 nanosecond period, * field are needed to provide the nominal 16 nanosecond period,
* leaving 19 bits for fractional nanoseconds. * leaving 19 bits for fractional nanoseconds.
* *
* We scale the NIC clock cycle by a large factor so that relatively
* small clock corrections can be added or subtracted at each clock
* tick. The drawbacks of a large factor are a) that the clock
* register overflows more quickly (not such a big deal) and b) that
* the increment per tick has to fit into 24 bits. As a result we
* need to use a shift of 19 so we can fit a value of 16 into the
* TIMINCA register.
*
* *
* SYSTIMH SYSTIML * SYSTIMH SYSTIML
* +--------------+ +---+---+------+ * +--------------+ +---+---+------+
...@@ -95,6 +106,11 @@ static cycle_t igb_82580_systim_read(const struct cyclecounter *cc) ...@@ -95,6 +106,11 @@ static cycle_t igb_82580_systim_read(const struct cyclecounter *cc)
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
struct e1000_hw *hw = &igb->hw; struct e1000_hw *hw = &igb->hw;
/*
* The timestamp latches on lowest register read. For the 82580
* the lowest register is SYSTIMR instead of SYSTIML. However we only
* need to provide nanosecond resolution, so we just ignore it.
*/
jk = rd32(E1000_SYSTIMR); jk = rd32(E1000_SYSTIMR);
lo = rd32(E1000_SYSTIML); lo = rd32(E1000_SYSTIML);
hi = rd32(E1000_SYSTIMH); hi = rd32(E1000_SYSTIMH);
...@@ -320,3 +336,46 @@ void igb_ptp_remove(struct igb_adapter *adapter) ...@@ -320,3 +336,46 @@ void igb_ptp_remove(struct igb_adapter *adapter)
adapter->netdev->name); adapter->netdev->name);
} }
} }
/**
* igb_systim_to_hwtstamp - convert system time value to hw timestamp
* @adapter: board private structure
* @hwtstamps: timestamp structure to update
* @systim: unsigned 64bit system time value.
*
* We need to convert the system time value stored in the RX/TXSTMP registers
* into a hwtstamp which can be used by the upper level timestamping functions.
*
* The 'tmreg_lock' spinlock is used to protect the consistency of the
* system time value. This is needed because reading the 64 bit time
* value involves reading two (or three) 32 bit registers. The first
* read latches the value. Ditto for writing.
*
* In addition, here have extended the system time with an overflow
* counter in software.
**/
void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
struct skb_shared_hwtstamps *hwtstamps,
u64 systim)
{
u64 ns;
unsigned long flags;
switch (adapter->hw.mac.type) {
case e1000_i350:
case e1000_82580:
case e1000_82576:
break;
default:
return;
}
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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment