]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
hinic: fix a bug of ndo_stop
authorLuo bin <luobin9@huawei.com>
Sun, 10 May 2020 19:01:08 +0000 (19:01 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 May 2020 06:17:13 +0000 (08:17 +0200)
[ Upstream commit e8a1b0efd632d1c9db7d4e93da66377c7b524862 ]

if some function in ndo_stop interface returns failure because of
hardware fault, must go on excuting rest steps rather than return
failure directly, otherwise will cause memory leak.And bump the
timeout for SET_FUNC_STATE to ensure that cmd won't return failure
when hw is busy. Otherwise hw may stomp host memory if we free
memory regardless of the return value of SET_FUNC_STATE.

Fixes: 51ba902a16e6 ("net-next/hinic: Initialize hw interface")
Signed-off-by: Luo bin <luobin9@huawei.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
drivers/net/ethernet/huawei/hinic/hinic_main.c

index 9fcf2e5e000395100a7977f02dfb3b66c02307eb..0e40d647093cd699060740c58ddebe7a51a4f972 100644 (file)
@@ -54,6 +54,8 @@
 
 #define MGMT_MSG_TIMEOUT                5000
 
+#define SET_FUNC_PORT_MGMT_TIMEOUT     25000
+
 #define mgmt_to_pfhwdev(pf_mgmt)        \
                container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
 
@@ -247,12 +249,13 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
                            u8 *buf_in, u16 in_size,
                            u8 *buf_out, u16 *out_size,
                            enum mgmt_direction_type direction,
-                           u16 resp_msg_id)
+                           u16 resp_msg_id, u32 timeout)
 {
        struct hinic_hwif *hwif = pf_to_mgmt->hwif;
        struct pci_dev *pdev = hwif->pdev;
        struct hinic_recv_msg *recv_msg;
        struct completion *recv_done;
+       unsigned long timeo;
        u16 msg_id;
        int err;
 
@@ -276,8 +279,9 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
                goto unlock_sync_msg;
        }
 
-       if (!wait_for_completion_timeout(recv_done,
-                                        msecs_to_jiffies(MGMT_MSG_TIMEOUT))) {
+       timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
+
+       if (!wait_for_completion_timeout(recv_done, timeo)) {
                dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
                err = -ETIMEDOUT;
                goto unlock_sync_msg;
@@ -351,6 +355,7 @@ int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
 {
        struct hinic_hwif *hwif = pf_to_mgmt->hwif;
        struct pci_dev *pdev = hwif->pdev;
+       u32 timeout = 0;
 
        if (sync != HINIC_MGMT_MSG_SYNC) {
                dev_err(&pdev->dev, "Invalid MGMT msg type\n");
@@ -362,9 +367,12 @@ int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
                return -EINVAL;
        }
 
+       if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
+               timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
+
        return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
                                buf_out, out_size, MGMT_DIRECT_SEND,
-                               MSG_NOT_RESP);
+                               MSG_NOT_RESP, timeout);
 }
 
 /**
index 44c73215d0264e4398446c5f047f98b1e7192926..13ed3923c6887fd027265111f399fa863c4a0061 100644 (file)
@@ -473,7 +473,6 @@ static int hinic_close(struct net_device *netdev)
 {
        struct hinic_dev *nic_dev = netdev_priv(netdev);
        unsigned int flags;
-       int err;
 
        down(&nic_dev->mgmt_lock);
 
@@ -487,20 +486,9 @@ static int hinic_close(struct net_device *netdev)
 
        up(&nic_dev->mgmt_lock);
 
-       err = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE);
-       if (err) {
-               netif_err(nic_dev, drv, netdev,
-                         "Failed to set func port state\n");
-               nic_dev->flags |= (flags & HINIC_INTF_UP);
-               return err;
-       }
+       hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE);
 
-       err = hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE);
-       if (err) {
-               netif_err(nic_dev, drv, netdev, "Failed to set port state\n");
-               nic_dev->flags |= (flags & HINIC_INTF_UP);
-               return err;
-       }
+       hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE);
 
        free_rxqs(nic_dev);
        free_txqs(nic_dev);