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

nfp: centralize runtime reconfiguration logic

All functions which need to reallocate ring resources at runtime
look very similar.  Centralize that logic into a separate function.
Encapsulate configuration parameters in a structure.
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 81cc2e43
...@@ -583,6 +583,12 @@ struct nfp_net { ...@@ -583,6 +583,12 @@ struct nfp_net {
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
}; };
struct nfp_net_ring_set {
unsigned int mtu;
unsigned int dcnt;
void *rings;
};
/* Functions to read/write from/to a BAR /* Functions to read/write from/to a BAR
* Performs any endian conversion necessary. * Performs any endian conversion necessary.
*/ */
...@@ -771,7 +777,9 @@ void nfp_net_rss_write_key(struct nfp_net *nn); ...@@ -771,7 +777,9 @@ 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); int
nfp_net_ring_reconfig(struct nfp_net *nn, 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);
......
...@@ -1573,7 +1573,7 @@ static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring, u32 cnt) ...@@ -1573,7 +1573,7 @@ static int nfp_net_tx_ring_alloc(struct nfp_net_tx_ring *tx_ring, u32 cnt)
} }
static struct nfp_net_tx_ring * static struct nfp_net_tx_ring *
nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt) nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, struct nfp_net_ring_set *s)
{ {
struct nfp_net_tx_ring *rings; struct nfp_net_tx_ring *rings;
unsigned int r; unsigned int r;
...@@ -1585,11 +1585,11 @@ nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt) ...@@ -1585,11 +1585,11 @@ nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt)
for (r = 0; r < nn->num_tx_rings; r++) { for (r = 0; r < nn->num_tx_rings; r++) {
nfp_net_tx_ring_init(&rings[r], nn->tx_rings[r].r_vec, 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)) if (nfp_net_tx_ring_alloc(&rings[r], s->dcnt))
goto err_free_prev; goto err_free_prev;
} }
return rings; return s->rings = rings;
err_free_prev: err_free_prev:
while (r--) while (r--)
...@@ -1598,27 +1598,29 @@ nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt) ...@@ -1598,27 +1598,29 @@ nfp_net_shadow_tx_rings_prepare(struct nfp_net *nn, u32 buf_cnt)
return NULL; return NULL;
} }
static struct nfp_net_tx_ring * static void
nfp_net_shadow_tx_rings_swap(struct nfp_net *nn, struct nfp_net_tx_ring *rings) nfp_net_shadow_tx_rings_swap(struct nfp_net *nn, struct nfp_net_ring_set *s)
{ {
struct nfp_net_tx_ring *old = nn->tx_rings; struct nfp_net_tx_ring *rings = s->rings;
struct nfp_net_ring_set new = *s;
unsigned int r; unsigned int r;
s->dcnt = nn->txd_cnt;
s->rings = nn->tx_rings;
for (r = 0; r < nn->num_tx_rings; r++) for (r = 0; r < nn->num_tx_rings; r++)
old[r].r_vec->tx_ring = &rings[r]; nn->tx_rings[r].r_vec->tx_ring = &rings[r];
nn->tx_rings = rings; nn->txd_cnt = new.dcnt;
return old; nn->tx_rings = new.rings;
} }
static void static void
nfp_net_shadow_tx_rings_free(struct nfp_net *nn, struct nfp_net_tx_ring *rings) nfp_net_shadow_tx_rings_free(struct nfp_net *nn, struct nfp_net_ring_set *s)
{ {
struct nfp_net_tx_ring *rings = s->rings;
unsigned int r; unsigned int r;
if (!rings)
return;
for (r = 0; r < nn->num_tx_rings; r++) for (r = 0; r < nn->num_tx_rings; r++)
nfp_net_tx_ring_free(&rings[r]); nfp_net_tx_ring_free(&rings[r]);
...@@ -1691,9 +1693,9 @@ nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring, unsigned int fl_bufsz, ...@@ -1691,9 +1693,9 @@ nfp_net_rx_ring_alloc(struct nfp_net_rx_ring *rx_ring, unsigned int fl_bufsz,
} }
static struct nfp_net_rx_ring * static struct nfp_net_rx_ring *
nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz, nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, struct nfp_net_ring_set *s)
u32 buf_cnt)
{ {
unsigned int fl_bufsz = nfp_net_calc_fl_bufsz(nn, s->mtu);
struct nfp_net_rx_ring *rings; struct nfp_net_rx_ring *rings;
unsigned int r; unsigned int r;
...@@ -1704,14 +1706,14 @@ nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz, ...@@ -1704,14 +1706,14 @@ nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz,
for (r = 0; r < nn->num_rx_rings; r++) { for (r = 0; r < nn->num_rx_rings; r++) {
nfp_net_rx_ring_init(&rings[r], nn->rx_rings[r].r_vec, r); nfp_net_rx_ring_init(&rings[r], nn->rx_rings[r].r_vec, r);
if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz, buf_cnt)) if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz, s->dcnt))
goto err_free_prev; goto err_free_prev;
if (nfp_net_rx_ring_bufs_alloc(nn, &rings[r])) if (nfp_net_rx_ring_bufs_alloc(nn, &rings[r]))
goto err_free_ring; goto err_free_ring;
} }
return rings; return s->rings = rings;
err_free_prev: err_free_prev:
while (r--) { while (r--) {
...@@ -1723,27 +1725,32 @@ nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz, ...@@ -1723,27 +1725,32 @@ nfp_net_shadow_rx_rings_prepare(struct nfp_net *nn, unsigned int fl_bufsz,
return NULL; return NULL;
} }
static struct nfp_net_rx_ring * static void
nfp_net_shadow_rx_rings_swap(struct nfp_net *nn, struct nfp_net_rx_ring *rings) nfp_net_shadow_rx_rings_swap(struct nfp_net *nn, struct nfp_net_ring_set *s)
{ {
struct nfp_net_rx_ring *old = nn->rx_rings; struct nfp_net_rx_ring *rings = s->rings;
struct nfp_net_ring_set new = *s;
unsigned int r; unsigned int r;
s->mtu = nn->netdev->mtu;
s->dcnt = nn->rxd_cnt;
s->rings = nn->rx_rings;
for (r = 0; r < nn->num_rx_rings; r++) for (r = 0; r < nn->num_rx_rings; r++)
old[r].r_vec->rx_ring = &rings[r]; nn->rx_rings[r].r_vec->rx_ring = &rings[r];
nn->rx_rings = rings; nn->netdev->mtu = new.mtu;
return old; nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, new.mtu);
nn->rxd_cnt = new.dcnt;
nn->rx_rings = new.rings;
} }
static void static void
nfp_net_shadow_rx_rings_free(struct nfp_net *nn, struct nfp_net_rx_ring *rings) nfp_net_shadow_rx_rings_free(struct nfp_net *nn, struct nfp_net_ring_set *s)
{ {
struct nfp_net_rx_ring *rings = s->rings;
unsigned int r; unsigned int r;
if (!rings)
return;
for (r = 0; r < nn->num_rx_rings; r++) { for (r = 0; r < nn->num_rx_rings; r++) {
nfp_net_rx_ring_bufs_free(nn, &rings[r]); nfp_net_rx_ring_bufs_free(nn, &rings[r]);
nfp_net_rx_ring_free(&rings[r]); nfp_net_rx_ring_free(&rings[r]);
...@@ -2255,89 +2262,50 @@ static void nfp_net_set_rx_mode(struct net_device *netdev) ...@@ -2255,89 +2262,50 @@ static void nfp_net_set_rx_mode(struct net_device *netdev)
nn->ctrl = new_ctrl; nn->ctrl = new_ctrl;
} }
static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu) static int
nfp_net_ring_swap_enable(struct nfp_net *nn,
struct nfp_net_ring_set *rx,
struct nfp_net_ring_set *tx)
{ {
unsigned int old_mtu, old_fl_bufsz, new_fl_bufsz; if (rx)
struct nfp_net *nn = netdev_priv(netdev); nfp_net_shadow_rx_rings_swap(nn, rx);
struct nfp_net_rx_ring *tmp_rings; if (tx)
int err; nfp_net_shadow_tx_rings_swap(nn, tx);
old_mtu = netdev->mtu;
old_fl_bufsz = nn->fl_bufsz;
new_fl_bufsz = nfp_net_calc_fl_bufsz(nn, 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;
nn->fl_bufsz = new_fl_bufsz;
err = nfp_net_set_config_and_enable(nn);
if (err) {
const int err_new = err;
/* Try with old configuration and old rings */ return __nfp_net_set_config_and_enable(nn);
tmp_rings = nfp_net_shadow_rx_rings_swap(nn, tmp_rings); }
netdev->mtu = old_mtu;
nn->fl_bufsz = old_fl_bufsz;
err = __nfp_net_set_config_and_enable(nn);
if (err)
nn_err(nn, "Can't restore MTU - FW communication failed (%d,%d)\n",
err_new, err);
}
nfp_net_shadow_rx_rings_free(nn, tmp_rings);
nfp_net_open_stack(nn);
return err; static void
nfp_net_ring_reconfig_down(struct nfp_net *nn,
struct nfp_net_ring_set *rx,
struct nfp_net_ring_set *tx)
{
nn->netdev->mtu = rx ? rx->mtu : nn->netdev->mtu;
nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, nn->netdev->mtu);
nn->rxd_cnt = rx ? rx->dcnt : nn->rxd_cnt;
nn->txd_cnt = tx ? tx->dcnt : nn->txd_cnt;
} }
int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt) int
nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx,
struct nfp_net_ring_set *tx)
{ {
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; int err;
if (!netif_running(nn->netdev)) { if (!netif_running(nn->netdev)) {
nn->rxd_cnt = rxd_cnt; nfp_net_ring_reconfig_down(nn, rx, tx);
nn->txd_cnt = txd_cnt;
return 0; return 0;
} }
old_rxd_cnt = nn->rxd_cnt;
old_txd_cnt = nn->txd_cnt;
/* Prepare new rings */ /* Prepare new rings */
if (nn->rxd_cnt != rxd_cnt) { if (rx) {
rx_rings = nfp_net_shadow_rx_rings_prepare(nn, nn->fl_bufsz, if (!nfp_net_shadow_rx_rings_prepare(nn, rx))
rxd_cnt);
if (!rx_rings)
return -ENOMEM; return -ENOMEM;
} }
if (nn->txd_cnt != txd_cnt) { if (tx) {
tx_rings = nfp_net_shadow_tx_rings_prepare(nn, txd_cnt); if (!nfp_net_shadow_tx_rings_prepare(nn, tx)) {
if (!tx_rings) { err = -ENOMEM;
nfp_net_shadow_rx_rings_free(nn, rx_rings); goto err_free_rx;
return -ENOMEM;
} }
} }
...@@ -2345,39 +2313,43 @@ int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt) ...@@ -2345,39 +2313,43 @@ int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
nfp_net_close_stack(nn); nfp_net_close_stack(nn);
nfp_net_clear_config_and_disable(nn); nfp_net_clear_config_and_disable(nn);
if (rx_rings) err = nfp_net_ring_swap_enable(nn, rx, tx);
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) { if (err) {
const int err_new = err; int err2;
/* 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; nfp_net_clear_config_and_disable(nn);
nn->txd_cnt = old_txd_cnt;
err = __nfp_net_set_config_and_enable(nn); /* Try with old configuration and old rings */
if (err) err2 = nfp_net_ring_swap_enable(nn, rx, tx);
if (err2)
nn_err(nn, "Can't restore ring config - FW communication failed (%d,%d)\n", nn_err(nn, "Can't restore ring config - FW communication failed (%d,%d)\n",
err_new, err); err, err2);
} }
nfp_net_shadow_rx_rings_free(nn, rx_rings); if (rx)
nfp_net_shadow_tx_rings_free(nn, tx_rings); nfp_net_shadow_rx_rings_free(nn, rx);
if (tx)
nfp_net_shadow_tx_rings_free(nn, tx);
nfp_net_open_stack(nn); nfp_net_open_stack(nn);
return err; return err;
err_free_rx:
if (rx)
nfp_net_shadow_rx_rings_free(nn, rx);
return err;
}
static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu)
{
struct nfp_net *nn = netdev_priv(netdev);
struct nfp_net_ring_set rx = {
.mtu = new_mtu,
.dcnt = nn->rxd_cnt,
};
return nfp_net_ring_reconfig(nn, &rx, NULL);
} }
static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev, static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev,
......
...@@ -158,6 +158,25 @@ static void nfp_net_get_ringparam(struct net_device *netdev, ...@@ -158,6 +158,25 @@ static void nfp_net_get_ringparam(struct net_device *netdev,
ring->tx_pending = nn->txd_cnt; ring->tx_pending = nn->txd_cnt;
} }
static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
{
struct nfp_net_ring_set *reconfig_rx = NULL, *reconfig_tx = NULL;
struct nfp_net_ring_set rx = {
.mtu = nn->netdev->mtu,
.dcnt = rxd_cnt,
};
struct nfp_net_ring_set tx = {
.dcnt = txd_cnt,
};
if (nn->rxd_cnt != rxd_cnt)
reconfig_rx = &rx;
if (nn->txd_cnt != txd_cnt)
reconfig_tx = &tx;
return nfp_net_ring_reconfig(nn, reconfig_rx, reconfig_tx);
}
static int nfp_net_set_ringparam(struct net_device *netdev, static int nfp_net_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring) struct ethtool_ringparam *ring)
{ {
......
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