> -----Original Message-----
> From: Intel-wired-lan <[email protected]> On Behalf
> Of Matteo Croce
> Sent: Monday, March 23, 2026 7:28 PM
> To: Nguyen, Anthony L <[email protected]>; Kitszel,
> Przemyslaw <[email protected]>; Andrew Lunn
> <[email protected]>; David S. Miller <[email protected]>; Eric
> Dumazet <[email protected]>; Jakub Kicinski <[email protected]>; Paolo
> Abeni <[email protected]>; Alexei Starovoitov <[email protected]>; Daniel
> Borkmann <[email protected]>; Jesper Dangaard Brouer
> <[email protected]>; John Fastabend <[email protected]>; Mohsin
> Bashir <[email protected]>
> Cc: [email protected]; [email protected]; intel-wired-
> [email protected]; [email protected]
> Subject: [Intel-wired-lan] [PATCH net-next v4 1/2] e1000e: add basic
> XDP support
>
> Add XDP support to the e1000e driver covering the actions defined by
> NETDEV_XDP_ACT_BASIC: XDP_DROP, XDP_PASS, XDP_TX and XDP_ABORTED.
>
> Infrastructure:
> - e1000_xdp_setup() / e1000_xdp() for program attach/detach with
> MTU validation and close/open cycle
> - ndo_bpf support in net_device_ops
> - xdp_rxq_info registration in setup/free_rx_resources
>
> Receive path:
> - e1000_alloc_rx_buffers_xdp() for page-based Rx buffer allocation
> with XDP_PACKET_HEADROOM
> - e1000_clean_rx_irq_xdp() as the XDP receive handler
> - e1000_run_xdp() to execute the XDP program on received packets
> - SKB building via napi_build_skb() for XDP_PASS with metadata,
> checksum offload and RSS hash support
>
> Transmit path:
> - e1000_xdp_xmit_ring() to DMA-map and enqueue an XDP frame
> - e1000_xdp_xmit_back() to convert an xdp_buff to a frame and send it
> - e1000_finalize_xdp() to flush the TX ring after XDP processing
> - TX completion via xdp_return_frame() with buffer type tracking
>
> Assisted-by: claude-opus-4-6
> Signed-off-by: Matteo Croce <[email protected]>
> ---
> drivers/net/ethernet/intel/Kconfig | 1 +
> drivers/net/ethernet/intel/e1000e/e1000.h | 18 +-
> drivers/net/ethernet/intel/e1000e/netdev.c | 533 ++++++++++++++++++++-
> 3 files changed, 540 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/Kconfig
> b/drivers/net/ethernet/intel/Kconfig
> index 288fa8ce53af..46e37cb68e70 100644
> --- a/drivers/net/ethernet/intel/Kconfig
> +++ b/drivers/net/ethernet/intel/Kconfig
> @@ -63,6 +63,7 @@ config E1000E
> depends on PCI && (!SPARC32 || BROKEN)
> depends on PTP_1588_CLOCK_OPTIONAL
> select CRC32
> + select PAGE_POOL
> help
> This driver supports the PCI-Express Intel(R) PRO/1000
> gigabit
> ethernet family of adapters. For PCI or PCI-X e1000 adapters,
> diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h
> b/drivers/net/ethernet/intel/e1000e/e1000.h
> index 63ebe00376f5..4c1175d4e5cb 100644
> --- a/drivers/net/ethernet/intel/e1000e/e1000.h
> +++ b/drivers/net/ethernet/intel/e1000e/e1000.h
> @@ -19,10 +19,13 @@
> #include <linux/net_tstamp.h>
> #include <linux/ptp_clock_kernel.h>
> #include <linux/ptp_classify.h>
...
> +/**
> + * e1000_xdp_xmit_ring - transmit an XDP frame on the TX ring
> + * @adapter: board private structure
> + * @tx_ring: Tx descriptor ring
> + * @xdpf: XDP frame to transmit
> + *
> + * Returns E1000_XDP_TX on success, E1000_XDP_CONSUMED on failure
> **/
> +static int e1000_xdp_xmit_ring(struct e1000_adapter *adapter,
> + struct e1000_ring *tx_ring,
> + struct xdp_frame *xdpf)
> +{
> + struct e1000_buffer *buffer_info;
> + struct e1000_tx_desc *tx_desc;
> + dma_addr_t dma;
> + u16 i;
> +
> + if (e1000_desc_unused(tx_ring) < 1)
> + return E1000_XDP_CONSUMED;
> +
> + i = tx_ring->next_to_use;
Unsynchronized read of next_to_use. ndo_start_xmit on another CPU can be
reading+writing this same field RIGHT NOW under __netif_tx_lock, which we do
NOT hold.
Isn't it ?
> + buffer_info = &tx_ring->buffer_info[i];
> +
> + dma = dma_map_single(&adapter->pdev->dev, xdpf->data, xdpf-
> >len,
> + DMA_TO_DEVICE);
> + if (dma_mapping_error(&adapter->pdev->dev, dma))
> + return E1000_XDP_CONSUMED;
> +
> + buffer_info->xdpf = xdpf;
> + buffer_info->type = E1000_TX_BUF_XDP;
> + buffer_info->dma = dma;
> + buffer_info->length = xdpf->len;
> + buffer_info->time_stamp = jiffies;
> + buffer_info->next_to_watch = i;
> + buffer_info->segs = 1;
> + buffer_info->bytecount = xdpf->len;
> + buffer_info->mapped_as_page = 0;
> +
> + tx_desc = E1000_TX_DESC(*tx_ring, i);
> + tx_desc->buffer_addr = cpu_to_le64(dma);
Writing DMA descriptor that ndo_start_xmit may also be writing to
at the same index - probably causes ring corruption
> + tx_desc->lower.data = cpu_to_le32(adapter->txd_cmd |
> + E1000_TXD_CMD_IFCS |
> + xdpf->len);
> + tx_desc->upper.data = 0;
> +
> + i++;
> + if (i == tx_ring->count)
> + i = 0;
> + tx_ring->next_to_use = i;
Unsynchronized store - races with the identical write in e1000_xmit_frame.
> +
> + return E1000_XDP_TX;
> +}
> +
...
> kfree(adapter->tx_ring);
> kfree(adapter->rx_ring);
>
> --
> 2.53.0