MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE);
 }
 
+static int atomic_size_to_mode(int size_mask)
+{
+       /* driver does not support atomic_size > 256B
+        * and does not know how to translate bigger sizes
+        */
+       int supported_size_mask = size_mask & 0x1ff;
+       int log_max_size;
+
+       if (!supported_size_mask)
+               return -EOPNOTSUPP;
+
+       log_max_size = __fls(supported_size_mask);
+
+       if (log_max_size > 3)
+               return log_max_size;
+
+       return MLX5_ATOMIC_MODE_8B;
+}
+
+static int get_atomic_mode(struct mlx5_ib_dev *dev,
+                          enum ib_qp_type qp_type)
+{
+       u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations);
+       u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic);
+       int atomic_mode = -EOPNOTSUPP;
+       int atomic_size_mask;
+
+       if (!atomic)
+               return -EOPNOTSUPP;
+
+       if (qp_type == MLX5_IB_QPT_DCT)
+               atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc);
+       else
+               atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp);
+
+       if ((atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP) ||
+           (atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD))
+               atomic_mode = atomic_size_to_mode(atomic_size_mask);
+
+       if (atomic_mode <= 0 &&
+           (atomic_operations & MLX5_ATOMIC_OPS_CMP_SWAP &&
+            atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD))
+               atomic_mode = MLX5_ATOMIC_MODE_IB_COMP;
+
+       return atomic_mode;
+}
+
 static inline bool check_flags_mask(uint64_t input, uint64_t supported)
 {
        return (input & ~supported) == 0;
        return 0;
 }
 
-static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_attr *attr,
-                                  int attr_mask)
+static int to_mlx5_access_flags(struct mlx5_ib_qp *qp,
+                               const struct ib_qp_attr *attr,
+                               int attr_mask, __be32 *hw_access_flags)
 {
-       u32 hw_access_flags = 0;
        u8 dest_rd_atomic;
        u32 access_flags;
 
+       struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
+
        if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
                dest_rd_atomic = attr->max_dest_rd_atomic;
        else
                access_flags &= IB_ACCESS_REMOTE_WRITE;
 
        if (access_flags & IB_ACCESS_REMOTE_READ)
-               hw_access_flags |= MLX5_QP_BIT_RRE;
-       if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
-               hw_access_flags |= (MLX5_QP_BIT_RAE | MLX5_ATOMIC_MODE_CX);
+               *hw_access_flags |= MLX5_QP_BIT_RRE;
+       if ((access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+           qp->ibqp.qp_type == IB_QPT_RC) {
+               int atomic_mode;
+
+               atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type);
+               if (atomic_mode < 0)
+                       return -EOPNOTSUPP;
+
+               *hw_access_flags |= MLX5_QP_BIT_RAE;
+               *hw_access_flags |= atomic_mode << MLX5_ATOMIC_MODE_OFFSET;
+       }
+
        if (access_flags & IB_ACCESS_REMOTE_WRITE)
-               hw_access_flags |= MLX5_QP_BIT_RWE;
+               *hw_access_flags |= MLX5_QP_BIT_RWE;
+
+       *hw_access_flags = cpu_to_be32(*hw_access_flags);
 
-       return cpu_to_be32(hw_access_flags);
+       return 0;
 }
 
 enum {
                                cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
        }
 
-       if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC))
-               context->params2 |= to_mlx5_access_flags(qp, attr, attr_mask);
+       if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
+               __be32 access_flags = 0;
+
+               err = to_mlx5_access_flags(qp, attr, attr_mask, &access_flags);
+               if (err)
+                       goto out;
+
+               context->params2 |= access_flags;
+       }
 
        if (attr_mask & IB_QP_MIN_RNR_TIMER)
                context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
                if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
                        MLX5_SET(dctc, dctc, rwe, 1);
                if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) {
-                       if (!mlx5_ib_dc_atomic_is_supported(dev))
+                       int atomic_mode;
+
+                       atomic_mode = get_atomic_mode(dev, MLX5_IB_QPT_DCT);
+                       if (atomic_mode < 0)
                                return -EOPNOTSUPP;
+
+                       MLX5_SET(dctc, dctc, atomic_mode, atomic_mode);
                        MLX5_SET(dctc, dctc, rae, 1);
-                       MLX5_SET(dctc, dctc, atomic_mode, MLX5_ATOMIC_MODE_DCT_CX);
                }
                MLX5_SET(dctc, dctc, pkey_index, attr->pkey_index);
                MLX5_SET(dctc, dctc, port, attr->port_num);
 
 };
 
 enum {
-       MLX5_ATOMIC_MODE_IB_COMP        = 1 << 16,
-       MLX5_ATOMIC_MODE_CX             = 2 << 16,
-       MLX5_ATOMIC_MODE_8B             = 3 << 16,
-       MLX5_ATOMIC_MODE_16B            = 4 << 16,
-       MLX5_ATOMIC_MODE_32B            = 5 << 16,
-       MLX5_ATOMIC_MODE_64B            = 6 << 16,
-       MLX5_ATOMIC_MODE_128B           = 7 << 16,
-       MLX5_ATOMIC_MODE_256B           = 8 << 16,
+       MLX5_ATOMIC_MODE_OFFSET = 16,
+       MLX5_ATOMIC_MODE_IB_COMP = 1,
+       MLX5_ATOMIC_MODE_CX = 2,
+       MLX5_ATOMIC_MODE_8B = 3,
+       MLX5_ATOMIC_MODE_16B = 4,
+       MLX5_ATOMIC_MODE_32B = 5,
+       MLX5_ATOMIC_MODE_64B = 6,
+       MLX5_ATOMIC_MODE_128B = 7,
+       MLX5_ATOMIC_MODE_256B = 8,
 };
 
 enum {
        MLX5E_DCBX_PARAM_VER_OPER_AUTO  = 0x3,
 };
 
-enum mlx5_dct_atomic_mode {
-       MLX5_ATOMIC_MODE_DCT_CX         = 2,
-};
-
 enum {
        MLX5_ATOMIC_OPS_CMP_SWAP        = 1 << 0,
        MLX5_ATOMIC_OPS_FETCH_ADD       = 1 << 1,
+       MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP = 1 << 2,
+       MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD = 1 << 3,
 };
 
 enum mlx5_page_fault_resume_flags {