Commit ecd63a02 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

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: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 68f929ff
...@@ -171,7 +171,10 @@ struct nfp_net_tx_desc { ...@@ -171,7 +171,10 @@ struct nfp_net_tx_desc {
* on the head's buffer). Equal to skb->len for non-TSO packets. * on the head's buffer). Equal to skb->len for non-TSO packets.
*/ */
struct nfp_net_tx_buf { struct nfp_net_tx_buf {
struct sk_buff *skb; union {
struct sk_buff *skb;
void *frag;
};
dma_addr_t dma_addr; dma_addr_t dma_addr;
short int fidx; short int fidx;
u16 pkt_cnt; u16 pkt_cnt;
...@@ -341,6 +344,7 @@ struct nfp_net_rx_ring { ...@@ -341,6 +344,7 @@ struct nfp_net_rx_ring {
* @napi: NAPI structure for this ring vec * @napi: NAPI structure for this ring vec
* @tx_ring: Pointer to TX ring * @tx_ring: Pointer to TX ring
* @rx_ring: Pointer to RX ring * @rx_ring: Pointer to RX ring
* @xdp_ring: Pointer to an extra TX ring for XDP
* @irq_idx: Index into MSI-X table * @irq_idx: Index into MSI-X table
* @rx_sync: Seqlock for atomic updates of RX stats * @rx_sync: Seqlock for atomic updates of RX stats
* @rx_pkts: Number of received packets * @rx_pkts: Number of received packets
...@@ -384,6 +388,8 @@ struct nfp_net_r_vector { ...@@ -384,6 +388,8 @@ struct nfp_net_r_vector {
u64 hw_csum_rx_inner_ok; u64 hw_csum_rx_inner_ok;
u64 hw_csum_rx_error; u64 hw_csum_rx_error;
struct nfp_net_tx_ring *xdp_ring;
struct u64_stats_sync tx_sync; struct u64_stats_sync tx_sync;
u64 tx_pkts; u64 tx_pkts;
u64 tx_bytes; u64 tx_bytes;
...@@ -432,6 +438,7 @@ struct nfp_stat_pair { ...@@ -432,6 +438,7 @@ struct nfp_stat_pair {
* @ctrl: Local copy of the control register/word. * @ctrl: Local copy of the control register/word.
* @fl_bufsz: Currently configured size of the freelist buffers * @fl_bufsz: Currently configured size of the freelist buffers
* @rx_offset: Offset in the RX buffers where packet data starts * @rx_offset: Offset in the RX buffers where packet data starts
* @xdp_prog: Installed XDP program
* @cpp: Pointer to the CPP handle * @cpp: Pointer to the CPP handle
* @nfp_dev_cpp: Pointer to the NFP Device handle * @nfp_dev_cpp: Pointer to the NFP Device handle
* @ctrl_area: Pointer to the CPP area for the control BAR * @ctrl_area: Pointer to the CPP area for the control BAR
...@@ -451,6 +458,7 @@ struct nfp_stat_pair { ...@@ -451,6 +458,7 @@ struct nfp_stat_pair {
* @max_tx_rings: Maximum number of TX rings supported by the Firmware * @max_tx_rings: Maximum number of TX rings supported by the Firmware
* @max_rx_rings: Maximum number of RX 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_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 * @num_rx_rings: Currently configured number of RX rings
* @txd_cnt: Size of the TX ring in number of descriptors * @txd_cnt: Size of the TX ring in number of descriptors
* @rxd_cnt: Size of the RX ring in number of descriptors * @rxd_cnt: Size of the RX ring in number of descriptors
...@@ -500,6 +508,8 @@ struct nfp_net { ...@@ -500,6 +508,8 @@ struct nfp_net {
u32 rx_offset; u32 rx_offset;
struct bpf_prog *xdp_prog;
struct nfp_net_tx_ring *tx_rings; struct nfp_net_tx_ring *tx_rings;
struct nfp_net_rx_ring *rx_rings; struct nfp_net_rx_ring *rx_rings;
...@@ -532,6 +542,7 @@ struct nfp_net { ...@@ -532,6 +542,7 @@ struct nfp_net {
unsigned int max_rx_rings; unsigned int max_rx_rings;
unsigned int num_tx_rings; unsigned int num_tx_rings;
unsigned int num_stack_tx_rings;
unsigned int num_rx_rings; unsigned int num_rx_rings;
int stride_tx; int stride_tx;
...@@ -779,8 +790,8 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn); ...@@ -779,8 +790,8 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn);
int nfp_net_irqs_alloc(struct nfp_net *nn); int nfp_net_irqs_alloc(struct nfp_net *nn);
void nfp_net_irqs_disable(struct nfp_net *nn); void nfp_net_irqs_disable(struct nfp_net *nn);
int int
nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx, nfp_net_ring_reconfig(struct nfp_net *nn, struct bpf_prog **xdp_prog,
struct nfp_net_ring_set *tx); struct nfp_net_ring_set *rx, struct nfp_net_ring_set *tx);
#ifdef CONFIG_NFP_NET_DEBUG #ifdef CONFIG_NFP_NET_DEBUG
void nfp_net_debugfs_create(void); void nfp_net_debugfs_create(void);
......
...@@ -114,6 +114,16 @@ static const struct file_operations nfp_rx_q_fops = { ...@@ -114,6 +114,16 @@ static const struct file_operations nfp_rx_q_fops = {
.llseek = seq_lseek .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) static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
{ {
struct nfp_net_r_vector *r_vec = file->private; 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) ...@@ -126,10 +136,13 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
rtnl_lock(); 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; goto out;
nn = r_vec->nfp_net; nn = r_vec->nfp_net;
tx_ring = r_vec->tx_ring;
if (!netif_running(nn->netdev)) if (!netif_running(nn->netdev))
goto out; goto out;
...@@ -148,9 +161,14 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data) ...@@ -148,9 +161,14 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
txd->vals[2], txd->vals[3]); txd->vals[2], txd->vals[3]);
skb = READ_ONCE(tx_ring->txbufs[i].skb); skb = READ_ONCE(tx_ring->txbufs[i].skb);
if (skb) if (skb) {
seq_printf(file, " skb->head=%p skb->data=%p", if (tx_ring == r_vec->tx_ring)
skb->head, skb->data); 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) if (tx_ring->txbufs[i].dma_addr)
seq_printf(file, " dma_addr=%pad", seq_printf(file, " dma_addr=%pad",
&tx_ring->txbufs[i].dma_addr); &tx_ring->txbufs[i].dma_addr);
...@@ -176,7 +194,7 @@ static int nfp_net_debugfs_tx_q_open(struct inode *inode, struct file *f) ...@@ -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); 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, .owner = THIS_MODULE,
.open = nfp_net_debugfs_tx_q_open, .open = nfp_net_debugfs_tx_q_open,
.release = single_release, .release = single_release,
...@@ -186,7 +204,7 @@ static const struct file_operations nfp_tx_q_fops = { ...@@ -186,7 +204,7 @@ static const struct file_operations nfp_tx_q_fops = {
void nfp_net_debugfs_adapter_add(struct nfp_net *nn) 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]; char int_name[16];
int i; int i;
...@@ -204,13 +222,16 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn) ...@@ -204,13 +222,16 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
rx = debugfs_create_dir("rx", queues); rx = debugfs_create_dir("rx", queues);
tx = debugfs_create_dir("tx", 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; return;
for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) { for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) {
sprintf(int_name, "%d", i); sprintf(int_name, "%d", i);
debugfs_create_file(int_name, S_IRUSR, rx, debugfs_create_file(int_name, S_IRUSR, rx,
&nn->r_vecs[i], &nfp_rx_q_fops); &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++) { 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) ...@@ -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) if (nn->txd_cnt != txd_cnt)
reconfig_tx = &tx; 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, static int nfp_net_set_ringparam(struct net_device *netdev,
...@@ -639,14 +640,19 @@ static void nfp_net_get_channels(struct net_device *netdev, ...@@ -639,14 +640,19 @@ static void nfp_net_get_channels(struct net_device *netdev,
struct ethtool_channels *channel) struct ethtool_channels *channel)
{ {
struct nfp_net *nn = netdev_priv(netdev); 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_rx = min(nn->max_rx_rings, nn->max_r_vecs);
channel->max_tx = min(nn->max_tx_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_combined = min(channel->max_rx, channel->max_tx);
channel->max_other = NFP_NET_NON_Q_VECTORS; 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->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; 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, ...@@ -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) if (nn->num_rx_rings != total_rx)
reconfig_rx = &rx; reconfig_rx = &rx;
if (nn->num_tx_rings != total_tx) if (nn->num_stack_tx_rings != total_tx ||
(nn->xdp_prog && reconfig_rx))
reconfig_tx = &tx; 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, static int nfp_net_set_channels(struct net_device *netdev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment