#include <linux/crc32.h>
#include <linux/if_vlan.h>
+static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
+ struct bnx2x_virtf **vf,
+ struct pf_vf_bulletin_content **bulletin,
+ bool test_queue);
+
/* General service functions */
static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
u16 pf_id)
/* Prepare the VFs event synchronization mechanism */
mutex_init(&bp->vfdb->event_mutex);
+ mutex_init(&bp->vfdb->bulletin_mutex);
+
return 0;
failed:
DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
vf->abs_vfid, q->sp_obj.func_id, q->cid);
}
+static int bnx2x_max_speed_cap(struct bnx2x *bp)
+{
+ u32 supported = bp->port.supported[bnx2x_get_link_cfg_idx(bp)];
+
+ if (supported &
+ (SUPPORTED_20000baseMLD2_Full | SUPPORTED_20000baseKR2_Full))
+ return 20000;
+
+ return 10000; /* assume lowest supported speed is 10G */
+}
+
+int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx)
+{
+ struct bnx2x_link_report_data *state = &bp->last_reported_link;
+ struct pf_vf_bulletin_content *bulletin;
+ struct bnx2x_virtf *vf;
+ bool update = true;
+ int rc = 0;
+
+ /* sanity and init */
+ rc = bnx2x_vf_op_prep(bp, idx, &vf, &bulletin, false);
+ if (rc)
+ return rc;
+
+ mutex_lock(&bp->vfdb->bulletin_mutex);
+
+ if (vf->link_cfg == IFLA_VF_LINK_STATE_AUTO) {
+ bulletin->valid_bitmap |= 1 << LINK_VALID;
+
+ bulletin->link_speed = state->line_speed;
+ bulletin->link_flags = 0;
+ if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN;
+ if (test_bit(BNX2X_LINK_REPORT_FD,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_FULL_DUPLEX;
+ if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_RX_FC_ON;
+ if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
+ &state->link_report_flags))
+ bulletin->link_flags |= VFPF_LINK_REPORT_TX_FC_ON;
+ } else if (vf->link_cfg == IFLA_VF_LINK_STATE_DISABLE &&
+ !(bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) {
+ bulletin->valid_bitmap |= 1 << LINK_VALID;
+ bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN;
+ } else if (vf->link_cfg == IFLA_VF_LINK_STATE_ENABLE &&
+ (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) {
+ bulletin->valid_bitmap |= 1 << LINK_VALID;
+ bulletin->link_speed = bnx2x_max_speed_cap(bp);
+ bulletin->link_flags &= ~VFPF_LINK_REPORT_LINK_DOWN;
+ } else {
+ update = false;
+ }
+
+ if (update) {
+ DP(NETIF_MSG_LINK | BNX2X_MSG_IOV,
+ "vf %d mode %u speed %d flags %x\n", idx,
+ vf->link_cfg, bulletin->link_speed, bulletin->link_flags);
+
+ /* Post update on VF's bulletin board */
+ rc = bnx2x_post_vf_bulletin(bp, idx);
+ if (rc) {
+ BNX2X_ERR("failed to update VF[%d] bulletin\n", idx);
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
+ return rc;
+}
+
+int bnx2x_set_vf_link_state(struct net_device *dev, int idx, int link_state)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x_virtf *vf = BP_VF(bp, idx);
+
+ if (!vf)
+ return -EINVAL;
+
+ if (vf->link_cfg == link_state)
+ return 0; /* nothing todo */
+
+ vf->link_cfg = link_state;
+
+ return bnx2x_iov_link_update_vf(bp, idx);
+}
+
+void bnx2x_iov_link_update(struct bnx2x *bp)
+{
+ int vfid;
+
+ if (!IS_SRIOV(bp))
+ return;
+
+ for_each_vf(bp, vfid)
+ bnx2x_iov_link_update_vf(bp, vfid);
+}
+
/* called by bnx2x_nic_load */
int bnx2x_iov_nic_init(struct bnx2x *bp)
{
pci_disable_sriov(bp->pdev);
}
-static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx,
- struct bnx2x_virtf **vf,
- struct pf_vf_bulletin_content **bulletin)
+static int 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("vf ndo called though PF is down\n");
+ BNX2X_ERR("PF is down - can't utilize iov-related functionality\n");
return -EINVAL;
}
if (!IS_SRIOV(bp)) {
- BNX2X_ERR("vf ndo called though sriov is disabled\n");
+ BNX2X_ERR("sriov is disabled - can't utilize iov-realted functionality\n");
return -EINVAL;
}
if (vfidx >= BNX2X_NR_VIRTFN(bp)) {
- BNX2X_ERR("vf ndo called for uninitialized VF. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
+ 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;
}
*bulletin = BP_VF_BULLETIN(bp, vfidx);
if (!*vf) {
- BNX2X_ERR("vf ndo called but vf struct is null. vfidx was %d\n",
- vfidx);
+ BNX2X_ERR("Unable to get VF structure for vfidx %d\n", vfidx);
return -EINVAL;
}
- if (!(*vf)->vfqs) {
- BNX2X_ERR("vf ndo called but vfqs struct is null. Was ndo invoked before dynamically enabling SR-IOV? vfidx was %d\n",
+ 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("vf ndo called but Bulletin Board struct is null. vfidx was %d\n",
+ BNX2X_ERR("Bulletin Board struct is null for vfidx %d\n",
vfidx);
return -EINVAL;
}
int rc;
/* sanity and init */
- rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
+ rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true);
if (rc)
return rc;
+
mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
if (!mac_obj || !vlan_obj) {
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 */
else
/* function has not been loaded yet. Show vlans as 0s */
memset(&ivi->vlan, 0, VLAN_HLEN);
+
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
}
return 0;
struct bnx2x_virtf *vf = NULL;
struct pf_vf_bulletin_content *bulletin = NULL;
- /* sanity and init */
- rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
- if (rc)
- return rc;
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
*/
/* 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;
unsigned long accept_flags;
int rc;
- /* sanity and init */
- rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
- if (rc)
- return rc;
-
if (vlan > 4095) {
BNX2X_ERR("illegal vlan value %d\n", vlan);
return -EINVAL;
DP(BNX2X_MSG_IOV, "configuring VF %d with VLAN %d qos %d\n",
vfidx, vlan, 0);
+ /* 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);
+
if (vlan > 0)
bulletin->valid_bitmap |= 1 << VLAN_VALID;
else
bulletin->valid_bitmap &= ~(1 << VLAN_VALID);
bulletin->vlan = vlan;
+ mutex_unlock(&bp->vfdb->bulletin_mutex);
+
/* is vf initialized and queue set up? */
if (vf->state != VF_ENABLED ||
bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) !=
* 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 the used blindly by the VF.
+ * PF and then used blindly by the VF.
*/
-u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
- struct pf_vf_bulletin_content *bulletin)
+u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin)
{
return crc32(BULLETIN_CRC_SEED,
((u8 *)bulletin) + 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 = bp->pf2vf_bulletin->content;
+ struct pf_vf_bulletin_content *bulletin;
int attempts;
- /* bulletin board hasn't changed since last sample */
- if (bp->old_bulletin.version == bulletin.version)
- return PFVF_BULLETIN_UNCHANGED;
+ /* sampling structure in mid post may result with corrupted data
+ * validate crc to ensure coherency.
+ */
+ for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
+ u32 crc;
- /* validate crc of new bulletin board */
- if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
- /* sampling structure in mid post may result with corrupted data
- * validate crc to ensure coherency.
- */
- for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
- bulletin = bp->pf2vf_bulletin->content;
- if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
- &bulletin))
- break;
- BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n",
- bulletin.crc,
- bnx2x_crc_vf_bulletin(bp, &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;
- }
+ /* sample the bulletin board */
+ memcpy(&bp->shadow_bulletin, bp->pf2vf_bulletin,
+ sizeof(union pf_vf_bulletin));
+
+ crc = bnx2x_crc_vf_bulletin(&bp->shadow_bulletin.content);
+
+ if (bp->shadow_bulletin.content.crc == crc)
+ break;
+
+ BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n",
+ bp->shadow_bulletin.content.crc, crc);
+ }
+
+ 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)) {
+ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID &&
+ !ether_addr_equal(bulletin->mac, bp->old_bulletin.mac)) {
/* update new mac to net device */
- memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+ memcpy(bp->dev->dev_addr, bulletin->mac, ETH_ALEN);
+ }
+
+ if (bulletin->valid_bitmap & (1 << LINK_VALID)) {
+ DP(BNX2X_MSG_IOV, "link update speed %d flags %x\n",
+ bulletin->link_speed, bulletin->link_flags);
+
+ 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);
}
- /* the vlan in bulletin board is valid and is new */
- if (bulletin.valid_bitmap & 1 << VLAN_VALID)
- memcpy(&bulletin.vlan, &bp->old_bulletin.vlan, VLAN_HLEN);
-
/* copy new bulletin board to bp */
- bp->old_bulletin = bulletin;
+ memcpy(&bp->old_bulletin, bulletin,
+ sizeof(struct pf_vf_bulletin_content));
return PFVF_BULLETIN_UPDATED;
}
if (!bp->pf2vf_bulletin)
goto alloc_mem_err;
+ bnx2x_vf_bulletin_finalize(&bp->pf2vf_bulletin->content, true);
+
return 0;
alloc_mem_err:
#define VF_CACHE_LINE 0x0010
#define VF_CFG_VLAN 0x0020
#define VF_CFG_STATS_COALESCE 0x0040
-
+#define VF_CFG_EXT_BULLETIN 0x0080
+ u8 link_cfg; /* IFLA_VF_LINK_STATE_AUTO
+ * IFLA_VF_LINK_STATE_ENABLE
+ * IFLA_VF_LINK_STATE_DISABLE
+ */
u8 state;
#define VF_FREE 0 /* VF ready to be acquired holds no resc */
#define VF_ACQUIRED 1 /* VF acquired, but not initialized */
#define BP_VFDB(bp) ((bp)->vfdb)
/* vf array */
struct bnx2x_virtf *vfs;
-#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[(idx)]))
-#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[(idx)].var)
+#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[idx]))
+#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[idx].var)
/* queue array - for all vfs */
struct bnx2x_vf_queue *vfqs;
/* vf HW contexts */
struct hw_dma context[BNX2X_VF_CIDS/ILT_PAGE_CIDS];
-#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[(i)])
+#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[i])
/* SR-IOV information */
struct bnx2x_sriov sriov;
struct hw_dma mbx_dma;
#define BP_VF_MBX_DMA(bp) (&((bp)->vfdb->mbx_dma))
struct bnx2x_vf_mbx mbxs[BNX2X_MAX_NUM_OF_VFS];
-#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[(vfid)]))
+#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[vfid]))
struct hw_dma bulletin_dma;
#define BP_VF_BULLETIN_DMA(bp) (&((bp)->vfdb->bulletin_dma))
/* sp_rtnl synchronization */
struct mutex event_mutex;
u64 event_occur;
+
+ /* bulletin board update synchronization */
+ struct mutex bulletin_mutex;
};
/* queue access */
bool bnx2x_tlv_supported(u16 tlvtype);
-u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
- struct pf_vf_bulletin_content *bulletin);
+u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin);
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
+void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin,
+ bool support_long);
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag);
+void bnx2x_iov_link_update(struct bnx2x *bp);
+int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx);
+
+int bnx2x_set_vf_link_state(struct net_device *dev, int vf, int link_state);
+
#else /* CONFIG_BNX2X_SRIOV */
static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
static inline void bnx2x_iov_task(struct work_struct *work) {}
static inline void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag) {}
+static inline void bnx2x_iov_link_update(struct bnx2x *bp) {}
+static inline int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx) {return 0; }
+
+static inline int bnx2x_set_vf_link_state(struct net_device *dev, int vf,
+ int link_state) {return 0; }
+struct pf_vf_bulletin_content;
+static inline void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin,
+ bool support_long) {}
#endif /* CONFIG_BNX2X_SRIOV */
#endif /* bnx2x_sriov.h */