/* 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);
dev_info(dev, "Task queue pairs numbers: %u\n", hdev->num_tqps);
dev_info(dev, "Desc num per TX queue: %u\n", hdev->num_tx_desc);
dev_info(dev, "Desc num per RX queue: %u\n", hdev->num_rx_desc);
dev_info(dev, "Numbers of vports: %u\n", hdev->num_alloc_vport);
dev_info(dev, "HW tc map: 0x%x\n", hdev->hw_tc_map);
dev_info(dev, "PF media type of this VF: %u\n",
hdev->hw.mac.media_type);
/* un-init roce, if it exists */ if (hdev->roce_client) { while (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state))
msleep(HCLGEVF_WAIT_RESET_DONE);
clear_bit(HCLGEVF_STATE_ROCE_REGISTERED, &hdev->state);
/* un-init nic/unic, if this was not called by roce client */ if (client->ops->uninit_instance && hdev->nic_client &&
client->type != HNAE3_CLIENT_ROCE) { while (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state))
msleep(HCLGEVF_WAIT_RESET_DONE);
clear_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state);
/* nic's msix numbers is always equals to the roce's. */
hdev->num_nic_msix = hdev->num_roce_msix;
/* VF should have NIC vectors and Roce vectors, NIC vectors * are queued before Roce vectors. The offset is fixed to 64.
*/
hdev->num_msi = hdev->num_roce_msix +
hdev->roce_base_msix_offset;
} else {
hdev->num_msi =
hnae3_get_field(le16_to_cpu(req->vf_intr_vector_number),
HCLGEVF_VEC_NUM_M, HCLGEVF_VEC_NUM_S);
hdev->num_nic_msix = hdev->num_msi;
}
if (hdev->num_nic_msix < HNAE3_MIN_VECTOR_NUM) {
dev_err(&hdev->pdev->dev, "Just %u msi resources, not enough for vf(min:2).\n",
hdev->num_nic_msix); return -EINVAL;
}
if (!dev_specs->max_non_tso_bd_num)
dev_specs->max_non_tso_bd_num = HCLGEVF_MAX_NON_TSO_BD_NUM; if (!dev_specs->rss_ind_tbl_size)
dev_specs->rss_ind_tbl_size = HCLGEVF_RSS_IND_TBL_SIZE; if (!dev_specs->rss_key_size)
dev_specs->rss_key_size = HCLGE_COMM_RSS_KEY_SIZE; if (!dev_specs->max_int_gl)
dev_specs->max_int_gl = HCLGEVF_DEF_MAX_INT_GL; if (!dev_specs->max_frm_size)
dev_specs->max_frm_size = HCLGEVF_MAC_MAX_FRAME;
}
staticint hclgevf_query_dev_specs(struct hclgevf_dev *hdev)
{ struct hclge_desc desc[HCLGEVF_QUERY_DEV_SPECS_BD_NUM]; int ret; int i;
/* set default specifications as devices lower than version V3 do not * support querying specifications from firmware.
*/ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3) {
hclgevf_set_default_dev_specs(hdev); return 0;
}
for (i = 0; i < HCLGEVF_QUERY_DEV_SPECS_BD_NUM - 1; i++) {
hclgevf_cmd_setup_basic_desc(&desc[i],
HCLGE_OPC_QUERY_DEV_SPECS, true);
desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
}
hclgevf_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_QUERY_DEV_SPECS, true);
ret = hclgevf_cmd_send(&hdev->hw, desc, HCLGEVF_QUERY_DEV_SPECS_BD_NUM); if (ret) return ret;
if (!test_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state)) {
pci_set_master(pdev);
ret = hclgevf_init_msi(hdev); if (ret) {
dev_err(&pdev->dev, "failed(%d) to init MSI/MSI-X\n", ret); return ret;
}
ret = hclgevf_misc_irq_init(hdev); if (ret) {
hclgevf_uninit_msi(hdev);
dev_err(&pdev->dev, "failed(%d) to init Misc IRQ(vector0)\n",
ret); return ret;
}
ret = hclgevf_misc_irq_init(hdev); if (ret) goto err_misc_irq_init;
set_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state);
ret = hclgevf_configure(hdev); if (ret) {
dev_err(&pdev->dev, "failed(%d) to fetch configuration\n", ret); goto err_config;
}
ret = hclgevf_alloc_tqps(hdev); if (ret) {
dev_err(&pdev->dev, "failed(%d) to allocate TQPs\n", ret); goto err_config;
}
ret = hclgevf_set_handle_info(hdev); if (ret) goto err_config;
ret = hclgevf_config_gro(hdev); if (ret) goto err_config;
/* Initialize RSS for this VF */
ret = hclge_comm_rss_init_cfg(&hdev->nic, hdev->ae_dev,
&hdev->rss_cfg); if (ret) {
dev_err(&pdev->dev, "failed to init rss cfg, ret = %d\n", ret); goto err_config;
}
ret = hclgevf_rss_init_hw(hdev); if (ret) {
dev_err(&hdev->pdev->dev, "failed(%d) to initialize RSS\n", ret); goto err_config;
}
/* ensure vf tbl list as empty before init */
ret = hclgevf_clear_vport_list(hdev); if (ret) {
dev_err(&pdev->dev, "failed to clear tbl list configuration, ret = %d.\n",
ret); goto err_config;
}
ret = hclgevf_init_vlan_config(hdev, true); if (ret) {
dev_err(&hdev->pdev->dev, "failed(%d) to initialize VLAN config\n", ret); goto err_config;
}
hclgevf_init_rxd_adv_layout(hdev);
ret = hclgevf_devlink_init(hdev); if (ret) goto err_config;
/** * hclgevf_get_channels - Get the current channels enabled and max supported. * @handle: hardware information for network interface * @ch: ethtool channels structure * * We don't support separate tx and rx queues as channels. The other count * represents how many queues are being used for control. max_combined counts * how many queue pairs we can support. They may not be mapped 1 to 1 with * q_vectors since we support a lot more queue pairs than q_vectors.
**/ staticvoid hclgevf_get_channels(struct hnae3_handle *handle, struct ethtool_channels *ch)
{ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
/* Use the user's configuration when it is not larger than * max_rss_size, otherwise, use the maximum specification value.
*/ if (kinfo->req_rss_size != kinfo->rss_size && kinfo->req_rss_size &&
kinfo->req_rss_size <= max_rss_size)
kinfo->rss_size = kinfo->req_rss_size; elseif (kinfo->rss_size > max_rss_size ||
(!kinfo->req_rss_size && kinfo->rss_size < max_rss_size))
kinfo->rss_size = max_rss_size;
hclge_comm_get_rss_tc_info(kinfo->rss_size, hdev->hw_tc_map,
tc_offset, tc_valid, tc_size);
ret = hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset,
tc_valid, tc_size); if (ret) return ret;
/* RSS indirection table has been configured by user */ if (rxfh_configured) goto out;
/* Reinitializes the rss indirect table according to the new RSS size */
rss_indir = kcalloc(hdev->ae_dev->dev_specs.rss_ind_tbl_size, sizeof(u32), GFP_KERNEL); if (!rss_indir) return -ENOMEM;
for (i = 0; i < hdev->ae_dev->dev_specs.rss_ind_tbl_size; i++)
rss_indir[i] = i % kinfo->rss_size;
hdev->rss_cfg.rss_size = kinfo->rss_size;
ret = hclgevf_set_rss(handle, rss_indir, NULL, 0); if (ret)
dev_err(&hdev->pdev->dev, "set rss indir table fail, ret=%d\n",
ret);
kfree(rss_indir);
out: if (!ret)
dev_info(&hdev->pdev->dev, "Channels changed, rss_size from %u to %u, tqps from %u to %u",
cur_rss_size, kinfo->rss_size,
cur_tqps, kinfo->rss_size * kinfo->tc_info.num_tc);
if (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state) ||
test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state)) {
dev_warn(&hdev->pdev->dev, "is resetting when updating port based vlan info\n");
rtnl_unlock(); return;
}
ret = hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT); if (ret) {
rtnl_unlock(); return;
}
/* send msg to PF and wait update port based vlan info */
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN,
HCLGE_MBX_PORT_BASE_VLAN_CFG);
memcpy(send_msg.data, port_base_vlan, sizeof(*port_base_vlan));
ret = hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); if (!ret) { if (state == HNAE3_PORT_BASE_VLAN_DISABLE)
nic->port_base_vlan_state = state; else
nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_ENABLE;
}
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.