File Index
Files and directories
Sign in
FILE

hbg_err.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c 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.