mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
nfp: add XDP support in the driver
Add XDP support. Separate stack's and XDP's TX rings logically. Add functions for handling XDP_TX and cleanup of XDP's TX rings. For XDP allocate all RX buffers as separate pages and map them with DMA_BIDIRECTIONAL. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
68f929ff26
commit
ecd63a0217
@@ -171,7 +171,10 @@ struct nfp_net_tx_desc {
|
||||
* on the head's buffer). Equal to skb->len for non-TSO packets.
|
||||
*/
|
||||
struct nfp_net_tx_buf {
|
||||
struct sk_buff *skb;
|
||||
union {
|
||||
struct sk_buff *skb;
|
||||
void *frag;
|
||||
};
|
||||
dma_addr_t dma_addr;
|
||||
short int fidx;
|
||||
u16 pkt_cnt;
|
||||
@@ -341,6 +344,7 @@ struct nfp_net_rx_ring {
|
||||
* @napi: NAPI structure for this ring vec
|
||||
* @tx_ring: Pointer to TX ring
|
||||
* @rx_ring: Pointer to RX ring
|
||||
* @xdp_ring: Pointer to an extra TX ring for XDP
|
||||
* @irq_idx: Index into MSI-X table
|
||||
* @rx_sync: Seqlock for atomic updates of RX stats
|
||||
* @rx_pkts: Number of received packets
|
||||
@@ -384,6 +388,8 @@ struct nfp_net_r_vector {
|
||||
u64 hw_csum_rx_inner_ok;
|
||||
u64 hw_csum_rx_error;
|
||||
|
||||
struct nfp_net_tx_ring *xdp_ring;
|
||||
|
||||
struct u64_stats_sync tx_sync;
|
||||
u64 tx_pkts;
|
||||
u64 tx_bytes;
|
||||
@@ -432,6 +438,7 @@ struct nfp_stat_pair {
|
||||
* @ctrl: Local copy of the control register/word.
|
||||
* @fl_bufsz: Currently configured size of the freelist buffers
|
||||
* @rx_offset: Offset in the RX buffers where packet data starts
|
||||
* @xdp_prog: Installed XDP program
|
||||
* @cpp: Pointer to the CPP handle
|
||||
* @nfp_dev_cpp: Pointer to the NFP Device handle
|
||||
* @ctrl_area: Pointer to the CPP area for the control BAR
|
||||
@@ -451,6 +458,7 @@ struct nfp_stat_pair {
|
||||
* @max_tx_rings: Maximum number of TX rings supported by the Firmware
|
||||
* @max_rx_rings: Maximum number of RX rings supported by the Firmware
|
||||
* @num_tx_rings: Currently configured number of TX rings
|
||||
* @num_stack_tx_rings: Number of TX rings used by the stack (not XDP)
|
||||
* @num_rx_rings: Currently configured number of RX rings
|
||||
* @txd_cnt: Size of the TX ring in number of descriptors
|
||||
* @rxd_cnt: Size of the RX ring in number of descriptors
|
||||
@@ -500,6 +508,8 @@ struct nfp_net {
|
||||
|
||||
u32 rx_offset;
|
||||
|
||||
struct bpf_prog *xdp_prog;
|
||||
|
||||
struct nfp_net_tx_ring *tx_rings;
|
||||
struct nfp_net_rx_ring *rx_rings;
|
||||
|
||||
@@ -532,6 +542,7 @@ struct nfp_net {
|
||||
unsigned int max_rx_rings;
|
||||
|
||||
unsigned int num_tx_rings;
|
||||
unsigned int num_stack_tx_rings;
|
||||
unsigned int num_rx_rings;
|
||||
|
||||
int stride_tx;
|
||||
@@ -779,8 +790,8 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn);
|
||||
int nfp_net_irqs_alloc(struct nfp_net *nn);
|
||||
void nfp_net_irqs_disable(struct nfp_net *nn);
|
||||
int
|
||||
nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx,
|
||||
struct nfp_net_ring_set *tx);
|
||||
nfp_net_ring_reconfig(struct nfp_net *nn, struct bpf_prog **xdp_prog,
|
||||
struct nfp_net_ring_set *rx, struct nfp_net_ring_set *tx);
|
||||
|
||||
#ifdef CONFIG_NFP_NET_DEBUG
|
||||
void nfp_net_debugfs_create(void);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,16 @@ static const struct file_operations nfp_rx_q_fops = {
|
||||
.llseek = seq_lseek
|
||||
};
|
||||
|
||||
static int nfp_net_debugfs_tx_q_open(struct inode *inode, struct file *f);
|
||||
|
||||
static const struct file_operations nfp_tx_q_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = nfp_net_debugfs_tx_q_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek
|
||||
};
|
||||
|
||||
static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
|
||||
{
|
||||
struct nfp_net_r_vector *r_vec = file->private;
|
||||
@@ -126,10 +136,13 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (!r_vec->nfp_net || !r_vec->tx_ring)
|
||||
if (debugfs_real_fops(file->file) == &nfp_tx_q_fops)
|
||||
tx_ring = r_vec->tx_ring;
|
||||
else
|
||||
tx_ring = r_vec->xdp_ring;
|
||||
if (!r_vec->nfp_net || !tx_ring)
|
||||
goto out;
|
||||
nn = r_vec->nfp_net;
|
||||
tx_ring = r_vec->tx_ring;
|
||||
if (!netif_running(nn->netdev))
|
||||
goto out;
|
||||
|
||||
@@ -148,9 +161,14 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
|
||||
txd->vals[2], txd->vals[3]);
|
||||
|
||||
skb = READ_ONCE(tx_ring->txbufs[i].skb);
|
||||
if (skb)
|
||||
seq_printf(file, " skb->head=%p skb->data=%p",
|
||||
skb->head, skb->data);
|
||||
if (skb) {
|
||||
if (tx_ring == r_vec->tx_ring)
|
||||
seq_printf(file, " skb->head=%p skb->data=%p",
|
||||
skb->head, skb->data);
|
||||
else
|
||||
seq_printf(file, " frag=%p", skb);
|
||||
}
|
||||
|
||||
if (tx_ring->txbufs[i].dma_addr)
|
||||
seq_printf(file, " dma_addr=%pad",
|
||||
&tx_ring->txbufs[i].dma_addr);
|
||||
@@ -176,7 +194,7 @@ static int nfp_net_debugfs_tx_q_open(struct inode *inode, struct file *f)
|
||||
return single_open(f, nfp_net_debugfs_tx_q_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations nfp_tx_q_fops = {
|
||||
static const struct file_operations nfp_xdp_q_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = nfp_net_debugfs_tx_q_open,
|
||||
.release = single_release,
|
||||
@@ -186,7 +204,7 @@ static const struct file_operations nfp_tx_q_fops = {
|
||||
|
||||
void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
|
||||
{
|
||||
struct dentry *queues, *tx, *rx;
|
||||
struct dentry *queues, *tx, *rx, *xdp;
|
||||
char int_name[16];
|
||||
int i;
|
||||
|
||||
@@ -204,13 +222,16 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
|
||||
|
||||
rx = debugfs_create_dir("rx", queues);
|
||||
tx = debugfs_create_dir("tx", queues);
|
||||
if (IS_ERR_OR_NULL(rx) || IS_ERR_OR_NULL(tx))
|
||||
xdp = debugfs_create_dir("xdp", queues);
|
||||
if (IS_ERR_OR_NULL(rx) || IS_ERR_OR_NULL(tx) || IS_ERR_OR_NULL(xdp))
|
||||
return;
|
||||
|
||||
for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) {
|
||||
sprintf(int_name, "%d", i);
|
||||
debugfs_create_file(int_name, S_IRUSR, rx,
|
||||
&nn->r_vecs[i], &nfp_rx_q_fops);
|
||||
debugfs_create_file(int_name, S_IRUSR, xdp,
|
||||
&nn->r_vecs[i], &nfp_xdp_q_fops);
|
||||
}
|
||||
|
||||
for (i = 0; i < min(nn->max_tx_rings, nn->max_r_vecs); i++) {
|
||||
|
||||
@@ -176,7 +176,8 @@ static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
|
||||
if (nn->txd_cnt != txd_cnt)
|
||||
reconfig_tx = &tx;
|
||||
|
||||
return nfp_net_ring_reconfig(nn, reconfig_rx, reconfig_tx);
|
||||
return nfp_net_ring_reconfig(nn, &nn->xdp_prog,
|
||||
reconfig_rx, reconfig_tx);
|
||||
}
|
||||
|
||||
static int nfp_net_set_ringparam(struct net_device *netdev,
|
||||
@@ -639,14 +640,19 @@ static void nfp_net_get_channels(struct net_device *netdev,
|
||||
struct ethtool_channels *channel)
|
||||
{
|
||||
struct nfp_net *nn = netdev_priv(netdev);
|
||||
unsigned int num_tx_rings;
|
||||
|
||||
num_tx_rings = nn->num_tx_rings;
|
||||
if (nn->xdp_prog)
|
||||
num_tx_rings -= nn->num_rx_rings;
|
||||
|
||||
channel->max_rx = min(nn->max_rx_rings, nn->max_r_vecs);
|
||||
channel->max_tx = min(nn->max_tx_rings, nn->max_r_vecs);
|
||||
channel->max_combined = min(channel->max_rx, channel->max_tx);
|
||||
channel->max_other = NFP_NET_NON_Q_VECTORS;
|
||||
channel->combined_count = min(nn->num_rx_rings, nn->num_tx_rings);
|
||||
channel->combined_count = min(nn->num_rx_rings, num_tx_rings);
|
||||
channel->rx_count = nn->num_rx_rings - channel->combined_count;
|
||||
channel->tx_count = nn->num_tx_rings - channel->combined_count;
|
||||
channel->tx_count = num_tx_rings - channel->combined_count;
|
||||
channel->other_count = NFP_NET_NON_Q_VECTORS;
|
||||
}
|
||||
|
||||
@@ -666,10 +672,16 @@ static int nfp_net_set_num_rings(struct nfp_net *nn, unsigned int total_rx,
|
||||
|
||||
if (nn->num_rx_rings != total_rx)
|
||||
reconfig_rx = ℞
|
||||
if (nn->num_tx_rings != total_tx)
|
||||
if (nn->num_stack_tx_rings != total_tx ||
|
||||
(nn->xdp_prog && reconfig_rx))
|
||||
reconfig_tx = &tx;
|
||||
|
||||
return nfp_net_ring_reconfig(nn, reconfig_rx, reconfig_tx);
|
||||
/* nfp_net_check_config() will catch tx.n_rings > nn->max_tx_rings */
|
||||
if (nn->xdp_prog)
|
||||
tx.n_rings += total_rx;
|
||||
|
||||
return nfp_net_ring_reconfig(nn, &nn->xdp_prog,
|
||||
reconfig_rx, reconfig_tx);
|
||||
}
|
||||
|
||||
static int nfp_net_set_channels(struct net_device *netdev,
|
||||
|
||||
Reference in New Issue
Block a user