|
@@ -494,7 +494,7 @@ static void nfp_net_irqs_assign(struct net_device *netdev)
|
|
nn->lsc_handler = nfp_net_irq_lsc;
|
|
nn->lsc_handler = nfp_net_irq_lsc;
|
|
nn->exn_handler = nfp_net_irq_exn;
|
|
nn->exn_handler = nfp_net_irq_exn;
|
|
|
|
|
|
- for (r = 0; r < nn->num_r_vecs; r++) {
|
|
|
|
|
|
+ for (r = 0; r < nn->max_r_vecs; r++) {
|
|
r_vec = &nn->r_vecs[r];
|
|
r_vec = &nn->r_vecs[r];
|
|
r_vec->nfp_net = nn;
|
|
r_vec->nfp_net = nn;
|
|
r_vec->handler = nfp_net_irq_rxtx;
|
|
r_vec->handler = nfp_net_irq_rxtx;
|
|
@@ -1578,12 +1578,12 @@ nfp_net_tx_ring_set_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;
|
|
|
|
|
|
- rings = kcalloc(nn->num_tx_rings, sizeof(*rings), GFP_KERNEL);
|
|
|
|
|
|
+ rings = kcalloc(s->n_rings, sizeof(*rings), GFP_KERNEL);
|
|
if (!rings)
|
|
if (!rings)
|
|
return NULL;
|
|
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);
|
|
|
|
|
|
+ for (r = 0; r < s->n_rings; r++) {
|
|
|
|
+ nfp_net_tx_ring_init(&rings[r], &nn->r_vecs[r], r);
|
|
|
|
|
|
if (nfp_net_tx_ring_alloc(&rings[r], s->dcnt))
|
|
if (nfp_net_tx_ring_alloc(&rings[r], s->dcnt))
|
|
goto err_free_prev;
|
|
goto err_free_prev;
|
|
@@ -1605,9 +1605,11 @@ nfp_net_tx_ring_set_swap(struct nfp_net *nn, struct nfp_net_ring_set *s)
|
|
|
|
|
|
s->dcnt = nn->txd_cnt;
|
|
s->dcnt = nn->txd_cnt;
|
|
s->rings = nn->tx_rings;
|
|
s->rings = nn->tx_rings;
|
|
|
|
+ s->n_rings = nn->num_tx_rings;
|
|
|
|
|
|
nn->txd_cnt = new.dcnt;
|
|
nn->txd_cnt = new.dcnt;
|
|
nn->tx_rings = new.rings;
|
|
nn->tx_rings = new.rings;
|
|
|
|
+ nn->num_tx_rings = new.n_rings;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
@@ -1616,7 +1618,7 @@ nfp_net_tx_ring_set_free(struct nfp_net *nn, struct nfp_net_ring_set *s)
|
|
struct nfp_net_tx_ring *rings = s->rings;
|
|
struct nfp_net_tx_ring *rings = s->rings;
|
|
unsigned int r;
|
|
unsigned int r;
|
|
|
|
|
|
- for (r = 0; r < nn->num_tx_rings; r++)
|
|
|
|
|
|
+ for (r = 0; r < s->n_rings; r++)
|
|
nfp_net_tx_ring_free(&rings[r]);
|
|
nfp_net_tx_ring_free(&rings[r]);
|
|
|
|
|
|
kfree(rings);
|
|
kfree(rings);
|
|
@@ -1694,12 +1696,12 @@ nfp_net_rx_ring_set_prepare(struct nfp_net *nn, struct nfp_net_ring_set *s)
|
|
struct nfp_net_rx_ring *rings;
|
|
struct nfp_net_rx_ring *rings;
|
|
unsigned int r;
|
|
unsigned int r;
|
|
|
|
|
|
- rings = kcalloc(nn->num_rx_rings, sizeof(*rings), GFP_KERNEL);
|
|
|
|
|
|
+ rings = kcalloc(s->n_rings, sizeof(*rings), GFP_KERNEL);
|
|
if (!rings)
|
|
if (!rings)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- for (r = 0; r < nn->num_rx_rings; r++) {
|
|
|
|
- nfp_net_rx_ring_init(&rings[r], nn->rx_rings[r].r_vec, r);
|
|
|
|
|
|
+ for (r = 0; r < s->n_rings; r++) {
|
|
|
|
+ nfp_net_rx_ring_init(&rings[r], &nn->r_vecs[r], r);
|
|
|
|
|
|
if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz, s->dcnt))
|
|
if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz, s->dcnt))
|
|
goto err_free_prev;
|
|
goto err_free_prev;
|
|
@@ -1728,11 +1730,13 @@ nfp_net_rx_ring_set_swap(struct nfp_net *nn, struct nfp_net_ring_set *s)
|
|
s->mtu = nn->netdev->mtu;
|
|
s->mtu = nn->netdev->mtu;
|
|
s->dcnt = nn->rxd_cnt;
|
|
s->dcnt = nn->rxd_cnt;
|
|
s->rings = nn->rx_rings;
|
|
s->rings = nn->rx_rings;
|
|
|
|
+ s->n_rings = nn->num_rx_rings;
|
|
|
|
|
|
nn->netdev->mtu = new.mtu;
|
|
nn->netdev->mtu = new.mtu;
|
|
nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, new.mtu);
|
|
nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, new.mtu);
|
|
nn->rxd_cnt = new.dcnt;
|
|
nn->rxd_cnt = new.dcnt;
|
|
nn->rx_rings = new.rings;
|
|
nn->rx_rings = new.rings;
|
|
|
|
+ nn->num_rx_rings = new.n_rings;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
@@ -1741,7 +1745,7 @@ nfp_net_rx_ring_set_free(struct nfp_net *nn, struct nfp_net_ring_set *s)
|
|
struct nfp_net_rx_ring *rings = s->rings;
|
|
struct nfp_net_rx_ring *rings = s->rings;
|
|
unsigned int r;
|
|
unsigned int r;
|
|
|
|
|
|
- for (r = 0; r < nn->num_rx_rings; r++) {
|
|
|
|
|
|
+ for (r = 0; r < s->n_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]);
|
|
}
|
|
}
|
|
@@ -1764,19 +1768,20 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
|
|
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
|
|
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
|
|
int err;
|
|
int err;
|
|
|
|
|
|
|
|
+ /* Setup NAPI */
|
|
|
|
+ netif_napi_add(nn->netdev, &r_vec->napi,
|
|
|
|
+ nfp_net_poll, NAPI_POLL_WEIGHT);
|
|
|
|
+
|
|
snprintf(r_vec->name, sizeof(r_vec->name),
|
|
snprintf(r_vec->name, sizeof(r_vec->name),
|
|
"%s-rxtx-%d", nn->netdev->name, idx);
|
|
"%s-rxtx-%d", nn->netdev->name, idx);
|
|
err = request_irq(entry->vector, r_vec->handler, 0, r_vec->name, r_vec);
|
|
err = request_irq(entry->vector, r_vec->handler, 0, r_vec->name, r_vec);
|
|
if (err) {
|
|
if (err) {
|
|
|
|
+ netif_napi_del(&r_vec->napi);
|
|
nn_err(nn, "Error requesting IRQ %d\n", entry->vector);
|
|
nn_err(nn, "Error requesting IRQ %d\n", entry->vector);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
disable_irq(entry->vector);
|
|
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);
|
|
irq_set_affinity_hint(entry->vector, &r_vec->affinity_mask);
|
|
|
|
|
|
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, entry->vector, entry->entry);
|
|
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, entry->vector, entry->entry);
|
|
@@ -2036,10 +2041,12 @@ static int nfp_net_netdev_open(struct net_device *netdev)
|
|
{
|
|
{
|
|
struct nfp_net *nn = netdev_priv(netdev);
|
|
struct nfp_net *nn = netdev_priv(netdev);
|
|
struct nfp_net_ring_set rx = {
|
|
struct nfp_net_ring_set rx = {
|
|
|
|
+ .n_rings = nn->num_rx_rings,
|
|
.mtu = nn->netdev->mtu,
|
|
.mtu = nn->netdev->mtu,
|
|
.dcnt = nn->rxd_cnt,
|
|
.dcnt = nn->rxd_cnt,
|
|
};
|
|
};
|
|
struct nfp_net_ring_set tx = {
|
|
struct nfp_net_ring_set tx = {
|
|
|
|
+ .n_rings = nn->num_tx_rings,
|
|
.dcnt = nn->txd_cnt,
|
|
.dcnt = nn->txd_cnt,
|
|
};
|
|
};
|
|
int err, r;
|
|
int err, r;
|
|
@@ -2239,49 +2246,89 @@ static void nfp_net_rss_init_itbl(struct nfp_net *nn)
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-nfp_net_ring_swap_enable(struct nfp_net *nn,
|
|
|
|
|
|
+nfp_net_ring_swap_enable(struct nfp_net *nn, unsigned int *num_vecs,
|
|
struct nfp_net_ring_set *rx,
|
|
struct nfp_net_ring_set *rx,
|
|
struct nfp_net_ring_set *tx)
|
|
struct nfp_net_ring_set *tx)
|
|
{
|
|
{
|
|
unsigned int r;
|
|
unsigned int r;
|
|
|
|
+ int err;
|
|
|
|
|
|
if (rx)
|
|
if (rx)
|
|
nfp_net_rx_ring_set_swap(nn, rx);
|
|
nfp_net_rx_ring_set_swap(nn, rx);
|
|
if (tx)
|
|
if (tx)
|
|
nfp_net_tx_ring_set_swap(nn, tx);
|
|
nfp_net_tx_ring_set_swap(nn, tx);
|
|
|
|
|
|
|
|
+ swap(*num_vecs, nn->num_r_vecs);
|
|
|
|
+
|
|
for (r = 0; r < nn->max_r_vecs; r++)
|
|
for (r = 0; r < nn->max_r_vecs; r++)
|
|
nfp_net_vector_assign_rings(nn, &nn->r_vecs[r], r);
|
|
nfp_net_vector_assign_rings(nn, &nn->r_vecs[r], r);
|
|
|
|
|
|
|
|
+ if (nn->netdev->real_num_rx_queues != nn->num_rx_rings) {
|
|
|
|
+ if (!netif_is_rxfh_configured(nn->netdev))
|
|
|
|
+ nfp_net_rss_init_itbl(nn);
|
|
|
|
+
|
|
|
|
+ err = netif_set_real_num_rx_queues(nn->netdev,
|
|
|
|
+ nn->num_rx_rings);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (nn->netdev->real_num_tx_queues != nn->num_tx_rings) {
|
|
|
|
+ err = netif_set_real_num_tx_queues(nn->netdev,
|
|
|
|
+ nn->num_tx_rings);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
return __nfp_net_set_config_and_enable(nn);
|
|
return __nfp_net_set_config_and_enable(nn);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
nfp_net_ring_reconfig_down(struct nfp_net *nn,
|
|
nfp_net_ring_reconfig_down(struct nfp_net *nn,
|
|
struct nfp_net_ring_set *rx,
|
|
struct nfp_net_ring_set *rx,
|
|
- struct nfp_net_ring_set *tx)
|
|
|
|
|
|
+ struct nfp_net_ring_set *tx,
|
|
|
|
+ unsigned int num_vecs)
|
|
{
|
|
{
|
|
nn->netdev->mtu = rx ? rx->mtu : nn->netdev->mtu;
|
|
nn->netdev->mtu = rx ? rx->mtu : nn->netdev->mtu;
|
|
nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, 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->rxd_cnt = rx ? rx->dcnt : nn->rxd_cnt;
|
|
nn->txd_cnt = tx ? tx->dcnt : nn->txd_cnt;
|
|
nn->txd_cnt = tx ? tx->dcnt : nn->txd_cnt;
|
|
|
|
+ nn->num_rx_rings = rx ? rx->n_rings : nn->num_rx_rings;
|
|
|
|
+ nn->num_tx_rings = tx ? tx->n_rings : nn->num_tx_rings;
|
|
|
|
+ nn->num_r_vecs = num_vecs;
|
|
|
|
+
|
|
|
|
+ if (!netif_is_rxfh_configured(nn->netdev))
|
|
|
|
+ nfp_net_rss_init_itbl(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 nfp_net_ring_set *rx,
|
|
struct nfp_net_ring_set *tx)
|
|
struct nfp_net_ring_set *tx)
|
|
{
|
|
{
|
|
|
|
+ unsigned int num_vecs, r;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
|
|
+ num_vecs = max(rx ? rx->n_rings : nn->num_rx_rings,
|
|
|
|
+ tx ? tx->n_rings : nn->num_tx_rings);
|
|
|
|
+
|
|
if (!netif_running(nn->netdev)) {
|
|
if (!netif_running(nn->netdev)) {
|
|
- nfp_net_ring_reconfig_down(nn, rx, tx);
|
|
|
|
|
|
+ nfp_net_ring_reconfig_down(nn, rx, tx, num_vecs);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* Prepare new rings */
|
|
/* Prepare new rings */
|
|
|
|
+ for (r = nn->num_r_vecs; r < num_vecs; r++) {
|
|
|
|
+ err = nfp_net_prepare_vector(nn, &nn->r_vecs[r], r);
|
|
|
|
+ if (err) {
|
|
|
|
+ num_vecs = r;
|
|
|
|
+ goto err_cleanup_vecs;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
if (rx) {
|
|
if (rx) {
|
|
- if (!nfp_net_rx_ring_set_prepare(nn, rx))
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ if (!nfp_net_rx_ring_set_prepare(nn, rx)) {
|
|
|
|
+ err = -ENOMEM;
|
|
|
|
+ goto err_cleanup_vecs;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
if (tx) {
|
|
if (tx) {
|
|
if (!nfp_net_tx_ring_set_prepare(nn, tx)) {
|
|
if (!nfp_net_tx_ring_set_prepare(nn, tx)) {
|
|
@@ -2294,18 +2341,20 @@ nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx,
|
|
nfp_net_close_stack(nn);
|
|
nfp_net_close_stack(nn);
|
|
nfp_net_clear_config_and_disable(nn);
|
|
nfp_net_clear_config_and_disable(nn);
|
|
|
|
|
|
- err = nfp_net_ring_swap_enable(nn, rx, tx);
|
|
|
|
|
|
+ err = nfp_net_ring_swap_enable(nn, &num_vecs, rx, tx);
|
|
if (err) {
|
|
if (err) {
|
|
int err2;
|
|
int err2;
|
|
|
|
|
|
nfp_net_clear_config_and_disable(nn);
|
|
nfp_net_clear_config_and_disable(nn);
|
|
|
|
|
|
/* Try with old configuration and old rings */
|
|
/* Try with old configuration and old rings */
|
|
- err2 = nfp_net_ring_swap_enable(nn, rx, tx);
|
|
|
|
|
|
+ err2 = nfp_net_ring_swap_enable(nn, &num_vecs, rx, tx);
|
|
if (err2)
|
|
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, err2);
|
|
err, err2);
|
|
}
|
|
}
|
|
|
|
+ for (r = num_vecs - 1; r >= nn->num_r_vecs; r--)
|
|
|
|
+ nfp_net_cleanup_vector(nn, &nn->r_vecs[r]);
|
|
|
|
|
|
if (rx)
|
|
if (rx)
|
|
nfp_net_rx_ring_set_free(nn, rx);
|
|
nfp_net_rx_ring_set_free(nn, rx);
|
|
@@ -2319,6 +2368,9 @@ nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx,
|
|
err_free_rx:
|
|
err_free_rx:
|
|
if (rx)
|
|
if (rx)
|
|
nfp_net_rx_ring_set_free(nn, rx);
|
|
nfp_net_rx_ring_set_free(nn, rx);
|
|
|
|
+err_cleanup_vecs:
|
|
|
|
+ for (r = num_vecs - 1; r >= nn->num_r_vecs; r--)
|
|
|
|
+ nfp_net_cleanup_vector(nn, &nn->r_vecs[r]);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2326,6 +2378,7 @@ static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu)
|
|
{
|
|
{
|
|
struct nfp_net *nn = netdev_priv(netdev);
|
|
struct nfp_net *nn = netdev_priv(netdev);
|
|
struct nfp_net_ring_set rx = {
|
|
struct nfp_net_ring_set rx = {
|
|
|
|
+ .n_rings = nn->num_rx_rings,
|
|
.mtu = new_mtu,
|
|
.mtu = new_mtu,
|
|
.dcnt = nn->rxd_cnt,
|
|
.dcnt = nn->rxd_cnt,
|
|
};
|
|
};
|