bnx2x: Support of PF driver of a VF q_teardown request
authorAriel Elior <ariele@broadcom.com>
Tue, 1 Jan 2013 05:22:39 +0000 (05:22 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Jan 2013 09:45:07 +0000 (01:45 -0800)
The 'q_teardown' request is basically the opposite of the 'q_setup'.
Here the PF driver removes from the device the queue it opened against
the VF fastpath ring at 'setup_q' stage, along with all related
rx_mode info.

Signed-off-by: Ariel Elior <ariele@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c

index e63925cbe501a9650fab67bb431faf45f81eb953..9fd43c079045f8901aa436f1b34b5b2be645122a 100644 (file)
@@ -111,6 +111,13 @@ enum bnx2x_vfop_qctor_state {
           BNX2X_VFOP_QCTOR_INT_EN
 };
 
+enum bnx2x_vfop_qdtor_state {
+          BNX2X_VFOP_QDTOR_HALT,
+          BNX2X_VFOP_QDTOR_TERMINATE,
+          BNX2X_VFOP_QDTOR_CFCDEL,
+          BNX2X_VFOP_QDTOR_DONE
+};
+
 enum bnx2x_vfop_vlan_mac_state {
           BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
           BNX2X_VFOP_VLAN_MAC_CLEAR,
@@ -137,6 +144,14 @@ enum bnx2x_vfop_rxmode_state {
           BNX2X_VFOP_RXMODE_DONE
 };
 
+enum bnx2x_vfop_qteardown_state {
+          BNX2X_VFOP_QTEARDOWN_RXMODE,
+          BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
+          BNX2X_VFOP_QTEARDOWN_CLR_MAC,
+          BNX2X_VFOP_QTEARDOWN_QDTOR,
+          BNX2X_VFOP_QTEARDOWN_DONE
+};
+
 #define bnx2x_vfop_reset_wq(vf)        atomic_set(&vf->op_in_progress, 0)
 
 void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
@@ -342,6 +357,101 @@ static int bnx2x_vfop_qctor_cmd(struct bnx2x *bp,
        return -ENOMEM;
 }
 
+/* VFOP queue destruction */
+static void bnx2x_vfop_qdtor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_args_qdtor *qdtor = &vfop->args.qdtor;
+       struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+       enum bnx2x_vfop_qdtor_state state = vfop->state;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_QDTOR_HALT:
+
+               /* has this queue already been stopped? */
+               if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+                   BNX2X_Q_LOGICAL_STATE_STOPPED) {
+                       DP(BNX2X_MSG_IOV,
+                          "Entered qdtor but queue was already stopped. Aborting gracefully\n");
+                       goto op_done;
+               }
+
+               /* next state */
+               vfop->state = BNX2X_VFOP_QDTOR_TERMINATE;
+
+               q_params->cmd = BNX2X_Q_CMD_HALT;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_QDTOR_TERMINATE:
+               /* next state */
+               vfop->state = BNX2X_VFOP_QDTOR_CFCDEL;
+
+               q_params->cmd = BNX2X_Q_CMD_TERMINATE;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_QDTOR_CFCDEL:
+               /* next state */
+               vfop->state = BNX2X_VFOP_QDTOR_DONE;
+
+               q_params->cmd = BNX2X_Q_CMD_CFC_DEL;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+       BNX2X_ERR("QDTOR[%d:%d] error: cmd %d, rc %d\n",
+                 vf->abs_vfid, qdtor->qid, q_params->cmd, vfop->rc);
+op_done:
+       case BNX2X_VFOP_QDTOR_DONE:
+               /* invalidate the context */
+               qdtor->cxt->ustorm_ag_context.cdu_usage = 0;
+               qdtor->cxt->xstorm_ag_context.cdu_reserved = 0;
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_pending:
+       return;
+}
+
+static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
+                               struct bnx2x_virtf *vf,
+                               struct bnx2x_vfop_cmd *cmd,
+                               int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_queue_state_params *qstate =
+                       &vf->op_params.qctor.qstate;
+
+               memset(qstate, 0, sizeof(*qstate));
+               qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+               vfop->args.qdtor.qid = qid;
+               vfop->args.qdtor.cxt = bnx2x_vfq(vf, qid, cxt);
+
+               bnx2x_vfop_opset(BNX2X_VFOP_QDTOR_HALT,
+                                bnx2x_vfop_qdtor, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
+                                            cmd->block);
+       }
+       DP(BNX2X_MSG_IOV, "VF[%d] failed to add a vfop. rc %d\n",
+          vf->abs_vfid, vfop->rc);
+       return -ENOMEM;
+}
+
 static void
 bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
 {
@@ -593,6 +703,44 @@ bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
        set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
 }
 
+static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp,
+                                    struct bnx2x_virtf *vf,
+                                    struct bnx2x_vfop_cmd *cmd,
+                                    int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = NULL,   /* single */
+                       .credit = NULL,         /* consume credit */
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = true,
+                       .add = false /* don't care */,
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+               /* set extra args */
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
 int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
                            struct bnx2x_virtf *vf,
                            struct bnx2x_vfop_cmd *cmd,
@@ -675,6 +823,44 @@ int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
        return -ENOMEM;
 }
 
+static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp,
+                              struct bnx2x_virtf *vf,
+                              struct bnx2x_vfop_cmd *cmd,
+                              int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = NULL, /* single command */
+                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = true,
+                       .add = false, /* don't care */
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+               /* set extra args */
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
 int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
                             struct bnx2x_virtf *vf,
                             struct bnx2x_vfop_cmd *cmd,
@@ -956,6 +1142,89 @@ int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
        return -ENOMEM;
 }
 
+/* VFOP queue tear-down ('drop all' rx-mode, clear vlans, clear macs,
+ * queue destructor)
+ */
+static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       int qid = vfop->args.qx.qid;
+       enum bnx2x_vfop_qteardown_state state = vfop->state;
+       struct bnx2x_vfop_cmd cmd;
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       cmd.done = bnx2x_vfop_qdown;
+       cmd.block = false;
+
+       switch (state) {
+       case BNX2X_VFOP_QTEARDOWN_RXMODE:
+               /* Drop all */
+               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN;
+               vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QTEARDOWN_CLR_VLAN:
+               /* vlan-clear-all: don't consume credit */
+               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MAC;
+               vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, false);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
+               /* mac-clear-all: consume credit */
+               vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
+               vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QTEARDOWN_QDTOR:
+               /* run the queue destruction flow */
+               DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
+               vfop->state = BNX2X_VFOP_QTEARDOWN_DONE;
+               DP(BNX2X_MSG_IOV, "new state: BNX2X_VFOP_QTEARDOWN_DONE\n");
+               vfop->rc = bnx2x_vfop_qdtor_cmd(bp, vf, &cmd, qid);
+               DP(BNX2X_MSG_IOV, "returned from cmd\n");
+               if (vfop->rc)
+                       goto op_err;
+               return;
+op_err:
+       BNX2X_ERR("QTEARDOWN[%d:%d] error: rc %d\n",
+                 vf->abs_vfid, qid, vfop->rc);
+
+       case BNX2X_VFOP_QTEARDOWN_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+}
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               vfop->args.qx.qid = qid;
+               bnx2x_vfop_opset(BNX2X_VFOP_QTEARDOWN_RXMODE,
+                                bnx2x_vfop_qdown, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdown,
+                                            cmd->block);
+       }
+
+       return -ENOMEM;
+}
+
 /* VF enable primitives
  * when pretend is required the caller is responsible
  * for calling pretend prior to calling these routines
index f75bd65e46aeb7d5c27f0736f078508485a156f8..9f0099c543e0c0ab59555f9dbb0c6b33ddd54769 100644 (file)
@@ -641,6 +641,11 @@ int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
                          struct bnx2x_vfop_cmd *cmd,
                          int qid);
 
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        int qid);
+
 int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
                         struct bnx2x_virtf *vf,
                         struct bnx2x_vfop_cmd *cmd,
index ad92bf4227b0ed9ffda4531492746a8815ee4128..af30eb4a37bf8b6cfb6050fce48a350949800966 100644 (file)
@@ -787,6 +787,23 @@ response:
        bnx2x_vf_mbx_resp(bp, vf);
 }
 
+static void bnx2x_vf_mbx_teardown_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                   struct bnx2x_vf_mbx *mbx)
+{
+       int qid = mbx->msg->req.q_op.vf_qid;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "VF[%d] Q_TEARDOWN: vf_qid=%d\n",
+          vf->abs_vfid, qid);
+
+       vf->op_rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qid);
+       if (vf->op_rc)
+               bnx2x_vf_mbx_resp(bp, vf);
+}
+
 /* dispatch request */
 static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                  struct bnx2x_vf_mbx *mbx)
@@ -814,7 +831,11 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                case CHANNEL_TLV_SET_Q_FILTERS:
                        bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
                        break;
+               case CHANNEL_TLV_TEARDOWN_Q:
+                       bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
+                       break;
                }
+
        } else {
                /* unknown TLV - this may belong to a VF driver from the future
                 * - a version written after this PF driver was written, which