FILE
hbg_err.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c
1// SPDX-License-Identifier: GPL-2.0+ 2// Copyright (c) 2024 Hisilicon Limited. 3 4#include <linux/etherdevice.h> 5#include <linux/netdevice.h> 6#include <linux/phy.h> 7#include <linux/rtnetlink.h> 8#include "hbg_common.h" 9#include "hbg_err.h" 10#include "hbg_hw.h" 11 12static void hbg_restore_mac_table(struct hbg_priv *priv) 13{ 14 struct hbg_mac_filter *filter = &priv->filter; 15 u64 addr; 16 u32 i; 17 18 for (i = 0; i < filter->table_max_len; i++) 19 if (!is_zero_ether_addr(filter->mac_table[i].addr)) { 20 addr = ether_addr_to_u64(filter->mac_table[i].addr); 21 hbg_hw_set_uc_addr(priv, addr, i); 22 } 23 24 hbg_hw_set_mac_filter_enable(priv, priv->filter.enabled); 25} 26 27static void hbg_restore_user_def_settings(struct hbg_priv *priv) 28{ 29 /* The index of host mac is always 0. */ 30 u64 rx_pause_addr = ether_addr_to_u64(priv->filter.mac_table[0].addr); 31 struct ethtool_pauseparam *pause_param = &priv->user_def.pause_param; 32 33 hbg_restore_mac_table(priv); 34 hbg_hw_set_mtu(priv, priv->netdev->mtu); 35 hbg_hw_set_pause_enable(priv, pause_param->tx_pause, 36 pause_param->rx_pause); 37 hbg_hw_set_rx_pause_mac_addr(priv, rx_pause_addr); 38} 39 40int hbg_rebuild(struct hbg_priv *priv) 41{ 42 int ret; 43 44 ret = hbg_hw_init(priv); 45 if (ret) 46 return ret; 47 48 hbg_restore_user_def_settings(priv); 49 return 0; 50} 51 52static int hbg_reset_prepare(struct hbg_priv *priv, enum hbg_reset_type type) 53{ 54 int ret; 55 56 if (test_and_set_bit(HBG_NIC_STATE_RESETTING, &priv->state)) 57 return -EBUSY; 58 59 if (netif_running(priv->netdev)) { 60 clear_bit(HBG_NIC_STATE_RESETTING, &priv->state); 61 dev_warn(&priv->pdev->dev, 62 "failed to reset because port is up\n"); 63 return -EBUSY; 64 } 65 66 netif_device_detach(priv->netdev); 67 68 priv->reset_type = type; 69 clear_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state); 70 ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET); 71 if (ret) { 72 priv->stats.reset_fail_cnt++; 73 set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state); 74 clear_bit(HBG_NIC_STATE_RESETTING, &priv->state); 75 } 76 77 return ret; 78} 79 80static int hbg_reset_done(struct hbg_priv *priv, enum hbg_reset_type type) 81{ 82 int ret; 83 84 if (!test_bit(HBG_NIC_STATE_RESETTING, &priv->state) || 85 type != priv->reset_type) 86 return 0; 87 88 ret = hbg_rebuild(priv); 89 if (ret) { 90 priv->stats.reset_fail_cnt++; 91 set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state); 92 clear_bit(HBG_NIC_STATE_RESETTING, &priv->state); 93 dev_err(&priv->pdev->dev, "failed to rebuild after reset\n"); 94 return ret; 95 } 96 97 netif_device_attach(priv->netdev); 98 clear_bit(HBG_NIC_STATE_RESETTING, &priv->state); 99 100 dev_info(&priv->pdev->dev, "reset done\n"); 101 return ret; 102} 103 104int hbg_reset(struct hbg_priv *priv) 105{ 106 int ret; 107 108 ret = hbg_reset_prepare(priv, HBG_RESET_TYPE_FUNCTION); 109 if (ret) 110 return ret; 111 112 return hbg_reset_done(priv, HBG_RESET_TYPE_FUNCTION); 113} 114 115void hbg_err_reset(struct hbg_priv *priv) 116{ 117 bool running; 118 119 rtnl_lock(); 120 running = netif_running(priv->netdev); 121 if (running) 122 dev_close(priv->netdev); 123 124 if (hbg_reset(priv)) 125 goto err_unlock; 126 127 if (running) 128 dev_open(priv->netdev, NULL); 129 130err_unlock: 131 rtnl_unlock(); 132} 133 134static pci_ers_result_t hbg_pci_err_detected(struct pci_dev *pdev, 135 pci_channel_state_t state) 136{ 137 struct net_device *netdev = pci_get_drvdata(pdev); 138 139 if (state == pci_channel_io_perm_failure) { 140 netif_device_detach(netdev); 141 return PCI_ERS_RESULT_DISCONNECT; 142 } 143 144 return PCI_ERS_RESULT_NEED_RESET; 145} 146 147static pci_ers_result_t hbg_pci_err_slot_reset(struct pci_dev *pdev) 148{ 149 struct net_device *netdev = pci_get_drvdata(pdev); 150 struct hbg_priv *priv = netdev_priv(netdev); 151 152 netif_device_detach(netdev); 153 pci_disable_device(pdev); 154 155 if (pci_enable_device(pdev)) { 156 dev_err(&pdev->dev, 157 "failed to re-enable PCI device after reset\n"); 158 return PCI_ERS_RESULT_DISCONNECT; 159 } 160 161 pci_set_master(pdev); 162 pci_restore_state(pdev); 163 164 hbg_err_reset(priv); 165 return PCI_ERS_RESULT_RECOVERED; 166} 167 168static void hbg_pci_err_reset_prepare(struct pci_dev *pdev) 169{ 170 struct net_device *netdev = pci_get_drvdata(pdev); 171 struct hbg_priv *priv = netdev_priv(netdev); 172 173 hbg_reset_prepare(priv, HBG_RESET_TYPE_FLR); 174} 175 176static void hbg_pci_err_reset_done(struct pci_dev *pdev) 177{ 178 struct net_device *netdev = pci_get_drvdata(pdev); 179 struct hbg_priv *priv = netdev_priv(netdev); 180 181 hbg_reset_done(priv, HBG_RESET_TYPE_FLR); 182} 183 184static const struct pci_error_handlers hbg_pci_err_handler = { 185 .error_detected = hbg_pci_err_detected, 186 .slot_reset = hbg_pci_err_slot_reset, 187 .reset_prepare = hbg_pci_err_reset_prepare, 188 .reset_done = hbg_pci_err_reset_done, 189}; 190 191void hbg_set_pci_err_handler(struct pci_driver *pdrv) 192{ 193 pdrv->err_handler = &hbg_pci_err_handler; 194}
~/
Read-only file preview.