]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
eth: fbnic: add TX packets timestamping support
authorVadim Fedorenko <vadfed@meta.com>
Tue, 8 Oct 2024 18:14:35 +0000 (11:14 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 10 Oct 2024 10:52:11 +0000 (12:52 +0200)
Add TX configuration to ethtool interface. Add processing of TX
timestamp completions as well as configuration to request HW to create
TX timestamp completion.

Signed-off-by: Vadim Fedorenko <vadfed@meta.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c

index 3afb7227574a794ce0401e3650a8f96c56c7da4e..24e05944326424ba3680ae95e18020e7fe770b68 100644 (file)
@@ -16,9 +16,14 @@ fbnic_get_ts_info(struct net_device *netdev,
 
        tsinfo->so_timestamping =
                SOF_TIMESTAMPING_TX_SOFTWARE |
+               SOF_TIMESTAMPING_TX_HARDWARE |
                SOF_TIMESTAMPING_RX_HARDWARE |
                SOF_TIMESTAMPING_RAW_HARDWARE;
 
+       tsinfo->tx_types =
+               BIT(HWTSTAMP_TX_OFF) |
+               BIT(HWTSTAMP_TX_ON);
+
        tsinfo->rx_filters =
                BIT(HWTSTAMP_FILTER_NONE) |
                BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
index cbf7a6c6331a35ac5952e75bfeb828e8cb49d959..2e3d06946e7478d3c0a1049d4652975b3c5a1e09 100644 (file)
 #include "fbnic_netdev.h"
 #include "fbnic_txrx.h"
 
+enum {
+       FBNIC_XMIT_CB_TS        = 0x01,
+};
+
 struct fbnic_xmit_cb {
        u32 bytecount;
        u8 desc_count;
+       u8 flags;
        int hw_head;
 };
 
@@ -150,11 +155,32 @@ static void fbnic_unmap_page_twd(struct device *dev, __le64 *twd)
 #define FBNIC_TWD_TYPE(_type) \
        cpu_to_le64(FIELD_PREP(FBNIC_TWD_TYPE_MASK, FBNIC_TWD_TYPE_##_type))
 
+static bool fbnic_tx_tstamp(struct sk_buff *skb)
+{
+       struct fbnic_net *fbn;
+
+       if (!unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+               return false;
+
+       fbn = netdev_priv(skb->dev);
+       if (fbn->hwtstamp_config.tx_type == HWTSTAMP_TX_OFF)
+               return false;
+
+       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+       FBNIC_XMIT_CB(skb)->flags |= FBNIC_XMIT_CB_TS;
+       FBNIC_XMIT_CB(skb)->hw_head = -1;
+
+       return true;
+}
+
 static bool
 fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
 {
        unsigned int l2len, i3len;
 
+       if (fbnic_tx_tstamp(skb))
+               *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_TS);
+
        if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL))
                return false;
 
@@ -374,6 +400,12 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget,
                if (desc_cnt > clean_desc)
                        break;
 
+               if (unlikely(FBNIC_XMIT_CB(skb)->flags & FBNIC_XMIT_CB_TS)) {
+                       FBNIC_XMIT_CB(skb)->hw_head = hw_head;
+                       if (likely(!discard))
+                               break;
+               }
+
                ring->tx_buf[head] = NULL;
 
                clean_desc -= desc_cnt;
@@ -427,6 +459,53 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget,
                                 FBNIC_TX_DESC_WAKEUP);
 }
 
+static void fbnic_clean_tsq(struct fbnic_napi_vector *nv,
+                           struct fbnic_ring *ring,
+                           u64 tcd, int *ts_head, int *head0)
+{
+       struct skb_shared_hwtstamps hwtstamp;
+       struct fbnic_net *fbn;
+       struct sk_buff *skb;
+       int head;
+       u64 ns;
+
+       head = (*ts_head < 0) ? ring->head : *ts_head;
+
+       do {
+               unsigned int desc_cnt;
+
+               if (head == ring->tail) {
+                       if (unlikely(net_ratelimit()))
+                               netdev_err(nv->napi.dev,
+                                          "Tx timestamp without matching packet\n");
+                       return;
+               }
+
+               skb = ring->tx_buf[head];
+               desc_cnt = FBNIC_XMIT_CB(skb)->desc_count;
+
+               head += desc_cnt;
+               head &= ring->size_mask;
+       } while (!(FBNIC_XMIT_CB(skb)->flags & FBNIC_XMIT_CB_TS));
+
+       fbn = netdev_priv(nv->napi.dev);
+       ns = fbnic_ts40_to_ns(fbn, FIELD_GET(FBNIC_TCD_TYPE1_TS_MASK, tcd));
+
+       memset(&hwtstamp, 0, sizeof(hwtstamp));
+       hwtstamp.hwtstamp = ns_to_ktime(ns);
+
+       *ts_head = head;
+
+       FBNIC_XMIT_CB(skb)->flags &= ~FBNIC_XMIT_CB_TS;
+       if (*head0 < 0) {
+               head = FBNIC_XMIT_CB(skb)->hw_head;
+               if (head >= 0)
+                       *head0 = head;
+       }
+
+       skb_tstamp_tx(skb, &hwtstamp);
+}
+
 static void fbnic_page_pool_init(struct fbnic_ring *ring, unsigned int idx,
                                 struct page *page)
 {
@@ -460,10 +539,12 @@ static void fbnic_page_pool_drain(struct fbnic_ring *ring, unsigned int idx,
 }
 
 static void fbnic_clean_twq(struct fbnic_napi_vector *nv, int napi_budget,
-                           struct fbnic_q_triad *qt, s32 head0)
+                           struct fbnic_q_triad *qt, s32 ts_head, s32 head0)
 {
        if (head0 >= 0)
                fbnic_clean_twq0(nv, napi_budget, &qt->sub0, false, head0);
+       else if (ts_head >= 0)
+               fbnic_clean_twq0(nv, napi_budget, &qt->sub0, false, ts_head);
 }
 
 static void
@@ -471,9 +552,9 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt,
                int napi_budget)
 {
        struct fbnic_ring *cmpl = &qt->cmpl;
+       s32 head0 = -1, ts_head = -1;
        __le64 *raw_tcd, done;
        u32 head = cmpl->head;
-       s32 head0 = -1;
 
        done = (head & (cmpl->size_mask + 1)) ? 0 : cpu_to_le64(FBNIC_TCD_DONE);
        raw_tcd = &cmpl->desc[head & cmpl->size_mask];
@@ -496,6 +577,12 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt,
                         * they are skipped for now.
                         */
                        break;
+               case FBNIC_TCD_TYPE_1:
+                       if (WARN_ON_ONCE(tcd & FBNIC_TCD_TWQ1))
+                               break;
+
+                       fbnic_clean_tsq(nv, &qt->sub0, tcd, &ts_head, &head0);
+                       break;
                default:
                        break;
                }
@@ -515,7 +602,7 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt,
        }
 
        /* Unmap and free processed buffers */
-       fbnic_clean_twq(nv, napi_budget, qt, head0);
+       fbnic_clean_twq(nv, napi_budget, qt, ts_head, head0);
 }
 
 static void fbnic_clean_bdq(struct fbnic_napi_vector *nv, int napi_budget,