Commit 24d390b2 authored by David S. Miller's avatar David S. Miller

Merge branch 'nfp-mtu-buffer-reconfig'

Jakub Kicinski says:

====================
MTU/buffer reconfig changes

I re-discussed MPLS/MTU internally, dropped it from the patch 1,
re-tested everything, found out I forgot about debugfs pointers,
fixed that as well.

v5:
 - don't reserve space in RX buffers for MPLS label stack
   (patch 1);
 - fix debugfs pointers to ring structures (patch 5).
v4:
 - cut down on unrelated patches;
 - don't "close" the device on error path.

--- v4 cover letter

Previous series included some not entirely related patches,
this one is cut down.  Main issue I'm trying to solve here
is that .ndo_change_mtu() in nfpvf driver is doing full
close/open to reallocate buffers - which if open fails
can result in device being basically closed even though
the interface is started.  As suggested by you I try to move
towards a paradigm where the resources are allocated first
and the MTU change is only done once I'm certain (almost)
nothing can fail.  Almost because I need to communicate
with FW and that can always time out.

Patch 1 fixes small issue.  Next 10 patches reorganize things
so that I can easily allocate new rings and sets of buffers
while the device is running.  Patches 13 and 15 reshape the
.ndo_change_mtu() and ethtool's ring-resize operation into
desired form.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 70f767d3 cc7c0333
...@@ -298,6 +298,8 @@ struct nfp_net_rx_buf { ...@@ -298,6 +298,8 @@ struct nfp_net_rx_buf {
* @rxds: Virtual address of FL/RX ring in host memory * @rxds: Virtual address of FL/RX ring in host memory
* @dma: DMA address of the FL/RX ring * @dma: DMA address of the FL/RX ring
* @size: Size, in bytes, of the FL/RX ring (needed to free) * @size: Size, in bytes, of the FL/RX ring (needed to free)
* @bufsz: Buffer allocation size for convenience of management routines
* (NOTE: this is in second cache line, do not use on fast path!)
*/ */
struct nfp_net_rx_ring { struct nfp_net_rx_ring {
struct nfp_net_r_vector *r_vec; struct nfp_net_r_vector *r_vec;
...@@ -319,6 +321,7 @@ struct nfp_net_rx_ring { ...@@ -319,6 +321,7 @@ struct nfp_net_rx_ring {
dma_addr_t dma; dma_addr_t dma;
unsigned int size; unsigned int size;
unsigned int bufsz;
} ____cacheline_aligned; } ____cacheline_aligned;
/** /**
...@@ -472,6 +475,9 @@ struct nfp_net { ...@@ -472,6 +475,9 @@ struct nfp_net {
u32 rx_offset; u32 rx_offset;
struct nfp_net_tx_ring *tx_rings;
struct nfp_net_rx_ring *rx_rings;
#ifdef CONFIG_PCI_IOV #ifdef CONFIG_PCI_IOV
unsigned int num_vfs; unsigned int num_vfs;
struct vf_data_storage *vfinfo; struct vf_data_storage *vfinfo;
...@@ -504,9 +510,6 @@ struct nfp_net { ...@@ -504,9 +510,6 @@ struct nfp_net {
int txd_cnt; int txd_cnt;
int rxd_cnt; int rxd_cnt;
struct nfp_net_tx_ring tx_rings[NFP_NET_MAX_TX_RINGS];
struct nfp_net_rx_ring rx_rings[NFP_NET_MAX_RX_RINGS];
u8 num_irqs; u8 num_irqs;
u8 num_r_vecs; u8 num_r_vecs;
struct nfp_net_r_vector r_vecs[NFP_NET_MAX_TX_RINGS]; struct nfp_net_r_vector r_vecs[NFP_NET_MAX_TX_RINGS];
...@@ -721,6 +724,7 @@ void nfp_net_rss_write_key(struct nfp_net *nn); ...@@ -721,6 +724,7 @@ void nfp_net_rss_write_key(struct nfp_net *nn);
void nfp_net_coalesce_write_cfg(struct nfp_net *nn); 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 nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt);
#ifdef CONFIG_NFP_NET_DEBUG #ifdef CONFIG_NFP_NET_DEBUG
void nfp_net_debugfs_create(void); void nfp_net_debugfs_create(void);
......
...@@ -347,12 +347,18 @@ static irqreturn_t nfp_net_irq_exn(int irq, void *data) ...@@ -347,12 +347,18 @@ static irqreturn_t nfp_net_irq_exn(int irq, void *data)
/** /**
* nfp_net_tx_ring_init() - Fill in the boilerplate for a TX ring * nfp_net_tx_ring_init() - Fill in the boilerplate for a TX ring
* @tx_ring: TX ring structure * @tx_ring: TX ring structure
* @r_vec: IRQ vector servicing this ring
* @idx: Ring index
*/ */
static void nfp_net_tx_ring_init(struct nfp_net_tx_ring *tx_ring) static void
nfp_net_tx_ring_init(struct nfp_net_tx_ring *tx_ring,
struct nfp_net_r_vector *r_vec, unsigned int idx)
{ {
struct nfp_net_r_vector *r_vec = tx_ring->r_vec;
struct nfp_net *nn = r_vec->nfp_net; struct nfp_net *nn = r_vec->nfp_net;
tx_ring->idx = idx;
tx_ring->r_vec = r_vec;
tx_ring->qcidx = tx_ring->idx * nn->stride_tx; tx_ring->qcidx = tx_ring->idx * nn->stride_tx;
tx_ring->qcp_q = nn->tx_bar + NFP_QCP_QUEUE_OFF(tx_ring->qcidx); tx_ring->qcp_q = nn->tx_bar + NFP_QCP_QUEUE_OFF(tx_ring->qcidx);
} }
...@@ -360,12 +366,18 @@ static void nfp_net_tx_ring_init(struct nfp_net_tx_ring *tx_ring) ...@@ -360,12 +366,18 @@ static void nfp_net_tx_ring_init(struct nfp_net_tx_ring *tx_ring)
/** /**
* nfp_net_rx_ring_init() - Fill in the boilerplate for a RX ring * nfp_net_rx_ring_init() - Fill in the boilerplate for a RX ring
* @rx_ring: RX ring structure * @rx_ring: RX ring structure
* @r_vec: IRQ vector servicing this ring
* @idx: Ring index
*/ */
static void nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring) static void
nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring,
struct nfp_net_r_vector *r_vec, unsigned int idx)
{ {
struct nfp_net_r_vector *r_vec = rx_ring->r_vec;
struct nfp_net *nn = r_vec->nfp_net; struct nfp_net *nn = r_vec->nfp_net;
rx_ring->idx = idx;
rx_ring->r_vec = r_vec;
rx_ring->fl_qcidx = rx_ring->idx * nn->stride_rx; rx_ring->fl_qcidx = rx_ring->idx * nn->stride_rx;
rx_ring->rx_qcidx = rx_ring->fl_qcidx + (nn->stride_rx - 1); rx_ring->rx_qcidx = rx_ring->fl_qcidx + (nn->stride_rx - 1);
...@@ -401,16 +413,6 @@ static void nfp_net_irqs_assign(struct net_device *netdev) ...@@ -401,16 +413,6 @@ static void nfp_net_irqs_assign(struct net_device *netdev)
r_vec->irq_idx = NFP_NET_NON_Q_VECTORS + r; r_vec->irq_idx = NFP_NET_NON_Q_VECTORS + r;
cpumask_set_cpu(r, &r_vec->affinity_mask); cpumask_set_cpu(r, &r_vec->affinity_mask);
r_vec->tx_ring = &nn->tx_rings[r];
nn->tx_rings[r].idx = r;
nn->tx_rings[r].r_vec = r_vec;
nfp_net_tx_ring_init(r_vec->tx_ring);
r_vec->rx_ring = &nn->rx_rings[r];
nn->rx_rings[r].idx = r;
nn->rx_rings[r].r_vec = r_vec;
nfp_net_rx_ring_init(r_vec->rx_ring);
} }
} }
...@@ -865,61 +867,59 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) ...@@ -865,61 +867,59 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring)
} }
/** /**
* nfp_net_tx_flush() - Free any untransmitted buffers currently on the TX ring * nfp_net_tx_ring_reset() - Free any untransmitted buffers and reset pointers
* @tx_ring: TX ring structure * @nn: NFP Net device
* @tx_ring: TX ring structure
* *
* Assumes that the device is stopped * Assumes that the device is stopped
*/ */
static void nfp_net_tx_flush(struct nfp_net_tx_ring *tx_ring) static void
nfp_net_tx_ring_reset(struct nfp_net *nn, struct nfp_net_tx_ring *tx_ring)
{ {
struct nfp_net_r_vector *r_vec = tx_ring->r_vec;
struct nfp_net *nn = r_vec->nfp_net;
struct pci_dev *pdev = nn->pdev;
const struct skb_frag_struct *frag; const struct skb_frag_struct *frag;
struct netdev_queue *nd_q; struct netdev_queue *nd_q;
struct sk_buff *skb; struct pci_dev *pdev = nn->pdev;
int nr_frags;
int fidx;
int idx;
while (tx_ring->rd_p != tx_ring->wr_p) { while (tx_ring->rd_p != tx_ring->wr_p) {
idx = tx_ring->rd_p % tx_ring->cnt; int nr_frags, fidx, idx;
struct sk_buff *skb;
idx = tx_ring->rd_p % tx_ring->cnt;
skb = tx_ring->txbufs[idx].skb; skb = tx_ring->txbufs[idx].skb;
if (skb) { nr_frags = skb_shinfo(skb)->nr_frags;
nr_frags = skb_shinfo(skb)->nr_frags; fidx = tx_ring->txbufs[idx].fidx;
fidx = tx_ring->txbufs[idx].fidx;
if (fidx == -1) {
if (fidx == -1) { /* unmap head */
/* unmap head */ dma_unmap_single(&pdev->dev,
dma_unmap_single(&pdev->dev, tx_ring->txbufs[idx].dma_addr,
tx_ring->txbufs[idx].dma_addr, skb_headlen(skb), DMA_TO_DEVICE);
skb_headlen(skb), } else {
DMA_TO_DEVICE); /* unmap fragment */
} else { frag = &skb_shinfo(skb)->frags[fidx];
/* unmap fragment */ dma_unmap_page(&pdev->dev,
frag = &skb_shinfo(skb)->frags[fidx]; tx_ring->txbufs[idx].dma_addr,
dma_unmap_page(&pdev->dev, skb_frag_size(frag), DMA_TO_DEVICE);
tx_ring->txbufs[idx].dma_addr,
skb_frag_size(frag),
DMA_TO_DEVICE);
}
/* check for last gather fragment */
if (fidx == nr_frags - 1)
dev_kfree_skb_any(skb);
tx_ring->txbufs[idx].dma_addr = 0;
tx_ring->txbufs[idx].skb = NULL;
tx_ring->txbufs[idx].fidx = -2;
} }
memset(&tx_ring->txds[idx], 0, sizeof(tx_ring->txds[idx])); /* check for last gather fragment */
if (fidx == nr_frags - 1)
dev_kfree_skb_any(skb);
tx_ring->txbufs[idx].dma_addr = 0;
tx_ring->txbufs[idx].skb = NULL;
tx_ring->txbufs[idx].fidx = -2;
tx_ring->qcp_rd_p++; tx_ring->qcp_rd_p++;
tx_ring->rd_p++; tx_ring->rd_p++;
} }
memset(tx_ring->txds, 0, sizeof(*tx_ring->txds) * tx_ring->cnt);
tx_ring->wr_p = 0;
tx_ring->rd_p = 0;
tx_ring->qcp_rd_p = 0;
tx_ring->wr_ptr_add = 0;
nd_q = netdev_get_tx_queue(nn->netdev, tx_ring->idx); nd_q = netdev_get_tx_queue(nn->netdev, tx_ring->idx);
netdev_tx_reset_queue(nd_q); netdev_tx_reset_queue(nd_q);
} }
...@@ -957,25 +957,27 @@ static inline int nfp_net_rx_space(struct nfp_net_rx_ring *rx_ring) ...@@ -957,25 +957,27 @@ static inline int nfp_net_rx_space(struct nfp_net_rx_ring *rx_ring)
* nfp_net_rx_alloc_one() - Allocate and map skb for RX * nfp_net_rx_alloc_one() - Allocate and map skb for RX
* @rx_ring: RX ring structure of the skb * @rx_ring: RX ring structure of the skb
* @dma_addr: Pointer to storage for DMA address (output param) * @dma_addr: Pointer to storage for DMA address (output param)
* @fl_bufsz: size of freelist buffers
* *
* This function will allcate a new skb, map it for DMA. * This function will allcate a new skb, map it for DMA.
* *
* Return: allocated skb or NULL on failure. * Return: allocated skb or NULL on failure.
*/ */
static struct sk_buff * static struct sk_buff *
nfp_net_rx_alloc_one(struct nfp_net_rx_ring *rx_ring, dma_addr_t *dma_addr) nfp_net_rx_alloc_one(struct nfp_net_rx_ring *rx_ring, dma_addr_t *dma_addr,
unsigned int fl_bufsz)
{ {
struct nfp_net *nn = rx_ring->r_vec->nfp_net; struct nfp_net *nn = rx_ring->r_vec->nfp_net;
struct sk_buff *skb; struct sk_buff *skb;
skb = netdev_alloc_skb(nn->netdev, nn->fl_bufsz); skb = netdev_alloc_skb(nn->netdev, fl_bufsz);
if (!skb) { if (!skb) {
nn_warn_ratelimit(nn, "Failed to alloc receive SKB\n"); nn_warn_ratelimit(nn, "Failed to alloc receive SKB\n");
return NULL; return NULL;
} }
*dma_addr = dma_map_single(&nn->pdev->dev, skb->data, *dma_addr = dma_map_single(&nn->pdev->dev, skb->data,
nn->fl_bufsz, DMA_FROM_DEVICE); fl_bufsz, DMA_FROM_DEVICE);
if (dma_mapping_error(&nn->pdev->dev, *dma_addr)) { if (dma_mapping_error(&nn->pdev->dev, *dma_addr)) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
nn_warn_ratelimit(nn, "Failed to map DMA RX buffer\n"); nn_warn_ratelimit(nn, "Failed to map DMA RX buffer\n");
...@@ -1020,61 +1022,100 @@ static void nfp_net_rx_give_one(struct nfp_net_rx_ring *rx_ring, ...@@ -1020,61 +1022,100 @@ static void nfp_net_rx_give_one(struct nfp_net_rx_ring *rx_ring,
} }
/** /**
* nfp_net_rx_flush() - Free any buffers currently on the RX ring * nfp_net_rx_ring_reset() - Reflect in SW state of freelist after disable
* @rx_ring: RX ring to remove buffers from * @rx_ring: RX ring structure
* *
* Assumes that the device is stopped * Warning: Do *not* call if ring buffers were never put on the FW freelist
* (i.e. device was not enabled)!
*/ */
static void nfp_net_rx_flush(struct nfp_net_rx_ring *rx_ring) static void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring)
{ {
struct nfp_net *nn = rx_ring->r_vec->nfp_net; unsigned int wr_idx, last_idx;
struct pci_dev *pdev = nn->pdev;
int idx;
while (rx_ring->rd_p != rx_ring->wr_p) { /* Move the empty entry to the end of the list */
idx = rx_ring->rd_p % rx_ring->cnt; wr_idx = rx_ring->wr_p % rx_ring->cnt;
last_idx = rx_ring->cnt - 1;
rx_ring->rxbufs[wr_idx].dma_addr = rx_ring->rxbufs[last_idx].dma_addr;
rx_ring->rxbufs[wr_idx].skb = rx_ring->rxbufs[last_idx].skb;
rx_ring->rxbufs[last_idx].dma_addr = 0;
rx_ring->rxbufs[last_idx].skb = NULL;
if (rx_ring->rxbufs[idx].skb) { memset(rx_ring->rxds, 0, sizeof(*rx_ring->rxds) * rx_ring->cnt);
dma_unmap_single(&pdev->dev, rx_ring->wr_p = 0;
rx_ring->rxbufs[idx].dma_addr, rx_ring->rd_p = 0;
nn->fl_bufsz, DMA_FROM_DEVICE); rx_ring->wr_ptr_add = 0;
dev_kfree_skb_any(rx_ring->rxbufs[idx].skb); }
rx_ring->rxbufs[idx].dma_addr = 0;
rx_ring->rxbufs[idx].skb = NULL;
}
memset(&rx_ring->rxds[idx], 0, sizeof(rx_ring->rxds[idx])); /**
* nfp_net_rx_ring_bufs_free() - Free any buffers currently on the RX ring
* @nn: NFP Net device
* @rx_ring: RX ring to remove buffers from
*
* Assumes that the device is stopped and buffers are in [0, ring->cnt - 1)
* entries. After device is disabled nfp_net_rx_ring_reset() must be called
* to restore required ring geometry.
*/
static void
nfp_net_rx_ring_bufs_free(struct nfp_net *nn, struct nfp_net_rx_ring *rx_ring)
{
struct pci_dev *pdev = nn->pdev;
unsigned int i;
rx_ring->rd_p++; for (i = 0; i < rx_ring->cnt - 1; i++) {
/* NULL skb can only happen when initial filling of the ring
* fails to allocate enough buffers and calls here to free
* already allocated ones.
*/
if (!rx_ring->rxbufs[i].skb)
continue;
dma_unmap_single(&pdev->dev, rx_ring->rxbufs[i].dma_addr,
rx_ring->bufsz, DMA_FROM_DEVICE);
dev_kfree_skb_any(rx_ring->rxbufs[i].skb);
rx_ring->rxbufs[i].dma_addr = 0;
rx_ring->rxbufs[i].skb = NULL;
} }
} }
/** /**
* nfp_net_rx_fill_freelist() - Attempt filling freelist with RX buffers * nfp_net_rx_ring_bufs_alloc() - Fill RX ring with buffers (don't give to FW)
* @rx_ring: RX ring to fill * @nn: NFP Net device
* * @rx_ring: RX ring to remove buffers from
* Try to fill as many buffers as possible into freelist. Return
* number of buffers added.
*
* Return: Number of freelist buffers added.
*/ */
static int nfp_net_rx_fill_freelist(struct nfp_net_rx_ring *rx_ring) static int
nfp_net_rx_ring_bufs_alloc(struct nfp_net *nn, struct nfp_net_rx_ring *rx_ring)
{ {
struct sk_buff *skb; struct nfp_net_rx_buf *rxbufs;
dma_addr_t dma_addr; unsigned int i;
rxbufs = rx_ring->rxbufs;
while (nfp_net_rx_space(rx_ring)) { for (i = 0; i < rx_ring->cnt - 1; i++) {
skb = nfp_net_rx_alloc_one(rx_ring, &dma_addr); rxbufs[i].skb =
if (!skb) { nfp_net_rx_alloc_one(rx_ring, &rxbufs[i].dma_addr,
nfp_net_rx_flush(rx_ring); rx_ring->bufsz);
if (!rxbufs[i].skb) {
nfp_net_rx_ring_bufs_free(nn, rx_ring);
return -ENOMEM; return -ENOMEM;
} }
nfp_net_rx_give_one(rx_ring, skb, dma_addr);
} }
return 0; return 0;
} }
/**
* nfp_net_rx_ring_fill_freelist() - Give buffers from the ring to FW
* @rx_ring: RX ring to fill
*/
static void nfp_net_rx_ring_fill_freelist(struct nfp_net_rx_ring *rx_ring)
{
unsigned int i;
for (i = 0; i < rx_ring->cnt - 1; i++)
nfp_net_rx_give_one(rx_ring, rx_ring->rxbufs[i].skb,
rx_ring->rxbufs[i].dma_addr);
}
/** /**
* nfp_net_rx_csum_has_errors() - group check if rxd has any csum errors * nfp_net_rx_csum_has_errors() - group check if rxd has any csum errors
* @flags: RX descriptor flags field in CPU byte order * @flags: RX descriptor flags field in CPU byte order
...@@ -1240,7 +1281,8 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) ...@@ -1240,7 +1281,8 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
skb = rx_ring->rxbufs[idx].skb; skb = rx_ring->rxbufs[idx].skb;
new_skb = nfp_net_rx_alloc_one(rx_ring, &new_dma_addr); new_skb = nfp_net_rx_alloc_one(rx_ring, &new_dma_addr,
nn->fl_bufsz);
if (!new_skb) { if (!new_skb) {
nfp_net_rx_give_one(rx_ring, rx_ring->rxbufs[idx].skb, nfp_net_rx_give_one(rx_ring, rx_ring->rxbufs[idx].skb,
rx_ring->rxbufs[idx].dma_addr); rx_ring->rxbufs[idx].dma_addr);
...@@ -1349,10 +1391,6 @@ static void nfp_net_tx_ring_free(struct nfp_net_tx_ring *tx_ring) ...@@ -1349,10 +1391,6 @@ static void nfp_net_tx_ring_free(struct nfp_net_tx_ring *tx_ring)
struct nfp_net *nn = r_vec->nfp_net; struct nfp_net *nn = r_vec->nfp_net;
struct pci_dev *pdev = nn->pdev; struct pci_dev *pdev = nn->pdev;
nn_writeq(nn, NFP_NET_CFG_TXR_ADDR(tx_ring->idx), 0);
nn_writeb(nn, NFP_NET_CFG_TXR_SZ(tx_ring->idx), 0);
nn_writeb(nn, NFP_NET_CFG_TXR_VEC(tx_ring->idx), 0);
kfree(tx_ring->txbufs); kfree(tx_ring->txbufs);
if (tx_ring->txds) if (tx_ring->txds)
...@@ -1360,11 +1398,6 @@ static void nfp_net_tx_ring_free(struct nfp_net_tx_ring *tx_ring) ...@@ -1360,11 +1398,6 @@ static void nfp_net_tx_ring_free(struct nfp_net_tx_ring *tx_ring)
tx_ring->txds, tx_ring->dma); tx_ring->txds, tx_ring->dma);
tx_ring->cnt = 0; tx_ring->cnt = 0;
tx_ring->wr_p = 0;
tx_ring->rd_p = 0;
tx_ring->qcp_rd_p = 0;
tx_ring->wr_ptr_add = 0;
tx_ring->txbufs = NULL; tx_ring->txbufs = NULL;
tx_ring->txds = NULL; tx_ring->txds = NULL;
tx_ring->dma = 0; tx_ring->dma = 0;
...@@ -1374,17 +1407,18 @@ static void nfp_net_tx_ring_free(struct nfp_net_tx_ring *tx_ring) ...@@ -1374,17 +1407,18 @@ static void nfp_net_tx_ring_free(struct nfp_net_tx_ring *tx_ring)
/** /**
* nfp_net_tx_ring_alloc() - Allocate resource for a TX ring * nfp_net_tx_ring_alloc() - Allocate resource for a TX ring
* @tx_ring: TX Ring structure to allocate * @tx_ring: TX Ring structure to allocate
* @cnt: Ring buffer count
* *
* Return: 0 on success, negative errno otherwise. * Return: 0 on success, negative errno otherwise.
*/ */
static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring) static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring, u32 cnt)
{ {
struct nfp_net_r_vector *r_vec = tx_ring->r_vec; struct nfp_net_r_vector *r_vec = tx_ring->r_vec;
struct nfp_net *nn = r_vec->nfp_net; struct nfp_net *nn = r_vec->nfp_net;
struct pci_dev *pdev = nn->pdev; struct pci_dev *pdev = nn->pdev;
int sz; int sz;
tx_ring->cnt = nn->txd_cnt; tx_ring->cnt = cnt;
tx_ring->size = sizeof(*tx_ring->txds) * tx_ring->cnt; tx_ring->size = sizeof(*tx_ring->txds) * tx_ring->cnt;
tx_ring->txds = dma_zalloc_coherent(&pdev->dev, tx_ring->size, tx_ring->txds = dma_zalloc_coherent(&pdev->dev, tx_ring->size,
...@@ -1397,11 +1431,6 @@ static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring) ...@@ -1397,11 +1431,6 @@ static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring)
if (!tx_ring->txbufs) if (!tx_ring->txbufs)
goto err_alloc; goto err_alloc;
/* Write the DMA address, size and MSI-X info to the device */
nn_writeq(nn, NFP_NET_CFG_TXR_ADDR(tx_ring->idx), tx_ring->dma);
nn_writeb(nn, NFP_NET_CFG_TXR_SZ(tx_ring->idx), ilog2(tx_ring->cnt));
nn_writeb(nn, NFP_NET_CFG_TXR_VEC(tx_ring->idx), r_vec->irq_idx);
netif_set_xps_queue(nn->netdev, &r_vec->affinity_mask, tx_ring->idx); netif_set_xps_queue(nn->netdev, &r_vec->affinity_mask, tx_ring->idx);
nn_dbg(nn, "TxQ%02d: QCidx=%02d cnt=%d dma=%#llx host=%p\n", nn_dbg(nn, "TxQ%02d: QCidx=%02d cnt=%d dma=%#llx host=%p\n",
...@@ -1415,6 +1444,59 @@ static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring) ...@@ -1415,6 +1444,59 @@ static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring)
return -ENOMEM; return -ENOMEM;
} }
static struct nfp_net_tx_ring *
nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt)
{
struct nfp_net_tx_ring *rings;
unsigned int r;
rings = kcalloc(nn->num_tx_rings, sizeof(*rings), GFP_KERNEL);
if (!rings)
return NULL;
for (r = 0; r < nn->num_tx_rings; r++) {
nfp_net_tx_ring_init(&rings[r], nn->tx_rings[r].r_vec, r);
if (nfp_net_tx_ring_alloc(&rings[r], buf_cnt))
goto err_free_prev;
}
return rings;
err_free_prev:
while (r--)
nfp_net_tx_ring_free(&rings[r]);
kfree(rings);
return NULL;
}
static struct nfp_net_tx_ring *
nfp_net_shadow_tx_rings_swap(struct nfp_net *nn, struct nfp_net_tx_ring *rings)
{
struct nfp_net_tx_ring *old = nn->tx_rings;
unsigned int r;
for (r = 0; r < nn->num_tx_rings; r++)
old[r].r_vec->tx_ring = &rings[r];
nn->tx_rings = rings;
return old;
}
static void
nfp_net_shadow_tx_rings_free(struct nfp_net *nn, struct nfp_net_tx_ring *rings)
{
unsigned int r;
if (!rings)
return;
for (r = 0; r < nn->num_tx_rings; r++)
nfp_net_tx_ring_free(&rings[r]);
kfree(rings);
}
/** /**
* nfp_net_rx_ring_free() - Free resources allocated to a RX ring * nfp_net_rx_ring_free() - Free resources allocated to a RX ring
* @rx_ring: RX ring to free * @rx_ring: RX ring to free
...@@ -1425,10 +1507,6 @@ static void nfp_net_rx_ring_free(struct nfp_net_rx_ring *rx_ring) ...@@ -1425,10 +1507,6 @@ static void nfp_net_rx_ring_free(struct nfp_net_rx_ring *rx_ring)
struct nfp_net *nn = r_vec->nfp_net; struct nfp_net *nn = r_vec->nfp_net;
struct pci_dev *pdev = nn->pdev; struct pci_dev *pdev = nn->pdev;
nn_writeq(nn, NFP_NET_CFG_RXR_ADDR(rx_ring->idx), 0);
nn_writeb(nn, NFP_NET_CFG_RXR_SZ(rx_ring->idx), 0);
nn_writeb(nn, NFP_NET_CFG_RXR_VEC(rx_ring->idx), 0);
kfree(rx_ring->rxbufs); kfree(rx_ring->rxbufs);
if (rx_ring->rxds) if (rx_ring->rxds)
...@@ -1436,10 +1514,6 @@ static void nfp_net_rx_ring_free(struct nfp_net_rx_ring *rx_ring) ...@@ -1436,10 +1514,6 @@ static void nfp_net_rx_ring_free(struct nfp_net_rx_ring *rx_ring)
rx_ring->rxds, rx_ring->dma); rx_ring->rxds, rx_ring->dma);
rx_ring->cnt = 0; rx_ring->cnt = 0;
rx_ring->wr_p = 0;
rx_ring->rd_p = 0;
rx_ring->wr_ptr_add = 0;
rx_ring->rxbufs = NULL; rx_ring->rxbufs = NULL;
rx_ring->rxds = NULL; rx_ring->rxds = NULL;
rx_ring->dma = 0; rx_ring->dma = 0;
...@@ -1449,17 +1523,22 @@ static void nfp_net_rx_ring_free(struct nfp_net_rx_ring *rx_ring) ...@@ -1449,17 +1523,22 @@ static void nfp_net_rx_ring_free(struct nfp_net_rx_ring *rx_ring)
/** /**
* nfp_net_rx_ring_alloc() - Allocate resource for a RX ring * nfp_net_rx_ring_alloc() - Allocate resource for a RX ring
* @rx_ring: RX ring to allocate * @rx_ring: RX ring to allocate
* @fl_bufsz: Size of buffers to allocate
* @cnt: Ring buffer count
* *
* Return: 0 on success, negative errno otherwise. * Return: 0 on success, negative errno otherwise.
*/ */
static int nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring) static int
nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring, unsigned int fl_bufsz,
u32 cnt)
{ {
struct nfp_net_r_vector *r_vec = rx_ring->r_vec; struct nfp_net_r_vector *r_vec = rx_ring->r_vec;
struct nfp_net *nn = r_vec->nfp_net; struct nfp_net *nn = r_vec->nfp_net;
struct pci_dev *pdev = nn->pdev; struct pci_dev *pdev = nn->pdev;
int sz; int sz;
rx_ring->cnt = nn->rxd_cnt; rx_ring->cnt = cnt;
rx_ring->bufsz = fl_bufsz;
rx_ring->size = sizeof(*rx_ring->rxds) * rx_ring->cnt; rx_ring->size = sizeof(*rx_ring->rxds) * rx_ring->cnt;
rx_ring->rxds = dma_zalloc_coherent(&pdev->dev, rx_ring->size, rx_ring->rxds = dma_zalloc_coherent(&pdev->dev, rx_ring->size,
...@@ -1472,11 +1551,6 @@ static int nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring) ...@@ -1472,11 +1551,6 @@ static int nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring)
if (!rx_ring->rxbufs) if (!rx_ring->rxbufs)
goto err_alloc; goto err_alloc;
/* Write the DMA address, size and MSI-X info to the device */
nn_writeq(nn, NFP_NET_CFG_RXR_ADDR(rx_ring->idx), rx_ring->dma);
nn_writeb(nn, NFP_NET_CFG_RXR_SZ(rx_ring->idx), ilog2(rx_ring->cnt));
nn_writeb(nn, NFP_NET_CFG_RXR_VEC(rx_ring->idx), r_vec->irq_idx);
nn_dbg(nn, "RxQ%02d: FlQCidx=%02d RxQCidx=%02d cnt=%d dma=%#llx host=%p\n", nn_dbg(nn, "RxQ%02d: FlQCidx=%02d RxQCidx=%02d cnt=%d dma=%#llx host=%p\n",
rx_ring->idx, rx_ring->fl_qcidx, rx_ring->rx_qcidx, rx_ring->idx, rx_ring->fl_qcidx, rx_ring->rx_qcidx,
rx_ring->cnt, (unsigned long long)rx_ring->dma, rx_ring->rxds); rx_ring->cnt, (unsigned long long)rx_ring->dma, rx_ring->rxds);
...@@ -1488,91 +1562,109 @@ static int nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring) ...@@ -1488,91 +1562,109 @@ static int nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring)
return -ENOMEM; return -ENOMEM;
} }
static void __nfp_net_free_rings(struct nfp_net *nn, unsigned int n_free) static struct nfp_net_rx_ring *
nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz,
u32 buf_cnt)
{ {
struct nfp_net_r_vector *r_vec; struct nfp_net_rx_ring *rings;
struct msix_entry *entry; unsigned int r;
while (n_free--) { rings = kcalloc(nn->num_rx_rings, sizeof(*rings), GFP_KERNEL);
r_vec = &nn->r_vecs[n_free]; if (!rings)
entry = &nn->irq_entries[r_vec->irq_idx]; return NULL;
nfp_net_rx_ring_free(r_vec->rx_ring); for (r = 0; r < nn->num_rx_rings; r++) {
nfp_net_tx_ring_free(r_vec->tx_ring); nfp_net_rx_ring_init(&rings[r], nn->rx_rings[r].r_vec, r);
irq_set_affinity_hint(entry->vector, NULL); if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz, buf_cnt))
free_irq(entry->vector, r_vec); goto err_free_prev;
netif_napi_del(&r_vec->napi); if (nfp_net_rx_ring_bufs_alloc(nn, &rings[r]))
goto err_free_ring;
}
return rings;
err_free_prev:
while (r--) {
nfp_net_rx_ring_bufs_free(nn, &rings[r]);
err_free_ring:
nfp_net_rx_ring_free(&rings[r]);
} }
kfree(rings);
return NULL;
} }
/** static struct nfp_net_rx_ring *
* nfp_net_free_rings() - Free all ring resources nfp_net_shadow_rx_rings_swap(struct nfp_net *nn, struct nfp_net_rx_ring *rings)
* @nn: NFP Net device to reconfigure
*/
static void nfp_net_free_rings(struct nfp_net *nn)
{ {
__nfp_net_free_rings(nn, nn->num_r_vecs); struct nfp_net_rx_ring *old = nn->rx_rings;
unsigned int r;
for (r = 0; r < nn->num_rx_rings; r++)
old[r].r_vec->rx_ring = &rings[r];
nn->rx_rings = rings;
return old;
} }
/** static void
* nfp_net_alloc_rings() - Allocate resources for RX and TX rings nfp_net_shadow_rx_rings_free(struct nfp_net *nn, struct nfp_net_rx_ring *rings)
* @nn: NFP Net device to reconfigure
*
* Return: 0 on success or negative errno on error.
*/
static int nfp_net_alloc_rings(struct nfp_net *nn)
{ {
struct nfp_net_r_vector *r_vec; unsigned int r;
struct msix_entry *entry;
int err; if (!rings)
int r; return;
for (r = 0; r < nn->num_r_vecs; r++) { for (r = 0; r < nn->num_r_vecs; r++) {
r_vec = &nn->r_vecs[r]; nfp_net_rx_ring_bufs_free(nn, &rings[r]);
entry = &nn->irq_entries[r_vec->irq_idx]; nfp_net_rx_ring_free(&rings[r]);
}
/* Setup NAPI */
netif_napi_add(nn->netdev, &r_vec->napi,
nfp_net_poll, NAPI_POLL_WEIGHT);
snprintf(r_vec->name, sizeof(r_vec->name),
"%s-rxtx-%d", nn->netdev->name, r);
err = request_irq(entry->vector, r_vec->handler, 0,
r_vec->name, r_vec);
if (err) {
nn_dbg(nn, "Error requesting IRQ %d\n", entry->vector);
goto err_napi_del;
}
irq_set_affinity_hint(entry->vector, &r_vec->affinity_mask); kfree(rings);
}
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", static int
r, entry->vector, entry->entry); nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
int idx)
{
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
int err;
/* Allocate TX ring resources */ r_vec->tx_ring = &nn->tx_rings[idx];
err = nfp_net_tx_ring_alloc(r_vec->tx_ring); nfp_net_tx_ring_init(r_vec->tx_ring, r_vec, idx);
if (err)
goto err_free_irq;
/* Allocate RX ring resources */ r_vec->rx_ring = &nn->rx_rings[idx];
err = nfp_net_rx_ring_alloc(r_vec->rx_ring); nfp_net_rx_ring_init(r_vec->rx_ring, r_vec, idx);
if (err)
goto err_free_tx; snprintf(r_vec->name, sizeof(r_vec->name),
"%s-rxtx-%d", nn->netdev->name, idx);
err = request_irq(entry->vector, r_vec->handler, 0, r_vec->name, r_vec);
if (err) {
nn_err(nn, "Error requesting IRQ %d\n", entry->vector);
return err;
} }
disable_irq(entry->vector);
/* Setup NAPI */
netif_napi_add(nn->netdev, &r_vec->napi,
nfp_net_poll, NAPI_POLL_WEIGHT);
irq_set_affinity_hint(entry->vector, &r_vec->affinity_mask);
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, entry->vector, entry->entry);
return 0; return 0;
}
static void
nfp_net_cleanup_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec)
{
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
err_free_tx:
nfp_net_tx_ring_free(r_vec->tx_ring);
err_free_irq:
irq_set_affinity_hint(entry->vector, NULL); irq_set_affinity_hint(entry->vector, NULL);
free_irq(entry->vector, r_vec);
err_napi_del:
netif_napi_del(&r_vec->napi); netif_napi_del(&r_vec->napi);
__nfp_net_free_rings(nn, r); free_irq(entry->vector, r_vec);
return err;
} }
/** /**
...@@ -1646,6 +1738,17 @@ static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *mac) ...@@ -1646,6 +1738,17 @@ static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *mac)
get_unaligned_be16(nn->netdev->dev_addr + 4) << 16); get_unaligned_be16(nn->netdev->dev_addr + 4) << 16);
} }
static void nfp_net_vec_clear_ring_data(struct nfp_net *nn, unsigned int idx)
{
nn_writeq(nn, NFP_NET_CFG_RXR_ADDR(idx), 0);
nn_writeb(nn, NFP_NET_CFG_RXR_SZ(idx), 0);
nn_writeb(nn, NFP_NET_CFG_RXR_VEC(idx), 0);
nn_writeq(nn, NFP_NET_CFG_TXR_ADDR(idx), 0);
nn_writeb(nn, NFP_NET_CFG_TXR_SZ(idx), 0);
nn_writeb(nn, NFP_NET_CFG_TXR_VEC(idx), 0);
}
/** /**
* nfp_net_clear_config_and_disable() - Clear control BAR and disable NFP * nfp_net_clear_config_and_disable() - Clear control BAR and disable NFP
* @nn: NFP Net device to reconfigure * @nn: NFP Net device to reconfigure
...@@ -1653,6 +1756,7 @@ static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *mac) ...@@ -1653,6 +1756,7 @@ static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *mac)
static void nfp_net_clear_config_and_disable(struct nfp_net *nn) static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
{ {
u32 new_ctrl, update; u32 new_ctrl, update;
unsigned int r;
int err; int err;
new_ctrl = nn->ctrl; new_ctrl = nn->ctrl;
...@@ -1669,79 +1773,40 @@ static void nfp_net_clear_config_and_disable(struct nfp_net *nn) ...@@ -1669,79 +1773,40 @@ static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl); nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
err = nfp_net_reconfig(nn, update); err = nfp_net_reconfig(nn, update);
if (err) { if (err)
nn_err(nn, "Could not disable device: %d\n", err); nn_err(nn, "Could not disable device: %d\n", err);
return;
for (r = 0; r < nn->num_r_vecs; r++) {
nfp_net_rx_ring_reset(nn->r_vecs[r].rx_ring);
nfp_net_tx_ring_reset(nn, nn->r_vecs[r].tx_ring);
nfp_net_vec_clear_ring_data(nn, r);
} }
nn->ctrl = new_ctrl; nn->ctrl = new_ctrl;
} }
/** static void
* nfp_net_start_vec() - Start ring vector nfp_net_vec_write_ring_data(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
* @nn: NFP Net device structure unsigned int idx)
* @r_vec: Ring vector to be started
*/
static int nfp_net_start_vec(struct nfp_net *nn, struct nfp_net_r_vector *r_vec)
{ {
unsigned int irq_vec; /* Write the DMA address, size and MSI-X info to the device */
int err = 0; nn_writeq(nn, NFP_NET_CFG_RXR_ADDR(idx), r_vec->rx_ring->dma);
nn_writeb(nn, NFP_NET_CFG_RXR_SZ(idx), ilog2(r_vec->rx_ring->cnt));
irq_vec = nn->irq_entries[r_vec->irq_idx].vector; nn_writeb(nn, NFP_NET_CFG_RXR_VEC(idx), r_vec->irq_idx);
disable_irq(irq_vec);
err = nfp_net_rx_fill_freelist(r_vec->rx_ring);
if (err) {
nn_err(nn, "RV%02d: couldn't allocate enough buffers\n",
r_vec->irq_idx);
goto out;
}
napi_enable(&r_vec->napi);
out:
enable_irq(irq_vec);
return err; nn_writeq(nn, NFP_NET_CFG_TXR_ADDR(idx), r_vec->tx_ring->dma);
nn_writeb(nn, NFP_NET_CFG_TXR_SZ(idx), ilog2(r_vec->tx_ring->cnt));
nn_writeb(nn, NFP_NET_CFG_TXR_VEC(idx), r_vec->irq_idx);
} }
static int nfp_net_netdev_open(struct net_device *netdev) static int __nfp_net_set_config_and_enable(struct nfp_net *nn)
{ {
struct nfp_net *nn = netdev_priv(netdev); u32 new_ctrl, update = 0;
int err, r; unsigned int r;
u32 update = 0; int err;
u32 new_ctrl;
if (nn->ctrl & NFP_NET_CFG_CTRL_ENABLE) {
nn_err(nn, "Dev is already enabled: 0x%08x\n", nn->ctrl);
return -EBUSY;
}
new_ctrl = nn->ctrl; new_ctrl = nn->ctrl;
/* Step 1: Allocate resources for rings and the like
* - Request interrupts
* - Allocate RX and TX ring resources
* - Setup initial RSS table
*/
err = nfp_net_aux_irq_request(nn, NFP_NET_CFG_EXN, "%s-exn",
nn->exn_name, sizeof(nn->exn_name),
NFP_NET_IRQ_EXN_IDX, nn->exn_handler);
if (err)
return err;
err = nfp_net_alloc_rings(nn);
if (err)
goto err_free_exn;
err = netif_set_real_num_tx_queues(netdev, nn->num_tx_rings);
if (err)
goto err_free_rings;
err = netif_set_real_num_rx_queues(netdev, nn->num_rx_rings);
if (err)
goto err_free_rings;
if (nn->cap & NFP_NET_CFG_CTRL_RSS) { if (nn->cap & NFP_NET_CFG_CTRL_RSS) {
nfp_net_rss_write_key(nn); nfp_net_rss_write_key(nn);
nfp_net_rss_write_itbl(nn); nfp_net_rss_write_itbl(nn);
...@@ -1756,22 +1821,18 @@ static int nfp_net_netdev_open(struct net_device *netdev) ...@@ -1756,22 +1821,18 @@ static int nfp_net_netdev_open(struct net_device *netdev)
update |= NFP_NET_CFG_UPDATE_IRQMOD; update |= NFP_NET_CFG_UPDATE_IRQMOD;
} }
/* Step 2: Configure the NFP for (r = 0; r < nn->num_r_vecs; r++)
* - Enable rings from 0 to tx_rings/rx_rings - 1. nfp_net_vec_write_ring_data(nn, &nn->r_vecs[r], r);
* - Write MAC address (in case it changed)
* - Set the MTU
* - Set the Freelist buffer size
* - Enable the FW
*/
nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, nn->num_tx_rings == 64 ? nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, nn->num_tx_rings == 64 ?
0xffffffffffffffffULL : ((u64)1 << nn->num_tx_rings) - 1); 0xffffffffffffffffULL : ((u64)1 << nn->num_tx_rings) - 1);
nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, nn->num_rx_rings == 64 ? nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, nn->num_rx_rings == 64 ?
0xffffffffffffffffULL : ((u64)1 << nn->num_rx_rings) - 1); 0xffffffffffffffffULL : ((u64)1 << nn->num_rx_rings) - 1);
nfp_net_write_mac_addr(nn, netdev->dev_addr); nfp_net_write_mac_addr(nn, nn->netdev->dev_addr);
nn_writel(nn, NFP_NET_CFG_MTU, netdev->mtu); nn_writel(nn, NFP_NET_CFG_MTU, nn->netdev->mtu);
nn_writel(nn, NFP_NET_CFG_FLBUFSZ, nn->fl_bufsz); nn_writel(nn, NFP_NET_CFG_FLBUFSZ, nn->fl_bufsz);
/* Enable device */ /* Enable device */
...@@ -1784,61 +1845,206 @@ static int nfp_net_netdev_open(struct net_device *netdev) ...@@ -1784,61 +1845,206 @@ static int nfp_net_netdev_open(struct net_device *netdev)
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl); nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
err = nfp_net_reconfig(nn, update); err = nfp_net_reconfig(nn, update);
if (err)
goto err_clear_config;
nn->ctrl = new_ctrl; nn->ctrl = new_ctrl;
for (r = 0; r < nn->num_r_vecs; r++)
nfp_net_rx_ring_fill_freelist(nn->r_vecs[r].rx_ring);
/* Since reconfiguration requests while NFP is down are ignored we /* Since reconfiguration requests while NFP is down are ignored we
* have to wipe the entire VXLAN configuration and reinitialize it. * have to wipe the entire VXLAN configuration and reinitialize it.
*/ */
if (nn->ctrl & NFP_NET_CFG_CTRL_VXLAN) { if (nn->ctrl & NFP_NET_CFG_CTRL_VXLAN) {
memset(&nn->vxlan_ports, 0, sizeof(nn->vxlan_ports)); memset(&nn->vxlan_ports, 0, sizeof(nn->vxlan_ports));
memset(&nn->vxlan_usecnt, 0, sizeof(nn->vxlan_usecnt)); memset(&nn->vxlan_usecnt, 0, sizeof(nn->vxlan_usecnt));
vxlan_get_rx_port(netdev); vxlan_get_rx_port(nn->netdev);
} }
/* Step 3: Enable for kernel return err;
* - put some freelist descriptors on each RX ring }
* - enable NAPI on each ring
* - enable all TX queues /**
* - set link state * nfp_net_set_config_and_enable() - Write control BAR and enable NFP
*/ * @nn: NFP Net device to reconfigure
*/
static int nfp_net_set_config_and_enable(struct nfp_net *nn)
{
int err;
err = __nfp_net_set_config_and_enable(nn);
if (err)
nfp_net_clear_config_and_disable(nn);
return err;
}
/**
* nfp_net_open_stack() - Start the device from stack's perspective
* @nn: NFP Net device to reconfigure
*/
static void nfp_net_open_stack(struct nfp_net *nn)
{
unsigned int r;
for (r = 0; r < nn->num_r_vecs; r++) { for (r = 0; r < nn->num_r_vecs; r++) {
err = nfp_net_start_vec(nn, &nn->r_vecs[r]); napi_enable(&nn->r_vecs[r].napi);
if (err) enable_irq(nn->irq_entries[nn->r_vecs[r].irq_idx].vector);
goto err_disable_napi;
} }
netif_tx_wake_all_queues(netdev); netif_tx_wake_all_queues(nn->netdev);
enable_irq(nn->irq_entries[NFP_NET_CFG_LSC].vector);
nfp_net_read_link_status(nn);
}
static int nfp_net_netdev_open(struct net_device *netdev)
{
struct nfp_net *nn = netdev_priv(netdev);
int err, r;
if (nn->ctrl & NFP_NET_CFG_CTRL_ENABLE) {
nn_err(nn, "Dev is already enabled: 0x%08x\n", nn->ctrl);
return -EBUSY;
}
/* Step 1: Allocate resources for rings and the like
* - Request interrupts
* - Allocate RX and TX ring resources
* - Setup initial RSS table
*/
err = nfp_net_aux_irq_request(nn, NFP_NET_CFG_EXN, "%s-exn",
nn->exn_name, sizeof(nn->exn_name),
NFP_NET_IRQ_EXN_IDX, nn->exn_handler);
if (err)
return err;
err = nfp_net_aux_irq_request(nn, NFP_NET_CFG_LSC, "%s-lsc", err = nfp_net_aux_irq_request(nn, NFP_NET_CFG_LSC, "%s-lsc",
nn->lsc_name, sizeof(nn->lsc_name), nn->lsc_name, sizeof(nn->lsc_name),
NFP_NET_IRQ_LSC_IDX, nn->lsc_handler); NFP_NET_IRQ_LSC_IDX, nn->lsc_handler);
if (err) if (err)
goto err_stop_tx; goto err_free_exn;
nfp_net_read_link_status(nn); disable_irq(nn->irq_entries[NFP_NET_CFG_LSC].vector);
return 0; nn->rx_rings = kcalloc(nn->num_rx_rings, sizeof(*nn->rx_rings),
GFP_KERNEL);
if (!nn->rx_rings)
goto err_free_lsc;
nn->tx_rings = kcalloc(nn->num_tx_rings, sizeof(*nn->tx_rings),
GFP_KERNEL);
if (!nn->tx_rings)
goto err_free_rx_rings;
err_stop_tx: for (r = 0; r < nn->num_r_vecs; r++) {
netif_tx_disable(netdev); err = nfp_net_prepare_vector(nn, &nn->r_vecs[r], r);
for (r = 0; r < nn->num_r_vecs; r++) if (err)
nfp_net_tx_flush(nn->r_vecs[r].tx_ring); goto err_free_prev_vecs;
err_disable_napi:
while (r--) { err = nfp_net_tx_ring_alloc(nn->r_vecs[r].tx_ring, nn->txd_cnt);
napi_disable(&nn->r_vecs[r].napi); if (err)
nfp_net_rx_flush(nn->r_vecs[r].rx_ring); goto err_cleanup_vec_p;
err = nfp_net_rx_ring_alloc(nn->r_vecs[r].rx_ring,
nn->fl_bufsz, nn->rxd_cnt);
if (err)
goto err_free_tx_ring_p;
err = nfp_net_rx_ring_bufs_alloc(nn, nn->r_vecs[r].rx_ring);
if (err)
goto err_flush_rx_ring_p;
} }
err_clear_config:
nfp_net_clear_config_and_disable(nn); err = netif_set_real_num_tx_queues(netdev, nn->num_tx_rings);
if (err)
goto err_free_rings;
err = netif_set_real_num_rx_queues(netdev, nn->num_rx_rings);
if (err)
goto err_free_rings;
/* Step 2: Configure the NFP
* - Enable rings from 0 to tx_rings/rx_rings - 1.
* - Write MAC address (in case it changed)
* - Set the MTU
* - Set the Freelist buffer size
* - Enable the FW
*/
err = nfp_net_set_config_and_enable(nn);
if (err)
goto err_free_rings;
/* Step 3: Enable for kernel
* - put some freelist descriptors on each RX ring
* - enable NAPI on each ring
* - enable all TX queues
* - set link state
*/
nfp_net_open_stack(nn);
return 0;
err_free_rings: err_free_rings:
nfp_net_free_rings(nn); r = nn->num_r_vecs;
err_free_prev_vecs:
while (r--) {
nfp_net_rx_ring_bufs_free(nn, nn->r_vecs[r].rx_ring);
err_flush_rx_ring_p:
nfp_net_rx_ring_free(nn->r_vecs[r].rx_ring);
err_free_tx_ring_p:
nfp_net_tx_ring_free(nn->r_vecs[r].tx_ring);
err_cleanup_vec_p:
nfp_net_cleanup_vector(nn, &nn->r_vecs[r]);
}
kfree(nn->tx_rings);
err_free_rx_rings:
kfree(nn->rx_rings);
err_free_lsc:
nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
err_free_exn: err_free_exn:
nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX); nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX);
return err; return err;
} }
/**
* nfp_net_close_stack() - Quiescent the stack (part of close)
* @nn: NFP Net device to reconfigure
*/
static void nfp_net_close_stack(struct nfp_net *nn)
{
unsigned int r;
disable_irq(nn->irq_entries[NFP_NET_CFG_LSC].vector);
netif_carrier_off(nn->netdev);
nn->link_up = false;
for (r = 0; r < nn->num_r_vecs; r++) {
disable_irq(nn->irq_entries[nn->r_vecs[r].irq_idx].vector);
napi_disable(&nn->r_vecs[r].napi);
}
netif_tx_disable(nn->netdev);
}
/**
* nfp_net_close_free_all() - Free all runtime resources
* @nn: NFP Net device to reconfigure
*/
static void nfp_net_close_free_all(struct nfp_net *nn)
{
unsigned int r;
for (r = 0; r < nn->num_r_vecs; r++) {
nfp_net_rx_ring_bufs_free(nn, nn->r_vecs[r].rx_ring);
nfp_net_rx_ring_free(nn->r_vecs[r].rx_ring);
nfp_net_tx_ring_free(nn->r_vecs[r].tx_ring);
nfp_net_cleanup_vector(nn, &nn->r_vecs[r]);
}
kfree(nn->rx_rings);
kfree(nn->tx_rings);
nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX);
}
/** /**
* nfp_net_netdev_close() - Called when the device is downed * nfp_net_netdev_close() - Called when the device is downed
* @netdev: netdev structure * @netdev: netdev structure
...@@ -1846,7 +2052,6 @@ static int nfp_net_netdev_open(struct net_device *netdev) ...@@ -1846,7 +2052,6 @@ static int nfp_net_netdev_open(struct net_device *netdev)
static int nfp_net_netdev_close(struct net_device *netdev) static int nfp_net_netdev_close(struct net_device *netdev)
{ {
struct nfp_net *nn = netdev_priv(netdev); struct nfp_net *nn = netdev_priv(netdev);
int r;
if (!(nn->ctrl & NFP_NET_CFG_CTRL_ENABLE)) { if (!(nn->ctrl & NFP_NET_CFG_CTRL_ENABLE)) {
nn_err(nn, "Dev is not up: 0x%08x\n", nn->ctrl); nn_err(nn, "Dev is not up: 0x%08x\n", nn->ctrl);
...@@ -1855,14 +2060,7 @@ static int nfp_net_netdev_close(struct net_device *netdev) ...@@ -1855,14 +2060,7 @@ static int nfp_net_netdev_close(struct net_device *netdev)
/* Step 1: Disable RX and TX rings from the Linux kernel perspective /* Step 1: Disable RX and TX rings from the Linux kernel perspective
*/ */
nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); nfp_net_close_stack(nn);
netif_carrier_off(netdev);
nn->link_up = false;
for (r = 0; r < nn->num_r_vecs; r++)
napi_disable(&nn->r_vecs[r].napi);
netif_tx_disable(netdev);
/* Step 2: Tell NFP /* Step 2: Tell NFP
*/ */
...@@ -1870,13 +2068,7 @@ static int nfp_net_netdev_close(struct net_device *netdev) ...@@ -1870,13 +2068,7 @@ static int nfp_net_netdev_close(struct net_device *netdev)
/* Step 3: Free resources /* Step 3: Free resources
*/ */
for (r = 0; r < nn->num_r_vecs; r++) { nfp_net_close_free_all(nn);
nfp_net_rx_flush(nn->r_vecs[r].rx_ring);
nfp_net_tx_flush(nn->r_vecs[r].tx_ring);
}
nfp_net_free_rings(nn);
nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX);
nn_dbg(nn, "%s down", netdev->name); nn_dbg(nn, "%s down", netdev->name);
return 0; return 0;
...@@ -1910,29 +2102,132 @@ static void nfp_net_set_rx_mode(struct net_device *netdev) ...@@ -1910,29 +2102,132 @@ static void nfp_net_set_rx_mode(struct net_device *netdev)
static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu) static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu)
{ {
unsigned int old_mtu, old_fl_bufsz, new_fl_bufsz;
struct nfp_net *nn = netdev_priv(netdev); struct nfp_net *nn = netdev_priv(netdev);
u32 tmp; struct nfp_net_rx_ring *tmp_rings;
int err;
nn_dbg(nn, "New MTU = %d\n", new_mtu);
if (new_mtu < 68 || new_mtu > nn->max_mtu) { if (new_mtu < 68 || new_mtu > nn->max_mtu) {
nn_err(nn, "New MTU (%d) is not valid\n", new_mtu); nn_err(nn, "New MTU (%d) is not valid\n", new_mtu);
return -EINVAL; return -EINVAL;
} }
old_mtu = netdev->mtu;
old_fl_bufsz = nn->fl_bufsz;
new_fl_bufsz = NFP_NET_MAX_PREPEND + ETH_HLEN + VLAN_HLEN * 2 + new_mtu;
if (!netif_running(netdev)) {
netdev->mtu = new_mtu;
nn->fl_bufsz = new_fl_bufsz;
return 0;
}
/* Prepare new rings */
tmp_rings = nfp_net_shadow_rx_rings_prepare(nn, new_fl_bufsz,
nn->rxd_cnt);
if (!tmp_rings)
return -ENOMEM;
/* Stop device, swap in new rings, try to start the firmware */
nfp_net_close_stack(nn);
nfp_net_clear_config_and_disable(nn);
tmp_rings = nfp_net_shadow_rx_rings_swap(nn, tmp_rings);
netdev->mtu = new_mtu; netdev->mtu = new_mtu;
nn->fl_bufsz = new_fl_bufsz;
/* Freelist buffer size rounded up to the nearest 1K */ err = nfp_net_set_config_and_enable(nn);
tmp = new_mtu + ETH_HLEN + VLAN_HLEN + NFP_NET_MAX_PREPEND; if (err) {
nn->fl_bufsz = roundup(tmp, 1024); const int err_new = err;
/* Try with old configuration and old rings */
tmp_rings = nfp_net_shadow_rx_rings_swap(nn, tmp_rings);
netdev->mtu = old_mtu;
nn->fl_bufsz = old_fl_bufsz;
/* restart if running */ err = __nfp_net_set_config_and_enable(nn);
if (netif_running(netdev)) { if (err)
nfp_net_netdev_close(netdev); nn_err(nn, "Can't restore MTU - FW communication failed (%d,%d)\n",
nfp_net_netdev_open(netdev); err_new, err);
} }
return 0; nfp_net_shadow_rx_rings_free(nn, tmp_rings);
nfp_net_open_stack(nn);
return err;
}
int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
{
struct nfp_net_tx_ring *tx_rings = NULL;
struct nfp_net_rx_ring *rx_rings = NULL;
u32 old_rxd_cnt, old_txd_cnt;
int err;
if (!netif_running(nn->netdev)) {
nn->rxd_cnt = rxd_cnt;
nn->txd_cnt = txd_cnt;
return 0;
}
old_rxd_cnt = nn->rxd_cnt;
old_txd_cnt = nn->txd_cnt;
/* Prepare new rings */
if (nn->rxd_cnt != rxd_cnt) {
rx_rings = nfp_net_shadow_rx_rings_prepare(nn, nn->fl_bufsz,
rxd_cnt);
if (!rx_rings)
return -ENOMEM;
}
if (nn->txd_cnt != txd_cnt) {
tx_rings = nfp_net_shadow_tx_rings_prepare(nn, txd_cnt);
if (!tx_rings) {
nfp_net_shadow_rx_rings_free(nn, rx_rings);
return -ENOMEM;
}
}
/* Stop device, swap in new rings, try to start the firmware */
nfp_net_close_stack(nn);
nfp_net_clear_config_and_disable(nn);
if (rx_rings)
rx_rings = nfp_net_shadow_rx_rings_swap(nn, rx_rings);
if (tx_rings)
tx_rings = nfp_net_shadow_tx_rings_swap(nn, tx_rings);
nn->rxd_cnt = rxd_cnt;
nn->txd_cnt = txd_cnt;
err = nfp_net_set_config_and_enable(nn);
if (err) {
const int err_new = err;
/* Try with old configuration and old rings */
if (rx_rings)
rx_rings = nfp_net_shadow_rx_rings_swap(nn, rx_rings);
if (tx_rings)
tx_rings = nfp_net_shadow_tx_rings_swap(nn, tx_rings);
nn->rxd_cnt = old_rxd_cnt;
nn->txd_cnt = old_txd_cnt;
err = __nfp_net_set_config_and_enable(nn);
if (err)
nn_err(nn, "Can't restore ring config - FW communication failed (%d,%d)\n",
err_new, err);
}
nfp_net_shadow_rx_rings_free(nn, rx_rings);
nfp_net_shadow_tx_rings_free(nn, tx_rings);
nfp_net_open_stack(nn);
return err;
} }
static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev, static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev,
......
...@@ -40,8 +40,9 @@ static struct dentry *nfp_dir; ...@@ -40,8 +40,9 @@ static struct dentry *nfp_dir;
static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data) static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data)
{ {
struct nfp_net_rx_ring *rx_ring = file->private;
int fl_rd_p, fl_wr_p, rx_rd_p, rx_wr_p, rxd_cnt; int fl_rd_p, fl_wr_p, rx_rd_p, rx_wr_p, rxd_cnt;
struct nfp_net_r_vector *r_vec = file->private;
struct nfp_net_rx_ring *rx_ring;
struct nfp_net_rx_desc *rxd; struct nfp_net_rx_desc *rxd;
struct sk_buff *skb; struct sk_buff *skb;
struct nfp_net *nn; struct nfp_net *nn;
...@@ -49,9 +50,10 @@ static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data) ...@@ -49,9 +50,10 @@ static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data)
rtnl_lock(); rtnl_lock();
if (!rx_ring->r_vec || !rx_ring->r_vec->nfp_net) if (!r_vec->nfp_net || !r_vec->rx_ring)
goto out; goto out;
nn = rx_ring->r_vec->nfp_net; nn = r_vec->nfp_net;
rx_ring = r_vec->rx_ring;
if (!netif_running(nn->netdev)) if (!netif_running(nn->netdev))
goto out; goto out;
...@@ -115,7 +117,8 @@ static const struct file_operations nfp_rx_q_fops = { ...@@ -115,7 +117,8 @@ static const struct file_operations nfp_rx_q_fops = {
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_tx_ring *tx_ring = file->private; struct nfp_net_r_vector *r_vec = file->private;
struct nfp_net_tx_ring *tx_ring;
struct nfp_net_tx_desc *txd; struct nfp_net_tx_desc *txd;
int d_rd_p, d_wr_p, txd_cnt; int d_rd_p, d_wr_p, txd_cnt;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -124,9 +127,10 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data) ...@@ -124,9 +127,10 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
rtnl_lock(); rtnl_lock();
if (!tx_ring->r_vec || !tx_ring->r_vec->nfp_net) if (!r_vec->nfp_net || !r_vec->tx_ring)
goto out; goto out;
nn = tx_ring->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;
...@@ -207,13 +211,13 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn) ...@@ -207,13 +211,13 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
for (i = 0; i < nn->num_rx_rings; i++) { for (i = 0; i < nn->num_rx_rings; 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->rx_rings[i], &nfp_rx_q_fops); &nn->r_vecs[i], &nfp_rx_q_fops);
} }
for (i = 0; i < nn->num_tx_rings; i++) { for (i = 0; i < nn->num_tx_rings; i++) {
sprintf(int_name, "%d", i); sprintf(int_name, "%d", i);
debugfs_create_file(int_name, S_IRUSR, tx, debugfs_create_file(int_name, S_IRUSR, tx,
&nn->tx_rings[i], &nfp_tx_q_fops); &nn->r_vecs[i], &nfp_tx_q_fops);
} }
} }
......
...@@ -153,37 +153,25 @@ static int nfp_net_set_ringparam(struct net_device *netdev, ...@@ -153,37 +153,25 @@ static int nfp_net_set_ringparam(struct net_device *netdev,
struct nfp_net *nn = netdev_priv(netdev); struct nfp_net *nn = netdev_priv(netdev);
u32 rxd_cnt, txd_cnt; u32 rxd_cnt, txd_cnt;
if (netif_running(netdev)) {
/* Some NIC drivers allow reconfiguration on the fly,
* some down the interface, change and then up it
* again. For now we don't allow changes when the
* device is up.
*/
nn_warn(nn, "Can't change rings while device is up\n");
return -EBUSY;
}
/* We don't have separate queues/rings for small/large frames. */ /* We don't have separate queues/rings for small/large frames. */
if (ring->rx_mini_pending || ring->rx_jumbo_pending) if (ring->rx_mini_pending || ring->rx_jumbo_pending)
return -EINVAL; return -EINVAL;
/* Round up to supported values */ /* Round up to supported values */
rxd_cnt = roundup_pow_of_two(ring->rx_pending); rxd_cnt = roundup_pow_of_two(ring->rx_pending);
rxd_cnt = max_t(u32, rxd_cnt, NFP_NET_MIN_RX_DESCS);
rxd_cnt = min_t(u32, rxd_cnt, NFP_NET_MAX_RX_DESCS);
txd_cnt = roundup_pow_of_two(ring->tx_pending); txd_cnt = roundup_pow_of_two(ring->tx_pending);
txd_cnt = max_t(u32, txd_cnt, NFP_NET_MIN_TX_DESCS);
txd_cnt = min_t(u32, txd_cnt, NFP_NET_MAX_TX_DESCS);
if (nn->rxd_cnt != rxd_cnt || nn->txd_cnt != txd_cnt) if (rxd_cnt < NFP_NET_MIN_RX_DESCS || rxd_cnt > NFP_NET_MAX_RX_DESCS ||
nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n", txd_cnt < NFP_NET_MIN_TX_DESCS || txd_cnt > NFP_NET_MAX_TX_DESCS)
nn->rxd_cnt, rxd_cnt, nn->txd_cnt, txd_cnt); return -EINVAL;
nn->rxd_cnt = rxd_cnt; if (nn->rxd_cnt == rxd_cnt && nn->txd_cnt == txd_cnt)
nn->txd_cnt = txd_cnt; return 0;
return 0; nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n",
nn->rxd_cnt, rxd_cnt, nn->txd_cnt, txd_cnt);
return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt);
} }
static void nfp_net_get_strings(struct net_device *netdev, static void nfp_net_get_strings(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