net: hns3: fix an interrupt residual problem
[ Upstream commit 8e6b9c6ea5a55045eed6526d8ee49e93192d1a58 ]
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: 08a100689d
("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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
67d587bfa3
commit
c1b1d3b0d8
@@ -473,20 +473,14 @@ static void hns3_mask_vector_irq(struct hns3_enet_tqp_vector *tqp_vector,
|
|||||||
writel(mask_en, tqp_vector->mask_addr);
|
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);
|
napi_enable(&tqp_vector->napi);
|
||||||
enable_irq(tqp_vector->vector_irq);
|
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);
|
disable_irq(tqp_vector->vector_irq);
|
||||||
napi_disable(&tqp_vector->napi);
|
napi_disable(&tqp_vector->napi);
|
||||||
cancel_work_sync(&tqp_vector->rx_group.dim.work);
|
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;
|
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)
|
static int hns3_nic_net_up(struct net_device *netdev)
|
||||||
{
|
{
|
||||||
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
||||||
struct hnae3_handle *h = priv->ae_handle;
|
struct hnae3_handle *h = priv->ae_handle;
|
||||||
int i, j;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = hns3_nic_reset_all_ring(h);
|
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);
|
clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
||||||
|
|
||||||
/* enable the vectors */
|
hns3_enable_irqs_and_tqps(netdev);
|
||||||
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]);
|
|
||||||
|
|
||||||
/* start the ae_dev */
|
/* start the ae_dev */
|
||||||
ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
|
ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
||||||
while (j--)
|
hns3_disable_irqs_and_tqps(netdev);
|
||||||
hns3_tqp_disable(h->kinfo.tqp[j]);
|
|
||||||
|
|
||||||
for (j = i - 1; j >= 0; j--)
|
|
||||||
hns3_vector_disable(&priv->tqp_vector[j]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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)
|
static void hns3_nic_net_down(struct net_device *netdev)
|
||||||
{
|
{
|
||||||
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
||||||
struct hnae3_handle *h = hns3_get_handle(netdev);
|
|
||||||
const struct hnae3_ae_ops *ops;
|
const struct hnae3_ae_ops *ops;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* disable vectors */
|
hns3_disable_irqs_and_tqps(netdev);
|
||||||
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]);
|
|
||||||
|
|
||||||
/* stop ae_dev */
|
/* stop ae_dev */
|
||||||
ops = priv->ae_handle->ae_algo->ops;
|
ops = priv->ae_handle->ae_algo->ops;
|
||||||
@@ -5870,8 +5877,6 @@ int hns3_set_channels(struct net_device *netdev,
|
|||||||
void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
|
void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
|
||||||
{
|
{
|
||||||
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
||||||
struct hnae3_handle *h = priv->ae_handle;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!if_running)
|
if (!if_running)
|
||||||
return;
|
return;
|
||||||
@@ -5882,11 +5887,7 @@ void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
|
|||||||
netif_carrier_off(ndev);
|
netif_carrier_off(ndev);
|
||||||
netif_tx_disable(ndev);
|
netif_tx_disable(ndev);
|
||||||
|
|
||||||
for (i = 0; i < priv->vector_num; i++)
|
hns3_disable_irqs_and_tqps(ndev);
|
||||||
hns3_vector_disable(&priv->tqp_vector[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
||||||
hns3_tqp_disable(h->kinfo.tqp[i]);
|
|
||||||
|
|
||||||
/* delay ring buffer clearing to hns3_reset_notify_uninit_enet
|
/* delay ring buffer clearing to hns3_reset_notify_uninit_enet
|
||||||
* during reset process, because driver may not be able
|
* during reset process, because driver may not be able
|
||||||
@@ -5902,7 +5903,6 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
|
|||||||
{
|
{
|
||||||
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
||||||
struct hnae3_handle *h = priv->ae_handle;
|
struct hnae3_handle *h = priv->ae_handle;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!if_running)
|
if (!if_running)
|
||||||
return;
|
return;
|
||||||
@@ -5918,11 +5918,7 @@ void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
|
|||||||
|
|
||||||
clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
|
||||||
|
|
||||||
for (i = 0; i < priv->vector_num; i++)
|
hns3_enable_irqs_and_tqps(ndev);
|
||||||
hns3_vector_enable(&priv->tqp_vector[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
||||||
hns3_tqp_enable(h->kinfo.tqp[i]);
|
|
||||||
|
|
||||||
netif_tx_wake_all_queues(ndev);
|
netif_tx_wake_all_queues(ndev);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user