162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) 2022 Gerhard Engleder <gerhard@engleder-embedded.com> */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/if_vlan.h>
562306a36Sopenharmony_ci#include <net/xdp_sock_drv.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "tsnep.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ciint tsnep_xdp_setup_prog(struct tsnep_adapter *adapter, struct bpf_prog *prog,
1062306a36Sopenharmony_ci			 struct netlink_ext_ack *extack)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	struct bpf_prog *old_prog;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	old_prog = xchg(&adapter->xdp_prog, prog);
1562306a36Sopenharmony_ci	if (old_prog)
1662306a36Sopenharmony_ci		bpf_prog_put(old_prog);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	return 0;
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic int tsnep_xdp_enable_pool(struct tsnep_adapter *adapter,
2262306a36Sopenharmony_ci				 struct xsk_buff_pool *pool, u16 queue_id)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct tsnep_queue *queue;
2562306a36Sopenharmony_ci	int retval;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (queue_id >= adapter->num_rx_queues ||
2862306a36Sopenharmony_ci	    queue_id >= adapter->num_tx_queues)
2962306a36Sopenharmony_ci		return -EINVAL;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	queue = &adapter->queue[queue_id];
3262306a36Sopenharmony_ci	if (queue->rx->queue_index != queue_id ||
3362306a36Sopenharmony_ci	    queue->tx->queue_index != queue_id) {
3462306a36Sopenharmony_ci		netdev_err(adapter->netdev,
3562306a36Sopenharmony_ci			   "XSK support only for TX/RX queue pairs\n");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci		return -EOPNOTSUPP;
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	retval = xsk_pool_dma_map(pool, adapter->dmadev,
4162306a36Sopenharmony_ci				  DMA_ATTR_SKIP_CPU_SYNC);
4262306a36Sopenharmony_ci	if (retval) {
4362306a36Sopenharmony_ci		netdev_err(adapter->netdev, "failed to map XSK pool\n");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		return retval;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	retval = tsnep_enable_xsk(queue, pool);
4962306a36Sopenharmony_ci	if (retval) {
5062306a36Sopenharmony_ci		xsk_pool_dma_unmap(pool, DMA_ATTR_SKIP_CPU_SYNC);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		return retval;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int tsnep_xdp_disable_pool(struct tsnep_adapter *adapter, u16 queue_id)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct xsk_buff_pool *pool;
6162306a36Sopenharmony_ci	struct tsnep_queue *queue;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (queue_id >= adapter->num_rx_queues ||
6462306a36Sopenharmony_ci	    queue_id >= adapter->num_tx_queues)
6562306a36Sopenharmony_ci		return -EINVAL;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	pool = xsk_get_pool_from_qid(adapter->netdev, queue_id);
6862306a36Sopenharmony_ci	if (!pool)
6962306a36Sopenharmony_ci		return -EINVAL;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	queue = &adapter->queue[queue_id];
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	tsnep_disable_xsk(queue);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	xsk_pool_dma_unmap(pool, DMA_ATTR_SKIP_CPU_SYNC);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return 0;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciint tsnep_xdp_setup_pool(struct tsnep_adapter *adapter,
8162306a36Sopenharmony_ci			 struct xsk_buff_pool *pool, u16 queue_id)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	return pool ? tsnep_xdp_enable_pool(adapter, pool, queue_id) :
8462306a36Sopenharmony_ci		      tsnep_xdp_disable_pool(adapter, queue_id);
8562306a36Sopenharmony_ci}
86