bnx2x: New multi-function mode: UFP
authorYuval Mintz <Yuval.Mintz@qlogic.com>
Wed, 17 Sep 2014 13:24:37 +0000 (16:24 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Sep 2014 20:31:08 +0000 (16:31 -0400)
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>
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h

index 7ecb61f4a61dd88c306071377c47f80796b0f075..10291df0b9833bc8eb4657f3cf56ec07af234c11 100644 (file)
@@ -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;
 
index 010277571adbef36392679d696ce3c1f4fd65912..adcacda7af7b10e70b053821acc1e2dfe722732a 100644 (file)
@@ -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);
 }
 
index 3e0621acdf05570db85127f0da200ac80160876e..3295863b5adfcfbf31bd187c3023c91c61147d2a 100644 (file)
@@ -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
index 82ea6b682981597cb2caebb3aa16dfeeece700a9..da6c5bb1e109f93add7618466238040e5bfefa95 100644 (file)
@@ -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,7 +3348,8 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
 
-       REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
+       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 */
        netif_tx_wake_all_queues(bp->dev);
@@ -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;
+
+       /* sanity */
+       if (event & DRV_STATUS_DCC_EVENT_MASK &&
+           event & DRV_STATUS_OEM_EVENT_MASK) {
+               BNX2X_ERR("Received simultaneous events %08x\n", event);
+               return;
+       }
 
-       if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
+       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;
+       }
 
-               /*
-                * This is the only place besides the function initialization
+       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)) {
-               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);
+               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);
+               }
        }
 
        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",
index 19d0c1152434e4d8e75a71510dadae8e16c25ae1..7bc2924a7e24f071d6f39adfed574dff7c2af71a 100644 (file)
@@ -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;
index 21c8f6fb89e557b6ac98748c6c3a14943e584f70..e97275f456c0ae789ab3e628482d73ccf2dd949c 100644 (file)
@@ -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;
 };