for (i = 0; i < p_vf->num_sbs; i++) if (p_vf->igu_sbs[i] == sb_idx) returntrue;
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[0%02x] - tried using sb_idx %04x which doesn't exist as one of its 0x%02x SBs\n",
p_vf->abs_vf_id, sb_idx, p_vf->num_sbs);
/* Some sanity checks */ if (iov->num_vfs > NUM_OF_VFS(cdev) ||
iov->total_vfs > NUM_OF_VFS(cdev)) { /* This can happen only due to a bug. In this case we set * num_vfs to zero to avoid memory corruption in the code that * assumes max number of vfs
*/
DP_NOTICE(cdev, "IOV: Unexpected number of vfs set: %d setting num_vf to zero\n",
iov->num_vfs);
int qed_iov_hw_info(struct qed_hwfn *p_hwfn)
{ struct qed_dev *cdev = p_hwfn->cdev; int pos; int rc;
if (is_kdump_kernel()) return 0;
if (IS_VF(p_hwfn->cdev)) return 0;
/* Learn the PCI configuration */
pos = pci_find_ext_capability(p_hwfn->cdev->pdev,
PCI_EXT_CAP_ID_SRIOV); if (!pos) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No PCIe IOV support\n"); return 0;
}
/* Allocate a new struct for IOV information */
cdev->p_iov_info = kzalloc(sizeof(*cdev->p_iov_info), GFP_KERNEL); if (!cdev->p_iov_info) return -ENOMEM;
cdev->p_iov_info->pos = pos;
rc = qed_iov_pci_cfg_info(cdev); if (rc) return rc;
/* We want PF IOV to be synonemous with the existence of p_iov_info; * In case the capability is published but there are no VFs, simply * de-allocate the struct.
*/ if (!cdev->p_iov_info->total_vfs) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "IOV capabilities, but no VFs are published\n");
kfree(cdev->p_iov_info);
cdev->p_iov_info = NULL; return 0;
}
/* First VF index based on offset is tricky: * - If ARI is supported [likely], offset - (16 - pf_id) would * provide the number for eng0. 2nd engine Vfs would begin * after the first engine's VFs. * - If !ARI, VFs would start on next device. * so offset - (256 - pf_id) would provide the number. * Utilize the fact that (256 - pf_id) is achieved only by later * to differentiate between the two.
*/
if (p_hwfn->cdev->p_iov_info->offset < (256 - p_hwfn->abs_pf_id)) {
u32 first = p_hwfn->cdev->p_iov_info->offset +
p_hwfn->abs_pf_id - 16;
cdev->p_iov_info->first_vf_in_pf = first;
if (QED_PATH_ID(p_hwfn))
cdev->p_iov_info->first_vf_in_pf -= MAX_NUM_VFS_BB;
} else {
u32 first = p_hwfn->cdev->p_iov_info->offset +
p_hwfn->abs_pf_id - 256;
cdev->p_iov_info->first_vf_in_pf = first;
}
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "First VF in hwfn 0x%08x\n",
cdev->p_iov_info->first_vf_in_pf);
/* iterate over all queues, clear sb consumer */ for (i = 0; i < vf->num_sbs; i++)
qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt,
vf->igu_sbs[i],
vf->opaque_fid, true);
}
/* For AH onward, configuration is per-PF. Find maximum of all * the currently enabled child VFs, and set the number to be that.
*/ if (!QED_IS_BB(p_hwfn->cdev)) {
qed_for_each_vf(p_hwfn, i) { struct qed_vf_info *p_vf;
p_vf = qed_iov_get_vf_info(p_hwfn, (u16)i, true); if (!p_vf) continue;
/** * qed_iov_config_perm_table() - Configure the permission zone table. * * @p_hwfn: HW device data. * @p_ptt: PTT window for writing the registers. * @vf: VF info data. * @enable: The actual permission for this VF. * * In E4, queue zone permission table size is 320x9. There * are 320 VF queues for single engine device (256 for dual * engine device), and each entry has the following format: * {Valid, VF[7:0]}
*/ staticvoid qed_iov_config_perm_table(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf, u8 enable)
{
u32 reg_addr, val;
u16 qzone_id = 0; int qid;
qid = p_params->req_tx_queue[i]; if (qid > max_vf_qzone) {
DP_NOTICE(p_hwfn, "Can't enable Tx qid [%04x] for VF[%d]: max qid 0x%04x\n",
qid, p_params->rel_vf_id, max_vf_qzone); return -EINVAL;
}
/* If client *really* wants, Tx qid can be shared with PF */ if (qid < min_vf_qzone)
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[%d] is using PF qid [0x%04x] for Txq[0x%02x]\n",
p_params->rel_vf_id, qid, i);
}
/* Limit number of queues according to number of CIDs */
qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH, &cids);
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[%d] - requesting to initialize for 0x%04x queues [0x%04x CIDs available]\n",
vf->relative_vf_id, p_params->num_queues, (u16)cids);
num_irqs = min_t(u16, p_params->num_queues, ((u16)cids));
num_of_vf_avaiable_chains = qed_iov_alloc_vf_igu_sbs(p_hwfn,
p_ptt,
vf, num_irqs); if (!num_of_vf_avaiable_chains) {
DP_ERR(p_hwfn, "no available igu sbs\n"); return -ENOMEM;
}
/* Choose queue number and index ranges */
vf->num_rxqs = num_of_vf_avaiable_chains;
vf->num_txqs = num_of_vf_avaiable_chains;
for (i = 0; i < vf->num_rxqs; i++) { struct qed_vf_queue *p_queue = &vf->vf_queues[i];
vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); if (!vf) {
DP_ERR(p_hwfn, "%s : vf is NULL\n", __func__); return -EINVAL;
}
if (vf->bulletin.p_virt)
memset(vf->bulletin.p_virt, 0, sizeof(*vf->bulletin.p_virt));
memset(&vf->p_vf_info, 0, sizeof(vf->p_vf_info));
/* Get the link configuration back in bulletin so * that when VFs are re-enabled they get the actual * link configuration.
*/
memcpy(¶ms, qed_mcp_get_link_params(p_hwfn), sizeof(params));
memcpy(&link, qed_mcp_get_link_state(p_hwfn), sizeof(link));
memcpy(&caps, qed_mcp_get_link_capabilities(p_hwfn), sizeof(caps));
qed_iov_set_link(p_hwfn, rel_vf_id, ¶ms, &link, &caps);
/* Forget the VF's acquisition message */
memset(&vf->acquire, 0, sizeof(vf->acquire));
/* disablng interrupts and resetting permission table was done during * vf-close, however, we could get here without going through vf_close
*/ /* Disable Interrupts for VF */
qed_iov_vf_igu_set_int(p_hwfn, p_ptt, vf, 0);
/* place a given tlv on the tlv buffer, continuing current tlv list */ void *qed_add_tlv(struct qed_hwfn *p_hwfn, u8 **offset, u16 type, u16 length)
{ struct channel_tlv *tl = (struct channel_tlv *)*offset;
tl->type = type;
tl->length = length;
/* Offset should keep pointing to next TLV (the end of the last) */
*offset += length;
/* Return a pointer to the start of the added tlv */ return *offset - length;
}
/* list the types and lengths of the tlvs on the buffer */ void qed_dp_tlv_list(struct qed_hwfn *p_hwfn, void *tlvs_list)
{
u16 i = 1, total_length = 0; struct channel_tlv *tlv;
do {
tlv = (struct channel_tlv *)((u8 *)tlvs_list + total_length);
/* output tlv */
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "TLV number %d: type %d, length %d\n",
i, tlv->type, tlv->length);
if (tlv->type == CHANNEL_TLV_LIST_END) return;
/* Validate entry - protect against malicious VFs */ if (!tlv->length) {
DP_NOTICE(p_hwfn, "TLV of length 0 found\n"); return;
}
/* Once PF copies the rc to the VF, the latter can continue * and send an additional message. So we have to make sure the * channel would be re-set to ready prior to that.
*/
REG_WR(p_hwfn,
GET_GTT_REG_ADDR(GTT_BAR0_MAP_REG_USDM_RAM,
USTORM_VF_PF_CHANNEL_READY, eng_vf_id), 1);
/* Prepare response for all extended tlvs if they are found by PF */ for (i = 0; i < QED_IOV_VP_UPDATE_MAX; i++) { if (!(tlvs_mask & BIT(i))) continue;
/* If VF didn't bother asking for QIDs than don't bother limiting * number of CIDs. The VF doesn't care about the number, and this * has the likely result of causing an additional acquisition.
*/ if (!(p_vf->acquire.vfdev_info.capabilities &
VFPF_ACQUIRE_CAP_QUEUE_QIDS)) return;
/* If doorbell bar was mapped by VF, limit the VF CIDs to an amount * that would make sure doorbells for all CIDs fall within the bar. * If it doesn't, make sure regview window is sufficient.
*/ if (p_vf->acquire.vfdev_info.capabilities &
VFPF_ACQUIRE_CAP_PHYSICAL_BAR) {
bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); if (bar_size)
bar_size = 1 << bar_size;
/* Queue related information */
p_resp->num_rxqs = p_vf->num_rxqs;
p_resp->num_txqs = p_vf->num_txqs;
p_resp->num_sbs = p_vf->num_sbs;
for (i = 0; i < p_resp->num_sbs; i++) {
p_resp->hw_sbs[i].hw_sb_id = p_vf->igu_sbs[i];
p_resp->hw_sbs[i].sb_qid = 0;
}
/* These fields are filled for backward compatibility. * Unused by modern vfs.
*/ for (i = 0; i < p_resp->num_rxqs; i++) {
qed_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid,
(u16 *)&p_resp->hw_qid[i]);
p_resp->cid[i] = i;
}
/* Filter related information */
p_resp->num_mac_filters = min_t(u8, p_vf->num_mac_filters,
p_req->num_mac_filters);
p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters,
p_req->num_vlan_filters);
/* This isn't really needed/enforced, but some legacy VFs might depend * on the correct filling of this field.
*/
p_resp->num_mc_filters = QED_MAX_MC_ADDRS;
/* Some legacy OSes are incapable of correctly handling this * failure.
*/ if ((p_vf->acquire.vfdev_info.eth_fp_hsi_minor ==
ETH_HSI_VER_NO_PKT_LEN_TUNN) &&
(p_vf->acquire.vfdev_info.os_type ==
VFPF_ACQUIRE_OS_WINDOWS)) return PFVF_STATUS_SUCCESS;
/* Write the PF version so that VF would know which version * is supported - might be later overridden. This guarantees that * VF could recognize legacy PF based on lack of versions in reply.
*/
pfdev_info->major_fp_hsi = ETH_HSI_VER_MAJOR;
pfdev_info->minor_fp_hsi = ETH_HSI_VER_MINOR;
if (vf->state != VF_FREE && vf->state != VF_STOPPED) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[%d] sent ACQUIRE but is already in state %d - fail request\n",
vf->abs_vf_id, vf->state); goto out;
}
/* Validate FW compatibility */ if (req->vfdev_info.eth_fp_hsi_major != ETH_HSI_VER_MAJOR) { if (req->vfdev_info.capabilities &
VFPF_ACQUIRE_CAP_PRE_FP_HSI) { struct vf_pf_vfdev_info *p_vfdev = &req->vfdev_info;
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "VF[%d] is pre-fastpath HSI\n",
vf->abs_vf_id);
p_vfdev->eth_fp_hsi_major = ETH_HSI_VER_MAJOR;
p_vfdev->eth_fp_hsi_minor = ETH_HSI_VER_NO_PKT_LEN_TUNN;
} else {
DP_INFO(p_hwfn, "VF[%d] needs fastpath HSI %02x.%02x, which is incompatible with loaded FW's fastpath HSI %02x.%02x\n",
vf->abs_vf_id,
req->vfdev_info.eth_fp_hsi_major,
req->vfdev_info.eth_fp_hsi_minor,
ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR);
goto out;
}
}
/* On 100g PFs, prevent old VFs from loading */ if ((p_hwfn->cdev->num_hwfns > 1) &&
!(req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_100G)) {
DP_INFO(p_hwfn, "VF[%d] is running an old driver that doesn't support 100g\n",
vf->abs_vf_id); goto out;
}
/* Store the acquire message */
memcpy(&vf->acquire, req, sizeof(vf->acquire));
/* Share our ability to use multiple queue-ids only with VFs * that request it.
*/ if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_QUEUE_QIDS)
pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_QUEUE_QIDS;
/* Share the sizes of the bars with VF */
resp->pfdev_info.bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt);
/* Fill resources available to VF; Make sure there are enough to * satisfy the VF's request.
*/
vfpf_status = qed_iov_vf_mbx_acquire_resc(p_hwfn, p_ptt, vf,
&req->resc_request, resc); if (vfpf_status != PFVF_STATUS_SUCCESS) goto out;
/* Start the VF in FW */
rc = qed_sp_vf_start(p_hwfn, vf); if (rc) {
DP_NOTICE(p_hwfn, "Failed to start VF[%02x]\n", vf->abs_vf_id);
vfpf_status = PFVF_STATUS_FAILURE; goto out;
}
/* Fill agreed size of bulletin board in response */
resp->bulletin_size = vf->bulletin.size;
qed_iov_post_vf_bulletin(p_hwfn, vf->relative_vf_id, p_ptt);
if ((events & BIT(MAC_ADDR_FORCED)) ||
p_vf->p_vf_info.is_trusted_configured) { /* Since there's no way [currently] of removing the MAC, * we can always assume this means we need to force it.
*/
memset(&filter, 0, sizeof(filter));
filter.type = QED_FILTER_MAC;
filter.opcode = QED_FILTER_REPLACE;
filter.is_rx_filter = 1;
filter.is_tx_filter = 1;
filter.vport_to_add_to = p_vf->vport_id;
ether_addr_copy(filter.mac, p_vf->bulletin.p_virt->mac);
rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid,
&filter, QED_SPQ_MODE_CB, NULL); if (rc) {
DP_NOTICE(p_hwfn, "PF failed to configure MAC for VF\n"); return rc;
} if (p_vf->p_vf_info.is_trusted_configured)
p_vf->configured_features |=
BIT(VFPF_BULLETIN_MAC_ADDR); else
p_vf->configured_features |=
BIT(MAC_ADDR_FORCED);
}
if (events & BIT(VLAN_ADDR_FORCED)) { struct qed_sp_vport_update_params vport_update;
u8 removal; int i;
/* If forced features are terminated, we need to configure the shadow * configuration back again.
*/ if (events)
qed_iov_reconfigure_unicast_shadow(p_hwfn, p_vf, events);
/* Initialize Status block in CAU */ for (sb_id = 0; sb_id < vf->num_sbs; sb_id++) { if (!start->sb_addr[sb_id]) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "VF[%d] did not fill the address of SB %d\n",
vf->relative_vf_id, sb_id); break;
}
/* Take into consideration configuration forced by hypervisor; * If none is configured, use the supplied VF values [for old * vfs that would still be fine, since they passed '0' as padding].
*/
p_bitmap = &vf_info->bulletin.p_virt->valid_bitmap; if (!(*p_bitmap & BIT(VFPF_BULLETIN_UNTAGGED_DEFAULT_FORCED))) {
u8 vf_req = start->only_untagged;
/* Taking a bigger struct instead of adding a TLV to list was a * mistake, but one which we're now stuck with, as some older * clients assume the size of the previous response.
*/ if (!b_legacy)
length = sizeof(*p_tlv); else
length = sizeof(struct pfvf_def_resp_tlv);
/* Search for the qid if the VF published its going to provide it */ if (!(p_vf->acquire.vfdev_info.capabilities &
VFPF_ACQUIRE_CAP_QUEUE_QIDS)) { if (b_is_tx) return QED_IOV_LEGACY_QID_TX; else return QED_IOV_LEGACY_QID_RX;
}
p_qid_tlv = (struct vfpf_qid_tlv *)
qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt,
CHANNEL_TLV_QID); if (!p_qid_tlv) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "VF[%2x]: Failed to provide qid\n",
p_vf->relative_vf_id);
/* Legacy VFs have their Producers in a different location, which they * calculate on their own and clean the producer prior to this.
*/ if (!(vf_legacy & QED_QCID_LEGACY_VF_RX_PROD))
qed_wr(p_hwfn, p_ptt, MSEM_REG_FAST_MEMORY +
SEM_FAST_REG_INT_RAM +
MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id,
req->rx_qid), 0);
rc = qed_eth_rxq_start_ramrod(p_hwfn, p_cid,
req->bd_max_bytes,
req->rxq_addr,
req->cqe_pbl_addr, req->cqe_pbl_size); if (rc) {
status = PFVF_STATUS_FAILURE;
qed_eth_queue_cid_release(p_hwfn, p_cid);
} else {
p_queue->cids[qid_usage_idx].p_cid = p_cid;
p_queue->cids[qid_usage_idx].b_is_tx = false;
status = PFVF_STATUS_SUCCESS;
vf->num_active_rxqs++;
}
if (!qed_iov_pf_validate_tunn_param(p_req)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No tunnel update requested by VF\n");
status = PFVF_STATUS_FAILURE; goto send_resp;
}
/* If PF modifies VF's req then it should * still return an error in case of partial configuration * or modified configuration as opposed to requested one.
*/
rc = qed_pf_validate_modify_tunn_config(p_hwfn, &tunn_feature_mask,
&b_update_required, &tunn);
if (rc)
status = PFVF_STATUS_FAILURE;
/* If QED client is willing to update anything ? */ if (b_update_required) {
u16 geneve_port;
rc = qed_sp_pf_update_tunn_cfg(p_hwfn, p_ptt, &tunn,
QED_SPQ_MODE_EBLOCK, NULL); if (rc)
status = PFVF_STATUS_FAILURE;
/* Taking a bigger struct instead of adding a TLV to list was a * mistake, but one which we're now stuck with, as some older * clients assume the size of the previous response.
*/ if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor ==
ETH_HSI_VER_NO_PKT_LEN_TUNN)
b_legacy = true;
if (!b_legacy)
length = sizeof(*p_tlv); else
length = sizeof(struct pfvf_def_resp_tlv);
p_queue = &vf->vf_queues[req->tx_qid]; if (p_queue->cids[qid_usage_idx].p_cid) goto out;
vf_legacy = qed_vf_calculate_legacy(vf);
/* Acquire a new queue-cid */
params.queue_id = p_queue->fw_tx_qid;
params.vport_id = vf->vport_id;
params.stats_id = vf->abs_vf_id + 0x10;
/* Since IGU index is passed via sb_info, construct a dummy one */
memset(&sb_dummy, 0, sizeof(sb_dummy));
sb_dummy.igu_sb_id = req->hw_sb;
params.p_sb = &sb_dummy;
params.sb_idx = req->sb_index;
if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, QED_IOV_VALIDATE_Q_NA)) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[%d] Tried Closing Rx 0x%04x.%02x which is inactive\n",
vf->relative_vf_id, rxq_id, qid_usage_idx); return -EINVAL;
}
p_queue = &vf->vf_queues[rxq_id];
/* We've validated the index and the existence of the active RXQ - * now we need to make sure that it's using the correct qid.
*/ if (!p_queue->cids[qid_usage_idx].p_cid ||
p_queue->cids[qid_usage_idx].b_is_tx) { struct qed_queue_cid *p_cid;
p_cid = qed_iov_get_vf_rx_queue_cid(p_queue);
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[%d] - Tried Closing Rx 0x%04x.%02x, but Rx is at %04x.%02x\n",
vf->relative_vf_id,
rxq_id, qid_usage_idx, rxq_id, p_cid->qid_usage_idx); return -EINVAL;
}
/* Now that we know we have a valid Rx-queue - close it */
rc = qed_eth_rx_queue_stop(p_hwfn,
p_queue->cids[qid_usage_idx].p_cid, false, cqe_completion); if (rc) return rc;
/* There has never been an official driver that used this interface * for stopping multiple queues, and it is now considered deprecated. * Validate this isn't used here.
*/
req = &mbx->req_virt->stop_rxqs; if (req->num_rxqs != 1) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Odd; VF[%d] tried stopping multiple Rx queues\n",
vf->relative_vf_id);
status = PFVF_STATUS_NOT_SUPPORTED; goto out;
}
/* Find which qid-index is associated with the queue */
qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); if (qid_usage_idx == QED_IOV_QID_INVALID) goto out;
rc = qed_iov_vf_stop_rxqs(p_hwfn, vf, req->rx_qid,
qid_usage_idx, req->cqe_completion); if (!rc)
status = PFVF_STATUS_SUCCESS;
out:
qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_STOP_RXQS,
length, status);
}
/* There has never been an official driver that used this interface * for stopping multiple queues, and it is now considered deprecated. * Validate this isn't used here.
*/
req = &mbx->req_virt->stop_txqs; if (req->num_txqs != 1) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Odd; VF[%d] tried stopping multiple Tx queues\n",
vf->relative_vf_id);
status = PFVF_STATUS_NOT_SUPPORTED; goto out;
}
/* Find which qid-index is associated with the queue */
qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); if (qid_usage_idx == QED_IOV_QID_INVALID) goto out;
rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid, qid_usage_idx); if (!rc)
status = PFVF_STATUS_SUCCESS;
/* There shouldn't exist a VF that uses queue-qids yet uses this * API with multiple Rx queues. Validate this.
*/ if ((vf->acquire.vfdev_info.capabilities &
VFPF_ACQUIRE_CAP_QUEUE_QIDS) && req->num_rxqs != 1) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "VF[%d] supports QIDs but sends multiple queues\n",
vf->relative_vf_id); goto out;
}
/* Validate inputs - for the legacy case this is still true since * qid_usage_idx for each Rx queue would be LEGACY_QID_RX.
*/ for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) { if (!qed_iov_validate_rxq(p_hwfn, vf, i,
QED_IOV_VALIDATE_Q_NA) ||
!vf->vf_queues[i].cids[qid_usage_idx].p_cid ||
vf->vf_queues[i].cids[qid_usage_idx].b_is_tx) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "VF[%d]: Incorrect Rxqs [%04x, %02x]\n",
vf->relative_vf_id, req->rx_qid,
req->num_rxqs); goto out;
}
}
/* Prepare the handlers */ for (i = 0; i < req->num_rxqs; i++) {
u16 qid = req->rx_qid + i;
/* Untrusted VFs can't even be trusted to know that fact. * Simply indicate everything is configured fine, and trace * configuration 'behind their back'.
*/ if (!(*tlvs & tlv_mask)) return 0;
/* Validate PF can send such a request */ if (!vf->vport_instance) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "No VPORT instance available for VF[%d], failing vport update\n",
vf->abs_vf_id);
status = PFVF_STATUS_FAILURE; goto out;
}
p_rss_params = vzalloc(sizeof(*p_rss_params)); if (!p_rss_params) {
status = PFVF_STATUS_FAILURE; goto out;
}
/* Search for extended tlvs list and update values * from VF in struct qed_sp_vport_update_params.
*/
qed_iov_vp_update_act_param(p_hwfn, ¶ms, mbx, &tlvs_mask);
qed_iov_vp_update_vlan_param(p_hwfn, ¶ms, vf, mbx, &tlvs_mask);
qed_iov_vp_update_tx_switch(p_hwfn, ¶ms, mbx, &tlvs_mask);
qed_iov_vp_update_mcast_bin_param(p_hwfn, ¶ms, mbx, &tlvs_mask);
qed_iov_vp_update_accept_flag(p_hwfn, ¶ms, mbx, &tlvs_mask);
qed_iov_vp_update_accept_any_vlan(p_hwfn, ¶ms, mbx, &tlvs_mask);
qed_iov_vp_update_sge_tpa_param(p_hwfn, vf, ¶ms,
&sge_tpa_params, mbx, &tlvs_mask);
tlvs_accepted = tlvs_mask;
/* Some of the extended TLVs need to be validated first; In that case, * they can update the mask without updating the accepted [so that * PF could communicate to VF it has rejected request].
*/
qed_iov_vp_update_rss_param(p_hwfn, vf, ¶ms, p_rss_params,
mbx, &tlvs_mask, &tlvs_accepted);
if (qed_iov_pre_update_vport(p_hwfn, vf->relative_vf_id,
¶ms, &tlvs_accepted)) {
tlvs_accepted = 0;
status = PFVF_STATUS_NOT_SUPPORTED; goto out;
}
if (!tlvs_accepted) { if (tlvs_mask)
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Upper-layer prevents VF vport configuration\n"); else
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No feature tlvs found for vport update\n");
status = PFVF_STATUS_NOT_SUPPORTED; goto out;
}
/* First remove entries and then add new ones */ if (p_params->opcode == QED_FILTER_REMOVE) { for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) if (p_vf->shadow_config.vlans[i].used &&
p_vf->shadow_config.vlans[i].vid ==
p_params->vlan) {
p_vf->shadow_config.vlans[i].used = false; break;
} if (i == QED_ETH_VF_NUM_VLAN_FILTERS + 1) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF [%d] - Tries to remove a non-existing vlan\n",
p_vf->relative_vf_id); return -EINVAL;
}
} elseif (p_params->opcode == QED_FILTER_REPLACE ||
p_params->opcode == QED_FILTER_FLUSH) { for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++)
p_vf->shadow_config.vlans[i].used = false;
}
/* In forced mode, we're willing to remove entries - but we don't add * new ones.
*/ if (p_vf->bulletin.p_virt->valid_bitmap & BIT(VLAN_ADDR_FORCED)) return 0;
if (p_params->opcode == QED_FILTER_ADD ||
p_params->opcode == QED_FILTER_REPLACE) { for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++) { if (p_vf->shadow_config.vlans[i].used) continue;
/* If we're in forced-mode, we don't allow any change */ if (p_vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED)) return 0;
/* Don't keep track of shadow copy since we don't intend to restore. */ if (p_vf->p_vf_info.is_trusted_configured) return 0;
/* First remove entries and then add new ones */ if (p_params->opcode == QED_FILTER_REMOVE) { for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { if (ether_addr_equal(p_vf->shadow_config.macs[i],
p_params->mac)) {
eth_zero_addr(p_vf->shadow_config.macs[i]); break;
}
}
if (i == QED_ETH_VF_NUM_MAC_FILTERS) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "MAC isn't configured\n"); return -EINVAL;
}
} elseif (p_params->opcode == QED_FILTER_REPLACE ||
p_params->opcode == QED_FILTER_FLUSH) { for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++)
eth_zero_addr(p_vf->shadow_config.macs[i]);
}
/* List the new MAC address */ if (p_params->opcode != QED_FILTER_ADD &&
p_params->opcode != QED_FILTER_REPLACE) return 0;
for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { if (is_zero_ether_addr(p_vf->shadow_config.macs[i])) {
ether_addr_copy(p_vf->shadow_config.macs[i],
p_params->mac);
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Added MAC at %d entry in shadow\n", i); break;
}
}
if (i == QED_ETH_VF_NUM_MAC_FILTERS) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No available place for MAC\n"); return -EINVAL;
}
vf = qed_iov_get_public_vf_info(hwfn, vfid, true); if (!vf) return -EINVAL;
/* No real decision to make; Store the configured MAC */ if (params->type == QED_FILTER_MAC ||
params->type == QED_FILTER_MAC_VLAN) {
ether_addr_copy(vf->mac, params->mac);
if (vf->is_trusted_configured) {
qed_iov_bulletin_set_mac(hwfn, vf->mac, vfid);
/* Update and post bulleitin again */
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}
if (!vf->vport_instance) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "No VPORT instance available for VF[%d], failing ucast MAC configuration\n",
vf->abs_vf_id);
status = PFVF_STATUS_FAILURE; goto out;
}
/* Update shadow copy of the VF configuration */ if (qed_iov_vf_update_unicast_shadow(p_hwfn, vf, ¶ms)) {
status = PFVF_STATUS_FAILURE; goto out;
}
/* Determine if the unicast filtering is acceptable by PF */ if ((p_bulletin->valid_bitmap & BIT(VLAN_ADDR_FORCED)) &&
(params.type == QED_FILTER_VLAN ||
params.type == QED_FILTER_MAC_VLAN)) { /* Once VLAN is forced or PVID is set, do not allow * to add/replace any further VLANs.
*/ if (params.opcode == QED_FILTER_ADD ||
params.opcode == QED_FILTER_REPLACE)
status = PFVF_STATUS_FORCED; goto out;
}
if ((p_bulletin->valid_bitmap & BIT(MAC_ADDR_FORCED)) &&
(params.type == QED_FILTER_MAC ||
params.type == QED_FILTER_MAC_VLAN)) { if (!ether_addr_equal(p_bulletin->mac, params.mac) ||
(params.opcode != QED_FILTER_ADD &&
params.opcode != QED_FILTER_REPLACE))
status = PFVF_STATUS_FORCED; goto out;
}
rc = qed_iov_chk_ucast(p_hwfn, vf->relative_vf_id, ¶ms); if (rc) {
status = PFVF_STATUS_FAILURE; goto out;
}
rc = qed_sp_eth_filter_ucast(p_hwfn, vf->opaque_fid, ¶ms,
QED_SPQ_MODE_CB, NULL); if (rc)
status = PFVF_STATUS_FAILURE;
/* If VF isn't active, no need for anything but SW */ if (!p_vf->b_init) goto cleanup;
rc = qed_iov_vf_flr_poll(p_hwfn, p_vf, p_ptt); if (rc) goto cleanup;
rc = qed_final_cleanup(p_hwfn, p_ptt, vfid, true); if (rc) {
DP_ERR(p_hwfn, "Failed handle FLR of VF[%d]\n", vfid); return rc;
}
/* Workaround to make VF-PF channel ready, as FW * doesn't do that as a part of FLR.
*/
REG_WR(p_hwfn,
GET_GTT_REG_ADDR(GTT_BAR0_MAP_REG_USDM_RAM,
USTORM_VF_PF_CHANNEL_READY, vfid), 1);
/* VF_STOPPED has to be set only after final cleanup * but prior to re-enabling the VF.
*/
p_vf->state = VF_STOPPED;
rc = qed_iov_enable_vf_access(p_hwfn, p_ptt, p_vf); if (rc) {
DP_ERR(p_hwfn, "Failed to re-enable VF[%d] access\n",
vfid); return rc;
}
cleanup: /* Mark VF for ack and clean pending state */ if (p_vf->state == VF_RESET)
p_vf->state = VF_STOPPED;
ack_vfs[vfid / 32] |= BIT((vfid % 32));
p_hwfn->pf_iov_info->pending_flr[rel_vf_id / 64] &=
~(1ULL << (rel_vf_id % 64));
p_vf->vf_mbx.b_pending_msg = false;
}
/* Since BRB <-> PRS interface can't be tested as part of the flr * polling due to HW limitations, simply sleep a bit. And since * there's no need to wait per-vf, do it before looping.
*/
msleep(100);
for (i = 0; i < p_hwfn->cdev->p_iov_info->total_vfs; i++)
qed_iov_execute_vf_flr_cleanup(p_hwfn, p_ptt, i, ack_vfs);
/* No need to lock here, since pending_flr should * only change here and before ACKing MFw. Since * MFW will not trigger an additional attention for * VF flr until ACKs, we're safe.
*/
p_flr[rel_vf_id / 64] |= 1ULL << (rel_vf_id % 64);
found = true;
}
}
p_vf = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); if (!p_vf) return;
mbx = &p_vf->vf_mbx;
/* qed_iov_process_mbx_request */ if (!mbx->b_pending_msg) {
DP_NOTICE(p_hwfn, "VF[%02x]: Trying to process mailbox message when none is pending\n",
p_vf->abs_vf_id); return;
}
mbx->b_pending_msg = false;
/* check if tlv type is known */ if (qed_iov_tlv_supported(mbx->first_tlv.tl.type) &&
!p_vf->b_malicious) { switch (mbx->first_tlv.tl.type) { case CHANNEL_TLV_ACQUIRE:
qed_iov_vf_mbx_acquire(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_VPORT_START:
qed_iov_vf_mbx_start_vport(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_VPORT_TEARDOWN:
qed_iov_vf_mbx_stop_vport(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_START_RXQ:
qed_iov_vf_mbx_start_rxq(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_START_TXQ:
qed_iov_vf_mbx_start_txq(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_STOP_RXQS:
qed_iov_vf_mbx_stop_rxqs(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_STOP_TXQS:
qed_iov_vf_mbx_stop_txqs(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_UPDATE_RXQ:
qed_iov_vf_mbx_update_rxqs(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_VPORT_UPDATE:
qed_iov_vf_mbx_vport_update(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_UCAST_FILTER:
qed_iov_vf_mbx_ucast_filter(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_CLOSE:
qed_iov_vf_mbx_close(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_INT_CLEANUP:
qed_iov_vf_mbx_int_cleanup(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_RELEASE:
qed_iov_vf_mbx_release(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_UPDATE_TUNN_PARAM:
qed_iov_vf_mbx_update_tunn_param(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_COALESCE_UPDATE:
qed_iov_vf_pf_set_coalesce(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_COALESCE_READ:
qed_iov_vf_pf_get_coalesce(p_hwfn, p_ptt, p_vf); break; case CHANNEL_TLV_BULLETIN_UPDATE_MAC:
qed_iov_vf_pf_bulletin_update_mac(p_hwfn, p_ptt, p_vf); break;
}
} elseif (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "VF [%02x] - considered malicious; Ignoring TLV [%04x]\n",
p_vf->abs_vf_id, mbx->first_tlv.tl.type);
qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf,
mbx->first_tlv.tl.type, sizeof(struct pfvf_def_resp_tlv),
PFVF_STATUS_MALICIOUS);
} else { /* unknown TLV - this may belong to a VF driver from the future * - a version written after this PF driver was written, which * supports features unknown as of yet. Too bad since we don't * support them. Or this may be because someone wrote a crappy * VF driver and is sending garbage over the channel.
*/
DP_NOTICE(p_hwfn, "VF[%02x]: unknown TLV. type %04x length %04x padding %08x reply address %llu\n",
p_vf->abs_vf_id,
mbx->first_tlv.tl.type,
mbx->first_tlv.tl.length,
mbx->first_tlv.padding, mbx->first_tlv.reply_address);
/* Try replying in case reply address matches the acquisition's * posted address.
*/ if (p_vf->acquire.first_tlv.reply_address &&
(mbx->first_tlv.reply_address ==
p_vf->acquire.first_tlv.reply_address)) {
qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf,
mbx->first_tlv.tl.type, sizeof(struct pfvf_def_resp_tlv),
PFVF_STATUS_NOT_SUPPORTED);
} else {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "VF[%02x]: Can't respond to TLV - no valid reply address\n",
p_vf->abs_vf_id);
}
}
}
staticvoid qed_iov_pf_get_pending_events(struct qed_hwfn *p_hwfn, u64 *events)
{ int i;
if (!_qed_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min, false)) {
DP_VERBOSE(p_hwfn,
QED_MSG_IOV, "Got indication for VF [abs 0x%08x] that cannot be handled by PF\n",
abs_vfid); return NULL;
}
/* List the physical address of the request so that handler * could later on copy the message from it.
*/
p_vf->vf_mbx.pending_req = HILO_64(vf_msg->hi, vf_msg->lo);
/* Mark the event and schedule the workqueue */
p_vf->vf_mbx.b_pending_msg = true;
qed_schedule_iov(p_hwfn, QED_IOV_WQ_MSG_FLAG);
vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); if (!vf_info) {
DP_NOTICE(p_hwfn->cdev, "Can not set MAC, invalid vfid [%d]\n",
vfid); return -EINVAL;
}
if (vf_info->b_malicious) {
DP_NOTICE(p_hwfn->cdev, "Can't set MAC to malicious VF [%d]\n",
vfid); return -EINVAL;
}
if (vf_info->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV, "Can not set MAC, Forced MAC is configured\n"); return -EINVAL;
}
/* Failure to acquire the ptt in 100g creates an odd error * where the first engine has already released IOV.
*/ if (!ptt) {
DP_ERR(hwfn, "Failed to acquire ptt\n"); return -EBUSY;
}
/* Clean WFQ db and configure equal weight for all vports */
qed_clean_wfq_db(hwfn, ptt);
qed_for_each_vf(hwfn, j) { int k;
if (!qed_iov_is_valid_vfid(hwfn, j, true, false)) continue;
/* Wait until VF is disabled before releasing */ for (k = 0; k < 100; k++) { if (!qed_iov_is_vf_stopped(hwfn, j))
msleep(20); else break;
}
if (k < 100)
qed_iov_release_hw_for_vf(&cdev->hwfns[i],
ptt, j); else
DP_ERR(hwfn, "Timeout waiting for VF's FLR to end\n");
}
/* Since we have an equal resource distribution per-VF, and we assume * PF has acquired the QED_PF_L2_QUE first queues, we start setting * sequentially from there.
*/
base = FEAT_NUM(hwfn, QED_PF_L2_QUE) + vfid * params->num_queues;
params->rel_vf_id = vfid; for (i = 0; i < params->num_queues; i++) {
params->req_rx_queue[i] = base + i;
params->req_tx_queue[i] = base + i;
}
}
staticint qed_sriov_enable(struct qed_dev *cdev, int num)
{ struct qed_iov_vf_init_params params; struct qed_hwfn *hwfn; struct qed_ptt *ptt; int i, j, rc;
if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) {
DP_NOTICE(cdev, "Can start at most %d VFs\n",
RESC_NUM(&cdev->hwfns[0], QED_VPORT) - 1); return -EINVAL;
}
memset(¶ms, 0, sizeof(params));
/* Initialize HW for VF access */
for_each_hwfn(cdev, j) {
hwfn = &cdev->hwfns[j];
ptt = qed_ptt_acquire(hwfn);
/* Make sure not to use more than 16 queues per VF */
params.num_queues = min_t(int,
FEAT_NUM(hwfn, QED_VF_L2_QUE) / num,
16);
if (!ptt) {
DP_ERR(hwfn, "Failed to acquire ptt\n");
rc = -EBUSY; goto err;
}
for (i = 0; i < num; i++) { if (!qed_iov_is_valid_vfid(hwfn, i, false, true)) continue;
qed_sriov_enable_qid_config(hwfn, i, ¶ms);
rc = qed_iov_init_hw_for_vf(hwfn, ptt, ¶ms); if (rc) {
DP_ERR(cdev, "Failed to enable VF[%d]\n", i);
qed_ptt_release(hwfn, ptt); goto err;
}
}
hwfn = QED_LEADING_HWFN(cdev);
ptt = qed_ptt_acquire(hwfn); if (!ptt) {
DP_ERR(hwfn, "Failed to acquire ptt\n");
rc = -EBUSY; goto err;
}
rc = qed_mcp_ov_update_eswitch(hwfn, ptt, QED_OV_ESWITCH_VEB); if (rc)
DP_INFO(cdev, "Failed to update eswitch mode\n");
qed_ptt_release(hwfn, ptt);
return num;
err:
qed_sriov_disable(cdev, false); return rc;
}
staticint qed_sriov_configure(struct qed_dev *cdev, int num_vfs_param)
{ if (!IS_QED_SRIOV(cdev)) {
DP_VERBOSE(cdev, QED_MSG_IOV, "SR-IOV is not supported\n"); return -EOPNOTSUPP;
}
if (num_vfs_param) return qed_sriov_enable(cdev, num_vfs_param); else return qed_sriov_disable(cdev, true);
}
staticint qed_sriov_pf_set_mac(struct qed_dev *cdev, u8 *mac, int vfid)
{ int i;
if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) {
DP_VERBOSE(cdev, QED_MSG_IOV, "Cannot set a VF MAC; Sriov is not enabled\n"); return -EINVAL;
}
if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true, true)) {
DP_VERBOSE(cdev, QED_MSG_IOV, "Cannot set VF[%d] MAC (VF is not active)\n", vfid); return -EINVAL;
}
vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); if (!vf_info) continue;
/* Set the MAC, and schedule the IOV task */ if (vf_info->is_trusted_configured)
ether_addr_copy(vf_info->mac, mac); else
ether_addr_copy(vf_info->forced_mac, mac);
staticint qed_sriov_pf_set_vlan(struct qed_dev *cdev, u16 vid, int vfid)
{ int i;
if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) {
DP_VERBOSE(cdev, QED_MSG_IOV, "Cannot set a VF MAC; Sriov is not enabled\n"); return -EINVAL;
}
if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true, true)) {
DP_VERBOSE(cdev, QED_MSG_IOV, "Cannot set VF[%d] MAC (VF is not active)\n", vfid); return -EINVAL;
}
/* Update bulletin of all future possible VFs with link configuration */ for (i = 0; i < hwfn->cdev->p_iov_info->total_vfs; i++) { struct qed_public_vf_info *vf_info;
vf_info = qed_iov_get_public_vf_info(hwfn, i, false); if (!vf_info) continue;
/* Only hwfn0 is actually interested in the link speed. * But since only it would receive an MFW indication of link, * need to take configuration from it - otherwise things like * rate limiting for hwfn1 VF would not work.
*/
memcpy(¶ms, qed_mcp_get_link_params(lead_hwfn), sizeof(params));
memcpy(&link, qed_mcp_get_link_state(lead_hwfn), sizeof(link));
memcpy(&caps, qed_mcp_get_link_capabilities(lead_hwfn), sizeof(caps));
/* Modify link according to the VF's configured link state */ switch (vf_info->link_state) { case IFLA_VF_LINK_STATE_DISABLE:
link.link_up = false; break; case IFLA_VF_LINK_STATE_ENABLE:
link.link_up = true; /* Set speed according to maximum supported by HW. * that is 40G for regular devices and 100G for CMT * mode devices.
*/
link.speed = (hwfn->cdev->num_hwfns > 1) ?
100000 : 40000; break; default: /* In auto mode pass PF link image to VF */ break;
}
if (link.link_up && vf_info->tx_rate) { struct qed_ptt *ptt; int rate;
rate = min_t(int, vf_info->tx_rate, link.speed);
ptt = qed_ptt_acquire(hwfn); if (!ptt) {
DP_NOTICE(hwfn, "Failed to acquire PTT\n"); return;
}
if (!qed_iov_configure_tx_rate(hwfn, ptt, i, rate)) {
vf_info->tx_rate = rate;
link.speed = rate;
}
qed_ptt_release(hwfn, ptt);
}
qed_iov_set_link(hwfn, i, ¶ms, &link, &caps);
}
info = qed_iov_get_public_vf_info(hwfn, i, true); if (!info) continue;
/* Update data on bulletin board */ if (info->is_trusted_configured)
mac = qed_iov_bulletin_get_mac(hwfn, i); else
mac = qed_iov_bulletin_get_forced_mac(hwfn, i);
if (qed_pf_validate_req_vf_mac(hwfn, mac, info)) {
DP_VERBOSE(hwfn,
QED_MSG_IOV, "Handling PF setting of VF MAC to VF 0x%02x [Abs 0x%02x]\n",
i,
hwfn->cdev->p_iov_info->first_vf_in_pf + i);
/* Update bulletin board with MAC */
qed_set_bulletin_mac(hwfn, info, i);
update = true;
}
if (qed_iov_bulletin_get_forced_vlan(hwfn, i) ^
info->forced_vlan) {
DP_VERBOSE(hwfn,
QED_MSG_IOV, "Handling PF setting of pvid [0x%04x] to VF 0x%02x [Abs 0x%02x]\n",
info->forced_vlan,
i,
hwfn->cdev->p_iov_info->first_vf_in_pf + i);
qed_iov_bulletin_set_forced_vlan(hwfn,
info->forced_vlan, i);
update = true;
}
if (update)
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}
staticvoid qed_handle_bulletin_post(struct qed_hwfn *hwfn)
{ struct qed_ptt *ptt; int i;
ptt = qed_ptt_acquire(hwfn); if (!ptt) {
DP_NOTICE(hwfn, "Failed allocating a ptt entry\n");
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); return;
}
qed_for_each_vf(hwfn, i)
qed_iov_post_vf_bulletin(hwfn, i, ptt);
qed_ptt_release(hwfn, ptt);
}
staticvoid qed_update_mac_for_vf_trust_change(struct qed_hwfn *hwfn, int vf_id)
{ struct qed_public_vf_info *vf_info; struct qed_vf_info *vf;
u8 *force_mac; int i;
/* Force MAC converted to generic MAC in case of VF trust on */ if (vf_info->is_trusted_configured &&
(vf->bulletin.p_virt->valid_bitmap & BIT(MAC_ADDR_FORCED))) {
force_mac = qed_iov_bulletin_get_forced_mac(hwfn, vf_id);
if (force_mac) { /* Clear existing shadow copy of MAC to have a clean * slate.
*/ for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { if (ether_addr_equal(vf->shadow_config.macs[i],
vf_info->mac)) {
eth_zero_addr(vf->shadow_config.macs[i]);
DP_VERBOSE(hwfn, QED_MSG_IOV, "Shadow MAC %pM removed for VF 0x%02x, VF trust mode is ON\n",
vf_info->mac, vf_id); break;
}
}
/* Update shadow copy with VF MAC when trust mode is turned off */ if (!vf_info->is_trusted_configured) {
u8 empty_mac[ETH_ALEN];
eth_zero_addr(empty_mac); for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) { if (ether_addr_equal(vf->shadow_config.macs[i],
empty_mac)) {
ether_addr_copy(vf->shadow_config.macs[i],
vf_info->mac);
DP_VERBOSE(hwfn, QED_MSG_IOV, "Shadow is updated with %pM for VF 0x%02x, VF trust mode is OFF\n",
vf_info->mac, vf_id); break;
}
} /* Clear bulletin when trust mode is turned off, * to have a clean slate for next (normal) operations.
*/
qed_iov_bulletin_set_mac(hwfn, empty_mac, vf_id);
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}
qed_for_each_vf(hwfn, i) { /* Need to make sure current requested configuration didn't * flip so that we'll end up configuring something that's not * needed.
*/
vf_info = qed_iov_get_public_vf_info(hwfn, i, true); if (vf_info->is_trusted_configured ==
vf_info->is_trusted_request) continue;
vf_info->is_trusted_configured = vf_info->is_trusted_request;
/* Handle forced MAC mode */
qed_update_mac_for_vf_trust_change(hwfn, i);
/* Validate that the VF has a configured vport */
vf = qed_iov_get_vf_info(hwfn, i, true); if (!vf || !vf->vport_instance) continue;
/* Remove if needed; Otherwise this would set the mask */ if (!vf_info->is_trusted_configured) {
flags->rx_accept_filter &= ~mask;
flags->tx_accept_filter &= ~mask;
params.accept_any_vlan = false;
}
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.