Commit 2d2faaf0 authored by David S. Miller's avatar David S. Miller

Merge branch 'hns3-add-support-for-reset'

Lipeng says:

====================
net: hns3: add support for reset

There are 4 reset types for HNS3 PF driver, include global reset,
core reset, IMP reset, PF reset.The core reset will reset all datapath
of all functions except IMP, MAC and PCI interface. Global reset is equal
with the core reset plus all MAC reset. IMP reset is caused by watchdog
timer expiration, the same range with core reset. PF reset will reset
whole physical function.

This patchset adds reset support for hns3 driver and fix some related bugs.

---
Change log:
V1 -> V2:
1, fix some comments from Yunsheng Lin.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9691cea9 c6dc5213
...@@ -110,6 +110,21 @@ enum hnae3_media_type { ...@@ -110,6 +110,21 @@ enum hnae3_media_type {
HNAE3_MEDIA_TYPE_BACKPLANE, HNAE3_MEDIA_TYPE_BACKPLANE,
}; };
enum hnae3_reset_notify_type {
HNAE3_UP_CLIENT,
HNAE3_DOWN_CLIENT,
HNAE3_INIT_CLIENT,
HNAE3_UNINIT_CLIENT,
};
enum hnae3_reset_type {
HNAE3_FUNC_RESET,
HNAE3_CORE_RESET,
HNAE3_GLOBAL_RESET,
HNAE3_IMP_RESET,
HNAE3_NONE_RESET,
};
struct hnae3_vector_info { struct hnae3_vector_info {
u8 __iomem *io_addr; u8 __iomem *io_addr;
int vector; int vector;
...@@ -133,6 +148,8 @@ struct hnae3_client_ops { ...@@ -133,6 +148,8 @@ struct hnae3_client_ops {
void (*uninit_instance)(struct hnae3_handle *handle, bool reset); void (*uninit_instance)(struct hnae3_handle *handle, bool reset);
void (*link_status_change)(struct hnae3_handle *handle, bool state); void (*link_status_change)(struct hnae3_handle *handle, bool state);
int (*setup_tc)(struct hnae3_handle *handle, u8 tc); int (*setup_tc)(struct hnae3_handle *handle, u8 tc);
int (*reset_notify)(struct hnae3_handle *handle,
enum hnae3_reset_notify_type type);
}; };
#define HNAE3_CLIENT_NAME_LENGTH 16 #define HNAE3_CLIENT_NAME_LENGTH 16
...@@ -367,6 +384,8 @@ struct hnae3_ae_ops { ...@@ -367,6 +384,8 @@ struct hnae3_ae_ops {
u16 vlan_id, bool is_kill); u16 vlan_id, bool is_kill);
int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid, int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
u16 vlan, u8 qos, __be16 proto); u16 vlan, u8 qos, __be16 proto);
void (*reset_event)(struct hnae3_handle *handle,
enum hnae3_reset_type reset);
}; };
struct hnae3_dcb_ops { struct hnae3_dcb_ops {
......
...@@ -62,7 +62,7 @@ static void hclge_free_cmd_desc(struct hclge_cmq_ring *ring) ...@@ -62,7 +62,7 @@ static void hclge_free_cmd_desc(struct hclge_cmq_ring *ring)
ring->desc = NULL; ring->desc = NULL;
} }
static int hclge_init_cmd_queue(struct hclge_dev *hdev, int ring_type) static int hclge_alloc_cmd_queue(struct hclge_dev *hdev, int ring_type)
{ {
struct hclge_hw *hw = &hdev->hw; struct hclge_hw *hw = &hdev->hw;
struct hclge_cmq_ring *ring = struct hclge_cmq_ring *ring =
...@@ -79,9 +79,6 @@ static int hclge_init_cmd_queue(struct hclge_dev *hdev, int ring_type) ...@@ -79,9 +79,6 @@ static int hclge_init_cmd_queue(struct hclge_dev *hdev, int ring_type)
return ret; return ret;
} }
ring->next_to_clean = 0;
ring->next_to_use = 0;
return 0; return 0;
} }
...@@ -302,37 +299,52 @@ static enum hclge_cmd_status hclge_cmd_query_firmware_version( ...@@ -302,37 +299,52 @@ static enum hclge_cmd_status hclge_cmd_query_firmware_version(
return ret; return ret;
} }
int hclge_cmd_init(struct hclge_dev *hdev) int hclge_cmd_queue_init(struct hclge_dev *hdev)
{ {
u32 version;
int ret; int ret;
/* Setup the queue entries for use cmd queue */ /* Setup the queue entries for use cmd queue */
hdev->hw.cmq.csq.desc_num = HCLGE_NIC_CMQ_DESC_NUM; hdev->hw.cmq.csq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
hdev->hw.cmq.crq.desc_num = HCLGE_NIC_CMQ_DESC_NUM; hdev->hw.cmq.crq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
/* Setup the lock for command queue */
spin_lock_init(&hdev->hw.cmq.csq.lock);
spin_lock_init(&hdev->hw.cmq.crq.lock);
/* Setup Tx write back timeout */ /* Setup Tx write back timeout */
hdev->hw.cmq.tx_timeout = HCLGE_CMDQ_TX_TIMEOUT; hdev->hw.cmq.tx_timeout = HCLGE_CMDQ_TX_TIMEOUT;
/* Setup queue rings */ /* Setup queue rings */
ret = hclge_init_cmd_queue(hdev, HCLGE_TYPE_CSQ); ret = hclge_alloc_cmd_queue(hdev, HCLGE_TYPE_CSQ);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"CSQ ring setup error %d\n", ret); "CSQ ring setup error %d\n", ret);
return ret; return ret;
} }
ret = hclge_init_cmd_queue(hdev, HCLGE_TYPE_CRQ); ret = hclge_alloc_cmd_queue(hdev, HCLGE_TYPE_CRQ);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"CRQ ring setup error %d\n", ret); "CRQ ring setup error %d\n", ret);
goto err_csq; goto err_csq;
} }
return 0;
err_csq:
hclge_free_cmd_desc(&hdev->hw.cmq.csq);
return ret;
}
int hclge_cmd_init(struct hclge_dev *hdev)
{
u32 version;
int ret;
hdev->hw.cmq.csq.next_to_clean = 0;
hdev->hw.cmq.csq.next_to_use = 0;
hdev->hw.cmq.crq.next_to_clean = 0;
hdev->hw.cmq.crq.next_to_use = 0;
/* Setup the lock for command queue */
spin_lock_init(&hdev->hw.cmq.csq.lock);
spin_lock_init(&hdev->hw.cmq.crq.lock);
hclge_cmd_init_regs(&hdev->hw); hclge_cmd_init_regs(&hdev->hw);
ret = hclge_cmd_query_firmware_version(&hdev->hw, &version); ret = hclge_cmd_query_firmware_version(&hdev->hw, &version);
...@@ -346,9 +358,6 @@ int hclge_cmd_init(struct hclge_dev *hdev) ...@@ -346,9 +358,6 @@ int hclge_cmd_init(struct hclge_dev *hdev)
dev_info(&hdev->pdev->dev, "The firmware version is %08x\n", version); dev_info(&hdev->pdev->dev, "The firmware version is %08x\n", version);
return 0; return 0;
err_csq:
hclge_free_cmd_desc(&hdev->hw.cmq.csq);
return ret;
} }
static void hclge_destroy_queue(struct hclge_cmq_ring *ring) static void hclge_destroy_queue(struct hclge_cmq_ring *ring)
......
...@@ -63,6 +63,11 @@ enum hclge_cmd_status { ...@@ -63,6 +63,11 @@ enum hclge_cmd_status {
HCLGE_ERR_CSQ_ERROR = -3, HCLGE_ERR_CSQ_ERROR = -3,
}; };
struct hclge_misc_vector {
u8 __iomem *addr;
int vector_irq;
};
struct hclge_cmq { struct hclge_cmq {
struct hclge_cmq_ring csq; struct hclge_cmq_ring csq;
struct hclge_cmq_ring crq; struct hclge_cmq_ring crq;
...@@ -692,6 +697,13 @@ struct hclge_reset_tqp_queue_cmd { ...@@ -692,6 +697,13 @@ struct hclge_reset_tqp_queue_cmd {
u8 rsv[20]; u8 rsv[20];
}; };
#define HCLGE_CFG_RESET_MAC_B 3
#define HCLGE_CFG_RESET_FUNC_B 7
struct hclge_reset_cmd {
u8 mac_func_reset;
u8 fun_reset_vfid;
u8 rsv[22];
};
#define HCLGE_DEFAULT_TX_BUF 0x4000 /* 16k bytes */ #define HCLGE_DEFAULT_TX_BUF 0x4000 /* 16k bytes */
#define HCLGE_TOTAL_PKT_BUF 0x108000 /* 1.03125M bytes */ #define HCLGE_TOTAL_PKT_BUF 0x108000 /* 1.03125M bytes */
#define HCLGE_DEFAULT_DV 0xA000 /* 40k byte */ #define HCLGE_DEFAULT_DV 0xA000 /* 40k byte */
...@@ -750,4 +762,5 @@ enum hclge_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw, ...@@ -750,4 +762,5 @@ enum hclge_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw,
struct hclge_desc *desc); struct hclge_desc *desc);
void hclge_destroy_cmd_queue(struct hclge_hw *hw); void hclge_destroy_cmd_queue(struct hclge_hw *hw);
int hclge_cmd_queue_init(struct hclge_dev *hdev);
#endif #endif
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
(HCLGE_PF_CFG_BLOCK_SIZE / HCLGE_CFG_RD_LEN_BYTES) (HCLGE_PF_CFG_BLOCK_SIZE / HCLGE_CFG_RD_LEN_BYTES)
#define HCLGE_VECTOR_REG_BASE 0x20000 #define HCLGE_VECTOR_REG_BASE 0x20000
#define HCLGE_MISC_VECTOR_REG_BASE 0x20400
#define HCLGE_VECTOR_REG_OFFSET 0x4 #define HCLGE_VECTOR_REG_OFFSET 0x4
#define HCLGE_VECTOR_VF_OFFSET 0x100000 #define HCLGE_VECTOR_VF_OFFSET 0x100000
...@@ -78,6 +79,19 @@ ...@@ -78,6 +79,19 @@
#define HCLGE_PHY_MDIX_STATUS_B (6) #define HCLGE_PHY_MDIX_STATUS_B (6)
#define HCLGE_PHY_SPEED_DUP_RESOLVE_B (11) #define HCLGE_PHY_SPEED_DUP_RESOLVE_B (11)
/* Reset related Registers */
#define HCLGE_MISC_RESET_STS_REG 0x20700
#define HCLGE_GLOBAL_RESET_REG 0x20A00
#define HCLGE_GLOBAL_RESET_BIT 0x0
#define HCLGE_CORE_RESET_BIT 0x1
#define HCLGE_FUN_RST_ING 0x20C00
#define HCLGE_FUN_RST_ING_B 0
/* Vector0 register bits define */
#define HCLGE_VECTOR0_GLOBALRESET_INT_B 5
#define HCLGE_VECTOR0_CORERESET_INT_B 6
#define HCLGE_VECTOR0_IMPRESET_INT_B 7
enum HCLGE_DEV_STATE { enum HCLGE_DEV_STATE {
HCLGE_STATE_REINITING, HCLGE_STATE_REINITING,
HCLGE_STATE_DOWN, HCLGE_STATE_DOWN,
...@@ -87,6 +101,7 @@ enum HCLGE_DEV_STATE { ...@@ -87,6 +101,7 @@ enum HCLGE_DEV_STATE {
HCLGE_STATE_SERVICE_SCHED, HCLGE_STATE_SERVICE_SCHED,
HCLGE_STATE_MBX_HANDLING, HCLGE_STATE_MBX_HANDLING,
HCLGE_STATE_MBX_IRQ, HCLGE_STATE_MBX_IRQ,
HCLGE_STATE_RESET_INT,
HCLGE_STATE_MAX HCLGE_STATE_MAX
}; };
...@@ -400,9 +415,11 @@ struct hclge_dev { ...@@ -400,9 +415,11 @@ struct hclge_dev {
struct pci_dev *pdev; struct pci_dev *pdev;
struct hnae3_ae_dev *ae_dev; struct hnae3_ae_dev *ae_dev;
struct hclge_hw hw; struct hclge_hw hw;
struct hclge_misc_vector misc_vector;
struct hclge_hw_stats hw_stats; struct hclge_hw_stats hw_stats;
unsigned long state; unsigned long state;
enum hnae3_reset_type reset_type;
u32 fw_version; u32 fw_version;
u16 num_vmdq_vport; /* Num vmdq vport this PF has set up */ u16 num_vmdq_vport; /* Num vmdq vport this PF has set up */
u16 num_tqps; /* Num task queue pairs of this PF */ u16 num_tqps; /* Num task queue pairs of this PF */
......
...@@ -258,6 +258,7 @@ static int hns3_nic_net_up(struct net_device *netdev) ...@@ -258,6 +258,7 @@ static int hns3_nic_net_up(struct net_device *netdev)
static int hns3_nic_net_open(struct net_device *netdev) static int hns3_nic_net_open(struct net_device *netdev)
{ {
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret; int ret;
netif_carrier_off(netdev); netif_carrier_off(netdev);
...@@ -273,6 +274,7 @@ static int hns3_nic_net_open(struct net_device *netdev) ...@@ -273,6 +274,7 @@ static int hns3_nic_net_open(struct net_device *netdev)
return ret; return ret;
} }
priv->last_reset_time = jiffies;
return 0; return 0;
} }
...@@ -1322,10 +1324,91 @@ static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -1322,10 +1324,91 @@ static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu)
return ret; return ret;
} }
static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hns3_enet_ring *tx_ring = NULL;
int timeout_queue = 0;
int hw_head, hw_tail;
int i;
/* Find the stopped queue the same way the stack does */
for (i = 0; i < ndev->real_num_tx_queues; i++) {
struct netdev_queue *q;
unsigned long trans_start;
q = netdev_get_tx_queue(ndev, i);
trans_start = q->trans_start;
if (netif_xmit_stopped(q) &&
time_after(jiffies,
(trans_start + ndev->watchdog_timeo))) {
timeout_queue = i;
break;
}
}
if (i == ndev->num_tx_queues) {
netdev_info(ndev,
"no netdev TX timeout queue found, timeout count: %llu\n",
priv->tx_timeout_count);
return false;
}
tx_ring = priv->ring_data[timeout_queue].ring;
hw_head = readl_relaxed(tx_ring->tqp->io_base +
HNS3_RING_TX_RING_HEAD_REG);
hw_tail = readl_relaxed(tx_ring->tqp->io_base +
HNS3_RING_TX_RING_TAIL_REG);
netdev_info(ndev,
"tx_timeout count: %llu, queue id: %d, SW_NTU: 0x%x, SW_NTC: 0x%x, HW_HEAD: 0x%x, HW_TAIL: 0x%x, INT: 0x%x\n",
priv->tx_timeout_count,
timeout_queue,
tx_ring->next_to_use,
tx_ring->next_to_clean,
hw_head,
hw_tail,
readl(tx_ring->tqp_vector->mask_addr));
return true;
}
static void hns3_nic_net_timeout(struct net_device *ndev)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
unsigned long last_reset_time = priv->last_reset_time;
struct hnae3_handle *h = priv->ae_handle;
if (!hns3_get_tx_timeo_queue_info(ndev))
return;
priv->tx_timeout_count++;
/* This timeout is far away enough from last timeout,
* if timeout again,set the reset type to PF reset
*/
if (time_after(jiffies, (last_reset_time + 20 * HZ)))
priv->reset_level = HNAE3_FUNC_RESET;
/* Don't do any new action before the next timeout */
else if (time_before(jiffies, (last_reset_time + ndev->watchdog_timeo)))
return;
priv->last_reset_time = jiffies;
if (h->ae_algo->ops->reset_event)
h->ae_algo->ops->reset_event(h, priv->reset_level);
priv->reset_level++;
if (priv->reset_level > HNAE3_GLOBAL_RESET)
priv->reset_level = HNAE3_GLOBAL_RESET;
}
static const struct net_device_ops hns3_nic_netdev_ops = { static const struct net_device_ops hns3_nic_netdev_ops = {
.ndo_open = hns3_nic_net_open, .ndo_open = hns3_nic_net_open,
.ndo_stop = hns3_nic_net_stop, .ndo_stop = hns3_nic_net_stop,
.ndo_start_xmit = hns3_nic_net_xmit, .ndo_start_xmit = hns3_nic_net_xmit,
.ndo_tx_timeout = hns3_nic_net_timeout,
.ndo_set_mac_address = hns3_nic_net_set_mac_address, .ndo_set_mac_address = hns3_nic_net_set_mac_address,
.ndo_change_mtu = hns3_nic_change_mtu, .ndo_change_mtu = hns3_nic_change_mtu,
.ndo_set_features = hns3_nic_set_features, .ndo_set_features = hns3_nic_set_features,
...@@ -2475,9 +2558,8 @@ static int hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv) ...@@ -2475,9 +2558,8 @@ static int hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv)
(void)irq_set_affinity_hint( (void)irq_set_affinity_hint(
priv->tqp_vector[i].vector_irq, priv->tqp_vector[i].vector_irq,
NULL); NULL);
devm_free_irq(&pdev->dev, free_irq(priv->tqp_vector[i].vector_irq,
priv->tqp_vector[i].vector_irq, &priv->tqp_vector[i]);
&priv->tqp_vector[i]);
} }
priv->ring_data[i].ring->irq_init_flag = HNS3_VECTOR_NOT_INITED; priv->ring_data[i].ring->irq_init_flag = HNS3_VECTOR_NOT_INITED;
...@@ -2763,6 +2845,9 @@ static int hns3_client_init(struct hnae3_handle *handle) ...@@ -2763,6 +2845,9 @@ static int hns3_client_init(struct hnae3_handle *handle)
priv->dev = &pdev->dev; priv->dev = &pdev->dev;
priv->netdev = netdev; priv->netdev = netdev;
priv->ae_handle = handle; priv->ae_handle = handle;
priv->last_reset_time = jiffies;
priv->reset_level = HNAE3_FUNC_RESET;
priv->tx_timeout_count = 0;
handle->kinfo.netdev = netdev; handle->kinfo.netdev = netdev;
handle->priv = (void *)priv; handle->priv = (void *)priv;
...@@ -2923,11 +3008,164 @@ static int hns3_client_setup_tc(struct hnae3_handle *handle, u8 tc) ...@@ -2923,11 +3008,164 @@ static int hns3_client_setup_tc(struct hnae3_handle *handle, u8 tc)
return ret; return ret;
} }
static void hns3_recover_hw_addr(struct net_device *ndev)
{
struct netdev_hw_addr_list *list;
struct netdev_hw_addr *ha, *tmp;
/* 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);
/* 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);
}
static void hns3_drop_skb_data(struct hns3_enet_ring *ring, struct sk_buff *skb)
{
dev_kfree_skb_any(skb);
}
static void hns3_clear_all_ring(struct hnae3_handle *h)
{
struct net_device *ndev = h->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(ndev);
u32 i;
for (i = 0; i < h->kinfo.num_tqps; i++) {
struct netdev_queue *dev_queue;
struct hns3_enet_ring *ring;
ring = priv->ring_data[i].ring;
hns3_clean_tx_ring(ring, ring->desc_num);
dev_queue = netdev_get_tx_queue(ndev,
priv->ring_data[i].queue_index);
netdev_tx_reset_queue(dev_queue);
ring = priv->ring_data[i + h->kinfo.num_tqps].ring;
hns3_clean_rx_ring(ring, ring->desc_num, hns3_drop_skb_data);
}
}
static int hns3_reset_notify_down_enet(struct hnae3_handle *handle)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct net_device *ndev = kinfo->netdev;
if (!netif_running(ndev))
return -EIO;
return hns3_nic_net_stop(ndev);
}
static int hns3_reset_notify_up_enet(struct hnae3_handle *handle)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hns3_nic_priv *priv = netdev_priv(kinfo->netdev);
int ret = 0;
if (netif_running(kinfo->netdev)) {
ret = hns3_nic_net_up(kinfo->netdev);
if (ret) {
netdev_err(kinfo->netdev,
"hns net up fail, ret=%d!\n", ret);
return ret;
}
priv->last_reset_time = jiffies;
}
return ret;
}
static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
{
struct net_device *netdev = handle->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret;
priv->reset_level = 1;
hns3_init_mac_addr(netdev);
hns3_nic_set_rx_mode(netdev);
hns3_recover_hw_addr(netdev);
/* Carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
ret = hns3_get_ring_config(priv);
if (ret)
return ret;
ret = hns3_nic_init_vector_data(priv);
if (ret)
return ret;
ret = hns3_init_all_ring(priv);
if (ret) {
hns3_nic_uninit_vector_data(priv);
priv->ring_data = NULL;
}
return ret;
}
static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
{
struct net_device *netdev = handle->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret;
hns3_clear_all_ring(handle);
ret = hns3_nic_uninit_vector_data(priv);
if (ret) {
netdev_err(netdev, "uninit vector error\n");
return ret;
}
ret = hns3_uninit_all_ring(priv);
if (ret)
netdev_err(netdev, "uninit ring error\n");
priv->ring_data = NULL;
return ret;
}
static int hns3_reset_notify(struct hnae3_handle *handle,
enum hnae3_reset_notify_type type)
{
int ret = 0;
switch (type) {
case HNAE3_UP_CLIENT:
ret = hns3_reset_notify_up_enet(handle);
break;
case HNAE3_DOWN_CLIENT:
ret = hns3_reset_notify_down_enet(handle);
break;
case HNAE3_INIT_CLIENT:
ret = hns3_reset_notify_init_enet(handle);
break;
case HNAE3_UNINIT_CLIENT:
ret = hns3_reset_notify_uninit_enet(handle);
break;
default:
break;
}
return ret;
}
static const struct hnae3_client_ops client_ops = { static const struct hnae3_client_ops client_ops = {
.init_instance = hns3_client_init, .init_instance = hns3_client_init,
.uninit_instance = hns3_client_uninit, .uninit_instance = hns3_client_uninit,
.link_status_change = hns3_link_status_change, .link_status_change = hns3_link_status_change,
.setup_tc = hns3_client_setup_tc, .setup_tc = hns3_client_setup_tc,
.reset_notify = hns3_reset_notify,
}; };
/* hns3_init_module - Driver registration routine /* hns3_init_module - Driver registration routine
......
...@@ -518,6 +518,8 @@ struct hns3_nic_priv { ...@@ -518,6 +518,8 @@ struct hns3_nic_priv {
/* The most recently read link state */ /* The most recently read link state */
int link; int link;
u64 tx_timeout_count; u64 tx_timeout_count;
enum hnae3_reset_type reset_level;
unsigned long last_reset_time;
unsigned long state; unsigned long state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment