Commit 6686c459 authored by David S. Miller's avatar David S. Miller

Merge branch 'hns3-VF-reset'

Salil Mehta says:

====================
Add support of VF Reset to HNS3 VF driver

This patch-set adds the support of VF reset to the existing VF driver.
VF Reset can be triggered due to TX watchdog firing  as a result of TX
data-path not working. VF reset could also be a result of some internal
configuration changes if that requires reset, or as a result of the
PF/Core/Global/IMP(Integrated Management Processor) reset happened in
the PF.

Summary of Patches:
* Watchdog timer trigger chnages are present in Patch 1.
* Reset Service Task and related Event handling is present in Patches {2,3}
* Changes to send reset request to PF, reset stack and re-initialization
  of the hclge device is present in Patches {4,5,6}
* Changes related to ARQ (Asynchronous Receive Queue) and its event handling
  are present in Patches {7,8}
* Changes required in PF to handle the VF Reset request and actually perform
  hardware VF reset is there in Patch 9.

NOTE: This patch depends upon "[PATCH net-next 00/11] fix some bugs for HNS3 driver"
	Link: https://lkml.org/lkml/2018/3/21/72
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a2e10a2 2bfbd35d
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
enum HCLGE_MBX_OPCODE { enum HCLGE_MBX_OPCODE {
HCLGE_MBX_RESET = 0x01, /* (VF -> PF) assert reset */ HCLGE_MBX_RESET = 0x01, /* (VF -> PF) assert reset */
HCLGE_MBX_ASSERTING_RESET, /* (PF -> VF) PF is asserting reset*/
HCLGE_MBX_SET_UNICAST, /* (VF -> PF) set UC addr */ HCLGE_MBX_SET_UNICAST, /* (VF -> PF) set UC addr */
HCLGE_MBX_SET_MULTICAST, /* (VF -> PF) set MC addr */ HCLGE_MBX_SET_MULTICAST, /* (VF -> PF) set MC addr */
HCLGE_MBX_SET_VLAN, /* (VF -> PF) set VLAN */ HCLGE_MBX_SET_VLAN, /* (VF -> PF) set VLAN */
...@@ -85,6 +86,21 @@ struct hclge_mbx_pf_to_vf_cmd { ...@@ -85,6 +86,21 @@ struct hclge_mbx_pf_to_vf_cmd {
u16 msg[8]; u16 msg[8];
}; };
/* used by VF to store the received Async responses from PF */
struct hclgevf_mbx_arq_ring {
#define HCLGE_MBX_MAX_ARQ_MSG_SIZE 8
#define HCLGE_MBX_MAX_ARQ_MSG_NUM 1024
struct hclgevf_dev *hdev;
u32 head;
u32 tail;
u32 count;
u16 msg_q[HCLGE_MBX_MAX_ARQ_MSG_NUM][HCLGE_MBX_MAX_ARQ_MSG_SIZE];
};
#define hclge_mbx_ring_ptr_move_crq(crq) \ #define hclge_mbx_ring_ptr_move_crq(crq) \
(crq->next_to_use = (crq->next_to_use + 1) % crq->desc_num) (crq->next_to_use = (crq->next_to_use + 1) % crq->desc_num)
#define hclge_mbx_tail_ptr_move_arq(arq) \
(arq.tail = (arq.tail + 1) % HCLGE_MBX_MAX_ARQ_MSG_SIZE)
#define hclge_mbx_head_ptr_move_arq(arq) \
(arq.head = (arq.head + 1) % HCLGE_MBX_MAX_ARQ_MSG_SIZE)
#endif #endif
...@@ -118,6 +118,8 @@ enum hnae3_reset_notify_type { ...@@ -118,6 +118,8 @@ enum hnae3_reset_notify_type {
}; };
enum hnae3_reset_type { enum hnae3_reset_type {
HNAE3_VF_RESET,
HNAE3_VF_FULL_RESET,
HNAE3_FUNC_RESET, HNAE3_FUNC_RESET,
HNAE3_CORE_RESET, HNAE3_CORE_RESET,
HNAE3_GLOBAL_RESET, HNAE3_GLOBAL_RESET,
...@@ -400,8 +402,7 @@ struct hnae3_ae_ops { ...@@ -400,8 +402,7 @@ struct hnae3_ae_ops {
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);
int (*enable_hw_strip_rxvtag)(struct hnae3_handle *handle, bool enable); int (*enable_hw_strip_rxvtag)(struct hnae3_handle *handle, bool enable);
void (*reset_event)(struct hnae3_handle *handle, void (*reset_event)(struct hnae3_handle *handle);
enum hnae3_reset_type reset);
void (*get_channels)(struct hnae3_handle *handle, void (*get_channels)(struct hnae3_handle *handle,
struct ethtool_channels *ch); struct ethtool_channels *ch);
void (*get_tqps_and_rss_info)(struct hnae3_handle *h, void (*get_tqps_and_rss_info)(struct hnae3_handle *h,
...@@ -495,6 +496,9 @@ struct hnae3_handle { ...@@ -495,6 +496,9 @@ struct hnae3_handle {
struct hnae3_ae_algo *ae_algo; /* the class who provides this handle */ struct hnae3_ae_algo *ae_algo; /* the class who provides this handle */
u64 flags; /* Indicate the capabilities for this handle*/ u64 flags; /* Indicate the capabilities for this handle*/
unsigned long last_reset_time;
enum hnae3_reset_type reset_level;
union { union {
struct net_device *netdev; /* first member */ struct net_device *netdev; /* first member */
struct hnae3_knic_private_info kinfo; struct hnae3_knic_private_info kinfo;
......
...@@ -320,7 +320,7 @@ static int hns3_nic_net_open(struct net_device *netdev) ...@@ -320,7 +320,7 @@ static int hns3_nic_net_open(struct net_device *netdev)
return ret; return ret;
} }
priv->last_reset_time = jiffies; priv->ae_handle->last_reset_time = jiffies;
return 0; return 0;
} }
...@@ -1543,7 +1543,6 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev) ...@@ -1543,7 +1543,6 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev)
static void hns3_nic_net_timeout(struct net_device *ndev) static void hns3_nic_net_timeout(struct net_device *ndev)
{ {
struct hns3_nic_priv *priv = netdev_priv(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; struct hnae3_handle *h = priv->ae_handle;
if (!hns3_get_tx_timeo_queue_info(ndev)) if (!hns3_get_tx_timeo_queue_info(ndev))
...@@ -1551,24 +1550,12 @@ static void hns3_nic_net_timeout(struct net_device *ndev) ...@@ -1551,24 +1550,12 @@ static void hns3_nic_net_timeout(struct net_device *ndev)
priv->tx_timeout_count++; priv->tx_timeout_count++;
/* This timeout is far away enough from last timeout, if (time_before(jiffies, (h->last_reset_time + ndev->watchdog_timeo)))
* 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; return;
priv->last_reset_time = jiffies; /* request the reset */
if (h->ae_algo->ops->reset_event) if (h->ae_algo->ops->reset_event)
h->ae_algo->ops->reset_event(h, priv->reset_level); h->ae_algo->ops->reset_event(h);
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 = {
...@@ -3122,8 +3109,8 @@ static int hns3_client_init(struct hnae3_handle *handle) ...@@ -3122,8 +3109,8 @@ 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->ae_handle->reset_level = HNAE3_NONE_RESET;
priv->reset_level = HNAE3_FUNC_RESET; priv->ae_handle->last_reset_time = jiffies;
priv->tx_timeout_count = 0; priv->tx_timeout_count = 0;
handle->kinfo.netdev = netdev; handle->kinfo.netdev = netdev;
...@@ -3355,7 +3342,6 @@ static int hns3_reset_notify_down_enet(struct hnae3_handle *handle) ...@@ -3355,7 +3342,6 @@ static int hns3_reset_notify_down_enet(struct hnae3_handle *handle)
static int hns3_reset_notify_up_enet(struct hnae3_handle *handle) static int hns3_reset_notify_up_enet(struct hnae3_handle *handle)
{ {
struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hns3_nic_priv *priv = netdev_priv(kinfo->netdev);
int ret = 0; int ret = 0;
if (netif_running(kinfo->netdev)) { if (netif_running(kinfo->netdev)) {
...@@ -3365,8 +3351,7 @@ static int hns3_reset_notify_up_enet(struct hnae3_handle *handle) ...@@ -3365,8 +3351,7 @@ static int hns3_reset_notify_up_enet(struct hnae3_handle *handle)
"hns net up fail, ret=%d!\n", ret); "hns net up fail, ret=%d!\n", ret);
return ret; return ret;
} }
handle->last_reset_time = jiffies;
priv->last_reset_time = jiffies;
} }
return ret; return ret;
...@@ -3378,7 +3363,6 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) ...@@ -3378,7 +3363,6 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
struct hns3_nic_priv *priv = netdev_priv(netdev); struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret; int ret;
priv->reset_level = 1;
hns3_init_mac_addr(netdev); hns3_init_mac_addr(netdev);
hns3_nic_set_rx_mode(netdev); hns3_nic_set_rx_mode(netdev);
hns3_recover_hw_addr(netdev); hns3_recover_hw_addr(netdev);
......
...@@ -532,8 +532,6 @@ struct hns3_nic_priv { ...@@ -532,8 +532,6 @@ 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;
......
...@@ -2749,7 +2749,7 @@ static int hclge_reset_wait(struct hclge_dev *hdev) ...@@ -2749,7 +2749,7 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
return 0; return 0;
} }
static int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id) int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id)
{ {
struct hclge_desc desc; struct hclge_desc desc;
struct hclge_reset_cmd *req = (struct hclge_reset_cmd *)desc.data; struct hclge_reset_cmd *req = (struct hclge_reset_cmd *)desc.data;
...@@ -2845,27 +2845,31 @@ static void hclge_reset(struct hclge_dev *hdev) ...@@ -2845,27 +2845,31 @@ static void hclge_reset(struct hclge_dev *hdev)
hclge_notify_client(hdev, HNAE3_UP_CLIENT); hclge_notify_client(hdev, HNAE3_UP_CLIENT);
} }
static void hclge_reset_event(struct hnae3_handle *handle, static void hclge_reset_event(struct hnae3_handle *handle)
enum hnae3_reset_type reset)
{ {
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
dev_info(&hdev->pdev->dev, /* check if this is a new reset request and we are not here just because
"Receive reset event , reset_type is %d", reset); * last reset attempt did not succeed and watchdog hit us again. We will
* know this if last reset request did not occur very recently (watchdog
* timer = 5*HZ, let us check after sufficiently large time, say 4*5*Hz)
* In case of new request we reset the "reset level" to PF reset.
*/
if (time_after(jiffies, (handle->last_reset_time + 4 * 5 * HZ)))
handle->reset_level = HNAE3_FUNC_RESET;
switch (reset) { dev_info(&hdev->pdev->dev, "received reset event , reset type is %d",
case HNAE3_FUNC_RESET: handle->reset_level);
case HNAE3_CORE_RESET:
case HNAE3_GLOBAL_RESET: /* request reset & schedule reset task */
/* request reset & schedule reset task */ set_bit(handle->reset_level, &hdev->reset_request);
set_bit(reset, &hdev->reset_request); hclge_reset_task_schedule(hdev);
hclge_reset_task_schedule(hdev);
break; if (handle->reset_level < HNAE3_GLOBAL_RESET)
default: handle->reset_level++;
dev_warn(&hdev->pdev->dev, "Unsupported reset event:%d", reset);
break; handle->last_reset_time = jiffies;
}
} }
static void hclge_reset_subtask(struct hclge_dev *hdev) static void hclge_reset_subtask(struct hclge_dev *hdev)
......
...@@ -657,4 +657,5 @@ void hclge_mbx_handler(struct hclge_dev *hdev); ...@@ -657,4 +657,5 @@ void hclge_mbx_handler(struct hclge_dev *hdev);
void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id); void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id);
void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id); void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id);
int hclge_cfg_flowctrl(struct hclge_dev *hdev); int hclge_cfg_flowctrl(struct hclge_dev *hdev);
int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id);
#endif #endif
...@@ -79,6 +79,18 @@ static int hclge_send_mbx_msg(struct hclge_vport *vport, u8 *msg, u16 msg_len, ...@@ -79,6 +79,18 @@ static int hclge_send_mbx_msg(struct hclge_vport *vport, u8 *msg, u16 msg_len,
return status; return status;
} }
int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport)
{
u8 msg_data[2];
u8 dest_vfid;
dest_vfid = (u8)vport->vport_id;
/* send this requested info to VF */
return hclge_send_mbx_msg(vport, msg_data, sizeof(u8),
HCLGE_MBX_ASSERTING_RESET, dest_vfid);
}
static void hclge_free_vector_ring_chain(struct hnae3_ring_chain_node *head) static void hclge_free_vector_ring_chain(struct hnae3_ring_chain_node *head)
{ {
struct hnae3_ring_chain_node *chain_tmp, *chain; struct hnae3_ring_chain_node *chain_tmp, *chain;
...@@ -339,6 +351,33 @@ static void hclge_mbx_reset_vf_queue(struct hclge_vport *vport, ...@@ -339,6 +351,33 @@ static void hclge_mbx_reset_vf_queue(struct hclge_vport *vport,
hclge_gen_resp_to_vf(vport, mbx_req, 0, NULL, 0); hclge_gen_resp_to_vf(vport, mbx_req, 0, NULL, 0);
} }
static void hclge_reset_vf(struct hclge_vport *vport,
struct hclge_mbx_vf_to_pf_cmd *mbx_req)
{
struct hclge_dev *hdev = vport->back;
int ret;
dev_warn(&hdev->pdev->dev, "PF received VF reset request from VF %d!",
mbx_req->mbx_src_vfid);
/* Acknowledge VF that PF is now about to assert the reset for the VF.
* On receiving this message VF will get into pending state and will
* start polling for the hardware reset completion status.
*/
ret = hclge_inform_reset_assert_to_vf(vport);
if (ret) {
dev_err(&hdev->pdev->dev,
"PF fail(%d) to inform VF(%d)of reset, reset failed!\n",
ret, vport->vport_id);
return;
}
dev_warn(&hdev->pdev->dev, "PF is now resetting VF %d.\n",
mbx_req->mbx_src_vfid);
/* reset this virtual function */
hclge_func_reset_cmd(hdev, mbx_req->mbx_src_vfid);
}
void hclge_mbx_handler(struct hclge_dev *hdev) void hclge_mbx_handler(struct hclge_dev *hdev)
{ {
struct hclge_cmq_ring *crq = &hdev->hw.cmq.crq; struct hclge_cmq_ring *crq = &hdev->hw.cmq.crq;
...@@ -416,6 +455,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev) ...@@ -416,6 +455,9 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
case HCLGE_MBX_QUEUE_RESET: case HCLGE_MBX_QUEUE_RESET:
hclge_mbx_reset_vf_queue(vport, req); hclge_mbx_reset_vf_queue(vport, req);
break; break;
case HCLGE_MBX_RESET:
hclge_reset_vf(vport, req);
break;
default: default:
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"un-supported mailbox message, code = %d\n", "un-supported mailbox message, code = %d\n",
......
...@@ -315,6 +315,12 @@ int hclgevf_cmd_init(struct hclgevf_dev *hdev) ...@@ -315,6 +315,12 @@ int hclgevf_cmd_init(struct hclgevf_dev *hdev)
goto err_csq; goto err_csq;
} }
/* initialize the pointers of async rx queue of mailbox */
hdev->arq.hdev = hdev;
hdev->arq.head = 0;
hdev->arq.tail = 0;
hdev->arq.count = 0;
/* get firmware version */ /* get firmware version */
ret = hclgevf_cmd_query_firmware_version(&hdev->hw, &version); ret = hclgevf_cmd_query_firmware_version(&hdev->hw, &version);
if (ret) { if (ret) {
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
#define HCLGEVF_VECTOR0_RX_CMDQ_INT_B 1 #define HCLGEVF_VECTOR0_RX_CMDQ_INT_B 1
#define HCLGEVF_TQP_RESET_TRY_TIMES 10 #define HCLGEVF_TQP_RESET_TRY_TIMES 10
/* Reset related Registers */
#define HCLGEVF_FUN_RST_ING 0x20C00
#define HCLGEVF_FUN_RST_ING_B 0
#define HCLGEVF_RSS_IND_TBL_SIZE 512 #define HCLGEVF_RSS_IND_TBL_SIZE 512
#define HCLGEVF_RSS_SET_BITMAP_MSK 0xffff #define HCLGEVF_RSS_SET_BITMAP_MSK 0xffff
...@@ -52,6 +55,8 @@ enum hclgevf_states { ...@@ -52,6 +55,8 @@ enum hclgevf_states {
HCLGEVF_STATE_DISABLED, HCLGEVF_STATE_DISABLED,
/* task states */ /* task states */
HCLGEVF_STATE_SERVICE_SCHED, HCLGEVF_STATE_SERVICE_SCHED,
HCLGEVF_STATE_RST_SERVICE_SCHED,
HCLGEVF_STATE_RST_HANDLING,
HCLGEVF_STATE_MBX_SERVICE_SCHED, HCLGEVF_STATE_MBX_SERVICE_SCHED,
HCLGEVF_STATE_MBX_HANDLING, HCLGEVF_STATE_MBX_HANDLING,
}; };
...@@ -122,6 +127,11 @@ struct hclgevf_dev { ...@@ -122,6 +127,11 @@ struct hclgevf_dev {
struct hclgevf_rss_cfg rss_cfg; struct hclgevf_rss_cfg rss_cfg;
unsigned long state; unsigned long state;
#define HCLGEVF_RESET_REQUESTED 0
#define HCLGEVF_RESET_PENDING 1
unsigned long reset_state; /* requested, pending */
u32 reset_attempts;
u32 fw_version; u32 fw_version;
u16 num_tqps; /* num task queue pairs of this PF */ u16 num_tqps; /* num task queue pairs of this PF */
...@@ -142,10 +152,13 @@ struct hclgevf_dev { ...@@ -142,10 +152,13 @@ struct hclgevf_dev {
int *vector_irq; int *vector_irq;
bool accept_mta_mc; /* whether to accept mta filter multicast */ bool accept_mta_mc; /* whether to accept mta filter multicast */
bool mbx_event_pending;
struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */ struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */
struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */
struct timer_list service_timer; struct timer_list service_timer;
struct work_struct service_task; struct work_struct service_task;
struct work_struct rst_service_task;
struct work_struct mbx_service_task; struct work_struct mbx_service_task;
struct hclgevf_tqp *htqp; struct hclgevf_tqp *htqp;
...@@ -158,11 +171,29 @@ struct hclgevf_dev { ...@@ -158,11 +171,29 @@ struct hclgevf_dev {
u32 flag; u32 flag;
}; };
static inline bool hclgevf_dev_ongoing_reset(struct hclgevf_dev *hdev)
{
return (hdev &&
(test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state)) &&
(hdev->nic.reset_level == HNAE3_VF_RESET));
}
static inline bool hclgevf_dev_ongoing_full_reset(struct hclgevf_dev *hdev)
{
return (hdev &&
(test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state)) &&
(hdev->nic.reset_level == HNAE3_VF_FULL_RESET));
}
int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev, u16 code, u16 subcode, int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev, u16 code, u16 subcode,
const u8 *msg_data, u8 msg_len, bool need_resp, const u8 *msg_data, u8 msg_len, bool need_resp,
u8 *resp_data, u16 resp_len); u8 *resp_data, u16 resp_len);
void hclgevf_mbx_handler(struct hclgevf_dev *hdev); void hclgevf_mbx_handler(struct hclgevf_dev *hdev);
void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev);
void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state); void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state);
void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed, void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed,
u8 duplex); u8 duplex);
void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev);
void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev);
#endif #endif
...@@ -132,9 +132,8 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) ...@@ -132,9 +132,8 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
struct hclge_mbx_pf_to_vf_cmd *req; struct hclge_mbx_pf_to_vf_cmd *req;
struct hclgevf_cmq_ring *crq; struct hclgevf_cmq_ring *crq;
struct hclgevf_desc *desc; struct hclgevf_desc *desc;
u16 link_status, flag; u16 *msg_q;
u32 speed; u16 flag;
u8 duplex;
u8 *temp; u8 *temp;
int i; int i;
...@@ -146,6 +145,12 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) ...@@ -146,6 +145,12 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
desc = &crq->desc[crq->next_to_use]; desc = &crq->desc[crq->next_to_use];
req = (struct hclge_mbx_pf_to_vf_cmd *)desc->data; req = (struct hclge_mbx_pf_to_vf_cmd *)desc->data;
/* synchronous messages are time critical and need preferential
* treatment. Therefore, we need to acknowledge all the sync
* responses as quickly as possible so that waiting tasks do not
* timeout and simultaneously queue the async messages for later
* prcessing in context of mailbox task i.e. the slow path.
*/
switch (req->msg[0]) { switch (req->msg[0]) {
case HCLGE_MBX_PF_VF_RESP: case HCLGE_MBX_PF_VF_RESP:
if (resp->received_resp) if (resp->received_resp)
...@@ -165,13 +170,31 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) ...@@ -165,13 +170,31 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
} }
break; break;
case HCLGE_MBX_LINK_STAT_CHANGE: case HCLGE_MBX_LINK_STAT_CHANGE:
link_status = le16_to_cpu(req->msg[1]); case HCLGE_MBX_ASSERTING_RESET:
memcpy(&speed, &req->msg[2], sizeof(speed)); /* set this mbx event as pending. This is required as we
duplex = (u8)le16_to_cpu(req->msg[4]); * might loose interrupt event when mbx task is busy
* handling. This shall be cleared when mbx task just
* enters handling state.
*/
hdev->mbx_event_pending = true;
/* update upper layer with new link link status */ /* we will drop the async msg if we find ARQ as full
hclgevf_update_link_status(hdev, link_status); * and continue with next message
hclgevf_update_speed_duplex(hdev, speed, duplex); */
if (hdev->arq.count >= HCLGE_MBX_MAX_ARQ_MSG_NUM) {
dev_warn(&hdev->pdev->dev,
"Async Q full, dropping msg(%d)\n",
req->msg[1]);
break;
}
/* tail the async message in arq */
msg_q = hdev->arq.msg_q[hdev->arq.tail];
memcpy(&msg_q[0], req->msg, HCLGE_MBX_MAX_ARQ_MSG_SIZE);
hclge_mbx_tail_ptr_move_arq(hdev->arq);
hdev->arq.count++;
hclgevf_mbx_task_schedule(hdev);
break; break;
default: default:
...@@ -189,3 +212,57 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) ...@@ -189,3 +212,57 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CRQ_HEAD_REG, hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CRQ_HEAD_REG,
crq->next_to_use); crq->next_to_use);
} }
void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
{
u16 link_status;
u16 *msg_q;
u8 duplex;
u32 speed;
u32 tail;
/* we can safely clear it now as we are at start of the async message
* processing
*/
hdev->mbx_event_pending = false;
tail = hdev->arq.tail;
/* process all the async queue messages */
while (tail != hdev->arq.head) {
msg_q = hdev->arq.msg_q[hdev->arq.head];
switch (msg_q[0]) {
case HCLGE_MBX_LINK_STAT_CHANGE:
link_status = le16_to_cpu(msg_q[1]);
memcpy(&speed, &msg_q[2], sizeof(speed));
duplex = (u8)le16_to_cpu(msg_q[4]);
/* update upper layer with new link link status */
hclgevf_update_link_status(hdev, link_status);
hclgevf_update_speed_duplex(hdev, speed, duplex);
break;
case HCLGE_MBX_ASSERTING_RESET:
/* PF has asserted reset hence VF should go in pending
* state and poll for the hardware reset status till it
* has been completely reset. After this stack should
* eventually be re-initialized.
*/
hdev->nic.reset_level = HNAE3_VF_RESET;
set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
hclgevf_reset_task_schedule(hdev);
break;
default:
dev_err(&hdev->pdev->dev,
"fetched unsupported(%d) message from arq\n",
msg_q[0]);
break;
}
hclge_mbx_head_ptr_move_arq(hdev->arq);
hdev->arq.count--;
msg_q = hdev->arq.msg_q[hdev->arq.head];
}
}
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