staticint bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
/* place a given tlv on the tlv buffer at a given offset */ staticvoid bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list,
u16 offset, u16 type, u16 length)
{ struct channel_tlv *tl =
(struct channel_tlv *)(tlvs_list + offset);
tl->type = type;
tl->length = length;
}
/* Clear the mailbox and init the header of the first tlv */ staticvoid bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length)
{
mutex_lock(&bp->vf2pf_mutex);
DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
type);
/* Finds a TLV by type in a TLV buffer; If found, returns pointer to the TLV */ staticvoid *bnx2x_search_tlv_list(struct bnx2x *bp, void *tlvs_list, enum channel_tlvs req_tlv)
{ struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
do { if (tlv->type == req_tlv) return tlv;
if (!tlv->length) {
BNX2X_ERR("Found TLV with length 0\n"); return NULL;
}
DP(BNX2X_MSG_IOV, "TLV list does not contain %d TLV\n", req_tlv);
return NULL;
}
/* list the types and lengths of the tlvs on the buffer */ staticvoid bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
{ int i = 1; struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
while (tlv->type != CHANNEL_TLV_LIST_END) { /* output tlv */
DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
tlv->type, tlv->length);
/* advance to next tlv */
tlvs_list += tlv->length;
/* cast general tlv list pointer to channel tlv header*/
tlv = (struct channel_tlv *)tlvs_list;
i++;
/* break condition for this loop */ if (i > MAX_TLVS_IN_LIST) {
WARN(true, "corrupt tlvs"); return;
}
}
/* output last tlv */
DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
tlv->type, tlv->length);
}
/* test whether we support a tlv type */ bool bnx2x_tlv_supported(u16 tlvtype)
{ return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX;
}
/* Clear response buffer */
memset(&bp->vf2pf_mbox->resp, 0, sizeof(union pfvf_tlvs));
} else { /* Determine reason of PF failure of acquire process */
fp_hsi_resp = bnx2x_search_tlv_list(bp, resp,
CHANNEL_TLV_FP_HSI_SUPPORT); if (fp_hsi_resp && !fp_hsi_resp->is_supported)
BNX2X_ERR("Old hypervisor - doesn't support current fastpath HSI version; Need to downgrade VF driver [or upgrade hypervisor]\n"); else
BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
bp->acquire_resp.hdr.status);
rc = -EAGAIN; goto out;
}
}
/* Retrieve physical port id (if possible) */
phys_port_resp = (struct vfpf_port_phys_id_resp_tlv *)
bnx2x_search_tlv_list(bp, resp,
CHANNEL_TLV_PHYS_PORT_ID); if (phys_port_resp) {
memcpy(bp->phys_port_id, phys_port_resp->id, ETH_ALEN);
bp->flags |= HAS_PHYS_PORT_ID;
}
/* Old Hypevisors might not even support the FP_HSI_SUPPORT TLV. *Ifthat'sthecase,weneedtomakecertainrequiredFWwas *supportedbysuchahypervisor[i.e.,v0-v2].
*/
fp_hsi_resp = bnx2x_search_tlv_list(bp, resp,
CHANNEL_TLV_FP_HSI_SUPPORT); if (!fp_hsi_resp && (ETH_FP_HSI_VERSION > ETH_FP_HSI_VER_2)) {
BNX2X_ERR("Old hypervisor - need to downgrade VF's driver\n");
/* Since acquire succeeded on the PF side, we need to send a *releasemessageinordertoallowfutureprobes.
*/
bnx2x_vfpf_finalize(bp, &req->first_tlv);
bnx2x_vfpf_release(bp);
if (resp->hdr.status == PFVF_STATUS_SUCCESS) { /* PF released us */
DP(BNX2X_MSG_SP, "vf released\n");
} else { /* PF reports error */
BNX2X_ERR("PF failed our release request - are we out of sync? Response status: %d\n",
resp->hdr.status);
rc = -EAGAIN; goto out;
}
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
}
/* Tell PF about SB addresses */ int bnx2x_vfpf_init(struct bnx2x *bp)
{ struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; int rc, i;
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req));
/* status blocks */
for_each_eth_queue(bp, i)
req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i,
status_blk_mapping);
/* statistics - requests only supports single queue for now */
req->stats_addr = bp->fw_stats_data_mapping +
offsetof(struct bnx2x_fw_stats_data, queue_stats);
/* output tlvs list */
bnx2x_dp_tlv_list(bp, req);
/* send message to pf */
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) {
BNX2X_ERR("failed to send message to pf. rc was %d\n", rc); goto out;
}
/* failure may mean PF was configured with a new mac for us */ while (resp->hdr.status == PFVF_STATUS_FAILURE) {
DP(BNX2X_MSG_IOV, "vfpf SET MAC failed. Check bulletin board for new posts\n");
/* copy mac from bulletin to device */
eth_hw_addr_set(bp->dev, bulletin.mac);
/* check if bulletin board was updated */ if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) { /* copy mac from device to request */
memcpy(req->filters[0].mac, bp->dev->dev_addr,
ETH_ALEN);
/* send message to pf */
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
bp->vf2pf_mbox_mapping);
} else { /* no new info in bulletin */ break;
}
}
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
rc = -EINVAL;
}
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
}
/* request pf to config rss table for vf queues*/ int bnx2x_vfpf_config_rss(struct bnx2x *bp, struct bnx2x_config_rss_params *params)
{ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; struct vfpf_rss_tlv *req = &bp->vf2pf_mbox->req.update_rss; int rc = 0;
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_UPDATE_RSS, sizeof(*req));
/* output tlvs list */
bnx2x_dp_tlv_list(bp, req);
/* send message to pf */
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) {
BNX2X_ERR("failed to send message to pf. rc was %d\n", rc); goto out;
}
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { /* Since older drivers don't support this feature (and VF has *nowayofknowingotherthanfailingthis),don'tpropagate *anerrorinthiscase.
*/
DP(BNX2X_MSG_IOV, "Failed to send rss message to PF over VF-PF channel [%d]\n",
resp->hdr.status);
}
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
}
int bnx2x_vfpf_set_mcast(struct net_device *dev)
{ struct bnx2x *bp = netdev_priv(dev); struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; int rc = 0, i = 0; struct netdev_hw_addr *ha;
if (bp->state != BNX2X_STATE_OPEN) {
DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); return -EINVAL;
}
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS, sizeof(*req));
/* We support PFVF_MAX_MULTICAST_PER_VF mcast addresses tops */ if (netdev_mc_count(dev) > PFVF_MAX_MULTICAST_PER_VF) {
DP(NETIF_MSG_IFUP, "VF supports not more than %d multicast MAC addresses\n",
PFVF_MAX_MULTICAST_PER_VF);
rc = -EINVAL; goto out;
}
/* Offset should continue representing the offset to the tail *ofTLVdata(outsidethisfunctionscope)
*/
*offset += sizeof(struct vfpf_port_phys_id_resp_tlv);
}
/* Offset should continue representing the offset to the tail *ofTLVdata(outsidethisfunctionscope)
*/
*offset += sizeof(struct vfpf_fp_hsi_resp_tlv);
}
/* if a mac has been set for this vf, supply it */ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
memcpy(resc->current_mac_addr, bulletin->mac,
ETH_ALEN);
}
}
}
/* Handle possible VF requests for physical port identifiers. *'length'shouldcontinuetoindicatetheoffsetofthefirstempty *placeinthebuffer(i.e.,wherenextTLVshouldbeinserted)
*/ if (bnx2x_search_tlv_list(bp, &mbx->msg->req,
CHANNEL_TLV_PHYS_PORT_ID))
bnx2x_vf_mbx_resp_phys_port(bp, vf, &mbx->msg->resp, &length);
/* `New' vfs will want to know if fastpath HSI is supported, since *ifthat'snotthecasetheycouldprintintosystemlogthefact *thedriverversionmustbeupdated.
*/
bnx2x_vf_mbx_resp_fp_hsi_ver(bp, vf, &mbx->msg->resp, &length);
/* send the response */
bnx2x_vf_mbx_resp_send_msg(bp, vf, vfop_status);
}
staticbool bnx2x_vf_mbx_is_windows_vm(struct bnx2x *bp, struct vfpf_acquire_tlv *acquire)
{ /* Windows driver does one of three things: *1.Olddriverdoesn'thavebulletinboardaddressset. *2.'Middle'driversendsmc_num==32. *3.NewdriversetstheOSfield.
*/ if (!acquire->bulletin_addr ||
acquire->resc_request.num_mc_filters == 32 ||
((acquire->vfdev_info.vf_os & VF_OS_MASK) ==
VF_OS_WINDOWS)) returntrue;
returnfalse;
}
staticint bnx2x_vf_mbx_acquire_chk_dorq(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vf_mbx *mbx)
{ /* Linux drivers which correctly set the doorbell size also *sendaphysicalportrequest
*/ if (bnx2x_search_tlv_list(bp, &mbx->msg->req,
CHANNEL_TLV_PHYS_PORT_ID)) return0;
/* Issue does not exist in windows VMs */ if (bnx2x_vf_mbx_is_windows_vm(bp, &mbx->msg->req.acquire)) return0;
/* Prevent VFs with old drivers from loading, since they calculate *CIDsincorrectlyrequiringaVF-flr[VMreboot]inordertorecover *whilebeingupgraded.
*/
rc = bnx2x_vf_mbx_acquire_chk_dorq(bp, vf, mbx); if (rc) {
DP(BNX2X_MSG_IOV, "VF [%d] - Can't support acquire request due to doorbell mismatch. Please update VM driver\n",
vf->abs_vfid); goto out;
}
/* Verify the VF fastpath HSI can be supported by the loaded FW. *Linuxvfsshouldbeoblivioustochangesbetweenv0andv2.
*/ if (bnx2x_vf_mbx_is_windows_vm(bp, &mbx->msg->req.acquire))
vf->fp_hsi = acquire->vfdev_info.fp_hsi_ver; else
vf->fp_hsi = max_t(u8, acquire->vfdev_info.fp_hsi_ver,
ETH_FP_HSI_VER_2); if (vf->fp_hsi > ETH_FP_HSI_VERSION) {
DP(BNX2X_MSG_IOV, "VF [%d] - Can't support acquire request since VF requests a FW version which is too new [%02x > %02x]\n",
vf->abs_vfid, acquire->vfdev_info.fp_hsi_ver,
ETH_FP_HSI_VERSION);
rc = -EINVAL; goto out;
}
/* acquire the resources */
rc = bnx2x_vf_acquire(bp, vf, &acquire->resc_request);
/* store address of vf's bulletin board */
vf->bulletin_map = acquire->bulletin_addr; if (acquire->vfdev_info.caps & VF_CAP_SUPPORT_EXT_BULLETIN) {
DP(BNX2X_MSG_IOV, "VF[%d] supports long bulletin boards\n",
vf->abs_vfid);
vf->cfg_flags |= VF_CFG_EXT_BULLETIN;
} else {
vf->cfg_flags &= ~VF_CFG_EXT_BULLETIN;
}
staticint bnx2x_vf_filters_contain(struct vfpf_set_q_filters_tlv *filters,
u32 flags)
{ int i, cnt = 0;
for (i = 0; i < filters->n_mac_vlan_filters; i++) if ((filters->filters[i].flags & flags) == flags)
cnt++;
return cnt;
}
staticvoid bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx, struct vfpf_q_mac_vlan_filter *filter)
{
DP(msglvl, "MAC-VLAN[%d] -- flags=0x%x\n", idx, filter->flags); if (filter->flags & VFPF_Q_FILTER_VLAN_TAG_VALID)
DP_CONT(msglvl, ", vlan=%d", filter->vlan_tag); if (filter->flags & VFPF_Q_FILTER_DEST_MAC_VALID)
DP_CONT(msglvl, ", MAC=%pM", filter->mac);
DP_CONT(msglvl, "\n");
}
staticvoid bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl, struct vfpf_set_q_filters_tlv *filters)
{ int i;
if (filters->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) for (i = 0; i < filters->n_mac_vlan_filters; i++)
bnx2x_vf_mbx_dp_q_filter(bp, msglvl, i,
&filters->filters[i]);
if (filters->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED)
DP(msglvl, "RX-MASK=0x%x\n", filters->rx_mask);
if (filters->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) for (i = 0; i < filters->n_multicast; i++)
DP(msglvl, "MULTICAST=%pM\n", filters->multicast[i]);
}
/* if a mac was already set for this VF via the set vf mac ndo, we only *acceptmacconfigurationsofthatmac.Whyacceptthematall? *becausePFmayhavebeenunabletoconfigurethemacatthetime *sincequeuewasnotsetup.
*/ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) { struct vfpf_q_mac_vlan_filter *filter = NULL; int i;
for (i = 0; i < filters->n_mac_vlan_filters; i++) { if (!(filters->filters[i].flags &
VFPF_Q_FILTER_DEST_MAC_VALID)) continue;
/* once a mac was set by ndo can only accept *asinglemac...
*/ if (filter) {
BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called [%d filters]\n",
vf->abs_vfid,
filters->n_mac_vlan_filters);
rc = -EPERM; goto response;
}
filter = &filters->filters[i];
}
/* ...and only the mac set by the ndo */ if (filter &&
!ether_addr_equal(filter->mac, bulletin->mac)) {
BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n",
vf->abs_vfid);
/* if vlan was set by hypervisor we don't allow guest to config vlan */ if (bulletin->valid_bitmap & 1 << VLAN_VALID) { /* search for vlan filters */
if (bnx2x_vf_filters_contain(filters,
VFPF_Q_FILTER_VLAN_TAG_VALID)) {
BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n",
vf->abs_vfid);
rc = -EPERM; goto response;
}
}
if (tpa_tlv->tpa_client_info.max_sges_for_packet >
U_ETH_MAX_SGES_FOR_PACKET) {
rc = -EINVAL;
BNX2X_ERR("TPA update: max_sges received %d, max is %d\n",
tpa_tlv->tpa_client_info.max_sges_for_packet,
U_ETH_MAX_SGES_FOR_PACKET);
}
if (tpa_tlv->tpa_client_info.max_tpa_queues > MAX_AGG_QS(bp)) {
rc = -EINVAL;
BNX2X_ERR("TPA update: max_tpa_queues received %d, max is %d\n",
tpa_tlv->tpa_client_info.max_tpa_queues,
MAX_AGG_QS(bp));
}
if (vf->state == VF_LOST) { /* Just ack the FW and return if VFs are lost *incaseofparityerror.VFsaresupposedtobetimedout *onwaitingforPFresponse.
*/
DP(BNX2X_MSG_IOV, "VF 0x%x lost, not handling the request\n", vf->abs_vfid);
/* check if tlv type is known */ if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) { /* Lock the per vf op mutex and note the locker's identity. *Theunlockwilltakeplaceinmbxresponse.
*/
bnx2x_lock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
/* switch on the opcode */ switch (mbx->first_tlv.tl.type) { case CHANNEL_TLV_ACQUIRE:
bnx2x_vf_mbx_acquire(bp, vf, mbx); return; case CHANNEL_TLV_INIT:
bnx2x_vf_mbx_init_vf(bp, vf, mbx); return; case CHANNEL_TLV_SETUP_Q:
bnx2x_vf_mbx_setup_q(bp, vf, mbx); return; case CHANNEL_TLV_SET_Q_FILTERS:
bnx2x_vf_mbx_set_q_filters(bp, vf, mbx); return; case CHANNEL_TLV_TEARDOWN_Q:
bnx2x_vf_mbx_teardown_q(bp, vf, mbx); return; case CHANNEL_TLV_CLOSE:
bnx2x_vf_mbx_close_vf(bp, vf, mbx); return; case CHANNEL_TLV_RELEASE:
bnx2x_vf_mbx_release_vf(bp, vf, mbx); return; case CHANNEL_TLV_UPDATE_RSS:
bnx2x_vf_mbx_update_rss(bp, vf, mbx); return; case CHANNEL_TLV_UPDATE_TPA:
bnx2x_vf_mbx_update_tpa(bp, vf, mbx); return;
}
} else { /* unknown TLV - this may belong to a VF driver from the future *-aversionwrittenafterthisPFdriverwaswritten,which *supportsfeaturesunknownasofyet.Toobadsincewedon't *supportthem.Orthismaybebecausesomeonewroteacrappy *VFdriverandissendinggarbageoverthechannel.
*/
BNX2X_ERR("unknown TLV. type %d length %d vf->state was %d. first 20 bytes of mailbox buffer:\n",
mbx->first_tlv.tl.type, mbx->first_tlv.tl.length,
vf->state); for (i = 0; i < 20; i++)
DP_CONT(BNX2X_MSG_IOV, "%x ",
mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
}
/* can we respond to VF (do we have an address for it?) */ if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) { /* notify the VF that we do not support this request */
bnx2x_vf_mbx_resp(bp, vf, PFVF_STATUS_NOT_SUPPORTED);
} else { /* can't send a response since this VF is unknown to us *justacktheFWtoreleasethemailboxandunlock *thechannel.
*/
storm_memset_vf_mbx_ack(bp, vf->abs_vfid); /* Firmware ack should be written before unlocking channel */
bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
}
}
/* check if the vf_id is valid */ if (vfpf_event->vf_id - BP_VFDB(bp)->sriov.first_vf_in_pf >
BNX2X_NR_VIRTFN(bp)) {
BNX2X_ERR("Illegal vf_id %d max allowed: %d\n",
vfpf_event->vf_id, BNX2X_NR_VIRTFN(bp)); return;
}
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.