Merge tag 'asm-generic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / mellanox / mlx5 / core / cmd.c
index 594a1499cf9bdaceed0203657c0afe330cd8f810..037fc4cdf5af675e811f5f50950816d8dfeaff51 100644 (file)
@@ -254,6 +254,156 @@ static void dump_buf(void *buf, int size, int data_only, int offset)
                pr_debug("\n");
 }
 
+enum {
+       MLX5_DRIVER_STATUS_ABORTED = 0xfe,
+       MLX5_DRIVER_SYND = 0xbadd00de,
+};
+
+static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
+                                      u32 *synd, u8 *status)
+{
+       *synd = 0;
+       *status = 0;
+
+       switch (op) {
+       case MLX5_CMD_OP_TEARDOWN_HCA:
+       case MLX5_CMD_OP_DISABLE_HCA:
+       case MLX5_CMD_OP_MANAGE_PAGES:
+       case MLX5_CMD_OP_DESTROY_MKEY:
+       case MLX5_CMD_OP_DESTROY_EQ:
+       case MLX5_CMD_OP_DESTROY_CQ:
+       case MLX5_CMD_OP_DESTROY_QP:
+       case MLX5_CMD_OP_DESTROY_PSV:
+       case MLX5_CMD_OP_DESTROY_SRQ:
+       case MLX5_CMD_OP_DESTROY_XRC_SRQ:
+       case MLX5_CMD_OP_DESTROY_DCT:
+       case MLX5_CMD_OP_DEALLOC_Q_COUNTER:
+       case MLX5_CMD_OP_DEALLOC_PD:
+       case MLX5_CMD_OP_DEALLOC_UAR:
+       case MLX5_CMD_OP_DETTACH_FROM_MCG:
+       case MLX5_CMD_OP_DEALLOC_XRCD:
+       case MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN:
+       case MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT:
+       case MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY:
+       case MLX5_CMD_OP_DESTROY_TIR:
+       case MLX5_CMD_OP_DESTROY_SQ:
+       case MLX5_CMD_OP_DESTROY_RQ:
+       case MLX5_CMD_OP_DESTROY_RMP:
+       case MLX5_CMD_OP_DESTROY_TIS:
+       case MLX5_CMD_OP_DESTROY_RQT:
+       case MLX5_CMD_OP_DESTROY_FLOW_TABLE:
+       case MLX5_CMD_OP_DESTROY_FLOW_GROUP:
+       case MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY:
+               return MLX5_CMD_STAT_OK;
+
+       case MLX5_CMD_OP_QUERY_HCA_CAP:
+       case MLX5_CMD_OP_QUERY_ADAPTER:
+       case MLX5_CMD_OP_INIT_HCA:
+       case MLX5_CMD_OP_ENABLE_HCA:
+       case MLX5_CMD_OP_QUERY_PAGES:
+       case MLX5_CMD_OP_SET_HCA_CAP:
+       case MLX5_CMD_OP_QUERY_ISSI:
+       case MLX5_CMD_OP_SET_ISSI:
+       case MLX5_CMD_OP_CREATE_MKEY:
+       case MLX5_CMD_OP_QUERY_MKEY:
+       case MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS:
+       case MLX5_CMD_OP_PAGE_FAULT_RESUME:
+       case MLX5_CMD_OP_CREATE_EQ:
+       case MLX5_CMD_OP_QUERY_EQ:
+       case MLX5_CMD_OP_GEN_EQE:
+       case MLX5_CMD_OP_CREATE_CQ:
+       case MLX5_CMD_OP_QUERY_CQ:
+       case MLX5_CMD_OP_MODIFY_CQ:
+       case MLX5_CMD_OP_CREATE_QP:
+       case MLX5_CMD_OP_RST2INIT_QP:
+       case MLX5_CMD_OP_INIT2RTR_QP:
+       case MLX5_CMD_OP_RTR2RTS_QP:
+       case MLX5_CMD_OP_RTS2RTS_QP:
+       case MLX5_CMD_OP_SQERR2RTS_QP:
+       case MLX5_CMD_OP_2ERR_QP:
+       case MLX5_CMD_OP_2RST_QP:
+       case MLX5_CMD_OP_QUERY_QP:
+       case MLX5_CMD_OP_SQD_RTS_QP:
+       case MLX5_CMD_OP_INIT2INIT_QP:
+       case MLX5_CMD_OP_CREATE_PSV:
+       case MLX5_CMD_OP_CREATE_SRQ:
+       case MLX5_CMD_OP_QUERY_SRQ:
+       case MLX5_CMD_OP_ARM_RQ:
+       case MLX5_CMD_OP_CREATE_XRC_SRQ:
+       case MLX5_CMD_OP_QUERY_XRC_SRQ:
+       case MLX5_CMD_OP_ARM_XRC_SRQ:
+       case MLX5_CMD_OP_CREATE_DCT:
+       case MLX5_CMD_OP_DRAIN_DCT:
+       case MLX5_CMD_OP_QUERY_DCT:
+       case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION:
+       case MLX5_CMD_OP_QUERY_VPORT_STATE:
+       case MLX5_CMD_OP_MODIFY_VPORT_STATE:
+       case MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT:
+       case MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT:
+       case MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT:
+       case MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT:
+       case MLX5_CMD_OP_QUERY_ROCE_ADDRESS:
+       case MLX5_CMD_OP_SET_ROCE_ADDRESS:
+       case MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT:
+       case MLX5_CMD_OP_MODIFY_HCA_VPORT_CONTEXT:
+       case MLX5_CMD_OP_QUERY_HCA_VPORT_GID:
+       case MLX5_CMD_OP_QUERY_HCA_VPORT_PKEY:
+       case MLX5_CMD_OP_QUERY_VPORT_COUNTER:
+       case MLX5_CMD_OP_ALLOC_Q_COUNTER:
+       case MLX5_CMD_OP_QUERY_Q_COUNTER:
+       case MLX5_CMD_OP_ALLOC_PD:
+       case MLX5_CMD_OP_ALLOC_UAR:
+       case MLX5_CMD_OP_CONFIG_INT_MODERATION:
+       case MLX5_CMD_OP_ACCESS_REG:
+       case MLX5_CMD_OP_ATTACH_TO_MCG:
+       case MLX5_CMD_OP_GET_DROPPED_PACKET_LOG:
+       case MLX5_CMD_OP_MAD_IFC:
+       case MLX5_CMD_OP_QUERY_MAD_DEMUX:
+       case MLX5_CMD_OP_SET_MAD_DEMUX:
+       case MLX5_CMD_OP_NOP:
+       case MLX5_CMD_OP_ALLOC_XRCD:
+       case MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN:
+       case MLX5_CMD_OP_QUERY_CONG_STATUS:
+       case MLX5_CMD_OP_MODIFY_CONG_STATUS:
+       case MLX5_CMD_OP_QUERY_CONG_PARAMS:
+       case MLX5_CMD_OP_MODIFY_CONG_PARAMS:
+       case MLX5_CMD_OP_QUERY_CONG_STATISTICS:
+       case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT:
+       case MLX5_CMD_OP_SET_L2_TABLE_ENTRY:
+       case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY:
+       case MLX5_CMD_OP_CREATE_TIR:
+       case MLX5_CMD_OP_MODIFY_TIR:
+       case MLX5_CMD_OP_QUERY_TIR:
+       case MLX5_CMD_OP_CREATE_SQ:
+       case MLX5_CMD_OP_MODIFY_SQ:
+       case MLX5_CMD_OP_QUERY_SQ:
+       case MLX5_CMD_OP_CREATE_RQ:
+       case MLX5_CMD_OP_MODIFY_RQ:
+       case MLX5_CMD_OP_QUERY_RQ:
+       case MLX5_CMD_OP_CREATE_RMP:
+       case MLX5_CMD_OP_MODIFY_RMP:
+       case MLX5_CMD_OP_QUERY_RMP:
+       case MLX5_CMD_OP_CREATE_TIS:
+       case MLX5_CMD_OP_MODIFY_TIS:
+       case MLX5_CMD_OP_QUERY_TIS:
+       case MLX5_CMD_OP_CREATE_RQT:
+       case MLX5_CMD_OP_MODIFY_RQT:
+       case MLX5_CMD_OP_QUERY_RQT:
+       case MLX5_CMD_OP_CREATE_FLOW_TABLE:
+       case MLX5_CMD_OP_QUERY_FLOW_TABLE:
+       case MLX5_CMD_OP_CREATE_FLOW_GROUP:
+       case MLX5_CMD_OP_QUERY_FLOW_GROUP:
+       case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY:
+       case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY:
+               *status = MLX5_DRIVER_STATUS_ABORTED;
+               *synd = MLX5_DRIVER_SYND;
+               return -EIO;
+       default:
+               mlx5_core_err(dev, "Unknown FW command (%d)\n", op);
+               return -EINVAL;
+       }
+}
+
 const char *mlx5_command_str(int command)
 {
        switch (command) {
@@ -473,6 +623,7 @@ static void cmd_work_handler(struct work_struct *work)
        struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd);
        struct mlx5_cmd_layout *lay;
        struct semaphore *sem;
+       unsigned long flags;
 
        sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
        down(sem);
@@ -485,6 +636,9 @@ static void cmd_work_handler(struct work_struct *work)
                }
        } else {
                ent->idx = cmd->max_reg_cmds;
+               spin_lock_irqsave(&cmd->alloc_lock, flags);
+               clear_bit(ent->idx, &cmd->bitmask);
+               spin_unlock_irqrestore(&cmd->alloc_lock, flags);
        }
 
        ent->token = alloc_token(cmd);
@@ -584,6 +738,16 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
        return err;
 }
 
+static __be32 *get_synd_ptr(struct mlx5_outbox_hdr *out)
+{
+       return &out->syndrome;
+}
+
+static u8 *get_status_ptr(struct mlx5_outbox_hdr *out)
+{
+       return &out->status;
+}
+
 /*  Notes:
  *    1. Callback functions may not sleep
  *    2. page queue commands do not support asynchrous completion
@@ -1081,7 +1245,7 @@ static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
        }
 }
 
-void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
+void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec)
 {
        struct mlx5_cmd *cmd = &dev->cmd;
        struct mlx5_cmd_work_ent *ent;
@@ -1092,7 +1256,10 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
        s64 ds;
        struct mlx5_cmd_stats *stats;
        unsigned long flags;
+       unsigned long vector;
 
+       /* there can be at most 32 command queues */
+       vector = vec & 0xffffffff;
        for (i = 0; i < (1 << cmd->log_sz); i++) {
                if (test_bit(i, &vector)) {
                        struct semaphore *sem;
@@ -1110,11 +1277,16 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
                                        ent->ret = verify_signature(ent);
                                else
                                        ent->ret = 0;
-                               ent->status = ent->lay->status_own >> 1;
+                               if (vec & MLX5_TRIGGERED_CMD_COMP)
+                                       ent->status = MLX5_DRIVER_STATUS_ABORTED;
+                               else
+                                       ent->status = ent->lay->status_own >> 1;
+
                                mlx5_core_dbg(dev, "command completed. ret 0x%x, delivery status %s(0x%x)\n",
                                              ent->ret, deliv_status_to_str(ent->status), ent->status);
                        }
                        free_ent(cmd, ent->idx);
+
                        if (ent->callback) {
                                ds = ent->ts2 - ent->ts1;
                                if (ent->op < ARRAY_SIZE(cmd->stats)) {
@@ -1136,6 +1308,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
                                mlx5_free_cmd_msg(dev, ent->out);
                                free_msg(dev, ent->in);
 
+                               err = err ? err : ent->status;
                                free_cmd(ent);
                                callback(err, context);
                        } else {
@@ -1183,6 +1356,11 @@ static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
        return msg;
 }
 
+static u16 opcode_from_in(struct mlx5_inbox_hdr *in)
+{
+       return be16_to_cpu(in->opcode);
+}
+
 static int is_manage_pages(struct mlx5_inbox_hdr *in)
 {
        return be16_to_cpu(in->opcode) == MLX5_CMD_OP_MANAGE_PAGES;
@@ -1197,6 +1375,15 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
        gfp_t gfp;
        int err;
        u8 status = 0;
+       u32 drv_synd;
+
+       if (pci_channel_offline(dev->pdev) ||
+           dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+               err = mlx5_internal_err_ret_value(dev, opcode_from_in(in), &drv_synd, &status);
+               *get_synd_ptr(out) = cpu_to_be32(drv_synd);
+               *get_status_ptr(out) = status;
+               return err;
+       }
 
        pages_queue = is_manage_pages(in);
        gfp = callback ? GFP_ATOMIC : GFP_KERNEL;
@@ -1363,6 +1550,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
        int err;
        int i;
 
+       memset(cmd, 0, sizeof(*cmd));
        cmd_if_rev = cmdif_rev(dev);
        if (cmd_if_rev != CMD_IF_REV) {
                dev_err(&dev->pdev->dev,