xref: /linux/drivers/net/ethernet/intel/igb/igb_xsk.c (revision 0ad9617c78acbc71373fb341a6f75d4012b01d69)
180f6ccf9SSriram Yagnaraman // SPDX-License-Identifier: GPL-2.0
280f6ccf9SSriram Yagnaraman /* Copyright(c) 2018 Intel Corporation. */
380f6ccf9SSriram Yagnaraman 
480f6ccf9SSriram Yagnaraman #include <linux/bpf_trace.h>
580f6ccf9SSriram Yagnaraman #include <net/xdp_sock_drv.h>
680f6ccf9SSriram Yagnaraman #include <net/xdp.h>
780f6ccf9SSriram Yagnaraman 
880f6ccf9SSriram Yagnaraman #include "e1000_hw.h"
980f6ccf9SSriram Yagnaraman #include "igb.h"
1080f6ccf9SSriram Yagnaraman 
1180f6ccf9SSriram Yagnaraman static int igb_realloc_rx_buffer_info(struct igb_ring *ring, bool pool_present)
1280f6ccf9SSriram Yagnaraman {
1380f6ccf9SSriram Yagnaraman 	int size = pool_present ?
1480f6ccf9SSriram Yagnaraman 		sizeof(*ring->rx_buffer_info_zc) * ring->count :
1580f6ccf9SSriram Yagnaraman 		sizeof(*ring->rx_buffer_info) * ring->count;
1680f6ccf9SSriram Yagnaraman 	void *buff_info = vmalloc(size);
1780f6ccf9SSriram Yagnaraman 
1880f6ccf9SSriram Yagnaraman 	if (!buff_info)
1980f6ccf9SSriram Yagnaraman 		return -ENOMEM;
2080f6ccf9SSriram Yagnaraman 
2180f6ccf9SSriram Yagnaraman 	if (pool_present) {
2280f6ccf9SSriram Yagnaraman 		vfree(ring->rx_buffer_info);
2380f6ccf9SSriram Yagnaraman 		ring->rx_buffer_info = NULL;
2480f6ccf9SSriram Yagnaraman 		ring->rx_buffer_info_zc = buff_info;
2580f6ccf9SSriram Yagnaraman 	} else {
2680f6ccf9SSriram Yagnaraman 		vfree(ring->rx_buffer_info_zc);
2780f6ccf9SSriram Yagnaraman 		ring->rx_buffer_info_zc = NULL;
2880f6ccf9SSriram Yagnaraman 		ring->rx_buffer_info = buff_info;
2980f6ccf9SSriram Yagnaraman 	}
3080f6ccf9SSriram Yagnaraman 
3180f6ccf9SSriram Yagnaraman 	return 0;
3280f6ccf9SSriram Yagnaraman }
3380f6ccf9SSriram Yagnaraman 
3480f6ccf9SSriram Yagnaraman static void igb_txrx_ring_disable(struct igb_adapter *adapter, u16 qid)
3580f6ccf9SSriram Yagnaraman {
3680f6ccf9SSriram Yagnaraman 	struct igb_ring *tx_ring = adapter->tx_ring[qid];
3780f6ccf9SSriram Yagnaraman 	struct igb_ring *rx_ring = adapter->rx_ring[qid];
3880f6ccf9SSriram Yagnaraman 	struct e1000_hw *hw = &adapter->hw;
3980f6ccf9SSriram Yagnaraman 
4080f6ccf9SSriram Yagnaraman 	set_bit(IGB_RING_FLAG_TX_DISABLED, &tx_ring->flags);
4180f6ccf9SSriram Yagnaraman 
4280f6ccf9SSriram Yagnaraman 	wr32(E1000_TXDCTL(tx_ring->reg_idx), 0);
4380f6ccf9SSriram Yagnaraman 	wr32(E1000_RXDCTL(rx_ring->reg_idx), 0);
4480f6ccf9SSriram Yagnaraman 
4580f6ccf9SSriram Yagnaraman 	synchronize_net();
4680f6ccf9SSriram Yagnaraman 
4780f6ccf9SSriram Yagnaraman 	/* Rx/Tx share the same napi context. */
4880f6ccf9SSriram Yagnaraman 	napi_disable(&rx_ring->q_vector->napi);
4980f6ccf9SSriram Yagnaraman 
5080f6ccf9SSriram Yagnaraman 	igb_clean_tx_ring(tx_ring);
5180f6ccf9SSriram Yagnaraman 	igb_clean_rx_ring(rx_ring);
5280f6ccf9SSriram Yagnaraman 
5380f6ccf9SSriram Yagnaraman 	memset(&rx_ring->rx_stats, 0, sizeof(rx_ring->rx_stats));
5480f6ccf9SSriram Yagnaraman 	memset(&tx_ring->tx_stats, 0, sizeof(tx_ring->tx_stats));
5580f6ccf9SSriram Yagnaraman }
5680f6ccf9SSriram Yagnaraman 
5780f6ccf9SSriram Yagnaraman static void igb_txrx_ring_enable(struct igb_adapter *adapter, u16 qid)
5880f6ccf9SSriram Yagnaraman {
5980f6ccf9SSriram Yagnaraman 	struct igb_ring *tx_ring = adapter->tx_ring[qid];
6080f6ccf9SSriram Yagnaraman 	struct igb_ring *rx_ring = adapter->rx_ring[qid];
6180f6ccf9SSriram Yagnaraman 
6280f6ccf9SSriram Yagnaraman 	igb_configure_tx_ring(adapter, tx_ring);
6380f6ccf9SSriram Yagnaraman 	igb_configure_rx_ring(adapter, rx_ring);
6480f6ccf9SSriram Yagnaraman 
6580f6ccf9SSriram Yagnaraman 	synchronize_net();
6680f6ccf9SSriram Yagnaraman 
6780f6ccf9SSriram Yagnaraman 	clear_bit(IGB_RING_FLAG_TX_DISABLED, &tx_ring->flags);
6880f6ccf9SSriram Yagnaraman 
6980f6ccf9SSriram Yagnaraman 	/* call igb_desc_unused which always leaves
7080f6ccf9SSriram Yagnaraman 	 * at least 1 descriptor unused to make sure
7180f6ccf9SSriram Yagnaraman 	 * next_to_use != next_to_clean
7280f6ccf9SSriram Yagnaraman 	 */
732c619601SSriram Yagnaraman 	if (rx_ring->xsk_pool)
742c619601SSriram Yagnaraman 		igb_alloc_rx_buffers_zc(rx_ring, rx_ring->xsk_pool,
752c619601SSriram Yagnaraman 					igb_desc_unused(rx_ring));
762c619601SSriram Yagnaraman 	else
7780f6ccf9SSriram Yagnaraman 		igb_alloc_rx_buffers(rx_ring, igb_desc_unused(rx_ring));
7880f6ccf9SSriram Yagnaraman 
7980f6ccf9SSriram Yagnaraman 	/* Rx/Tx share the same napi context. */
8080f6ccf9SSriram Yagnaraman 	napi_enable(&rx_ring->q_vector->napi);
8180f6ccf9SSriram Yagnaraman }
8280f6ccf9SSriram Yagnaraman 
8380f6ccf9SSriram Yagnaraman struct xsk_buff_pool *igb_xsk_pool(struct igb_adapter *adapter,
8480f6ccf9SSriram Yagnaraman 				   struct igb_ring *ring)
8580f6ccf9SSriram Yagnaraman {
8680f6ccf9SSriram Yagnaraman 	int qid = ring->queue_index;
8780f6ccf9SSriram Yagnaraman 	struct xsk_buff_pool *pool;
8880f6ccf9SSriram Yagnaraman 
8980f6ccf9SSriram Yagnaraman 	pool = xsk_get_pool_from_qid(adapter->netdev, qid);
9080f6ccf9SSriram Yagnaraman 
9180f6ccf9SSriram Yagnaraman 	if (!igb_xdp_is_enabled(adapter))
9280f6ccf9SSriram Yagnaraman 		return NULL;
9380f6ccf9SSriram Yagnaraman 
9480f6ccf9SSriram Yagnaraman 	return (pool && pool->dev) ? pool : NULL;
9580f6ccf9SSriram Yagnaraman }
9680f6ccf9SSriram Yagnaraman 
9780f6ccf9SSriram Yagnaraman static int igb_xsk_pool_enable(struct igb_adapter *adapter,
9880f6ccf9SSriram Yagnaraman 			       struct xsk_buff_pool *pool,
9980f6ccf9SSriram Yagnaraman 			       u16 qid)
10080f6ccf9SSriram Yagnaraman {
10180f6ccf9SSriram Yagnaraman 	struct net_device *netdev = adapter->netdev;
10280f6ccf9SSriram Yagnaraman 	struct igb_ring *rx_ring;
10380f6ccf9SSriram Yagnaraman 	bool if_running;
10480f6ccf9SSriram Yagnaraman 	int err;
10580f6ccf9SSriram Yagnaraman 
10680f6ccf9SSriram Yagnaraman 	if (qid >= adapter->num_rx_queues)
10780f6ccf9SSriram Yagnaraman 		return -EINVAL;
10880f6ccf9SSriram Yagnaraman 
10980f6ccf9SSriram Yagnaraman 	if (qid >= netdev->real_num_rx_queues ||
11080f6ccf9SSriram Yagnaraman 	    qid >= netdev->real_num_tx_queues)
11180f6ccf9SSriram Yagnaraman 		return -EINVAL;
11280f6ccf9SSriram Yagnaraman 
11380f6ccf9SSriram Yagnaraman 	err = xsk_pool_dma_map(pool, &adapter->pdev->dev, IGB_RX_DMA_ATTR);
11480f6ccf9SSriram Yagnaraman 	if (err)
11580f6ccf9SSriram Yagnaraman 		return err;
11680f6ccf9SSriram Yagnaraman 
11780f6ccf9SSriram Yagnaraman 	rx_ring = adapter->rx_ring[qid];
11880f6ccf9SSriram Yagnaraman 	if_running = netif_running(adapter->netdev) && igb_xdp_is_enabled(adapter);
11980f6ccf9SSriram Yagnaraman 	if (if_running)
12080f6ccf9SSriram Yagnaraman 		igb_txrx_ring_disable(adapter, qid);
12180f6ccf9SSriram Yagnaraman 
12280f6ccf9SSriram Yagnaraman 	if (if_running) {
12380f6ccf9SSriram Yagnaraman 		err = igb_realloc_rx_buffer_info(rx_ring, true);
12480f6ccf9SSriram Yagnaraman 		if (!err) {
12580f6ccf9SSriram Yagnaraman 			igb_txrx_ring_enable(adapter, qid);
12680f6ccf9SSriram Yagnaraman 			/* Kick start the NAPI context so that receiving will start */
12780f6ccf9SSriram Yagnaraman 			err = igb_xsk_wakeup(adapter->netdev, qid, XDP_WAKEUP_RX);
12880f6ccf9SSriram Yagnaraman 		}
12980f6ccf9SSriram Yagnaraman 
13080f6ccf9SSriram Yagnaraman 		if (err) {
13180f6ccf9SSriram Yagnaraman 			xsk_pool_dma_unmap(pool, IGB_RX_DMA_ATTR);
13280f6ccf9SSriram Yagnaraman 			return err;
13380f6ccf9SSriram Yagnaraman 		}
13480f6ccf9SSriram Yagnaraman 	}
13580f6ccf9SSriram Yagnaraman 
13680f6ccf9SSriram Yagnaraman 	return 0;
13780f6ccf9SSriram Yagnaraman }
13880f6ccf9SSriram Yagnaraman 
13980f6ccf9SSriram Yagnaraman static int igb_xsk_pool_disable(struct igb_adapter *adapter, u16 qid)
14080f6ccf9SSriram Yagnaraman {
14180f6ccf9SSriram Yagnaraman 	struct xsk_buff_pool *pool;
14280f6ccf9SSriram Yagnaraman 	struct igb_ring *rx_ring;
14380f6ccf9SSriram Yagnaraman 	bool if_running;
14480f6ccf9SSriram Yagnaraman 	int err;
14580f6ccf9SSriram Yagnaraman 
14680f6ccf9SSriram Yagnaraman 	pool = xsk_get_pool_from_qid(adapter->netdev, qid);
14780f6ccf9SSriram Yagnaraman 	if (!pool)
14880f6ccf9SSriram Yagnaraman 		return -EINVAL;
14980f6ccf9SSriram Yagnaraman 
15080f6ccf9SSriram Yagnaraman 	rx_ring = adapter->rx_ring[qid];
15180f6ccf9SSriram Yagnaraman 	if_running = netif_running(adapter->netdev) && igb_xdp_is_enabled(adapter);
15280f6ccf9SSriram Yagnaraman 	if (if_running)
15380f6ccf9SSriram Yagnaraman 		igb_txrx_ring_disable(adapter, qid);
15480f6ccf9SSriram Yagnaraman 
15580f6ccf9SSriram Yagnaraman 	xsk_pool_dma_unmap(pool, IGB_RX_DMA_ATTR);
15680f6ccf9SSriram Yagnaraman 
15780f6ccf9SSriram Yagnaraman 	if (if_running) {
15880f6ccf9SSriram Yagnaraman 		err = igb_realloc_rx_buffer_info(rx_ring, false);
15980f6ccf9SSriram Yagnaraman 		if (err)
16080f6ccf9SSriram Yagnaraman 			return err;
16180f6ccf9SSriram Yagnaraman 
16280f6ccf9SSriram Yagnaraman 		igb_txrx_ring_enable(adapter, qid);
16380f6ccf9SSriram Yagnaraman 	}
16480f6ccf9SSriram Yagnaraman 
16580f6ccf9SSriram Yagnaraman 	return 0;
16680f6ccf9SSriram Yagnaraman }
16780f6ccf9SSriram Yagnaraman 
16880f6ccf9SSriram Yagnaraman int igb_xsk_pool_setup(struct igb_adapter *adapter,
16980f6ccf9SSriram Yagnaraman 		       struct xsk_buff_pool *pool,
17080f6ccf9SSriram Yagnaraman 		       u16 qid)
17180f6ccf9SSriram Yagnaraman {
17280f6ccf9SSriram Yagnaraman 	return pool ? igb_xsk_pool_enable(adapter, pool, qid) :
17380f6ccf9SSriram Yagnaraman 		igb_xsk_pool_disable(adapter, qid);
17480f6ccf9SSriram Yagnaraman }
17580f6ccf9SSriram Yagnaraman 
1762c619601SSriram Yagnaraman static u16 igb_fill_rx_descs(struct xsk_buff_pool *pool, struct xdp_buff **xdp,
1772c619601SSriram Yagnaraman 			     union e1000_adv_rx_desc *rx_desc, u16 count)
1782c619601SSriram Yagnaraman {
1792c619601SSriram Yagnaraman 	dma_addr_t dma;
1802c619601SSriram Yagnaraman 	u16 buffs;
1812c619601SSriram Yagnaraman 	int i;
1822c619601SSriram Yagnaraman 
1832c619601SSriram Yagnaraman 	/* nothing to do */
1842c619601SSriram Yagnaraman 	if (!count)
1852c619601SSriram Yagnaraman 		return 0;
1862c619601SSriram Yagnaraman 
1872c619601SSriram Yagnaraman 	buffs = xsk_buff_alloc_batch(pool, xdp, count);
1882c619601SSriram Yagnaraman 	for (i = 0; i < buffs; i++) {
1892c619601SSriram Yagnaraman 		dma = xsk_buff_xdp_get_dma(*xdp);
1902c619601SSriram Yagnaraman 		rx_desc->read.pkt_addr = cpu_to_le64(dma);
1912c619601SSriram Yagnaraman 		rx_desc->wb.upper.length = 0;
1922c619601SSriram Yagnaraman 
1932c619601SSriram Yagnaraman 		rx_desc++;
1942c619601SSriram Yagnaraman 		xdp++;
1952c619601SSriram Yagnaraman 	}
1962c619601SSriram Yagnaraman 
1972c619601SSriram Yagnaraman 	return buffs;
1982c619601SSriram Yagnaraman }
1992c619601SSriram Yagnaraman 
2002c619601SSriram Yagnaraman bool igb_alloc_rx_buffers_zc(struct igb_ring *rx_ring,
2012c619601SSriram Yagnaraman 			     struct xsk_buff_pool *xsk_pool, u16 count)
2022c619601SSriram Yagnaraman {
2032c619601SSriram Yagnaraman 	u32 nb_buffs_extra = 0, nb_buffs = 0;
2042c619601SSriram Yagnaraman 	union e1000_adv_rx_desc *rx_desc;
2052c619601SSriram Yagnaraman 	u16 ntu = rx_ring->next_to_use;
2062c619601SSriram Yagnaraman 	u16 total_count = count;
2072c619601SSriram Yagnaraman 	struct xdp_buff **xdp;
2082c619601SSriram Yagnaraman 
2092c619601SSriram Yagnaraman 	rx_desc = IGB_RX_DESC(rx_ring, ntu);
2102c619601SSriram Yagnaraman 	xdp = &rx_ring->rx_buffer_info_zc[ntu];
2112c619601SSriram Yagnaraman 
2122c619601SSriram Yagnaraman 	if (ntu + count >= rx_ring->count) {
2132c619601SSriram Yagnaraman 		nb_buffs_extra = igb_fill_rx_descs(xsk_pool, xdp, rx_desc,
2142c619601SSriram Yagnaraman 						   rx_ring->count - ntu);
2152c619601SSriram Yagnaraman 		if (nb_buffs_extra != rx_ring->count - ntu) {
2162c619601SSriram Yagnaraman 			ntu += nb_buffs_extra;
2172c619601SSriram Yagnaraman 			goto exit;
2182c619601SSriram Yagnaraman 		}
2192c619601SSriram Yagnaraman 		rx_desc = IGB_RX_DESC(rx_ring, 0);
2202c619601SSriram Yagnaraman 		xdp = rx_ring->rx_buffer_info_zc;
2212c619601SSriram Yagnaraman 		ntu = 0;
2222c619601SSriram Yagnaraman 		count -= nb_buffs_extra;
2232c619601SSriram Yagnaraman 	}
2242c619601SSriram Yagnaraman 
2252c619601SSriram Yagnaraman 	nb_buffs = igb_fill_rx_descs(xsk_pool, xdp, rx_desc, count);
2262c619601SSriram Yagnaraman 	ntu += nb_buffs;
2272c619601SSriram Yagnaraman 	if (ntu == rx_ring->count)
2282c619601SSriram Yagnaraman 		ntu = 0;
2292c619601SSriram Yagnaraman 
2302c619601SSriram Yagnaraman 	/* clear the length for the next_to_use descriptor */
2312c619601SSriram Yagnaraman 	rx_desc = IGB_RX_DESC(rx_ring, ntu);
2322c619601SSriram Yagnaraman 	rx_desc->wb.upper.length = 0;
2332c619601SSriram Yagnaraman 
2342c619601SSriram Yagnaraman exit:
2352c619601SSriram Yagnaraman 	if (rx_ring->next_to_use != ntu) {
2362c619601SSriram Yagnaraman 		rx_ring->next_to_use = ntu;
2372c619601SSriram Yagnaraman 
2382c619601SSriram Yagnaraman 		/* Force memory writes to complete before letting h/w
2392c619601SSriram Yagnaraman 		 * know there are new descriptors to fetch.  (Only
2402c619601SSriram Yagnaraman 		 * applicable for weak-ordered memory model archs,
2412c619601SSriram Yagnaraman 		 * such as IA-64).
2422c619601SSriram Yagnaraman 		 */
2432c619601SSriram Yagnaraman 		wmb();
2442c619601SSriram Yagnaraman 		writel(ntu, rx_ring->tail);
2452c619601SSriram Yagnaraman 	}
2462c619601SSriram Yagnaraman 
2472c619601SSriram Yagnaraman 	return total_count == (nb_buffs + nb_buffs_extra);
2482c619601SSriram Yagnaraman }
2492c619601SSriram Yagnaraman 
2502c619601SSriram Yagnaraman void igb_clean_rx_ring_zc(struct igb_ring *rx_ring)
2512c619601SSriram Yagnaraman {
2522c619601SSriram Yagnaraman 	u16 ntc = rx_ring->next_to_clean;
2532c619601SSriram Yagnaraman 	u16 ntu = rx_ring->next_to_use;
2542c619601SSriram Yagnaraman 
2552c619601SSriram Yagnaraman 	while (ntc != ntu) {
2562c619601SSriram Yagnaraman 		struct xdp_buff *xdp = rx_ring->rx_buffer_info_zc[ntc];
2572c619601SSriram Yagnaraman 
2582c619601SSriram Yagnaraman 		xsk_buff_free(xdp);
2592c619601SSriram Yagnaraman 		ntc++;
2602c619601SSriram Yagnaraman 		if (ntc >= rx_ring->count)
2612c619601SSriram Yagnaraman 			ntc = 0;
2622c619601SSriram Yagnaraman 	}
2632c619601SSriram Yagnaraman }
2642c619601SSriram Yagnaraman 
2652c619601SSriram Yagnaraman static struct sk_buff *igb_construct_skb_zc(struct igb_ring *rx_ring,
2662c619601SSriram Yagnaraman 					    struct xdp_buff *xdp,
2672c619601SSriram Yagnaraman 					    ktime_t timestamp)
2682c619601SSriram Yagnaraman {
2692c619601SSriram Yagnaraman 	unsigned int totalsize = xdp->data_end - xdp->data_meta;
2702c619601SSriram Yagnaraman 	unsigned int metasize = xdp->data - xdp->data_meta;
2712c619601SSriram Yagnaraman 	struct sk_buff *skb;
2722c619601SSriram Yagnaraman 
2732c619601SSriram Yagnaraman 	net_prefetch(xdp->data_meta);
2742c619601SSriram Yagnaraman 
2752c619601SSriram Yagnaraman 	/* allocate a skb to store the frags */
2762c619601SSriram Yagnaraman 	skb = napi_alloc_skb(&rx_ring->q_vector->napi, totalsize);
2772c619601SSriram Yagnaraman 	if (unlikely(!skb))
2782c619601SSriram Yagnaraman 		return NULL;
2792c619601SSriram Yagnaraman 
2802c619601SSriram Yagnaraman 	if (timestamp)
2812c619601SSriram Yagnaraman 		skb_hwtstamps(skb)->hwtstamp = timestamp;
2822c619601SSriram Yagnaraman 
2832c619601SSriram Yagnaraman 	memcpy(__skb_put(skb, totalsize), xdp->data_meta,
2842c619601SSriram Yagnaraman 	       ALIGN(totalsize, sizeof(long)));
2852c619601SSriram Yagnaraman 
2862c619601SSriram Yagnaraman 	if (metasize) {
2872c619601SSriram Yagnaraman 		skb_metadata_set(skb, metasize);
2882c619601SSriram Yagnaraman 		__skb_pull(skb, metasize);
2892c619601SSriram Yagnaraman 	}
2902c619601SSriram Yagnaraman 
2912c619601SSriram Yagnaraman 	return skb;
2922c619601SSriram Yagnaraman }
2932c619601SSriram Yagnaraman 
2942c619601SSriram Yagnaraman static int igb_run_xdp_zc(struct igb_adapter *adapter, struct igb_ring *rx_ring,
2952c619601SSriram Yagnaraman 			  struct xdp_buff *xdp, struct xsk_buff_pool *xsk_pool,
2962c619601SSriram Yagnaraman 			  struct bpf_prog *xdp_prog)
2972c619601SSriram Yagnaraman {
2982c619601SSriram Yagnaraman 	int err, result = IGB_XDP_PASS;
2992c619601SSriram Yagnaraman 	u32 act;
3002c619601SSriram Yagnaraman 
3012c619601SSriram Yagnaraman 	prefetchw(xdp->data_hard_start); /* xdp_frame write */
3022c619601SSriram Yagnaraman 
3032c619601SSriram Yagnaraman 	act = bpf_prog_run_xdp(xdp_prog, xdp);
3042c619601SSriram Yagnaraman 
3052c619601SSriram Yagnaraman 	if (likely(act == XDP_REDIRECT)) {
3062c619601SSriram Yagnaraman 		err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog);
3072c619601SSriram Yagnaraman 		if (!err)
3082c619601SSriram Yagnaraman 			return IGB_XDP_REDIR;
3092c619601SSriram Yagnaraman 
3102c619601SSriram Yagnaraman 		if (xsk_uses_need_wakeup(xsk_pool) &&
3112c619601SSriram Yagnaraman 		    err == -ENOBUFS)
3122c619601SSriram Yagnaraman 			result = IGB_XDP_EXIT;
3132c619601SSriram Yagnaraman 		else
3142c619601SSriram Yagnaraman 			result = IGB_XDP_CONSUMED;
3152c619601SSriram Yagnaraman 		goto out_failure;
3162c619601SSriram Yagnaraman 	}
3172c619601SSriram Yagnaraman 
3182c619601SSriram Yagnaraman 	switch (act) {
3192c619601SSriram Yagnaraman 	case XDP_PASS:
3202c619601SSriram Yagnaraman 		break;
3212c619601SSriram Yagnaraman 	case XDP_TX:
3222c619601SSriram Yagnaraman 		result = igb_xdp_xmit_back(adapter, xdp);
3232c619601SSriram Yagnaraman 		if (result == IGB_XDP_CONSUMED)
3242c619601SSriram Yagnaraman 			goto out_failure;
3252c619601SSriram Yagnaraman 		break;
3262c619601SSriram Yagnaraman 	default:
3272c619601SSriram Yagnaraman 		bpf_warn_invalid_xdp_action(adapter->netdev, xdp_prog, act);
3282c619601SSriram Yagnaraman 		fallthrough;
3292c619601SSriram Yagnaraman 	case XDP_ABORTED:
3302c619601SSriram Yagnaraman out_failure:
3312c619601SSriram Yagnaraman 		trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
3322c619601SSriram Yagnaraman 		fallthrough;
3332c619601SSriram Yagnaraman 	case XDP_DROP:
3342c619601SSriram Yagnaraman 		result = IGB_XDP_CONSUMED;
3352c619601SSriram Yagnaraman 		break;
3362c619601SSriram Yagnaraman 	}
3372c619601SSriram Yagnaraman 
3382c619601SSriram Yagnaraman 	return result;
3392c619601SSriram Yagnaraman }
3402c619601SSriram Yagnaraman 
3412c619601SSriram Yagnaraman int igb_clean_rx_irq_zc(struct igb_q_vector *q_vector,
3422c619601SSriram Yagnaraman 			struct xsk_buff_pool *xsk_pool, const int budget)
3432c619601SSriram Yagnaraman {
3442c619601SSriram Yagnaraman 	struct igb_adapter *adapter = q_vector->adapter;
3452c619601SSriram Yagnaraman 	unsigned int total_bytes = 0, total_packets = 0;
3462c619601SSriram Yagnaraman 	struct igb_ring *rx_ring = q_vector->rx.ring;
3472c619601SSriram Yagnaraman 	u32 ntc = rx_ring->next_to_clean;
3482c619601SSriram Yagnaraman 	struct bpf_prog *xdp_prog;
3492c619601SSriram Yagnaraman 	unsigned int xdp_xmit = 0;
3502c619601SSriram Yagnaraman 	bool failure = false;
3512c619601SSriram Yagnaraman 	u16 entries_to_alloc;
3522c619601SSriram Yagnaraman 	struct sk_buff *skb;
3532c619601SSriram Yagnaraman 
3542c619601SSriram Yagnaraman 	/* xdp_prog cannot be NULL in the ZC path */
3552c619601SSriram Yagnaraman 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
3562c619601SSriram Yagnaraman 
3572c619601SSriram Yagnaraman 	while (likely(total_packets < budget)) {
3582c619601SSriram Yagnaraman 		union e1000_adv_rx_desc *rx_desc;
3592c619601SSriram Yagnaraman 		ktime_t timestamp = 0;
3602c619601SSriram Yagnaraman 		struct xdp_buff *xdp;
3612c619601SSriram Yagnaraman 		unsigned int size;
3622c619601SSriram Yagnaraman 		int xdp_res = 0;
3632c619601SSriram Yagnaraman 
3642c619601SSriram Yagnaraman 		rx_desc = IGB_RX_DESC(rx_ring, ntc);
3652c619601SSriram Yagnaraman 		size = le16_to_cpu(rx_desc->wb.upper.length);
3662c619601SSriram Yagnaraman 		if (!size)
3672c619601SSriram Yagnaraman 			break;
3682c619601SSriram Yagnaraman 
3692c619601SSriram Yagnaraman 		/* This memory barrier is needed to keep us from reading
3702c619601SSriram Yagnaraman 		 * any other fields out of the rx_desc until we know the
3712c619601SSriram Yagnaraman 		 * descriptor has been written back
3722c619601SSriram Yagnaraman 		 */
3732c619601SSriram Yagnaraman 		dma_rmb();
3742c619601SSriram Yagnaraman 
3752c619601SSriram Yagnaraman 		xdp = rx_ring->rx_buffer_info_zc[ntc];
3762c619601SSriram Yagnaraman 		xsk_buff_set_size(xdp, size);
3772c619601SSriram Yagnaraman 		xsk_buff_dma_sync_for_cpu(xdp);
3782c619601SSriram Yagnaraman 
3792c619601SSriram Yagnaraman 		/* pull rx packet timestamp if available and valid */
3802c619601SSriram Yagnaraman 		if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
3812c619601SSriram Yagnaraman 			int ts_hdr_len;
3822c619601SSriram Yagnaraman 
3832c619601SSriram Yagnaraman 			ts_hdr_len = igb_ptp_rx_pktstamp(rx_ring->q_vector,
3842c619601SSriram Yagnaraman 							 xdp->data,
3852c619601SSriram Yagnaraman 							 &timestamp);
3862c619601SSriram Yagnaraman 
3872c619601SSriram Yagnaraman 			xdp->data += ts_hdr_len;
3882c619601SSriram Yagnaraman 			xdp->data_meta += ts_hdr_len;
3892c619601SSriram Yagnaraman 			size -= ts_hdr_len;
3902c619601SSriram Yagnaraman 		}
3912c619601SSriram Yagnaraman 
3922c619601SSriram Yagnaraman 		xdp_res = igb_run_xdp_zc(adapter, rx_ring, xdp, xsk_pool,
3932c619601SSriram Yagnaraman 					 xdp_prog);
3942c619601SSriram Yagnaraman 
3952c619601SSriram Yagnaraman 		if (xdp_res) {
3962c619601SSriram Yagnaraman 			if (likely(xdp_res & (IGB_XDP_TX | IGB_XDP_REDIR))) {
3972c619601SSriram Yagnaraman 				xdp_xmit |= xdp_res;
3982c619601SSriram Yagnaraman 			} else if (xdp_res == IGB_XDP_EXIT) {
3992c619601SSriram Yagnaraman 				failure = true;
4002c619601SSriram Yagnaraman 				break;
4012c619601SSriram Yagnaraman 			} else if (xdp_res == IGB_XDP_CONSUMED) {
4022c619601SSriram Yagnaraman 				xsk_buff_free(xdp);
4032c619601SSriram Yagnaraman 			}
4042c619601SSriram Yagnaraman 
4052c619601SSriram Yagnaraman 			total_packets++;
4062c619601SSriram Yagnaraman 			total_bytes += size;
4072c619601SSriram Yagnaraman 			ntc++;
4082c619601SSriram Yagnaraman 			if (ntc == rx_ring->count)
4092c619601SSriram Yagnaraman 				ntc = 0;
4102c619601SSriram Yagnaraman 			continue;
4112c619601SSriram Yagnaraman 		}
4122c619601SSriram Yagnaraman 
4132c619601SSriram Yagnaraman 		skb = igb_construct_skb_zc(rx_ring, xdp, timestamp);
4142c619601SSriram Yagnaraman 
4152c619601SSriram Yagnaraman 		/* exit if we failed to retrieve a buffer */
4162c619601SSriram Yagnaraman 		if (!skb) {
4172c619601SSriram Yagnaraman 			rx_ring->rx_stats.alloc_failed++;
4182c619601SSriram Yagnaraman 			break;
4192c619601SSriram Yagnaraman 		}
4202c619601SSriram Yagnaraman 
4212c619601SSriram Yagnaraman 		xsk_buff_free(xdp);
4222c619601SSriram Yagnaraman 		ntc++;
4232c619601SSriram Yagnaraman 		if (ntc == rx_ring->count)
4242c619601SSriram Yagnaraman 			ntc = 0;
4252c619601SSriram Yagnaraman 
4262c619601SSriram Yagnaraman 		if (eth_skb_pad(skb))
4272c619601SSriram Yagnaraman 			continue;
4282c619601SSriram Yagnaraman 
4292c619601SSriram Yagnaraman 		/* probably a little skewed due to removing CRC */
4302c619601SSriram Yagnaraman 		total_bytes += skb->len;
4312c619601SSriram Yagnaraman 
4322c619601SSriram Yagnaraman 		/* populate checksum, timestamp, VLAN, and protocol */
4332c619601SSriram Yagnaraman 		igb_process_skb_fields(rx_ring, rx_desc, skb);
4342c619601SSriram Yagnaraman 
4352c619601SSriram Yagnaraman 		napi_gro_receive(&q_vector->napi, skb);
4362c619601SSriram Yagnaraman 
4372c619601SSriram Yagnaraman 		/* update budget accounting */
4382c619601SSriram Yagnaraman 		total_packets++;
4392c619601SSriram Yagnaraman 	}
4402c619601SSriram Yagnaraman 
4412c619601SSriram Yagnaraman 	rx_ring->next_to_clean = ntc;
4422c619601SSriram Yagnaraman 
4432c619601SSriram Yagnaraman 	if (xdp_xmit)
4442c619601SSriram Yagnaraman 		igb_finalize_xdp(adapter, xdp_xmit);
4452c619601SSriram Yagnaraman 
4462c619601SSriram Yagnaraman 	igb_update_rx_stats(q_vector, total_packets, total_bytes);
4472c619601SSriram Yagnaraman 
4482c619601SSriram Yagnaraman 	entries_to_alloc = igb_desc_unused(rx_ring);
4492c619601SSriram Yagnaraman 	if (entries_to_alloc >= IGB_RX_BUFFER_WRITE)
4502c619601SSriram Yagnaraman 		failure |= !igb_alloc_rx_buffers_zc(rx_ring, xsk_pool,
4512c619601SSriram Yagnaraman 						    entries_to_alloc);
4522c619601SSriram Yagnaraman 
4532c619601SSriram Yagnaraman 	if (xsk_uses_need_wakeup(xsk_pool)) {
4542c619601SSriram Yagnaraman 		if (failure || rx_ring->next_to_clean == rx_ring->next_to_use)
4552c619601SSriram Yagnaraman 			xsk_set_rx_need_wakeup(xsk_pool);
4562c619601SSriram Yagnaraman 		else
4572c619601SSriram Yagnaraman 			xsk_clear_rx_need_wakeup(xsk_pool);
4582c619601SSriram Yagnaraman 
4592c619601SSriram Yagnaraman 		return (int)total_packets;
4602c619601SSriram Yagnaraman 	}
4612c619601SSriram Yagnaraman 	return failure ? budget : (int)total_packets;
4622c619601SSriram Yagnaraman }
4632c619601SSriram Yagnaraman 
464*f8e284a0SSriram Yagnaraman bool igb_xmit_zc(struct igb_ring *tx_ring, struct xsk_buff_pool *xsk_pool)
465*f8e284a0SSriram Yagnaraman {
466*f8e284a0SSriram Yagnaraman 	unsigned int budget = igb_desc_unused(tx_ring);
467*f8e284a0SSriram Yagnaraman 	u32 cmd_type, olinfo_status, nb_pkts, i = 0;
468*f8e284a0SSriram Yagnaraman 	struct xdp_desc *descs = xsk_pool->tx_descs;
469*f8e284a0SSriram Yagnaraman 	union e1000_adv_tx_desc *tx_desc = NULL;
470*f8e284a0SSriram Yagnaraman 	struct igb_tx_buffer *tx_buffer_info;
471*f8e284a0SSriram Yagnaraman 	unsigned int total_bytes = 0;
472*f8e284a0SSriram Yagnaraman 	dma_addr_t dma;
473*f8e284a0SSriram Yagnaraman 
474*f8e284a0SSriram Yagnaraman 	if (!netif_carrier_ok(tx_ring->netdev))
475*f8e284a0SSriram Yagnaraman 		return true;
476*f8e284a0SSriram Yagnaraman 
477*f8e284a0SSriram Yagnaraman 	if (test_bit(IGB_RING_FLAG_TX_DISABLED, &tx_ring->flags))
478*f8e284a0SSriram Yagnaraman 		return true;
479*f8e284a0SSriram Yagnaraman 
480*f8e284a0SSriram Yagnaraman 	nb_pkts = xsk_tx_peek_release_desc_batch(xsk_pool, budget);
481*f8e284a0SSriram Yagnaraman 	if (!nb_pkts)
482*f8e284a0SSriram Yagnaraman 		return true;
483*f8e284a0SSriram Yagnaraman 
484*f8e284a0SSriram Yagnaraman 	while (nb_pkts-- > 0) {
485*f8e284a0SSriram Yagnaraman 		dma = xsk_buff_raw_get_dma(xsk_pool, descs[i].addr);
486*f8e284a0SSriram Yagnaraman 		xsk_buff_raw_dma_sync_for_device(xsk_pool, dma, descs[i].len);
487*f8e284a0SSriram Yagnaraman 
488*f8e284a0SSriram Yagnaraman 		tx_buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
489*f8e284a0SSriram Yagnaraman 		tx_buffer_info->bytecount = descs[i].len;
490*f8e284a0SSriram Yagnaraman 		tx_buffer_info->type = IGB_TYPE_XSK;
491*f8e284a0SSriram Yagnaraman 		tx_buffer_info->xdpf = NULL;
492*f8e284a0SSriram Yagnaraman 		tx_buffer_info->gso_segs = 1;
493*f8e284a0SSriram Yagnaraman 		tx_buffer_info->time_stamp = jiffies;
494*f8e284a0SSriram Yagnaraman 
495*f8e284a0SSriram Yagnaraman 		tx_desc = IGB_TX_DESC(tx_ring, tx_ring->next_to_use);
496*f8e284a0SSriram Yagnaraman 		tx_desc->read.buffer_addr = cpu_to_le64(dma);
497*f8e284a0SSriram Yagnaraman 
498*f8e284a0SSriram Yagnaraman 		/* put descriptor type bits */
499*f8e284a0SSriram Yagnaraman 		cmd_type = E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_DEXT |
500*f8e284a0SSriram Yagnaraman 			   E1000_ADVTXD_DCMD_IFCS;
501*f8e284a0SSriram Yagnaraman 		olinfo_status = descs[i].len << E1000_ADVTXD_PAYLEN_SHIFT;
502*f8e284a0SSriram Yagnaraman 
503*f8e284a0SSriram Yagnaraman 		/* FIXME: This sets the Report Status (RS) bit for every
504*f8e284a0SSriram Yagnaraman 		 * descriptor. One nice to have optimization would be to set it
505*f8e284a0SSriram Yagnaraman 		 * only for the last descriptor in the whole batch. See Intel
506*f8e284a0SSriram Yagnaraman 		 * ice driver for an example on how to do it.
507*f8e284a0SSriram Yagnaraman 		 */
508*f8e284a0SSriram Yagnaraman 		cmd_type |= descs[i].len | IGB_TXD_DCMD;
509*f8e284a0SSriram Yagnaraman 		tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
510*f8e284a0SSriram Yagnaraman 		tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
511*f8e284a0SSriram Yagnaraman 
512*f8e284a0SSriram Yagnaraman 		total_bytes += descs[i].len;
513*f8e284a0SSriram Yagnaraman 
514*f8e284a0SSriram Yagnaraman 		i++;
515*f8e284a0SSriram Yagnaraman 		tx_ring->next_to_use++;
516*f8e284a0SSriram Yagnaraman 		tx_buffer_info->next_to_watch = tx_desc;
517*f8e284a0SSriram Yagnaraman 		if (tx_ring->next_to_use == tx_ring->count)
518*f8e284a0SSriram Yagnaraman 			tx_ring->next_to_use = 0;
519*f8e284a0SSriram Yagnaraman 	}
520*f8e284a0SSriram Yagnaraman 
521*f8e284a0SSriram Yagnaraman 	netdev_tx_sent_queue(txring_txq(tx_ring), total_bytes);
522*f8e284a0SSriram Yagnaraman 	igb_xdp_ring_update_tail(tx_ring);
523*f8e284a0SSriram Yagnaraman 
524*f8e284a0SSriram Yagnaraman 	return nb_pkts < budget;
525*f8e284a0SSriram Yagnaraman }
526*f8e284a0SSriram Yagnaraman 
52780f6ccf9SSriram Yagnaraman int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
52880f6ccf9SSriram Yagnaraman {
52980f6ccf9SSriram Yagnaraman 	struct igb_adapter *adapter = netdev_priv(dev);
53080f6ccf9SSriram Yagnaraman 	struct e1000_hw *hw = &adapter->hw;
53180f6ccf9SSriram Yagnaraman 	struct igb_ring *ring;
53280f6ccf9SSriram Yagnaraman 	u32 eics = 0;
53380f6ccf9SSriram Yagnaraman 
53480f6ccf9SSriram Yagnaraman 	if (test_bit(__IGB_DOWN, &adapter->state))
53580f6ccf9SSriram Yagnaraman 		return -ENETDOWN;
53680f6ccf9SSriram Yagnaraman 
53780f6ccf9SSriram Yagnaraman 	if (!igb_xdp_is_enabled(adapter))
53880f6ccf9SSriram Yagnaraman 		return -EINVAL;
53980f6ccf9SSriram Yagnaraman 
54080f6ccf9SSriram Yagnaraman 	if (qid >= adapter->num_tx_queues)
54180f6ccf9SSriram Yagnaraman 		return -EINVAL;
54280f6ccf9SSriram Yagnaraman 
54380f6ccf9SSriram Yagnaraman 	ring = adapter->tx_ring[qid];
54480f6ccf9SSriram Yagnaraman 
54580f6ccf9SSriram Yagnaraman 	if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
54680f6ccf9SSriram Yagnaraman 		return -ENETDOWN;
54780f6ccf9SSriram Yagnaraman 
54880f6ccf9SSriram Yagnaraman 	if (!READ_ONCE(ring->xsk_pool))
54980f6ccf9SSriram Yagnaraman 		return -EINVAL;
55080f6ccf9SSriram Yagnaraman 
55180f6ccf9SSriram Yagnaraman 	if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
55280f6ccf9SSriram Yagnaraman 		/* Cause software interrupt */
55380f6ccf9SSriram Yagnaraman 		if (adapter->flags & IGB_FLAG_HAS_MSIX) {
55480f6ccf9SSriram Yagnaraman 			eics |= ring->q_vector->eims_value;
55580f6ccf9SSriram Yagnaraman 			wr32(E1000_EICS, eics);
55680f6ccf9SSriram Yagnaraman 		} else {
55780f6ccf9SSriram Yagnaraman 			wr32(E1000_ICS, E1000_ICS_RXDMT0);
55880f6ccf9SSriram Yagnaraman 		}
55980f6ccf9SSriram Yagnaraman 	}
56080f6ccf9SSriram Yagnaraman 
56180f6ccf9SSriram Yagnaraman 	return 0;
56280f6ccf9SSriram Yagnaraman }
563