aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorYevgeny Petrilin <yevgenyp@mellanox.co.il>2011-12-12 23:12:25 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-13 13:56:05 -0500
commite8f081aacdbf4740da46d0f4b602620dc2ec1a76 (patch)
treee67e3e629c1c2998094abe98720d6d0578a884bf /drivers
parentf5311ac109b21c9b47118655a5b6d887bcc686f8 (diff)
net/mlx4_core: Implement the master-slave communication channel
When SRIOV is enabled, pf and vfs communicate via shared comm channel. The vf gets its side of the comm channel via a VF BAR. Each VF (slave) creates its vHCR (virtual HCA Command Register), Its DMA address is passed to the PF (master) using Communication Channel Register. The same Register is used to notify the master of commands posted by the slaves and for the master to pass events to the slaves, such as command completions and asynchronous events. The vHCR format is identical to the HCR format, except for the 'go' and 't' bits, which are reserved in the vHCR. Posting commands to the vHCR is identical to the way it is done with the HCR, albeit that the function/PF token fields are used instead of the HCR go bit. Specifically: - When the function prepares a new command in the vHCR, it issues the Post_vHCR_cmd communication channel command and toggles the value of the function token; when PF token has an equal value, the command has been accepted and a new command may be posted. - When the PF detects a Post_vHCR_cmd command, it concludes that a new command is available in the vHCR; after processing the command, the PF toggles the PF token to match the function token. When the 'e' bit is not set, the completion of a Post_vHCR_cmd command also indicates the completion the vHCR command. If, however, the 'e' bit is set, the completion of a Post_vHCR_cmd command only indicates that the vHCR command has been accepted for execution by the PF. Function commands are processed by the PF as follows: -DMA (using the ACCESS_MEM command) the vHCR image into a shadow buffer. -Validate that the opcode is non-privileged, and that the opcode- and input-modifiers are legal. -DMA the in-box (if required) into a shadow buffer. -Validate the command: o Resource ranges (e.g., QP ranges). o Partition key. o Ranges of referenced resources (e.g., CQs within QP contexts). -If the 'e' bit is set o complete the Post_vHCR_cmd command -Execute the command on the HCR. -DMA the results to the vHCR out-box (if required). -If the 'e' bit is set o Indicate command completion by generating a completion event using the GEN_EQE command -Otherwise o DMA the command status to the vHCR o Complete the Post_vHCR_cmd command Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Yevgeny Petrillin <yevgenyp@mellanox.com> Signed-off-by: Liran Liss <liranl@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c699
1 files changed, 672 insertions, 27 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index b27654e5d544..9c0bdcabaea0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -39,12 +39,18 @@
39#include <linux/errno.h> 39#include <linux/errno.h>
40 40
41#include <linux/mlx4/cmd.h> 41#include <linux/mlx4/cmd.h>
42#include <linux/semaphore.h>
42 43
43#include <asm/io.h> 44#include <asm/io.h>
44 45
45#include "mlx4.h" 46#include "mlx4.h"
47#include "fw.h"
46 48
47#define CMD_POLL_TOKEN 0xffff 49#define CMD_POLL_TOKEN 0xffff
50#define INBOX_MASK 0xffffffffffffff00ULL
51
52#define CMD_CHAN_VER 1
53#define CMD_CHAN_IF_REV 1
48 54
49enum { 55enum {
50 /* command completed successfully: */ 56 /* command completed successfully: */
@@ -110,8 +116,12 @@ struct mlx4_cmd_context {
110 int next; 116 int next;
111 u64 out_param; 117 u64 out_param;
112 u16 token; 118 u16 token;
119 u8 fw_status;
113}; 120};
114 121
122static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
123 struct mlx4_vhcr_cmd *in_vhcr);
124
115static int mlx4_status_to_errno(u8 status) 125static int mlx4_status_to_errno(u8 status)
116{ 126{
117 static const int trans_table[] = { 127 static const int trans_table[] = {
@@ -142,6 +152,125 @@ static int mlx4_status_to_errno(u8 status)
142 return trans_table[status]; 152 return trans_table[status];
143} 153}
144 154
155static int comm_pending(struct mlx4_dev *dev)
156{
157 struct mlx4_priv *priv = mlx4_priv(dev);
158 u32 status = readl(&priv->mfunc.comm->slave_read);
159
160 return (swab32(status) >> 31) != priv->cmd.comm_toggle;
161}
162
163static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param)
164{
165 struct mlx4_priv *priv = mlx4_priv(dev);
166 u32 val;
167
168 priv->cmd.comm_toggle ^= 1;
169 val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31);
170 __raw_writel((__force u32) cpu_to_be32(val),
171 &priv->mfunc.comm->slave_write);
172 mmiowb();
173}
174
175/* dummy procedure for this patch */
176int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
177{
178 return 0;
179}
180
181static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
182 unsigned long timeout)
183{
184 struct mlx4_priv *priv = mlx4_priv(dev);
185 unsigned long end;
186 int err = 0;
187 int ret_from_pending = 0;
188
189 /* First, verify that the master reports correct status */
190 if (comm_pending(dev)) {
191 mlx4_warn(dev, "Communication channel is not idle."
192 "my toggle is %d (cmd:0x%x)\n",
193 priv->cmd.comm_toggle, cmd);
194 return -EAGAIN;
195 }
196
197 /* Write command */
198 down(&priv->cmd.poll_sem);
199 mlx4_comm_cmd_post(dev, cmd, param);
200
201 end = msecs_to_jiffies(timeout) + jiffies;
202 while (comm_pending(dev) && time_before(jiffies, end))
203 cond_resched();
204 ret_from_pending = comm_pending(dev);
205 if (ret_from_pending) {
206 /* check if the slave is trying to boot in the middle of
207 * FLR process. The only non-zero result in the RESET command
208 * is MLX4_DELAY_RESET_SLAVE*/
209 if ((MLX4_COMM_CMD_RESET == cmd)) {
210 mlx4_warn(dev, "Got slave FLRed from Communication"
211 " channel (ret:0x%x)\n", ret_from_pending);
212 err = MLX4_DELAY_RESET_SLAVE;
213 } else {
214 mlx4_warn(dev, "Communication channel timed out\n");
215 err = -ETIMEDOUT;
216 }
217 }
218
219 up(&priv->cmd.poll_sem);
220 return err;
221}
222
223static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op,
224 u16 param, unsigned long timeout)
225{
226 struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
227 struct mlx4_cmd_context *context;
228 int err = 0;
229
230 down(&cmd->event_sem);
231
232 spin_lock(&cmd->context_lock);
233 BUG_ON(cmd->free_head < 0);
234 context = &cmd->context[cmd->free_head];
235 context->token += cmd->token_mask + 1;
236 cmd->free_head = context->next;
237 spin_unlock(&cmd->context_lock);
238
239 init_completion(&context->done);
240
241 mlx4_comm_cmd_post(dev, op, param);
242
243 if (!wait_for_completion_timeout(&context->done,
244 msecs_to_jiffies(timeout))) {
245 err = -EBUSY;
246 goto out;
247 }
248
249 err = context->result;
250 if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) {
251 mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
252 op, context->fw_status);
253 goto out;
254 }
255
256out:
257 spin_lock(&cmd->context_lock);
258 context->next = cmd->free_head;
259 cmd->free_head = context - cmd->context;
260 spin_unlock(&cmd->context_lock);
261
262 up(&cmd->event_sem);
263 return err;
264}
265
266static int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
267 unsigned long timeout)
268{
269 if (mlx4_priv(dev)->cmd.use_events)
270 return mlx4_comm_cmd_wait(dev, cmd, param, timeout);
271 return mlx4_comm_cmd_poll(dev, cmd, param, timeout);
272}
273
145static int cmd_pending(struct mlx4_dev *dev) 274static int cmd_pending(struct mlx4_dev *dev)
146{ 275{
147 u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 276 u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
@@ -167,8 +296,10 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
167 end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 296 end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
168 297
169 while (cmd_pending(dev)) { 298 while (cmd_pending(dev)) {
170 if (time_after_eq(jiffies, end)) 299 if (time_after_eq(jiffies, end)) {
300 mlx4_err(dev, "%s:cmd_pending failed\n", __func__);
171 goto out; 301 goto out;
302 }
172 cond_resched(); 303 cond_resched();
173 } 304 }
174 305
@@ -192,7 +323,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
192 (cmd->toggle << HCR_T_BIT) | 323 (cmd->toggle << HCR_T_BIT) |
193 (event ? (1 << HCR_E_BIT) : 0) | 324 (event ? (1 << HCR_E_BIT) : 0) |
194 (op_modifier << HCR_OPMOD_SHIFT) | 325 (op_modifier << HCR_OPMOD_SHIFT) |
195 op), hcr + 6); 326 op), hcr + 6);
196 327
197 /* 328 /*
198 * Make sure that our HCR writes don't get mixed in with 329 * Make sure that our HCR writes don't get mixed in with
@@ -209,6 +340,62 @@ out:
209 return ret; 340 return ret;
210} 341}
211 342
343static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
344 int out_is_imm, u32 in_modifier, u8 op_modifier,
345 u16 op, unsigned long timeout)
346{
347 struct mlx4_priv *priv = mlx4_priv(dev);
348 struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr;
349 int ret;
350
351 down(&priv->cmd.slave_sem);
352 vhcr->in_param = cpu_to_be64(in_param);
353 vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0;
354 vhcr->in_modifier = cpu_to_be32(in_modifier);
355 vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff));
356 vhcr->token = cpu_to_be16(CMD_POLL_TOKEN);
357 vhcr->status = 0;
358 vhcr->flags = !!(priv->cmd.use_events) << 6;
359 if (mlx4_is_master(dev)) {
360 ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr);
361 if (!ret) {
362 if (out_is_imm) {
363 if (out_param)
364 *out_param =
365 be64_to_cpu(vhcr->out_param);
366 else {
367 mlx4_err(dev, "response expected while"
368 "output mailbox is NULL for "
369 "command 0x%x\n", op);
370 vhcr->status = -EINVAL;
371 }
372 }
373 ret = vhcr->status;
374 }
375 } else {
376 ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0,
377 MLX4_COMM_TIME + timeout);
378 if (!ret) {
379 if (out_is_imm) {
380 if (out_param)
381 *out_param =
382 be64_to_cpu(vhcr->out_param);
383 else {
384 mlx4_err(dev, "response expected while"
385 "output mailbox is NULL for "
386 "command 0x%x\n", op);
387 vhcr->status = -EINVAL;
388 }
389 }
390 ret = vhcr->status;
391 } else
392 mlx4_err(dev, "failed execution of VHCR_POST command"
393 "opcode 0x%x\n", op);
394 }
395 up(&priv->cmd.slave_sem);
396 return ret;
397}
398
212static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 399static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
213 int out_is_imm, u32 in_modifier, u8 op_modifier, 400 int out_is_imm, u32 in_modifier, u8 op_modifier,
214 u16 op, unsigned long timeout) 401 u16 op, unsigned long timeout)
@@ -217,6 +404,7 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
217 void __iomem *hcr = priv->cmd.hcr; 404 void __iomem *hcr = priv->cmd.hcr;
218 int err = 0; 405 int err = 0;
219 unsigned long end; 406 unsigned long end;
407 u32 stat;
220 408
221 down(&priv->cmd.poll_sem); 409 down(&priv->cmd.poll_sem);
222 410
@@ -240,9 +428,12 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
240 __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 428 __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
241 (u64) be32_to_cpu((__force __be32) 429 (u64) be32_to_cpu((__force __be32)
242 __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 430 __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4));
243 431 stat = be32_to_cpu((__force __be32)
244 err = mlx4_status_to_errno(be32_to_cpu((__force __be32) 432 __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24;
245 __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24); 433 err = mlx4_status_to_errno(stat);
434 if (err)
435 mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
436 op, stat);
246 437
247out: 438out:
248 up(&priv->cmd.poll_sem); 439 up(&priv->cmd.poll_sem);
@@ -259,6 +450,7 @@ void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
259 if (token != context->token) 450 if (token != context->token)
260 return; 451 return;
261 452
453 context->fw_status = status;
262 context->result = mlx4_status_to_errno(status); 454 context->result = mlx4_status_to_errno(status);
263 context->out_param = out_param; 455 context->out_param = out_param;
264 456
@@ -287,14 +479,18 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
287 mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 479 mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
288 in_modifier, op_modifier, op, context->token, 1); 480 in_modifier, op_modifier, op, context->token, 1);
289 481
290 if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { 482 if (!wait_for_completion_timeout(&context->done,
483 msecs_to_jiffies(timeout))) {
291 err = -EBUSY; 484 err = -EBUSY;
292 goto out; 485 goto out;
293 } 486 }
294 487
295 err = context->result; 488 err = context->result;
296 if (err) 489 if (err) {
490 mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
491 op, context->fw_status);
297 goto out; 492 goto out;
493 }
298 494
299 if (out_is_imm) 495 if (out_is_imm)
300 *out_param = context->out_param; 496 *out_param = context->out_param;
@@ -313,15 +509,448 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
313 int out_is_imm, u32 in_modifier, u8 op_modifier, 509 int out_is_imm, u32 in_modifier, u8 op_modifier,
314 u16 op, unsigned long timeout, int native) 510 u16 op, unsigned long timeout, int native)
315{ 511{
316 if (mlx4_priv(dev)->cmd.use_events) 512 if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) {
317 return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, 513 if (mlx4_priv(dev)->cmd.use_events)
318 in_modifier, op_modifier, op, timeout); 514 return mlx4_cmd_wait(dev, in_param, out_param,
319 else 515 out_is_imm, in_modifier,
320 return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm, 516 op_modifier, op, timeout);
321 in_modifier, op_modifier, op, timeout); 517 else
518 return mlx4_cmd_poll(dev, in_param, out_param,
519 out_is_imm, in_modifier,
520 op_modifier, op, timeout);
521 }
522 return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm,
523 in_modifier, op_modifier, op, timeout);
322} 524}
323EXPORT_SYMBOL_GPL(__mlx4_cmd); 525EXPORT_SYMBOL_GPL(__mlx4_cmd);
324 526
527
528static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev)
529{
530 return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL,
531 MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
532}
533
534static int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr,
535 int slave, u64 slave_addr,
536 int size, int is_read)
537{
538 u64 in_param;
539 u64 out_param;
540
541 if ((slave_addr & 0xfff) | (master_addr & 0xfff) |
542 (slave & ~0x7f) | (size & 0xff)) {
543 mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx "
544 "master_addr:0x%llx slave_id:%d size:%d\n",
545 slave_addr, master_addr, slave, size);
546 return -EINVAL;
547 }
548
549 if (is_read) {
550 in_param = (u64) slave | slave_addr;
551 out_param = (u64) dev->caps.function | master_addr;
552 } else {
553 in_param = (u64) dev->caps.function | master_addr;
554 out_param = (u64) slave | slave_addr;
555 }
556
557 return mlx4_cmd_imm(dev, in_param, &out_param, size, 0,
558 MLX4_CMD_ACCESS_MEM,
559 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
560}
561
562int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
563 struct mlx4_vhcr *vhcr,
564 struct mlx4_cmd_mailbox *inbox,
565 struct mlx4_cmd_mailbox *outbox,
566 struct mlx4_cmd_info *cmd)
567{
568 u64 in_param;
569 u64 out_param;
570 int err;
571
572 in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param;
573 out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param;
574 if (cmd->encode_slave_id) {
575 in_param &= 0xffffffffffffff00ll;
576 in_param |= slave;
577 }
578
579 err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm,
580 vhcr->in_modifier, vhcr->op_modifier, vhcr->op,
581 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
582
583 if (cmd->out_is_imm)
584 vhcr->out_param = out_param;
585
586 return err;
587}
588
589static struct mlx4_cmd_info cmd_info[] = {
590 {
591 .opcode = MLX4_CMD_QUERY_FW,
592 .has_inbox = false,
593 .has_outbox = true,
594 .out_is_imm = false,
595 .encode_slave_id = false,
596 .verify = NULL,
597 .wrapper = NULL
598 },
599 {
600 .opcode = MLX4_CMD_QUERY_HCA,
601 .has_inbox = false,
602 .has_outbox = true,
603 .out_is_imm = false,
604 .encode_slave_id = false,
605 .verify = NULL,
606 .wrapper = NULL
607 },
608 {
609 .opcode = MLX4_CMD_QUERY_DEV_CAP,
610 .has_inbox = false,
611 .has_outbox = true,
612 .out_is_imm = false,
613 .encode_slave_id = false,
614 .verify = NULL,
615 .wrapper = NULL
616 },
617};
618
619static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
620 struct mlx4_vhcr_cmd *in_vhcr)
621{
622 struct mlx4_priv *priv = mlx4_priv(dev);
623 struct mlx4_cmd_info *cmd = NULL;
624 struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr;
625 struct mlx4_vhcr *vhcr;
626 struct mlx4_cmd_mailbox *inbox = NULL;
627 struct mlx4_cmd_mailbox *outbox = NULL;
628 u64 in_param;
629 u64 out_param;
630 int ret = 0;
631 int i;
632
633 /* Create sw representation of Virtual HCR */
634 vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL);
635 if (!vhcr)
636 return -ENOMEM;
637
638 /* DMA in the vHCR */
639 if (!in_vhcr) {
640 ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
641 priv->mfunc.master.slave_state[slave].vhcr_dma,
642 ALIGN(sizeof(struct mlx4_vhcr_cmd),
643 MLX4_ACCESS_MEM_ALIGN), 1);
644 if (ret) {
645 mlx4_err(dev, "%s:Failed reading vhcr"
646 "ret: 0x%x\n", __func__, ret);
647 kfree(vhcr);
648 return ret;
649 }
650 }
651
652 /* Fill SW VHCR fields */
653 vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param);
654 vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param);
655 vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier);
656 vhcr->token = be16_to_cpu(vhcr_cmd->token);
657 vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff;
658 vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12);
659 vhcr->e_bit = vhcr_cmd->flags & (1 << 6);
660
661 /* Lookup command */
662 for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) {
663 if (vhcr->op == cmd_info[i].opcode) {
664 cmd = &cmd_info[i];
665 break;
666 }
667 }
668 if (!cmd) {
669 mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n",
670 vhcr->op, slave);
671 vhcr_cmd->status = -EINVAL;
672 goto out_status;
673 }
674
675 /* Read inbox */
676 if (cmd->has_inbox) {
677 vhcr->in_param &= INBOX_MASK;
678 inbox = mlx4_alloc_cmd_mailbox(dev);
679 if (IS_ERR(inbox)) {
680 ret = PTR_ERR(inbox);
681 inbox = NULL;
682 goto out;
683 }
684
685 ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave,
686 vhcr->in_param,
687 MLX4_MAILBOX_SIZE, 1);
688 if (ret) {
689 mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n",
690 __func__, cmd->opcode);
691 goto out;
692 }
693 }
694
695 /* Apply permission and bound checks if applicable */
696 if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) {
697 mlx4_warn(dev, "Command:0x%x from slave: %d failed protection "
698 "checks for resource_id:%d\n", vhcr->op, slave,
699 vhcr->in_modifier);
700 vhcr_cmd->status = -EPERM;
701 goto out_status;
702 }
703
704 /* Allocate outbox */
705 if (cmd->has_outbox) {
706 outbox = mlx4_alloc_cmd_mailbox(dev);
707 if (IS_ERR(outbox)) {
708 ret = PTR_ERR(outbox);
709 outbox = NULL;
710 goto out;
711 }
712 }
713
714 /* Execute the command! */
715 if (cmd->wrapper) {
716 vhcr_cmd->status = cmd->wrapper(dev, slave, vhcr, inbox, outbox,
717 cmd);
718 if (cmd->out_is_imm)
719 vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
720 } else {
721 in_param = cmd->has_inbox ? (u64) inbox->dma :
722 vhcr->in_param;
723 out_param = cmd->has_outbox ? (u64) outbox->dma :
724 vhcr->out_param;
725 vhcr_cmd->status = __mlx4_cmd(dev, in_param, &out_param,
726 cmd->out_is_imm, vhcr->in_modifier,
727 vhcr->op_modifier, vhcr->op,
728 MLX4_CMD_TIME_CLASS_A,
729 MLX4_CMD_NATIVE);
730
731 if (vhcr_cmd->status) {
732 mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with"
733 " error:%d, status %d\n",
734 vhcr->op, slave, vhcr->errno,
735 vhcr_cmd->status);
736 ret = vhcr_cmd->status;
737 goto out;
738 }
739
740 if (cmd->out_is_imm) {
741 vhcr->out_param = out_param;
742 vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
743 }
744 }
745
746 /* Write outbox if command completed successfully */
747 if (cmd->has_outbox && !vhcr->errno) {
748 ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave,
749 vhcr->out_param,
750 MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED);
751 if (ret) {
752 mlx4_err(dev, "%s:Failed writing outbox\n", __func__);
753 goto out;
754 }
755 }
756
757out_status:
758 /* DMA back vhcr result */
759 if (!in_vhcr) {
760 ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
761 priv->mfunc.master.slave_state[slave].vhcr_dma,
762 ALIGN(sizeof(struct mlx4_vhcr),
763 MLX4_ACCESS_MEM_ALIGN),
764 MLX4_CMD_WRAPPED);
765 if (ret)
766 mlx4_err(dev, "%s:Failed writing vhcr result\n",
767 __func__);
768 else if (vhcr->e_bit &&
769 mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe))
770 mlx4_warn(dev, "Failed to generate command completion "
771 "eqe for slave %d\n", slave);
772 }
773
774out:
775 kfree(vhcr);
776 mlx4_free_cmd_mailbox(dev, inbox);
777 mlx4_free_cmd_mailbox(dev, outbox);
778 return ret;
779}
780
781static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
782 u16 param, u8 toggle)
783{
784 struct mlx4_priv *priv = mlx4_priv(dev);
785 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
786 u32 reply;
787 u32 slave_status = 0;
788 u8 is_going_down = 0;
789
790 slave_state[slave].comm_toggle ^= 1;
791 reply = (u32) slave_state[slave].comm_toggle << 31;
792 if (toggle != slave_state[slave].comm_toggle) {
793 mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER"
794 "STATE COMPROMISIED ***\n", toggle, slave);
795 goto reset_slave;
796 }
797 if (cmd == MLX4_COMM_CMD_RESET) {
798 mlx4_warn(dev, "Received reset from slave:%d\n", slave);
799 slave_state[slave].active = false;
800 /*check if we are in the middle of FLR process,
801 if so return "retry" status to the slave*/
802 if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) {
803 slave_status = MLX4_DELAY_RESET_SLAVE;
804 goto inform_slave_state;
805 }
806
807 /* write the version in the event field */
808 reply |= mlx4_comm_get_version();
809
810 goto reset_slave;
811 }
812 /*command from slave in the middle of FLR*/
813 if (cmd != MLX4_COMM_CMD_RESET &&
814 MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) {
815 mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) "
816 "in the middle of FLR\n", slave, cmd);
817 return;
818 }
819
820 switch (cmd) {
821 case MLX4_COMM_CMD_VHCR0:
822 if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET)
823 goto reset_slave;
824 slave_state[slave].vhcr_dma = ((u64) param) << 48;
825 priv->mfunc.master.slave_state[slave].cookie = 0;
826 mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]);
827 break;
828 case MLX4_COMM_CMD_VHCR1:
829 if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
830 goto reset_slave;
831 slave_state[slave].vhcr_dma |= ((u64) param) << 32;
832 break;
833 case MLX4_COMM_CMD_VHCR2:
834 if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1)
835 goto reset_slave;
836 slave_state[slave].vhcr_dma |= ((u64) param) << 16;
837 break;
838 case MLX4_COMM_CMD_VHCR_EN:
839 if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
840 goto reset_slave;
841 slave_state[slave].vhcr_dma |= param;
842 slave_state[slave].active = true;
843 break;
844 case MLX4_COMM_CMD_VHCR_POST:
845 if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
846 (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST))
847 goto reset_slave;
848 down(&priv->cmd.slave_sem);
849 if (mlx4_master_process_vhcr(dev, slave, NULL)) {
850 mlx4_err(dev, "Failed processing vhcr for slave:%d,"
851 " reseting slave.\n", slave);
852 up(&priv->cmd.slave_sem);
853 goto reset_slave;
854 }
855 up(&priv->cmd.slave_sem);
856 break;
857 default:
858 mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave);
859 goto reset_slave;
860 }
861 spin_lock(&priv->mfunc.master.slave_state_lock);
862 if (!slave_state[slave].is_slave_going_down)
863 slave_state[slave].last_cmd = cmd;
864 else
865 is_going_down = 1;
866 spin_unlock(&priv->mfunc.master.slave_state_lock);
867 if (is_going_down) {
868 mlx4_warn(dev, "Slave is going down aborting command(%d)"
869 " executing from slave:%d\n",
870 cmd, slave);
871 return;
872 }
873 __raw_writel((__force u32) cpu_to_be32(reply),
874 &priv->mfunc.comm[slave].slave_read);
875 mmiowb();
876
877 return;
878
879reset_slave:
880 spin_lock(&priv->mfunc.master.slave_state_lock);
881 if (!slave_state[slave].is_slave_going_down)
882 slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET;
883 spin_unlock(&priv->mfunc.master.slave_state_lock);
884 /*with slave in the middle of flr, no need to clean resources again.*/
885inform_slave_state:
886 memset(&slave_state[slave].event_eq, 0,
887 sizeof(struct mlx4_slave_event_eq_info));
888 __raw_writel((__force u32) cpu_to_be32(reply),
889 &priv->mfunc.comm[slave].slave_read);
890 wmb();
891}
892
893/* master command processing */
894void mlx4_master_comm_channel(struct work_struct *work)
895{
896 struct mlx4_mfunc_master_ctx *master =
897 container_of(work,
898 struct mlx4_mfunc_master_ctx,
899 comm_work);
900 struct mlx4_mfunc *mfunc =
901 container_of(master, struct mlx4_mfunc, master);
902 struct mlx4_priv *priv =
903 container_of(mfunc, struct mlx4_priv, mfunc);
904 struct mlx4_dev *dev = &priv->dev;
905 __be32 *bit_vec;
906 u32 comm_cmd;
907 u32 vec;
908 int i, j, slave;
909 int toggle;
910 int served = 0;
911 int reported = 0;
912 u32 slt;
913
914 bit_vec = master->comm_arm_bit_vector;
915 for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) {
916 vec = be32_to_cpu(bit_vec[i]);
917 for (j = 0; j < 32; j++) {
918 if (!(vec & (1 << j)))
919 continue;
920 ++reported;
921 slave = (i * 32) + j;
922 comm_cmd = swab32(readl(
923 &mfunc->comm[slave].slave_write));
924 slt = swab32(readl(&mfunc->comm[slave].slave_read))
925 >> 31;
926 toggle = comm_cmd >> 31;
927 if (toggle != slt) {
928 if (master->slave_state[slave].comm_toggle
929 != slt) {
930 printk(KERN_INFO "slave %d out of sync."
931 " read toggle %d, state toggle %d. "
932 "Resynching.\n", slave, slt,
933 master->slave_state[slave].comm_toggle);
934 master->slave_state[slave].comm_toggle =
935 slt;
936 }
937 mlx4_master_do_cmd(dev, slave,
938 comm_cmd >> 16 & 0xff,
939 comm_cmd & 0xffff, toggle);
940 ++served;
941 }
942 }
943 }
944
945 if (reported && reported != served)
946 mlx4_warn(dev, "Got command event with bitmask from %d slaves"
947 " but %d were served\n",
948 reported, served);
949
950 if (mlx4_ARM_COMM_CHANNEL(dev))
951 mlx4_warn(dev, "Failed to arm comm channel events\n");
952}
953
325int mlx4_cmd_init(struct mlx4_dev *dev) 954int mlx4_cmd_init(struct mlx4_dev *dev)
326{ 955{
327 struct mlx4_priv *priv = mlx4_priv(dev); 956 struct mlx4_priv *priv = mlx4_priv(dev);
@@ -331,22 +960,30 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
331 priv->cmd.use_events = 0; 960 priv->cmd.use_events = 0;
332 priv->cmd.toggle = 1; 961 priv->cmd.toggle = 1;
333 962
334 priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_HCR_BASE, 963 priv->cmd.hcr = NULL;
335 MLX4_HCR_SIZE); 964 priv->mfunc.vhcr = NULL;
336 if (!priv->cmd.hcr) { 965
337 mlx4_err(dev, "Couldn't map command register."); 966 if (!mlx4_is_slave(dev)) {
338 return -ENOMEM; 967 priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) +
968 MLX4_HCR_BASE, MLX4_HCR_SIZE);
969 if (!priv->cmd.hcr) {
970 mlx4_err(dev, "Couldn't map command register.\n");
971 return -ENOMEM;
972 }
339 } 973 }
340 974
341 priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, 975 priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
342 MLX4_MAILBOX_SIZE, 976 MLX4_MAILBOX_SIZE,
343 MLX4_MAILBOX_SIZE, 0); 977 MLX4_MAILBOX_SIZE, 0);
344 if (!priv->cmd.pool) { 978 if (!priv->cmd.pool)
345 iounmap(priv->cmd.hcr); 979 goto err_hcr;
346 return -ENOMEM;
347 }
348 980
349 return 0; 981 return 0;
982
983err_hcr:
984 if (!mlx4_is_slave(dev))
985 iounmap(priv->cmd.hcr);
986 return -ENOMEM;
350} 987}
351 988
352void mlx4_cmd_cleanup(struct mlx4_dev *dev) 989void mlx4_cmd_cleanup(struct mlx4_dev *dev)
@@ -354,7 +991,9 @@ void mlx4_cmd_cleanup(struct mlx4_dev *dev)
354 struct mlx4_priv *priv = mlx4_priv(dev); 991 struct mlx4_priv *priv = mlx4_priv(dev);
355 992
356 pci_pool_destroy(priv->cmd.pool); 993 pci_pool_destroy(priv->cmd.pool);
357 iounmap(priv->cmd.hcr); 994
995 if (!mlx4_is_slave(dev))
996 iounmap(priv->cmd.hcr);
358} 997}
359 998
360/* 999/*
@@ -365,6 +1004,7 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev)
365{ 1004{
366 struct mlx4_priv *priv = mlx4_priv(dev); 1005 struct mlx4_priv *priv = mlx4_priv(dev);
367 int i; 1006 int i;
1007 int err = 0;
368 1008
369 priv->cmd.context = kmalloc(priv->cmd.max_cmds * 1009 priv->cmd.context = kmalloc(priv->cmd.max_cmds *
370 sizeof (struct mlx4_cmd_context), 1010 sizeof (struct mlx4_cmd_context),
@@ -389,11 +1029,10 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev)
389 ; /* nothing */ 1029 ; /* nothing */
390 --priv->cmd.token_mask; 1030 --priv->cmd.token_mask;
391 1031
392 priv->cmd.use_events = 1;
393
394 down(&priv->cmd.poll_sem); 1032 down(&priv->cmd.poll_sem);
1033 priv->cmd.use_events = 1;
395 1034
396 return 0; 1035 return err;
397} 1036}
398 1037
399/* 1038/*
@@ -433,7 +1072,8 @@ struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
433} 1072}
434EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 1073EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
435 1074
436void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox) 1075void mlx4_free_cmd_mailbox(struct mlx4_dev *dev,
1076 struct mlx4_cmd_mailbox *mailbox)
437{ 1077{
438 if (!mailbox) 1078 if (!mailbox)
439 return; 1079 return;
@@ -442,3 +1082,8 @@ void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbo
442 kfree(mailbox); 1082 kfree(mailbox);
443} 1083}
444EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 1084EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox);
1085
1086u32 mlx4_comm_get_version(void)
1087{
1088 return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
1089}