1*3f5a61f6SJijie Shao // SPDX-License-Identifier: GPL-2.0+ 2*3f5a61f6SJijie Shao // Copyright (c) 2024 Hisilicon Limited. 3*3f5a61f6SJijie Shao 4*3f5a61f6SJijie Shao #include <linux/etherdevice.h> 5*3f5a61f6SJijie Shao #include <linux/netdevice.h> 6*3f5a61f6SJijie Shao #include <linux/phy.h> 7*3f5a61f6SJijie Shao #include <linux/rtnetlink.h> 8*3f5a61f6SJijie Shao #include "hbg_common.h" 9*3f5a61f6SJijie Shao #include "hbg_err.h" 10*3f5a61f6SJijie Shao #include "hbg_hw.h" 11*3f5a61f6SJijie Shao 12*3f5a61f6SJijie Shao static void hbg_restore_mac_table(struct hbg_priv *priv) 13*3f5a61f6SJijie Shao { 14*3f5a61f6SJijie Shao struct hbg_mac_filter *filter = &priv->filter; 15*3f5a61f6SJijie Shao u64 addr; 16*3f5a61f6SJijie Shao u32 i; 17*3f5a61f6SJijie Shao 18*3f5a61f6SJijie Shao for (i = 0; i < filter->table_max_len; i++) 19*3f5a61f6SJijie Shao if (!is_zero_ether_addr(filter->mac_table[i].addr)) { 20*3f5a61f6SJijie Shao addr = ether_addr_to_u64(filter->mac_table[i].addr); 21*3f5a61f6SJijie Shao hbg_hw_set_uc_addr(priv, addr, i); 22*3f5a61f6SJijie Shao } 23*3f5a61f6SJijie Shao 24*3f5a61f6SJijie Shao hbg_hw_set_mac_filter_enable(priv, priv->filter.enabled); 25*3f5a61f6SJijie Shao } 26*3f5a61f6SJijie Shao 27*3f5a61f6SJijie Shao static void hbg_restore_user_def_settings(struct hbg_priv *priv) 28*3f5a61f6SJijie Shao { 29*3f5a61f6SJijie Shao struct ethtool_pauseparam *pause_param = &priv->user_def.pause_param; 30*3f5a61f6SJijie Shao 31*3f5a61f6SJijie Shao hbg_restore_mac_table(priv); 32*3f5a61f6SJijie Shao hbg_hw_set_mtu(priv, priv->netdev->mtu); 33*3f5a61f6SJijie Shao hbg_hw_set_pause_enable(priv, pause_param->tx_pause, 34*3f5a61f6SJijie Shao pause_param->rx_pause); 35*3f5a61f6SJijie Shao } 36*3f5a61f6SJijie Shao 37*3f5a61f6SJijie Shao int hbg_rebuild(struct hbg_priv *priv) 38*3f5a61f6SJijie Shao { 39*3f5a61f6SJijie Shao int ret; 40*3f5a61f6SJijie Shao 41*3f5a61f6SJijie Shao ret = hbg_hw_init(priv); 42*3f5a61f6SJijie Shao if (ret) 43*3f5a61f6SJijie Shao return ret; 44*3f5a61f6SJijie Shao 45*3f5a61f6SJijie Shao hbg_restore_user_def_settings(priv); 46*3f5a61f6SJijie Shao return 0; 47*3f5a61f6SJijie Shao } 48*3f5a61f6SJijie Shao 49*3f5a61f6SJijie Shao static int hbg_reset_prepare(struct hbg_priv *priv, enum hbg_reset_type type) 50*3f5a61f6SJijie Shao { 51*3f5a61f6SJijie Shao int ret; 52*3f5a61f6SJijie Shao 53*3f5a61f6SJijie Shao ASSERT_RTNL(); 54*3f5a61f6SJijie Shao 55*3f5a61f6SJijie Shao if (netif_running(priv->netdev)) { 56*3f5a61f6SJijie Shao dev_warn(&priv->pdev->dev, 57*3f5a61f6SJijie Shao "failed to reset because port is up\n"); 58*3f5a61f6SJijie Shao return -EBUSY; 59*3f5a61f6SJijie Shao } 60*3f5a61f6SJijie Shao 61*3f5a61f6SJijie Shao priv->reset_type = type; 62*3f5a61f6SJijie Shao set_bit(HBG_NIC_STATE_RESETTING, &priv->state); 63*3f5a61f6SJijie Shao clear_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state); 64*3f5a61f6SJijie Shao ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET); 65*3f5a61f6SJijie Shao if (ret) { 66*3f5a61f6SJijie Shao set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state); 67*3f5a61f6SJijie Shao clear_bit(HBG_NIC_STATE_RESETTING, &priv->state); 68*3f5a61f6SJijie Shao } 69*3f5a61f6SJijie Shao 70*3f5a61f6SJijie Shao return ret; 71*3f5a61f6SJijie Shao } 72*3f5a61f6SJijie Shao 73*3f5a61f6SJijie Shao static int hbg_reset_done(struct hbg_priv *priv, enum hbg_reset_type type) 74*3f5a61f6SJijie Shao { 75*3f5a61f6SJijie Shao int ret; 76*3f5a61f6SJijie Shao 77*3f5a61f6SJijie Shao if (!test_bit(HBG_NIC_STATE_RESETTING, &priv->state) || 78*3f5a61f6SJijie Shao type != priv->reset_type) 79*3f5a61f6SJijie Shao return 0; 80*3f5a61f6SJijie Shao 81*3f5a61f6SJijie Shao ASSERT_RTNL(); 82*3f5a61f6SJijie Shao 83*3f5a61f6SJijie Shao clear_bit(HBG_NIC_STATE_RESETTING, &priv->state); 84*3f5a61f6SJijie Shao ret = hbg_rebuild(priv); 85*3f5a61f6SJijie Shao if (ret) { 86*3f5a61f6SJijie Shao set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state); 87*3f5a61f6SJijie Shao dev_err(&priv->pdev->dev, "failed to rebuild after reset\n"); 88*3f5a61f6SJijie Shao return ret; 89*3f5a61f6SJijie Shao } 90*3f5a61f6SJijie Shao 91*3f5a61f6SJijie Shao dev_info(&priv->pdev->dev, "reset done\n"); 92*3f5a61f6SJijie Shao return ret; 93*3f5a61f6SJijie Shao } 94*3f5a61f6SJijie Shao 95*3f5a61f6SJijie Shao /* must be protected by rtnl lock */ 96*3f5a61f6SJijie Shao int hbg_reset(struct hbg_priv *priv) 97*3f5a61f6SJijie Shao { 98*3f5a61f6SJijie Shao int ret; 99*3f5a61f6SJijie Shao 100*3f5a61f6SJijie Shao ASSERT_RTNL(); 101*3f5a61f6SJijie Shao ret = hbg_reset_prepare(priv, HBG_RESET_TYPE_FUNCTION); 102*3f5a61f6SJijie Shao if (ret) 103*3f5a61f6SJijie Shao return ret; 104*3f5a61f6SJijie Shao 105*3f5a61f6SJijie Shao return hbg_reset_done(priv, HBG_RESET_TYPE_FUNCTION); 106*3f5a61f6SJijie Shao } 107*3f5a61f6SJijie Shao 108*3f5a61f6SJijie Shao static void hbg_pci_err_reset_prepare(struct pci_dev *pdev) 109*3f5a61f6SJijie Shao { 110*3f5a61f6SJijie Shao struct net_device *netdev = pci_get_drvdata(pdev); 111*3f5a61f6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev); 112*3f5a61f6SJijie Shao 113*3f5a61f6SJijie Shao rtnl_lock(); 114*3f5a61f6SJijie Shao hbg_reset_prepare(priv, HBG_RESET_TYPE_FLR); 115*3f5a61f6SJijie Shao } 116*3f5a61f6SJijie Shao 117*3f5a61f6SJijie Shao static void hbg_pci_err_reset_done(struct pci_dev *pdev) 118*3f5a61f6SJijie Shao { 119*3f5a61f6SJijie Shao struct net_device *netdev = pci_get_drvdata(pdev); 120*3f5a61f6SJijie Shao struct hbg_priv *priv = netdev_priv(netdev); 121*3f5a61f6SJijie Shao 122*3f5a61f6SJijie Shao hbg_reset_done(priv, HBG_RESET_TYPE_FLR); 123*3f5a61f6SJijie Shao rtnl_unlock(); 124*3f5a61f6SJijie Shao } 125*3f5a61f6SJijie Shao 126*3f5a61f6SJijie Shao static const struct pci_error_handlers hbg_pci_err_handler = { 127*3f5a61f6SJijie Shao .reset_prepare = hbg_pci_err_reset_prepare, 128*3f5a61f6SJijie Shao .reset_done = hbg_pci_err_reset_done, 129*3f5a61f6SJijie Shao }; 130*3f5a61f6SJijie Shao 131*3f5a61f6SJijie Shao void hbg_set_pci_err_handler(struct pci_driver *pdrv) 132*3f5a61f6SJijie Shao { 133*3f5a61f6SJijie Shao pdrv->err_handler = &hbg_pci_err_handler; 134*3f5a61f6SJijie Shao } 135