Skip to content

Commit

Permalink
igc: Add support for DMA timestamp for non-PTP packets
Browse files Browse the repository at this point in the history
For PTP traffic, timestamp is retrieved from TXSTMP register.
For all other packets, DMA timestamp field of the Transmit
Descriptor Write-back is used.

This is required to work around the HW time stamp misses in
TXSTAMP register due to the HW limitation, when heavy traffic
is initiated.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: Aravindhan Gunasekaran <aravindhan.gunasekaran@intel.com>
Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
  • Loading branch information
vcgomes authored and ranjan-dutta committed May 24, 2021
1 parent b0c88db commit 26a890b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 2 deletions.
4 changes: 4 additions & 0 deletions drivers/net/ethernet/intel/igc/igc.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ enum igc_tx_flags {
/* olinfo flags */
IGC_TX_FLAGS_IPV4 = 0x10,
IGC_TX_FLAGS_CSUM = 0x20,

IGC_TX_FLAGS_DMA_TSTAMP = 0x200,
};

enum igc_boards {
Expand Down Expand Up @@ -613,6 +615,8 @@ void igc_ptp_reset(struct igc_adapter *adapter);
void igc_ptp_suspend(struct igc_adapter *adapter);
void igc_ptp_stop(struct igc_adapter *adapter);
ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf);
void igc_ptp_tx_dma_tstamp(struct igc_adapter *adapter,
struct sk_buff *skb, u64 tstamp);
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
void igc_ptp_tx_hang(struct igc_adapter *adapter);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/igc/igc_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ union igc_adv_tx_desc {
__le32 olinfo_status;
} read;
struct {
__le64 rsvd; /* Reserved */
__le64 dma_tstamp;
__le32 nxtseq_seed;
__le32 status;
} wb;
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@
#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */
#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define IGC_TXD_STAT_TS_STAT 0x00000002 /* DMA Timestamp in packet */
#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */
#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
Expand Down Expand Up @@ -478,6 +479,7 @@
#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001
#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008
#define IGC_TQAVCTRL_PREEMPT_ENA 0x00000002
#define IGC_TQAVCTRL_1588_STAT_EN 0x00000004
#define IGC_TQAVCTRL_MIN_FRAG_MASK 0x0000C000
#define IGC_TQAVCTRL_MIN_FRAG_SHIFT 14

Expand Down
22 changes: 21 additions & 1 deletion drivers/net/ethernet/intel/igc/igc_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,14 @@ static int igc_tso(struct igc_ring *tx_ring,
return 1;
}

static bool igc_is_ptp_packet(struct sk_buff *skb)
{
__be16 protocol = vlan_get_protocol(skb);

/* FIXME: also handle UDP packets */
return protocol == htons(ETH_P_1588);
}

static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
struct igc_ring *tx_ring)
{
Expand Down Expand Up @@ -1447,6 +1455,7 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,

if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
bool is_ptp = igc_is_ptp_packet(skb);

spin_lock(&adapter->ptp_tx_lock);

Expand All @@ -1455,12 +1464,16 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
* timestamping request.
*/
if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
!adapter->ptp_tx_skb) {
is_ptp && !adapter->ptp_tx_skb) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGC_TX_FLAGS_TSTAMP;

adapter->ptp_tx_skb = skb_get(skb);
adapter->ptp_tx_start = jiffies;
} else if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
!is_ptp) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGC_TX_FLAGS_DMA_TSTAMP;
} else {
adapter->tx_hwtstamp_skipped++;
}
Expand Down Expand Up @@ -2693,6 +2706,13 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
if (!(eop_desc->wb.status & cpu_to_le32(IGC_TXD_STAT_DD)))
break;

if (eop_desc->wb.status & cpu_to_le32(IGC_TXD_STAT_TS_STAT) &&
tx_buffer->tx_flags & IGC_TX_FLAGS_DMA_TSTAMP) {
u64 tstamp = le64_to_cpu(eop_desc->wb.dma_tstamp);

igc_ptp_tx_dma_tstamp(adapter, tx_buffer->skb, tstamp);
}

/* clear next_to_watch to prevent false hangs */
tx_buffer->next_to_watch = NULL;

Expand Down
72 changes: 72 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,31 @@ static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,
}
}

static void igc_ptp_dma_time_to_hwtstamp(struct igc_adapter *adapter,
struct skb_shared_hwtstamps *hwtstamps,
u64 systim)
{
struct igc_hw *hw = &adapter->hw;
u32 sec, nsec;

/* FIXME: use a workqueue to read these values to avoid
* reading these registers in the hot path.
*/
nsec = rd32(IGC_SYSTIML);
sec = rd32(IGC_SYSTIMH);

switch (adapter->hw.mac.type) {
case igc_i225:
memset(hwtstamps, 0, sizeof(*hwtstamps));

/* HACK */
hwtstamps->hwtstamp = ktime_set(sec, systim & 0xFFFFFFFF);
break;
default:
break;
}
}

/**
* igc_ptp_rx_pktstamp - Retrieve timestamp from Rx packet buffer
* @adapter: Pointer to adapter the packet buffer belongs to
Expand Down Expand Up @@ -532,13 +557,26 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter)
static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
u32 tqavctrl;

tqavctrl = rd32(IGC_TQAVCTRL);
tqavctrl &= ~IGC_TQAVCTRL_1588_STAT_EN;

wr32(IGC_TQAVCTRL, tqavctrl);

wr32(IGC_TSYNCTXCTL, 0);
}

static void igc_ptp_enable_tx_timestamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
u32 tqavctrl;

/* Enable DMA Fetch timestamping */
tqavctrl = rd32(IGC_TQAVCTRL);
tqavctrl |= IGC_TQAVCTRL_1588_STAT_EN;

wr32(IGC_TQAVCTRL, tqavctrl);

wr32(IGC_TSYNCTXCTL, IGC_TSYNCTXCTL_ENABLED | IGC_TSYNCTXCTL_TXSYNSIG);

Expand Down Expand Up @@ -687,6 +725,40 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
dev_kfree_skb_any(skb);
}

void igc_ptp_tx_dma_tstamp(struct igc_adapter *adapter,
struct sk_buff *skb, u64 tstamp)
{
struct skb_shared_hwtstamps shhwtstamps;
int adjust = 0;

if (!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
return;

igc_ptp_dma_time_to_hwtstamp(adapter, &shhwtstamps, tstamp);

/* FIXME: Use different latencies for DMA timestamps? */
switch (adapter->link_speed) {
case SPEED_10:
adjust = IGC_I225_TX_LATENCY_10;
break;
case SPEED_100:
adjust = IGC_I225_TX_LATENCY_100;
break;
case SPEED_1000:
adjust = IGC_I225_TX_LATENCY_1000;
break;
case SPEED_2500:
adjust = IGC_I225_TX_LATENCY_2500;
break;
}

shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust);

/* Notify the stack and free the skb after we've unlocked */
skb_tstamp_tx(skb, &shhwtstamps);
}

/**
* igc_ptp_tx_work
* @work: pointer to work struct
Expand Down

0 comments on commit 26a890b

Please sign in to comment.