]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
bnx2x: Support of PF driver of a VF q_filters request
authorAriel Elior <ariele@broadcom.com>
Tue, 1 Jan 2013 05:22:38 +0000 (05:22 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Jan 2013 09:45:07 +0000 (01:45 -0800)
The VF driver uses the 'q_filters' message on the VF <-> PF channel
for configuring an open queue, for example when the rxmode changes.

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 5b47b0849a58d467915d3067191a28af3a42c335..e63925cbe501a9650fab67bb431faf45f81eb953 100644 (file)
@@ -102,6 +102,8 @@ static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
 }
 /* VFOP - VF slow-path operation support */
 
+#define BNX2X_VFOP_FILTER_ADD_CNT_MAX          0x10000
+
 /* VFOP operations states */
 enum bnx2x_vfop_qctor_state {
           BNX2X_VFOP_QCTOR_INIT,
@@ -124,6 +126,17 @@ enum bnx2x_vfop_qsetup_state {
           BNX2X_VFOP_QSETUP_DONE
 };
 
+enum bnx2x_vfop_mcast_state {
+          BNX2X_VFOP_MCAST_DEL,
+          BNX2X_VFOP_MCAST_ADD,
+          BNX2X_VFOP_MCAST_CHK_DONE
+};
+
+enum bnx2x_vfop_rxmode_state {
+          BNX2X_VFOP_RXMODE_CONFIG,
+          BNX2X_VFOP_RXMODE_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,
@@ -572,6 +585,57 @@ bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
        ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
 }
 
+static inline void
+bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+                          struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+       bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
+       set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
+}
+
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           struct bnx2x_vfop_filters *macs,
+                           int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = macs,
+                       .credit = NULL,         /* consume credit */
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = false,
+                       .add = false, /* don't care since only the items in the
+                                      * filters list affect the sp operation,
+                                      * not the list itself
+                                      */
+               };
+               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 */
+               filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
 int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
                            struct bnx2x_virtf *vf,
                            struct bnx2x_vfop_cmd *cmd,
@@ -611,6 +675,48 @@ int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
        return -ENOMEM;
 }
 
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+                            struct bnx2x_virtf *vf,
+                            struct bnx2x_vfop_cmd *cmd,
+                            struct bnx2x_vfop_filters *vlans,
+                            int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = vlans,
+                       .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 = false,
+                       .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 */
+               filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
+                       atomic_read(filters.credit);
+
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
 /* VFOP queue setup (queue constructor + set vlan 0) */
 static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
@@ -676,6 +782,180 @@ int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
        return -ENOMEM;
 }
 
+/* VFOP multi-casts */
+static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
+       struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
+       struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
+       enum bnx2x_vfop_mcast_state state = vfop->state;
+       int i;
+
+       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_MCAST_DEL:
+               /* clear existing mcasts */
+               vfop->state = BNX2X_VFOP_MCAST_ADD;
+               vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_MCAST_ADD:
+               if (raw->check_pending(raw))
+                       goto op_pending;
+
+               if (args->mc_num) {
+                       /* update mcast list on the ramrod params */
+                       INIT_LIST_HEAD(&mcast->mcast_list);
+                       for (i = 0; i < args->mc_num; i++)
+                               list_add_tail(&(args->mc[i].link),
+                                             &mcast->mcast_list);
+                       /* add new mcasts */
+                       vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
+                       vfop->rc = bnx2x_config_mcast(bp, mcast,
+                                                     BNX2X_MCAST_CMD_ADD);
+               }
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       case BNX2X_VFOP_MCAST_CHK_DONE:
+               vfop->rc = raw->check_pending(raw) ? 1 : 0;
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_err:
+       BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
+op_done:
+       kfree(args->mc);
+       bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+       return;
+}
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        bnx2x_mac_addr_t *mcasts,
+                        int mcast_num, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = NULL;
+       size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
+       struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
+                                          NULL;
+
+       if (!mc_sz || mc) {
+               vfop = bnx2x_vfop_add(bp, vf);
+               if (vfop) {
+                       int i;
+                       struct bnx2x_mcast_ramrod_params *ramrod =
+                               &vf->op_params.mcast;
+
+                       /* set ramrod params */
+                       memset(ramrod, 0, sizeof(*ramrod));
+                       ramrod->mcast_obj = &vf->mcast_obj;
+                       if (drv_only)
+                               set_bit(RAMROD_DRV_CLR_ONLY,
+                                       &ramrod->ramrod_flags);
+
+                       /* copy mcasts pointers */
+                       vfop->args.mc_list.mc_num = mcast_num;
+                       vfop->args.mc_list.mc = mc;
+                       for (i = 0; i < mcast_num; i++)
+                               mc[i].mac = mcasts[i];
+
+                       bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
+                                        bnx2x_vfop_mcast, cmd->done);
+                       return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
+                                                    cmd->block);
+               } else {
+                       kfree(mc);
+               }
+       }
+       return -ENOMEM;
+}
+
+/* VFOP rx-mode */
+static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
+       enum bnx2x_vfop_rxmode_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_RXMODE_CONFIG:
+               /* next state */
+               vfop->state = BNX2X_VFOP_RXMODE_DONE;
+
+               vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+               BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
+op_done:
+       case BNX2X_VFOP_RXMODE_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_pending:
+       return;
+}
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+                         struct bnx2x_virtf *vf,
+                         struct bnx2x_vfop_cmd *cmd,
+                         int qid, unsigned long accept_flags)
+{
+       struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_rx_mode_ramrod_params *ramrod =
+                       &vf->op_params.rx_mode;
+
+               memset(ramrod, 0, sizeof(*ramrod));
+
+               /* Prepare ramrod parameters */
+               ramrod->cid = vfq->cid;
+               ramrod->cl_id = vfq_cl_id(vf, vfq);
+               ramrod->rx_mode_obj = &bp->rx_mode_obj;
+               ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
+
+               ramrod->rx_accept_flags = accept_flags;
+               ramrod->tx_accept_flags = accept_flags;
+               ramrod->pstate = &vf->filter_state;
+               ramrod->state = BNX2X_FILTER_RX_MODE_PENDING;
+
+               set_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+               set_bit(RAMROD_RX, &ramrod->ramrod_flags);
+               set_bit(RAMROD_TX, &ramrod->ramrod_flags);
+
+               ramrod->rdata =
+                       bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
+               ramrod->rdata_mapping =
+                       bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
+
+               bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
+                                bnx2x_vfop_rxmode, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
 /* VF enable primitives
  * when pretend is required the caller is responsible
  * for calling pretend prior to calling these routines
index 49d452e9117457b37da97c93359f9eb5aee6a254..f75bd65e46aeb7d5c27f0736f078508485a156f8 100644 (file)
@@ -441,6 +441,10 @@ void bnx2x_iov_sp_task(struct bnx2x *bp);
 /* global vf mailbox routines */
 void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
 void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
+
+/* CORE VF API */
+typedef u8 bnx2x_mac_addr_t[ETH_ALEN];
+
 /* acquire */
 int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
                     struct vf_pf_resc_request *resc);
@@ -615,11 +619,39 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
                           struct bnx2x_vf_queue *q,
                           struct bnx2x_vfop_qctor_params *p,
                           unsigned long q_type);
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           struct bnx2x_vfop_filters *macs,
+                           int qid, bool drv_only);
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           int qid, u16 vid, bool add);
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+                            struct bnx2x_virtf *vf,
+                            struct bnx2x_vfop_cmd *cmd,
+                            struct bnx2x_vfop_filters *vlans,
+                            int qid, bool drv_only);
+
 int bnx2x_vfop_qsetup_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,
+                        bnx2x_mac_addr_t *mcasts,
+                        int mcast_num, bool drv_only);
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+                         struct bnx2x_virtf *vf,
+                         struct bnx2x_vfop_cmd *cmd,
+                         int qid, unsigned long accept_flags);
+
 int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
 u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
 /* VF FLR helpers */
index 6605567e4b0c73879a6fef60d213332abf75b4fe..ad92bf4227b0ed9ffda4531492746a8815ee4128 100644 (file)
@@ -513,6 +513,280 @@ response:
        bnx2x_vf_mbx_resp(bp, vf);
 }
 
+enum bnx2x_vfop_filters_state {
+          BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+          BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
+          BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
+          BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
+          BNX2X_VFOP_MBX_Q_FILTERS_DONE
+};
+
+static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
+                                    struct bnx2x_virtf *vf,
+                                    struct vfpf_set_q_filters_tlv *tlv,
+                                    struct bnx2x_vfop_filters **pfl,
+                                    u32 type_flag)
+{
+       int i, j;
+       struct bnx2x_vfop_filters *fl = NULL;
+       size_t fsz;
+
+       fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
+               sizeof(struct bnx2x_vfop_filters);
+
+       fl = kzalloc(fsz, GFP_KERNEL);
+       if (!fl)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&fl->head);
+
+       for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
+               struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
+
+               if ((msg_filter->flags & type_flag) != type_flag)
+                       continue;
+               if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
+                       fl->filters[j].mac = msg_filter->mac;
+                       fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
+               } else {
+                       fl->filters[j].vid = msg_filter->vlan_tag;
+                       fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
+               }
+               fl->filters[j].add =
+                       (msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
+                       true : false;
+               list_add_tail(&fl->filters[j++].link, &fl->head);
+       }
+       if (list_empty(&fl->head))
+               kfree(fl);
+       else
+               *pfl = fl;
+
+       return 0;
+}
+
+static void bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx,
+                                      struct vfpf_q_mac_vlan_filter *filter)
+{
+       DP(msglvl, "MAC-VLAN[%d] -- flags=0x%x\n", idx, filter->flags);
+       if (filter->flags & VFPF_Q_FILTER_VLAN_TAG_VALID)
+               DP_CONT(msglvl, ", vlan=%d", filter->vlan_tag);
+       if (filter->flags & VFPF_Q_FILTER_DEST_MAC_VALID)
+               DP_CONT(msglvl, ", MAC=%pM", filter->mac);
+       DP_CONT(msglvl, "\n");
+}
+
+static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
+                                      struct vfpf_set_q_filters_tlv *filters)
+{
+       int i;
+
+       if (filters->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED)
+               for (i = 0; i < filters->n_mac_vlan_filters; i++)
+                       bnx2x_vf_mbx_dp_q_filter(bp, msglvl, i,
+                                                &filters->filters[i]);
+
+       if (filters->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED)
+               DP(msglvl, "RX-MASK=0x%x\n", filters->rx_mask);
+
+       if (filters->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED)
+               for (i = 0; i < filters->n_multicast; i++)
+                       DP(msglvl, "MULTICAST=%pM\n", filters->multicast[i]);
+}
+
+#define VFPF_MAC_FILTER                VFPF_Q_FILTER_DEST_MAC_VALID
+#define VFPF_VLAN_FILTER       VFPF_Q_FILTER_VLAN_TAG_VALID
+
+static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       int rc;
+
+       struct vfpf_set_q_filters_tlv *msg =
+               &BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
+
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       enum bnx2x_vfop_filters_state state = vfop->state;
+
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vfop_mbx_qfilters,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       switch (state) {
+       case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
+
+               /* check for any vlan/mac changes */
+               if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+                       /* build mac list */
+                       struct bnx2x_vfop_filters *fl = NULL;
+
+                       vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+                                                            VFPF_MAC_FILTER);
+                       if (vfop->rc)
+                               goto op_err;
+
+                       if (fl) {
+                               /* set mac list */
+                               rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
+                                                            msg->vf_qid,
+                                                            false);
+                               if (rc) {
+                                       vfop->rc = rc;
+                                       goto op_err;
+                               }
+                               return;
+                       }
+               }
+               /* fall through */
+
+       case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
+
+               /* check for any vlan/mac changes */
+               if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+                       /* build vlan list */
+                       struct bnx2x_vfop_filters *fl = NULL;
+
+                       vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+                                                            VFPF_VLAN_FILTER);
+                       if (vfop->rc)
+                               goto op_err;
+
+                       if (fl) {
+                               /* set vlan list */
+                               rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
+                                                             msg->vf_qid,
+                                                             false);
+                               if (rc) {
+                                       vfop->rc = rc;
+                                       goto op_err;
+                               }
+                               return;
+                       }
+               }
+               /* fall through */
+
+       case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
+
+               if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
+                       unsigned long accept = 0;
+
+                       /* covert VF-PF if mask to bnx2x accept flags */
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
+                               __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
+
+                       if (msg->rx_mask &
+                                       VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
+                               __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
+
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
+                               __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
+
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
+                               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
+
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
+                               __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
+
+                       /* A packet arriving the vf's mac should be accepted
+                        * with any vlan
+                        */
+                       __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
+
+                       /* set rx-mode */
+                       rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
+                                                  msg->vf_qid, accept);
+                       if (rc) {
+                               vfop->rc = rc;
+                               goto op_err;
+                       }
+                       return;
+               }
+               /* fall through */
+
+       case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
+
+               if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
+                       /* set mcasts */
+                       rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
+                                                 msg->n_multicast, false);
+                       if (rc) {
+                               vfop->rc = rc;
+                               goto op_err;
+                       }
+                       return;
+               }
+               /* fall through */
+op_done:
+       case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+op_err:
+       BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
+                 vf->abs_vfid, msg->vf_qid, vfop->rc);
+       goto op_done;
+
+       default:
+               bnx2x_vfop_default(state);
+       }
+}
+
+static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp,
+                                       struct bnx2x_virtf *vf,
+                                       struct bnx2x_vfop_cmd *cmd)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       if (vfop) {
+               bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+                                bnx2x_vfop_mbx_qfilters, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
+                                      struct bnx2x_virtf *vf,
+                                      struct bnx2x_vf_mbx *mbx)
+{
+       struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       /* verify vf_qid */
+       if (filters->vf_qid > vf_rxq_count(vf))
+               goto response;
+
+       DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n",
+          vf->abs_vfid,
+          filters->vf_qid);
+
+       /* print q_filter message */
+       bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters);
+
+       vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd);
+       if (vf->op_rc)
+               goto response;
+       return;
+
+response:
+       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)
@@ -537,6 +811,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                case CHANNEL_TLV_SETUP_Q:
                        bnx2x_vf_mbx_setup_q(bp, vf, mbx);
                        break;
+               case CHANNEL_TLV_SET_Q_FILTERS:
+                       bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
+                       break;
                }
        } else {
                /* unknown TLV - this may belong to a VF driver from the future