]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: txgbe: support TX head write-back mode
authorJiawen Wu <jiawenwu@trustnetic.com>
Thu, 23 Oct 2025 01:45:37 +0000 (09:45 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 28 Oct 2025 09:44:17 +0000 (10:44 +0100)
TX head write-back mode is supported on AML devices. When it is enabled,
the hardware no longer writes the descriptors DD one by one, but write
back pointer of completion descriptor to the head_wb address.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20251023014538.12644-3-jiawenwu@trustnetic.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/wangxun/libwx/wx_hw.c
drivers/net/ethernet/wangxun/libwx/wx_lib.c
drivers/net/ethernet/wangxun/libwx/wx_type.h
drivers/net/ethernet/wangxun/libwx/wx_vf.h
drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c

index 2dbbb42aa9c0126c343a69702a19eca66f027dca..986bc5acc47219bdc64508dcb1c33ccd6718ebc0 100644 (file)
@@ -1905,6 +1905,15 @@ static void wx_configure_tx_ring(struct wx *wx,
        memset(ring->tx_buffer_info, 0,
               sizeof(struct wx_tx_buffer) * ring->count);
 
+       if (ring->headwb_mem) {
+               wr32(wx, WX_PX_TR_HEAD_ADDRL(reg_idx),
+                    ring->headwb_dma & DMA_BIT_MASK(32));
+               wr32(wx, WX_PX_TR_HEAD_ADDRH(reg_idx),
+                    upper_32_bits(ring->headwb_dma));
+
+               txdctl |= WX_PX_TR_CFG_HEAD_WB;
+       }
+
        /* enable queue */
        wr32(wx, WX_PX_TR_CFG(reg_idx), txdctl);
 
index 3adf7048320aee7945d2772a5ef6e369aba47c11..622213fe67902891ece5163cc14a2627d6cc39fd 100644 (file)
@@ -735,9 +735,22 @@ static bool wx_clean_tx_irq(struct wx_q_vector *q_vector,
                /* prevent any other reads prior to eop_desc */
                smp_rmb();
 
-               /* if DD is not set pending work has not been completed */
-               if (!(eop_desc->wb.status & cpu_to_le32(WX_TXD_STAT_DD)))
+               if (tx_ring->headwb_mem) {
+                       u32 head = *tx_ring->headwb_mem;
+
+                       if (head == tx_ring->next_to_clean)
+                               break;
+                       else if (head > tx_ring->next_to_clean &&
+                                !(tx_buffer->next_eop >= tx_ring->next_to_clean &&
+                                  tx_buffer->next_eop < head))
+                               break;
+                       else if (!(tx_buffer->next_eop >= tx_ring->next_to_clean ||
+                                  tx_buffer->next_eop < head))
+                               break;
+               } else if (!(eop_desc->wb.status & cpu_to_le32(WX_TXD_STAT_DD))) {
+                       /* if DD is not set pending work has not been completed */
                        break;
+               }
 
                /* clear next_to_watch to prevent false hangs */
                tx_buffer->next_to_watch = NULL;
@@ -1075,6 +1088,10 @@ static int wx_tx_map(struct wx_ring *tx_ring,
        /* set next_to_watch value indicating a packet is present */
        first->next_to_watch = tx_desc;
 
+       /* set next_eop for amlite tx head wb */
+       if (tx_ring->headwb_mem)
+               first->next_eop = i;
+
        i++;
        if (i == tx_ring->count)
                i = 0;
@@ -2683,6 +2700,16 @@ void wx_clean_all_tx_rings(struct wx *wx)
 }
 EXPORT_SYMBOL(wx_clean_all_tx_rings);
 
+static void wx_free_headwb_resources(struct wx_ring *tx_ring)
+{
+       if (!tx_ring->headwb_mem)
+               return;
+
+       dma_free_coherent(tx_ring->dev, sizeof(u32),
+                         tx_ring->headwb_mem, tx_ring->headwb_dma);
+       tx_ring->headwb_mem = NULL;
+}
+
 /**
  * wx_free_tx_resources - Free Tx Resources per Queue
  * @tx_ring: Tx descriptor ring for a specific queue
@@ -2702,6 +2729,8 @@ static void wx_free_tx_resources(struct wx_ring *tx_ring)
        dma_free_coherent(tx_ring->dev, tx_ring->size,
                          tx_ring->desc, tx_ring->dma);
        tx_ring->desc = NULL;
+
+       wx_free_headwb_resources(tx_ring);
 }
 
 /**
@@ -2840,6 +2869,24 @@ err_setup_rx:
        return err;
 }
 
+static void wx_setup_headwb_resources(struct wx_ring *tx_ring)
+{
+       struct wx *wx = netdev_priv(tx_ring->netdev);
+
+       if (!test_bit(WX_FLAG_TXHEAD_WB_ENABLED, wx->flags))
+               return;
+
+       if (!tx_ring->q_vector)
+               return;
+
+       tx_ring->headwb_mem = dma_alloc_coherent(tx_ring->dev,
+                                                sizeof(u32),
+                                                &tx_ring->headwb_dma,
+                                                GFP_KERNEL);
+       if (!tx_ring->headwb_mem)
+               dev_info(tx_ring->dev, "Allocate headwb memory failed, disable it\n");
+}
+
 /**
  * wx_setup_tx_resources - allocate Tx resources (Descriptors)
  * @tx_ring: tx descriptor ring (for a specific queue) to setup
@@ -2880,6 +2927,8 @@ static int wx_setup_tx_resources(struct wx_ring *tx_ring)
        if (!tx_ring->desc)
                goto err;
 
+       wx_setup_headwb_resources(tx_ring);
+
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
 
index eb3f32551c14bb6be4133d57c2b14dc866a0b860..8b3c39945c0b04f4166e7cecf1c0a2ce0bc3995c 100644 (file)
@@ -434,12 +434,15 @@ enum WX_MSCA_CMD_value {
 #define WX_PX_TR_WP(_i)              (0x03008 + ((_i) * 0x40))
 #define WX_PX_TR_RP(_i)              (0x0300C + ((_i) * 0x40))
 #define WX_PX_TR_CFG(_i)             (0x03010 + ((_i) * 0x40))
+#define WX_PX_TR_HEAD_ADDRL(_i)      (0x03028 + ((_i) * 0x40))
+#define WX_PX_TR_HEAD_ADDRH(_i)      (0x0302C + ((_i) * 0x40))
 /* Transmit Config masks */
 #define WX_PX_TR_CFG_ENABLE          BIT(0) /* Ena specific Tx Queue */
 #define WX_PX_TR_CFG_TR_SIZE_SHIFT   1 /* tx desc number per ring */
 #define WX_PX_TR_CFG_SWFLSH          BIT(26) /* Tx Desc. wr-bk flushing */
 #define WX_PX_TR_CFG_WTHRESH_SHIFT   16 /* shift to WTHRESH bits */
 #define WX_PX_TR_CFG_THRE_SHIFT      8
+#define WX_PX_TR_CFG_HEAD_WB         BIT(27)
 
 /* Receive DMA Registers */
 #define WX_PX_RR_BAL(_i)             (0x01000 + ((_i) * 0x40))
@@ -1011,6 +1014,7 @@ struct wx_tx_buffer {
        DEFINE_DMA_UNMAP_LEN(len);
        __be16 protocol;
        u32 tx_flags;
+       u32 next_eop;
 };
 
 struct wx_rx_buffer {
@@ -1062,6 +1066,8 @@ struct wx_ring {
        };
        u8 __iomem *tail;
        dma_addr_t dma;                 /* phys. address of descriptor ring */
+       dma_addr_t headwb_dma;
+       u32 *headwb_mem;
        unsigned int size;              /* length in bytes */
 
        u16 count;                      /* amount of descriptors */
@@ -1239,6 +1245,7 @@ enum wx_pf_flags {
        WX_FLAG_NEED_UPDATE_LINK,
        WX_FLAG_NEED_DO_RESET,
        WX_FLAG_RX_MERGE_ENABLED,
+       WX_FLAG_TXHEAD_WB_ENABLED,
        WX_PF_FLAGS_NBITS               /* must be last */
 };
 
index ecb19859239365710b261e33e44c0118ecacd15a..eb6ca3fe4e97b61af74647317c10937b8dccc580 100644 (file)
@@ -92,6 +92,9 @@
 #define WX_VXTXDCTL_PTHRESH(f)   FIELD_PREP(GENMASK(11, 8), f)
 #define WX_VXTXDCTL_WTHRESH(f)   FIELD_PREP(GENMASK(22, 16), f)
 #define WX_VXTXDCTL_FLUSH        BIT(26)
+#define WX_VXTXDCTL_HEAD_WB      BIT(27)
+#define WX_VXTXD_HEAD_ADDRL(r)   (0x3028 + (0x40 * (r)))
+#define WX_VXTXD_HEAD_ADDRH(r)   (0x302C + (0x40 * (r)))
 
 #define WX_PFLINK_STATUS(g)      FIELD_GET(BIT(0), g)
 #define WX_PFLINK_SPEED(g)       FIELD_GET(GENMASK(31, 1), g)
index f54107f3c6d7f8c68815190f78afd16ccfb0291a..aa8be036956c0e8ba8f34d969eaf3a5586d47288 100644 (file)
@@ -132,6 +132,15 @@ static void wx_configure_tx_ring_vf(struct wx *wx, struct wx_ring *ring)
        txdctl |= WX_VXTXDCTL_BUFLEN(wx_buf_len(ring->count));
        txdctl |= WX_VXTXDCTL_ENABLE;
 
+       if (ring->headwb_mem) {
+               wr32(wx, WX_VXTXD_HEAD_ADDRL(reg_idx),
+                    ring->headwb_dma & DMA_BIT_MASK(32));
+               wr32(wx, WX_VXTXD_HEAD_ADDRH(reg_idx),
+                    upper_32_bits(ring->headwb_dma));
+
+               txdctl |= WX_VXTXDCTL_HEAD_WB;
+       }
+
        /* reinitialize tx_buffer_info */
        memset(ring->tx_buffer_info, 0,
               sizeof(struct wx_tx_buffer) * ring->count);
index 60a04c5a76782ccfb59ff977d81f1a8f853beb7f..ff690e9a075af1505390b42b21f7c8b3b7f3138e 100644 (file)
@@ -424,6 +424,7 @@ static int txgbe_sw_init(struct wx *wx)
        case wx_mac_aml:
        case wx_mac_aml40:
                set_bit(WX_FLAG_RX_MERGE_ENABLED, wx->flags);
+               set_bit(WX_FLAG_TXHEAD_WB_ENABLED, wx->flags);
                set_bit(WX_FLAG_SWFW_RING, wx->flags);
                wx->swfw_index = 0;
                break;
index 52c1e223bbd781f22145e567004e839f980cb6ae..37e4ec487afdd41a74e2fcedc9ea5b45b8fec7ef 100644 (file)
@@ -163,6 +163,7 @@ static int txgbevf_sw_init(struct wx *wx)
        case wx_mac_aml:
        case wx_mac_aml40:
                set_bit(WX_FLAG_RX_MERGE_ENABLED, wx->flags);
+               set_bit(WX_FLAG_TXHEAD_WB_ENABLED, wx->flags);
                break;
        default:
                break;