aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJacob Keller <jacob.e.keller@intel.com>2012-12-05 02:24:46 -0500
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2013-01-23 17:33:28 -0500
commit891dc0821d2089afcb04d3cace0a3522093680e7 (patch)
tree3300dfc075d53037268f162d540b1b3b4cd18a5d /drivers
parent6cb562d6681155190c52ef7603c559c284eef159 (diff)
ixgbe: Add ptp work item to poll for the Tx timestamp
This patch copies the igb implementation of Tx timestamps, which uses a work item to poll for the Tx timestamp. In addition it adds a timeout value of 15 seconds, after which it will stop polling. This is necessary due to an issue with the descriptor being marked done before the Tx timestamp event has occurred. These two events don't correlate, so using the done bit on the descriptor as indication that the timestamp must already have been taken leads to potentially dropped Tx timestamps (especially under heavy packet load) Reported-by: Matthew Vick <matthew.vick@intel.com> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h5
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c16
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c78
3 files changed, 65 insertions, 34 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 2572e1393e22..261859822ee5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -582,6 +582,9 @@ struct ixgbe_adapter {
582 582
583 struct ptp_clock *ptp_clock; 583 struct ptp_clock *ptp_clock;
584 struct ptp_clock_info ptp_caps; 584 struct ptp_clock_info ptp_caps;
585 struct work_struct ptp_tx_work;
586 struct sk_buff *ptp_tx_skb;
587 unsigned long ptp_tx_start;
585 unsigned long last_overflow_check; 588 unsigned long last_overflow_check;
586 unsigned long last_rx_ptp_check; 589 unsigned long last_rx_ptp_check;
587 spinlock_t tmreg_lock; 590 spinlock_t tmreg_lock;
@@ -752,8 +755,6 @@ extern void ixgbe_ptp_init(struct ixgbe_adapter *adapter);
752extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter); 755extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
753extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter); 756extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
754extern void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter); 757extern void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
755extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
756 struct sk_buff *skb);
757extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring, 758extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
758 union ixgbe_adv_rx_desc *rx_desc, 759 union ixgbe_adv_rx_desc *rx_desc,
759 struct sk_buff *skb); 760 struct sk_buff *skb);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index ab4328842a66..4c2e9d6564ad 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -850,9 +850,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
850 total_bytes += tx_buffer->bytecount; 850 total_bytes += tx_buffer->bytecount;
851 total_packets += tx_buffer->gso_segs; 851 total_packets += tx_buffer->gso_segs;
852 852
853 if (unlikely(tx_buffer->tx_flags & IXGBE_TX_FLAGS_TSTAMP))
854 ixgbe_ptp_tx_hwtstamp(q_vector, tx_buffer->skb);
855
856 /* free the skb */ 853 /* free the skb */
857 dev_kfree_skb_any(tx_buffer->skb); 854 dev_kfree_skb_any(tx_buffer->skb);
858 855
@@ -5880,7 +5877,6 @@ static void ixgbe_service_task(struct work_struct *work)
5880 struct ixgbe_adapter *adapter = container_of(work, 5877 struct ixgbe_adapter *adapter = container_of(work,
5881 struct ixgbe_adapter, 5878 struct ixgbe_adapter,
5882 service_task); 5879 service_task);
5883
5884 ixgbe_reset_subtask(adapter); 5880 ixgbe_reset_subtask(adapter);
5885 ixgbe_sfp_detection_subtask(adapter); 5881 ixgbe_sfp_detection_subtask(adapter);
5886 ixgbe_sfp_link_config_subtask(adapter); 5882 ixgbe_sfp_link_config_subtask(adapter);
@@ -5888,8 +5884,11 @@ static void ixgbe_service_task(struct work_struct *work)
5888 ixgbe_watchdog_subtask(adapter); 5884 ixgbe_watchdog_subtask(adapter);
5889 ixgbe_fdir_reinit_subtask(adapter); 5885 ixgbe_fdir_reinit_subtask(adapter);
5890 ixgbe_check_hang_subtask(adapter); 5886 ixgbe_check_hang_subtask(adapter);
5891 ixgbe_ptp_overflow_check(adapter); 5887
5892 ixgbe_ptp_rx_hang(adapter); 5888 if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) {
5889 ixgbe_ptp_overflow_check(adapter);
5890 ixgbe_ptp_rx_hang(adapter);
5891 }
5893 5892
5894 ixgbe_service_event_complete(adapter); 5893 ixgbe_service_event_complete(adapter);
5895} 5894}
@@ -6435,6 +6434,11 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
6435 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 6434 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
6436 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 6435 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
6437 tx_flags |= IXGBE_TX_FLAGS_TSTAMP; 6436 tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
6437
6438 /* schedule check for Tx timestamp */
6439 adapter->ptp_tx_skb = skb_get(skb);
6440 adapter->ptp_tx_start = jiffies;
6441 schedule_work(&adapter->ptp_tx_work);
6438 } 6442 }
6439 6443
6440#ifdef CONFIG_PCI_IOV 6444#ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index dcc67e2f8db4..33cb8c629354 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -96,6 +96,7 @@
96#define IXGBE_MAX_TIMEADJ_VALUE 0x7FFFFFFFFFFFFFFFULL 96#define IXGBE_MAX_TIMEADJ_VALUE 0x7FFFFFFFFFFFFFFFULL
97 97
98#define IXGBE_OVERFLOW_PERIOD (HZ * 30) 98#define IXGBE_OVERFLOW_PERIOD (HZ * 30)
99#define IXGBE_PTP_TX_TIMEOUT (HZ * 15)
99 100
100#ifndef NSECS_PER_SEC 101#ifndef NSECS_PER_SEC
101#define NSECS_PER_SEC 1000000000ULL 102#define NSECS_PER_SEC 1000000000ULL
@@ -401,7 +402,6 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
401 } 402 }
402} 403}
403 404
404
405/** 405/**
406 * ixgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow 406 * ixgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow
407 * @adapter: private adapter struct 407 * @adapter: private adapter struct
@@ -416,8 +416,7 @@ void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter)
416 IXGBE_OVERFLOW_PERIOD); 416 IXGBE_OVERFLOW_PERIOD);
417 struct timespec ts; 417 struct timespec ts;
418 418
419 if ((adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) && 419 if (timeout) {
420 (timeout)) {
421 ixgbe_ptp_gettime(&adapter->ptp_caps, &ts); 420 ixgbe_ptp_gettime(&adapter->ptp_caps, &ts);
422 adapter->last_overflow_check = jiffies; 421 adapter->last_overflow_check = jiffies;
423 } 422 }
@@ -467,48 +466,68 @@ void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter)
467 466
468/** 467/**
469 * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp 468 * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
470 * @q_vector: structure containing interrupt and ring information 469 * @adapter: the private adapter struct
471 * @skb: particular skb to send timestamp with
472 * 470 *
473 * if the timestamp is valid, we convert it into the timecounter ns 471 * if the timestamp is valid, we convert it into the timecounter ns
474 * value, then store that result into the shhwtstamps structure which 472 * value, then store that result into the shhwtstamps structure which
475 * is passed up the network stack 473 * is passed up the network stack
476 */ 474 */
477void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector, 475static void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter)
478 struct sk_buff *skb)
479{ 476{
480 struct ixgbe_adapter *adapter; 477 struct ixgbe_hw *hw = &adapter->hw;
481 struct ixgbe_hw *hw;
482 struct skb_shared_hwtstamps shhwtstamps; 478 struct skb_shared_hwtstamps shhwtstamps;
483 u64 regval = 0, ns; 479 u64 regval = 0, ns;
484 u32 tsynctxctl;
485 unsigned long flags; 480 unsigned long flags;
486 481
487 /* we cannot process timestamps on a ring without a q_vector */
488 if (!q_vector || !q_vector->adapter)
489 return;
490
491 adapter = q_vector->adapter;
492 hw = &adapter->hw;
493
494 tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
495 regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL); 482 regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
496 regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32; 483 regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32;
497 484
498 /*
499 * if TX timestamp is not valid, exit after clearing the
500 * timestamp registers
501 */
502 if (!(tsynctxctl & IXGBE_TSYNCTXCTL_VALID))
503 return;
504
505 spin_lock_irqsave(&adapter->tmreg_lock, flags); 485 spin_lock_irqsave(&adapter->tmreg_lock, flags);
506 ns = timecounter_cyc2time(&adapter->tc, regval); 486 ns = timecounter_cyc2time(&adapter->tc, regval);
507 spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 487 spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
508 488
509 memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 489 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
510 shhwtstamps.hwtstamp = ns_to_ktime(ns); 490 shhwtstamps.hwtstamp = ns_to_ktime(ns);
511 skb_tstamp_tx(skb, &shhwtstamps); 491 skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
492
493 dev_kfree_skb_any(adapter->ptp_tx_skb);
494 adapter->ptp_tx_skb = NULL;
495}
496
497/**
498 * ixgbe_ptp_tx_hwtstamp_work
499 * @work: pointer to the work struct
500 *
501 * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware
502 * timestamp has been taken for the current skb. It is necesary, because the
503 * descriptor's "done" bit does not correlate with the timestamp event.
504 */
505static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
506{
507 struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter,
508 ptp_tx_work);
509 struct ixgbe_hw *hw = &adapter->hw;
510 bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
511 IXGBE_PTP_TX_TIMEOUT);
512 u32 tsynctxctl;
513
514 /* we have to have a valid skb */
515 if (!adapter->ptp_tx_skb)
516 return;
517
518 if (timeout) {
519 dev_kfree_skb_any(adapter->ptp_tx_skb);
520 adapter->ptp_tx_skb = NULL;
521 e_warn(drv, "clearing Tx Timestamp hang");
522 return;
523 }
524
525 tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
526 if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID)
527 ixgbe_ptp_tx_hwtstamp(adapter);
528 else
529 /* reschedule to keep checking if it's not available yet */
530 schedule_work(&adapter->ptp_tx_work);
512} 531}
513 532
514/** 533/**
@@ -865,6 +884,7 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
865 } 884 }
866 885
867 spin_lock_init(&adapter->tmreg_lock); 886 spin_lock_init(&adapter->tmreg_lock);
887 INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work);
868 888
869 adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, 889 adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
870 &adapter->pdev->dev); 890 &adapter->pdev->dev);
@@ -896,6 +916,12 @@ void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
896 916
897 ixgbe_ptp_setup_sdp(adapter); 917 ixgbe_ptp_setup_sdp(adapter);
898 918
919 cancel_work_sync(&adapter->ptp_tx_work);
920 if (adapter->ptp_tx_skb) {
921 dev_kfree_skb_any(adapter->ptp_tx_skb);
922 adapter->ptp_tx_skb = NULL;
923 }
924
899 if (adapter->ptp_clock) { 925 if (adapter->ptp_clock) {
900 ptp_clock_unregister(adapter->ptp_clock); 926 ptp_clock_unregister(adapter->ptp_clock);
901 adapter->ptp_clock = NULL; 927 adapter->ptp_clock = NULL;