return -EPERM;
 }
 
+int MLX4_CMD_GET_OP_REQ_wrapper(struct mlx4_dev *dev, int slave,
+                    struct mlx4_vhcr *vhcr,
+                    struct mlx4_cmd_mailbox *inbox,
+                    struct mlx4_cmd_mailbox *outbox,
+                    struct mlx4_cmd_info *cmd)
+{
+       return -EPERM;
+}
+
 int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
                     struct mlx4_vhcr *vhcr,
                     struct mlx4_cmd_mailbox *inbox,
                .verify = NULL,
                .wrapper = MLX4_CMD_UPDATE_QP_wrapper
        },
+       {
+               .opcode = MLX4_CMD_GET_OP_REQ,
+               .has_inbox = false,
+               .has_outbox = false,
+               .out_is_imm = false,
+               .encode_slave_id = false,
+               .verify = NULL,
+               .wrapper = MLX4_CMD_GET_OP_REQ_wrapper,
+       },
        {
                .opcode = MLX4_CMD_CONF_SPECIAL_QP,
                .has_inbox = false,
 
                               (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)          | \
                               (1ull << MLX4_EVENT_TYPE_CMD)                | \
+                              (1ull << MLX4_EVENT_TYPE_OP_REQUIRED)        | \
                               (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL)       | \
                               (1ull << MLX4_EVENT_TYPE_FLR_EVENT)          | \
                               (1ull << MLX4_EVENT_TYPE_FATAL_WARNING))
                        mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn);
                        break;
 
+               case MLX4_EVENT_TYPE_OP_REQUIRED:
+                       atomic_inc(&priv->opreq_count);
+                       /* FW commands can't be executed from interrupt context
+                        * working in deferred task
+                        */
+                       queue_work(mlx4_wq, &priv->opreq_task);
+                       break;
+
                case MLX4_EVENT_TYPE_COMM_CHANNEL:
                        if (!mlx4_is_master(dev)) {
                                mlx4_warn(dev, "Received comm channel event "
 
                        MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
 }
 EXPORT_SYMBOL_GPL(mlx4_wol_write);
+
+enum {
+       ADD_TO_MCG = 0x26,
+};
+
+
+void mlx4_opreq_action(struct work_struct *work)
+{
+       struct mlx4_priv *priv = container_of(work, struct mlx4_priv,
+                                             opreq_task);
+       struct mlx4_dev *dev = &priv->dev;
+       int num_tasks = atomic_read(&priv->opreq_count);
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_mgm *mgm;
+       u32 *outbox;
+       u32 modifier;
+       u16 token;
+       u16 type_m;
+       u16 type;
+       int err;
+       u32 num_qps;
+       struct mlx4_qp qp;
+       int i;
+       u8 rem_mcg;
+       u8 prot;
+
+#define GET_OP_REQ_MODIFIER_OFFSET     0x08
+#define GET_OP_REQ_TOKEN_OFFSET                0x14
+#define GET_OP_REQ_TYPE_OFFSET         0x1a
+#define GET_OP_REQ_DATA_OFFSET         0x20
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox)) {
+               mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n");
+               return;
+       }
+       outbox = mailbox->buf;
+
+       while (num_tasks) {
+               err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
+                                  MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
+                                  MLX4_CMD_NATIVE);
+               if (err) {
+                       mlx4_err(dev, "Failed to retreive required operation: %d\n",
+                                err);
+                       return;
+               }
+               MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET);
+               MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET);
+               MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET);
+               type_m = type >> 12;
+               type &= 0xfff;
+
+               switch (type) {
+               case ADD_TO_MCG:
+                       if (dev->caps.steering_mode ==
+                           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+                               mlx4_warn(dev, "ADD MCG operation is not supported in DEVICE_MANAGED steering mode\n");
+                               err = EPERM;
+                               break;
+                       }
+                       mgm = (struct mlx4_mgm *)((u8 *)(outbox) +
+                                                 GET_OP_REQ_DATA_OFFSET);
+                       num_qps = be32_to_cpu(mgm->members_count) &
+                                 MGM_QPN_MASK;
+                       rem_mcg = ((u8 *)(&mgm->members_count))[0] & 1;
+                       prot = ((u8 *)(&mgm->members_count))[0] >> 6;
+
+                       for (i = 0; i < num_qps; i++) {
+                               qp.qpn = be32_to_cpu(mgm->qp[i]);
+                               if (rem_mcg)
+                                       err = mlx4_multicast_detach(dev, &qp,
+                                                                   mgm->gid,
+                                                                   prot, 0);
+                               else
+                                       err = mlx4_multicast_attach(dev, &qp,
+                                                                   mgm->gid,
+                                                                   mgm->gid[5]
+                                                                   , 0, prot,
+                                                                   NULL);
+                               if (err)
+                                       break;
+                       }
+                       break;
+               default:
+                       mlx4_warn(dev, "Bad type for required operation\n");
+                       err = EINVAL;
+                       break;
+               }
+               err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16),
+                              1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
+                              MLX4_CMD_NATIVE);
+               if (err) {
+                       mlx4_err(dev, "Failed to acknowledge required request: %d\n",
+                                err);
+                       goto out;
+               }
+               memset(outbox, 0, 0xffc);
+               num_tasks = atomic_dec_return(&priv->opreq_count);
+       }
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+}
 
 int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
 int mlx4_NOP(struct mlx4_dev *dev);
 int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg);
+void mlx4_opreq_action(struct work_struct *work);
 
 #endif /* MLX4_FW_H */
 
                goto err_xrcd_table_free;
        }
 
+       if (!mlx4_is_slave(dev)) {
+               err = mlx4_init_mcg_table(dev);
+               if (err) {
+                       mlx4_err(dev, "Failed to initialize multicast group table, aborting.\n");
+                       goto err_mr_table_free;
+               }
+       }
+
        err = mlx4_init_eq_table(dev);
        if (err) {
                mlx4_err(dev, "Failed to initialize "
                         "event queue table, aborting.\n");
-               goto err_mr_table_free;
+               goto err_mcg_table_free;
        }
 
        err = mlx4_cmd_use_events(dev);
                goto err_srq_table_free;
        }
 
-       if (!mlx4_is_slave(dev)) {
-               err = mlx4_init_mcg_table(dev);
-               if (err) {
-                       mlx4_err(dev, "Failed to initialize "
-                                "multicast group table, aborting.\n");
-                       goto err_qp_table_free;
-               }
-       }
-
        err = mlx4_init_counters_table(dev);
        if (err && err != -ENOENT) {
                mlx4_err(dev, "Failed to initialize counters table, aborting.\n");
-               goto err_mcg_table_free;
+               goto err_qp_table_free;
        }
 
        if (!mlx4_is_slave(dev)) {
 err_counters_table_free:
        mlx4_cleanup_counters_table(dev);
 
-err_mcg_table_free:
-       mlx4_cleanup_mcg_table(dev);
-
 err_qp_table_free:
        mlx4_cleanup_qp_table(dev);
 
 err_eq_table_free:
        mlx4_cleanup_eq_table(dev);
 
+err_mcg_table_free:
+       if (!mlx4_is_slave(dev))
+               mlx4_cleanup_mcg_table(dev);
+
 err_mr_table_free:
        mlx4_cleanup_mr_table(dev);
 
                        }
                }
 
+               atomic_set(&priv->opreq_count, 0);
+               INIT_WORK(&priv->opreq_task, mlx4_opreq_action);
+
                /*
                 * Now reset the HCA before we touch the PCI capabilities or
                 * attempt a firmware command, since a boot ROM may have left
                mlx4_cleanup_port_info(&priv->port[port]);
 
        mlx4_cleanup_counters_table(dev);
-       mlx4_cleanup_mcg_table(dev);
        mlx4_cleanup_qp_table(dev);
        mlx4_cleanup_srq_table(dev);
        mlx4_cleanup_cq_table(dev);
        mlx4_cmd_use_polling(dev);
        mlx4_cleanup_eq_table(dev);
+       mlx4_cleanup_mcg_table(dev);
        mlx4_cleanup_mr_table(dev);
        mlx4_cleanup_xrcd_table(dev);
        mlx4_cleanup_pd_table(dev);
                                                   RES_TR_FREE_SLAVES_ONLY);
 
                mlx4_cleanup_counters_table(dev);
-               mlx4_cleanup_mcg_table(dev);
                mlx4_cleanup_qp_table(dev);
                mlx4_cleanup_srq_table(dev);
                mlx4_cleanup_cq_table(dev);
                mlx4_cmd_use_polling(dev);
                mlx4_cleanup_eq_table(dev);
+               mlx4_cleanup_mcg_table(dev);
                mlx4_cleanup_mr_table(dev);
                mlx4_cleanup_xrcd_table(dev);
                mlx4_cleanup_pd_table(dev);
 
 
 #include "mlx4.h"
 
-#define MGM_QPN_MASK       0x00FFFFFF
-#define MGM_BLCK_LB_BIT    30
-
 static const u8 zero_gid[16];  /* automatically initialized to 0 */
 
-struct mlx4_mgm {
-       __be32                  next_gid_index;
-       __be32                  members_count;
-       u32                     reserved[2];
-       u8                      gid[16];
-       __be32                  qp[MLX4_MAX_QP_PER_MGM];
-};
-
 int mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
 {
        return 1 << dev->oper_log_mgm_entry_size;
 
        struct mlx4_mfunc_master_ctx    master;
 };
 
+#define MGM_QPN_MASK       0x00FFFFFF
+#define MGM_BLCK_LB_BIT    30
+
+struct mlx4_mgm {
+       __be32                  next_gid_index;
+       __be32                  members_count;
+       u32                     reserved[2];
+       u8                      gid[16];
+       __be32                  qp[MLX4_MAX_QP_PER_MGM];
+};
+
 struct mlx4_cmd {
        struct pci_pool        *pool;
        void __iomem           *hcr;
        u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
        __be64                  slave_node_guids[MLX4_MFUNC_MAX];
 
+       atomic_t                opreq_count;
+       struct work_struct      opreq_task;
 };
 
 static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
 
        MLX4_CMD_SET_ICM_SIZE    = 0xffd,
        /*master notify fw on finish for slave's flr*/
        MLX4_CMD_INFORM_FLR_DONE = 0x5b,
+       MLX4_CMD_GET_OP_REQ      = 0x59,
 
        /* TPT commands */
        MLX4_CMD_SW2HW_MPT       = 0xd,
 
        MLX4_EVENT_TYPE_CMD                = 0x0a,
        MLX4_EVENT_TYPE_VEP_UPDATE         = 0x19,
        MLX4_EVENT_TYPE_COMM_CHANNEL       = 0x18,
+       MLX4_EVENT_TYPE_OP_REQUIRED        = 0x1a,
        MLX4_EVENT_TYPE_FATAL_WARNING      = 0x1b,
        MLX4_EVENT_TYPE_FLR_EVENT          = 0x1c,
        MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT = 0x1d,