[PATCH net-next 1/1] igc: ptp: Add 1-step functionality to igc driver
From: Lasse Johnsen <hidden>
Date: 2022-09-08 22:18:43
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 <redacted> ---
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