Skip to content

Commit 164d1e9

Browse files
Jakub Kicinskidavem330
authored andcommitted
nfp: add support for ethtool .set_channels
Allow changing the number of rings via ethtool .set_channels API. Runtime reconfig needs to be extended to handle number of rings. We need to be able to activate interrupt vectors before rings are assigned to them. Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1e9e10d commit 164d1e9

File tree

4 files changed

+123
-22
lines changed

4 files changed

+123
-22
lines changed

drivers/net/ethernet/netronome/nfp/nfp_net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ struct nfp_net {
584584
};
585585

586586
struct nfp_net_ring_set {
587+
unsigned int n_rings;
587588
unsigned int mtu;
588589
unsigned int dcnt;
589590
void *rings;

drivers/net/ethernet/netronome/nfp/nfp_net_common.c

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ static void nfp_net_irqs_assign(struct net_device *netdev)
494494
nn->lsc_handler = nfp_net_irq_lsc;
495495
nn->exn_handler = nfp_net_irq_exn;
496496

497-
for (r = 0; r < nn->num_r_vecs; r++) {
497+
for (r = 0; r < nn->max_r_vecs; r++) {
498498
r_vec = &nn->r_vecs[r];
499499
r_vec->nfp_net = nn;
500500
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)
15781578
struct nfp_net_tx_ring *rings;
15791579
unsigned int r;
15801580

1581-
rings = kcalloc(nn->num_tx_rings, sizeof(*rings), GFP_KERNEL);
1581+
rings = kcalloc(s->n_rings, sizeof(*rings), GFP_KERNEL);
15821582
if (!rings)
15831583
return NULL;
15841584

1585-
for (r = 0; r < nn->num_tx_rings; r++) {
1586-
nfp_net_tx_ring_init(&rings[r], nn->tx_rings[r].r_vec, r);
1585+
for (r = 0; r < s->n_rings; r++) {
1586+
nfp_net_tx_ring_init(&rings[r], &nn->r_vecs[r], r);
15871587

15881588
if (nfp_net_tx_ring_alloc(&rings[r], s->dcnt))
15891589
goto err_free_prev;
@@ -1605,9 +1605,11 @@ nfp_net_tx_ring_set_swap(struct nfp_net *nn, struct nfp_net_ring_set *s)
16051605

16061606
s->dcnt = nn->txd_cnt;
16071607
s->rings = nn->tx_rings;
1608+
s->n_rings = nn->num_tx_rings;
16081609

16091610
nn->txd_cnt = new.dcnt;
16101611
nn->tx_rings = new.rings;
1612+
nn->num_tx_rings = new.n_rings;
16111613
}
16121614

16131615
static void
@@ -1616,7 +1618,7 @@ nfp_net_tx_ring_set_free(struct nfp_net *nn, struct nfp_net_ring_set *s)
16161618
struct nfp_net_tx_ring *rings = s->rings;
16171619
unsigned int r;
16181620

1619-
for (r = 0; r < nn->num_tx_rings; r++)
1621+
for (r = 0; r < s->n_rings; r++)
16201622
nfp_net_tx_ring_free(&rings[r]);
16211623

16221624
kfree(rings);
@@ -1694,12 +1696,12 @@ nfp_net_rx_ring_set_prepare(struct nfp_net *nn, struct nfp_net_ring_set *s)
16941696
struct nfp_net_rx_ring *rings;
16951697
unsigned int r;
16961698

1697-
rings = kcalloc(nn->num_rx_rings, sizeof(*rings), GFP_KERNEL);
1699+
rings = kcalloc(s->n_rings, sizeof(*rings), GFP_KERNEL);
16981700
if (!rings)
16991701
return NULL;
17001702

1701-
for (r = 0; r < nn->num_rx_rings; r++) {
1702-
nfp_net_rx_ring_init(&rings[r], nn->rx_rings[r].r_vec, r);
1703+
for (r = 0; r < s->n_rings; r++) {
1704+
nfp_net_rx_ring_init(&rings[r], &nn->r_vecs[r], r);
17031705

17041706
if (nfp_net_rx_ring_alloc(&rings[r], fl_bufsz, s->dcnt))
17051707
goto err_free_prev;
@@ -1728,11 +1730,13 @@ nfp_net_rx_ring_set_swap(struct nfp_net *nn, struct nfp_net_ring_set *s)
17281730
s->mtu = nn->netdev->mtu;
17291731
s->dcnt = nn->rxd_cnt;
17301732
s->rings = nn->rx_rings;
1733+
s->n_rings = nn->num_rx_rings;
17311734

17321735
nn->netdev->mtu = new.mtu;
17331736
nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, new.mtu);
17341737
nn->rxd_cnt = new.dcnt;
17351738
nn->rx_rings = new.rings;
1739+
nn->num_rx_rings = new.n_rings;
17361740
}
17371741

17381742
static void
@@ -1741,7 +1745,7 @@ nfp_net_rx_ring_set_free(struct nfp_net *nn, struct nfp_net_ring_set *s)
17411745
struct nfp_net_rx_ring *rings = s->rings;
17421746
unsigned int r;
17431747

1744-
for (r = 0; r < nn->num_rx_rings; r++) {
1748+
for (r = 0; r < s->n_rings; r++) {
17451749
nfp_net_rx_ring_bufs_free(nn, &rings[r]);
17461750
nfp_net_rx_ring_free(&rings[r]);
17471751
}
@@ -1764,19 +1768,20 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
17641768
struct msix_entry *entry = &nn->irq_entries[r_vec->irq_idx];
17651769
int err;
17661770

1771+
/* Setup NAPI */
1772+
netif_napi_add(nn->netdev, &r_vec->napi,
1773+
nfp_net_poll, NAPI_POLL_WEIGHT);
1774+
17671775
snprintf(r_vec->name, sizeof(r_vec->name),
17681776
"%s-rxtx-%d", nn->netdev->name, idx);
17691777
err = request_irq(entry->vector, r_vec->handler, 0, r_vec->name, r_vec);
17701778
if (err) {
1779+
netif_napi_del(&r_vec->napi);
17711780
nn_err(nn, "Error requesting IRQ %d\n", entry->vector);
17721781
return err;
17731782
}
17741783
disable_irq(entry->vector);
17751784

1776-
/* Setup NAPI */
1777-
netif_napi_add(nn->netdev, &r_vec->napi,
1778-
nfp_net_poll, NAPI_POLL_WEIGHT);
1779-
17801785
irq_set_affinity_hint(entry->vector, &r_vec->affinity_mask);
17811786

17821787
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)
20362041
{
20372042
struct nfp_net *nn = netdev_priv(netdev);
20382043
struct nfp_net_ring_set rx = {
2044+
.n_rings = nn->num_rx_rings,
20392045
.mtu = nn->netdev->mtu,
20402046
.dcnt = nn->rxd_cnt,
20412047
};
20422048
struct nfp_net_ring_set tx = {
2049+
.n_rings = nn->num_tx_rings,
20432050
.dcnt = nn->txd_cnt,
20442051
};
20452052
int err, r;
@@ -2239,49 +2246,89 @@ static void nfp_net_rss_init_itbl(struct nfp_net *nn)
22392246
}
22402247

22412248
static int
2242-
nfp_net_ring_swap_enable(struct nfp_net *nn,
2249+
nfp_net_ring_swap_enable(struct nfp_net *nn, unsigned int *num_vecs,
22432250
struct nfp_net_ring_set *rx,
22442251
struct nfp_net_ring_set *tx)
22452252
{
22462253
unsigned int r;
2254+
int err;
22472255

22482256
if (rx)
22492257
nfp_net_rx_ring_set_swap(nn, rx);
22502258
if (tx)
22512259
nfp_net_tx_ring_set_swap(nn, tx);
22522260

2261+
swap(*num_vecs, nn->num_r_vecs);
2262+
22532263
for (r = 0; r < nn->max_r_vecs; r++)
22542264
nfp_net_vector_assign_rings(nn, &nn->r_vecs[r], r);
22552265

2266+
if (nn->netdev->real_num_rx_queues != nn->num_rx_rings) {
2267+
if (!netif_is_rxfh_configured(nn->netdev))
2268+
nfp_net_rss_init_itbl(nn);
2269+
2270+
err = netif_set_real_num_rx_queues(nn->netdev,
2271+
nn->num_rx_rings);
2272+
if (err)
2273+
return err;
2274+
}
2275+
2276+
if (nn->netdev->real_num_tx_queues != nn->num_tx_rings) {
2277+
err = netif_set_real_num_tx_queues(nn->netdev,
2278+
nn->num_tx_rings);
2279+
if (err)
2280+
return err;
2281+
}
2282+
22562283
return __nfp_net_set_config_and_enable(nn);
22572284
}
22582285

22592286
static void
22602287
nfp_net_ring_reconfig_down(struct nfp_net *nn,
22612288
struct nfp_net_ring_set *rx,
2262-
struct nfp_net_ring_set *tx)
2289+
struct nfp_net_ring_set *tx,
2290+
unsigned int num_vecs)
22632291
{
22642292
nn->netdev->mtu = rx ? rx->mtu : nn->netdev->mtu;
22652293
nn->fl_bufsz = nfp_net_calc_fl_bufsz(nn, nn->netdev->mtu);
22662294
nn->rxd_cnt = rx ? rx->dcnt : nn->rxd_cnt;
22672295
nn->txd_cnt = tx ? tx->dcnt : nn->txd_cnt;
2296+
nn->num_rx_rings = rx ? rx->n_rings : nn->num_rx_rings;
2297+
nn->num_tx_rings = tx ? tx->n_rings : nn->num_tx_rings;
2298+
nn->num_r_vecs = num_vecs;
2299+
2300+
if (!netif_is_rxfh_configured(nn->netdev))
2301+
nfp_net_rss_init_itbl(nn);
22682302
}
22692303

22702304
int
22712305
nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx,
22722306
struct nfp_net_ring_set *tx)
22732307
{
2308+
unsigned int num_vecs, r;
22742309
int err;
22752310

2311+
num_vecs = max(rx ? rx->n_rings : nn->num_rx_rings,
2312+
tx ? tx->n_rings : nn->num_tx_rings);
2313+
22762314
if (!netif_running(nn->netdev)) {
2277-
nfp_net_ring_reconfig_down(nn, rx, tx);
2315+
nfp_net_ring_reconfig_down(nn, rx, tx, num_vecs);
22782316
return 0;
22792317
}
22802318

22812319
/* Prepare new rings */
2320+
for (r = nn->num_r_vecs; r < num_vecs; r++) {
2321+
err = nfp_net_prepare_vector(nn, &nn->r_vecs[r], r);
2322+
if (err) {
2323+
num_vecs = r;
2324+
goto err_cleanup_vecs;
2325+
}
2326+
}
22822327
if (rx) {
2283-
if (!nfp_net_rx_ring_set_prepare(nn, rx))
2284-
return -ENOMEM;
2328+
if (!nfp_net_rx_ring_set_prepare(nn, rx)) {
2329+
err = -ENOMEM;
2330+
goto err_cleanup_vecs;
2331+
}
22852332
}
22862333
if (tx) {
22872334
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,
22942341
nfp_net_close_stack(nn);
22952342
nfp_net_clear_config_and_disable(nn);
22962343

2297-
err = nfp_net_ring_swap_enable(nn, rx, tx);
2344+
err = nfp_net_ring_swap_enable(nn, &num_vecs, rx, tx);
22982345
if (err) {
22992346
int err2;
23002347

23012348
nfp_net_clear_config_and_disable(nn);
23022349

23032350
/* Try with old configuration and old rings */
2304-
err2 = nfp_net_ring_swap_enable(nn, rx, tx);
2351+
err2 = nfp_net_ring_swap_enable(nn, &num_vecs, rx, tx);
23052352
if (err2)
23062353
nn_err(nn, "Can't restore ring config - FW communication failed (%d,%d)\n",
23072354
err, err2);
23082355
}
2356+
for (r = num_vecs - 1; r >= nn->num_r_vecs; r--)
2357+
nfp_net_cleanup_vector(nn, &nn->r_vecs[r]);
23092358

23102359
if (rx)
23112360
nfp_net_rx_ring_set_free(nn, rx);
@@ -2319,13 +2368,17 @@ nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_ring_set *rx,
23192368
err_free_rx:
23202369
if (rx)
23212370
nfp_net_rx_ring_set_free(nn, rx);
2371+
err_cleanup_vecs:
2372+
for (r = num_vecs - 1; r >= nn->num_r_vecs; r--)
2373+
nfp_net_cleanup_vector(nn, &nn->r_vecs[r]);
23222374
return err;
23232375
}
23242376

23252377
static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu)
23262378
{
23272379
struct nfp_net *nn = netdev_priv(netdev);
23282380
struct nfp_net_ring_set rx = {
2381+
.n_rings = nn->num_rx_rings,
23292382
.mtu = new_mtu,
23302383
.dcnt = nn->rxd_cnt,
23312384
};

drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,13 @@ void nfp_net_debugfs_adapter_add(struct nfp_net *nn)
207207
if (IS_ERR_OR_NULL(rx) || IS_ERR_OR_NULL(tx))
208208
return;
209209

210-
for (i = 0; i < nn->num_rx_rings; i++) {
210+
for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) {
211211
sprintf(int_name, "%d", i);
212212
debugfs_create_file(int_name, S_IRUSR, rx,
213213
&nn->r_vecs[i], &nfp_rx_q_fops);
214214
}
215215

216-
for (i = 0; i < nn->num_tx_rings; i++) {
216+
for (i = 0; i < min(nn->max_tx_rings, nn->max_r_vecs); i++) {
217217
sprintf(int_name, "%d", i);
218218
debugfs_create_file(int_name, S_IRUSR, tx,
219219
&nn->r_vecs[i], &nfp_tx_q_fops);

drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,12 @@ static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
162162
{
163163
struct nfp_net_ring_set *reconfig_rx = NULL, *reconfig_tx = NULL;
164164
struct nfp_net_ring_set rx = {
165+
.n_rings = nn->num_rx_rings,
165166
.mtu = nn->netdev->mtu,
166167
.dcnt = rxd_cnt,
167168
};
168169
struct nfp_net_ring_set tx = {
170+
.n_rings = nn->num_tx_rings,
169171
.dcnt = txd_cnt,
170172
};
171173

@@ -648,6 +650,50 @@ static void nfp_net_get_channels(struct net_device *netdev,
648650
channel->other_count = NFP_NET_NON_Q_VECTORS;
649651
}
650652

653+
static int nfp_net_set_num_rings(struct nfp_net *nn, unsigned int total_rx,
654+
unsigned int total_tx)
655+
{
656+
struct nfp_net_ring_set *reconfig_rx = NULL, *reconfig_tx = NULL;
657+
struct nfp_net_ring_set rx = {
658+
.n_rings = total_rx,
659+
.mtu = nn->netdev->mtu,
660+
.dcnt = nn->rxd_cnt,
661+
};
662+
struct nfp_net_ring_set tx = {
663+
.n_rings = total_tx,
664+
.dcnt = nn->txd_cnt,
665+
};
666+
667+
if (nn->num_rx_rings != total_rx)
668+
reconfig_rx = &rx;
669+
if (nn->num_tx_rings != total_tx)
670+
reconfig_tx = &tx;
671+
672+
return nfp_net_ring_reconfig(nn, reconfig_rx, reconfig_tx);
673+
}
674+
675+
static int nfp_net_set_channels(struct net_device *netdev,
676+
struct ethtool_channels *channel)
677+
{
678+
struct nfp_net *nn = netdev_priv(netdev);
679+
unsigned int total_rx, total_tx;
680+
681+
/* Reject unsupported */
682+
if (!channel->combined_count ||
683+
channel->other_count != NFP_NET_NON_Q_VECTORS ||
684+
(channel->rx_count && channel->tx_count))
685+
return -EINVAL;
686+
687+
total_rx = channel->combined_count + channel->rx_count;
688+
total_tx = channel->combined_count + channel->tx_count;
689+
690+
if (total_rx > min(nn->max_rx_rings, nn->max_r_vecs) ||
691+
total_tx > min(nn->max_tx_rings, nn->max_r_vecs))
692+
return -EINVAL;
693+
694+
return nfp_net_set_num_rings(nn, total_rx, total_tx);
695+
}
696+
651697
static const struct ethtool_ops nfp_net_ethtool_ops = {
652698
.get_drvinfo = nfp_net_get_drvinfo,
653699
.get_link = ethtool_op_get_link,
@@ -667,6 +713,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
667713
.get_coalesce = nfp_net_get_coalesce,
668714
.set_coalesce = nfp_net_set_coalesce,
669715
.get_channels = nfp_net_get_channels,
716+
.set_channels = nfp_net_set_channels,
670717
};
671718

672719
void nfp_net_set_ethtool_ops(struct net_device *netdev)

0 commit comments

Comments
 (0)