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