/* Enable host coalescing in the transition to INIT state */ if (test_bit(BNX2X_Q_FLG_HC, &init_p->rx.flags))
__set_bit(BNX2X_Q_FLG_HC_EN, &init_p->rx.flags);
if (test_bit(BNX2X_Q_FLG_HC, &init_p->tx.flags))
__set_bit(BNX2X_Q_FLG_HC_EN, &init_p->tx.flags);
if (bnx2x_get_q_logical_state(bp, q_params.q_obj) ==
BNX2X_Q_LOGICAL_STATE_STOPPED) {
DP(BNX2X_MSG_IOV, "queue was already stopped. Aborting gracefully\n"); goto out;
}
/* Run Queue 'destruction' ramrods */ for (i = 0; i < ARRAY_SIZE(cmds); i++) {
q_params.cmd = cmds[i];
rc = bnx2x_queue_state_change(bp, &q_params); if (rc) {
BNX2X_ERR("Failed to run Queue command %d\n", cmds[i]); return rc;
}
}
out: /* Clean Context */ if (bnx2x_vfq(vf, qid, cxt)) {
bnx2x_vfq(vf, qid, cxt)->ustorm_ag_context.cdu_usage = 0;
bnx2x_vfq(vf, qid, cxt)->xstorm_ag_context.cdu_reserved = 0;
}
return0;
}
staticvoid
bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
{ struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid); if (vf) { /* the first igu entry belonging to VFs of this PF */ if (!BP_VFDB(bp)->first_vf_igu_entry)
BP_VFDB(bp)->first_vf_igu_entry = igu_sb_id;
/* the first igu entry belonging to this VF */ if (!vf_sb_count(vf))
vf->igu_base_id = igu_sb_id;
int bnx2x_vf_mac_vlan_config_list(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vf_mac_vlan_filters *filters, int qid, bool drv_only)
{ int rc = 0, i;
DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) return -EINVAL;
/* Prepare ramrod params */ for (i = 0; i < filters->count; i++) {
rc = bnx2x_vf_mac_vlan_config(bp, vf, qid,
&filters->filters[i], drv_only); if (rc) break;
}
/* Rollback if needed */ if (i != filters->count) {
BNX2X_ERR("Managed only %d/%d filters - rolling back\n",
i, filters->count); while (--i >= 0) { if (!filters->filters[i].applied) continue;
filters->filters[i].add = !filters->filters[i].add;
bnx2x_vf_mac_vlan_config(bp, vf, qid,
&filters->filters[i],
drv_only);
}
}
/* It's our responsibility to free the filters */
kfree(filters);
return rc;
}
int bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid, struct bnx2x_vf_queue_construct_params *qctor)
{ int rc;
int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
bnx2x_mac_addr_t *mcasts, int mc_num, bool drv_only)
{ struct bnx2x_mcast_list_elem *mc = NULL; struct bnx2x_mcast_ramrod_params mcast; int rc, i;
DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
/* Prepare Multicast command */
memset(&mcast, 0, sizeof(struct bnx2x_mcast_ramrod_params));
mcast.mcast_obj = &vf->mcast_obj; if (drv_only)
set_bit(RAMROD_DRV_CLR_ONLY, &mcast.ramrod_flags); else
set_bit(RAMROD_COMP_WAIT, &mcast.ramrod_flags); if (mc_num) {
mc = kcalloc(mc_num, sizeof(struct bnx2x_mcast_list_elem),
GFP_KERNEL); if (!mc) {
BNX2X_ERR("Cannot Configure multicasts due to lack of memory\n"); return -ENOMEM;
}
}
if (mc_num) {
INIT_LIST_HEAD(&mcast.mcast_list); for (i = 0; i < mc_num; i++) {
mc[i].mac = mcasts[i];
list_add_tail(&mc[i].link,
&mcast.mcast_list);
}
/* add new mcasts */
mcast.mcast_list_len = mc_num;
rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_SET); if (rc)
BNX2X_ERR("Failed to set multicasts\n");
} else { /* clear existing mcasts */
rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL); if (rc)
BNX2X_ERR("Failed to remove multicasts\n");
}
staticvoid bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf)
{ /* Reset vf in IGU interrupts are still disabled */
bnx2x_vf_igu_reset(bp, vf);
/* pretend to enable the vf with the PBF */
bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
REG_WR(bp, PBF_REG_DISABLE_VF, 0);
bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
}
dev = pci_get_domain_bus_and_slot(vf->domain, vf->bus, vf->devfn); if (!dev) returnfalse;
pending = bnx2x_is_pcie_pending(dev);
pci_dev_put(dev);
return pending;
}
int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
{ /* Verify no pending pci transactions */ if (bnx2x_vf_is_pcie_pending(bp, abs_vfid))
BNX2X_ERR("PCIE Transactions still pending\n");
return0;
}
/* must be called after the number of PF queues and the number of VFs are *bothknown
*/ staticvoid
bnx2x_iov_static_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
{ struct vf_pf_resc_request *resc = &vf->alloc_resc;
/* will be set only during VF-ACQUIRE */
resc->num_rxqs = 0;
resc->num_txqs = 0;
/* FW cleanup command - poll for the results */ if (bnx2x_send_final_clnup(bp, (u8)FW_VF_HANDLE(vf->abs_vfid),
poll_cnt))
BNX2X_ERR("VF[%d] Final cleanup timed-out\n", vf->abs_vfid);
/* verify TX hw is flushed */
bnx2x_tx_hw_flushed(bp, poll_cnt);
}
/* the cleanup operations are valid if and only if the VF *wasfirstacquired.
*/ for (i = 0; i < vf_rxq_count(vf); i++) {
rc = bnx2x_vf_queue_flr(bp, vf, i); if (rc) goto out;
}
/* re-open the mailbox */
bnx2x_vf_enable_mbx(bp, vf->abs_vfid); return;
out:
BNX2X_ERR("vf[%d:%d] failed flr: rc %d\n",
vf->abs_vfid, i, rc);
}
staticvoid bnx2x_vf_flr_clnup(struct bnx2x *bp)
{ struct bnx2x_virtf *vf; int i;
for (i = 0; i < BNX2X_NR_VIRTFN(bp); i++) { /* VF should be RESET & in FLR cleanup states */ if (bnx2x_vf(bp, i, state) != VF_RESET ||
!bnx2x_vf(bp, i, flr_clnup_stage)) continue;
DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n",
i, BNX2X_NR_VIRTFN(bp));
vf = BP_VF(bp, i);
/* lock the vf pf channel */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
/* invoke the VF FLR SM */
bnx2x_vf_flr(bp, vf);
/* mark the VF to be ACKED and continue */
vf->flr_clnup_stage = false;
bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
}
/* Acknowledge the handled VFs. *weareacknowledgeallthevfswhichanflrwasrequestedfor,even *ifamongstthemtherearesuchthatweneveropened,sincethemcp *willinterruptusimmediatelyagainifweonlyacksomeofthebits, *resultinginanendlessloop.ThiscanhappenforexampleinKVM *wherean'allones'flrrequestissometimesgivenbyhypervisor
*/
DP(BNX2X_MSG_MCP, "DRV_STATUS_VF_DISABLED ACK for vfs 0x%x 0x%x\n",
bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]); for (i = 0; i < FLRD_VFS_DWORDS; i++)
SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i],
bp->vfdb->flrd_vfs[i]);
/* clear the acked bits - better yet if the MCP implemented *writetoclearsemantics
*/ for (i = 0; i < FLRD_VFS_DWORDS; i++)
SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i], 0);
}
void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
{ int i;
/* Read FLR'd VFs */ for (i = 0; i < FLRD_VFS_DWORDS; i++)
bp->vfdb->flrd_vfs[i] = SHMEM2_RD(bp, mcp_vf_disabled[i]);
DP(BNX2X_MSG_MCP, "DRV_STATUS_VF_DISABLED received for vfs 0x%x 0x%x\n",
bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
if (reset) { /* set as reset and ready for cleanup */
vf->state = VF_RESET;
vf->flr_clnup_stage = true;
DP(BNX2X_MSG_IOV, "Initiating Final cleanup for VF %d\n",
vf->abs_vfid);
}
}
/* do the FLR cleanup for all marked VFs*/
bnx2x_vf_flr_clnup(bp);
}
/* IOV global initialization routines */ void bnx2x_iov_init_dq(struct bnx2x *bp)
{ if (!IS_SRIOV(bp)) return;
/* Set the DQ such that the CID reflect the abs_vfid */
REG_WR(bp, DORQ_REG_VF_NORM_VF_BASE, 0);
REG_WR(bp, DORQ_REG_MAX_RVFID_SIZE, ilog2(BNX2X_MAX_NUM_OF_VFS));
/* Set VFs starting CID. If its > 0 the preceding CIDs are belong to *thePFL2queues
*/
REG_WR(bp, DORQ_REG_VF_NORM_CID_BASE, BNX2X_FIRST_VF_CID);
/* The VF window size is the log2 of the max number of CIDs per VF */
REG_WR(bp, DORQ_REG_VF_NORM_CID_WND_SIZE, BNX2X_VF_CID_WND);
/* The VF doorbell size 0 - *B, 4 - 128B. We set it here to match *thePfdoorbellsizealthoughthe2areindependent.
*/
REG_WR(bp, DORQ_REG_VF_NORM_CID_OFST, 3);
/* No security checks for now - *configuresinglerule(outof16)mask=0x1,value=0x0, *CIDrange0-0x1ffff
*/
REG_WR(bp, DORQ_REG_VF_TYPE_MASK_0, 1);
REG_WR(bp, DORQ_REG_VF_TYPE_VALUE_0, 0);
REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
/* set the VF doorbell threshold. This threshold represents the amount *ofdoorbellsallowedinthemainDORQfifoforaspecificVF.
*/
REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 64);
}
DP(BNX2X_MSG_IOV, "IOV info[%d]: first vf %d, nres %d, cap 0x%x, ctrl 0x%x, total %d, initial %d, num vfs %d, offset %d, stride %d, page size 0x%x\n",
BP_FUNC(bp),
iov->first_vf_in_pf, iov->nres, iov->cap, iov->ctrl, iov->total,
iov->initial, iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz);
return0;
}
/* must be called after PF bars are mapped */ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, int num_vfs_param)
{ int err, i; struct bnx2x_sriov *iov; struct pci_dev *dev = bp->pdev;
bp->vfdb = NULL;
/* verify is pf */ if (IS_VF(bp)) return0;
/* verify sriov capability is present in configuration space */ if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV)) return0;
/* verify chip revision */ if (CHIP_IS_E1x(bp)) return0;
/* check if SRIOV support is turned off */ if (!num_vfs_param) return0;
/* SRIOV assumes that num of PF CIDs < BNX2X_FIRST_VF_CID */ if (BNX2X_L2_MAX_CID(bp) >= BNX2X_FIRST_VF_CID) {
BNX2X_ERR("PF cids %d are overspilling into vf space (starts at %d). Abort SRIOV\n",
BNX2X_L2_MAX_CID(bp), BNX2X_FIRST_VF_CID); return0;
}
/* SRIOV can be enabled only with MSIX */ if (int_mode_param == BNX2X_INT_MODE_MSI ||
int_mode_param == BNX2X_INT_MODE_INTX) {
BNX2X_ERR("Forced MSI/INTx mode is incompatible with SRIOV\n"); return0;
}
/* verify ari is enabled */ if (!pci_ari_enabled(bp->pdev->bus)) {
BNX2X_ERR("ARI not supported (check pci bridge ARI forwarding), SRIOV can not be enabled\n"); return0;
}
/* verify igu is in normal mode */ if (CHIP_INT_MODE_IS_BC(bp)) {
BNX2X_ERR("IGU not normal mode, SRIOV can not be enabled\n"); return0;
}
/* allocate the vfs database */
bp->vfdb = kzalloc(sizeof(*(bp->vfdb)), GFP_KERNEL); if (!bp->vfdb) {
BNX2X_ERR("failed to allocate vf database\n");
err = -ENOMEM; goto failed;
}
/* get the sriov info - Linux already collected all the pertinent *information,howeverthesriovstructureisfortheprivateuse *ofthepcimodule.Alsowewantthisinformationregardless *ofthehyper-visor.
*/
iov = &(bp->vfdb->sriov);
err = bnx2x_sriov_info(bp, iov); if (err) goto failed;
/* SR-IOV capability was enabled but there are no VFs*/ if (iov->total == 0) {
err = 0; goto failed;
}
DP(BNX2X_MSG_IOV, "num_vfs_param was %d, nr_virtfn was %d\n",
num_vfs_param, iov->nr_virtfn);
/* allocate the vf array */
bp->vfdb->vfs = kcalloc(BNX2X_NR_VIRTFN(bp), sizeof(struct bnx2x_virtf),
GFP_KERNEL); if (!bp->vfdb->vfs) {
BNX2X_ERR("failed to allocate vf array\n");
err = -ENOMEM; goto failed;
}
/* Initial VF init - index and abs_vfid - nr_virtfn must be set */
for_each_vf(bp, i) {
bnx2x_vf(bp, i, index) = i;
bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
bnx2x_vf(bp, i, state) = VF_FREE;
mutex_init(&bnx2x_vf(bp, i, op_mutex));
bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE; /* enable spoofchk by default */
bnx2x_vf(bp, i, spoofchk) = 1;
}
/* re-read the IGU CAM for VFs - index and abs_vfid must be set */ if (!bnx2x_get_vf_igu_cam_info(bp)) {
BNX2X_ERR("No entries in IGU CAM for vfs\n");
err = -EINVAL; goto failed;
}
/* allocate the queue arrays for all VFs */
bp->vfdb->vfqs = kcalloc(BNX2X_MAX_NUM_VF_QUEUES, sizeof(struct bnx2x_vf_queue),
GFP_KERNEL);
if (!bp->vfdb->vfqs) {
BNX2X_ERR("failed to allocate vf queue array\n");
err = -ENOMEM; goto failed;
}
/* Prepare the VFs event synchronization mechanism */
mutex_init(&bp->vfdb->event_mutex);
mutex_init(&bp->vfdb->bulletin_mutex);
if (SHMEM2_HAS(bp, sriov_switch_mode))
SHMEM2_WR(bp, sriov_switch_mode, SRIOV_SWITCH_MODE_VEB);
/* called by bnx2x_chip_cleanup */ int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
{ int i;
if (!IS_SRIOV(bp)) return0;
/* release all the VFs */
for_each_vf(bp, i)
bnx2x_vf_release(bp, BP_VF(bp, i));
return0;
}
/* called by bnx2x_init_hw_func, returns the next ilt line */ int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line)
{ int i; struct bnx2x_ilt *ilt = BP_ILT(bp);
if (!IS_SRIOV(bp)) return line;
/* set vfs ilt lines */ for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) { struct hw_dma *hw_cxt = BP_VF_CXT_PAGE(bp, i);
/* If there are pending mcast commands - send them */ if (vf->mcast_obj.check_pending(&vf->mcast_obj)) {
rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); if (rc < 0)
BNX2X_ERR("Failed to send pending mcast commands: %d\n",
rc);
}
}
/* fcoe adds one global request and one queue request */
num_queues_req = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe;
first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
(is_fcoe ? 0 : 1);
DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS), "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
first_queue_query_index + num_queues_req);
/* all stats are coalesced to the leading queue */ if (vf->cfg_flags & VF_CFG_STATS_COALESCE) break;
}
}
bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
}
/* CORE VF API */ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, struct vf_pf_resc_request *resc)
{ int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vf->index) *
BNX2X_CIDS_PER_VF;
union cdu_context *base_cxt = (union cdu_context *)
BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
(base_vf_cid & (ILT_PAGE_CIDS-1)); int i;
/* if state is 'acquired' the VF was not released or FLR'd, in *thiscasethereturnedresourcesmatchtheacquiredalready *acquiredresources.Verifythattherequestednumbersdo *notexceedthealreadyacquirednumbers.
*/ if (vf->state == VF_ACQUIRED) {
DP(BNX2X_MSG_IOV, "VF[%d] Trying to re-acquire resources (VF was not released or FLR'd)\n",
vf->abs_vfid);
if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
BNX2X_ERR("VF[%d] When re-acquiring resources, requested numbers must be <= then previously acquired numbers\n",
vf->abs_vfid); return -EINVAL;
} return0;
}
/* Otherwise vf state must be 'free' or 'reset' */ if (vf->state != VF_FREE && vf->state != VF_RESET) {
BNX2X_ERR("VF[%d] Can not acquire a VF with state %d\n",
vf->abs_vfid, vf->state); return -EINVAL;
}
/* static allocation: *theglobalmaximumnumberarefixedperVF.Failtherequestif *requestednumberexceedtheseglobals
*/ if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
DP(BNX2X_MSG_IOV, "cannot fulfill vf resource request. Placing maximal available values in response\n"); /* set the max resource in the vf */ return -ENOMEM;
}
/* Set resources counters - 0 request means max available */
vf_sb_count(vf) = resc->num_sbs;
vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)
{ struct bnx2x_func_init_params func_init = {0}; int i;
/* the sb resources are initialized at this point, do the *FW/HWinitializations
*/
for_each_vf_sb(vf, i)
bnx2x_init_sb(bp, (dma_addr_t)sb_map[i], vf->abs_vfid, true,
vf_igu_sb(vf, i), vf_igu_sb(vf, i));
/* Sanity checks */ if (vf->state != VF_ACQUIRED) {
DP(BNX2X_MSG_IOV, "VF[%d] is not in VF_ACQUIRED, but %d\n",
vf->abs_vfid, vf->state); return -EINVAL;
}
/* let FLR complete ... */
msleep(100);
/* FLR cleanup epilogue */ if (bnx2x_vf_flr_clnup_epilog(bp, vf->abs_vfid)) return -EBUSY;
int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
{ int rc = 0, i;
DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
/* Close all queues */ for (i = 0; i < vf_rxq_count(vf); i++) {
rc = bnx2x_vf_queue_teardown(bp, vf, i); if (rc) goto op_err;
}
/* disable the interrupts */
DP(BNX2X_MSG_IOV, "disabling igu\n");
bnx2x_vf_igu_disable(bp, vf);
/* disable the VF */
DP(BNX2X_MSG_IOV, "clearing qtbl\n");
bnx2x_vf_clr_qtbl(bp, vf);
/* need to make sure there are no outstanding stats ramrods which may *causethedevicetoaccesstheVF'sstatsbufferwhichitwillfree *assoonaswereturnfromthecloseflow.
*/
{ struct set_vf_state_cookie cookie;
/* VF release can be called either: 1. The VF was acquired but *notenabled2.thevfwasenabledorintheprocessofbeing *enabled
*/ int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf)
{ int rc;
/* record the locking op */
vf->op_current = CHANNEL_TLV_NONE;
/* lock the channel */
mutex_unlock(&vf->op_mutex);
/* log the unlock */
DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
vf->abs_vfid, current_tlv);
}
staticint bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable)
{ struct bnx2x_queue_state_params q_params;
u32 prev_flags; int i, rc;
/* Verify changes are needed and record current Tx switching state */
prev_flags = bp->flags; if (enable)
bp->flags |= TX_SWITCHING; else
bp->flags &= ~TX_SWITCHING; if (prev_flags == bp->flags) return0;
/* Verify state enables the sending of queue ramrods */ if ((bp->state != BNX2X_STATE_OPEN) ||
(bnx2x_get_q_logical_state(bp,
&bnx2x_sp_obj(bp, &bp->fp[0]).q_obj) !=
BNX2X_Q_LOGICAL_STATE_ACTIVE)) return0;
int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
{ struct bnx2x *bp = netdev_priv(pci_get_drvdata(dev));
if (!IS_SRIOV(bp)) {
BNX2X_ERR("failed to configure SR-IOV since vfdb was not allocated. Check dmesg for errors in probe stage\n"); return -EINVAL;
}
DP(BNX2X_MSG_IOV, "bnx2x_sriov_configure called with %d, BNX2X_NR_VIRTFN(bp) was %d\n",
num_vfs_param, BNX2X_NR_VIRTFN(bp));
/* HW channel is only operational when PF is up */ if (bp->state != BNX2X_STATE_OPEN) {
BNX2X_ERR("VF num configuration via sysfs not supported while PF is down\n"); return -EINVAL;
}
/* we are always bound by the total_vfs in the configuration space */ if (num_vfs_param > BNX2X_NR_VIRTFN(bp)) {
BNX2X_ERR("truncating requested number of VFs (%d) down to maximum allowed (%d)\n",
num_vfs_param, BNX2X_NR_VIRTFN(bp));
num_vfs_param = BNX2X_NR_VIRTFN(bp);
}
/* set local queue arrays */
vf->vfqs = &bp->vfdb->vfqs[qcount];
qcount += vf_sb_count(vf);
bnx2x_iov_static_resc(bp, vf);
}
/* prepare msix vectors in VF configuration space - the value in the *PCIconfigurationspaceshouldbetheindexofthelastentry, *namelyonelessthantheactualsizeofthetable
*/ for (vf_idx = first_vf; vf_idx < first_vf + req_vfs; vf_idx++) {
bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf_idx));
REG_WR(bp, PCICFG_OFFSET + GRC_CONFIG_REG_VF_MSIX_CONTROL,
num_vf_queues - 1);
DP(BNX2X_MSG_IOV, "set msix vec num in VF %d cfg space to %d\n",
vf_idx, num_vf_queues - 1);
}
bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
/* enable sriov. This will probe all the VFs, and consequentially cause *the"acquire"messagestoappearontheVFPFchannel.
*/
DP(BNX2X_MSG_IOV, "about to call enable sriov\n");
bnx2x_disable_sriov(bp);
rc = bnx2x_set_pf_tx_switching(bp, true); if (rc) return rc;
void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp)
{ int vfidx; struct pf_vf_bulletin_content *bulletin;
DP(BNX2X_MSG_IOV, "configuring vlan for VFs from sp-task\n");
for_each_vf(bp, vfidx) {
bulletin = BP_VF_BULLETIN(bp, vfidx); if (bulletin->valid_bitmap & (1 << VLAN_VALID))
bnx2x_set_vf_vlan(bp->dev, vfidx, bulletin->vlan, 0,
htons(ETH_P_8021Q));
}
}
void bnx2x_disable_sriov(struct bnx2x *bp)
{ if (pci_vfs_assigned(bp->pdev)) {
DP(BNX2X_MSG_IOV, "Unloading driver while VFs are assigned - VFs will not be deallocated\n"); return;
}
pci_disable_sriov(bp->pdev);
}
staticint bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx, struct bnx2x_virtf **vf, struct pf_vf_bulletin_content **bulletin, bool test_queue)
{ if (bp->state != BNX2X_STATE_OPEN) {
BNX2X_ERR("PF is down - can't utilize iov-related functionality\n"); return -EINVAL;
}
if (!IS_SRIOV(bp)) {
BNX2X_ERR("sriov is disabled - can't utilize iov-related functionality\n"); return -EINVAL;
}
if (vfidx >= BNX2X_NR_VIRTFN(bp)) {
BNX2X_ERR("VF is uninitialized - can't utilize iov-related functionality. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
vfidx, BNX2X_NR_VIRTFN(bp)); return -EINVAL;
}
if (!*vf) {
BNX2X_ERR("Unable to get VF structure for vfidx %d\n", vfidx); return -EINVAL;
}
if (test_queue && !(*vf)->vfqs) {
BNX2X_ERR("vfqs struct is null. Was this invoked before dynamically enabling SR-IOV? vfidx was %d\n",
vfidx); return -EINVAL;
}
if (!*bulletin) {
BNX2X_ERR("Bulletin Board struct is null for vfidx %d\n",
vfidx); return -EINVAL;
}
ivi->vf = vfidx;
ivi->qos = 0;
ivi->max_tx_rate = 10000; /* always 10G. TBA take from link struct */
ivi->min_tx_rate = 0;
ivi->spoofchk = vf->spoofchk ? 1 : 0;
ivi->linkstate = vf->link_cfg; if (vf->state == VF_ENABLED) { /* mac and vlan are in vlan_mac objects */ if (bnx2x_validate_vf_sp_objs(bp, vf, false)) {
mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac, 0, ETH_ALEN);
vlan_obj->get_n_elements(bp, vlan_obj, 1,
(u8 *)&ivi->vlan, 0,
VLAN_HLEN);
}
} else {
mutex_lock(&bp->vfdb->bulletin_mutex); /* mac */ if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID)) /* mac configured by ndo so its in bulletin board */
memcpy(&ivi->mac, bulletin->mac, ETH_ALEN); else /* function has not been loaded yet. Show mac as 0s */
eth_zero_addr(ivi->mac);
/* vlan */ if (bulletin->valid_bitmap & (1 << VLAN_VALID)) /* vlan configured by ndo so its in bulletin board */
ivi->vlan = bulletin->vlan; else /* function has not been loaded yet. Show vlans as 0s */
ivi->vlan = 0;
mutex_unlock(&bp->vfdb->bulletin_mutex);
}
return0;
}
/* New mac for VF. Consider these cases: *1.VFhasn'tbeenacquiredyet-savethemacinlocalbulletinboardand *supplyatacquire. *2.VFhasalreadybeenacquiredbuthasnotyetinitialized-storeinlocal *bulletinboard.macwillbepostedonVFbulletinboardafterVFinit.VF *willconfigurethismacwhenitisready. *3.VFhasalreadyinitializedbuthasnotyetsetupaqueue-postthenew *maconVF'sbulletinboardrightnow.VFwillconfigurethismacwhenit *isready. *4.VFhasalreadysetaqueue-deleteanymacsalreadyconfiguredforthis *queueandmanuallyconfigthenewmac. *Inanyevent,oncethisfunctionhasbeencalledrefuseanyattemptsbythe *VFtoconfigureanymacforitselfexceptforthismac.Incaseofarace *wheretheVFfailstoseethenewpostonitsbulletinboardbeforesendinga *macconfigurationrequest,thePFwillsimplyfailtherequestandVFcantry *againafterconsultingitsbulletinboard.
*/ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
{ struct bnx2x *bp = netdev_priv(dev); int rc, q_logical_state; struct bnx2x_virtf *vf = NULL; struct pf_vf_bulletin_content *bulletin = NULL;
if (!is_valid_ether_addr(mac)) {
BNX2X_ERR("mac address invalid\n"); return -EINVAL;
}
/* sanity and init */
rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true); if (rc) return rc;
mutex_lock(&bp->vfdb->bulletin_mutex);
/* update PF's copy of the VF's bulletin. Will no longer accept mac *configurationrequestsfromvfunlessmatchthismac
*/
bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
memcpy(bulletin->mac, mac, ETH_ALEN);
/* Post update on VF's bulletin board */
rc = bnx2x_post_vf_bulletin(bp, vfidx);
/* release lock before checking return code */
mutex_unlock(&bp->vfdb->bulletin_mutex);
if (rc) {
BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx); return rc;
}
q_logical_state =
bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)); if (vf->state == VF_ENABLED &&
q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) { /* configure the mac in device on this vf's queue */ unsignedlong ramrod_flags = 0; struct bnx2x_vlan_mac_obj *mac_obj;
/* User should be able to see failure reason in system logs */ if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) return -EINVAL;
/* must lock vfpf channel to protect against vf flows */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
/* remove existing eth macs */
mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true); if (rc) {
BNX2X_ERR("failed to delete eth macs\n");
rc = -EINVAL; goto out;
}
/* remove existing uc list macs */
rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true); if (rc) {
BNX2X_ERR("failed to delete uc_list macs\n");
rc = -EINVAL; goto out;
}
/* configure the new mac to device */
__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
BNX2X_ETH_MAC, &ramrod_flags);
/* need to remove/add the VF's accept_any_vlan bit */
accept_flags = bnx2x_leading_vfq(vf, accept_flags); if (accept)
set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags); else
clear_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags);
/* sanity and init */
rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true); if (rc) return rc;
/* update PF's copy of the VF's bulletin. No point in posting the vlan *totheVFsinceitdoesn'thaveanythingtodowithit.Butituseful *tostoreithereincasetheVFisnotupyetandwecanonly *configurethevlanlaterwhenitdoes.Treatvlanid0asremovethe *Hosttag.
*/
mutex_lock(&bp->vfdb->bulletin_mutex);
/* Update the Queue state */
rc = bnx2x_queue_state_change(bp, &q_params); if (rc) {
BNX2X_ERR("Failed to %s spoofchk on VF %d - vfq %d\n",
val ? "enable" : "disable", idx, i); goto out;
}
}
out: if (!rc)
DP(BNX2X_MSG_IOV, "%s spoofchk for VF[%d]\n", val ? "Enabled" : "Disabled",
idx);
return rc;
}
/* crc is the first field in the bulletin board. Compute the crc over the *entirebulletinboardexcludingthecrcfielditself.Usethelengthfield *astheBulletinBoardwaspostedbyaPFwithpossiblyadifferentversion *fromthevfwhichwillsampleit.Therefore,thelengthiscomputedbythe *PFandthenusedblindlybytheVF.
*/
u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin)
{ return crc32(BULLETIN_CRC_SEED,
((u8 *)bulletin) + sizeof(bulletin->crc),
bulletin->length - sizeof(bulletin->crc));
}
/* Check for new posts on the bulletin board */ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
{ struct pf_vf_bulletin_content *bulletin; int attempts;
/* sampling structure in mid post may result with corrupted data *validatecrctoensurecoherency.
*/ for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
u32 crc;
/* sample the bulletin board */
memcpy(&bp->shadow_bulletin, bp->pf2vf_bulletin, sizeof(union pf_vf_bulletin));
if (attempts >= BULLETIN_ATTEMPTS) {
BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
attempts); return PFVF_BULLETIN_CRC_ERR;
}
bulletin = &bp->shadow_bulletin.content;
/* bulletin board hasn't changed since last sample */ if (bp->old_bulletin.version == bulletin->version) return PFVF_BULLETIN_UNCHANGED;
/* the mac address in bulletin board is valid and is new */ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID &&
!ether_addr_equal(bulletin->mac, bp->old_bulletin.mac)) { /* update new mac to net device */
eth_hw_addr_set(bp->dev, bulletin->mac);
}
bp->vf_link_vars.line_speed = bulletin->link_speed;
bp->vf_link_vars.link_report_flags = 0; /* Link is down */ if (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
&bp->vf_link_vars.link_report_flags); /* Full DUPLEX */ if (bulletin->link_flags & VFPF_LINK_REPORT_FULL_DUPLEX)
__set_bit(BNX2X_LINK_REPORT_FD,
&bp->vf_link_vars.link_report_flags); /* Rx Flow Control is ON */ if (bulletin->link_flags & VFPF_LINK_REPORT_RX_FC_ON)
__set_bit(BNX2X_LINK_REPORT_RX_FC_ON,
&bp->vf_link_vars.link_report_flags); /* Tx Flow Control is ON */ if (bulletin->link_flags & VFPF_LINK_REPORT_TX_FC_ON)
__set_bit(BNX2X_LINK_REPORT_TX_FC_ON,
&bp->vf_link_vars.link_report_flags);
__bnx2x_link_report(bp);
}
/* copy new bulletin board to bp */
memcpy(&bp->old_bulletin, bulletin, sizeof(struct pf_vf_bulletin_content));
/* if channel is down we need to self destruct */ if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN)
bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
BNX2X_MSG_IOV);
}
void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
{ /* vf doorbells are embedded within the regview */ return bp->regview + PXP_VF_ADDR_DB_START;
}
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.