net: hns3: fix an interrupt residual problem
authorYonglong Liu <liuyonglong@huawei.com>
Wed, 30 Apr 2025 09:30:50 +0000 (17:30 +0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 1 May 2025 14:19:48 +0000 (07:19 -0700)
When a VF is passthrough to a VM, and the VM is killed, the reported
interrupt may not been handled, it will remain, and won't be clear by
the nic engine even with a flr or tqp reset. When the VM restart, the
interrupt of the first vector may be dropped by the second enable_irq
in vfio, see the issue below:
https://gitlab.com/qemu-project/qemu/-/issues/2884#note_2423361621

We notice that the vfio has always behaved this way, and the interrupt
is a residue of the nic engine, so we fix the problem by moving the
vector enable process out of the enable_irq loop.

Fixes: 08a100689d4b ("net: hns3: re-organize vector handle")
Signed-off-by: Yonglong Liu <liuyonglong@huawei.com>
Signed-off-by: Jijie Shao <shaojijie@huawei.com>
Link: https://patch.msgid.link/20250430093052.2400464-3-shaojijie@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c

index 9ff797fb36c4564fb15abb3888dba58f6b61b2a6..b03b8758c7774ec29d1d39cef96686d547078257 100644 (file)
@@ -473,20 +473,14 @@ static void hns3_mask_vector_irq(struct hns3_enet_tqp_vector *tqp_vector,
        writel(mask_en, tqp_vector->mask_addr);
 }
 
-static void hns3_vector_enable(struct hns3_enet_tqp_vector *tqp_vector)
+static void hns3_irq_enable(struct hns3_enet_tqp_vector *tqp_vector)
 {
        napi_enable(&tqp_vector->napi);
        enable_irq(tqp_vector->vector_irq);
-
-       /* enable vector */
-       hns3_mask_vector_irq(tqp_vector, 1);
 }
 
-static void hns3_vector_disable(struct hns3_enet_tqp_vector *tqp_vector)
+static void hns3_irq_disable(struct hns3_enet_tqp_vector *tqp_vector)
 {
-       /* disable vector */
-       hns3_mask_vector_irq(tqp_vector, 0);
-
        disable_irq(tqp_vector->vector_irq);
        napi_disable(&tqp_vector->napi);
        cancel_work_sync(&tqp_vector->rx_group.dim.work);
@@ -707,11 +701,42 @@ static int hns3_set_rx_cpu_rmap(struct net_device *netdev)
        return 0;
 }
 
+static void hns3_enable_irqs_and_tqps(struct net_device *netdev)
+{
+       struct hns3_nic_priv *priv = netdev_priv(netdev);
+       struct hnae3_handle *h = priv->ae_handle;
+       u16 i;
+
+       for (i = 0; i < priv->vector_num; i++)
+               hns3_irq_enable(&priv->tqp_vector[i]);
+
+       for (i = 0; i < priv->vector_num; i++)
+               hns3_mask_vector_irq(&priv->tqp_vector[i], 1);
+
+       for (i = 0; i < h->kinfo.num_tqps; i++)
+               hns3_tqp_enable(h->kinfo.tqp[i]);
+}
+
+static void hns3_disable_irqs_and_tqps(struct net_device *netdev)
+{
+       struct hns3_nic_priv *priv = netdev_priv(netdev);
+       struct hnae3_handle *h = priv->ae_handle;
+       u16 i;
+
+       for (i = 0; i < h->kinfo.num_tqps; i++)
+               hns3_tqp_disable(h->kinfo.tqp[i]);
+
+       for (i = 0; i < priv->vector_num; i++)
+               hns3_mask_vector_irq(&priv->tqp_vector[i], 0);
+
+       for (i = 0; i < priv->vector_num; i++)
+               hns3_irq_disable(&priv->tqp_vector[i]);
+}
+
 static int hns3_nic_net_up(struct net_device *netdev)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        struct hnae3_handle *h = priv->ae_handle;
-       int i, j;
        int ret;
 
        ret = hns3_nic_reset_all_ring(h);
@@ -720,23 +745,13 @@ static int hns3_nic_net_up(struct net_device *netdev)
 
        clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
 
-       /* enable the vectors */
-       for (i = 0; i < priv->vector_num; i++)
-               hns3_vector_enable(&priv->tqp_vector[i]);
-
-       /* enable rcb */
-       for (j = 0; j < h->kinfo.num_tqps; j++)
-               hns3_tqp_enable(h->kinfo.tqp[j]);
+       hns3_enable_irqs_and_tqps(netdev);
 
        /* start the ae_dev */
        ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
        if (ret) {
                set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
-               while (j--)
-                       hns3_tqp_disable(h->kinfo.tqp[j]);
-
-               for (j = i - 1; j >= 0; j--)
-                       hns3_vector_disable(&priv->tqp_vector[j]);
+               hns3_disable_irqs_and_tqps(netdev);
        }
 
        return ret;
@@ -823,17 +838,9 @@ static void hns3_reset_tx_queue(struct hnae3_handle *h)
 static void hns3_nic_net_down(struct net_device *netdev)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
-       struct hnae3_handle *h = hns3_get_handle(netdev);
        const struct hnae3_ae_ops *ops;
-       int i;
 
-       /* disable vectors */
-       for (i = 0; i < priv->vector_num; i++)
-               hns3_vector_disable(&priv->tqp_vector[i]);
-
-       /* disable rcb */
-       for (i = 0; i < h->kinfo.num_tqps; i++)
-               hns3_tqp_disable(h->kinfo.tqp[i]);
+       hns3_disable_irqs_and_tqps(netdev);
 
        /* stop ae_dev */
        ops = priv->ae_handle->ae_algo->ops;
@@ -5864,8 +5871,6 @@ int hns3_set_channels(struct net_device *netdev,
 void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
 {
        struct hns3_nic_priv *priv = netdev_priv(ndev);
-       struct hnae3_handle *h = priv->ae_handle;
-       int i;
 
        if (!if_running)
                return;
@@ -5876,11 +5881,7 @@ void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
        netif_carrier_off(ndev);
        netif_tx_disable(ndev);
 
-       for (i = 0; i < priv->vector_num; i++)
-               hns3_vector_disable(&priv->tqp_vector[i]);
-
-       for (i = 0; i < h->kinfo.num_tqps; i++)
-               hns3_tqp_disable(h->kinfo.tqp[i]);
+       hns3_disable_irqs_and_tqps(ndev);
 
        /* delay ring buffer clearing to hns3_reset_notify_uninit_enet
         * during reset process, because driver may not be able
@@ -5896,7 +5897,6 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
 {
        struct hns3_nic_priv *priv = netdev_priv(ndev);
        struct hnae3_handle *h = priv->ae_handle;
-       int i;
 
        if (!if_running)
                return;
@@ -5912,11 +5912,7 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
 
        clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
 
-       for (i = 0; i < priv->vector_num; i++)
-               hns3_vector_enable(&priv->tqp_vector[i]);
-
-       for (i = 0; i < h->kinfo.num_tqps; i++)
-               hns3_tqp_enable(h->kinfo.tqp[i]);
+       hns3_enable_irqs_and_tqps(ndev);
 
        netif_tx_wake_all_queues(ndev);