]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
eth: fbnic: support ring channel set while up
authorJakub Kicinski <kuba@kernel.org>
Fri, 20 Dec 2024 02:52:41 +0000 (18:52 -0800)
committerJakub Kicinski <kuba@kernel.org>
Mon, 23 Dec 2024 18:35:56 +0000 (10:35 -0800)
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>
drivers/net/ethernet/meta/fbnic/fbnic.h
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
drivers/net/ethernet/meta/fbnic/fbnic_irq.c
drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
drivers/net/ethernet/meta/fbnic/fbnic_pci.c
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
drivers/net/ethernet/meta/fbnic/fbnic_txrx.h

index ed527209b30cfd9cb373b193f2481b8b5f8cb3a9..14751f16e1252b36a85bfecc8d14349f52b35a37 100644 (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);
index d2fe97ae6a7161cd410065e9e9c08cd67aa34b62..20cd9f5f89e27a2f83d8c6bdac6f65cb2a5ae107 100644 (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
index a8ea7b6774a83774ac065b96562d54252580c369..1bbc0e56f3a039a05c470891e4ea5d84622ba493 100644 (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)
 {
index 0986c8f120a80414d6bcc4eb1618a2ea441f42a2..a392ac1cc4f2fcfae0923010ecc9d0f4da031e24 100644 (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);
index 32702dc4a06674e0c3daa8ef1c658def174bce84..6cbbc2ee3e1f98832a6405767c864d32b58a1015 100644 (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);
 
index 92fc1ad6ed6f954c6fdb889eafe04cf113d69738..bb54ce5f57871fe7a0dfb6ae096dd37c443cc2ee 100644 (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;
 
index 92c671135ad7347590284602ce534f32a73eb639..c2a94f31f71bd5831abd607622fd057276753c6d 100644 (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);