You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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: Richard Cochran <richardcochran@gmail.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
committed by
Jeff Kirsher
parent
d339b13316
commit
7ebae8177e
@@ -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
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
/* 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 {
|
|||||||
#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 *);
|
|||||||
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 *);
|
|||||||
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 @@ exit:
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
|||||||
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 @@ out:
|
|||||||
#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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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 @@
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user