eth: fbnic: support ring channel set while up

Implement the channel count changes. Copy the netdev priv,
allocate new channels using it. Stop, swap, start.
Then free the copy of the priv along with the channels it
holds, which are now the channels that used to be on the
real priv.

Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://patch.msgid.link/20241220025241.1522781-11-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2024-12-19 18:52:41 -08:00
parent 3a481cc726
commit 52dc722db0
7 changed files with 143 additions and 6 deletions

View File

@@ -162,6 +162,7 @@ int fbnic_napi_request_irq(struct fbnic_dev *fbd,
struct fbnic_napi_vector *nv);
void fbnic_napi_free_irq(struct fbnic_dev *fbd,
struct fbnic_napi_vector *nv);
void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr);
int fbnic_request_irq(struct fbnic_dev *dev, int nr, irq_handler_t handler,
unsigned long flags, const char *name, void *data);
void fbnic_free_irq(struct fbnic_dev *dev, int nr, void *data);

View File

@@ -65,6 +65,76 @@ static void fbnic_get_regs(struct net_device *netdev,
fbnic_csr_get_regs(fbn->fbd, data, &regs->version);
}
static struct fbnic_net *fbnic_clone_create(struct fbnic_net *orig)
{
struct fbnic_net *clone;
clone = kmemdup(orig, sizeof(*orig), GFP_KERNEL);
if (!clone)
return NULL;
memset(clone->tx, 0, sizeof(clone->tx));
memset(clone->rx, 0, sizeof(clone->rx));
memset(clone->napi, 0, sizeof(clone->napi));
return clone;
}
static void fbnic_clone_swap_cfg(struct fbnic_net *orig,
struct fbnic_net *clone)
{
swap(clone->rcq_size, orig->rcq_size);
swap(clone->hpq_size, orig->hpq_size);
swap(clone->ppq_size, orig->ppq_size);
swap(clone->txq_size, orig->txq_size);
swap(clone->num_rx_queues, orig->num_rx_queues);
swap(clone->num_tx_queues, orig->num_tx_queues);
swap(clone->num_napi, orig->num_napi);
}
static void fbnic_aggregate_vector_counters(struct fbnic_net *fbn,
struct fbnic_napi_vector *nv)
{
int i, j;
for (i = 0; i < nv->txt_count; i++) {
fbnic_aggregate_ring_tx_counters(fbn, &nv->qt[i].sub0);
fbnic_aggregate_ring_tx_counters(fbn, &nv->qt[i].sub1);
fbnic_aggregate_ring_tx_counters(fbn, &nv->qt[i].cmpl);
}
for (j = 0; j < nv->rxt_count; j++, i++) {
fbnic_aggregate_ring_rx_counters(fbn, &nv->qt[i].sub0);
fbnic_aggregate_ring_rx_counters(fbn, &nv->qt[i].sub1);
fbnic_aggregate_ring_rx_counters(fbn, &nv->qt[i].cmpl);
}
}
static void fbnic_clone_swap(struct fbnic_net *orig,
struct fbnic_net *clone)
{
struct fbnic_dev *fbd = orig->fbd;
unsigned int i;
for (i = 0; i < max(clone->num_napi, orig->num_napi); i++)
fbnic_synchronize_irq(fbd, FBNIC_NON_NAPI_VECTORS + i);
for (i = 0; i < orig->num_napi; i++)
fbnic_aggregate_vector_counters(orig, orig->napi[i]);
fbnic_clone_swap_cfg(orig, clone);
for (i = 0; i < ARRAY_SIZE(orig->napi); i++)
swap(clone->napi[i], orig->napi[i]);
for (i = 0; i < ARRAY_SIZE(orig->tx); i++)
swap(clone->tx[i], orig->tx[i]);
for (i = 0; i < ARRAY_SIZE(orig->rx); i++)
swap(clone->rx[i], orig->rx[i]);
}
static void fbnic_clone_free(struct fbnic_net *clone)
{
kfree(clone);
}
static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data)
{
int i;
@@ -342,6 +412,8 @@ static int fbnic_set_channels(struct net_device *netdev,
struct fbnic_net *fbn = netdev_priv(netdev);
unsigned int max_napis, standalone;
struct fbnic_dev *fbd = fbn->fbd;
struct fbnic_net *clone;
int err;
max_napis = fbd->num_irqs - FBNIC_NON_NAPI_VECTORS;
standalone = ch->rx_count + ch->tx_count;
@@ -363,7 +435,54 @@ static int fbnic_set_channels(struct net_device *netdev,
return 0;
}
return -EBUSY;
clone = fbnic_clone_create(fbn);
if (!clone)
return -ENOMEM;
fbnic_set_queues(clone, ch, max_napis);
err = fbnic_alloc_napi_vectors(clone);
if (err)
goto err_free_clone;
err = fbnic_alloc_resources(clone);
if (err)
goto err_free_napis;
fbnic_down_noidle(fbn);
err = fbnic_wait_all_queues_idle(fbn->fbd, true);
if (err)
goto err_start_stack;
err = fbnic_set_netif_queues(clone);
if (err)
goto err_start_stack;
/* Nothing can fail past this point */
fbnic_flush(fbn);
fbnic_clone_swap(fbn, clone);
/* Reset RSS indirection table */
fbnic_reset_indir_tbl(fbn);
fbnic_up(fbn);
fbnic_free_resources(clone);
fbnic_free_napi_vectors(clone);
fbnic_clone_free(clone);
return 0;
err_start_stack:
fbnic_flush(fbn);
fbnic_up(fbn);
fbnic_free_resources(clone);
err_free_napis:
fbnic_free_napi_vectors(clone);
err_free_clone:
fbnic_clone_free(clone);
return err;
}
static int

View File

@@ -146,6 +146,17 @@ void fbnic_pcs_irq_disable(struct fbnic_dev *fbd)
free_irq(fbd->pcs_msix_vector, fbd);
}
void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr)
{
struct pci_dev *pdev = to_pci_dev(fbd->dev);
int irq = pci_irq_vector(pdev, nr);
if (irq < 0)
return;
synchronize_irq(irq);
}
int fbnic_request_irq(struct fbnic_dev *fbd, int nr, irq_handler_t handler,
unsigned long flags, const char *name, void *data)
{

View File

@@ -65,6 +65,7 @@ struct fbnic_net {
int __fbnic_open(struct fbnic_net *fbn);
void fbnic_up(struct fbnic_net *fbn);
void fbnic_down(struct fbnic_net *fbn);
void fbnic_down_noidle(struct fbnic_net *fbn);
struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd);
void fbnic_netdev_free(struct fbnic_dev *fbd);

View File

@@ -145,7 +145,7 @@ void fbnic_up(struct fbnic_net *fbn)
fbnic_service_task_start(fbn);
}
static void fbnic_down_noidle(struct fbnic_net *fbn)
void fbnic_down_noidle(struct fbnic_net *fbn)
{
fbnic_service_task_stop(fbn);

View File

@@ -1045,8 +1045,8 @@ irqreturn_t fbnic_msix_clean_rings(int __always_unused irq, void *data)
return IRQ_HANDLED;
}
static void fbnic_aggregate_ring_rx_counters(struct fbnic_net *fbn,
struct fbnic_ring *rxr)
void fbnic_aggregate_ring_rx_counters(struct fbnic_net *fbn,
struct fbnic_ring *rxr)
{
struct fbnic_queue_stats *stats = &rxr->stats;
@@ -1056,8 +1056,8 @@ static void fbnic_aggregate_ring_rx_counters(struct fbnic_net *fbn,
fbn->rx_stats.dropped += stats->dropped;
}
static void fbnic_aggregate_ring_tx_counters(struct fbnic_net *fbn,
struct fbnic_ring *txr)
void fbnic_aggregate_ring_tx_counters(struct fbnic_net *fbn,
struct fbnic_ring *txr)
{
struct fbnic_queue_stats *stats = &txr->stats;

View File

@@ -120,6 +120,11 @@ netdev_features_t
fbnic_features_check(struct sk_buff *skb, struct net_device *dev,
netdev_features_t features);
void fbnic_aggregate_ring_rx_counters(struct fbnic_net *fbn,
struct fbnic_ring *rxr);
void fbnic_aggregate_ring_tx_counters(struct fbnic_net *fbn,
struct fbnic_ring *txr);
int fbnic_alloc_napi_vectors(struct fbnic_net *fbn);
void fbnic_free_napi_vectors(struct fbnic_net *fbn);
int fbnic_alloc_resources(struct fbnic_net *fbn);