|
@@ -24,6 +24,11 @@
|
|
|
#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)
|
|
@@ -1327,6 +1332,8 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
|
|
|
/* 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);
|
|
@@ -1472,6 +1479,107 @@ static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|
|
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)
|
|
|
{
|
|
@@ -2509,22 +2617,23 @@ void bnx2x_disable_sriov(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;
|
|
|
}
|
|
@@ -2534,19 +2643,18 @@ static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx,
|
|
|
*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;
|
|
|
}
|
|
@@ -2565,9 +2673,10 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
|
|
|
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) {
|
|
@@ -2590,6 +2699,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
|
|
|
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 */
|
|
@@ -2605,6 +2715,8 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
|
|
|
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;
|
|
@@ -2634,15 +2746,18 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
|
|
|
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
|
|
|
*/
|
|
@@ -2651,6 +2766,10 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *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;
|
|
@@ -2715,11 +2834,6 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
|
|
|
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;
|
|
@@ -2728,18 +2842,27 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
|
|
|
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)) !=
|
|
@@ -2849,10 +2972,9 @@ out:
|
|
|
* 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),
|
|
@@ -2862,47 +2984,74 @@ u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
|
|
|
/* 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;
|
|
|
}
|
|
@@ -2947,6 +3096,8 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
|
|
|
if (!bp->pf2vf_bulletin)
|
|
|
goto alloc_mem_err;
|
|
|
|
|
|
+ bnx2x_vf_bulletin_finalize(&bp->pf2vf_bulletin->content, true);
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
alloc_mem_err:
|