/* hclgevf_cmd_send - send command to command queue * @hw: pointer to the hw struct * @desc: prefilled descriptor for describing the command * @num : the number of descriptors to be sent * * This is the main send command for command queue, it * sends the queue, cleans the queue, etc
*/ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclge_desc *desc, int num)
{ return hclge_comm_cmd_send(&hw->hw, desc, num);
}
staticvoid hclgevf_trace_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc, int num, bool is_special)
{ int i;
trace_hclge_vf_cmd_send(hw, desc, 0, num);
if (is_special) return;
for (i = 1; i < num; i++)
trace_hclge_vf_cmd_send(hw, &desc[i], i, num);
}
staticvoid hclgevf_trace_cmd_get(struct hclge_comm_hw *hw, struct hclge_desc *desc, int num, bool is_special)
{ int i;
if (!HCLGE_COMM_SEND_SYNC(le16_to_cpu(desc->flag))) return;
trace_hclge_vf_cmd_get(hw, desc, 0, num);
if (is_special) return;
for (i = 1; i < num; i++)
trace_hclge_vf_cmd_get(hw, &desc[i], i, num);
}
status = hclge_comm_tqps_update_stats(handle, &hdev->hw.hw); if (status)
dev_err(&hdev->pdev->dev, "VF update of TQPS stats fail, status = %d.\n",
status);
}
staticint hclgevf_get_sset_count(struct hnae3_handle *handle, int strset)
{ if (strset == ETH_SS_TEST) return -EOPNOTSUPP; elseif (strset == ETH_SS_STATS) return hclge_comm_tqps_get_sset_count(handle);
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_BASIC_INFO, 0);
status = hclgevf_send_mbx_msg(hdev, &send_msg, true, resp_msg, sizeof(resp_msg)); if (status) {
dev_err(&hdev->pdev->dev, "failed to get basic info from pf, ret = %d", status); return status;
}
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN,
HCLGE_MBX_GET_PORT_BASE_VLAN_STATE);
ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg, sizeof(u8)); if (ret) {
dev_err(&hdev->pdev->dev, "VF request to get port based vlan state failed %d",
ret); return ret;
}
struct hclge_mbx_vf_queue_info *queue_info;
u8 resp_msg[HCLGEVF_TQPS_RSS_INFO_LEN]; struct hclge_vf_to_pf_msg send_msg; int status;
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_QINFO, 0);
status = hclgevf_send_mbx_msg(hdev, &send_msg, true, resp_msg,
HCLGEVF_TQPS_RSS_INFO_LEN); if (status) {
dev_err(&hdev->pdev->dev, "VF request to get tqp info from PF failed %d",
status); return status;
}
struct hclge_mbx_vf_queue_depth *queue_depth;
u8 resp_msg[HCLGEVF_TQPS_DEPTH_INFO_LEN]; struct hclge_vf_to_pf_msg send_msg; int ret;
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_QDEPTH, 0);
ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, resp_msg,
HCLGEVF_TQPS_DEPTH_INFO_LEN); if (ret) {
dev_err(&hdev->pdev->dev, "VF request to get tqp depth info from PF failed %d",
ret); return ret;
}
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_MEDIA_TYPE, 0);
ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, resp_msg, sizeof(resp_msg)); if (ret) {
dev_err(&hdev->pdev->dev, "VF request to get the pf port media type failed %d",
ret); return ret;
}
/* need an extended offset to configure queues >= * HCLGEVF_TQP_MAX_SIZE_DEV_V2.
*/ if (i < HCLGEVF_TQP_MAX_SIZE_DEV_V2)
tqp->q.io_base = hdev->hw.hw.io_base +
HCLGEVF_TQP_REG_OFFSET +
i * HCLGEVF_TQP_REG_SIZE; else
tqp->q.io_base = hdev->hw.hw.io_base +
HCLGEVF_TQP_REG_OFFSET +
HCLGEVF_TQP_EXT_REG_OFFSET +
(i - HCLGEVF_TQP_MAX_SIZE_DEV_V2) *
HCLGEVF_TQP_REG_SIZE;
/* when device supports tx push and has device memory, * the queue can execute push mode or doorbell mode on * device memory.
*/ if (test_bit(HNAE3_DEV_SUPPORT_TX_PUSH_B, ae_dev->caps))
tqp->q.mem_base = hdev->hw.hw.mem_base +
HCLGEVF_TQP_MEM_OFFSET(hdev, i);
for (i = 0; i < kinfo->num_tqps; i++) {
hdev->htqp[i].q.handle = &hdev->nic;
hdev->htqp[i].q.tqp_index = i;
kinfo->tqp[i] = &hdev->htqp[i].q;
}
/* after init the max rss_size and tqps, adjust the default tqp numbers * and rss size with the actual vector numbers
*/
kinfo->num_tqps = min_t(u16, hdev->num_nic_msix - 1, kinfo->num_tqps);
kinfo->rss_size = min_t(u16, kinfo->num_tqps / num_tc,
kinfo->rss_size);
return 0;
}
staticvoid hclgevf_request_link_info(struct hclgevf_dev *hdev)
{ struct hclge_vf_to_pf_msg send_msg; int status;
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_LINK_STATUS, 0);
status = hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); if (status)
dev_err(&hdev->pdev->dev, "VF failed to fetch link status(%d) from PF", status);
}
if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) {
ret = hclge_comm_set_rss_hash_key(rss_cfg, &hdev->hw.hw, key,
hfunc); if (ret) return ret;
}
/* update the shadow RSS table with user specified qids */ for (i = 0; i < hdev->ae_dev->dev_specs.rss_ind_tbl_size; i++)
rss_cfg->rss_indirection_tbl[i] = indir[i];
/* update the hardware */ return hclge_comm_set_rss_indir_table(hdev->ae_dev, &hdev->hw.hw,
rss_cfg->rss_indirection_tbl);
}
if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return -EOPNOTSUPP;
ret = hclge_comm_set_rss_tuple(hdev->ae_dev, &hdev->hw.hw,
&hdev->rss_cfg, nfc); if (ret)
dev_err(&hdev->pdev->dev, "failed to set rss tuple, ret = %d.\n", ret);
staticint hclgevf_unmap_ring_from_vector( struct hnae3_handle *handle, int vector, struct hnae3_ring_chain_node *ring_chain)
{ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); int ret, vector_id;
if (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state)) return 0;
vector_id = hclgevf_get_vector_index(hdev, vector); if (vector_id < 0) {
dev_err(&handle->pdev->dev, "Get vector index fail. ret =%d\n", vector_id); return vector_id;
}
ret = hclgevf_bind_ring_to_vector(handle, false, vector_id, ring_chain); if (ret)
dev_err(&handle->pdev->dev, "Unmap ring from vector fail. vector=%d, ret =%d\n",
vector_id,
ret);
return ret;
}
staticint hclgevf_put_vector(struct hnae3_handle *handle, int vector)
{ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); int vector_id;
vector_id = hclgevf_get_vector_index(hdev, vector); if (vector_id < 0) {
dev_err(&handle->pdev->dev, "hclgevf_put_vector get vector index fail. ret =%d\n",
vector_id); return vector_id;
}
if (test_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state)) {
ret = hclgevf_set_promisc_mode(handle, en_uc_pmc, en_mc_pmc); if (!ret)
clear_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state);
}
}
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_MAC_ADDR, 0);
status = hclgevf_send_mbx_msg(hdev, &send_msg, true, host_mac,
ETH_ALEN); if (status) {
dev_err(&hdev->pdev->dev, "fail to get VF MAC from host %d", status); return status;
}
list = (mac_type == HCLGEVF_MAC_ADDR_UC) ?
&hdev->mac_table.uc_mac_list : &hdev->mac_table.mc_mac_list;
spin_lock_bh(&hdev->mac_table.mac_list_lock);
/* if the mac addr is already in the mac list, no need to add a new * one into it, just check the mac addr state, convert it to a new * state, or just remove it, or do nothing.
*/
mac_node = hclgevf_find_mac_node(list, addr); if (mac_node) {
hclgevf_update_mac_node(mac_node, state);
spin_unlock_bh(&hdev->mac_table.mac_list_lock); return 0;
} /* if this address is never added, unnecessary to delete */ if (state == HCLGEVF_MAC_TO_DEL) {
spin_unlock_bh(&hdev->mac_table.mac_list_lock); return -ENOENT;
}
list_for_each_entry_safe(mac_node, tmp, add_list, node) { /* if the mac address from tmp_add_list is not in the * uc/mc_mac_list, it means have received a TO_DEL request * during the time window of sending mac config request to PF * If mac_node state is ACTIVE, then change its state to TO_DEL, * then it will be removed at next time. If is TO_ADD, it means * send TO_ADD request failed, so just remove the mac node.
*/
new_node = hclgevf_find_mac_node(mac_list, mac_node->mac_addr); if (new_node) {
hclgevf_update_mac_node(new_node, mac_node->state);
list_del(&mac_node->node);
kfree(mac_node);
} elseif (mac_node->state == HCLGEVF_MAC_ACTIVE) {
mac_node->state = HCLGEVF_MAC_TO_DEL;
list_move_tail(&mac_node->node, mac_list);
} else {
list_del(&mac_node->node);
kfree(mac_node);
}
}
}
list_for_each_entry_safe(mac_node, tmp, del_list, node) {
new_node = hclgevf_find_mac_node(mac_list, mac_node->mac_addr); if (new_node) { /* If the mac addr is exist in the mac list, it means * received a new request TO_ADD during the time window * of sending mac addr configurrequest to PF, so just * change the mac state to ACTIVE.
*/
new_node->state = HCLGEVF_MAC_ACTIVE;
list_del(&mac_node->node);
kfree(mac_node);
} else {
list_move_tail(&mac_node->node, mac_list);
}
}
}
/* move the mac addr to the tmp_add_list and tmp_del_list, then * we can add/delete these mac addr outside the spin lock
*/
list = (mac_type == HCLGEVF_MAC_ADDR_UC) ?
&hdev->mac_table.uc_mac_list : &hdev->mac_table.mc_mac_list;
spin_lock_bh(&hdev->mac_table.mac_list_lock);
list_for_each_entry_safe(mac_node, tmp, list, node) { switch (mac_node->state) { case HCLGEVF_MAC_TO_DEL:
list_move_tail(&mac_node->node, &tmp_del_list); break; case HCLGEVF_MAC_TO_ADD:
new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); if (!new_node) goto stop_traverse;
/* delete first, in order to get max mac table space for adding */
hclgevf_config_mac_list(hdev, &tmp_del_list, mac_type);
hclgevf_config_mac_list(hdev, &tmp_add_list, mac_type);
/* if some mac addresses were added/deleted fail, move back to the * mac_list, and retry at next time.
*/
spin_lock_bh(&hdev->mac_table.mac_list_lock);
if (vlan_id > HCLGEVF_MAX_VLAN_ID) return -EINVAL;
if (proto != htons(ETH_P_8021Q)) return -EPROTONOSUPPORT;
/* When device is resetting or reset failed, firmware is unable to * handle mailbox. Just record the vlan id, and remove it after * reset finished.
*/ if ((test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state) ||
test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state)) && is_kill) {
set_bit(vlan_id, hdev->vlan_del_fail_bmap); return -EBUSY;
} elseif (!is_kill && test_bit(vlan_id, hdev->vlan_del_fail_bmap)) {
clear_bit(vlan_id, hdev->vlan_del_fail_bmap);
}
/* when remove hw vlan filter failed, record the vlan id, * and try to remove it from hw later, to be consistence * with stack.
*/
ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0); if (is_kill && ret)
set_bit(vlan_id, hdev->vlan_del_fail_bmap);
if (!test_bit(HCLGEVF_STATE_ROCE_REGISTERED, &hdev->state) || !client) return 0;
if (!client->ops->reset_notify) return -EOPNOTSUPP;
ret = client->ops->reset_notify(handle, type); if (ret)
dev_err(&hdev->pdev->dev, "notify roce client failed %d(%d)",
type, ret); return ret;
}
staticvoid hclgevf_set_reset_pending(struct hclgevf_dev *hdev, enum hnae3_reset_type reset_type)
{ /* When an incorrect reset type is executed, the get_reset_level * function generates the HNAE3_NONE_RESET flag. As a result, this * type do not need to pending.
*/ if (reset_type != HNAE3_NONE_RESET)
set_bit(reset_type, &hdev->reset_pending);
}
if (hdev->reset_type == HNAE3_VF_RESET)
ret = readl_poll_timeout(hdev->hw.hw.io_base +
HCLGEVF_VF_RST_ING, val,
!(val & HCLGEVF_VF_RST_ING_BIT),
HCLGEVF_RESET_WAIT_US,
HCLGEVF_RESET_WAIT_TIMEOUT_US); else
ret = readl_poll_timeout(hdev->hw.hw.io_base +
HCLGEVF_RST_ING, val,
!(val & HCLGEVF_RST_ING_BITS),
HCLGEVF_RESET_WAIT_US,
HCLGEVF_RESET_WAIT_TIMEOUT_US);
/* hardware completion status should be available by this time */ if (ret) {
dev_err(&hdev->pdev->dev, "couldn't get reset done status from h/w, timeout!\n"); return ret;
}
/* we will wait a bit more to let reset of the stack to complete. This * might happen in case reset assertion was made by PF. Yes, this also * means we might end up waiting bit more even for VF reset.
*/ if (hdev->reset_type == HNAE3_VF_FULL_RESET)
msleep(5000); else
msleep(500);
staticint hclgevf_reset_prepare(struct hclgevf_dev *hdev)
{ int ret;
hdev->rst_stats.rst_cnt++;
/* perform reset of the stack & ae device for a client */
ret = hclgevf_notify_roce_client(hdev, HNAE3_DOWN_CLIENT); if (ret) return ret;
rtnl_lock(); /* bring down the nic to stop any ongoing TX/RX */
ret = hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT);
rtnl_unlock(); if (ret) return ret;
return hclgevf_reset_prepare_wait(hdev);
}
staticint hclgevf_reset_rebuild(struct hclgevf_dev *hdev)
{ int ret;
hdev->rst_stats.hw_rst_done_cnt++;
ret = hclgevf_notify_roce_client(hdev, HNAE3_UNINIT_CLIENT); if (ret) return ret;
rtnl_lock(); /* now, re-initialize the nic client and ae device */
ret = hclgevf_reset_stack(hdev);
rtnl_unlock(); if (ret) {
dev_err(&hdev->pdev->dev, "failed to reset VF stack\n"); return ret;
}
ret = hclgevf_notify_roce_client(hdev, HNAE3_INIT_CLIENT); /* ignore RoCE notify error if it fails HCLGEVF_RESET_MAX_FAIL_CNT - 1 * times
*/ if (ret &&
hdev->rst_stats.rst_fail_cnt < HCLGEVF_RESET_MAX_FAIL_CNT - 1) return ret;
ret = hclgevf_notify_roce_client(hdev, HNAE3_UP_CLIENT); if (ret) return ret;
staticvoid hclgevf_reset(struct hclgevf_dev *hdev)
{ if (hclgevf_reset_prepare(hdev)) goto err_reset;
/* check if VF could successfully fetch the hardware reset completion * status from the hardware
*/ if (hclgevf_reset_wait(hdev)) { /* can't do much in this situation, will disable VF */
dev_err(&hdev->pdev->dev, "failed to fetch H/W reset completion status\n"); goto err_reset;
}
if (test_and_clear_bit(HCLGEVF_RESET_PENDING,
&hdev->reset_state)) { /* PF has intimated that it is about to reset the hardware. * We now have to poll & check if hardware has actually * completed the reset sequence. On hardware reset completion, * VF needs to reset the client and ae device.
*/
hdev->reset_attempts = 0;
hdev->last_reset_time = jiffies;
hdev->reset_type =
hclgevf_get_reset_level(&hdev->reset_pending); if (hdev->reset_type != HNAE3_NONE_RESET)
hclgevf_reset(hdev);
} elseif (test_and_clear_bit(HCLGEVF_RESET_REQUESTED,
&hdev->reset_state)) { /* we could be here when either of below happens: * 1. reset was initiated due to watchdog timeout caused by * a. IMP was earlier reset and our TX got choked down and * which resulted in watchdog reacting and inducing VF * reset. This also means our cmdq would be unreliable. * b. problem in TX due to other lower layer(example link * layer not functioning properly etc.) * 2. VF reset might have been initiated due to some config * change. * * NOTE: Theres no clear way to detect above cases than to react * to the response of PF for this reset request. PF will ack the * 1b and 2. cases but we will not get any intimation about 1a * from PF as cmdq would be in unreliable state i.e. mailbox * communication between PF and VF would be broken. * * if we are never geting into pending state it means either: * 1. PF is not receiving our request which could be due to IMP * reset * 2. PF is screwed * We cannot do much for 2. but to check first we can try reset * our PCIe + stack and see if it alleviates the problem.
*/ if (hdev->reset_attempts > HCLGEVF_MAX_RESET_ATTEMPTS_CNT) { /* prepare for full reset of stack + pcie interface */
hclgevf_set_reset_pending(hdev, HNAE3_VF_FULL_RESET);
/* "defer" schedule the reset task again */
set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
} else {
hdev->reset_attempts++;
hdev->serv_processed_cnt++; if (!(hdev->serv_processed_cnt % HCLGEVF_KEEP_ALIVE_TASK_INTERVAL))
hclgevf_keep_alive(hdev);
if (test_bit(HCLGEVF_STATE_DOWN, &hdev->state)) {
hdev->last_serv_processed = jiffies; goto out;
}
if (!(hdev->serv_processed_cnt % HCLGEVF_STATS_TIMER_INTERVAL))
hclge_comm_tqps_update_stats(handle, &hdev->hw.hw);
/* VF does not need to request link status when this bit is set, because * PF will push its link status to VFs when link status changed.
*/ if (!test_bit(HCLGEVF_STATE_PF_PUSH_LINK_STATUS, &hdev->state))
hclgevf_request_link_info(hdev);
/* Handle reset and mbx again in case periodical task delays the * handling by calling hclgevf_task_schedule() in * hclgevf_periodic_service_task()
*/
hclgevf_reset_service_task(hdev);
hclgevf_mailbox_service_task(hdev);
}
/* fetch the events from their corresponding regs */
cmdq_stat_reg = hclgevf_read_dev(&hdev->hw,
HCLGE_COMM_VECTOR0_CMDQ_STATE_REG); if (BIT(HCLGEVF_VECTOR0_RST_INT_B) & cmdq_stat_reg) {
rst_ing_reg = hclgevf_read_dev(&hdev->hw, HCLGEVF_RST_ING);
dev_info(&hdev->pdev->dev, "receive reset interrupt 0x%x!\n", rst_ing_reg);
hclgevf_set_reset_pending(hdev, HNAE3_VF_RESET);
set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state);
*clearval = ~(1U << HCLGEVF_VECTOR0_RST_INT_B);
hdev->rst_stats.vf_rst_cnt++; /* set up VF hardware reset status, its PF will clear * this status when PF has initialized done.
*/
val = hclgevf_read_dev(&hdev->hw, HCLGEVF_VF_RST_ING);
hclgevf_write_dev(&hdev->hw, HCLGEVF_VF_RST_ING,
val | HCLGEVF_VF_RST_ING_BIT); return HCLGEVF_VECTOR0_EVENT_RST;
}
/* check for vector0 mailbox(=CMDQ RX) event source */ if (BIT(HCLGEVF_VECTOR0_RX_CMDQ_INT_B) & cmdq_stat_reg) { /* for revision 0x21, clearing interrupt is writing bit 0 * to the clear register, writing bit 1 means to keep the * old value. * for revision 0x20, the clear register is a read & write * register, so we should just write 0 to the bit we are * handling, and keep other bits as cmdq_stat_reg.
*/ if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2)
*clearval = ~(1U << HCLGEVF_VECTOR0_RX_CMDQ_INT_B); else
*clearval = cmdq_stat_reg &
~BIT(HCLGEVF_VECTOR0_RX_CMDQ_INT_B);
return HCLGEVF_VECTOR0_EVENT_MBX;
}
/* print other vector0 event source */
dev_info(&hdev->pdev->dev, "vector 0 interrupt from unknown source, cmdq_src = %#x\n",
cmdq_stat_reg);
if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) {
ret = hclge_comm_set_rss_algo_key(&hdev->hw.hw,
rss_cfg->rss_algo,
rss_cfg->rss_hash_key); if (ret) return ret;
ret = hclge_comm_set_rss_input_tuple(&hdev->hw.hw, rss_cfg); if (ret) return ret;
}
ret = hclge_comm_set_rss_indir_table(hdev->ae_dev, &hdev->hw.hw,
rss_cfg->rss_indirection_tbl); if (ret) return ret;
INIT_DELAYED_WORK(&hdev->service_task, hclgevf_service_task); /* timer needs to be initialized before misc irq */
timer_setup(&hdev->reset_timer, hclgevf_reset_timer, 0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.