forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
....@@ -40,9 +40,11 @@
4040 #include <linux/random.h>
4141 #include <linux/io-mapping.h>
4242 #include <linux/mlx5/driver.h>
43
+#include <linux/mlx5/eq.h>
4344 #include <linux/debugfs.h>
4445
4546 #include "mlx5_core.h"
47
+#include "lib/eq.h"
4648
4749 enum {
4850 CMD_IF_REV = 5,
....@@ -67,12 +69,10 @@
6769 MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR = 0x10,
6870 };
6971
70
-static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
71
- struct mlx5_cmd_msg *in,
72
- struct mlx5_cmd_msg *out,
73
- void *uout, int uout_size,
74
- mlx5_cmd_cbk_t cbk,
75
- void *context, int page_queue)
72
+static struct mlx5_cmd_work_ent *
73
+cmd_alloc_ent(struct mlx5_cmd *cmd, struct mlx5_cmd_msg *in,
74
+ struct mlx5_cmd_msg *out, void *uout, int uout_size,
75
+ mlx5_cmd_cbk_t cbk, void *context, int page_queue)
7676 {
7777 gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL;
7878 struct mlx5_cmd_work_ent *ent;
....@@ -81,6 +81,7 @@
8181 if (!ent)
8282 return ERR_PTR(-ENOMEM);
8383
84
+ ent->idx = -EINVAL;
8485 ent->in = in;
8586 ent->out = out;
8687 ent->uout = uout;
....@@ -89,8 +90,14 @@
8990 ent->context = context;
9091 ent->cmd = cmd;
9192 ent->page_queue = page_queue;
93
+ refcount_set(&ent->refcnt, 1);
9294
9395 return ent;
96
+}
97
+
98
+static void cmd_free_ent(struct mlx5_cmd_work_ent *ent)
99
+{
100
+ kfree(ent);
94101 }
95102
96103 static u8 alloc_token(struct mlx5_cmd *cmd)
....@@ -107,7 +114,7 @@
107114 return token;
108115 }
109116
110
-static int alloc_ent(struct mlx5_cmd *cmd)
117
+static int cmd_alloc_index(struct mlx5_cmd *cmd)
111118 {
112119 unsigned long flags;
113120 int ret;
....@@ -121,12 +128,33 @@
121128 return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
122129 }
123130
124
-static void free_ent(struct mlx5_cmd *cmd, int idx)
131
+static void cmd_free_index(struct mlx5_cmd *cmd, int idx)
125132 {
133
+ lockdep_assert_held(&cmd->alloc_lock);
134
+ set_bit(idx, &cmd->bitmask);
135
+}
136
+
137
+static void cmd_ent_get(struct mlx5_cmd_work_ent *ent)
138
+{
139
+ refcount_inc(&ent->refcnt);
140
+}
141
+
142
+static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
143
+{
144
+ struct mlx5_cmd *cmd = ent->cmd;
126145 unsigned long flags;
127146
128147 spin_lock_irqsave(&cmd->alloc_lock, flags);
129
- set_bit(idx, &cmd->bitmask);
148
+ if (!refcount_dec_and_test(&ent->refcnt))
149
+ goto out;
150
+
151
+ if (ent->idx >= 0) {
152
+ cmd_free_index(cmd, ent->idx);
153
+ up(ent->page_queue ? &cmd->pages_sem : &cmd->sem);
154
+ }
155
+
156
+ cmd_free_ent(ent);
157
+out:
130158 spin_unlock_irqrestore(&cmd->alloc_lock, flags);
131159 }
132160
....@@ -217,11 +245,6 @@
217245 ent->ret = -ETIMEDOUT;
218246 }
219247
220
-static void free_cmd(struct mlx5_cmd_work_ent *ent)
221
-{
222
- kfree(ent);
223
-}
224
-
225248 static int verify_signature(struct mlx5_cmd_work_ent *ent)
226249 {
227250 struct mlx5_cmd_mailbox *next = ent->out->next;
....@@ -308,10 +331,13 @@
308331 case MLX5_CMD_OP_MODIFY_FLOW_TABLE:
309332 case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY:
310333 case MLX5_CMD_OP_SET_FLOW_TABLE_ROOT:
311
- case MLX5_CMD_OP_DEALLOC_ENCAP_HEADER:
334
+ case MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT:
312335 case MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT:
313336 case MLX5_CMD_OP_FPGA_DESTROY_QP:
314337 case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT:
338
+ case MLX5_CMD_OP_DEALLOC_MEMIC:
339
+ case MLX5_CMD_OP_PAGE_FAULT_RESUME:
340
+ case MLX5_CMD_OP_QUERY_ESW_FUNCTIONS:
315341 return MLX5_CMD_STAT_OK;
316342
317343 case MLX5_CMD_OP_QUERY_HCA_CAP:
....@@ -325,7 +351,6 @@
325351 case MLX5_CMD_OP_CREATE_MKEY:
326352 case MLX5_CMD_OP_QUERY_MKEY:
327353 case MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS:
328
- case MLX5_CMD_OP_PAGE_FAULT_RESUME:
329354 case MLX5_CMD_OP_CREATE_EQ:
330355 case MLX5_CMD_OP_QUERY_EQ:
331356 case MLX5_CMD_OP_GEN_EQE:
....@@ -370,6 +395,8 @@
370395 case MLX5_CMD_OP_QUERY_VPORT_COUNTER:
371396 case MLX5_CMD_OP_ALLOC_Q_COUNTER:
372397 case MLX5_CMD_OP_QUERY_Q_COUNTER:
398
+ case MLX5_CMD_OP_SET_MONITOR_COUNTER:
399
+ case MLX5_CMD_OP_ARM_MONITOR_COUNTER:
373400 case MLX5_CMD_OP_SET_PP_RATE_LIMIT:
374401 case MLX5_CMD_OP_QUERY_RATE_LIMIT:
375402 case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT:
....@@ -426,7 +453,7 @@
426453 case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY:
427454 case MLX5_CMD_OP_ALLOC_FLOW_COUNTER:
428455 case MLX5_CMD_OP_QUERY_FLOW_COUNTER:
429
- case MLX5_CMD_OP_ALLOC_ENCAP_HEADER:
456
+ case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT:
430457 case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT:
431458 case MLX5_CMD_OP_FPGA_CREATE_QP:
432459 case MLX5_CMD_OP_FPGA_MODIFY_QP:
....@@ -435,6 +462,13 @@
435462 case MLX5_CMD_OP_CREATE_GENERAL_OBJECT:
436463 case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
437464 case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
465
+ case MLX5_CMD_OP_CREATE_UCTX:
466
+ case MLX5_CMD_OP_DESTROY_UCTX:
467
+ case MLX5_CMD_OP_CREATE_UMEM:
468
+ case MLX5_CMD_OP_DESTROY_UMEM:
469
+ case MLX5_CMD_OP_ALLOC_MEMIC:
470
+ case MLX5_CMD_OP_MODIFY_XRQ:
471
+ case MLX5_CMD_OP_RELEASE_XRQ_ERROR:
438472 *status = MLX5_DRIVER_STATUS_ABORTED;
439473 *synd = MLX5_DRIVER_SYND;
440474 return -EIO;
....@@ -518,6 +552,8 @@
518552 MLX5_COMMAND_STR_CASE(ALLOC_Q_COUNTER);
519553 MLX5_COMMAND_STR_CASE(DEALLOC_Q_COUNTER);
520554 MLX5_COMMAND_STR_CASE(QUERY_Q_COUNTER);
555
+ MLX5_COMMAND_STR_CASE(SET_MONITOR_COUNTER);
556
+ MLX5_COMMAND_STR_CASE(ARM_MONITOR_COUNTER);
521557 MLX5_COMMAND_STR_CASE(SET_PP_RATE_LIMIT);
522558 MLX5_COMMAND_STR_CASE(QUERY_RATE_LIMIT);
523559 MLX5_COMMAND_STR_CASE(CREATE_SCHEDULING_ELEMENT);
....@@ -599,8 +635,8 @@
599635 MLX5_COMMAND_STR_CASE(DEALLOC_FLOW_COUNTER);
600636 MLX5_COMMAND_STR_CASE(QUERY_FLOW_COUNTER);
601637 MLX5_COMMAND_STR_CASE(MODIFY_FLOW_TABLE);
602
- MLX5_COMMAND_STR_CASE(ALLOC_ENCAP_HEADER);
603
- MLX5_COMMAND_STR_CASE(DEALLOC_ENCAP_HEADER);
638
+ MLX5_COMMAND_STR_CASE(ALLOC_PACKET_REFORMAT_CONTEXT);
639
+ MLX5_COMMAND_STR_CASE(DEALLOC_PACKET_REFORMAT_CONTEXT);
604640 MLX5_COMMAND_STR_CASE(ALLOC_MODIFY_HEADER_CONTEXT);
605641 MLX5_COMMAND_STR_CASE(DEALLOC_MODIFY_HEADER_CONTEXT);
606642 MLX5_COMMAND_STR_CASE(FPGA_CREATE_QP);
....@@ -617,6 +653,15 @@
617653 MLX5_COMMAND_STR_CASE(MODIFY_GENERAL_OBJECT);
618654 MLX5_COMMAND_STR_CASE(QUERY_GENERAL_OBJECT);
619655 MLX5_COMMAND_STR_CASE(QUERY_MODIFY_HEADER_CONTEXT);
656
+ MLX5_COMMAND_STR_CASE(ALLOC_MEMIC);
657
+ MLX5_COMMAND_STR_CASE(DEALLOC_MEMIC);
658
+ MLX5_COMMAND_STR_CASE(QUERY_ESW_FUNCTIONS);
659
+ MLX5_COMMAND_STR_CASE(CREATE_UCTX);
660
+ MLX5_COMMAND_STR_CASE(DESTROY_UCTX);
661
+ MLX5_COMMAND_STR_CASE(CREATE_UMEM);
662
+ MLX5_COMMAND_STR_CASE(DESTROY_UMEM);
663
+ MLX5_COMMAND_STR_CASE(RELEASE_XRQ_ERROR);
664
+ MLX5_COMMAND_STR_CASE(MODIFY_XRQ);
620665 default: return "unknown command opcode";
621666 }
622667 }
....@@ -801,6 +846,8 @@
801846 return MLX5_GET(mbox_in, in->first.data, opcode);
802847 }
803848
849
+static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced);
850
+
804851 static void cb_timeout_handler(struct work_struct *work)
805852 {
806853 struct delayed_work *dwork = container_of(work, struct delayed_work,
....@@ -811,16 +858,42 @@
811858 struct mlx5_core_dev *dev = container_of(ent->cmd, struct mlx5_core_dev,
812859 cmd);
813860
861
+ mlx5_cmd_eq_recover(dev);
862
+
863
+ /* Maybe got handled by eq recover ? */
864
+ if (!test_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state)) {
865
+ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, recovered after timeout\n", ent->idx,
866
+ mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
867
+ goto out; /* phew, already handled */
868
+ }
869
+
814870 ent->ret = -ETIMEDOUT;
815
- mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
816
- mlx5_command_str(msg_to_opcode(ent->in)),
817
- msg_to_opcode(ent->in));
818
- mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
871
+ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, timeout. Will cause a leak of a command resource\n",
872
+ ent->idx, mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
873
+ mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
874
+
875
+out:
876
+ cmd_ent_put(ent); /* for the cmd_ent_get() took on schedule delayed work */
819877 }
820878
821879 static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
822880 static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
823881 struct mlx5_cmd_msg *msg);
882
+
883
+static bool opcode_allowed(struct mlx5_cmd *cmd, u16 opcode)
884
+{
885
+ if (cmd->allowed_opcode == CMD_ALLOWED_OPCODE_ALL)
886
+ return true;
887
+
888
+ return cmd->allowed_opcode == opcode;
889
+}
890
+
891
+bool mlx5_cmd_is_down(struct mlx5_core_dev *dev)
892
+{
893
+ return pci_channel_offline(dev->pdev) ||
894
+ dev->cmd.state != MLX5_CMDIF_STATE_UP ||
895
+ dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR;
896
+}
824897
825898 static void cmd_work_handler(struct work_struct *work)
826899 {
....@@ -839,14 +912,14 @@
839912 sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
840913 down(sem);
841914 if (!ent->page_queue) {
842
- alloc_ret = alloc_ent(cmd);
915
+ alloc_ret = cmd_alloc_index(cmd);
843916 if (alloc_ret < 0) {
844
- mlx5_core_err(dev, "failed to allocate command entry\n");
917
+ mlx5_core_err_rl(dev, "failed to allocate command entry\n");
845918 if (ent->callback) {
846919 ent->callback(-EAGAIN, ent->context);
847920 mlx5_free_cmd_msg(dev, ent->out);
848921 free_msg(dev, ent->in);
849
- free_cmd(ent);
922
+ cmd_ent_put(ent);
850923 } else {
851924 ent->ret = -EAGAIN;
852925 complete(&ent->done);
....@@ -882,13 +955,13 @@
882955 ent->ts1 = ktime_get_ns();
883956 cmd_mode = cmd->mode;
884957
885
- if (ent->callback)
886
- schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
958
+ if (ent->callback && schedule_delayed_work(&ent->cb_timeout_work, cb_timeout))
959
+ cmd_ent_get(ent);
887960 set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
888961
962
+ cmd_ent_get(ent); /* for the _real_ FW event on completion */
889963 /* Skip sending command to fw if internal error */
890
- if (pci_channel_offline(dev->pdev) ||
891
- dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
964
+ if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, ent->op)) {
892965 u8 status = 0;
893966 u32 drv_synd;
894967
....@@ -896,11 +969,7 @@
896969 MLX5_SET(mbox_out, ent->out, status, status);
897970 MLX5_SET(mbox_out, ent->out, syndrome, drv_synd);
898971
899
- mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
900
- /* no doorbell, no need to keep the entry */
901
- free_ent(cmd, ent->idx);
902
- if (ent->callback)
903
- free_cmd(ent);
972
+ mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
904973 return;
905974 }
906975
....@@ -908,13 +977,12 @@
908977 mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx);
909978 wmb();
910979 iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
911
- mmiowb();
912980 /* if not in polling don't use ent after this point */
913981 if (cmd_mode == CMD_MODE_POLLING || poll_cmd) {
914982 poll_timeout(ent);
915983 /* make sure we read the descriptor after ownership is SW */
916984 rmb();
917
- mlx5_cmd_comp_handler(dev, 1UL << ent->idx, (ent->ret == -ETIMEDOUT));
985
+ mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, (ent->ret == -ETIMEDOUT));
918986 }
919987 }
920988
....@@ -948,6 +1016,35 @@
9481016 }
9491017 }
9501018
1019
+enum {
1020
+ MLX5_CMD_TIMEOUT_RECOVER_MSEC = 5 * 1000,
1021
+};
1022
+
1023
+static void wait_func_handle_exec_timeout(struct mlx5_core_dev *dev,
1024
+ struct mlx5_cmd_work_ent *ent)
1025
+{
1026
+ unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_RECOVER_MSEC);
1027
+
1028
+ mlx5_cmd_eq_recover(dev);
1029
+
1030
+ /* Re-wait on the ent->done after executing the recovery flow. If the
1031
+ * recovery flow (or any other recovery flow running simultaneously)
1032
+ * has recovered an EQE, it should cause the entry to be completed by
1033
+ * the command interface.
1034
+ */
1035
+ if (wait_for_completion_timeout(&ent->done, timeout)) {
1036
+ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) recovered after timeout\n", ent->idx,
1037
+ mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
1038
+ return;
1039
+ }
1040
+
1041
+ mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) No done completion\n", ent->idx,
1042
+ mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
1043
+
1044
+ ent->ret = -ETIMEDOUT;
1045
+ mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
1046
+}
1047
+
9511048 static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
9521049 {
9531050 unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
....@@ -959,12 +1056,10 @@
9591056 ent->ret = -ECANCELED;
9601057 goto out_err;
9611058 }
962
- if (cmd->mode == CMD_MODE_POLLING || ent->polling) {
1059
+ if (cmd->mode == CMD_MODE_POLLING || ent->polling)
9631060 wait_for_completion(&ent->done);
964
- } else if (!wait_for_completion_timeout(&ent->done, timeout)) {
965
- ent->ret = -ETIMEDOUT;
966
- mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
967
- }
1061
+ else if (!wait_for_completion_timeout(&ent->done, timeout))
1062
+ wait_func_handle_exec_timeout(dev, ent);
9681063
9691064 out_err:
9701065 err = ent->ret;
....@@ -1004,10 +1099,15 @@
10041099 if (callback && page_queue)
10051100 return -EINVAL;
10061101
1007
- ent = alloc_cmd(cmd, in, out, uout, uout_size, callback, context,
1008
- page_queue);
1102
+ ent = cmd_alloc_ent(cmd, in, out, uout, uout_size,
1103
+ callback, context, page_queue);
10091104 if (IS_ERR(ent))
10101105 return PTR_ERR(ent);
1106
+
1107
+ /* put for this ent is when consumed, depending on the use case
1108
+ * 1) (!callback) blocking flow: by caller after wait_func completes
1109
+ * 2) (callback) flow: by mlx5_cmd_comp_handler() when ent is handled
1110
+ */
10111111
10121112 ent->token = token;
10131113 ent->polling = force_polling;
....@@ -1027,17 +1127,15 @@
10271127 }
10281128
10291129 if (callback)
1030
- goto out;
1130
+ goto out; /* mlx5_cmd_comp_handler() will put(ent) */
10311131
10321132 err = wait_func(dev, ent);
1033
- if (err == -ETIMEDOUT)
1034
- goto out;
1035
- if (err == -ECANCELED)
1133
+ if (err == -ETIMEDOUT || err == -ECANCELED)
10361134 goto out_free;
10371135
10381136 ds = ent->ts2 - ent->ts1;
10391137 op = MLX5_GET(mbox_in, in->first.data, opcode);
1040
- if (op < ARRAY_SIZE(cmd->stats)) {
1138
+ if (op < MLX5_CMD_OP_MAX) {
10411139 stats = &cmd->stats[op];
10421140 spin_lock_irq(&stats->lock);
10431141 stats->sum += ds;
....@@ -1050,7 +1148,7 @@
10501148 *status = ent->status;
10511149
10521150 out_free:
1053
- free_cmd(ent);
1151
+ cmd_ent_put(ent);
10541152 out:
10551153 return err;
10561154 }
....@@ -1324,8 +1422,8 @@
13241422 return -EFAULT;
13251423
13261424 err = sscanf(outlen_str, "%d", &outlen);
1327
- if (err < 0)
1328
- return err;
1425
+ if (err != 1)
1426
+ return -EINVAL;
13291427
13301428 ptr = kzalloc(outlen, GFP_KERNEL);
13311429 if (!ptr)
....@@ -1351,7 +1449,7 @@
13511449 struct mlx5_cmd *cmd = &dev->cmd;
13521450
13531451 snprintf(cmd->wq_name, sizeof(cmd->wq_name), "mlx5_cmd_%s",
1354
- dev_name(&dev->pdev->dev));
1452
+ dev_name(dev->device));
13551453 }
13561454
13571455 static void clean_debug_files(struct mlx5_core_dev *dev)
....@@ -1365,49 +1463,35 @@
13651463 debugfs_remove_recursive(dbg->dbg_root);
13661464 }
13671465
1368
-static int create_debugfs_files(struct mlx5_core_dev *dev)
1466
+static void create_debugfs_files(struct mlx5_core_dev *dev)
13691467 {
13701468 struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
1371
- int err = -ENOMEM;
1372
-
1373
- if (!mlx5_debugfs_root)
1374
- return 0;
13751469
13761470 dbg->dbg_root = debugfs_create_dir("cmd", dev->priv.dbg_root);
1377
- if (!dbg->dbg_root)
1378
- return err;
13791471
1380
- dbg->dbg_in = debugfs_create_file("in", 0400, dbg->dbg_root,
1381
- dev, &dfops);
1382
- if (!dbg->dbg_in)
1383
- goto err_dbg;
1384
-
1385
- dbg->dbg_out = debugfs_create_file("out", 0200, dbg->dbg_root,
1386
- dev, &dfops);
1387
- if (!dbg->dbg_out)
1388
- goto err_dbg;
1389
-
1390
- dbg->dbg_outlen = debugfs_create_file("out_len", 0600, dbg->dbg_root,
1391
- dev, &olfops);
1392
- if (!dbg->dbg_outlen)
1393
- goto err_dbg;
1394
-
1395
- dbg->dbg_status = debugfs_create_u8("status", 0600, dbg->dbg_root,
1396
- &dbg->status);
1397
- if (!dbg->dbg_status)
1398
- goto err_dbg;
1399
-
1400
- dbg->dbg_run = debugfs_create_file("run", 0200, dbg->dbg_root, dev, &fops);
1401
- if (!dbg->dbg_run)
1402
- goto err_dbg;
1472
+ debugfs_create_file("in", 0400, dbg->dbg_root, dev, &dfops);
1473
+ debugfs_create_file("out", 0200, dbg->dbg_root, dev, &dfops);
1474
+ debugfs_create_file("out_len", 0600, dbg->dbg_root, dev, &olfops);
1475
+ debugfs_create_u8("status", 0600, dbg->dbg_root, &dbg->status);
1476
+ debugfs_create_file("run", 0200, dbg->dbg_root, dev, &fops);
14031477
14041478 mlx5_cmdif_debugfs_init(dev);
1479
+}
14051480
1406
- return 0;
1481
+void mlx5_cmd_allowed_opcode(struct mlx5_core_dev *dev, u16 opcode)
1482
+{
1483
+ struct mlx5_cmd *cmd = &dev->cmd;
1484
+ int i;
14071485
1408
-err_dbg:
1409
- clean_debug_files(dev);
1410
- return err;
1486
+ for (i = 0; i < cmd->max_reg_cmds; i++)
1487
+ down(&cmd->sem);
1488
+ down(&cmd->pages_sem);
1489
+
1490
+ cmd->allowed_opcode = opcode;
1491
+
1492
+ up(&cmd->pages_sem);
1493
+ for (i = 0; i < cmd->max_reg_cmds; i++)
1494
+ up(&cmd->sem);
14111495 }
14121496
14131497 static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
....@@ -1426,14 +1510,32 @@
14261510 up(&cmd->sem);
14271511 }
14281512
1513
+static int cmd_comp_notifier(struct notifier_block *nb,
1514
+ unsigned long type, void *data)
1515
+{
1516
+ struct mlx5_core_dev *dev;
1517
+ struct mlx5_cmd *cmd;
1518
+ struct mlx5_eqe *eqe;
1519
+
1520
+ cmd = mlx5_nb_cof(nb, struct mlx5_cmd, nb);
1521
+ dev = container_of(cmd, struct mlx5_core_dev, cmd);
1522
+ eqe = data;
1523
+
1524
+ mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector), false);
1525
+
1526
+ return NOTIFY_OK;
1527
+}
14291528 void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
14301529 {
1530
+ MLX5_NB_INIT(&dev->cmd.nb, cmd_comp_notifier, CMD);
1531
+ mlx5_eq_notifier_register(dev, &dev->cmd.nb);
14311532 mlx5_cmd_change_mod(dev, CMD_MODE_EVENTS);
14321533 }
14331534
14341535 void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
14351536 {
14361537 mlx5_cmd_change_mod(dev, CMD_MODE_POLLING);
1538
+ mlx5_eq_notifier_unregister(dev, &dev->cmd.nb);
14371539 }
14381540
14391541 static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
....@@ -1449,7 +1551,7 @@
14491551 }
14501552 }
14511553
1452
-void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
1554
+static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
14531555 {
14541556 struct mlx5_cmd *cmd = &dev->cmd;
14551557 struct mlx5_cmd_work_ent *ent;
....@@ -1466,8 +1568,6 @@
14661568 vector = vec & 0xffffffff;
14671569 for (i = 0; i < (1 << cmd->log_sz); i++) {
14681570 if (test_bit(i, &vector)) {
1469
- struct semaphore *sem;
1470
-
14711571 ent = cmd->ent_arr[i];
14721572
14731573 /* if we already completed the command, ignore it */
....@@ -1477,18 +1577,19 @@
14771577 if (!forced) {
14781578 mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
14791579 ent->idx);
1480
- free_ent(cmd, ent->idx);
1481
- free_cmd(ent);
1580
+ cmd_ent_put(ent);
14821581 }
14831582 continue;
14841583 }
14851584
1486
- if (ent->callback)
1487
- cancel_delayed_work(&ent->cb_timeout_work);
1488
- if (ent->page_queue)
1489
- sem = &cmd->pages_sem;
1490
- else
1491
- sem = &cmd->sem;
1585
+ if (ent->callback && cancel_delayed_work(&ent->cb_timeout_work))
1586
+ cmd_ent_put(ent); /* timeout work was canceled */
1587
+
1588
+ if (!forced || /* Real FW completion */
1589
+ mlx5_cmd_is_down(dev) || /* No real FW completion is expected */
1590
+ !opcode_allowed(cmd, ent->op))
1591
+ cmd_ent_put(ent);
1592
+
14921593 ent->ts2 = ktime_get_ns();
14931594 memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
14941595 dump_command(dev, ent, 0);
....@@ -1506,13 +1607,9 @@
15061607 ent->ret, deliv_status_to_str(ent->status), ent->status);
15071608 }
15081609
1509
- /* only real completion will free the entry slot */
1510
- if (!forced)
1511
- free_ent(cmd, ent->idx);
1512
-
15131610 if (ent->callback) {
15141611 ds = ent->ts2 - ent->ts1;
1515
- if (ent->op < ARRAY_SIZE(cmd->stats)) {
1612
+ if (ent->op < MLX5_CMD_OP_MAX) {
15161613 stats = &cmd->stats[ent->op];
15171614 spin_lock_irqsave(&stats->lock, flags);
15181615 stats->sum += ds;
....@@ -1537,21 +1634,100 @@
15371634 free_msg(dev, ent->in);
15381635
15391636 err = err ? err : ent->status;
1540
- if (!forced)
1541
- free_cmd(ent);
1637
+ /* final consumer is done, release ent */
1638
+ cmd_ent_put(ent);
15421639 callback(err, context);
15431640 } else {
1641
+ /* release wait_func() so mlx5_cmd_invoke()
1642
+ * can make the final ent_put()
1643
+ */
15441644 complete(&ent->done);
15451645 }
1546
- up(sem);
15471646 }
15481647 }
15491648 }
1550
-EXPORT_SYMBOL(mlx5_cmd_comp_handler);
1649
+
1650
+void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
1651
+{
1652
+ struct mlx5_cmd *cmd = &dev->cmd;
1653
+ unsigned long bitmask;
1654
+ unsigned long flags;
1655
+ u64 vector;
1656
+ int i;
1657
+
1658
+ /* wait for pending handlers to complete */
1659
+ mlx5_eq_synchronize_cmd_irq(dev);
1660
+ spin_lock_irqsave(&dev->cmd.alloc_lock, flags);
1661
+ vector = ~dev->cmd.bitmask & ((1ul << (1 << dev->cmd.log_sz)) - 1);
1662
+ if (!vector)
1663
+ goto no_trig;
1664
+
1665
+ bitmask = vector;
1666
+ /* we must increment the allocated entries refcount before triggering the completions
1667
+ * to guarantee pending commands will not get freed in the meanwhile.
1668
+ * For that reason, it also has to be done inside the alloc_lock.
1669
+ */
1670
+ for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
1671
+ cmd_ent_get(cmd->ent_arr[i]);
1672
+ vector |= MLX5_TRIGGERED_CMD_COMP;
1673
+ spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
1674
+
1675
+ mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
1676
+ mlx5_cmd_comp_handler(dev, vector, true);
1677
+ for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
1678
+ cmd_ent_put(cmd->ent_arr[i]);
1679
+ return;
1680
+
1681
+no_trig:
1682
+ spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
1683
+}
1684
+
1685
+void mlx5_cmd_flush(struct mlx5_core_dev *dev)
1686
+{
1687
+ struct mlx5_cmd *cmd = &dev->cmd;
1688
+ int i;
1689
+
1690
+ for (i = 0; i < cmd->max_reg_cmds; i++) {
1691
+ while (down_trylock(&cmd->sem)) {
1692
+ mlx5_cmd_trigger_completions(dev);
1693
+ cond_resched();
1694
+ }
1695
+ }
1696
+
1697
+ while (down_trylock(&cmd->pages_sem)) {
1698
+ mlx5_cmd_trigger_completions(dev);
1699
+ cond_resched();
1700
+ }
1701
+
1702
+ /* Unlock cmdif */
1703
+ up(&cmd->pages_sem);
1704
+ for (i = 0; i < cmd->max_reg_cmds; i++)
1705
+ up(&cmd->sem);
1706
+}
15511707
15521708 static int status_to_err(u8 status)
15531709 {
1554
- return status ? -1 : 0; /* TBD more meaningful codes */
1710
+ switch (status) {
1711
+ case MLX5_CMD_DELIVERY_STAT_OK:
1712
+ case MLX5_DRIVER_STATUS_ABORTED:
1713
+ return 0;
1714
+ case MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR:
1715
+ case MLX5_CMD_DELIVERY_STAT_TOK_ERR:
1716
+ return -EBADR;
1717
+ case MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR:
1718
+ case MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR:
1719
+ case MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR:
1720
+ return -EFAULT; /* Bad address */
1721
+ case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR:
1722
+ case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR:
1723
+ case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR:
1724
+ case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR:
1725
+ return -ENOMSG;
1726
+ case MLX5_CMD_DELIVERY_STAT_FW_ERR:
1727
+ return -EIO;
1728
+ default:
1729
+ return -EINVAL;
1730
+ }
15551731 }
15561732
15571733 static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
....@@ -1608,12 +1784,11 @@
16081784 int err;
16091785 u8 status = 0;
16101786 u32 drv_synd;
1787
+ u16 opcode;
16111788 u8 token;
16121789
1613
- if (pci_channel_offline(dev->pdev) ||
1614
- dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
1615
- u16 opcode = MLX5_GET(mbox_in, in, opcode);
1616
-
1790
+ opcode = MLX5_GET(mbox_in, in, opcode);
1791
+ if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, opcode)) {
16171792 err = mlx5_internal_err_ret_value(dev, opcode, &drv_synd, &status);
16181793 MLX5_SET(mbox_out, out, status, status);
16191794 MLX5_SET(mbox_out, out, syndrome, drv_synd);
....@@ -1677,12 +1852,57 @@
16771852 }
16781853 EXPORT_SYMBOL(mlx5_cmd_exec);
16791854
1680
-int mlx5_cmd_exec_cb(struct mlx5_core_dev *dev, void *in, int in_size,
1681
- void *out, int out_size, mlx5_cmd_cbk_t callback,
1682
- void *context)
1855
+void mlx5_cmd_init_async_ctx(struct mlx5_core_dev *dev,
1856
+ struct mlx5_async_ctx *ctx)
16831857 {
1684
- return cmd_exec(dev, in, in_size, out, out_size, callback, context,
1685
- false);
1858
+ ctx->dev = dev;
1859
+ /* Starts at 1 to avoid doing wake_up if we are not cleaning up */
1860
+ atomic_set(&ctx->num_inflight, 1);
1861
+ init_completion(&ctx->inflight_done);
1862
+}
1863
+EXPORT_SYMBOL(mlx5_cmd_init_async_ctx);
1864
+
1865
+/**
1866
+ * mlx5_cmd_cleanup_async_ctx - Clean up an async_ctx
1867
+ * @ctx: The ctx to clean
1868
+ *
1869
+ * Upon return all callbacks given to mlx5_cmd_exec_cb() have been called. The
1870
+ * caller must ensure that mlx5_cmd_exec_cb() is not called during or after
1871
+ * the call mlx5_cleanup_async_ctx().
1872
+ */
1873
+void mlx5_cmd_cleanup_async_ctx(struct mlx5_async_ctx *ctx)
1874
+{
1875
+ if (!atomic_dec_and_test(&ctx->num_inflight))
1876
+ wait_for_completion(&ctx->inflight_done);
1877
+}
1878
+EXPORT_SYMBOL(mlx5_cmd_cleanup_async_ctx);
1879
+
1880
+static void mlx5_cmd_exec_cb_handler(int status, void *_work)
1881
+{
1882
+ struct mlx5_async_work *work = _work;
1883
+ struct mlx5_async_ctx *ctx = work->ctx;
1884
+
1885
+ work->user_callback(status, work);
1886
+ if (atomic_dec_and_test(&ctx->num_inflight))
1887
+ complete(&ctx->inflight_done);
1888
+}
1889
+
1890
+int mlx5_cmd_exec_cb(struct mlx5_async_ctx *ctx, void *in, int in_size,
1891
+ void *out, int out_size, mlx5_async_cbk_t callback,
1892
+ struct mlx5_async_work *work)
1893
+{
1894
+ int ret;
1895
+
1896
+ work->ctx = ctx;
1897
+ work->user_callback = callback;
1898
+ if (WARN_ON(!atomic_inc_not_zero(&ctx->num_inflight)))
1899
+ return -EIO;
1900
+ ret = cmd_exec(ctx->dev, in, in_size, out, out_size,
1901
+ mlx5_cmd_exec_cb_handler, work, false);
1902
+ if (ret && atomic_dec_and_test(&ctx->num_inflight))
1903
+ complete(&ctx->inflight_done);
1904
+
1905
+ return ret;
16861906 }
16871907 EXPORT_SYMBOL(mlx5_cmd_exec_cb);
16881908
....@@ -1753,10 +1973,8 @@
17531973
17541974 static int alloc_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd)
17551975 {
1756
- struct device *ddev = &dev->pdev->dev;
1757
-
1758
- cmd->cmd_alloc_buf = dma_zalloc_coherent(ddev, MLX5_ADAPTER_PAGE_SIZE,
1759
- &cmd->alloc_dma, GFP_KERNEL);
1976
+ cmd->cmd_alloc_buf = dma_alloc_coherent(mlx5_core_dma_dev(dev), MLX5_ADAPTER_PAGE_SIZE,
1977
+ &cmd->alloc_dma, GFP_KERNEL);
17601978 if (!cmd->cmd_alloc_buf)
17611979 return -ENOMEM;
17621980
....@@ -1768,11 +1986,11 @@
17681986 return 0;
17691987 }
17701988
1771
- dma_free_coherent(ddev, MLX5_ADAPTER_PAGE_SIZE, cmd->cmd_alloc_buf,
1989
+ dma_free_coherent(mlx5_core_dma_dev(dev), MLX5_ADAPTER_PAGE_SIZE, cmd->cmd_alloc_buf,
17721990 cmd->alloc_dma);
1773
- cmd->cmd_alloc_buf = dma_zalloc_coherent(ddev,
1774
- 2 * MLX5_ADAPTER_PAGE_SIZE - 1,
1775
- &cmd->alloc_dma, GFP_KERNEL);
1991
+ cmd->cmd_alloc_buf = dma_alloc_coherent(mlx5_core_dma_dev(dev),
1992
+ 2 * MLX5_ADAPTER_PAGE_SIZE - 1,
1993
+ &cmd->alloc_dma, GFP_KERNEL);
17761994 if (!cmd->cmd_alloc_buf)
17771995 return -ENOMEM;
17781996
....@@ -1784,10 +2002,13 @@
17842002
17852003 static void free_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd)
17862004 {
1787
- struct device *ddev = &dev->pdev->dev;
1788
-
1789
- dma_free_coherent(ddev, cmd->alloc_size, cmd->cmd_alloc_buf,
2005
+ dma_free_coherent(mlx5_core_dma_dev(dev), cmd->alloc_size, cmd->cmd_alloc_buf,
17902006 cmd->alloc_dma);
2007
+}
2008
+
2009
+static u16 cmdif_rev(struct mlx5_core_dev *dev)
2010
+{
2011
+ return ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
17912012 }
17922013
17932014 int mlx5_cmd_init(struct mlx5_core_dev *dev)
....@@ -1803,16 +2024,21 @@
18032024 memset(cmd, 0, sizeof(*cmd));
18042025 cmd_if_rev = cmdif_rev(dev);
18052026 if (cmd_if_rev != CMD_IF_REV) {
1806
- dev_err(&dev->pdev->dev,
1807
- "Driver cmdif rev(%d) differs from firmware's(%d)\n",
1808
- CMD_IF_REV, cmd_if_rev);
2027
+ mlx5_core_err(dev,
2028
+ "Driver cmdif rev(%d) differs from firmware's(%d)\n",
2029
+ CMD_IF_REV, cmd_if_rev);
18092030 return -EINVAL;
18102031 }
18112032
1812
- cmd->pool = dma_pool_create("mlx5_cmd", &dev->pdev->dev, size, align,
1813
- 0);
1814
- if (!cmd->pool)
2033
+ cmd->stats = kvzalloc(MLX5_CMD_OP_MAX * sizeof(*cmd->stats), GFP_KERNEL);
2034
+ if (!cmd->stats)
18152035 return -ENOMEM;
2036
+
2037
+ cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0);
2038
+ if (!cmd->pool) {
2039
+ err = -ENOMEM;
2040
+ goto dma_pool_err;
2041
+ }
18162042
18172043 err = alloc_cmd_page(dev, cmd);
18182044 if (err)
....@@ -1822,33 +2048,34 @@
18222048 cmd->log_sz = cmd_l >> 4 & 0xf;
18232049 cmd->log_stride = cmd_l & 0xf;
18242050 if (1 << cmd->log_sz > MLX5_MAX_COMMANDS) {
1825
- dev_err(&dev->pdev->dev, "firmware reports too many outstanding commands %d\n",
1826
- 1 << cmd->log_sz);
2051
+ mlx5_core_err(dev, "firmware reports too many outstanding commands %d\n",
2052
+ 1 << cmd->log_sz);
18272053 err = -EINVAL;
18282054 goto err_free_page;
18292055 }
18302056
18312057 if (cmd->log_sz + cmd->log_stride > MLX5_ADAPTER_PAGE_SHIFT) {
1832
- dev_err(&dev->pdev->dev, "command queue size overflow\n");
2058
+ mlx5_core_err(dev, "command queue size overflow\n");
18332059 err = -EINVAL;
18342060 goto err_free_page;
18352061 }
18362062
2063
+ cmd->state = MLX5_CMDIF_STATE_DOWN;
18372064 cmd->checksum_disabled = 1;
18382065 cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
18392066 cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1;
18402067
18412068 cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
18422069 if (cmd->cmdif_rev > CMD_IF_REV) {
1843
- dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n",
1844
- CMD_IF_REV, cmd->cmdif_rev);
2070
+ mlx5_core_err(dev, "driver does not support command interface version. driver %d, firmware %d\n",
2071
+ CMD_IF_REV, cmd->cmdif_rev);
18452072 err = -EOPNOTSUPP;
18462073 goto err_free_page;
18472074 }
18482075
18492076 spin_lock_init(&cmd->alloc_lock);
18502077 spin_lock_init(&cmd->token_lock);
1851
- for (i = 0; i < ARRAY_SIZE(cmd->stats); i++)
2078
+ for (i = 0; i < MLX5_CMD_OP_MAX; i++)
18522079 spin_lock_init(&cmd->stats[i].lock);
18532080
18542081 sema_init(&cmd->sem, cmd->max_reg_cmds);
....@@ -1857,7 +2084,7 @@
18572084 cmd_h = (u32)((u64)(cmd->dma) >> 32);
18582085 cmd_l = (u32)(cmd->dma);
18592086 if (cmd_l & 0xfff) {
1860
- dev_err(&dev->pdev->dev, "invalid command queue address\n");
2087
+ mlx5_core_err(dev, "invalid command queue address\n");
18612088 err = -ENOMEM;
18622089 goto err_free_page;
18632090 }
....@@ -1871,27 +2098,21 @@
18712098 mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma));
18722099
18732100 cmd->mode = CMD_MODE_POLLING;
2101
+ cmd->allowed_opcode = CMD_ALLOWED_OPCODE_ALL;
18742102
18752103 create_msg_cache(dev);
18762104
18772105 set_wqname(dev);
18782106 cmd->wq = create_singlethread_workqueue(cmd->wq_name);
18792107 if (!cmd->wq) {
1880
- dev_err(&dev->pdev->dev, "failed to create command workqueue\n");
2108
+ mlx5_core_err(dev, "failed to create command workqueue\n");
18812109 err = -ENOMEM;
18822110 goto err_cache;
18832111 }
18842112
1885
- err = create_debugfs_files(dev);
1886
- if (err) {
1887
- err = -ENOMEM;
1888
- goto err_wq;
1889
- }
2113
+ create_debugfs_files(dev);
18902114
18912115 return 0;
1892
-
1893
-err_wq:
1894
- destroy_workqueue(cmd->wq);
18952116
18962117 err_cache:
18972118 destroy_msg_cache(dev);
....@@ -1901,7 +2122,8 @@
19012122
19022123 err_free_pool:
19032124 dma_pool_destroy(cmd->pool);
1904
-
2125
+dma_pool_err:
2126
+ kvfree(cmd->stats);
19052127 return err;
19062128 }
19072129 EXPORT_SYMBOL(mlx5_cmd_init);
....@@ -1915,5 +2137,13 @@
19152137 destroy_msg_cache(dev);
19162138 free_cmd_page(dev, cmd);
19172139 dma_pool_destroy(cmd->pool);
2140
+ kvfree(cmd->stats);
19182141 }
19192142 EXPORT_SYMBOL(mlx5_cmd_cleanup);
2143
+
2144
+void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
2145
+ enum mlx5_cmdif_state cmdif_state)
2146
+{
2147
+ dev->cmd.state = cmdif_state;
2148
+}
2149
+EXPORT_SYMBOL(mlx5_cmd_set_state);