]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
bnx2x: DCB rework
authorDmitry Kravkov <dmitry@broadcom.com>
Tue, 19 Jul 2011 01:42:04 +0000 (01:42 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 Jul 2011 16:57:48 +0000 (09:57 -0700)
create DCB related states in function state-machine
allow handling of DCB errors from FW
allow disablement of DCB in FW, when peer disappears or error
clean up unused functions/variables as pointed by
David Binderman <dcb314@hotmail.com>

Reported-by: David Binderman <dcb314@hotmail.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_dcb.c
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_sp.c
drivers/net/bnx2x/bnx2x_sp.h

index 53fa8ea983e969a2b236f9d92b0573868b9bb3b4..333f5d6c6b81d2b850e5609c875e5e2a50b208e9 100644 (file)
@@ -966,6 +966,8 @@ struct bnx2x_slowpath {
 
        union {
                struct function_start_data      func_start;
+               /* pfc configuration for DCBX ramrod */
+               struct flow_control_configuration pfc_config;
        } func_rdata;
 
        /* used by dmae command executer */
@@ -980,8 +982,6 @@ struct bnx2x_slowpath {
 
        u32                             wb_comp;
        u32                             wb_data[4];
-       /* pfc configuration for DCBX ramrod */
-       struct flow_control_configuration pfc_config;
 };
 
 #define bnx2x_sp(bp, var)              (&bp->slowpath->var)
@@ -1417,9 +1417,6 @@ struct bnx2x {
        char                    fw_ver[32];
        const struct firmware   *firmware;
 
-       /* LLDP params */
-       struct bnx2x_config_lldp_params         lldp_config_params;
-
        /* DCB support on/off */
        u16 dcb_state;
 #define BNX2X_DCB_STATE_OFF                    0
index 3bfba44961d3b66059777b47bbfacc7281e0fad2..d028794a22989deab9130afd4985141cca98eeda 100644 (file)
 #endif
 
 /* forward declarations of dcbx related functions */
-static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
+static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
 static void bnx2x_pfc_set_pfc(struct bnx2x *bp);
 static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);
-static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
+static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
 static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
                                          u32 *set_configuration_ets_pg,
                                          u32 *pri_pg_tbl);
@@ -47,8 +47,25 @@ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
                                struct cos_help_data *cos_data,
                                u32 *pg_pri_orginal_spread,
                                struct dcbx_ets_feature *ets);
-static void bnx2x_dcbx_fw_struct(struct bnx2x *bp);
+static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
+                                struct bnx2x_func_tx_start_params*);
 
+/* helpers: read/write len bytes from addr into buff by REG_RD/REG_WR */
+static void bnx2x_read_data(struct bnx2x *bp, u32 *buff,
+                                  u32 addr, u32 len)
+{
+       int i;
+       for (i = 0; i < len; i += 4, buff++)
+               *buff = REG_RD(bp, addr + i);
+}
+
+static void bnx2x_write_data(struct bnx2x *bp, u32 *buff,
+                                   u32 addr, u32 len)
+{
+       int i;
+       for (i = 0; i < len; i += 4, buff++)
+               REG_WR(bp, addr + i, *buff);
+}
 
 static void bnx2x_pfc_set(struct bnx2x *bp)
 {
@@ -205,7 +222,11 @@ static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,
        if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR))
                DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_ERROR\n");
 
-       if (app->enabled && !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR)) {
+       if (GET_FLAGS(error, DCBX_LOCAL_APP_MISMATCH))
+               DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_MISMATCH\n");
+
+       if (app->enabled &&
+           !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR | DCBX_LOCAL_APP_MISMATCH)) {
 
                bp->dcbx_port_params.app.enabled = true;
 
@@ -300,7 +321,7 @@ static void  bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp,
                DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_ERROR\n");
 
        if (bp->dcbx_port_params.app.enabled &&
-          !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR) &&
+          !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR | DCBX_LOCAL_PFC_MISMATCH) &&
           pfc->enabled) {
                bp->dcbx_port_params.pfc.enabled = true;
                bp->dcbx_port_params.pfc.priority_non_pauseable_mask =
@@ -329,8 +350,8 @@ static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
                               u32 offset,
                               int read_mib_type)
 {
-       int max_try_read = 0, i;
-       u32 *buff, mib_size, prefix_seq_num, suffix_seq_num;
+       int max_try_read = 0;
+       u32 mib_size, prefix_seq_num, suffix_seq_num;
        struct lldp_remote_mib *remote_mib ;
        struct lldp_local_mib  *local_mib;
 
@@ -349,9 +370,7 @@ static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
        offset += BP_PORT(bp) * mib_size;
 
        do {
-               buff = base_mib_addr;
-               for (i = 0; i < mib_size; i += 4, buff++)
-                       *buff = REG_RD(bp, offset + i);
+               bnx2x_read_data(bp, base_mib_addr, offset, mib_size);
 
                max_try_read++;
 
@@ -382,12 +401,8 @@ static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
 
 static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
 {
-       if (BP_PORT(bp)) {
-               BNX2X_ERR("4 port mode is not supported");
-               return;
-       }
-
-       if (bp->dcbx_port_params.pfc.enabled)
+       if (bp->dcbx_port_params.pfc.enabled &&
+           !(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR))
                /*
                 * 1. Fills up common PFC structures if required
                 * 2. Configure NIG, MAC and BRB via the elink
@@ -397,25 +412,30 @@ static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
                bnx2x_pfc_clear(bp);
 }
 
-static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
+static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
 {
-       DP(NETIF_MSG_LINK, "sending STOP TRAFFIC\n");
-       bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC,
-                     0 /* connectionless */,
-                     0 /* dataHi is zero */,
-                     0 /* dataLo is zero */,
-                     NONE_CONNECTION_TYPE);
+       struct bnx2x_func_state_params func_params = {0};
+
+       func_params.f_obj = &bp->func_obj;
+       func_params.cmd = BNX2X_F_CMD_TX_STOP;
+
+       DP(NETIF_MSG_LINK, "STOP TRAFFIC\n");
+       return bnx2x_func_state_change(bp, &func_params);
 }
 
-static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
+static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
 {
-       bnx2x_dcbx_fw_struct(bp);
-       DP(NETIF_MSG_LINK, "sending START TRAFFIC\n");
-       bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC,
-                     0, /* connectionless */
-                     U64_HI(bnx2x_sp_mapping(bp, pfc_config)),
-                     U64_LO(bnx2x_sp_mapping(bp, pfc_config)),
-                     NONE_CONNECTION_TYPE);
+       struct bnx2x_func_state_params func_params = {0};
+       struct bnx2x_func_tx_start_params *tx_params =
+               &func_params.params.tx_start;
+
+       func_params.f_obj = &bp->func_obj;
+       func_params.cmd = BNX2X_F_CMD_TX_START;
+
+       bnx2x_dcbx_fw_struct(bp, tx_params);
+
+       DP(NETIF_MSG_LINK, "START TRAFFIC\n");
+       return bnx2x_func_state_change(bp, &func_params);
 }
 
 static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)
@@ -522,7 +542,8 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
 {
        bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
 
-       if (!bp->dcbx_port_params.ets.enabled)
+       if (!bp->dcbx_port_params.ets.enabled ||
+           (bp->dcbx_error & DCBX_REMOTE_MIB_ERROR))
                return;
 
        if (CHIP_IS_E3B0(bp))
@@ -739,61 +760,14 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
        }
 }
 
-
-#define LLDP_STATS_OFFSET(bp)          (BP_PORT(bp)*\
-                                       sizeof(struct lldp_dcbx_stat))
-
-/* calculate struct offset in array according to chip information */
-#define LLDP_PARAMS_OFFSET(bp)         (BP_PORT(bp)*sizeof(struct lldp_params))
-
 #define LLDP_ADMIN_MIB_OFFSET(bp)      (PORT_MAX*sizeof(struct lldp_params) + \
                                      BP_PORT(bp)*sizeof(struct lldp_admin_mib))
 
-static void bnx2x_dcbx_lldp_updated_params(struct bnx2x *bp,
-                                          u32 dcbx_lldp_params_offset)
-{
-       struct lldp_params lldp_params = {0};
-       u32 i = 0, *buff = NULL;
-       u32 offset = dcbx_lldp_params_offset + LLDP_PARAMS_OFFSET(bp);
-
-       DP(NETIF_MSG_LINK, "lldp_offset 0x%x\n", offset);
-
-       if ((bp->lldp_config_params.overwrite_settings ==
-                               BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE)) {
-               /* Read the data first */
-               buff = (u32 *)&lldp_params;
-               for (i = 0; i < sizeof(struct lldp_params); i += 4,  buff++)
-                       *buff = REG_RD(bp, (offset + i));
-
-               lldp_params.msg_tx_hold =
-                       (u8)bp->lldp_config_params.msg_tx_hold;
-               lldp_params.msg_fast_tx_interval =
-                       (u8)bp->lldp_config_params.msg_fast_tx;
-               lldp_params.tx_crd_max =
-                       (u8)bp->lldp_config_params.tx_credit_max;
-               lldp_params.msg_tx_interval =
-                       (u8)bp->lldp_config_params.msg_tx_interval;
-               lldp_params.tx_fast =
-                       (u8)bp->lldp_config_params.tx_fast;
-
-               /* Write the data.*/
-               buff = (u32 *)&lldp_params;
-               for (i = 0; i < sizeof(struct lldp_params); i += 4, buff++)
-                       REG_WR(bp, (offset + i) , *buff);
-
-
-       } else if (BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE ==
-                               bp->lldp_config_params.overwrite_settings)
-               bp->lldp_config_params.overwrite_settings =
-                               BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID;
-}
-
 static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
                                u32 dcbx_lldp_params_offset)
 {
        struct lldp_admin_mib admin_mib;
        u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0;
-       u32 *buff;
        u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp);
 
        /*shortcuts*/
@@ -801,18 +775,18 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
        struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params;
 
        memset(&admin_mib, 0, sizeof(struct lldp_admin_mib));
-       buff = (u32 *)&admin_mib;
+
        /* Read the data first */
-       for (i = 0; i < sizeof(struct lldp_admin_mib); i += 4, buff++)
-               *buff = REG_RD(bp, (offset + i));
+       bnx2x_read_data(bp, (u32 *)&admin_mib, offset,
+                       sizeof(struct lldp_admin_mib));
 
        if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON)
                SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);
        else
                RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);
 
-       if ((BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE ==
-                               dp->overwrite_settings)) {
+       if (dp->overwrite_settings == BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE) {
+
                RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK);
                admin_mib.ver_cfg_flags |=
                        (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) &
@@ -908,19 +882,17 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
 
                af->app.default_pri = (u8)dp->admin_default_priority;
 
-       } else if (BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE ==
-                                               dp->overwrite_settings)
-               dp->overwrite_settings = BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID;
+       }
 
        /* Write the data. */
-       buff = (u32 *)&admin_mib;
-       for (i = 0; i < sizeof(struct lldp_admin_mib); i += 4, buff++)
-               REG_WR(bp, (offset + i), *buff);
+       bnx2x_write_data(bp, (u32 *)&admin_mib, offset,
+                        sizeof(struct lldp_admin_mib));
+
 }
 
 void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
 {
-       if (!CHIP_IS_E1x(bp) && !CHIP_MODE_IS_4_PORT(bp)) {
+       if (!CHIP_IS_E1x(bp)) {
                bp->dcb_state = dcb_on;
                bp->dcbx_enabled = dcbx_enabled;
        } else {
@@ -1029,9 +1001,6 @@ void bnx2x_dcbx_init(struct bnx2x *bp)
                bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
 
                if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
-                       bnx2x_dcbx_lldp_updated_params(bp,
-                                                      dcbx_lldp_params_offset);
-
                        bnx2x_dcbx_admin_mib_updated_params(bp,
                                dcbx_lldp_params_offset);
 
@@ -1043,7 +1012,7 @@ void bnx2x_dcbx_init(struct bnx2x *bp)
 }
 static void
 bnx2x_dcbx_print_cos_params(struct bnx2x *bp,
-                           struct flow_control_configuration *pfc_fw_cfg)
+                           struct bnx2x_func_tx_start_params *pfc_fw_cfg)
 {
        u8 pri = 0;
        u8 cos = 0;
@@ -1821,17 +1790,19 @@ static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
        }
 }
 
-static void bnx2x_dcbx_fw_struct(struct bnx2x *bp)
+static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
+                                struct bnx2x_func_tx_start_params *pfc_fw_cfg)
 {
-       struct flow_control_configuration   *pfc_fw_cfg = NULL;
        u16 pri_bit = 0;
        u8 cos = 0, pri = 0;
        struct priority_cos *tt2cos;
        u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 
-       pfc_fw_cfg = (struct flow_control_configuration *)
-                                       bnx2x_sp(bp, pfc_config);
-       memset(pfc_fw_cfg, 0, sizeof(struct flow_control_configuration));
+       memset(pfc_fw_cfg, 0, sizeof(*pfc_fw_cfg));
+
+       /* to disable DCB - the structure must be zeroed */
+       if (bp->dcbx_error & DCBX_REMOTE_MIB_ERROR)
+               return;
 
        /*shortcut*/
        tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos;
index ce3b5662ca5acdde6f298d13466e60c5741b143e..06727f32e5050a9c43a09a2363008f1c02045f17 100644 (file)
@@ -1834,6 +1834,7 @@ struct lldp_local_mib {
        #define DCBX_LOCAL_APP_ERROR             0x00000004
        #define DCBX_LOCAL_PFC_MISMATCH          0x00000010
        #define DCBX_LOCAL_APP_MISMATCH          0x00000020
+       #define DCBX_REMOTE_MIB_ERROR            0x00000040
        struct dcbx_features   features;
        u32 suffix_seq_num;
 };
index 8a374a77cdc96928be0c08861123c9993cdbe87b..a86517cffd4ac8bee9af53bba1cb46cd9bfb9c6b 100644 (file)
@@ -4403,11 +4403,17 @@ static void bnx2x_eq_int(struct bnx2x *bp)
 
                case EVENT_RING_OPCODE_STOP_TRAFFIC:
                        DP(NETIF_MSG_IFUP, "got STOP TRAFFIC\n");
+                       if (f_obj->complete_cmd(bp, f_obj,
+                                               BNX2X_F_CMD_TX_STOP))
+                               break;
                        bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED);
                        goto next_spqe;
 
                case EVENT_RING_OPCODE_START_TRAFFIC:
                        DP(NETIF_MSG_IFUP, "got START TRAFFIC\n");
+                       if (f_obj->complete_cmd(bp, f_obj,
+                                               BNX2X_F_CMD_TX_START))
+                               break;
                        bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED);
                        goto next_spqe;
                case EVENT_RING_OPCODE_FUNCTION_START:
@@ -7536,6 +7542,71 @@ void bnx2x_send_unload_done(struct bnx2x *bp)
                bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
 }
 
+static inline int bnx2x_func_wait_started(struct bnx2x *bp)
+{
+       int tout = 50;
+       int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
+
+       if (!bp->port.pmf)
+               return 0;
+
+       /*
+        * (assumption: No Attention from MCP at this stage)
+        * PMF probably in the middle of TXdisable/enable transaction
+        * 1. Sync IRS for default SB
+        * 2. Sync SP queue - this guarantes us that attention handling started
+        * 3. Wait, that TXdisable/enable transaction completes
+        *
+        * 1+2 guranty that if DCBx attention was scheduled it already changed
+        * pending bit of transaction from STARTED-->TX_STOPPED, if we alredy
+        * received complettion for the transaction the state is TX_STOPPED.
+        * State will return to STARTED after completion of TX_STOPPED-->STARTED
+        * transaction.
+        */
+
+       /* make sure default SB ISR is done */
+       if (msix)
+               synchronize_irq(bp->msix_table[0].vector);
+       else
+               synchronize_irq(bp->pdev->irq);
+
+       flush_workqueue(bnx2x_wq);
+
+       while (bnx2x_func_get_state(bp, &bp->func_obj) !=
+                               BNX2X_F_STATE_STARTED && tout--)
+               msleep(20);
+
+       if (bnx2x_func_get_state(bp, &bp->func_obj) !=
+                                               BNX2X_F_STATE_STARTED) {
+#ifdef BNX2X_STOP_ON_ERROR
+               return -EBUSY;
+#else
+               /*
+                * Failed to complete the transaction in a "good way"
+                * Force both transactions with CLR bit
+                */
+               struct bnx2x_func_state_params func_params = {0};
+
+               DP(BNX2X_MSG_SP, "Hmmm... unexpected function state! "
+                         "Forcing STARTED-->TX_ST0PPED-->STARTED\n");
+
+               func_params.f_obj = &bp->func_obj;
+               __set_bit(RAMROD_DRV_CLR_ONLY,
+                                       &func_params.ramrod_flags);
+
+               /* STARTED-->TX_ST0PPED */
+               func_params.cmd = BNX2X_F_CMD_TX_STOP;
+               bnx2x_func_state_change(bp, &func_params);
+
+               /* TX_ST0PPED-->STARTED */
+               func_params.cmd = BNX2X_F_CMD_TX_START;
+               return bnx2x_func_state_change(bp, &func_params);
+#endif
+       }
+
+       return 0;
+}
+
 void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
 {
        int port = BP_PORT(bp);
@@ -7595,6 +7666,26 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
        netif_addr_unlock_bh(bp->dev);
 
 
+
+       /*
+        * Send the UNLOAD_REQUEST to the MCP. This will return if
+        * this function should perform FUNC, PORT or COMMON HW
+        * reset.
+        */
+       reset_code = bnx2x_send_unload_req(bp, unload_mode);
+
+       /*
+        * (assumption: No Attention from MCP at this stage)
+        * PMF probably in the middle of TXdisable/enable transaction
+        */
+       rc = bnx2x_func_wait_started(bp);
+       if (rc) {
+               BNX2X_ERR("bnx2x_func_wait_started failed\n");
+#ifdef BNX2X_STOP_ON_ERROR
+               return;
+#endif
+       }
+
        /* Close multi and leading connections
         * Completions for ramrods are collected in a synchronous way
         */
@@ -7622,13 +7713,6 @@ unload_error:
 #endif
        }
 
-       /*
-        * Send the UNLOAD_REQUEST to the MCP. This will return if
-        * this function should perform FUNC, PORT or COMMON HW
-        * reset.
-        */
-       reset_code = bnx2x_send_unload_req(bp, unload_mode);
-
        /* Disable HW interrupts, NAPI */
        bnx2x_netif_stop(bp, 1);
 
index 358c339975362641e75b8557c86ebb0b65a814e1..6306ff59de0c020573b8b19db836b89d73fbca55 100644 (file)
@@ -4874,6 +4874,22 @@ static int bnx2x_queue_chk_transition(struct bnx2x *bp,
                 &params->params.update;
        u8 next_tx_only = o->num_tx_only;
 
+       /*
+        * Forget all pending for completion commands if a driver only state
+        * transition has been requested.
+        */
+       if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
+               o->pending = 0;
+               o->next_state = BNX2X_Q_STATE_MAX;
+       }
+
+       /*
+        * Don't allow a next state transition if we are in the middle of
+        * the previous one.
+        */
+       if (o->pending)
+               return -EBUSY;
+
        switch (state) {
        case BNX2X_Q_STATE_RESET:
                if (cmd == BNX2X_Q_CMD_INIT)
@@ -5053,6 +5069,21 @@ void bnx2x_queue_set_cos_cid(struct bnx2x *bp,
 }
 
 /********************** Function state object *********************************/
+enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
+                                          struct bnx2x_func_sp_obj *o)
+{
+       /* in the middle of transaction - return INVALID state */
+       if (o->pending)
+               return BNX2X_F_STATE_MAX;
+
+       /*
+        * unsure the order of reading of o->pending and o->state
+        * o->pending should be read first
+        */
+       rmb();
+
+       return o->state;
+}
 
 static int bnx2x_func_wait_comp(struct bnx2x *bp,
                                struct bnx2x_func_sp_obj *o,
@@ -5143,6 +5174,22 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
        enum bnx2x_func_state state = o->state, next_state = BNX2X_F_STATE_MAX;
        enum bnx2x_func_cmd cmd = params->cmd;
 
+       /*
+        * Forget all pending for completion commands if a driver only state
+        * transition has been requested.
+        */
+       if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
+               o->pending = 0;
+               o->next_state = BNX2X_F_STATE_MAX;
+       }
+
+       /*
+        * Don't allow a next state transition if we are in the middle of
+        * the previous one.
+        */
+       if (o->pending)
+               return -EBUSY;
+
        switch (state) {
        case BNX2X_F_STATE_RESET:
                if (cmd == BNX2X_F_CMD_HW_INIT)
@@ -5160,6 +5207,13 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
        case BNX2X_F_STATE_STARTED:
                if (cmd == BNX2X_F_CMD_STOP)
                        next_state = BNX2X_F_STATE_INITIALIZED;
+               else if (cmd == BNX2X_F_CMD_TX_STOP)
+                       next_state = BNX2X_F_STATE_TX_STOPPED;
+
+               break;
+       case BNX2X_F_STATE_TX_STOPPED:
+               if (cmd == BNX2X_F_CMD_TX_START)
+                       next_state = BNX2X_F_STATE_STARTED;
 
                break;
        default:
@@ -5444,6 +5498,38 @@ static inline int bnx2x_func_send_stop(struct bnx2x *bp,
                             NONE_CONNECTION_TYPE);
 }
 
+static inline int bnx2x_func_send_tx_stop(struct bnx2x *bp,
+                                      struct bnx2x_func_state_params *params)
+{
+       return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC, 0, 0, 0,
+                            NONE_CONNECTION_TYPE);
+}
+static inline int bnx2x_func_send_tx_start(struct bnx2x *bp,
+                                      struct bnx2x_func_state_params *params)
+{
+       struct bnx2x_func_sp_obj *o = params->f_obj;
+       struct flow_control_configuration *rdata =
+               (struct flow_control_configuration *)o->rdata;
+       dma_addr_t data_mapping = o->rdata_mapping;
+       struct bnx2x_func_tx_start_params *tx_start_params =
+               &params->params.tx_start;
+       int i;
+
+       memset(rdata, 0, sizeof(*rdata));
+
+       rdata->dcb_enabled = tx_start_params->dcb_enabled;
+       rdata->dcb_version = tx_start_params->dcb_version;
+       rdata->dont_add_pri_0_en = tx_start_params->dont_add_pri_0_en;
+
+       for (i = 0; i < ARRAY_SIZE(rdata->traffic_type_to_priority_cos); i++)
+               rdata->traffic_type_to_priority_cos[i] =
+                       tx_start_params->traffic_type_to_priority_cos[i];
+
+       return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0,
+                            U64_HI(data_mapping),
+                            U64_LO(data_mapping), NONE_CONNECTION_TYPE);
+}
+
 static int bnx2x_func_send_cmd(struct bnx2x *bp,
                               struct bnx2x_func_state_params *params)
 {
@@ -5456,6 +5542,10 @@ static int bnx2x_func_send_cmd(struct bnx2x *bp,
                return bnx2x_func_send_stop(bp, params);
        case BNX2X_F_CMD_HW_RESET:
                return bnx2x_func_hw_reset(bp, params);
+       case BNX2X_F_CMD_TX_STOP:
+               return bnx2x_func_send_tx_stop(bp, params);
+       case BNX2X_F_CMD_TX_START:
+               return bnx2x_func_send_tx_start(bp, params);
        default:
                BNX2X_ERR("Unknown command: %d\n", params->cmd);
                return -EINVAL;
index 83f3b0b4421162cef76da66fa0c785a3ba3949c5..73400dd77b2fa45b04bc414c0a4fefaeae3207d0 100644 (file)
@@ -996,6 +996,7 @@ enum bnx2x_func_state {
        BNX2X_F_STATE_RESET,
        BNX2X_F_STATE_INITIALIZED,
        BNX2X_F_STATE_STARTED,
+       BNX2X_F_STATE_TX_STOPPED,
        BNX2X_F_STATE_MAX,
 };
 
@@ -1005,6 +1006,8 @@ enum bnx2x_func_cmd {
        BNX2X_F_CMD_START,
        BNX2X_F_CMD_STOP,
        BNX2X_F_CMD_HW_RESET,
+       BNX2X_F_CMD_TX_STOP,
+       BNX2X_F_CMD_TX_START,
        BNX2X_F_CMD_MAX,
 };
 
@@ -1047,6 +1050,13 @@ struct bnx2x_func_start_params {
        u8 network_cos_mode;
 };
 
+struct bnx2x_func_tx_start_params {
+       struct priority_cos traffic_type_to_priority_cos[MAX_TRAFFIC_TYPES];
+       u8 dcb_enabled;
+       u8 dcb_version;
+       u8 dont_add_pri_0_en;
+};
+
 struct bnx2x_func_state_params {
        struct bnx2x_func_sp_obj *f_obj;
 
@@ -1061,6 +1071,7 @@ struct bnx2x_func_state_params {
                struct bnx2x_func_hw_init_params hw_init;
                struct bnx2x_func_hw_reset_params hw_reset;
                struct bnx2x_func_start_params start;
+               struct bnx2x_func_tx_start_params tx_start;
        } params;
 };
 
@@ -1152,6 +1163,8 @@ void bnx2x_init_func_obj(struct bnx2x *bp,
 int bnx2x_func_state_change(struct bnx2x *bp,
                            struct bnx2x_func_state_params *params);
 
+enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
+                                          struct bnx2x_func_sp_obj *o);
 /******************* Queue State **************/
 void bnx2x_init_queue_obj(struct bnx2x *bp,
                          struct bnx2x_queue_sp_obj *obj, u8 cl_id, u32 *cids,