bnx2x: New multi-function mode: UFP
Add support for a new multi-function mode based on the Unified Fabric Port system specifications. Support includes configuration of: 1. Outer vlan tags. 2. Bandwidth settings. 3. Virtual link enable/disable. Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com> Signed-off-by: Dmitry Kravkov <Dmitry.Kravkov@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
2e98ffc21c
commit
7609647e25
|
@ -1448,6 +1448,11 @@ struct bnx2x_fp_stats {
|
|||
struct bnx2x_eth_q_stats_old eth_q_stats_old;
|
||||
};
|
||||
|
||||
enum {
|
||||
SUB_MF_MODE_UNKNOWN = 0,
|
||||
SUB_MF_MODE_UFP,
|
||||
};
|
||||
|
||||
struct bnx2x {
|
||||
/* Fields used in the tx and intr/napi performance paths
|
||||
* are grouped together in the beginning of the structure
|
||||
|
@ -1659,6 +1664,9 @@ struct bnx2x {
|
|||
#define IS_MF_SI(bp) (bp->mf_mode == MULTI_FUNCTION_SI)
|
||||
#define IS_MF_SD(bp) (bp->mf_mode == MULTI_FUNCTION_SD)
|
||||
#define IS_MF_AFEX(bp) (bp->mf_mode == MULTI_FUNCTION_AFEX)
|
||||
u8 mf_sub_mode;
|
||||
#define IS_MF_UFP(bp) (IS_MF_SD(bp) && \
|
||||
bp->mf_sub_mode == SUB_MF_MODE_UFP)
|
||||
|
||||
u8 wol;
|
||||
|
||||
|
|
|
@ -936,6 +936,12 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
|
|||
start_params->gre_tunnel_type = IPGRE_TUNNEL;
|
||||
start_params->inner_gre_rss_en = 1;
|
||||
|
||||
if (IS_MF_UFP(bp) && BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)) {
|
||||
start_params->class_fail_ethtype = ETH_P_FIP;
|
||||
start_params->class_fail = 1;
|
||||
start_params->no_added_tags = 1;
|
||||
}
|
||||
|
||||
return bnx2x_func_state_change(bp, &func_params);
|
||||
}
|
||||
|
||||
|
|
|
@ -859,6 +859,7 @@ struct shared_feat_cfg { /* NVRAM Offset */
|
|||
#define SHARED_FEAT_CFG_FORCE_SF_MODE_SPIO4 0x00000200
|
||||
#define SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT 0x00000300
|
||||
#define SHARED_FEAT_CFG_FORCE_SF_MODE_AFEX_MODE 0x00000400
|
||||
#define SHARED_FEAT_CFG_FORCE_SF_MODE_UFP_MODE 0x00000600
|
||||
|
||||
/* The interval in seconds between sending LLDP packets. Set to zero
|
||||
to disable the feature */
|
||||
|
@ -1268,6 +1269,10 @@ struct drv_func_mb {
|
|||
#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000
|
||||
#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000
|
||||
#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000
|
||||
#define DRV_MSG_CODE_OEM_OK 0x00010000
|
||||
#define DRV_MSG_CODE_OEM_FAILURE 0x00020000
|
||||
#define DRV_MSG_CODE_OEM_UPDATE_SVID_OK 0x00030000
|
||||
#define DRV_MSG_CODE_OEM_UPDATE_SVID_FAILURE 0x00040000
|
||||
/*
|
||||
* The optic module verification command requires bootcode
|
||||
* v5.0.6 or later, te specific optic module verification command
|
||||
|
@ -1423,6 +1428,12 @@ struct drv_func_mb {
|
|||
#define DRV_STATUS_SET_MF_BW 0x00000004
|
||||
#define DRV_STATUS_LINK_EVENT 0x00000008
|
||||
|
||||
#define DRV_STATUS_OEM_EVENT_MASK 0x00000070
|
||||
#define DRV_STATUS_OEM_DISABLE_ENABLE_PF 0x00000010
|
||||
#define DRV_STATUS_OEM_BANDWIDTH_ALLOCATION 0x00000020
|
||||
|
||||
#define DRV_STATUS_OEM_UPDATE_SVID 0x00000080
|
||||
|
||||
#define DRV_STATUS_DCC_EVENT_MASK 0x0000ff00
|
||||
#define DRV_STATUS_DCC_DISABLE_ENABLE_PF 0x00000100
|
||||
#define DRV_STATUS_DCC_BANDWIDTH_ALLOCATION 0x00000200
|
||||
|
|
|
@ -2905,6 +2905,57 @@ static void bnx2x_handle_afex_cmd(struct bnx2x *bp, u32 cmd)
|
|||
}
|
||||
}
|
||||
|
||||
static void bnx2x_handle_update_svid_cmd(struct bnx2x *bp)
|
||||
{
|
||||
struct bnx2x_func_switch_update_params *switch_update_params;
|
||||
struct bnx2x_func_state_params func_params;
|
||||
|
||||
memset(&func_params, 0, sizeof(struct bnx2x_func_state_params));
|
||||
switch_update_params = &func_params.params.switch_update;
|
||||
func_params.f_obj = &bp->func_obj;
|
||||
func_params.cmd = BNX2X_F_CMD_SWITCH_UPDATE;
|
||||
|
||||
if (IS_MF_UFP(bp)) {
|
||||
int func = BP_ABS_FUNC(bp);
|
||||
u32 val;
|
||||
|
||||
/* Re-learn the S-tag from shmem */
|
||||
val = MF_CFG_RD(bp, func_mf_config[func].e1hov_tag) &
|
||||
FUNC_MF_CFG_E1HOV_TAG_MASK;
|
||||
if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
|
||||
bp->mf_ov = val;
|
||||
} else {
|
||||
BNX2X_ERR("Got an SVID event, but no tag is configured in shmem\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Configure new S-tag in LLH */
|
||||
REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + BP_PORT(bp) * 8,
|
||||
bp->mf_ov);
|
||||
|
||||
/* Send Ramrod to update FW of change */
|
||||
__set_bit(BNX2X_F_UPDATE_SD_VLAN_TAG_CHNG,
|
||||
&switch_update_params->changes);
|
||||
switch_update_params->vlan = bp->mf_ov;
|
||||
|
||||
if (bnx2x_func_state_change(bp, &func_params) < 0) {
|
||||
BNX2X_ERR("Failed to configure FW of S-tag Change to %02x\n",
|
||||
bp->mf_ov);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DP(BNX2X_MSG_MCP, "Configured S-tag %02x\n", bp->mf_ov);
|
||||
|
||||
bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_OK, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* not supported by SW yet */
|
||||
fail:
|
||||
bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_FAILURE, 0);
|
||||
}
|
||||
|
||||
static void bnx2x_pmf_update(struct bnx2x *bp)
|
||||
{
|
||||
int port = BP_PORT(bp);
|
||||
|
@ -3297,6 +3348,7 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
|
|||
{
|
||||
int port = BP_PORT(bp);
|
||||
|
||||
if (!(IS_MF_UFP(bp) && BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)))
|
||||
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port * 8, 1);
|
||||
|
||||
/* Tx queue should be only re-enabled */
|
||||
|
@ -3652,14 +3704,30 @@ out:
|
|||
ethver, iscsiver, fcoever);
|
||||
}
|
||||
|
||||
static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
|
||||
static void bnx2x_oem_event(struct bnx2x *bp, u32 event)
|
||||
{
|
||||
DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
|
||||
u32 cmd_ok, cmd_fail;
|
||||
|
||||
if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
|
||||
/* sanity */
|
||||
if (event & DRV_STATUS_DCC_EVENT_MASK &&
|
||||
event & DRV_STATUS_OEM_EVENT_MASK) {
|
||||
BNX2X_ERR("Received simultaneous events %08x\n", event);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the only place besides the function initialization
|
||||
if (event & DRV_STATUS_DCC_EVENT_MASK) {
|
||||
cmd_fail = DRV_MSG_CODE_DCC_FAILURE;
|
||||
cmd_ok = DRV_MSG_CODE_DCC_OK;
|
||||
} else /* if (event & DRV_STATUS_OEM_EVENT_MASK) */ {
|
||||
cmd_fail = DRV_MSG_CODE_OEM_FAILURE;
|
||||
cmd_ok = DRV_MSG_CODE_OEM_OK;
|
||||
}
|
||||
|
||||
DP(BNX2X_MSG_MCP, "oem_event 0x%x\n", event);
|
||||
|
||||
if (event & (DRV_STATUS_DCC_DISABLE_ENABLE_PF |
|
||||
DRV_STATUS_OEM_DISABLE_ENABLE_PF)) {
|
||||
/* This is the only place besides the function initialization
|
||||
* where the bp->flags can change so it is done without any
|
||||
* locks
|
||||
*/
|
||||
|
@ -3674,18 +3742,22 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
|
|||
|
||||
bnx2x_e1h_enable(bp);
|
||||
}
|
||||
dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF;
|
||||
event &= ~(DRV_STATUS_DCC_DISABLE_ENABLE_PF |
|
||||
DRV_STATUS_OEM_DISABLE_ENABLE_PF);
|
||||
}
|
||||
if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
|
||||
|
||||
if (event & (DRV_STATUS_DCC_BANDWIDTH_ALLOCATION |
|
||||
DRV_STATUS_OEM_BANDWIDTH_ALLOCATION)) {
|
||||
bnx2x_config_mf_bw(bp);
|
||||
dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
|
||||
event &= ~(DRV_STATUS_DCC_BANDWIDTH_ALLOCATION |
|
||||
DRV_STATUS_OEM_BANDWIDTH_ALLOCATION);
|
||||
}
|
||||
|
||||
/* Report results to MCP */
|
||||
if (dcc_event)
|
||||
bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE, 0);
|
||||
if (event)
|
||||
bnx2x_fw_command(bp, cmd_fail, 0);
|
||||
else
|
||||
bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK, 0);
|
||||
bnx2x_fw_command(bp, cmd_ok, 0);
|
||||
}
|
||||
|
||||
/* must be called under the spq lock */
|
||||
|
@ -4167,9 +4239,12 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
|
|||
func_mf_config[BP_ABS_FUNC(bp)].config);
|
||||
val = SHMEM_RD(bp,
|
||||
func_mb[BP_FW_MB_IDX(bp)].drv_status);
|
||||
if (val & DRV_STATUS_DCC_EVENT_MASK)
|
||||
bnx2x_dcc_event(bp,
|
||||
(val & DRV_STATUS_DCC_EVENT_MASK));
|
||||
|
||||
if (val & (DRV_STATUS_DCC_EVENT_MASK |
|
||||
DRV_STATUS_OEM_EVENT_MASK))
|
||||
bnx2x_oem_event(bp,
|
||||
(val & (DRV_STATUS_DCC_EVENT_MASK |
|
||||
DRV_STATUS_OEM_EVENT_MASK)));
|
||||
|
||||
if (val & DRV_STATUS_SET_MF_BW)
|
||||
bnx2x_set_mf_bw(bp);
|
||||
|
@ -4195,6 +4270,10 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
|
|||
val & DRV_STATUS_AFEX_EVENT_MASK);
|
||||
if (val & DRV_STATUS_EEE_NEGOTIATION_RESULTS)
|
||||
bnx2x_handle_eee_event(bp);
|
||||
|
||||
if (val & DRV_STATUS_OEM_UPDATE_SVID)
|
||||
bnx2x_handle_update_svid_cmd(bp);
|
||||
|
||||
if (bp->link_vars.periodic_flags &
|
||||
PERIODIC_FLAGS_LINK_EVENT) {
|
||||
/* sync with link */
|
||||
|
@ -7930,8 +8009,11 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
|
|||
REG_WR(bp, CFC_REG_WEAK_ENABLE_PF, 1);
|
||||
|
||||
if (IS_MF(bp)) {
|
||||
if (!(IS_MF_UFP(bp) && BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp))) {
|
||||
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port * 8, 1);
|
||||
REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->mf_ov);
|
||||
REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port * 8,
|
||||
bp->mf_ov);
|
||||
}
|
||||
}
|
||||
|
||||
bnx2x_init_block(bp, BLOCK_MISC_AEU, init_phase);
|
||||
|
@ -11626,6 +11708,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
|
|||
|
||||
bp->mf_ov = 0;
|
||||
bp->mf_mode = 0;
|
||||
bp->mf_sub_mode = 0;
|
||||
vn = BP_VN(bp);
|
||||
|
||||
if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
|
||||
|
@ -11691,6 +11774,13 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
|
|||
} else
|
||||
BNX2X_DEV_INFO("illegal OV for SD\n");
|
||||
break;
|
||||
case SHARED_FEAT_CFG_FORCE_SF_MODE_UFP_MODE:
|
||||
bp->mf_mode = MULTI_FUNCTION_SD;
|
||||
bp->mf_sub_mode = SUB_MF_MODE_UFP;
|
||||
bp->mf_config[vn] =
|
||||
MF_CFG_RD(bp,
|
||||
func_mf_config[func].config);
|
||||
break;
|
||||
case SHARED_FEAT_CFG_FORCE_SF_MODE_FORCED_SF:
|
||||
bp->mf_config[vn] = 0;
|
||||
break;
|
||||
|
@ -11714,6 +11804,11 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
|
|||
|
||||
BNX2X_DEV_INFO("MF OV for func %d is %d (0x%04x)\n",
|
||||
func, bp->mf_ov, bp->mf_ov);
|
||||
} else if (bp->mf_sub_mode == SUB_MF_MODE_UFP) {
|
||||
dev_err(&bp->pdev->dev,
|
||||
"Unexpected - no valid MF OV for func %d in UFP mode\n",
|
||||
func);
|
||||
bp->path_has_ovlan = true;
|
||||
} else {
|
||||
dev_err(&bp->pdev->dev,
|
||||
"No valid MF OV for func %d, aborting\n",
|
||||
|
|
|
@ -5673,8 +5673,23 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
|
|||
rdata->gre_tunnel_type = start_params->gre_tunnel_type;
|
||||
rdata->inner_gre_rss_en = start_params->inner_gre_rss_en;
|
||||
rdata->vxlan_dst_port = cpu_to_le16(4789);
|
||||
rdata->sd_vlan_eth_type = cpu_to_le16(0x8100);
|
||||
rdata->sd_accept_mf_clss_fail = start_params->class_fail;
|
||||
if (start_params->class_fail_ethtype) {
|
||||
rdata->sd_accept_mf_clss_fail_match_ethtype = 1;
|
||||
rdata->sd_accept_mf_clss_fail_ethtype =
|
||||
cpu_to_le16(start_params->class_fail_ethtype);
|
||||
}
|
||||
|
||||
rdata->sd_vlan_force_pri_flg = start_params->sd_vlan_force_pri;
|
||||
rdata->sd_vlan_force_pri_val = start_params->sd_vlan_force_pri_val;
|
||||
if (start_params->sd_vlan_eth_type)
|
||||
rdata->sd_vlan_eth_type =
|
||||
cpu_to_le16(start_params->sd_vlan_eth_type);
|
||||
else
|
||||
rdata->sd_vlan_eth_type =
|
||||
cpu_to_le16(0x8100);
|
||||
|
||||
rdata->no_added_tags = start_params->no_added_tags;
|
||||
/* No need for an explicit memory barrier here as long we would
|
||||
* need to ensure the ordering of writing to the SPQ element
|
||||
* and updating of the SPQ producer which involves a memory
|
||||
|
@ -5708,6 +5723,30 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp,
|
|||
&switch_update_params->changes);
|
||||
}
|
||||
|
||||
if (test_bit(BNX2X_F_UPDATE_SD_VLAN_TAG_CHNG,
|
||||
&switch_update_params->changes)) {
|
||||
rdata->sd_vlan_tag_change_flg = 1;
|
||||
rdata->sd_vlan_tag =
|
||||
cpu_to_le16(switch_update_params->vlan);
|
||||
}
|
||||
|
||||
if (test_bit(BNX2X_F_UPDATE_SD_VLAN_ETH_TYPE_CHNG,
|
||||
&switch_update_params->changes)) {
|
||||
rdata->sd_vlan_eth_type_change_flg = 1;
|
||||
rdata->sd_vlan_eth_type =
|
||||
cpu_to_le16(switch_update_params->vlan_eth_type);
|
||||
}
|
||||
|
||||
if (test_bit(BNX2X_F_UPDATE_VLAN_FORCE_PRIO_CHNG,
|
||||
&switch_update_params->changes)) {
|
||||
rdata->sd_vlan_force_pri_change_flg = 1;
|
||||
if (test_bit(BNX2X_F_UPDATE_VLAN_FORCE_PRIO_FLAG,
|
||||
&switch_update_params->changes))
|
||||
rdata->sd_vlan_force_pri_flg = 1;
|
||||
rdata->sd_vlan_force_pri_flg =
|
||||
switch_update_params->vlan_force_prio;
|
||||
}
|
||||
|
||||
if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
|
||||
&switch_update_params->changes)) {
|
||||
rdata->update_tunn_cfg_flg = 1;
|
||||
|
|
|
@ -1098,6 +1098,10 @@ struct bnx2x_queue_sp_obj {
|
|||
enum {
|
||||
BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
|
||||
BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
|
||||
BNX2X_F_UPDATE_SD_VLAN_TAG_CHNG,
|
||||
BNX2X_F_UPDATE_SD_VLAN_ETH_TYPE_CHNG,
|
||||
BNX2X_F_UPDATE_VLAN_FORCE_PRIO_CHNG,
|
||||
BNX2X_F_UPDATE_VLAN_FORCE_PRIO_FLAG,
|
||||
BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
|
||||
BNX2X_F_UPDATE_TUNNEL_CLSS_EN,
|
||||
BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN,
|
||||
|
@ -1178,10 +1182,29 @@ struct bnx2x_func_start_params {
|
|||
* capailities
|
||||
*/
|
||||
u8 inner_gre_rss_en;
|
||||
|
||||
/* Allows accepting of packets failing MF classification, possibly
|
||||
* only matching a given ethertype
|
||||
*/
|
||||
u8 class_fail;
|
||||
u16 class_fail_ethtype;
|
||||
|
||||
/* Override priority of output packets */
|
||||
u8 sd_vlan_force_pri;
|
||||
u8 sd_vlan_force_pri_val;
|
||||
|
||||
/* Replace vlan's ethertype */
|
||||
u16 sd_vlan_eth_type;
|
||||
|
||||
/* Prevent inner vlans from being added by FW */
|
||||
u8 no_added_tags;
|
||||
};
|
||||
|
||||
struct bnx2x_func_switch_update_params {
|
||||
unsigned long changes; /* BNX2X_F_UPDATE_XX bits */
|
||||
u16 vlan;
|
||||
u16 vlan_eth_type;
|
||||
u8 vlan_force_prio;
|
||||
u8 tunnel_mode;
|
||||
u8 gre_tunnel_type;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue