/* bnx2x_sriov.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation * Copyright 2014 QLogic Corporation * All rights reserved * * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other QLogic software provided under a * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior <ariel.elior@qlogic.com> * Written by: Shmulik Ravid * Ariel Elior <ariel.elior@qlogic.com> *
*/ #include"bnx2x.h" #include"bnx2x_init.h" #include"bnx2x_cmn.h" #include"bnx2x_sp.h" #include <linux/crc32.h> #include <linux/if_vlan.h>
/* 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);
/* Setup-op flags: * collect statistics, zero statistics, local-switching, security, * OV for Flex10, RSS and MCAST for leading
*/ if (test_bit(BNX2X_Q_FLG_STATS, &setup_p->flags))
__set_bit(BNX2X_Q_FLG_ZERO_STATS, &setup_p->flags);
/* for VFs, enable tx switching, bd coherency, and mac address * anti-spoofing
*/
__set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags);
__set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags); if (vf->spoofchk)
__set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags); else
__clear_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->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;
}
return 0;
}
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");
}
/* VF enable primitives * when pretend is required the caller is responsible * for calling pretend prior to calling these routines
*/
/* internal vf enable - until vf is enabled internally all transactions * are blocked. This routine should always be called last with pretend.
*/ staticvoid bnx2x_vf_enable_internal(struct bnx2x *bp, u8 enable)
{
REG_WR(bp, PGLUE_B_REG_INTERNAL_VFID_ENABLE, enable ? 1 : 0);
}
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");
return 0;
}
/* must be called after the number of PF queues and the number of VFs are * both known
*/ 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 * was first acquired.
*/ 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. * we are acknowledge all the vfs which an flr was requested for, even * if amongst them there are such that we never opened, since the mcp * will interrupt us immediately again if we only ack some of the bits, * resulting in an endless loop. This can happen for example in KVM * where an 'all ones' flr request is sometimes given by hyper visor
*/
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 * write to clear semantics
*/ 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 * the PF L2 queues
*/
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 * the Pf doorbell size although the 2 are independent.
*/
REG_WR(bp, DORQ_REG_VF_NORM_CID_OFST, 3);
/* No security checks for now - * configure single rule (out of 16) mask = 0x1, value = 0x0, * CID range 0 - 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 * of doorbells allowed in the main DORQ fifo for a specific VF.
*/
REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 64);
}
/* read the SRIOV capability structure * The fields can be read via configuration read or * directly from the device (starting at offset PCICFG_OFFSET)
*/ if (bnx2x_sriov_pci_cfg_info(bp, iov)) return -ENODEV;
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);
return 0;
}
/* 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)) return 0;
/* verify sriov capability is present in configuration space */ if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV)) return 0;
/* verify chip revision */ if (CHIP_IS_E1x(bp)) return 0;
/* check if SRIOV support is turned off */ if (!num_vfs_param) return 0;
/* 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); return 0;
}
/* 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"); return 0;
}
/* 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"); return 0;
}
/* 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"); return 0;
}
/* 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, however the sriov structure is for the private use * of the pci module. Also we want this information regardless * of the hyper-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);
/* init mcast object - This object will be re-initialized * during VF-ACQUIRE with the proper cl_id and cid. * It needs to be initialized here so that it can be safely * handled by a subsequent FLR flow.
*/
bnx2x_init_mcast_obj(bp, &vf->mcast_obj, 0xFF,
0xFF, 0xFF, 0xFF,
bnx2x_vf_sp(bp, vf, mcast_rdata),
bnx2x_vf_sp_map(bp, vf, mcast_rdata),
BNX2X_FILTER_MCAST_PENDING,
&vf->filter_state,
BNX2X_OBJ_TYPE_RX_TX);
/* set the mailbox message addresses */
BP_VF_MBX(bp, vfid)->msg = (struct bnx2x_vf_mbx_msg *)
(((u8 *)BP_VF_MBX_DMA(bp)->addr) + vfid *
MBX_MSG_ALIGNED_SIZE);
/* called by bnx2x_chip_cleanup */ int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
{ int i;
if (!IS_SRIOV(bp)) return 0;
/* release all the VFs */
for_each_vf(bp, i)
bnx2x_vf_release(bp, BP_VF(bp, i));
return 0;
}
/* 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);
}
}
int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
{ struct bnx2x_virtf *vf; int qidx = 0, abs_vfid;
u8 opcode;
u16 cid = 0xffff;
if (!IS_SRIOV(bp)) return 1;
/* first get the cid - the only events we handle here are cfc-delete * and set-mac completion
*/
opcode = elem->message.opcode;
switch (opcode) { case EVENT_RING_OPCODE_CFC_DEL:
cid = SW_CID(elem->message.data.cfc_del_event.cid);
DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid); break; case EVENT_RING_OPCODE_CLASSIFICATION_RULES: case EVENT_RING_OPCODE_MULTICAST_RULES: case EVENT_RING_OPCODE_FILTERS_RULES: case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
cid = SW_CID(elem->message.data.eth_event.echo);
DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid); break; case EVENT_RING_OPCODE_VF_FLR:
abs_vfid = elem->message.data.vf_flr_event.vf_id;
DP(BNX2X_MSG_IOV, "Got VF FLR notification abs_vfid=%d\n",
abs_vfid); goto get_vf; case EVENT_RING_OPCODE_MALICIOUS_VF:
abs_vfid = elem->message.data.malicious_vf_event.vf_id;
BNX2X_ERR("Got VF MALICIOUS notification abs_vfid=%d err_id=0x%x\n",
abs_vfid,
elem->message.data.malicious_vf_event.err_id); goto get_vf; default: return 1;
}
/* check if the cid is the VF range */ if (!bnx2x_iov_is_vf_cid(bp, cid)) {
DP(BNX2X_MSG_IOV, "cid is outside vf range: %d\n", cid); return 1;
}
/* extract vf and rxq index from vf_cid - relies on the following: * 1. vfid on cid reflects the true abs_vfid * 2. The max number of VFs (per path) is 64
*/
qidx = cid & ((1 << BNX2X_VF_CID_WND)-1);
abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
get_vf:
vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
if (!vf) {
BNX2X_ERR("EQ completion for unknown VF, cid %d, abs_vfid %d\n",
cid, abs_vfid); return 0;
}
switch (opcode) { case EVENT_RING_OPCODE_CFC_DEL:
DP(BNX2X_MSG_IOV, "got VF [%d:%d] cfc delete ramrod\n",
vf->abs_vfid, qidx);
vfq_get(vf, qidx)->sp_obj.complete_cmd(bp,
&vfq_get(vf,
qidx)->sp_obj,
BNX2X_Q_CMD_CFC_DEL); break; case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mac/vlan ramrod\n",
vf->abs_vfid, qidx);
bnx2x_vf_handle_classification_eqe(bp, vfq_get(vf, qidx), elem); break; case EVENT_RING_OPCODE_MULTICAST_RULES:
DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mcast ramrod\n",
vf->abs_vfid, qidx);
bnx2x_vf_handle_mcast_eqe(bp, vf); break; case EVENT_RING_OPCODE_FILTERS_RULES:
DP(BNX2X_MSG_IOV, "got VF [%d:%d] set rx-mode ramrod\n",
vf->abs_vfid, qidx);
bnx2x_vf_handle_filters_eqe(bp, vf); break; case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
DP(BNX2X_MSG_IOV, "got VF [%d:%d] RSS update ramrod\n",
vf->abs_vfid, qidx);
bnx2x_vf_handle_rss_update_eqe(bp, vf);
fallthrough; case EVENT_RING_OPCODE_VF_FLR: /* Do nothing for now */ return 0; case EVENT_RING_OPCODE_MALICIOUS_VF:
vf->malicious = true; return 0;
}
return 0;
}
staticstruct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid)
{ /* extract the vf from vf_cid - relies on the following: * 1. vfid on cid reflects the true abs_vfid * 2. The max number of VFs (per path) is 64
*/ int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1); return bnx2x_vf_by_abs_fid(bp, abs_vfid);
}
if (vf) { /* extract queue index from vf_cid - relies on the following: * 1. vfid on cid reflects the true abs_vfid * 2. The max number of VFs (per path) is 64
*/ int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1);
*q_obj = &bnx2x_vfq(vf, q_index, sp_obj);
} else {
BNX2X_ERR("No vf matching cid %d\n", vf_cid);
}
}
/* 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 * this case the returned resources match the acquired already * acquired resources. Verify that the requested numbers do * not exceed the already acquired numbers.
*/ 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;
} return 0;
}
/* 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: * the global maximum number are fixed per VF. Fail the request if * requested number exceed these globals
*/ 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/HW initializations
*/
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 * cause the device to access the VF's stats buffer which it will free * as soon as we return from the close flow.
*/
{ struct set_vf_state_cookie cookie;
/* VF release can be called either: 1. The VF was acquired but * not enabled 2. the vf was enabled or in the process of being * enabled
*/ int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf)
{ int rc;
/* VF release ~ VF close + VF release-resources * Release is the ultimate SW shutdown and is called whenever an * irrecoverable error is encountered.
*/ int bnx2x_vf_release(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) return 0;
/* 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)) return 0;
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 * PCI configuration space should be the index of the last entry, * namely one less than the actual size of the table
*/ 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" messages to appear on the VF PF channel.
*/
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);
}
return 0;
}
/* New mac for VF. Consider these cases: * 1. VF hasn't been acquired yet - save the mac in local bulletin board and * supply at acquire. * 2. VF has already been acquired but has not yet initialized - store in local * bulletin board. mac will be posted on VF bulletin board after VF init. VF * will configure this mac when it is ready. * 3. VF has already initialized but has not yet setup a queue - post the new * mac on VF's bulletin board right now. VF will configure this mac when it * is ready. * 4. VF has already set a queue - delete any macs already configured for this * queue and manually config the new mac. * In any event, once this function has been called refuse any attempts by the * VF to configure any mac for itself except for this mac. In case of a race * where the VF fails to see the new post on its bulletin board before sending a * mac configuration request, the PF will simply fail the request and VF can try * again after consulting its bulletin board.
*/ 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 * configuration requests from vf unless match this mac
*/
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 * to the VF since it doesn't have anything to do with it. But it useful * to store it here in case the VF is not up yet and we can only * configure the vlan later when it does. Treat vlan id 0 as remove the * Host tag.
*/
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 * entire bulletin board excluding the crc field itself. Use the length field * as the Bulletin Board was posted by a PF with possibly a different version * from the vf which will sample it. Therefore, the length is computed by the * PF and then used blindly by the VF.
*/
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 * validate crc to ensure coherency.
*/ 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.