1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3219820Sjeff * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
4219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff */
34219820Sjeff
35219820Sjeff#include <linux/sched.h>
36255932Salfred#include <linux/slab.h>
37219820Sjeff#include <linux/pci.h>
38219820Sjeff#include <linux/errno.h>
39219820Sjeff
40219820Sjeff#include <linux/mlx4/cmd.h>
41255932Salfred#include <linux/semaphore.h>
42255932Salfred#include <rdma/ib_smi.h>
43219820Sjeff
44219820Sjeff#include <asm/io.h>
45219820Sjeff
46219820Sjeff#include "mlx4.h"
47255932Salfred#include "fw.h"
48219820Sjeff
49219820Sjeff#define CMD_POLL_TOKEN 0xffff
50255932Salfred#define INBOX_MASK	0xffffffffffffff00ULL
51219820Sjeff
52255932Salfred#define CMD_CHAN_VER 1
53255932Salfred#define CMD_CHAN_IF_REV 1
54255932Salfred
55219820Sjeffenum {
56219820Sjeff	/* command completed successfully: */
57219820Sjeff	CMD_STAT_OK		= 0x00,
58219820Sjeff	/* Internal error (such as a bus error) occurred while processing command: */
59219820Sjeff	CMD_STAT_INTERNAL_ERR	= 0x01,
60219820Sjeff	/* Operation/command not supported or opcode modifier not supported: */
61219820Sjeff	CMD_STAT_BAD_OP		= 0x02,
62219820Sjeff	/* Parameter not supported or parameter out of range: */
63219820Sjeff	CMD_STAT_BAD_PARAM	= 0x03,
64219820Sjeff	/* System not enabled or bad system state: */
65219820Sjeff	CMD_STAT_BAD_SYS_STATE	= 0x04,
66219820Sjeff	/* Attempt to access reserved or unallocaterd resource: */
67219820Sjeff	CMD_STAT_BAD_RESOURCE	= 0x05,
68219820Sjeff	/* Requested resource is currently executing a command, or is otherwise busy: */
69219820Sjeff	CMD_STAT_RESOURCE_BUSY	= 0x06,
70219820Sjeff	/* Required capability exceeds device limits: */
71219820Sjeff	CMD_STAT_EXCEED_LIM	= 0x08,
72219820Sjeff	/* Resource is not in the appropriate state or ownership: */
73219820Sjeff	CMD_STAT_BAD_RES_STATE	= 0x09,
74219820Sjeff	/* Index out of range: */
75219820Sjeff	CMD_STAT_BAD_INDEX	= 0x0a,
76219820Sjeff	/* FW image corrupted: */
77219820Sjeff	CMD_STAT_BAD_NVMEM	= 0x0b,
78219820Sjeff	/* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */
79219820Sjeff	CMD_STAT_ICM_ERROR	= 0x0c,
80219820Sjeff	/* Attempt to modify a QP/EE which is not in the presumed state: */
81219820Sjeff	CMD_STAT_BAD_QP_STATE   = 0x10,
82219820Sjeff	/* Bad segment parameters (Address/Size): */
83219820Sjeff	CMD_STAT_BAD_SEG_PARAM	= 0x20,
84219820Sjeff	/* Memory Region has Memory Windows bound to: */
85219820Sjeff	CMD_STAT_REG_BOUND	= 0x21,
86219820Sjeff	/* HCA local attached memory not present: */
87219820Sjeff	CMD_STAT_LAM_NOT_PRE	= 0x22,
88219820Sjeff	/* Bad management packet (silently discarded): */
89219820Sjeff	CMD_STAT_BAD_PKT	= 0x30,
90219820Sjeff	/* More outstanding CQEs in CQ than new CQ size: */
91219820Sjeff	CMD_STAT_BAD_SIZE	= 0x40,
92219820Sjeff	/* Multi Function device support required: */
93219820Sjeff	CMD_STAT_MULTI_FUNC_REQ	= 0x50,
94219820Sjeff};
95219820Sjeff
96219820Sjeffenum {
97219820Sjeff	HCR_IN_PARAM_OFFSET	= 0x00,
98219820Sjeff	HCR_IN_MODIFIER_OFFSET	= 0x08,
99219820Sjeff	HCR_OUT_PARAM_OFFSET	= 0x0c,
100219820Sjeff	HCR_TOKEN_OFFSET	= 0x14,
101219820Sjeff	HCR_STATUS_OFFSET	= 0x18,
102219820Sjeff
103219820Sjeff	HCR_OPMOD_SHIFT		= 12,
104219820Sjeff	HCR_T_BIT		= 21,
105219820Sjeff	HCR_E_BIT		= 22,
106219820Sjeff	HCR_GO_BIT		= 23
107219820Sjeff};
108219820Sjeff
109219820Sjeffenum {
110219820Sjeff	GO_BIT_TIMEOUT_MSECS	= 10000
111219820Sjeff};
112219820Sjeff
113219820Sjeffstruct mlx4_cmd_context {
114219820Sjeff	struct completion	done;
115219820Sjeff	int			result;
116219820Sjeff	int			next;
117219820Sjeff	u64			out_param;
118219820Sjeff	u16			token;
119219820Sjeff	u8			fw_status;
120219820Sjeff};
121219820Sjeff
122255932Salfredstatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
123255932Salfred				    struct mlx4_vhcr_cmd *in_vhcr);
124255932Salfred
125219820Sjeffstatic int mlx4_status_to_errno(u8 status)
126219820Sjeff{
127219820Sjeff	static const int trans_table[] = {
128219820Sjeff		[CMD_STAT_INTERNAL_ERR]	  = -EIO,
129219820Sjeff		[CMD_STAT_BAD_OP]	  = -EPERM,
130219820Sjeff		[CMD_STAT_BAD_PARAM]	  = -EINVAL,
131219820Sjeff		[CMD_STAT_BAD_SYS_STATE]  = -ENXIO,
132219820Sjeff		[CMD_STAT_BAD_RESOURCE]	  = -EBADF,
133219820Sjeff		[CMD_STAT_RESOURCE_BUSY]  = -EBUSY,
134219820Sjeff		[CMD_STAT_EXCEED_LIM]	  = -ENOMEM,
135219820Sjeff		[CMD_STAT_BAD_RES_STATE]  = -EBADF,
136219820Sjeff		[CMD_STAT_BAD_INDEX]	  = -EBADF,
137219820Sjeff		[CMD_STAT_BAD_NVMEM]	  = -EFAULT,
138219820Sjeff		[CMD_STAT_ICM_ERROR]	  = -ENFILE,
139219820Sjeff		[CMD_STAT_BAD_QP_STATE]   = -EINVAL,
140219820Sjeff		[CMD_STAT_BAD_SEG_PARAM]  = -EFAULT,
141219820Sjeff		[CMD_STAT_REG_BOUND]	  = -EBUSY,
142219820Sjeff		[CMD_STAT_LAM_NOT_PRE]	  = -EAGAIN,
143219820Sjeff		[CMD_STAT_BAD_PKT]	  = -EINVAL,
144219820Sjeff		[CMD_STAT_BAD_SIZE]	  = -ENOMEM,
145219820Sjeff		[CMD_STAT_MULTI_FUNC_REQ] = -EACCES,
146219820Sjeff	};
147219820Sjeff
148219820Sjeff	if (status >= ARRAY_SIZE(trans_table) ||
149219820Sjeff	    (status != CMD_STAT_OK && trans_table[status] == 0))
150219820Sjeff		return -EIO;
151219820Sjeff
152219820Sjeff	return trans_table[status];
153219820Sjeff}
154219820Sjeff
155255932Salfredstatic u8 mlx4_errno_to_status(int errno)
156255932Salfred{
157255932Salfred	switch (errno) {
158255932Salfred	case -EPERM:
159255932Salfred		return CMD_STAT_BAD_OP;
160255932Salfred	case -EINVAL:
161255932Salfred		return CMD_STAT_BAD_PARAM;
162255932Salfred	case -ENXIO:
163255932Salfred		return CMD_STAT_BAD_SYS_STATE;
164255932Salfred	case -EBUSY:
165255932Salfred		return CMD_STAT_RESOURCE_BUSY;
166255932Salfred	case -ENOMEM:
167255932Salfred		return CMD_STAT_EXCEED_LIM;
168255932Salfred	case -ENFILE:
169255932Salfred		return CMD_STAT_ICM_ERROR;
170255932Salfred	default:
171255932Salfred		return CMD_STAT_INTERNAL_ERR;
172255932Salfred	}
173255932Salfred}
174255932Salfred
175255932Salfredstatic int comm_pending(struct mlx4_dev *dev)
176255932Salfred{
177255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
178255932Salfred	u32 status = readl(&priv->mfunc.comm->slave_read);
179255932Salfred
180255932Salfred	return (swab32(status) >> 31) != priv->cmd.comm_toggle;
181255932Salfred}
182255932Salfred
183255932Salfredstatic void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param)
184255932Salfred{
185255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
186255932Salfred	u32 val;
187255932Salfred
188255932Salfred	priv->cmd.comm_toggle ^= 1;
189255932Salfred	val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31);
190255932Salfred	__raw_writel((__force u32) cpu_to_be32(val),
191255932Salfred		     &priv->mfunc.comm->slave_write);
192255932Salfred	mmiowb();
193255932Salfred}
194255932Salfred
195255932Salfredstatic int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
196255932Salfred		       unsigned long timeout)
197255932Salfred{
198255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
199255932Salfred	unsigned long end;
200255932Salfred	int err = 0;
201255932Salfred	int ret_from_pending = 0;
202255932Salfred
203255932Salfred	/* First, verify that the master reports correct status */
204255932Salfred	if (comm_pending(dev)) {
205255932Salfred		mlx4_warn(dev, "Communication channel is not idle."
206255932Salfred			  "my toggle is %d (cmd:0x%x)\n",
207255932Salfred			  priv->cmd.comm_toggle, cmd);
208255932Salfred		return -EAGAIN;
209255932Salfred	}
210255932Salfred
211255932Salfred	/* Write command */
212255932Salfred	down(&priv->cmd.poll_sem);
213255932Salfred	mlx4_comm_cmd_post(dev, cmd, param);
214255932Salfred
215255932Salfred	end = msecs_to_jiffies(timeout) + jiffies;
216255932Salfred	while (comm_pending(dev) && time_before(jiffies, end))
217255932Salfred		cond_resched();
218255932Salfred	ret_from_pending = comm_pending(dev);
219255932Salfred	if (ret_from_pending) {
220255932Salfred		/* check if the slave is trying to boot in the middle of
221255932Salfred		 * FLR process. The only non-zero result in the RESET command
222255932Salfred		 * is MLX4_DELAY_RESET_SLAVE*/
223255932Salfred		if ((MLX4_COMM_CMD_RESET == cmd)) {
224255932Salfred			mlx4_warn(dev, "Got slave FLRed from Communication"
225255932Salfred				  " channel (ret:0x%x)\n", ret_from_pending);
226255932Salfred			err = MLX4_DELAY_RESET_SLAVE;
227255932Salfred		} else {
228255932Salfred			mlx4_warn(dev, "Communication channel timed out\n");
229255932Salfred			err = -ETIMEDOUT;
230255932Salfred		}
231255932Salfred	}
232255932Salfred
233255932Salfred	up(&priv->cmd.poll_sem);
234255932Salfred	return err;
235255932Salfred}
236255932Salfred
237255932Salfredstatic int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op,
238255932Salfred			      u16 param, unsigned long timeout)
239255932Salfred{
240255932Salfred	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
241255932Salfred	struct mlx4_cmd_context *context;
242255932Salfred	unsigned long end;
243255932Salfred	int err = 0;
244255932Salfred
245255932Salfred	down(&cmd->event_sem);
246255932Salfred
247255932Salfred	spin_lock(&cmd->context_lock);
248255932Salfred	BUG_ON(cmd->free_head < 0);
249255932Salfred	context = &cmd->context[cmd->free_head];
250255932Salfred	context->token += cmd->token_mask + 1;
251255932Salfred	cmd->free_head = context->next;
252255932Salfred	spin_unlock(&cmd->context_lock);
253255932Salfred
254255932Salfred	init_completion(&context->done);
255255932Salfred
256255932Salfred	mlx4_comm_cmd_post(dev, op, param);
257255932Salfred
258255932Salfred	if (!wait_for_completion_timeout(&context->done,
259255932Salfred					 msecs_to_jiffies(timeout))) {
260255932Salfred		mlx4_warn(dev, "communication channel command 0x%x timed out\n", op);
261255932Salfred		err = -EBUSY;
262255932Salfred		goto out;
263255932Salfred	}
264255932Salfred
265255932Salfred	err = context->result;
266255932Salfred	if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) {
267255932Salfred		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
268255932Salfred			 op, context->fw_status);
269255932Salfred		goto out;
270255932Salfred	}
271255932Salfred
272255932Salfredout:
273255932Salfred	/* wait for comm channel ready
274255932Salfred	 * this is necessary for prevention the race
275255932Salfred	 * when switching between event to polling mode
276255932Salfred	 */
277255932Salfred	end = msecs_to_jiffies(timeout) + jiffies;
278255932Salfred	while (comm_pending(dev) && time_before(jiffies, end))
279255932Salfred		cond_resched();
280255932Salfred
281255932Salfred	spin_lock(&cmd->context_lock);
282255932Salfred	context->next = cmd->free_head;
283255932Salfred	cmd->free_head = context - cmd->context;
284255932Salfred	spin_unlock(&cmd->context_lock);
285255932Salfred
286255932Salfred	up(&cmd->event_sem);
287255932Salfred	return err;
288255932Salfred}
289255932Salfred
290255932Salfredint mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
291255932Salfred		  unsigned long timeout)
292255932Salfred{
293255932Salfred	if (mlx4_priv(dev)->cmd.use_events)
294255932Salfred		return mlx4_comm_cmd_wait(dev, cmd, param, timeout);
295255932Salfred	return mlx4_comm_cmd_poll(dev, cmd, param, timeout);
296255932Salfred}
297255932Salfred
298219820Sjeffstatic int cmd_pending(struct mlx4_dev *dev)
299219820Sjeff{
300255932Salfred	u32 status;
301219820Sjeff
302255932Salfred	if (pci_channel_offline(dev->pdev))
303255932Salfred		return -EIO;
304255932Salfred
305255932Salfred	status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
306255932Salfred
307219820Sjeff	return (status & swab32(1 << HCR_GO_BIT)) ||
308219820Sjeff		(mlx4_priv(dev)->cmd.toggle ==
309219820Sjeff		 !!(status & swab32(1 << HCR_T_BIT)));
310219820Sjeff}
311219820Sjeff
312219820Sjeffstatic int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
313219820Sjeff			 u32 in_modifier, u8 op_modifier, u16 op, u16 token,
314219820Sjeff			 int event)
315219820Sjeff{
316219820Sjeff	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
317219820Sjeff	u32 __iomem *hcr = cmd->hcr;
318219820Sjeff	int ret = -EAGAIN;
319219820Sjeff	unsigned long end;
320219820Sjeff
321219820Sjeff	mutex_lock(&cmd->hcr_mutex);
322219820Sjeff
323255932Salfred	if (pci_channel_offline(dev->pdev)) {
324255932Salfred		/*
325255932Salfred		 * Device is going through error recovery
326255932Salfred		 * and cannot accept commands.
327255932Salfred		 */
328255932Salfred		ret = -EIO;
329255932Salfred		goto out;
330255932Salfred	}
331255932Salfred
332219820Sjeff	end = jiffies;
333219820Sjeff	if (event)
334219820Sjeff		end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
335219820Sjeff
336219820Sjeff	while (cmd_pending(dev)) {
337255932Salfred		if (pci_channel_offline(dev->pdev)) {
338255932Salfred			/*
339255932Salfred			 * Device is going through error recovery
340255932Salfred			 * and cannot accept commands.
341255932Salfred			 */
342255932Salfred			ret = -EIO;
343219820Sjeff			goto out;
344255932Salfred		}
345255932Salfred
346255932Salfred		if (time_after_eq(jiffies, end)) {
347255932Salfred			mlx4_err(dev, "%s:cmd_pending failed\n", __func__);
348255932Salfred			goto out;
349255932Salfred		}
350219820Sjeff		cond_resched();
351219820Sjeff	}
352219820Sjeff
353219820Sjeff	/*
354219820Sjeff	 * We use writel (instead of something like memcpy_toio)
355219820Sjeff	 * because writes of less than 32 bits to the HCR don't work
356219820Sjeff	 * (and some architectures such as ia64 implement memcpy_toio
357219820Sjeff	 * in terms of writeb).
358219820Sjeff	 */
359219820Sjeff	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),		  hcr + 0);
360219820Sjeff	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  hcr + 1);
361219820Sjeff	__raw_writel((__force u32) cpu_to_be32(in_modifier),		  hcr + 2);
362219820Sjeff	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),	  hcr + 3);
363219820Sjeff	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4);
364219820Sjeff	__raw_writel((__force u32) cpu_to_be32(token << 16),		  hcr + 5);
365219820Sjeff
366219820Sjeff	/* __raw_writel may not order writes. */
367219820Sjeff	wmb();
368219820Sjeff
369219820Sjeff	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)		|
370219820Sjeff					       (cmd->toggle << HCR_T_BIT)	|
371219820Sjeff					       (event ? (1 << HCR_E_BIT) : 0)	|
372219820Sjeff					       (op_modifier << HCR_OPMOD_SHIFT) |
373255932Salfred					       op), hcr + 6);
374219820Sjeff
375219820Sjeff	/*
376219820Sjeff	 * Make sure that our HCR writes don't get mixed in with
377219820Sjeff	 * writes from another CPU starting a FW command.
378219820Sjeff	 */
379219820Sjeff	mmiowb();
380219820Sjeff
381219820Sjeff	cmd->toggle = cmd->toggle ^ 1;
382219820Sjeff
383219820Sjeff	ret = 0;
384219820Sjeff
385219820Sjeffout:
386219820Sjeff	mutex_unlock(&cmd->hcr_mutex);
387219820Sjeff	return ret;
388219820Sjeff}
389219820Sjeff
390255932Salfredstatic int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
391255932Salfred			  int out_is_imm, u32 in_modifier, u8 op_modifier,
392255932Salfred			  u16 op, unsigned long timeout)
393255932Salfred{
394255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
395255932Salfred	struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr;
396255932Salfred	int ret;
397255932Salfred
398255932Salfred	mutex_lock(&priv->cmd.slave_cmd_mutex);
399255932Salfred
400255932Salfred	vhcr->in_param = cpu_to_be64(in_param);
401255932Salfred	vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0;
402255932Salfred	vhcr->in_modifier = cpu_to_be32(in_modifier);
403255932Salfred	vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff));
404255932Salfred	vhcr->token = cpu_to_be16(CMD_POLL_TOKEN);
405255932Salfred	vhcr->status = 0;
406255932Salfred	vhcr->flags = !!(priv->cmd.use_events) << 6;
407255932Salfred
408255932Salfred	if (mlx4_is_master(dev)) {
409255932Salfred		ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr);
410255932Salfred		if (!ret) {
411255932Salfred			if (out_is_imm) {
412255932Salfred				if (out_param)
413255932Salfred					*out_param =
414255932Salfred						be64_to_cpu(vhcr->out_param);
415255932Salfred				else {
416255932Salfred					mlx4_err(dev, "response expected while"
417255932Salfred						 "output mailbox is NULL for "
418255932Salfred						 "command 0x%x\n", op);
419255932Salfred					vhcr->status = CMD_STAT_BAD_PARAM;
420255932Salfred				}
421255932Salfred			}
422255932Salfred			ret = mlx4_status_to_errno(vhcr->status);
423255932Salfred		}
424255932Salfred	} else {
425255932Salfred		ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0,
426255932Salfred				    MLX4_COMM_TIME + timeout);
427255932Salfred		if (!ret) {
428255932Salfred			if (out_is_imm) {
429255932Salfred				if (out_param)
430255932Salfred					*out_param =
431255932Salfred						be64_to_cpu(vhcr->out_param);
432255932Salfred				else {
433255932Salfred					mlx4_err(dev, "response expected while"
434255932Salfred						 "output mailbox is NULL for "
435255932Salfred						 "command 0x%x\n", op);
436255932Salfred					vhcr->status = CMD_STAT_BAD_PARAM;
437255932Salfred				}
438255932Salfred			}
439255932Salfred			ret = mlx4_status_to_errno(vhcr->status);
440255932Salfred		} else
441255932Salfred			mlx4_err(dev, "failed execution of VHCR_POST command"
442255932Salfred				 "opcode 0x%x\n", op);
443255932Salfred	}
444255932Salfred
445255932Salfred	mutex_unlock(&priv->cmd.slave_cmd_mutex);
446255932Salfred	return ret;
447255932Salfred}
448255932Salfred
449219820Sjeffstatic int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
450219820Sjeff			 int out_is_imm, u32 in_modifier, u8 op_modifier,
451219820Sjeff			 u16 op, unsigned long timeout)
452219820Sjeff{
453219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
454219820Sjeff	void __iomem *hcr = priv->cmd.hcr;
455219820Sjeff	int err = 0;
456219820Sjeff	unsigned long end;
457219820Sjeff	u32 stat;
458219820Sjeff
459219820Sjeff	down(&priv->cmd.poll_sem);
460219820Sjeff
461255932Salfred	if (pci_channel_offline(dev->pdev)) {
462255932Salfred		/*
463255932Salfred		 * Device is going through error recovery
464255932Salfred		 * and cannot accept commands.
465255932Salfred		 */
466255932Salfred		err = -EIO;
467255932Salfred		goto out;
468255932Salfred	}
469255932Salfred
470219820Sjeff	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
471219820Sjeff			    in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
472219820Sjeff	if (err)
473219820Sjeff		goto out;
474219820Sjeff
475219820Sjeff	end = msecs_to_jiffies(timeout) + jiffies;
476255932Salfred	while (cmd_pending(dev) && time_before(jiffies, end)) {
477255932Salfred		if (pci_channel_offline(dev->pdev)) {
478255932Salfred			/*
479255932Salfred			 * Device is going through error recovery
480255932Salfred			 * and cannot accept commands.
481255932Salfred			 */
482255932Salfred			err = -EIO;
483255932Salfred			goto out;
484255932Salfred		}
485255932Salfred
486219820Sjeff		cond_resched();
487255932Salfred	}
488219820Sjeff
489219820Sjeff	if (cmd_pending(dev)) {
490255932Salfred		mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", op);
491219820Sjeff		err = -ETIMEDOUT;
492219820Sjeff		goto out;
493219820Sjeff	}
494219820Sjeff
495219820Sjeff	if (out_is_imm)
496219820Sjeff		*out_param =
497219820Sjeff			(u64) be32_to_cpu((__force __be32)
498219820Sjeff					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
499219820Sjeff			(u64) be32_to_cpu((__force __be32)
500219820Sjeff					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4));
501255932Salfred	stat = be32_to_cpu((__force __be32)
502255932Salfred			   __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24;
503219820Sjeff	err = mlx4_status_to_errno(stat);
504255932Salfred	if (err)
505255932Salfred		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
506255932Salfred			 op, stat);
507219820Sjeff
508219820Sjeffout:
509219820Sjeff	up(&priv->cmd.poll_sem);
510219820Sjeff	return err;
511219820Sjeff}
512219820Sjeff
513219820Sjeffvoid mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
514219820Sjeff{
515219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
516219820Sjeff	struct mlx4_cmd_context *context =
517219820Sjeff		&priv->cmd.context[token & priv->cmd.token_mask];
518219820Sjeff
519219820Sjeff	/* previously timed out command completing at long last */
520219820Sjeff	if (token != context->token)
521219820Sjeff		return;
522219820Sjeff
523219820Sjeff	context->fw_status = status;
524219820Sjeff	context->result    = mlx4_status_to_errno(status);
525219820Sjeff	context->out_param = out_param;
526219820Sjeff
527219820Sjeff	complete(&context->done);
528219820Sjeff}
529219820Sjeff
530255932Salfredstatic int get_status(struct mlx4_dev *dev, u32 *status, int *go_bit,
531255932Salfred		      int *t_bit)
532255932Salfred{
533255932Salfred	if (pci_channel_offline(dev->pdev))
534255932Salfred		return -EIO;
535255932Salfred
536255932Salfred	*status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
537255932Salfred	*t_bit = !!(*status & swab32(1 << HCR_T_BIT));
538255932Salfred	*go_bit = !!(*status & swab32(1 << HCR_GO_BIT));
539255932Salfred
540255932Salfred	return 0;
541255932Salfred}
542255932Salfred
543219820Sjeffstatic int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
544219820Sjeff			 int out_is_imm, u32 in_modifier, u8 op_modifier,
545219820Sjeff			 u16 op, unsigned long timeout)
546219820Sjeff{
547219820Sjeff	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
548219820Sjeff	struct mlx4_cmd_context *context;
549219820Sjeff	int err = 0;
550255932Salfred	int go_bit = 0, t_bit = 0, stat_err;
551255932Salfred	u32 status = 0;
552219820Sjeff
553219820Sjeff	down(&cmd->event_sem);
554219820Sjeff
555219820Sjeff	spin_lock(&cmd->context_lock);
556219820Sjeff	BUG_ON(cmd->free_head < 0);
557219820Sjeff	context = &cmd->context[cmd->free_head];
558219820Sjeff	context->token += cmd->token_mask + 1;
559219820Sjeff	cmd->free_head = context->next;
560219820Sjeff	spin_unlock(&cmd->context_lock);
561219820Sjeff
562219820Sjeff	init_completion(&context->done);
563219820Sjeff
564255932Salfred	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
565255932Salfred			    in_modifier, op_modifier, op, context->token, 1);
566255932Salfred	if (err) {
567255932Salfred		mlx4_warn(dev, "command 0x%x could not be posted (%d)\n",
568255932Salfred			  op, err);
569255932Salfred		goto out;
570255932Salfred	}
571219820Sjeff
572255932Salfred	if (!wait_for_completion_timeout(&context->done,
573255932Salfred					 msecs_to_jiffies(timeout))) {
574255932Salfred		stat_err = get_status(dev, &status, &go_bit, &t_bit);
575255932Salfred		mlx4_warn(dev, "command 0x%x timed out: "
576255932Salfred			  "get_status err=%d, status=0x%x, go_bit=%d, "
577255932Salfred			  "t_bit=%d, toggle=0x%x\n", op, stat_err, status,
578255932Salfred			  go_bit, t_bit, mlx4_priv(dev)->cmd.toggle);
579219820Sjeff		err = -EBUSY;
580219820Sjeff		goto out;
581219820Sjeff	}
582219820Sjeff
583219820Sjeff	err = context->result;
584219820Sjeff	if (err) {
585255932Salfred		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
586255932Salfred			 op, context->fw_status);
587219820Sjeff		goto out;
588219820Sjeff	}
589219820Sjeff
590219820Sjeff	if (out_is_imm)
591219820Sjeff		*out_param = context->out_param;
592219820Sjeff
593219820Sjeffout:
594219820Sjeff	spin_lock(&cmd->context_lock);
595219820Sjeff	context->next = cmd->free_head;
596219820Sjeff	cmd->free_head = context - cmd->context;
597219820Sjeff	spin_unlock(&cmd->context_lock);
598219820Sjeff
599219820Sjeff	up(&cmd->event_sem);
600219820Sjeff	return err;
601219820Sjeff}
602219820Sjeff
603219820Sjeffint __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
604219820Sjeff	       int out_is_imm, u32 in_modifier, u8 op_modifier,
605255932Salfred	       u16 op, unsigned long timeout, int native)
606219820Sjeff{
607255932Salfred	if (pci_channel_offline(dev->pdev))
608255932Salfred		return -EIO;
609255932Salfred
610255932Salfred	if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) {
611255932Salfred		if (mlx4_priv(dev)->cmd.use_events)
612255932Salfred			return mlx4_cmd_wait(dev, in_param, out_param,
613255932Salfred					     out_is_imm, in_modifier,
614255932Salfred					     op_modifier, op, timeout);
615255932Salfred		else
616255932Salfred			return mlx4_cmd_poll(dev, in_param, out_param,
617255932Salfred					     out_is_imm, in_modifier,
618255932Salfred					     op_modifier, op, timeout);
619255932Salfred	}
620255932Salfred	return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm,
621255932Salfred			      in_modifier, op_modifier, op, timeout);
622219820Sjeff}
623219820SjeffEXPORT_SYMBOL_GPL(__mlx4_cmd);
624219820Sjeff
625255932Salfred
626255932Salfredstatic int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev)
627255932Salfred{
628255932Salfred	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL,
629255932Salfred			MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
630255932Salfred}
631255932Salfred
632255932Salfredstatic int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr,
633255932Salfred			   int slave, u64 slave_addr,
634255932Salfred			   int size, int is_read)
635255932Salfred{
636255932Salfred	u64 in_param;
637255932Salfred	u64 out_param;
638255932Salfred
639255932Salfred	if ((slave_addr & 0xfff) | (master_addr & 0xfff) |
640255932Salfred	    (slave & ~0x7f) | (size & 0xff)) {
641255932Salfred		mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx "
642255932Salfred			      "master_addr:0x%llx slave_id:%d size:%d\n",
643255932Salfred			      slave_addr, master_addr, slave, size);
644255932Salfred		return -EINVAL;
645255932Salfred	}
646255932Salfred
647255932Salfred	if (is_read) {
648255932Salfred		in_param = (u64) slave | slave_addr;
649255932Salfred		out_param = (u64) dev->caps.function | master_addr;
650255932Salfred	} else {
651255932Salfred		in_param = (u64) dev->caps.function | master_addr;
652255932Salfred		out_param = (u64) slave | slave_addr;
653255932Salfred	}
654255932Salfred
655255932Salfred	return mlx4_cmd_imm(dev, in_param, &out_param, size, 0,
656255932Salfred			    MLX4_CMD_ACCESS_MEM,
657255932Salfred			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
658255932Salfred}
659255932Salfred
660255932Salfredstatic int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey,
661255932Salfred			       struct mlx4_cmd_mailbox *inbox,
662255932Salfred			       struct mlx4_cmd_mailbox *outbox)
663255932Salfred{
664255932Salfred	struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf);
665255932Salfred	struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf);
666255932Salfred	int err;
667255932Salfred	int i;
668255932Salfred
669255932Salfred	if (index & 0x1f)
670255932Salfred		return -EINVAL;
671255932Salfred
672255932Salfred	in_mad->attr_mod = cpu_to_be32(index / 32);
673255932Salfred
674255932Salfred	err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
675255932Salfred			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
676255932Salfred			   MLX4_CMD_NATIVE);
677255932Salfred	if (err)
678255932Salfred		return err;
679255932Salfred
680255932Salfred	for (i = 0; i < 32; ++i)
681255932Salfred		pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]);
682255932Salfred
683255932Salfred	return err;
684255932Salfred}
685255932Salfred
686255932Salfredstatic int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table,
687255932Salfred			       struct mlx4_cmd_mailbox *inbox,
688255932Salfred			       struct mlx4_cmd_mailbox *outbox)
689255932Salfred{
690255932Salfred	int i;
691255932Salfred	int err;
692255932Salfred
693255932Salfred	for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) {
694255932Salfred		err = query_pkey_block(dev, port, i, table + i, inbox, outbox);
695255932Salfred		if (err)
696255932Salfred			return err;
697255932Salfred	}
698255932Salfred
699255932Salfred	return 0;
700255932Salfred}
701255932Salfred#define PORT_CAPABILITY_LOCATION_IN_SMP 20
702255932Salfred#define PORT_STATE_OFFSET 32
703255932Salfred
704255932Salfredstatic enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf)
705255932Salfred{
706255932Salfred	if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP)
707255932Salfred		return IB_PORT_ACTIVE;
708255932Salfred	else
709255932Salfred		return IB_PORT_DOWN;
710255932Salfred}
711255932Salfred
712255932Salfredstatic int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
713255932Salfred				struct mlx4_vhcr *vhcr,
714255932Salfred				struct mlx4_cmd_mailbox *inbox,
715255932Salfred				struct mlx4_cmd_mailbox *outbox,
716255932Salfred				struct mlx4_cmd_info *cmd)
717255932Salfred{
718255932Salfred	struct ib_smp *smp = inbox->buf;
719255932Salfred	u32 index;
720255932Salfred	u8 port;
721255932Salfred	u16 *table;
722255932Salfred	int err;
723255932Salfred	int vidx, pidx;
724255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
725255932Salfred	struct ib_smp *outsmp = outbox->buf;
726255932Salfred	__be16 *outtab = (__be16 *)(outsmp->data);
727255932Salfred	__be32 slave_cap_mask;
728255932Salfred	__be64 slave_node_guid;
729255932Salfred	port = vhcr->in_modifier;
730255932Salfred
731255932Salfred	if (smp->base_version == 1 &&
732255932Salfred	    smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
733255932Salfred	    smp->class_version == 1) {
734255932Salfred		if (smp->method	== IB_MGMT_METHOD_GET) {
735255932Salfred			if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) {
736255932Salfred				index = be32_to_cpu(smp->attr_mod);
737255932Salfred				if (port < 1 || port > dev->caps.num_ports)
738255932Salfred					return -EINVAL;
739255932Salfred				table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL);
740255932Salfred				if (!table)
741255932Salfred					return -ENOMEM;
742255932Salfred				/* need to get the full pkey table because the paravirtualized
743255932Salfred				 * pkeys may be scattered among several pkey blocks.
744255932Salfred				 */
745255932Salfred				err = get_full_pkey_table(dev, port, table, inbox, outbox);
746255932Salfred				if (!err) {
747255932Salfred					for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) {
748255932Salfred						pidx = priv->virt2phys_pkey[slave][port - 1][vidx];
749255932Salfred						outtab[vidx % 32] = cpu_to_be16(table[pidx]);
750255932Salfred					}
751255932Salfred				}
752255932Salfred				kfree(table);
753255932Salfred				return err;
754255932Salfred			}
755255932Salfred			if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) {
756255932Salfred				/*get the slave specific caps:*/
757255932Salfred				/*do the command */
758255932Salfred				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
759255932Salfred					    vhcr->in_modifier, vhcr->op_modifier,
760255932Salfred					    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
761255932Salfred				/* modify the response for slaves */
762255932Salfred				if (!err && slave != mlx4_master_func_num(dev)) {
763255932Salfred					u8 *state = outsmp->data + PORT_STATE_OFFSET;
764255932Salfred
765255932Salfred					*state = (*state & 0xf0) | vf_port_state(dev, port, slave);
766255932Salfred					slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
767255932Salfred					memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4);
768255932Salfred				}
769255932Salfred				return err;
770255932Salfred			}
771255932Salfred			if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) {
772255932Salfred				/* compute slave's gid block */
773255932Salfred				smp->attr_mod = cpu_to_be32(slave / 8);
774255932Salfred				/* execute cmd */
775255932Salfred				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
776255932Salfred					     vhcr->in_modifier, vhcr->op_modifier,
777255932Salfred					     vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
778255932Salfred				if (!err) {
779255932Salfred					/* if needed, move slave gid to index 0 */
780255932Salfred					if (slave % 8)
781255932Salfred						memcpy(outsmp->data,
782255932Salfred						       outsmp->data + (slave % 8) * 8, 8);
783255932Salfred					/* delete all other gids */
784255932Salfred					memset(outsmp->data + 8, 0, 56);
785255932Salfred				}
786255932Salfred				return err;
787255932Salfred			}
788255932Salfred			if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) {
789255932Salfred				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
790255932Salfred					     vhcr->in_modifier, vhcr->op_modifier,
791255932Salfred					     vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
792255932Salfred				if (!err) {
793255932Salfred					slave_node_guid =  mlx4_get_slave_node_guid(dev, slave);
794255932Salfred					memcpy(outsmp->data + 12, &slave_node_guid, 8);
795255932Salfred				}
796255932Salfred				return err;
797255932Salfred			}
798255932Salfred		}
799255932Salfred	}
800255932Salfred	if (slave != mlx4_master_func_num(dev) &&
801255932Salfred	    ((smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) ||
802255932Salfred	     (smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
803255932Salfred	      smp->method == IB_MGMT_METHOD_SET))) {
804255932Salfred		mlx4_err(dev, "slave %d is trying to execute a Subnet MGMT MAD, "
805255932Salfred			 "class 0x%x, method 0x%x for attr 0x%x. Rejecting\n",
806255932Salfred			 slave, smp->method, smp->mgmt_class,
807255932Salfred			 be16_to_cpu(smp->attr_id));
808255932Salfred		return -EPERM;
809255932Salfred	}
810255932Salfred	/*default:*/
811255932Salfred	return mlx4_cmd_box(dev, inbox->dma, outbox->dma,
812255932Salfred				    vhcr->in_modifier, vhcr->op_modifier,
813255932Salfred				    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
814255932Salfred}
815255932Salfred
816255932Salfredint mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
817255932Salfred		     struct mlx4_vhcr *vhcr,
818255932Salfred		     struct mlx4_cmd_mailbox *inbox,
819255932Salfred		     struct mlx4_cmd_mailbox *outbox,
820255932Salfred		     struct mlx4_cmd_info *cmd)
821255932Salfred{
822255932Salfred	u64 in_param;
823255932Salfred	u64 out_param;
824255932Salfred	int err;
825255932Salfred
826255932Salfred	in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param;
827255932Salfred	out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param;
828255932Salfred	if (cmd->encode_slave_id) {
829255932Salfred		in_param &= 0xffffffffffffff00ll;
830255932Salfred		in_param |= slave;
831255932Salfred	}
832255932Salfred
833255932Salfred	err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm,
834255932Salfred			 vhcr->in_modifier, vhcr->op_modifier, vhcr->op,
835255932Salfred			 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
836255932Salfred
837255932Salfred	if (cmd->out_is_imm)
838255932Salfred		vhcr->out_param = out_param;
839255932Salfred
840255932Salfred	return err;
841255932Salfred}
842255932Salfred
843255932Salfredstatic struct mlx4_cmd_info cmd_info[] = {
844255932Salfred	{
845255932Salfred		.opcode = MLX4_CMD_QUERY_FW,
846255932Salfred		.has_inbox = false,
847255932Salfred		.has_outbox = true,
848255932Salfred		.out_is_imm = false,
849255932Salfred		.encode_slave_id = false,
850255932Salfred		.verify = NULL,
851255932Salfred		.wrapper = mlx4_QUERY_FW_wrapper
852255932Salfred	},
853255932Salfred	{
854255932Salfred		.opcode = MLX4_CMD_QUERY_HCA,
855255932Salfred		.has_inbox = false,
856255932Salfred		.has_outbox = true,
857255932Salfred		.out_is_imm = false,
858255932Salfred		.encode_slave_id = false,
859255932Salfred		.verify = NULL,
860255932Salfred		.wrapper = NULL
861255932Salfred	},
862255932Salfred	{
863255932Salfred		.opcode = MLX4_CMD_QUERY_DEV_CAP,
864255932Salfred		.has_inbox = false,
865255932Salfred		.has_outbox = true,
866255932Salfred		.out_is_imm = false,
867255932Salfred		.encode_slave_id = false,
868255932Salfred		.verify = NULL,
869255932Salfred		.wrapper = mlx4_QUERY_DEV_CAP_wrapper
870255932Salfred	},
871255932Salfred	{
872255932Salfred		.opcode = MLX4_CMD_QUERY_FUNC_CAP,
873255932Salfred		.has_inbox = false,
874255932Salfred		.has_outbox = true,
875255932Salfred		.out_is_imm = false,
876255932Salfred		.encode_slave_id = false,
877255932Salfred		.verify = NULL,
878255932Salfred		.wrapper = mlx4_QUERY_FUNC_CAP_wrapper
879255932Salfred	},
880255932Salfred	{
881255932Salfred		.opcode = MLX4_CMD_QUERY_ADAPTER,
882255932Salfred		.has_inbox = false,
883255932Salfred		.has_outbox = true,
884255932Salfred		.out_is_imm = false,
885255932Salfred		.encode_slave_id = false,
886255932Salfred		.verify = NULL,
887255932Salfred		.wrapper = NULL
888255932Salfred	},
889255932Salfred	{
890255932Salfred		.opcode = MLX4_CMD_INIT_PORT,
891255932Salfred		.has_inbox = false,
892255932Salfred		.has_outbox = false,
893255932Salfred		.out_is_imm = false,
894255932Salfred		.encode_slave_id = false,
895255932Salfred		.verify = NULL,
896255932Salfred		.wrapper = mlx4_INIT_PORT_wrapper
897255932Salfred	},
898255932Salfred	{
899255932Salfred		.opcode = MLX4_CMD_CLOSE_PORT,
900255932Salfred		.has_inbox = false,
901255932Salfred		.has_outbox = false,
902255932Salfred		.out_is_imm  = false,
903255932Salfred		.encode_slave_id = false,
904255932Salfred		.verify = NULL,
905255932Salfred		.wrapper = mlx4_CLOSE_PORT_wrapper
906255932Salfred	},
907255932Salfred	{
908255932Salfred		.opcode = MLX4_CMD_QUERY_PORT,
909255932Salfred		.has_inbox = false,
910255932Salfred		.has_outbox = true,
911255932Salfred		.out_is_imm = false,
912255932Salfred		.encode_slave_id = false,
913255932Salfred		.verify = NULL,
914255932Salfred		.wrapper = mlx4_QUERY_PORT_wrapper
915255932Salfred	},
916255932Salfred	{
917255932Salfred		.opcode = MLX4_CMD_SET_PORT,
918255932Salfred		.has_inbox = true,
919255932Salfred		.has_outbox = false,
920255932Salfred		.out_is_imm = false,
921255932Salfred		.encode_slave_id = false,
922255932Salfred		.verify = NULL,
923255932Salfred		.wrapper = mlx4_SET_PORT_wrapper
924255932Salfred	},
925255932Salfred	{
926255932Salfred		.opcode = MLX4_CMD_MAP_EQ,
927255932Salfred		.has_inbox = false,
928255932Salfred		.has_outbox = false,
929255932Salfred		.out_is_imm = false,
930255932Salfred		.encode_slave_id = false,
931255932Salfred		.verify = NULL,
932255932Salfred		.wrapper = mlx4_MAP_EQ_wrapper
933255932Salfred	},
934255932Salfred	{
935255932Salfred		.opcode = MLX4_CMD_SW2HW_EQ,
936255932Salfred		.has_inbox = true,
937255932Salfred		.has_outbox = false,
938255932Salfred		.out_is_imm = false,
939255932Salfred		.encode_slave_id = true,
940255932Salfred		.verify = NULL,
941255932Salfred		.wrapper = mlx4_SW2HW_EQ_wrapper
942255932Salfred	},
943255932Salfred	{
944255932Salfred		.opcode = MLX4_CMD_HW_HEALTH_CHECK,
945255932Salfred		.has_inbox = false,
946255932Salfred		.has_outbox = false,
947255932Salfred		.out_is_imm = false,
948255932Salfred		.encode_slave_id = false,
949255932Salfred		.verify = NULL,
950255932Salfred		.wrapper = NULL
951255932Salfred	},
952255932Salfred	{
953255932Salfred		.opcode = MLX4_CMD_NOP,
954255932Salfred		.has_inbox = false,
955255932Salfred		.has_outbox = false,
956255932Salfred		.out_is_imm = false,
957255932Salfred		.encode_slave_id = false,
958255932Salfred		.verify = NULL,
959255932Salfred		.wrapper = NULL
960255932Salfred	},
961255932Salfred	{
962255932Salfred		.opcode = MLX4_CMD_ALLOC_RES,
963255932Salfred		.has_inbox = false,
964255932Salfred		.has_outbox = false,
965255932Salfred		.out_is_imm = true,
966255932Salfred		.encode_slave_id = false,
967255932Salfred		.verify = NULL,
968255932Salfred		.wrapper = mlx4_ALLOC_RES_wrapper
969255932Salfred	},
970255932Salfred	{
971255932Salfred		.opcode = MLX4_CMD_FREE_RES,
972255932Salfred		.has_inbox = false,
973255932Salfred		.has_outbox = false,
974255932Salfred		.out_is_imm = false,
975255932Salfred		.encode_slave_id = false,
976255932Salfred		.verify = NULL,
977255932Salfred		.wrapper = mlx4_FREE_RES_wrapper
978255932Salfred	},
979255932Salfred	{
980255932Salfred		.opcode = MLX4_CMD_SW2HW_MPT,
981255932Salfred		.has_inbox = true,
982255932Salfred		.has_outbox = false,
983255932Salfred		.out_is_imm = false,
984255932Salfred		.encode_slave_id = true,
985255932Salfred		.verify = NULL,
986255932Salfred		.wrapper = mlx4_SW2HW_MPT_wrapper
987255932Salfred	},
988255932Salfred	{
989255932Salfred		.opcode = MLX4_CMD_QUERY_MPT,
990255932Salfred		.has_inbox = false,
991255932Salfred		.has_outbox = true,
992255932Salfred		.out_is_imm = false,
993255932Salfred		.encode_slave_id = false,
994255932Salfred		.verify = NULL,
995255932Salfred		.wrapper = mlx4_QUERY_MPT_wrapper
996255932Salfred	},
997255932Salfred	{
998255932Salfred		.opcode = MLX4_CMD_HW2SW_MPT,
999255932Salfred		.has_inbox = false,
1000255932Salfred		.has_outbox = false,
1001255932Salfred		.out_is_imm = false,
1002255932Salfred		.encode_slave_id = false,
1003255932Salfred		.verify = NULL,
1004255932Salfred		.wrapper = mlx4_HW2SW_MPT_wrapper
1005255932Salfred	},
1006255932Salfred	{
1007255932Salfred		.opcode = MLX4_CMD_READ_MTT,
1008255932Salfred		.has_inbox = false,
1009255932Salfred		.has_outbox = true,
1010255932Salfred		.out_is_imm = false,
1011255932Salfred		.encode_slave_id = false,
1012255932Salfred		.verify = NULL,
1013255932Salfred		.wrapper = NULL
1014255932Salfred	},
1015255932Salfred	{
1016255932Salfred		.opcode = MLX4_CMD_WRITE_MTT,
1017255932Salfred		.has_inbox = true,
1018255932Salfred		.has_outbox = false,
1019255932Salfred		.out_is_imm = false,
1020255932Salfred		.encode_slave_id = false,
1021255932Salfred		.verify = NULL,
1022255932Salfred		.wrapper = mlx4_WRITE_MTT_wrapper
1023255932Salfred	},
1024255932Salfred	{
1025255932Salfred		.opcode = MLX4_CMD_SYNC_TPT,
1026255932Salfred		.has_inbox = true,
1027255932Salfred		.has_outbox = false,
1028255932Salfred		.out_is_imm = false,
1029255932Salfred		.encode_slave_id = false,
1030255932Salfred		.verify = NULL,
1031255932Salfred		.wrapper = NULL
1032255932Salfred	},
1033255932Salfred	{
1034255932Salfred		.opcode = MLX4_CMD_HW2SW_EQ,
1035255932Salfred		.has_inbox = false,
1036255932Salfred		.has_outbox = true,
1037255932Salfred		.out_is_imm = false,
1038255932Salfred		.encode_slave_id = true,
1039255932Salfred		.verify = NULL,
1040255932Salfred		.wrapper = mlx4_HW2SW_EQ_wrapper
1041255932Salfred	},
1042255932Salfred	{
1043255932Salfred		.opcode = MLX4_CMD_QUERY_EQ,
1044255932Salfred		.has_inbox = false,
1045255932Salfred		.has_outbox = true,
1046255932Salfred		.out_is_imm = false,
1047255932Salfred		.encode_slave_id = true,
1048255932Salfred		.verify = NULL,
1049255932Salfred		.wrapper = mlx4_QUERY_EQ_wrapper
1050255932Salfred	},
1051255932Salfred	{
1052255932Salfred		.opcode = MLX4_CMD_SW2HW_CQ,
1053255932Salfred		.has_inbox = true,
1054255932Salfred		.has_outbox = false,
1055255932Salfred		.out_is_imm = false,
1056255932Salfred		.encode_slave_id = true,
1057255932Salfred		.verify = NULL,
1058255932Salfred		.wrapper = mlx4_SW2HW_CQ_wrapper
1059255932Salfred	},
1060255932Salfred	{
1061255932Salfred		.opcode = MLX4_CMD_HW2SW_CQ,
1062255932Salfred		.has_inbox = false,
1063255932Salfred		.has_outbox = false,
1064255932Salfred		.out_is_imm = false,
1065255932Salfred		.encode_slave_id = false,
1066255932Salfred		.verify = NULL,
1067255932Salfred		.wrapper = mlx4_HW2SW_CQ_wrapper
1068255932Salfred	},
1069255932Salfred	{
1070255932Salfred		.opcode = MLX4_CMD_QUERY_CQ,
1071255932Salfred		.has_inbox = false,
1072255932Salfred		.has_outbox = true,
1073255932Salfred		.out_is_imm = false,
1074255932Salfred		.encode_slave_id = false,
1075255932Salfred		.verify = NULL,
1076255932Salfred		.wrapper = mlx4_QUERY_CQ_wrapper
1077255932Salfred	},
1078255932Salfred	{
1079255932Salfred		.opcode = MLX4_CMD_MODIFY_CQ,
1080255932Salfred		.has_inbox = true,
1081255932Salfred		.has_outbox = false,
1082255932Salfred		.out_is_imm = true,
1083255932Salfred		.encode_slave_id = false,
1084255932Salfred		.verify = NULL,
1085255932Salfred		.wrapper = mlx4_MODIFY_CQ_wrapper
1086255932Salfred	},
1087255932Salfred	{
1088255932Salfred		.opcode = MLX4_CMD_SW2HW_SRQ,
1089255932Salfred		.has_inbox = true,
1090255932Salfred		.has_outbox = false,
1091255932Salfred		.out_is_imm = false,
1092255932Salfred		.encode_slave_id = true,
1093255932Salfred		.verify = NULL,
1094255932Salfred		.wrapper = mlx4_SW2HW_SRQ_wrapper
1095255932Salfred	},
1096255932Salfred	{
1097255932Salfred		.opcode = MLX4_CMD_HW2SW_SRQ,
1098255932Salfred		.has_inbox = false,
1099255932Salfred		.has_outbox = false,
1100255932Salfred		.out_is_imm = false,
1101255932Salfred		.encode_slave_id = false,
1102255932Salfred		.verify = NULL,
1103255932Salfred		.wrapper = mlx4_HW2SW_SRQ_wrapper
1104255932Salfred	},
1105255932Salfred	{
1106255932Salfred		.opcode = MLX4_CMD_QUERY_SRQ,
1107255932Salfred		.has_inbox = false,
1108255932Salfred		.has_outbox = true,
1109255932Salfred		.out_is_imm = false,
1110255932Salfred		.encode_slave_id = false,
1111255932Salfred		.verify = NULL,
1112255932Salfred		.wrapper = mlx4_QUERY_SRQ_wrapper
1113255932Salfred	},
1114255932Salfred	{
1115255932Salfred		.opcode = MLX4_CMD_ARM_SRQ,
1116255932Salfred		.has_inbox = false,
1117255932Salfred		.has_outbox = false,
1118255932Salfred		.out_is_imm = false,
1119255932Salfred		.encode_slave_id = false,
1120255932Salfred		.verify = NULL,
1121255932Salfred		.wrapper = mlx4_ARM_SRQ_wrapper
1122255932Salfred	},
1123255932Salfred	{
1124255932Salfred		.opcode = MLX4_CMD_RST2INIT_QP,
1125255932Salfred		.has_inbox = true,
1126255932Salfred		.has_outbox = false,
1127255932Salfred		.out_is_imm = false,
1128255932Salfred		.encode_slave_id = true,
1129255932Salfred		.verify = NULL,
1130255932Salfred		.wrapper = mlx4_RST2INIT_QP_wrapper
1131255932Salfred	},
1132255932Salfred	{
1133255932Salfred		.opcode = MLX4_CMD_INIT2INIT_QP,
1134255932Salfred		.has_inbox = true,
1135255932Salfred		.has_outbox = false,
1136255932Salfred		.out_is_imm = false,
1137255932Salfred		.encode_slave_id = false,
1138255932Salfred		.verify = NULL,
1139255932Salfred		.wrapper = mlx4_INIT2INIT_QP_wrapper
1140255932Salfred	},
1141255932Salfred	{
1142255932Salfred		.opcode = MLX4_CMD_INIT2RTR_QP,
1143255932Salfred		.has_inbox = true,
1144255932Salfred		.has_outbox = false,
1145255932Salfred		.out_is_imm = false,
1146255932Salfred		.encode_slave_id = false,
1147255932Salfred		.verify = NULL,
1148255932Salfred		.wrapper = mlx4_INIT2RTR_QP_wrapper
1149255932Salfred	},
1150255932Salfred	{
1151255932Salfred		.opcode = MLX4_CMD_RTR2RTS_QP,
1152255932Salfred		.has_inbox = true,
1153255932Salfred		.has_outbox = false,
1154255932Salfred		.out_is_imm = false,
1155255932Salfred		.encode_slave_id = false,
1156255932Salfred		.verify = NULL,
1157255932Salfred		.wrapper = mlx4_RTR2RTS_QP_wrapper
1158255932Salfred	},
1159255932Salfred	{
1160255932Salfred		.opcode = MLX4_CMD_RTS2RTS_QP,
1161255932Salfred		.has_inbox = true,
1162255932Salfred		.has_outbox = false,
1163255932Salfred		.out_is_imm = false,
1164255932Salfred		.encode_slave_id = false,
1165255932Salfred		.verify = NULL,
1166255932Salfred		.wrapper = mlx4_RTS2RTS_QP_wrapper
1167255932Salfred	},
1168255932Salfred	{
1169255932Salfred		.opcode = MLX4_CMD_SQERR2RTS_QP,
1170255932Salfred		.has_inbox = true,
1171255932Salfred		.has_outbox = false,
1172255932Salfred		.out_is_imm = false,
1173255932Salfred		.encode_slave_id = false,
1174255932Salfred		.verify = NULL,
1175255932Salfred		.wrapper = mlx4_SQERR2RTS_QP_wrapper
1176255932Salfred	},
1177255932Salfred	{
1178255932Salfred		.opcode = MLX4_CMD_2ERR_QP,
1179255932Salfred		.has_inbox = false,
1180255932Salfred		.has_outbox = false,
1181255932Salfred		.out_is_imm = false,
1182255932Salfred		.encode_slave_id = false,
1183255932Salfred		.verify = NULL,
1184255932Salfred		.wrapper = mlx4_GEN_QP_wrapper
1185255932Salfred	},
1186255932Salfred	{
1187255932Salfred		.opcode = MLX4_CMD_RTS2SQD_QP,
1188255932Salfred		.has_inbox = false,
1189255932Salfred		.has_outbox = false,
1190255932Salfred		.out_is_imm = false,
1191255932Salfred		.encode_slave_id = false,
1192255932Salfred		.verify = NULL,
1193255932Salfred		.wrapper = mlx4_GEN_QP_wrapper
1194255932Salfred	},
1195255932Salfred	{
1196255932Salfred		.opcode = MLX4_CMD_SQD2SQD_QP,
1197255932Salfred		.has_inbox = true,
1198255932Salfred		.has_outbox = false,
1199255932Salfred		.out_is_imm = false,
1200255932Salfred		.encode_slave_id = false,
1201255932Salfred		.verify = NULL,
1202255932Salfred		.wrapper = mlx4_SQD2SQD_QP_wrapper
1203255932Salfred	},
1204255932Salfred	{
1205255932Salfred		.opcode = MLX4_CMD_SQD2RTS_QP,
1206255932Salfred		.has_inbox = true,
1207255932Salfred		.has_outbox = false,
1208255932Salfred		.out_is_imm = false,
1209255932Salfred		.encode_slave_id = false,
1210255932Salfred		.verify = NULL,
1211255932Salfred		.wrapper = mlx4_SQD2RTS_QP_wrapper
1212255932Salfred	},
1213255932Salfred	{
1214255932Salfred		.opcode = MLX4_CMD_2RST_QP,
1215255932Salfred		.has_inbox = false,
1216255932Salfred		.has_outbox = false,
1217255932Salfred		.out_is_imm = false,
1218255932Salfred		.encode_slave_id = false,
1219255932Salfred		.verify = NULL,
1220255932Salfred		.wrapper = mlx4_2RST_QP_wrapper
1221255932Salfred	},
1222255932Salfred	{
1223255932Salfred		.opcode = MLX4_CMD_QUERY_QP,
1224255932Salfred		.has_inbox = false,
1225255932Salfred		.has_outbox = true,
1226255932Salfred		.out_is_imm = false,
1227255932Salfred		.encode_slave_id = false,
1228255932Salfred		.verify = NULL,
1229255932Salfred		.wrapper = mlx4_GEN_QP_wrapper
1230255932Salfred	},
1231255932Salfred	{
1232255932Salfred		.opcode = MLX4_CMD_SUSPEND_QP,
1233255932Salfred		.has_inbox = false,
1234255932Salfred		.has_outbox = false,
1235255932Salfred		.out_is_imm = false,
1236255932Salfred		.encode_slave_id = false,
1237255932Salfred		.verify = NULL,
1238255932Salfred		.wrapper = mlx4_GEN_QP_wrapper
1239255932Salfred	},
1240255932Salfred	{
1241255932Salfred		.opcode = MLX4_CMD_UNSUSPEND_QP,
1242255932Salfred		.has_inbox = false,
1243255932Salfred		.has_outbox = false,
1244255932Salfred		.out_is_imm = false,
1245255932Salfred		.encode_slave_id = false,
1246255932Salfred		.verify = NULL,
1247255932Salfred		.wrapper = mlx4_GEN_QP_wrapper
1248255932Salfred	},
1249255932Salfred	{
1250255932Salfred		.opcode = MLX4_CMD_CONF_SPECIAL_QP,
1251255932Salfred		.has_inbox = false,
1252255932Salfred		.has_outbox = false,
1253255932Salfred		.out_is_imm = false,
1254255932Salfred		.encode_slave_id = false,
1255255932Salfred		.verify = NULL, /* XXX verify: only demux can do this */
1256255932Salfred		.wrapper = NULL
1257255932Salfred	},
1258255932Salfred	{
1259255932Salfred		.opcode = MLX4_CMD_MAD_IFC,
1260255932Salfred		.has_inbox = true,
1261255932Salfred		.has_outbox = true,
1262255932Salfred		.out_is_imm = false,
1263255932Salfred		.encode_slave_id = false,
1264255932Salfred		.verify = NULL,
1265255932Salfred		.wrapper = mlx4_MAD_IFC_wrapper
1266255932Salfred	},
1267255932Salfred	{
1268255932Salfred		.opcode = MLX4_CMD_QUERY_IF_STAT,
1269255932Salfred		.has_inbox = false,
1270255932Salfred		.has_outbox = true,
1271255932Salfred		.out_is_imm = false,
1272255932Salfred		.encode_slave_id = false,
1273255932Salfred		.verify = NULL,
1274255932Salfred		.wrapper = mlx4_QUERY_IF_STAT_wrapper
1275255932Salfred	},
1276255932Salfred	/* Native multicast commands are not available for guests */
1277255932Salfred	{
1278255932Salfred		.opcode = MLX4_CMD_QP_ATTACH,
1279255932Salfred		.has_inbox = true,
1280255932Salfred		.has_outbox = false,
1281255932Salfred		.out_is_imm = false,
1282255932Salfred		.encode_slave_id = false,
1283255932Salfred		.verify = NULL,
1284255932Salfred		.wrapper = mlx4_QP_ATTACH_wrapper
1285255932Salfred	},
1286255932Salfred	{
1287255932Salfred		.opcode = MLX4_CMD_PROMISC,
1288255932Salfred		.has_inbox = false,
1289255932Salfred		.has_outbox = false,
1290255932Salfred		.out_is_imm = false,
1291255932Salfred		.encode_slave_id = false,
1292255932Salfred		.verify = NULL,
1293255932Salfred		.wrapper = mlx4_PROMISC_wrapper
1294255932Salfred	},
1295255932Salfred	/* Ethernet specific commands */
1296255932Salfred	{
1297255932Salfred		.opcode = MLX4_CMD_SET_VLAN_FLTR,
1298255932Salfred		.has_inbox = true,
1299255932Salfred		.has_outbox = false,
1300255932Salfred		.out_is_imm = false,
1301255932Salfred		.encode_slave_id = false,
1302255932Salfred		.verify = NULL,
1303255932Salfred		.wrapper = mlx4_SET_VLAN_FLTR_wrapper
1304255932Salfred	},
1305255932Salfred	{
1306255932Salfred		.opcode = MLX4_CMD_SET_MCAST_FLTR,
1307255932Salfred		.has_inbox = false,
1308255932Salfred		.has_outbox = false,
1309255932Salfred		.out_is_imm = false,
1310255932Salfred		.encode_slave_id = false,
1311255932Salfred		.verify = NULL,
1312255932Salfred		.wrapper = mlx4_SET_MCAST_FLTR_wrapper
1313255932Salfred	},
1314255932Salfred	{
1315255932Salfred		.opcode = MLX4_CMD_DUMP_ETH_STATS,
1316255932Salfred		.has_inbox = false,
1317255932Salfred		.has_outbox = true,
1318255932Salfred		.out_is_imm = false,
1319255932Salfred		.encode_slave_id = false,
1320255932Salfred		.verify = NULL,
1321255932Salfred		.wrapper = mlx4_DUMP_ETH_STATS_wrapper
1322255932Salfred	},
1323255932Salfred	{
1324255932Salfred		.opcode = MLX4_CMD_INFORM_FLR_DONE,
1325255932Salfred		.has_inbox = false,
1326255932Salfred		.has_outbox = false,
1327255932Salfred		.out_is_imm = false,
1328255932Salfred		.encode_slave_id = false,
1329255932Salfred		.verify = NULL,
1330255932Salfred		.wrapper = NULL
1331255932Salfred	},
1332255932Salfred	/* flow steering commands */
1333255932Salfred	{
1334255932Salfred		.opcode = MLX4_QP_FLOW_STEERING_ATTACH,
1335255932Salfred		.has_inbox = true,
1336255932Salfred		.has_outbox = false,
1337255932Salfred		.out_is_imm = true,
1338255932Salfred		.encode_slave_id = false,
1339255932Salfred		.verify = NULL,
1340255932Salfred		.wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper
1341255932Salfred	},
1342255932Salfred	{
1343255932Salfred		.opcode = MLX4_QP_FLOW_STEERING_DETACH,
1344255932Salfred		.has_inbox = false,
1345255932Salfred		.has_outbox = false,
1346255932Salfred		.out_is_imm = false,
1347255932Salfred		.encode_slave_id = false,
1348255932Salfred		.verify = NULL,
1349255932Salfred		.wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper
1350255932Salfred	},
1351255932Salfred};
1352255932Salfred
1353255932Salfredstatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
1354255932Salfred				    struct mlx4_vhcr_cmd *in_vhcr)
1355255932Salfred{
1356255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1357255932Salfred	struct mlx4_cmd_info *cmd = NULL;
1358255932Salfred	struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr;
1359255932Salfred	struct mlx4_vhcr *vhcr;
1360255932Salfred	struct mlx4_cmd_mailbox *inbox = NULL;
1361255932Salfred	struct mlx4_cmd_mailbox *outbox = NULL;
1362255932Salfred	u64 in_param;
1363255932Salfred	u64 out_param;
1364255932Salfred	int ret = 0;
1365255932Salfred	int i;
1366255932Salfred	int err = 0;
1367255932Salfred
1368255932Salfred	/* Create sw representation of Virtual HCR */
1369255932Salfred	vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL);
1370255932Salfred	if (!vhcr)
1371255932Salfred		return -ENOMEM;
1372255932Salfred
1373255932Salfred	/* DMA in the vHCR */
1374255932Salfred	if (!in_vhcr) {
1375255932Salfred		ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
1376255932Salfred				      priv->mfunc.master.slave_state[slave].vhcr_dma,
1377255932Salfred				      ALIGN(sizeof(struct mlx4_vhcr_cmd),
1378255932Salfred					    MLX4_ACCESS_MEM_ALIGN), 1);
1379255932Salfred		if (ret) {
1380255932Salfred			mlx4_err(dev, "%s:Failed reading vhcr"
1381255932Salfred				 "ret: 0x%x\n", __func__, ret);
1382255932Salfred			kfree(vhcr);
1383255932Salfred			return ret;
1384255932Salfred		}
1385255932Salfred	}
1386255932Salfred
1387255932Salfred	/* Fill SW VHCR fields */
1388255932Salfred	vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param);
1389255932Salfred	vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param);
1390255932Salfred	vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier);
1391255932Salfred	vhcr->token = be16_to_cpu(vhcr_cmd->token);
1392255932Salfred	vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff;
1393255932Salfred	vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12);
1394255932Salfred	vhcr->e_bit = vhcr_cmd->flags & (1 << 6);
1395255932Salfred
1396255932Salfred	/* Lookup command */
1397255932Salfred	for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) {
1398255932Salfred		if (vhcr->op == cmd_info[i].opcode) {
1399255932Salfred			cmd = &cmd_info[i];
1400255932Salfred			break;
1401255932Salfred		}
1402255932Salfred	}
1403255932Salfred	if (!cmd) {
1404255932Salfred		mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n",
1405255932Salfred			 vhcr->op, slave);
1406255932Salfred		vhcr_cmd->status = CMD_STAT_BAD_PARAM;
1407255932Salfred		goto out_status;
1408255932Salfred	}
1409255932Salfred
1410255932Salfred	/* Read inbox */
1411255932Salfred	if (cmd->has_inbox) {
1412255932Salfred		vhcr->in_param &= INBOX_MASK;
1413255932Salfred		inbox = mlx4_alloc_cmd_mailbox(dev);
1414255932Salfred		if (IS_ERR(inbox)) {
1415255932Salfred			vhcr_cmd->status = CMD_STAT_BAD_SIZE;
1416255932Salfred			inbox = NULL;
1417255932Salfred			goto out_status;
1418255932Salfred		}
1419255932Salfred
1420255932Salfred		if (mlx4_ACCESS_MEM(dev, inbox->dma, slave,
1421255932Salfred				    vhcr->in_param,
1422255932Salfred				    MLX4_MAILBOX_SIZE, 1)) {
1423255932Salfred			mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n",
1424255932Salfred				 __func__, cmd->opcode);
1425255932Salfred			vhcr_cmd->status = CMD_STAT_INTERNAL_ERR;
1426255932Salfred			goto out_status;
1427255932Salfred		}
1428255932Salfred	}
1429255932Salfred
1430255932Salfred	/* Apply permission and bound checks if applicable */
1431255932Salfred	if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) {
1432255932Salfred		mlx4_warn(dev, "Command:0x%x from slave: %d failed protection "
1433255932Salfred			  "checks for resource_id:%d\n", vhcr->op, slave,
1434255932Salfred			  vhcr->in_modifier);
1435255932Salfred		vhcr_cmd->status = CMD_STAT_BAD_OP;
1436255932Salfred		goto out_status;
1437255932Salfred	}
1438255932Salfred
1439255932Salfred	/* Allocate outbox */
1440255932Salfred	if (cmd->has_outbox) {
1441255932Salfred		outbox = mlx4_alloc_cmd_mailbox(dev);
1442255932Salfred		if (IS_ERR(outbox)) {
1443255932Salfred			vhcr_cmd->status = CMD_STAT_BAD_SIZE;
1444255932Salfred			outbox = NULL;
1445255932Salfred			goto out_status;
1446255932Salfred		}
1447255932Salfred	}
1448255932Salfred
1449255932Salfred	/* Execute the command! */
1450255932Salfred	if (cmd->wrapper) {
1451255932Salfred		err = cmd->wrapper(dev, slave, vhcr, inbox, outbox,
1452255932Salfred				   cmd);
1453255932Salfred		if (cmd->out_is_imm)
1454255932Salfred			vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
1455255932Salfred	} else {
1456255932Salfred		in_param = cmd->has_inbox ? (u64) inbox->dma :
1457255932Salfred			vhcr->in_param;
1458255932Salfred		out_param = cmd->has_outbox ? (u64) outbox->dma :
1459255932Salfred			vhcr->out_param;
1460255932Salfred		err = __mlx4_cmd(dev, in_param, &out_param,
1461255932Salfred				 cmd->out_is_imm, vhcr->in_modifier,
1462255932Salfred				 vhcr->op_modifier, vhcr->op,
1463255932Salfred				 MLX4_CMD_TIME_CLASS_A,
1464255932Salfred				 MLX4_CMD_NATIVE);
1465255932Salfred
1466255932Salfred		if (cmd->out_is_imm) {
1467255932Salfred			vhcr->out_param = out_param;
1468255932Salfred			vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
1469255932Salfred		}
1470255932Salfred	}
1471255932Salfred
1472255932Salfred	if (err) {
1473255932Salfred		mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with"
1474255932Salfred			  " error:%d, status %d\n",
1475255932Salfred			  vhcr->op, slave, vhcr->errno, err);
1476255932Salfred		vhcr_cmd->status = mlx4_errno_to_status(err);
1477255932Salfred		goto out_status;
1478255932Salfred	}
1479255932Salfred
1480255932Salfred
1481255932Salfred	/* Write outbox if command completed successfully */
1482255932Salfred	if (cmd->has_outbox && !vhcr_cmd->status) {
1483255932Salfred		ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave,
1484255932Salfred				      vhcr->out_param,
1485255932Salfred				      MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED);
1486255932Salfred		if (ret) {
1487255932Salfred			/* If we failed to write back the outbox after the
1488255932Salfred			 *command was successfully executed, we must fail this
1489255932Salfred			 * slave, as it is now in undefined state */
1490255932Salfred			mlx4_err(dev, "%s:Failed writing outbox\n", __func__);
1491255932Salfred			goto out;
1492255932Salfred		}
1493255932Salfred	}
1494255932Salfred
1495255932Salfredout_status:
1496255932Salfred	/* DMA back vhcr result */
1497255932Salfred	if (!in_vhcr) {
1498255932Salfred		ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
1499255932Salfred				      priv->mfunc.master.slave_state[slave].vhcr_dma,
1500255932Salfred				      ALIGN(sizeof(struct mlx4_vhcr),
1501255932Salfred					    MLX4_ACCESS_MEM_ALIGN),
1502255932Salfred				      MLX4_CMD_WRAPPED);
1503255932Salfred		if (ret)
1504255932Salfred			mlx4_err(dev, "%s:Failed writing vhcr result\n",
1505255932Salfred				 __func__);
1506255932Salfred		else if (vhcr->e_bit &&
1507255932Salfred			 mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe))
1508255932Salfred				mlx4_warn(dev, "Failed to generate command completion "
1509255932Salfred					  "eqe for slave %d\n", slave);
1510255932Salfred	}
1511255932Salfred
1512255932Salfredout:
1513255932Salfred	kfree(vhcr);
1514255932Salfred	mlx4_free_cmd_mailbox(dev, inbox);
1515255932Salfred	mlx4_free_cmd_mailbox(dev, outbox);
1516255932Salfred	return ret;
1517255932Salfred}
1518255932Salfred
1519255932Salfredstatic int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
1520255932Salfred{
1521255932Salfred	int port, err;
1522255932Salfred	struct mlx4_vport_state *vp_admin;
1523255932Salfred	struct mlx4_vport_oper_state *vp_oper;
1524255932Salfred
1525255932Salfred	for (port = 1; port <= MLX4_MAX_PORTS; port++) {
1526255932Salfred		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
1527255932Salfred		vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
1528255932Salfred		vp_oper->state = *vp_admin;
1529255932Salfred		if (MLX4_VGT != vp_admin->default_vlan) {
1530255932Salfred			err = mlx4_register_vlan(&priv->dev, port,
1531255932Salfred						 vp_admin->default_vlan, &(vp_oper->vlan_idx));
1532255932Salfred			if (err) {
1533255932Salfred				vp_oper->vlan_idx = NO_INDX;
1534255932Salfred				mlx4_warn((&priv->dev),
1535255932Salfred					  "No vlan resorces slave %d, port %d\n",
1536255932Salfred					  slave, port);
1537255932Salfred				return err;
1538255932Salfred			}
1539255932Salfred			mlx4_dbg((&(priv->dev)), "alloc vlan %d idx  %d slave %d port %d\n",
1540255932Salfred				 (int)(vp_oper->state.default_vlan),
1541255932Salfred				 vp_oper->vlan_idx, slave, port);
1542255932Salfred		}
1543255932Salfred		if (vp_admin->spoofchk) {
1544255932Salfred			vp_oper->mac_idx = __mlx4_register_mac(&priv->dev,
1545255932Salfred							       port,
1546255932Salfred							       vp_admin->mac);
1547255932Salfred			if (0 > vp_oper->mac_idx) {
1548255932Salfred				err = vp_oper->mac_idx;
1549255932Salfred				vp_oper->mac_idx = NO_INDX;
1550255932Salfred				mlx4_warn((&priv->dev),
1551255932Salfred					  "No mac resorces slave %d, port %d\n",
1552255932Salfred					  slave, port);
1553255932Salfred				return err;
1554255932Salfred			}
1555255932Salfred			mlx4_dbg((&(priv->dev)), "alloc mac %llx idx  %d slave %d port %d\n",
1556255932Salfred				 vp_oper->state.mac, vp_oper->mac_idx, slave, port);
1557255932Salfred		}
1558255932Salfred	}
1559255932Salfred	return 0;
1560255932Salfred}
1561255932Salfred
1562255932Salfredstatic void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
1563255932Salfred{
1564255932Salfred	int port;
1565255932Salfred	struct mlx4_vport_oper_state *vp_oper;
1566255932Salfred
1567255932Salfred	for (port = 1; port <= MLX4_MAX_PORTS; port++) {
1568255932Salfred		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
1569255932Salfred		if (NO_INDX != vp_oper->vlan_idx) {
1570255932Salfred			__mlx4_unregister_vlan(&priv->dev,
1571255932Salfred					       port, vp_oper->state.default_vlan);
1572255932Salfred			vp_oper->vlan_idx = NO_INDX;
1573255932Salfred		}
1574255932Salfred		if (NO_INDX != vp_oper->mac_idx) {
1575255932Salfred			__mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac);
1576255932Salfred			vp_oper->mac_idx = NO_INDX;
1577255932Salfred		}
1578255932Salfred	}
1579255932Salfred	return;
1580255932Salfred}
1581255932Salfred
1582255932Salfredstatic void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
1583255932Salfred			       u16 param, u8 toggle)
1584255932Salfred{
1585255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1586255932Salfred	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
1587255932Salfred	u32 reply;
1588255932Salfred	u8 is_going_down = 0;
1589255932Salfred	int i;
1590255932Salfred	unsigned long flags;
1591255932Salfred
1592255932Salfred	slave_state[slave].comm_toggle ^= 1;
1593255932Salfred	reply = (u32) slave_state[slave].comm_toggle << 31;
1594255932Salfred	if (toggle != slave_state[slave].comm_toggle) {
1595255932Salfred		mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER"
1596255932Salfred			  "STATE COMPROMISIED ***\n", toggle, slave);
1597255932Salfred		goto reset_slave;
1598255932Salfred	}
1599255932Salfred	if (cmd == MLX4_COMM_CMD_RESET) {
1600255932Salfred		mlx4_warn(dev, "Received reset from slave:%d\n", slave);
1601255932Salfred		slave_state[slave].active = false;
1602255932Salfred		mlx4_master_deactivate_admin_state(priv, slave);
1603255932Salfred		for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
1604255932Salfred				slave_state[slave].event_eq[i].eqn = -1;
1605255932Salfred				slave_state[slave].event_eq[i].token = 0;
1606255932Salfred		}
1607255932Salfred		/*check if we are in the middle of FLR process,
1608255932Salfred		if so return "retry" status to the slave*/
1609255932Salfred		if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd)
1610255932Salfred			goto inform_slave_state;
1611255932Salfred
1612255932Salfred		mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave);
1613255932Salfred
1614255932Salfred		/* write the version in the event field */
1615255932Salfred		reply |= mlx4_comm_get_version();
1616255932Salfred
1617255932Salfred		goto reset_slave;
1618255932Salfred	}
1619255932Salfred	/*command from slave in the middle of FLR*/
1620255932Salfred	if (cmd != MLX4_COMM_CMD_RESET &&
1621255932Salfred	    MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) {
1622255932Salfred		mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) "
1623255932Salfred			  "in the middle of FLR\n", slave, cmd);
1624255932Salfred		return;
1625255932Salfred	}
1626255932Salfred
1627255932Salfred	switch (cmd) {
1628255932Salfred	case MLX4_COMM_CMD_VHCR0:
1629255932Salfred		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET)
1630255932Salfred			goto reset_slave;
1631255932Salfred		slave_state[slave].vhcr_dma = ((u64) param) << 48;
1632255932Salfred		priv->mfunc.master.slave_state[slave].cookie = 0;
1633255932Salfred		mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]);
1634255932Salfred		break;
1635255932Salfred	case MLX4_COMM_CMD_VHCR1:
1636255932Salfred		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
1637255932Salfred			goto reset_slave;
1638255932Salfred		slave_state[slave].vhcr_dma |= ((u64) param) << 32;
1639255932Salfred		break;
1640255932Salfred	case MLX4_COMM_CMD_VHCR2:
1641255932Salfred		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1)
1642255932Salfred			goto reset_slave;
1643255932Salfred		slave_state[slave].vhcr_dma |= ((u64) param) << 16;
1644255932Salfred		break;
1645255932Salfred	case MLX4_COMM_CMD_VHCR_EN:
1646255932Salfred		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
1647255932Salfred			goto reset_slave;
1648255932Salfred		slave_state[slave].vhcr_dma |= param;
1649255932Salfred		if (mlx4_master_activate_admin_state(priv, slave))
1650255932Salfred				goto reset_slave;
1651255932Salfred		slave_state[slave].active = true;
1652255932Salfred		mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
1653255932Salfred		break;
1654255932Salfred	case MLX4_COMM_CMD_VHCR_POST:
1655255932Salfred		if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
1656255932Salfred		    (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST))
1657255932Salfred			goto reset_slave;
1658255932Salfred
1659255932Salfred		mutex_lock(&priv->cmd.slave_cmd_mutex);
1660255932Salfred		if (mlx4_master_process_vhcr(dev, slave, NULL)) {
1661255932Salfred			mlx4_err(dev, "Failed processing vhcr for slave:%d,"
1662255932Salfred				 " resetting slave.\n", slave);
1663255932Salfred			mutex_unlock(&priv->cmd.slave_cmd_mutex);
1664255932Salfred			goto reset_slave;
1665255932Salfred		}
1666255932Salfred		mutex_unlock(&priv->cmd.slave_cmd_mutex);
1667255932Salfred		break;
1668255932Salfred	default:
1669255932Salfred		mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave);
1670255932Salfred		goto reset_slave;
1671255932Salfred	}
1672255932Salfred	spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
1673255932Salfred	if (!slave_state[slave].is_slave_going_down)
1674255932Salfred		slave_state[slave].last_cmd = cmd;
1675255932Salfred	else
1676255932Salfred		is_going_down = 1;
1677255932Salfred	spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
1678255932Salfred	if (is_going_down) {
1679255932Salfred		mlx4_warn(dev, "Slave is going down aborting command(%d)"
1680255932Salfred			  " executing from slave:%d\n",
1681255932Salfred			  cmd, slave);
1682255932Salfred		return;
1683255932Salfred	}
1684255932Salfred	__raw_writel((__force u32) cpu_to_be32(reply),
1685255932Salfred		     &priv->mfunc.comm[slave].slave_read);
1686255932Salfred	mmiowb();
1687255932Salfred
1688255932Salfred	return;
1689255932Salfred
1690255932Salfredreset_slave:
1691255932Salfred	/* cleanup any slave resources */
1692255932Salfred	mlx4_delete_all_resources_for_slave(dev, slave);
1693255932Salfred	spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
1694255932Salfred	if (!slave_state[slave].is_slave_going_down)
1695255932Salfred		slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET;
1696255932Salfred	spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
1697255932Salfred	/*with slave in the middle of flr, no need to clean resources again.*/
1698255932Salfredinform_slave_state:
1699255932Salfred	memset(&slave_state[slave].event_eq, 0,
1700255932Salfred	       sizeof(struct mlx4_slave_event_eq_info));
1701255932Salfred	__raw_writel((__force u32) cpu_to_be32(reply),
1702255932Salfred		     &priv->mfunc.comm[slave].slave_read);
1703255932Salfred	wmb();
1704255932Salfred}
1705255932Salfred
1706255932Salfred/* master command processing */
1707255932Salfredvoid mlx4_master_comm_channel(struct work_struct *work)
1708255932Salfred{
1709255932Salfred	struct mlx4_mfunc_master_ctx *master =
1710255932Salfred		container_of(work,
1711255932Salfred			     struct mlx4_mfunc_master_ctx,
1712255932Salfred			     comm_work);
1713255932Salfred	struct mlx4_mfunc *mfunc =
1714255932Salfred		container_of(master, struct mlx4_mfunc, master);
1715255932Salfred	struct mlx4_priv *priv =
1716255932Salfred		container_of(mfunc, struct mlx4_priv, mfunc);
1717255932Salfred	struct mlx4_dev *dev = &priv->dev;
1718255932Salfred	__be32 *bit_vec;
1719255932Salfred	u32 comm_cmd;
1720255932Salfred	u32 vec;
1721255932Salfred	int i, j, slave;
1722255932Salfred	int toggle;
1723255932Salfred	int served = 0;
1724255932Salfred	int reported = 0;
1725255932Salfred	u32 slt;
1726255932Salfred
1727255932Salfred	bit_vec = master->comm_arm_bit_vector;
1728255932Salfred	for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) {
1729255932Salfred		vec = be32_to_cpu(bit_vec[i]);
1730255932Salfred		for (j = 0; j < 32; j++) {
1731255932Salfred			if (!(vec & (1 << j)))
1732255932Salfred				continue;
1733255932Salfred			++reported;
1734255932Salfred			slave = (i * 32) + j;
1735255932Salfred			comm_cmd = swab32(readl(
1736255932Salfred					  &mfunc->comm[slave].slave_write));
1737255932Salfred			slt = swab32(readl(&mfunc->comm[slave].slave_read))
1738255932Salfred				     >> 31;
1739255932Salfred			toggle = comm_cmd >> 31;
1740255932Salfred			if (toggle != slt) {
1741255932Salfred				if (master->slave_state[slave].comm_toggle
1742255932Salfred				    != slt) {
1743255932Salfred					mlx4_info(dev, "slave %d out of sync."
1744255932Salfred						  " read toggle %d, state toggle %d. "
1745255932Salfred						  "Resynching.\n", slave, slt,
1746255932Salfred						  master->slave_state[slave].comm_toggle);
1747255932Salfred					master->slave_state[slave].comm_toggle =
1748255932Salfred						slt;
1749255932Salfred				}
1750255932Salfred				mlx4_master_do_cmd(dev, slave,
1751255932Salfred						   comm_cmd >> 16 & 0xff,
1752255932Salfred						   comm_cmd & 0xffff, toggle);
1753255932Salfred				++served;
1754255932Salfred			}
1755255932Salfred		}
1756255932Salfred	}
1757255932Salfred
1758255932Salfred	if (reported && reported != served)
1759255932Salfred		mlx4_warn(dev, "Got command event with bitmask from %d slaves"
1760255932Salfred			  " but %d were served\n",
1761255932Salfred			  reported, served);
1762255932Salfred
1763255932Salfred	if (mlx4_ARM_COMM_CHANNEL(dev))
1764255932Salfred		mlx4_warn(dev, "Failed to arm comm channel events\n");
1765255932Salfred}
1766255932Salfred
1767255932Salfredstatic int sync_toggles(struct mlx4_dev *dev)
1768255932Salfred{
1769255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1770255932Salfred	int wr_toggle;
1771255932Salfred	int rd_toggle;
1772255932Salfred	unsigned long end;
1773255932Salfred
1774255932Salfred	wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31;
1775255932Salfred	end = jiffies + msecs_to_jiffies(5000);
1776255932Salfred
1777255932Salfred	while (time_before(jiffies, end)) {
1778255932Salfred		rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31;
1779255932Salfred		if (rd_toggle == wr_toggle) {
1780255932Salfred			priv->cmd.comm_toggle = rd_toggle;
1781255932Salfred			return 0;
1782255932Salfred		}
1783255932Salfred
1784255932Salfred		cond_resched();
1785255932Salfred	}
1786255932Salfred
1787255932Salfred	/*
1788255932Salfred	 * we could reach here if for example the previous VM using this
1789255932Salfred	 * function misbehaved and left the channel with unsynced state. We
1790255932Salfred	 * should fix this here and give this VM a chance to use a properly
1791255932Salfred	 * synced channel
1792255932Salfred	 */
1793255932Salfred	mlx4_warn(dev, "recovering from previously mis-behaved VM\n");
1794255932Salfred	__raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read);
1795255932Salfred	__raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write);
1796255932Salfred	priv->cmd.comm_toggle = 0;
1797255932Salfred
1798255932Salfred	return 0;
1799255932Salfred}
1800255932Salfred
1801255932Salfredint mlx4_multi_func_init(struct mlx4_dev *dev)
1802255932Salfred{
1803255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1804255932Salfred	struct mlx4_slave_state *s_state;
1805255932Salfred	int i, j, err, port;
1806255932Salfred
1807255932Salfred	if (mlx4_is_master(dev))
1808255932Salfred		priv->mfunc.comm =
1809255932Salfred		ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) +
1810255932Salfred			priv->fw.comm_base, MLX4_COMM_PAGESIZE);
1811255932Salfred	else
1812255932Salfred		priv->mfunc.comm =
1813255932Salfred		ioremap(pci_resource_start(dev->pdev, 2) +
1814255932Salfred			MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE);
1815255932Salfred	if (!priv->mfunc.comm) {
1816255932Salfred		mlx4_err(dev, "Couldn't map communication vector.\n");
1817255932Salfred		goto err_vhcr;
1818255932Salfred	}
1819255932Salfred
1820255932Salfred	if (mlx4_is_master(dev)) {
1821255932Salfred		priv->mfunc.master.slave_state =
1822255932Salfred			kzalloc(dev->num_slaves *
1823255932Salfred				sizeof(struct mlx4_slave_state), GFP_KERNEL);
1824255932Salfred		if (!priv->mfunc.master.slave_state)
1825255932Salfred			goto err_comm;
1826255932Salfred
1827255932Salfred		priv->mfunc.master.vf_admin =
1828255932Salfred			kzalloc(dev->num_slaves *
1829255932Salfred				sizeof(struct mlx4_vf_admin_state), GFP_KERNEL);
1830255932Salfred		if (!priv->mfunc.master.vf_admin)
1831255932Salfred			goto err_comm_admin;
1832255932Salfred
1833255932Salfred		priv->mfunc.master.vf_oper =
1834255932Salfred			kzalloc(dev->num_slaves *
1835255932Salfred				sizeof(struct mlx4_vf_oper_state), GFP_KERNEL);
1836255932Salfred		if (!priv->mfunc.master.vf_oper)
1837255932Salfred			goto err_comm_oper;
1838255932Salfred
1839255932Salfred		for (i = 0; i < dev->num_slaves; ++i) {
1840255932Salfred			s_state = &priv->mfunc.master.slave_state[i];
1841255932Salfred			s_state->last_cmd = MLX4_COMM_CMD_RESET;
1842255932Salfred			for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j)
1843255932Salfred				s_state->event_eq[j].eqn = -1;
1844255932Salfred			__raw_writel((__force u32) 0,
1845255932Salfred				     &priv->mfunc.comm[i].slave_write);
1846255932Salfred			__raw_writel((__force u32) 0,
1847255932Salfred				     &priv->mfunc.comm[i].slave_read);
1848255932Salfred			mmiowb();
1849255932Salfred			for (port = 1; port <= MLX4_MAX_PORTS; port++) {
1850255932Salfred				s_state->vlan_filter[port] =
1851255932Salfred					kzalloc(sizeof(struct mlx4_vlan_fltr),
1852255932Salfred						GFP_KERNEL);
1853255932Salfred				if (!s_state->vlan_filter[port]) {
1854255932Salfred					if (--port)
1855255932Salfred						kfree(s_state->vlan_filter[port]);
1856255932Salfred					goto err_slaves;
1857255932Salfred				}
1858255932Salfred				INIT_LIST_HEAD(&s_state->mcast_filters[port]);
1859255932Salfred				priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT;
1860255932Salfred				priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT;
1861255932Salfred				priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX;
1862255932Salfred				priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX;
1863255932Salfred			}
1864255932Salfred			spin_lock_init(&s_state->lock);
1865255932Salfred		}
1866255932Salfred
1867255932Salfred		memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size);
1868255932Salfred		priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD;
1869255932Salfred		INIT_WORK(&priv->mfunc.master.comm_work,
1870255932Salfred			  mlx4_master_comm_channel);
1871255932Salfred		INIT_WORK(&priv->mfunc.master.slave_event_work,
1872255932Salfred			  mlx4_gen_slave_eqe);
1873255932Salfred		INIT_WORK(&priv->mfunc.master.slave_flr_event_work,
1874255932Salfred			  mlx4_master_handle_slave_flr);
1875255932Salfred		spin_lock_init(&priv->mfunc.master.slave_state_lock);
1876255932Salfred		spin_lock_init(&priv->mfunc.master.slave_eq.event_lock);
1877255932Salfred		priv->mfunc.master.comm_wq =
1878255932Salfred			create_singlethread_workqueue("mlx4_comm");
1879255932Salfred		if (!priv->mfunc.master.comm_wq)
1880255932Salfred			goto err_slaves;
1881255932Salfred
1882255932Salfred		if (mlx4_init_resource_tracker(dev))
1883255932Salfred			goto err_thread;
1884255932Salfred
1885255932Salfred		err = mlx4_ARM_COMM_CHANNEL(dev);
1886255932Salfred		if (err) {
1887255932Salfred			mlx4_err(dev, " Failed to arm comm channel eq: %x\n",
1888255932Salfred				 err);
1889255932Salfred			goto err_resource;
1890255932Salfred		}
1891255932Salfred
1892255932Salfred	} else {
1893255932Salfred		err = sync_toggles(dev);
1894255932Salfred		if (err) {
1895255932Salfred			mlx4_err(dev, "Couldn't sync toggles\n");
1896255932Salfred			goto err_comm;
1897255932Salfred		}
1898255932Salfred	}
1899255932Salfred	return 0;
1900255932Salfred
1901255932Salfrederr_resource:
1902255932Salfred	mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL);
1903255932Salfrederr_thread:
1904255932Salfred	flush_workqueue(priv->mfunc.master.comm_wq);
1905255932Salfred	destroy_workqueue(priv->mfunc.master.comm_wq);
1906255932Salfrederr_slaves:
1907255932Salfred	while (--i) {
1908255932Salfred		for (port = 1; port <= MLX4_MAX_PORTS; port++)
1909255932Salfred			kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
1910255932Salfred	}
1911255932Salfred	kfree(priv->mfunc.master.vf_oper);
1912255932Salfrederr_comm_oper:
1913255932Salfred	kfree(priv->mfunc.master.vf_admin);
1914255932Salfrederr_comm_admin:
1915255932Salfred	kfree(priv->mfunc.master.slave_state);
1916255932Salfrederr_comm:
1917255932Salfred	iounmap(priv->mfunc.comm);
1918255932Salfrederr_vhcr:
1919255932Salfred	dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
1920255932Salfred					     priv->mfunc.vhcr,
1921255932Salfred					     priv->mfunc.vhcr_dma);
1922255932Salfred	priv->mfunc.vhcr = NULL;
1923255932Salfred	return -ENOMEM;
1924255932Salfred}
1925255932Salfred
1926219820Sjeffint mlx4_cmd_init(struct mlx4_dev *dev)
1927219820Sjeff{
1928219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1929219820Sjeff
1930219820Sjeff	mutex_init(&priv->cmd.hcr_mutex);
1931255932Salfred	mutex_init(&priv->cmd.slave_cmd_mutex);
1932219820Sjeff	sema_init(&priv->cmd.poll_sem, 1);
1933219820Sjeff	priv->cmd.use_events = 0;
1934219820Sjeff	priv->cmd.toggle     = 1;
1935219820Sjeff
1936255932Salfred	priv->cmd.hcr = NULL;
1937255932Salfred	priv->mfunc.vhcr = NULL;
1938255932Salfred
1939255932Salfred	if (!mlx4_is_slave(dev)) {
1940255932Salfred		priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) +
1941255932Salfred					MLX4_HCR_BASE, MLX4_HCR_SIZE);
1942255932Salfred		if (!priv->cmd.hcr) {
1943255932Salfred			mlx4_err(dev, "Couldn't map command register.\n");
1944255932Salfred			return -ENOMEM;
1945255932Salfred		}
1946219820Sjeff	}
1947219820Sjeff
1948255932Salfred	if (mlx4_is_mfunc(dev)) {
1949255932Salfred		priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE,
1950255932Salfred						      &priv->mfunc.vhcr_dma,
1951255932Salfred						      GFP_KERNEL);
1952255932Salfred		if (!priv->mfunc.vhcr) {
1953255932Salfred			mlx4_err(dev, "Couldn't allocate VHCR.\n");
1954255932Salfred			goto err_hcr;
1955255932Salfred		}
1956255932Salfred	}
1957255932Salfred
1958219820Sjeff	priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
1959219820Sjeff					 MLX4_MAILBOX_SIZE,
1960219820Sjeff					 MLX4_MAILBOX_SIZE, 0);
1961255932Salfred	if (!priv->cmd.pool)
1962255932Salfred		goto err_vhcr;
1963255932Salfred
1964255932Salfred	return 0;
1965255932Salfred
1966255932Salfrederr_vhcr:
1967255932Salfred	if (mlx4_is_mfunc(dev))
1968255932Salfred		dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
1969255932Salfred				  priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
1970255932Salfred	priv->mfunc.vhcr = NULL;
1971255932Salfred
1972255932Salfrederr_hcr:
1973255932Salfred	if (!mlx4_is_slave(dev))
1974219820Sjeff		iounmap(priv->cmd.hcr);
1975255932Salfred	return -ENOMEM;
1976255932Salfred}
1977255932Salfred
1978255932Salfredvoid mlx4_multi_func_cleanup(struct mlx4_dev *dev)
1979255932Salfred{
1980255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1981255932Salfred	int i, port;
1982255932Salfred
1983255932Salfred	if (mlx4_is_master(dev)) {
1984255932Salfred		flush_workqueue(priv->mfunc.master.comm_wq);
1985255932Salfred		destroy_workqueue(priv->mfunc.master.comm_wq);
1986255932Salfred		for (i = 0; i < dev->num_slaves; i++) {
1987255932Salfred			for (port = 1; port <= MLX4_MAX_PORTS; port++)
1988255932Salfred				kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
1989255932Salfred		}
1990255932Salfred		kfree(priv->mfunc.master.slave_state);
1991255932Salfred		kfree(priv->mfunc.master.vf_admin);
1992255932Salfred		kfree(priv->mfunc.master.vf_oper);
1993219820Sjeff	}
1994219820Sjeff
1995255932Salfred	iounmap(priv->mfunc.comm);
1996219820Sjeff}
1997219820Sjeff
1998219820Sjeffvoid mlx4_cmd_cleanup(struct mlx4_dev *dev)
1999219820Sjeff{
2000219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
2001219820Sjeff
2002219820Sjeff	pci_pool_destroy(priv->cmd.pool);
2003255932Salfred
2004255932Salfred	if (!mlx4_is_slave(dev))
2005255932Salfred		iounmap(priv->cmd.hcr);
2006255932Salfred	if (mlx4_is_mfunc(dev))
2007255932Salfred		dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
2008255932Salfred				  priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
2009255932Salfred	priv->mfunc.vhcr = NULL;
2010219820Sjeff}
2011219820Sjeff
2012219820Sjeff/*
2013219820Sjeff * Switch to using events to issue FW commands (can only be called
2014219820Sjeff * after event queue for command events has been initialized).
2015219820Sjeff */
2016219820Sjeffint mlx4_cmd_use_events(struct mlx4_dev *dev)
2017219820Sjeff{
2018219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
2019219820Sjeff	int i;
2020255932Salfred	int err = 0;
2021219820Sjeff
2022219820Sjeff	priv->cmd.context = kmalloc(priv->cmd.max_cmds *
2023219820Sjeff				   sizeof (struct mlx4_cmd_context),
2024219820Sjeff				   GFP_KERNEL);
2025219820Sjeff	if (!priv->cmd.context)
2026219820Sjeff		return -ENOMEM;
2027219820Sjeff
2028219820Sjeff	for (i = 0; i < priv->cmd.max_cmds; ++i) {
2029219820Sjeff		priv->cmd.context[i].token = i;
2030219820Sjeff		priv->cmd.context[i].next  = i + 1;
2031219820Sjeff	}
2032219820Sjeff
2033219820Sjeff	priv->cmd.context[priv->cmd.max_cmds - 1].next = -1;
2034219820Sjeff	priv->cmd.free_head = 0;
2035219820Sjeff
2036219820Sjeff	sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds);
2037219820Sjeff	spin_lock_init(&priv->cmd.context_lock);
2038219820Sjeff
2039219820Sjeff	for (priv->cmd.token_mask = 1;
2040219820Sjeff	     priv->cmd.token_mask < priv->cmd.max_cmds;
2041219820Sjeff	     priv->cmd.token_mask <<= 1)
2042219820Sjeff		; /* nothing */
2043219820Sjeff	--priv->cmd.token_mask;
2044219820Sjeff
2045255932Salfred	down(&priv->cmd.poll_sem);
2046219820Sjeff	priv->cmd.use_events = 1;
2047219820Sjeff
2048255932Salfred	return err;
2049219820Sjeff}
2050219820Sjeff
2051219820Sjeff/*
2052219820Sjeff * Switch back to polling (used when shutting down the device)
2053219820Sjeff */
2054219820Sjeffvoid mlx4_cmd_use_polling(struct mlx4_dev *dev)
2055219820Sjeff{
2056219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
2057219820Sjeff	int i;
2058219820Sjeff
2059219820Sjeff	priv->cmd.use_events = 0;
2060219820Sjeff
2061219820Sjeff	for (i = 0; i < priv->cmd.max_cmds; ++i)
2062219820Sjeff		down(&priv->cmd.event_sem);
2063219820Sjeff
2064219820Sjeff	kfree(priv->cmd.context);
2065219820Sjeff
2066219820Sjeff	up(&priv->cmd.poll_sem);
2067219820Sjeff}
2068219820Sjeff
2069219820Sjeffstruct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
2070219820Sjeff{
2071219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
2072219820Sjeff
2073219820Sjeff	mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL);
2074219820Sjeff	if (!mailbox)
2075219820Sjeff		return ERR_PTR(-ENOMEM);
2076219820Sjeff
2077219820Sjeff	mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL,
2078219820Sjeff				      &mailbox->dma);
2079219820Sjeff	if (!mailbox->buf) {
2080219820Sjeff		kfree(mailbox);
2081219820Sjeff		return ERR_PTR(-ENOMEM);
2082219820Sjeff	}
2083219820Sjeff
2084219820Sjeff	return mailbox;
2085219820Sjeff}
2086219820SjeffEXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
2087219820Sjeff
2088255932Salfredvoid mlx4_free_cmd_mailbox(struct mlx4_dev *dev,
2089255932Salfred			   struct mlx4_cmd_mailbox *mailbox)
2090219820Sjeff{
2091219820Sjeff	if (!mailbox)
2092219820Sjeff		return;
2093219820Sjeff
2094219820Sjeff	pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma);
2095219820Sjeff	kfree(mailbox);
2096219820Sjeff}
2097219820SjeffEXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox);
2098255932Salfred
2099255932Salfredu32 mlx4_comm_get_version(void)
2100255932Salfred{
2101255932Salfred	 return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
2102255932Salfred}
2103255932Salfred
2104255932Salfredint mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac)
2105255932Salfred{
2106255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
2107255932Salfred	struct mlx4_vport_state *s_info;
2108255932Salfred
2109255932Salfred	if (!mlx4_is_master(dev))
2110255932Salfred		return -EPROTONOSUPPORT;
2111255932Salfred
2112255932Salfred	if ((vf <= 0) || (vf > dev->num_vfs)) {
2113255932Salfred		mlx4_err(dev, "Bad vf number:%d (max vf activated: %d)\n", vf, dev->num_vfs);
2114255932Salfred		return -EINVAL;
2115255932Salfred	}
2116255932Salfred
2117255932Salfred	s_info = &priv->mfunc.master.vf_admin[vf].vport[port];
2118255932Salfred	s_info->mac = mlx4_mac_to_u64(mac);
2119255932Salfred	mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n",
2120255932Salfred		  vf, port, s_info->mac);
2121255932Salfred	return 0;
2122255932Salfred}
2123255932SalfredEXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
2124255932Salfred
2125255932Salfredint mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
2126255932Salfred{
2127255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
2128255932Salfred	struct mlx4_vport_state *s_info;
2129255932Salfred
2130255932Salfred	if ((!mlx4_is_master(dev)) ||
2131255932Salfred	    !(dev->caps.flags & MLX4_DEV_CAP_FLAG_ESWITCH_SUPPORT))
2132255932Salfred		return -EPROTONOSUPPORT;
2133255932Salfred
2134255932Salfred	if ((vf <= 0) || (vf > dev->num_vfs) || (vlan > 4095) || (qos > 7))
2135255932Salfred		return -EINVAL;
2136255932Salfred
2137255932Salfred	s_info = &priv->mfunc.master.vf_admin[vf].vport[port];
2138255932Salfred	if ((0 == vlan) && (0 == qos))
2139255932Salfred		s_info->default_vlan = MLX4_VGT;
2140255932Salfred	else
2141255932Salfred		s_info->default_vlan = vlan;
2142255932Salfred	s_info->default_qos = qos;
2143255932Salfred	return 0;
2144255932Salfred}
2145255932SalfredEXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
2146255932Salfred
2147255932Salfredint mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
2148255932Salfred{
2149255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
2150255932Salfred	struct mlx4_vport_state *s_info;
2151255932Salfred
2152255932Salfred	if ((!mlx4_is_master(dev)) ||
2153255932Salfred	    !(dev->caps.flags & MLX4_DEV_CAP_FLAG_ESWITCH_SUPPORT))
2154255932Salfred		return -EPROTONOSUPPORT;
2155255932Salfred
2156255932Salfred	if ((vf <= 0) || (vf > dev->num_vfs))
2157255932Salfred		return -EINVAL;
2158255932Salfred
2159255932Salfred	s_info = &priv->mfunc.master.vf_admin[vf].vport[port];
2160255932Salfred	s_info->spoofchk = setting;
2161255932Salfred
2162255932Salfred	return 0;
2163255932Salfred}
2164255932SalfredEXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk);
2165