net: hns3: bugfix for not checking return value
[sfrench/cifs-2.6.git] / drivers / net / ethernet / hisilicon / hns3 / hns3_enet.c
index 76ce2f21178bfe3d13824cd3d0404b4da641650f..20fcf0d1c2ce5f8ec986928019aefbd209088731 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/ipv6.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/aer.h>
 #include <linux/skbuff.h>
 #include <linux/sctp.h>
 #include <linux/vermagic.h>
@@ -508,16 +509,18 @@ static void hns3_nic_set_rx_mode(struct net_device *netdev)
        h->netdev_flags = new_flags;
 }
 
-void hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags)
+int hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        struct hnae3_handle *h = priv->ae_handle;
 
        if (h->ae_algo->ops->set_promisc_mode) {
-               h->ae_algo->ops->set_promisc_mode(h,
-                                                 promisc_flags & HNAE3_UPE,
-                                                 promisc_flags & HNAE3_MPE);
+               return h->ae_algo->ops->set_promisc_mode(h,
+                                               promisc_flags & HNAE3_UPE,
+                                               promisc_flags & HNAE3_MPE);
        }
+
+       return 0;
 }
 
 void hns3_enable_vlan_filter(struct net_device *netdev, bool enable)
@@ -1493,18 +1496,22 @@ static int hns3_vlan_rx_kill_vid(struct net_device *netdev,
        return ret;
 }
 
-static void hns3_restore_vlan(struct net_device *netdev)
+static int hns3_restore_vlan(struct net_device *netdev)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
+       int ret = 0;
        u16 vid;
-       int ret;
 
        for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
                ret = hns3_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
-               if (ret)
-                       netdev_warn(netdev, "Restore vlan: %d filter, ret:%d\n",
-                                   vid, ret);
+               if (ret) {
+                       netdev_err(netdev, "Restore vlan: %d filter, ret:%d\n",
+                                  vid, ret);
+                       return ret;
+               }
        }
+
+       return ret;
 }
 
 static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
@@ -1613,7 +1620,7 @@ static void hns3_nic_net_timeout(struct net_device *ndev)
 
        /* request the reset */
        if (h->ae_algo->ops->reset_event)
-               h->ae_algo->ops->reset_event(h);
+               h->ae_algo->ops->reset_event(h->pdev, h);
 }
 
 static const struct net_device_ops hns3_nic_netdev_ops = {
@@ -1771,6 +1778,52 @@ static void hns3_shutdown(struct pci_dev *pdev)
                pci_set_power_state(pdev, PCI_D3hot);
 }
 
+static pci_ers_result_t hns3_error_detected(struct pci_dev *pdev,
+                                           pci_channel_state_t state)
+{
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+       pci_ers_result_t ret;
+
+       dev_info(&pdev->dev, "PCI error detected, state(=%d)!!\n", state);
+
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       if (!ae_dev) {
+               dev_err(&pdev->dev,
+                       "Can't recover - error happened during device init\n");
+               return PCI_ERS_RESULT_NONE;
+       }
+
+       if (ae_dev->ops->process_hw_error)
+               ret = ae_dev->ops->process_hw_error(ae_dev);
+       else
+               return PCI_ERS_RESULT_NONE;
+
+       return ret;
+}
+
+static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev)
+{
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+
+       dev_info(dev, "requesting reset due to PCI error\n");
+
+       /* request the reset */
+       if (ae_dev->ops->reset_event) {
+               ae_dev->ops->reset_event(pdev, NULL);
+               return PCI_ERS_RESULT_RECOVERED;
+       }
+
+       return PCI_ERS_RESULT_DISCONNECT;
+}
+
+static const struct pci_error_handlers hns3_err_handler = {
+       .error_detected = hns3_error_detected,
+       .slot_reset     = hns3_slot_reset,
+};
+
 static struct pci_driver hns3_driver = {
        .name     = hns3_driver_name,
        .id_table = hns3_pci_tbl,
@@ -1778,6 +1831,7 @@ static struct pci_driver hns3_driver = {
        .remove   = hns3_remove,
        .shutdown = hns3_shutdown,
        .sriov_configure = hns3_pci_sriov_configure,
+       .err_handler    = &hns3_err_handler,
 };
 
 /* set default feature to hns3 */
@@ -2679,7 +2733,7 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
                        chain = devm_kzalloc(&pdev->dev, sizeof(*chain),
                                             GFP_KERNEL);
                        if (!chain)
-                               return -ENOMEM;
+                               goto err_free_chain;
 
                        cur_chain->next = chain;
                        chain->tqp_index = tx_ring->tqp->tqp_index;
@@ -2709,7 +2763,7 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
        while (rx_ring) {
                chain = devm_kzalloc(&pdev->dev, sizeof(*chain), GFP_KERNEL);
                if (!chain)
-                       return -ENOMEM;
+                       goto err_free_chain;
 
                cur_chain->next = chain;
                chain->tqp_index = rx_ring->tqp->tqp_index;
@@ -2724,6 +2778,16 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
        }
 
        return 0;
+
+err_free_chain:
+       cur_chain = head->next;
+       while (cur_chain) {
+               chain = cur_chain->next;
+               devm_kfree(&pdev->dev, chain);
+               cur_chain = chain;
+       }
+
+       return -ENOMEM;
 }
 
 static void hns3_free_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
@@ -2773,7 +2837,7 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
        struct hnae3_handle *h = priv->ae_handle;
        struct hns3_enet_tqp_vector *tqp_vector;
        int ret = 0;
-       u16 i;
+       int i;
 
        hns3_nic_set_cpumask(priv);
 
@@ -2820,13 +2884,19 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
                hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);
 
                if (ret)
-                       return ret;
+                       goto map_ring_fail;
 
                netif_napi_add(priv->netdev, &tqp_vector->napi,
                               hns3_nic_common_poll, NAPI_POLL_WEIGHT);
        }
 
        return 0;
+
+map_ring_fail:
+       while (i--)
+               netif_napi_del(&priv->tqp_vector[i].napi);
+
+       return ret;
 }
 
 static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv)
@@ -2983,8 +3053,10 @@ static int hns3_queue_to_ring(struct hnae3_queue *tqp,
                return ret;
 
        ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX);
-       if (ret)
+       if (ret) {
+               devm_kfree(priv->dev, priv->ring_data[tqp->tqp_index].ring);
                return ret;
+       }
 
        return 0;
 }
@@ -3011,6 +3083,12 @@ static int hns3_get_ring_config(struct hns3_nic_priv *priv)
 
        return 0;
 err:
+       while (i--) {
+               devm_kfree(priv->dev, priv->ring_data[i].ring);
+               devm_kfree(priv->dev,
+                          priv->ring_data[i + h->kinfo.num_tqps].ring);
+       }
+
        devm_kfree(&pdev->dev, priv->ring_data);
        return ret;
 }
@@ -3178,9 +3256,6 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
        int i;
 
        for (i = 0; i < h->kinfo.num_tqps; i++) {
-               if (h->ae_algo->ops->reset_queue)
-                       h->ae_algo->ops->reset_queue(h, i);
-
                hns3_fini_ring(priv->ring_data[i].ring);
                hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring);
        }
@@ -3188,11 +3263,12 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
 }
 
 /* Set mac addr if it is configured. or leave it to the AE driver */
-static void hns3_init_mac_addr(struct net_device *netdev, bool init)
+static int hns3_init_mac_addr(struct net_device *netdev, bool init)
 {
        struct hns3_nic_priv *priv = netdev_priv(netdev);
        struct hnae3_handle *h = priv->ae_handle;
        u8 mac_addr_temp[ETH_ALEN];
+       int ret = 0;
 
        if (h->ae_algo->ops->get_mac_addr && init) {
                h->ae_algo->ops->get_mac_addr(h, mac_addr_temp);
@@ -3207,8 +3283,9 @@ static void hns3_init_mac_addr(struct net_device *netdev, bool init)
        }
 
        if (h->ae_algo->ops->set_mac_addr)
-               h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
+               ret = h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
 
+       return ret;
 }
 
 static int hns3_restore_fd_rules(struct net_device *netdev)
@@ -3421,20 +3498,29 @@ err_out:
        return ret;
 }
 
-static void hns3_recover_hw_addr(struct net_device *ndev)
+static int hns3_recover_hw_addr(struct net_device *ndev)
 {
        struct netdev_hw_addr_list *list;
        struct netdev_hw_addr *ha, *tmp;
+       int ret = 0;
 
        /* go through and sync uc_addr entries to the device */
        list = &ndev->uc;
-       list_for_each_entry_safe(ha, tmp, &list->list, list)
-               hns3_nic_uc_sync(ndev, ha->addr);
+       list_for_each_entry_safe(ha, tmp, &list->list, list) {
+               ret = hns3_nic_uc_sync(ndev, ha->addr);
+               if (ret)
+                       return ret;
+       }
 
        /* go through and sync mc_addr entries to the device */
        list = &ndev->mc;
-       list_for_each_entry_safe(ha, tmp, &list->list, list)
-               hns3_nic_mc_sync(ndev, ha->addr);
+       list_for_each_entry_safe(ha, tmp, &list->list, list) {
+               ret = hns3_nic_mc_sync(ndev, ha->addr);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static void hns3_remove_hw_addr(struct net_device *netdev)
@@ -3561,7 +3647,10 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h)
        int ret;
 
        for (i = 0; i < h->kinfo.num_tqps; i++) {
-               h->ae_algo->ops->reset_queue(h, i);
+               ret = h->ae_algo->ops->reset_queue(h, i);
+               if (ret)
+                       return ret;
+
                hns3_init_ring_hw(priv->ring_data[i].ring);
 
                /* We need to clear tx ring here because self test will
@@ -3653,18 +3742,31 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
        bool vlan_filter_enable;
        int ret;
 
-       hns3_init_mac_addr(netdev, false);
-       hns3_recover_hw_addr(netdev);
-       hns3_update_promisc_mode(netdev, handle->netdev_flags);
+       ret = hns3_init_mac_addr(netdev, false);
+       if (ret)
+               return ret;
+
+       ret = hns3_recover_hw_addr(netdev);
+       if (ret)
+               return ret;
+
+       ret = hns3_update_promisc_mode(netdev, handle->netdev_flags);
+       if (ret)
+               return ret;
+
        vlan_filter_enable = netdev->flags & IFF_PROMISC ? false : true;
        hns3_enable_vlan_filter(netdev, vlan_filter_enable);
 
-
        /* Hardware table is only clear when pf resets */
-       if (!(handle->flags & HNAE3_SUPPORT_VF))
-               hns3_restore_vlan(netdev);
+       if (!(handle->flags & HNAE3_SUPPORT_VF)) {
+               ret = hns3_restore_vlan(netdev);
+               if (ret)
+                       return ret;
+       }
 
-       hns3_restore_fd_rules(netdev);
+       ret = hns3_restore_fd_rules(netdev);
+       if (ret)
+               return ret;
 
        /* Carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);