[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <44B51F36-B54D-47EB-8CDD-9A63432E9B80@timebeat.app>
Date: Thu, 8 Sep 2022 23:18:35 +0100
From: Lasse Johnsen <lasse@...ebeat.app>
To: netdev@...r.kernel.org, Tony Nguyen <anthony.l.nguyen@...el.com>,
Jesse Brandeburg <jesse.brandeburg@...el.com>
Cc: "Stanton, Kevin B" <kevin.b.stanton@...el.com>,
Jonathan Lemon <bsd@...com>,
Richard Cochran <richardcochran@...il.com>
Subject: [PATCH net-next 1/1] igc: ptp: Add 1-step functionality to igc driver
This patch adds 1-step functionality to the igc driver
1-step is only supported in L2 PTP
(... as the hardware can update the FCS, but not the UDP checksum on the fly..)
Signed-off-by: Lasse Johnsen <lasse@...ebeat.app>
---
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 1e7e707..70d9440 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -247,6 +247,8 @@ struct igc_adapter {
struct timespec64 start;
struct timespec64 period;
} perout[IGC_N_PEROUT];
+
+ bool onestep_discard;
};
void igc_up(struct igc_adapter *adapter);
@@ -403,13 +405,14 @@ enum igc_state_t {
enum igc_tx_flags {
/* cmd_type flags */
- IGC_TX_FLAGS_VLAN = 0x01,
- IGC_TX_FLAGS_TSO = 0x02,
- IGC_TX_FLAGS_TSTAMP = 0x04,
+ IGC_TX_FLAGS_VLAN = 0x01,
+ IGC_TX_FLAGS_TSO = 0x02,
+ IGC_TX_FLAGS_TSTAMP = 0x04,
+ IGC_TX_FLAGS_ONESTEP_SYNC = 0x08,
/* olinfo flags */
- IGC_TX_FLAGS_IPV4 = 0x10,
- IGC_TX_FLAGS_CSUM = 0x20,
+ IGC_TX_FLAGS_IPV4 = 0x10,
+ IGC_TX_FLAGS_CSUM = 0x20,
};
enum igc_boards {
@@ -631,6 +634,7 @@ 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);
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
+bool igc_ptp_process_onestep(struct igc_adapter *adapter, struct sk_buff *skb);
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h
index ce530f5..a7106b5 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.h
+++ b/drivers/net/ethernet/intel/igc/igc_base.h
@@ -31,6 +31,7 @@ struct igc_adv_tx_context_desc {
};
/* Adv Transmit Descriptor Config Masks */
+#define IGC_ADVTXD_ONESTEP 0x00040000 /* IEEE1588 perform one-step */
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 8cc077b..cba34ae 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1536,7 +1536,8 @@ static int igc_ethtool_get_ts_info(struct net_device *dev,
info->tx_types =
BIT(HWTSTAMP_TX_OFF) |
- BIT(HWTSTAMP_TX_ON);
+ BIT(HWTSTAMP_TX_ON) |
+ BIT(HWTSTAMP_TX_ONESTEP_SYNC);
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index a5ebee7..713da04 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1260,6 +1260,9 @@ static int igc_tx_map(struct igc_ring *tx_ring,
cmd_type |= size | IGC_TXD_DCMD;
tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
+ if (first->tx_flags & IGC_TX_FLAGS_ONESTEP_SYNC)
+ tx_desc->read.cmd_type_len |= IGC_ADVTXD_ONESTEP;
+
netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
/* set the timestamp */
@@ -1452,12 +1455,19 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
* the other timer registers before skipping the
* timestamping request.
*/
- if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON &&
+
+ if (adapter->tstamp_config.tx_type >= HWTSTAMP_TX_ON &&
!test_and_set_bit_lock(__IGC_PTP_TX_IN_PROGRESS,
&adapter->state)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGC_TX_FLAGS_TSTAMP;
+ if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ONESTEP_SYNC &&
+ igc_ptp_process_onestep(adapter, skb)) {
+ tx_flags |= IGC_TX_FLAGS_ONESTEP_SYNC;
+ adapter->onestep_discard = true;
+ }
+
adapter->ptp_tx_skb = skb_get(skb);
adapter->ptp_tx_start = jiffies;
} else {
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 653e9f1..dc57339 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -21,6 +21,9 @@
#define IGC_PTM_STAT_SLEEP 2
#define IGC_PTM_STAT_TIMEOUT 100
+#define IGC_PTP_TX_ONESTEP_L2_OFFSET 48
+#define IGC_PTP_TX_ONESTEP_L2_IN_VLAN_OFFSET 52
+
/* SYSTIM read access for I225 */
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts)
{
@@ -550,6 +553,35 @@ static void igc_ptp_enable_tx_timestamp(struct igc_adapter *adapter)
rd32(IGC_TXSTMPH);
}
+static void igc_ptp_update_1588_offset_in_tsynctxctl(struct igc_adapter *adapter, int ptp_class)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 onestep_offset = (rd32(IGC_TSYNCTXCTL) & 0xFF00) >> 8;
+
+ if ((ptp_class & PTP_CLASS_VLAN) &&
+ onestep_offset != IGC_PTP_TX_ONESTEP_L2_IN_VLAN_OFFSET) {
+ wr32(IGC_TSYNCTXCTL, IGC_TSYNCTXCTL_ENABLED | IGC_TSYNCTXCTL_TXSYNSIG |
+ (IGC_PTP_TX_ONESTEP_L2_IN_VLAN_OFFSET << 8));
+ } else if (!(ptp_class & PTP_CLASS_VLAN) &&
+ onestep_offset != IGC_PTP_TX_ONESTEP_L2_OFFSET) {
+ wr32(IGC_TSYNCTXCTL, IGC_TSYNCTXCTL_ENABLED | IGC_TSYNCTXCTL_TXSYNSIG |
+ (IGC_PTP_TX_ONESTEP_L2_OFFSET << 8));
+ }
+}
+
+bool igc_ptp_process_onestep(struct igc_adapter *adapter, struct sk_buff *skb)
+{
+ unsigned int ptp_class = ptp_classify_raw(skb);
+
+ if ((ptp_class & PTP_CLASS_L2) && (ptp_class & PTP_CLASS_V2)) {
+ if (ptp_msg_is_sync(skb, ptp_class)) {
+ igc_ptp_update_1588_offset_in_tsynctxctl(adapter, ptp_class);
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* igc_ptp_set_timestamp_mode - setup hardware for timestamping
* @adapter: networking device structure
@@ -564,6 +596,7 @@ static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter,
case HWTSTAMP_TX_OFF:
igc_ptp_disable_tx_timestamp(adapter);
break;
+ case HWTSTAMP_TX_ONESTEP_SYNC:
case HWTSTAMP_TX_ON:
igc_ptp_enable_tx_timestamp(adapter);
break;
@@ -603,6 +636,9 @@ static void igc_ptp_tx_timeout(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
+ if (adapter->onestep_discard)
+ adapter->onestep_discard = false;
+
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
adapter->tx_hwtstamp_timeouts++;
@@ -671,16 +707,14 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
- /* Clear the lock early before calling skb_tstamp_tx so that
- * applications are not woken up before the lock bit is clear. We use
- * a copy of the skb pointer to ensure other threads can't change it
- * while we're notifying the stack.
- */
+ if (adapter->onestep_discard)
+ adapter->onestep_discard = false;
+ else
+ skb_tstamp_tx(skb, &shhwtstamps);
+
adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state);
- /* Notify the stack and free the skb after we've unlocked */
- skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
}
@@ -959,6 +993,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
+ adapter->onestep_discard = false;
adapter->prev_ptp_time = ktime_to_timespec64(ktime_get_real());
adapter->ptp_reset_start = ktime_get();
--
2.37.3
Powered by blists - more mailing lists