bnx2x: VF can report link speed
Until now VFs were oblvious to the actual configured link parameters. This patch does 2 things: 1. It enables a PF to inform its VF using the bulletin board of the link configured, and allows the VF to present that information. 2. It adds support of `ndo_set_vf_link_state', allowing the hypervisor to set the VF link state. Signed-off-by: Dmitry Kravkov <Dmitry.Kravkov@qlogic.com> Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com> Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
edd79ca8b3
commit
6495d15a7c
|
@ -1482,6 +1482,7 @@ struct bnx2x {
|
|||
union pf_vf_bulletin *pf2vf_bulletin;
|
||||
dma_addr_t pf2vf_bulletin_mapping;
|
||||
|
||||
union pf_vf_bulletin shadow_bulletin;
|
||||
struct pf_vf_bulletin_content old_bulletin;
|
||||
|
||||
u16 requested_nr_virtfn;
|
||||
|
@ -1928,6 +1929,8 @@ struct bnx2x {
|
|||
struct semaphore stats_sema;
|
||||
|
||||
u8 phys_port_id[ETH_ALEN];
|
||||
|
||||
struct bnx2x_link_report_data vf_link_vars;
|
||||
};
|
||||
|
||||
/* Tx queues may be less or equal to Rx queues */
|
||||
|
|
|
@ -1185,29 +1185,38 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp)
|
|||
static void bnx2x_fill_report_data(struct bnx2x *bp,
|
||||
struct bnx2x_link_report_data *data)
|
||||
{
|
||||
u16 line_speed = bnx2x_get_mf_speed(bp);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
/* Fill the report data: effective line speed */
|
||||
data->line_speed = line_speed;
|
||||
if (IS_PF(bp)) {
|
||||
/* Fill the report data: effective line speed */
|
||||
data->line_speed = bnx2x_get_mf_speed(bp);
|
||||
|
||||
/* Link is down */
|
||||
if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
|
||||
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&data->link_report_flags);
|
||||
/* Link is down */
|
||||
if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
|
||||
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&data->link_report_flags);
|
||||
|
||||
/* Full DUPLEX */
|
||||
if (bp->link_vars.duplex == DUPLEX_FULL)
|
||||
__set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags);
|
||||
if (!BNX2X_NUM_ETH_QUEUES(bp))
|
||||
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&data->link_report_flags);
|
||||
|
||||
/* Rx Flow Control is ON */
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
|
||||
__set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags);
|
||||
/* Full DUPLEX */
|
||||
if (bp->link_vars.duplex == DUPLEX_FULL)
|
||||
__set_bit(BNX2X_LINK_REPORT_FD,
|
||||
&data->link_report_flags);
|
||||
|
||||
/* Tx Flow Control is ON */
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
|
||||
__set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags);
|
||||
/* Rx Flow Control is ON */
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
|
||||
__set_bit(BNX2X_LINK_REPORT_RX_FC_ON,
|
||||
&data->link_report_flags);
|
||||
|
||||
/* Tx Flow Control is ON */
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
|
||||
__set_bit(BNX2X_LINK_REPORT_TX_FC_ON,
|
||||
&data->link_report_flags);
|
||||
} else { /* VF */
|
||||
*data = bp->vf_link_vars;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1261,6 +1270,10 @@ void __bnx2x_link_report(struct bnx2x *bp)
|
|||
*/
|
||||
memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data));
|
||||
|
||||
/* propagate status to VFs */
|
||||
if (IS_PF(bp))
|
||||
bnx2x_iov_link_update(bp);
|
||||
|
||||
if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&cur_data.link_report_flags)) {
|
||||
netif_carrier_off(bp->dev);
|
||||
|
|
|
@ -216,6 +216,43 @@ static int bnx2x_get_port_type(struct bnx2x *bp)
|
|||
return port_type;
|
||||
}
|
||||
|
||||
static int bnx2x_get_vf_settings(struct net_device *dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct bnx2x *bp = netdev_priv(dev);
|
||||
|
||||
if (bp->state == BNX2X_STATE_OPEN) {
|
||||
if (test_bit(BNX2X_LINK_REPORT_FD,
|
||||
&bp->vf_link_vars.link_report_flags))
|
||||
cmd->duplex = DUPLEX_FULL;
|
||||
else
|
||||
cmd->duplex = DUPLEX_HALF;
|
||||
|
||||
ethtool_cmd_speed_set(cmd, bp->vf_link_vars.line_speed);
|
||||
} else {
|
||||
cmd->duplex = DUPLEX_UNKNOWN;
|
||||
ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
|
||||
}
|
||||
|
||||
cmd->port = PORT_OTHER;
|
||||
cmd->phy_address = 0;
|
||||
cmd->transceiver = XCVR_INTERNAL;
|
||||
cmd->autoneg = AUTONEG_DISABLE;
|
||||
cmd->maxtxpkt = 0;
|
||||
cmd->maxrxpkt = 0;
|
||||
|
||||
DP(BNX2X_MSG_ETHTOOL, "ethtool_cmd: cmd %d\n"
|
||||
" supported 0x%x advertising 0x%x speed %u\n"
|
||||
" duplex %d port %d phy_address %d transceiver %d\n"
|
||||
" autoneg %d maxtxpkt %d maxrxpkt %d\n",
|
||||
cmd->cmd, cmd->supported, cmd->advertising,
|
||||
ethtool_cmd_speed(cmd),
|
||||
cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
|
||||
cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct bnx2x *bp = netdev_priv(dev);
|
||||
|
@ -1110,6 +1147,10 @@ static u32 bnx2x_get_link(struct net_device *dev)
|
|||
if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN))
|
||||
return 0;
|
||||
|
||||
if (IS_VF(bp))
|
||||
return !test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&bp->vf_link_vars.link_report_flags);
|
||||
|
||||
return bp->link_vars.link_up;
|
||||
}
|
||||
|
||||
|
@ -3484,8 +3525,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
|
|||
};
|
||||
|
||||
static const struct ethtool_ops bnx2x_vf_ethtool_ops = {
|
||||
.get_settings = bnx2x_get_settings,
|
||||
.set_settings = bnx2x_set_settings,
|
||||
.get_settings = bnx2x_get_vf_settings,
|
||||
.get_drvinfo = bnx2x_get_drvinfo,
|
||||
.get_msglevel = bnx2x_get_msglevel,
|
||||
.set_msglevel = bnx2x_set_msglevel,
|
||||
|
|
|
@ -2698,6 +2698,14 @@ void bnx2x__link_status_update(struct bnx2x *bp)
|
|||
bp->link_vars.duplex = DUPLEX_FULL;
|
||||
bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
|
||||
__bnx2x_link_report(bp);
|
||||
|
||||
bnx2x_sample_bulletin(bp);
|
||||
|
||||
/* if bulletin board did not have an update for link status
|
||||
* __bnx2x_link_report will report current status
|
||||
* but it will NOT duplicate report in case of already reported
|
||||
* during sampling bulletin board.
|
||||
*/
|
||||
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
|
||||
}
|
||||
}
|
||||
|
@ -12424,6 +12432,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
|
|||
.ndo_busy_poll = bnx2x_low_latency_recv,
|
||||
#endif
|
||||
.ndo_get_phys_port_id = bnx2x_get_phys_port_id,
|
||||
.ndo_set_vf_link_state = bnx2x_set_vf_link_state,
|
||||
};
|
||||
|
||||
static int bnx2x_set_coherency_mask(struct bnx2x *bp)
|
||||
|
|
|
@ -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;
|
||||
|
||||
/* 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));
|
||||
|
||||
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)
|
||||
if (bp->old_bulletin.version == bulletin->version)
|
||||
return PFVF_BULLETIN_UNCHANGED;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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:
|
||||
|
|
|
@ -126,7 +126,11 @@ struct bnx2x_virtf {
|
|||
#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 */
|
||||
|
@ -295,22 +299,22 @@ struct bnx2x_vfdb {
|
|||
#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))
|
||||
|
@ -336,6 +340,9 @@ struct bnx2x_vfdb {
|
|||
/* sp_rtnl synchronization */
|
||||
struct mutex event_mutex;
|
||||
u64 event_occur;
|
||||
|
||||
/* bulletin board update synchronization */
|
||||
struct mutex bulletin_mutex;
|
||||
};
|
||||
|
||||
/* queue access */
|
||||
|
@ -467,9 +474,10 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp);
|
|||
|
||||
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);
|
||||
|
||||
|
@ -520,6 +528,11 @@ void bnx2x_iov_task(struct work_struct *work);
|
|||
|
||||
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,
|
||||
|
@ -579,6 +592,14 @@ static inline void bnx2x_iov_channel_down(struct bnx2x *bp) {}
|
|||
|
||||
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 */
|
||||
|
|
|
@ -251,6 +251,9 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
|
|||
bnx2x_add_tlv(bp, req, req->first_tlv.tl.length,
|
||||
CHANNEL_TLV_PHYS_PORT_ID, sizeof(struct channel_tlv));
|
||||
|
||||
/* Bulletin support for bulletin board with length > legacy length */
|
||||
req->vfdev_info.caps |= VF_CAP_SUPPORT_EXT_BULLETIN;
|
||||
|
||||
/* add list termination tlv */
|
||||
bnx2x_add_tlv(bp, req,
|
||||
req->first_tlv.tl.length + sizeof(struct channel_tlv),
|
||||
|
@ -1252,6 +1255,13 @@ static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|||
|
||||
/* store address of vf's bulletin board */
|
||||
vf->bulletin_map = acquire->bulletin_addr;
|
||||
if (acquire->vfdev_info.caps & VF_CAP_SUPPORT_EXT_BULLETIN) {
|
||||
DP(BNX2X_MSG_IOV, "VF[%d] supports long bulletin boards\n",
|
||||
vf->abs_vfid);
|
||||
vf->cfg_flags |= VF_CFG_EXT_BULLETIN;
|
||||
} else {
|
||||
vf->cfg_flags &= ~VF_CFG_EXT_BULLETIN;
|
||||
}
|
||||
|
||||
/* response */
|
||||
bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc);
|
||||
|
@ -1273,6 +1283,10 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|||
if (init->flags & VFPF_INIT_FLG_STATS_COALESCE)
|
||||
vf->cfg_flags |= VF_CFG_STATS_COALESCE;
|
||||
|
||||
/* Update VF's view of link state */
|
||||
if (vf->cfg_flags & VF_CFG_EXT_BULLETIN)
|
||||
bnx2x_iov_link_update_vf(bp, vf->index);
|
||||
|
||||
/* response */
|
||||
bnx2x_vf_mbx_resp(bp, vf, rc);
|
||||
}
|
||||
|
@ -2007,6 +2021,17 @@ void bnx2x_vf_mbx(struct bnx2x *bp)
|
|||
}
|
||||
}
|
||||
|
||||
void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin,
|
||||
bool support_long)
|
||||
{
|
||||
/* Older VFs contain a bug where they can't check CRC for bulletin
|
||||
* boards of length greater than legacy size.
|
||||
*/
|
||||
bulletin->length = support_long ? BULLETIN_CONTENT_SIZE :
|
||||
BULLETIN_CONTENT_LEGACY_SIZE;
|
||||
bulletin->crc = bnx2x_crc_vf_bulletin(bulletin);
|
||||
}
|
||||
|
||||
/* propagate local bulletin board to vf */
|
||||
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
|
||||
{
|
||||
|
@ -2023,8 +2048,9 @@ int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
|
|||
|
||||
/* increment bulletin board version and compute crc */
|
||||
bulletin->version++;
|
||||
bulletin->length = BULLETIN_CONTENT_SIZE;
|
||||
bulletin->crc = bnx2x_crc_vf_bulletin(bp, bulletin);
|
||||
bnx2x_vf_bulletin_finalize(bulletin,
|
||||
(bnx2x_vf(bp, vf, cfg_flags) &
|
||||
VF_CFG_EXT_BULLETIN) ? true : false);
|
||||
|
||||
/* propagate bulletin board via dmae to vm memory */
|
||||
rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr,
|
||||
|
|
|
@ -65,6 +65,7 @@ struct hw_sb_info {
|
|||
#define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST 0x00000008
|
||||
#define VFPF_RX_MASK_ACCEPT_BROADCAST 0x00000010
|
||||
#define BULLETIN_CONTENT_SIZE (sizeof(struct pf_vf_bulletin_content))
|
||||
#define BULLETIN_CONTENT_LEGACY_SIZE (32)
|
||||
#define BULLETIN_ATTEMPTS 5 /* crc failures before throwing towel */
|
||||
#define BULLETIN_CRC_SEED 0
|
||||
|
||||
|
@ -117,7 +118,9 @@ struct vfpf_acquire_tlv {
|
|||
/* the following fields are for debug purposes */
|
||||
u8 vf_id; /* ME register value */
|
||||
u8 vf_os; /* e.g. Linux, W2K8 */
|
||||
u8 padding[2];
|
||||
u8 padding;
|
||||
u8 caps;
|
||||
#define VF_CAP_SUPPORT_EXT_BULLETIN (1 << 0)
|
||||
} vfdev_info;
|
||||
|
||||
struct vf_pf_resc_request resc_request;
|
||||
|
@ -393,11 +396,23 @@ struct pf_vf_bulletin_content {
|
|||
* to attempt to send messages on the
|
||||
* channel after this bit is set
|
||||
*/
|
||||
#define LINK_VALID 3 /* alert the VF thet a new link status
|
||||
* update is available for it
|
||||
*/
|
||||
u8 mac[ETH_ALEN];
|
||||
u8 mac_padding[2];
|
||||
|
||||
u16 vlan;
|
||||
u8 vlan_padding[6];
|
||||
|
||||
u16 link_speed; /* Effective line speed */
|
||||
u8 link_speed_padding[6];
|
||||
u32 link_flags; /* VFPF_LINK_REPORT_XXX flags */
|
||||
#define VFPF_LINK_REPORT_LINK_DOWN (1 << 0)
|
||||
#define VFPF_LINK_REPORT_FULL_DUPLEX (1 << 1)
|
||||
#define VFPF_LINK_REPORT_RX_FC_ON (1 << 2)
|
||||
#define VFPF_LINK_REPORT_TX_FC_ON (1 << 3)
|
||||
u8 link_flags_padding[4];
|
||||
};
|
||||
|
||||
union pf_vf_bulletin {
|
||||
|
|
Loading…
Reference in New Issue