xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlx4/cmd.c (revision f9baff509f8a05a79626defdbdf4f4aa4efd373b)
15a2cc190SJeff Kirsher /*
25a2cc190SJeff Kirsher  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
35a2cc190SJeff Kirsher  * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
45a2cc190SJeff Kirsher  * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
55a2cc190SJeff Kirsher  *
65a2cc190SJeff Kirsher  * This software is available to you under a choice of one of two
75a2cc190SJeff Kirsher  * licenses.  You may choose to be licensed under the terms of the GNU
85a2cc190SJeff Kirsher  * General Public License (GPL) Version 2, available from the file
95a2cc190SJeff Kirsher  * COPYING in the main directory of this source tree, or the
105a2cc190SJeff Kirsher  * OpenIB.org BSD license below:
115a2cc190SJeff Kirsher  *
125a2cc190SJeff Kirsher  *     Redistribution and use in source and binary forms, with or
135a2cc190SJeff Kirsher  *     without modification, are permitted provided that the following
145a2cc190SJeff Kirsher  *     conditions are met:
155a2cc190SJeff Kirsher  *
165a2cc190SJeff Kirsher  *      - Redistributions of source code must retain the above
175a2cc190SJeff Kirsher  *        copyright notice, this list of conditions and the following
185a2cc190SJeff Kirsher  *        disclaimer.
195a2cc190SJeff Kirsher  *
205a2cc190SJeff Kirsher  *      - Redistributions in binary form must reproduce the above
215a2cc190SJeff Kirsher  *        copyright notice, this list of conditions and the following
225a2cc190SJeff Kirsher  *        disclaimer in the documentation and/or other materials
235a2cc190SJeff Kirsher  *        provided with the distribution.
245a2cc190SJeff Kirsher  *
255a2cc190SJeff Kirsher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
265a2cc190SJeff Kirsher  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
275a2cc190SJeff Kirsher  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
285a2cc190SJeff Kirsher  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
295a2cc190SJeff Kirsher  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
305a2cc190SJeff Kirsher  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
315a2cc190SJeff Kirsher  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
325a2cc190SJeff Kirsher  * SOFTWARE.
335a2cc190SJeff Kirsher  */
345a2cc190SJeff Kirsher 
355a2cc190SJeff Kirsher #include <linux/sched.h>
365a2cc190SJeff Kirsher #include <linux/slab.h>
37ee40fa06SPaul Gortmaker #include <linux/export.h>
385a2cc190SJeff Kirsher #include <linux/pci.h>
395a2cc190SJeff Kirsher #include <linux/errno.h>
405a2cc190SJeff Kirsher 
415a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h>
425a2cc190SJeff Kirsher 
435a2cc190SJeff Kirsher #include <asm/io.h>
445a2cc190SJeff Kirsher 
455a2cc190SJeff Kirsher #include "mlx4.h"
465a2cc190SJeff Kirsher 
475a2cc190SJeff Kirsher #define CMD_POLL_TOKEN 0xffff
485a2cc190SJeff Kirsher 
495a2cc190SJeff Kirsher enum {
505a2cc190SJeff Kirsher 	/* command completed successfully: */
515a2cc190SJeff Kirsher 	CMD_STAT_OK		= 0x00,
525a2cc190SJeff Kirsher 	/* Internal error (such as a bus error) occurred while processing command: */
535a2cc190SJeff Kirsher 	CMD_STAT_INTERNAL_ERR	= 0x01,
545a2cc190SJeff Kirsher 	/* Operation/command not supported or opcode modifier not supported: */
555a2cc190SJeff Kirsher 	CMD_STAT_BAD_OP		= 0x02,
565a2cc190SJeff Kirsher 	/* Parameter not supported or parameter out of range: */
575a2cc190SJeff Kirsher 	CMD_STAT_BAD_PARAM	= 0x03,
585a2cc190SJeff Kirsher 	/* System not enabled or bad system state: */
595a2cc190SJeff Kirsher 	CMD_STAT_BAD_SYS_STATE	= 0x04,
605a2cc190SJeff Kirsher 	/* Attempt to access reserved or unallocaterd resource: */
615a2cc190SJeff Kirsher 	CMD_STAT_BAD_RESOURCE	= 0x05,
625a2cc190SJeff Kirsher 	/* Requested resource is currently executing a command, or is otherwise busy: */
635a2cc190SJeff Kirsher 	CMD_STAT_RESOURCE_BUSY	= 0x06,
645a2cc190SJeff Kirsher 	/* Required capability exceeds device limits: */
655a2cc190SJeff Kirsher 	CMD_STAT_EXCEED_LIM	= 0x08,
665a2cc190SJeff Kirsher 	/* Resource is not in the appropriate state or ownership: */
675a2cc190SJeff Kirsher 	CMD_STAT_BAD_RES_STATE	= 0x09,
685a2cc190SJeff Kirsher 	/* Index out of range: */
695a2cc190SJeff Kirsher 	CMD_STAT_BAD_INDEX	= 0x0a,
705a2cc190SJeff Kirsher 	/* FW image corrupted: */
715a2cc190SJeff Kirsher 	CMD_STAT_BAD_NVMEM	= 0x0b,
725a2cc190SJeff Kirsher 	/* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */
735a2cc190SJeff Kirsher 	CMD_STAT_ICM_ERROR	= 0x0c,
745a2cc190SJeff Kirsher 	/* Attempt to modify a QP/EE which is not in the presumed state: */
755a2cc190SJeff Kirsher 	CMD_STAT_BAD_QP_STATE   = 0x10,
765a2cc190SJeff Kirsher 	/* Bad segment parameters (Address/Size): */
775a2cc190SJeff Kirsher 	CMD_STAT_BAD_SEG_PARAM	= 0x20,
785a2cc190SJeff Kirsher 	/* Memory Region has Memory Windows bound to: */
795a2cc190SJeff Kirsher 	CMD_STAT_REG_BOUND	= 0x21,
805a2cc190SJeff Kirsher 	/* HCA local attached memory not present: */
815a2cc190SJeff Kirsher 	CMD_STAT_LAM_NOT_PRE	= 0x22,
825a2cc190SJeff Kirsher 	/* Bad management packet (silently discarded): */
835a2cc190SJeff Kirsher 	CMD_STAT_BAD_PKT	= 0x30,
845a2cc190SJeff Kirsher 	/* More outstanding CQEs in CQ than new CQ size: */
855a2cc190SJeff Kirsher 	CMD_STAT_BAD_SIZE	= 0x40,
865a2cc190SJeff Kirsher 	/* Multi Function device support required: */
875a2cc190SJeff Kirsher 	CMD_STAT_MULTI_FUNC_REQ	= 0x50,
885a2cc190SJeff Kirsher };
895a2cc190SJeff Kirsher 
905a2cc190SJeff Kirsher enum {
915a2cc190SJeff Kirsher 	HCR_IN_PARAM_OFFSET	= 0x00,
925a2cc190SJeff Kirsher 	HCR_IN_MODIFIER_OFFSET	= 0x08,
935a2cc190SJeff Kirsher 	HCR_OUT_PARAM_OFFSET	= 0x0c,
945a2cc190SJeff Kirsher 	HCR_TOKEN_OFFSET	= 0x14,
955a2cc190SJeff Kirsher 	HCR_STATUS_OFFSET	= 0x18,
965a2cc190SJeff Kirsher 
975a2cc190SJeff Kirsher 	HCR_OPMOD_SHIFT		= 12,
985a2cc190SJeff Kirsher 	HCR_T_BIT		= 21,
995a2cc190SJeff Kirsher 	HCR_E_BIT		= 22,
1005a2cc190SJeff Kirsher 	HCR_GO_BIT		= 23
1015a2cc190SJeff Kirsher };
1025a2cc190SJeff Kirsher 
1035a2cc190SJeff Kirsher enum {
1045a2cc190SJeff Kirsher 	GO_BIT_TIMEOUT_MSECS	= 10000
1055a2cc190SJeff Kirsher };
1065a2cc190SJeff Kirsher 
1075a2cc190SJeff Kirsher struct mlx4_cmd_context {
1085a2cc190SJeff Kirsher 	struct completion	done;
1095a2cc190SJeff Kirsher 	int			result;
1105a2cc190SJeff Kirsher 	int			next;
1115a2cc190SJeff Kirsher 	u64			out_param;
1125a2cc190SJeff Kirsher 	u16			token;
1135a2cc190SJeff Kirsher };
1145a2cc190SJeff Kirsher 
1155a2cc190SJeff Kirsher static int mlx4_status_to_errno(u8 status)
1165a2cc190SJeff Kirsher {
1175a2cc190SJeff Kirsher 	static const int trans_table[] = {
1185a2cc190SJeff Kirsher 		[CMD_STAT_INTERNAL_ERR]	  = -EIO,
1195a2cc190SJeff Kirsher 		[CMD_STAT_BAD_OP]	  = -EPERM,
1205a2cc190SJeff Kirsher 		[CMD_STAT_BAD_PARAM]	  = -EINVAL,
1215a2cc190SJeff Kirsher 		[CMD_STAT_BAD_SYS_STATE]  = -ENXIO,
1225a2cc190SJeff Kirsher 		[CMD_STAT_BAD_RESOURCE]	  = -EBADF,
1235a2cc190SJeff Kirsher 		[CMD_STAT_RESOURCE_BUSY]  = -EBUSY,
1245a2cc190SJeff Kirsher 		[CMD_STAT_EXCEED_LIM]	  = -ENOMEM,
1255a2cc190SJeff Kirsher 		[CMD_STAT_BAD_RES_STATE]  = -EBADF,
1265a2cc190SJeff Kirsher 		[CMD_STAT_BAD_INDEX]	  = -EBADF,
1275a2cc190SJeff Kirsher 		[CMD_STAT_BAD_NVMEM]	  = -EFAULT,
1285a2cc190SJeff Kirsher 		[CMD_STAT_ICM_ERROR]	  = -ENFILE,
1295a2cc190SJeff Kirsher 		[CMD_STAT_BAD_QP_STATE]   = -EINVAL,
1305a2cc190SJeff Kirsher 		[CMD_STAT_BAD_SEG_PARAM]  = -EFAULT,
1315a2cc190SJeff Kirsher 		[CMD_STAT_REG_BOUND]	  = -EBUSY,
1325a2cc190SJeff Kirsher 		[CMD_STAT_LAM_NOT_PRE]	  = -EAGAIN,
1335a2cc190SJeff Kirsher 		[CMD_STAT_BAD_PKT]	  = -EINVAL,
1345a2cc190SJeff Kirsher 		[CMD_STAT_BAD_SIZE]	  = -ENOMEM,
1355a2cc190SJeff Kirsher 		[CMD_STAT_MULTI_FUNC_REQ] = -EACCES,
1365a2cc190SJeff Kirsher 	};
1375a2cc190SJeff Kirsher 
1385a2cc190SJeff Kirsher 	if (status >= ARRAY_SIZE(trans_table) ||
1395a2cc190SJeff Kirsher 	    (status != CMD_STAT_OK && trans_table[status] == 0))
1405a2cc190SJeff Kirsher 		return -EIO;
1415a2cc190SJeff Kirsher 
1425a2cc190SJeff Kirsher 	return trans_table[status];
1435a2cc190SJeff Kirsher }
1445a2cc190SJeff Kirsher 
1455a2cc190SJeff Kirsher static int cmd_pending(struct mlx4_dev *dev)
1465a2cc190SJeff Kirsher {
1475a2cc190SJeff Kirsher 	u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
1485a2cc190SJeff Kirsher 
1495a2cc190SJeff Kirsher 	return (status & swab32(1 << HCR_GO_BIT)) ||
1505a2cc190SJeff Kirsher 		(mlx4_priv(dev)->cmd.toggle ==
1515a2cc190SJeff Kirsher 		 !!(status & swab32(1 << HCR_T_BIT)));
1525a2cc190SJeff Kirsher }
1535a2cc190SJeff Kirsher 
1545a2cc190SJeff Kirsher static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
1555a2cc190SJeff Kirsher 			 u32 in_modifier, u8 op_modifier, u16 op, u16 token,
1565a2cc190SJeff Kirsher 			 int event)
1575a2cc190SJeff Kirsher {
1585a2cc190SJeff Kirsher 	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
1595a2cc190SJeff Kirsher 	u32 __iomem *hcr = cmd->hcr;
1605a2cc190SJeff Kirsher 	int ret = -EAGAIN;
1615a2cc190SJeff Kirsher 	unsigned long end;
1625a2cc190SJeff Kirsher 
1635a2cc190SJeff Kirsher 	mutex_lock(&cmd->hcr_mutex);
1645a2cc190SJeff Kirsher 
1655a2cc190SJeff Kirsher 	end = jiffies;
1665a2cc190SJeff Kirsher 	if (event)
1675a2cc190SJeff Kirsher 		end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
1685a2cc190SJeff Kirsher 
1695a2cc190SJeff Kirsher 	while (cmd_pending(dev)) {
1705a2cc190SJeff Kirsher 		if (time_after_eq(jiffies, end))
1715a2cc190SJeff Kirsher 			goto out;
1725a2cc190SJeff Kirsher 		cond_resched();
1735a2cc190SJeff Kirsher 	}
1745a2cc190SJeff Kirsher 
1755a2cc190SJeff Kirsher 	/*
1765a2cc190SJeff Kirsher 	 * We use writel (instead of something like memcpy_toio)
1775a2cc190SJeff Kirsher 	 * because writes of less than 32 bits to the HCR don't work
1785a2cc190SJeff Kirsher 	 * (and some architectures such as ia64 implement memcpy_toio
1795a2cc190SJeff Kirsher 	 * in terms of writeb).
1805a2cc190SJeff Kirsher 	 */
1815a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),		  hcr + 0);
1825a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  hcr + 1);
1835a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32(in_modifier),		  hcr + 2);
1845a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),	  hcr + 3);
1855a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4);
1865a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32(token << 16),		  hcr + 5);
1875a2cc190SJeff Kirsher 
1885a2cc190SJeff Kirsher 	/* __raw_writel may not order writes. */
1895a2cc190SJeff Kirsher 	wmb();
1905a2cc190SJeff Kirsher 
1915a2cc190SJeff Kirsher 	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)		|
1925a2cc190SJeff Kirsher 					       (cmd->toggle << HCR_T_BIT)	|
1935a2cc190SJeff Kirsher 					       (event ? (1 << HCR_E_BIT) : 0)	|
1945a2cc190SJeff Kirsher 					       (op_modifier << HCR_OPMOD_SHIFT) |
1955a2cc190SJeff Kirsher 					       op),			  hcr + 6);
1965a2cc190SJeff Kirsher 
1975a2cc190SJeff Kirsher 	/*
1985a2cc190SJeff Kirsher 	 * Make sure that our HCR writes don't get mixed in with
1995a2cc190SJeff Kirsher 	 * writes from another CPU starting a FW command.
2005a2cc190SJeff Kirsher 	 */
2015a2cc190SJeff Kirsher 	mmiowb();
2025a2cc190SJeff Kirsher 
2035a2cc190SJeff Kirsher 	cmd->toggle = cmd->toggle ^ 1;
2045a2cc190SJeff Kirsher 
2055a2cc190SJeff Kirsher 	ret = 0;
2065a2cc190SJeff Kirsher 
2075a2cc190SJeff Kirsher out:
2085a2cc190SJeff Kirsher 	mutex_unlock(&cmd->hcr_mutex);
2095a2cc190SJeff Kirsher 	return ret;
2105a2cc190SJeff Kirsher }
2115a2cc190SJeff Kirsher 
2125a2cc190SJeff Kirsher static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
2135a2cc190SJeff Kirsher 			 int out_is_imm, u32 in_modifier, u8 op_modifier,
2145a2cc190SJeff Kirsher 			 u16 op, unsigned long timeout)
2155a2cc190SJeff Kirsher {
2165a2cc190SJeff Kirsher 	struct mlx4_priv *priv = mlx4_priv(dev);
2175a2cc190SJeff Kirsher 	void __iomem *hcr = priv->cmd.hcr;
2185a2cc190SJeff Kirsher 	int err = 0;
2195a2cc190SJeff Kirsher 	unsigned long end;
2205a2cc190SJeff Kirsher 
2215a2cc190SJeff Kirsher 	down(&priv->cmd.poll_sem);
2225a2cc190SJeff Kirsher 
2235a2cc190SJeff Kirsher 	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
2245a2cc190SJeff Kirsher 			    in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
2255a2cc190SJeff Kirsher 	if (err)
2265a2cc190SJeff Kirsher 		goto out;
2275a2cc190SJeff Kirsher 
2285a2cc190SJeff Kirsher 	end = msecs_to_jiffies(timeout) + jiffies;
2295a2cc190SJeff Kirsher 	while (cmd_pending(dev) && time_before(jiffies, end))
2305a2cc190SJeff Kirsher 		cond_resched();
2315a2cc190SJeff Kirsher 
2325a2cc190SJeff Kirsher 	if (cmd_pending(dev)) {
2335a2cc190SJeff Kirsher 		err = -ETIMEDOUT;
2345a2cc190SJeff Kirsher 		goto out;
2355a2cc190SJeff Kirsher 	}
2365a2cc190SJeff Kirsher 
2375a2cc190SJeff Kirsher 	if (out_is_imm)
2385a2cc190SJeff Kirsher 		*out_param =
2395a2cc190SJeff Kirsher 			(u64) be32_to_cpu((__force __be32)
2405a2cc190SJeff Kirsher 					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
2415a2cc190SJeff Kirsher 			(u64) be32_to_cpu((__force __be32)
2425a2cc190SJeff Kirsher 					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4));
2435a2cc190SJeff Kirsher 
2445a2cc190SJeff Kirsher 	err = mlx4_status_to_errno(be32_to_cpu((__force __be32)
2455a2cc190SJeff Kirsher 					       __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24);
2465a2cc190SJeff Kirsher 
2475a2cc190SJeff Kirsher out:
2485a2cc190SJeff Kirsher 	up(&priv->cmd.poll_sem);
2495a2cc190SJeff Kirsher 	return err;
2505a2cc190SJeff Kirsher }
2515a2cc190SJeff Kirsher 
2525a2cc190SJeff Kirsher void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
2535a2cc190SJeff Kirsher {
2545a2cc190SJeff Kirsher 	struct mlx4_priv *priv = mlx4_priv(dev);
2555a2cc190SJeff Kirsher 	struct mlx4_cmd_context *context =
2565a2cc190SJeff Kirsher 		&priv->cmd.context[token & priv->cmd.token_mask];
2575a2cc190SJeff Kirsher 
2585a2cc190SJeff Kirsher 	/* previously timed out command completing at long last */
2595a2cc190SJeff Kirsher 	if (token != context->token)
2605a2cc190SJeff Kirsher 		return;
2615a2cc190SJeff Kirsher 
2625a2cc190SJeff Kirsher 	context->result    = mlx4_status_to_errno(status);
2635a2cc190SJeff Kirsher 	context->out_param = out_param;
2645a2cc190SJeff Kirsher 
2655a2cc190SJeff Kirsher 	complete(&context->done);
2665a2cc190SJeff Kirsher }
2675a2cc190SJeff Kirsher 
2685a2cc190SJeff Kirsher static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
2695a2cc190SJeff Kirsher 			 int out_is_imm, u32 in_modifier, u8 op_modifier,
2705a2cc190SJeff Kirsher 			 u16 op, unsigned long timeout)
2715a2cc190SJeff Kirsher {
2725a2cc190SJeff Kirsher 	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
2735a2cc190SJeff Kirsher 	struct mlx4_cmd_context *context;
2745a2cc190SJeff Kirsher 	int err = 0;
2755a2cc190SJeff Kirsher 
2765a2cc190SJeff Kirsher 	down(&cmd->event_sem);
2775a2cc190SJeff Kirsher 
2785a2cc190SJeff Kirsher 	spin_lock(&cmd->context_lock);
2795a2cc190SJeff Kirsher 	BUG_ON(cmd->free_head < 0);
2805a2cc190SJeff Kirsher 	context = &cmd->context[cmd->free_head];
2815a2cc190SJeff Kirsher 	context->token += cmd->token_mask + 1;
2825a2cc190SJeff Kirsher 	cmd->free_head = context->next;
2835a2cc190SJeff Kirsher 	spin_unlock(&cmd->context_lock);
2845a2cc190SJeff Kirsher 
2855a2cc190SJeff Kirsher 	init_completion(&context->done);
2865a2cc190SJeff Kirsher 
2875a2cc190SJeff Kirsher 	mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
2885a2cc190SJeff Kirsher 		      in_modifier, op_modifier, op, context->token, 1);
2895a2cc190SJeff Kirsher 
2905a2cc190SJeff Kirsher 	if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) {
2915a2cc190SJeff Kirsher 		err = -EBUSY;
2925a2cc190SJeff Kirsher 		goto out;
2935a2cc190SJeff Kirsher 	}
2945a2cc190SJeff Kirsher 
2955a2cc190SJeff Kirsher 	err = context->result;
2965a2cc190SJeff Kirsher 	if (err)
2975a2cc190SJeff Kirsher 		goto out;
2985a2cc190SJeff Kirsher 
2995a2cc190SJeff Kirsher 	if (out_is_imm)
3005a2cc190SJeff Kirsher 		*out_param = context->out_param;
3015a2cc190SJeff Kirsher 
3025a2cc190SJeff Kirsher out:
3035a2cc190SJeff Kirsher 	spin_lock(&cmd->context_lock);
3045a2cc190SJeff Kirsher 	context->next = cmd->free_head;
3055a2cc190SJeff Kirsher 	cmd->free_head = context - cmd->context;
3065a2cc190SJeff Kirsher 	spin_unlock(&cmd->context_lock);
3075a2cc190SJeff Kirsher 
3085a2cc190SJeff Kirsher 	up(&cmd->event_sem);
3095a2cc190SJeff Kirsher 	return err;
3105a2cc190SJeff Kirsher }
3115a2cc190SJeff Kirsher 
3125a2cc190SJeff Kirsher int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
3135a2cc190SJeff Kirsher 	       int out_is_imm, u32 in_modifier, u8 op_modifier,
314*f9baff50SJack Morgenstein 	       u16 op, unsigned long timeout, int native)
3155a2cc190SJeff Kirsher {
3165a2cc190SJeff Kirsher 	if (mlx4_priv(dev)->cmd.use_events)
3175a2cc190SJeff Kirsher 		return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm,
3185a2cc190SJeff Kirsher 				     in_modifier, op_modifier, op, timeout);
3195a2cc190SJeff Kirsher 	else
3205a2cc190SJeff Kirsher 		return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm,
3215a2cc190SJeff Kirsher 				     in_modifier, op_modifier, op, timeout);
3225a2cc190SJeff Kirsher }
3235a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(__mlx4_cmd);
3245a2cc190SJeff Kirsher 
3255a2cc190SJeff Kirsher int mlx4_cmd_init(struct mlx4_dev *dev)
3265a2cc190SJeff Kirsher {
3275a2cc190SJeff Kirsher 	struct mlx4_priv *priv = mlx4_priv(dev);
3285a2cc190SJeff Kirsher 
3295a2cc190SJeff Kirsher 	mutex_init(&priv->cmd.hcr_mutex);
3305a2cc190SJeff Kirsher 	sema_init(&priv->cmd.poll_sem, 1);
3315a2cc190SJeff Kirsher 	priv->cmd.use_events = 0;
3325a2cc190SJeff Kirsher 	priv->cmd.toggle     = 1;
3335a2cc190SJeff Kirsher 
3345a2cc190SJeff Kirsher 	priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_HCR_BASE,
3355a2cc190SJeff Kirsher 				MLX4_HCR_SIZE);
3365a2cc190SJeff Kirsher 	if (!priv->cmd.hcr) {
3375a2cc190SJeff Kirsher 		mlx4_err(dev, "Couldn't map command register.");
3385a2cc190SJeff Kirsher 		return -ENOMEM;
3395a2cc190SJeff Kirsher 	}
3405a2cc190SJeff Kirsher 
3415a2cc190SJeff Kirsher 	priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
3425a2cc190SJeff Kirsher 					 MLX4_MAILBOX_SIZE,
3435a2cc190SJeff Kirsher 					 MLX4_MAILBOX_SIZE, 0);
3445a2cc190SJeff Kirsher 	if (!priv->cmd.pool) {
3455a2cc190SJeff Kirsher 		iounmap(priv->cmd.hcr);
3465a2cc190SJeff Kirsher 		return -ENOMEM;
3475a2cc190SJeff Kirsher 	}
3485a2cc190SJeff Kirsher 
3495a2cc190SJeff Kirsher 	return 0;
3505a2cc190SJeff Kirsher }
3515a2cc190SJeff Kirsher 
3525a2cc190SJeff Kirsher void mlx4_cmd_cleanup(struct mlx4_dev *dev)
3535a2cc190SJeff Kirsher {
3545a2cc190SJeff Kirsher 	struct mlx4_priv *priv = mlx4_priv(dev);
3555a2cc190SJeff Kirsher 
3565a2cc190SJeff Kirsher 	pci_pool_destroy(priv->cmd.pool);
3575a2cc190SJeff Kirsher 	iounmap(priv->cmd.hcr);
3585a2cc190SJeff Kirsher }
3595a2cc190SJeff Kirsher 
3605a2cc190SJeff Kirsher /*
3615a2cc190SJeff Kirsher  * Switch to using events to issue FW commands (can only be called
3625a2cc190SJeff Kirsher  * after event queue for command events has been initialized).
3635a2cc190SJeff Kirsher  */
3645a2cc190SJeff Kirsher int mlx4_cmd_use_events(struct mlx4_dev *dev)
3655a2cc190SJeff Kirsher {
3665a2cc190SJeff Kirsher 	struct mlx4_priv *priv = mlx4_priv(dev);
3675a2cc190SJeff Kirsher 	int i;
3685a2cc190SJeff Kirsher 
3695a2cc190SJeff Kirsher 	priv->cmd.context = kmalloc(priv->cmd.max_cmds *
3705a2cc190SJeff Kirsher 				   sizeof (struct mlx4_cmd_context),
3715a2cc190SJeff Kirsher 				   GFP_KERNEL);
3725a2cc190SJeff Kirsher 	if (!priv->cmd.context)
3735a2cc190SJeff Kirsher 		return -ENOMEM;
3745a2cc190SJeff Kirsher 
3755a2cc190SJeff Kirsher 	for (i = 0; i < priv->cmd.max_cmds; ++i) {
3765a2cc190SJeff Kirsher 		priv->cmd.context[i].token = i;
3775a2cc190SJeff Kirsher 		priv->cmd.context[i].next  = i + 1;
3785a2cc190SJeff Kirsher 	}
3795a2cc190SJeff Kirsher 
3805a2cc190SJeff Kirsher 	priv->cmd.context[priv->cmd.max_cmds - 1].next = -1;
3815a2cc190SJeff Kirsher 	priv->cmd.free_head = 0;
3825a2cc190SJeff Kirsher 
3835a2cc190SJeff Kirsher 	sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds);
3845a2cc190SJeff Kirsher 	spin_lock_init(&priv->cmd.context_lock);
3855a2cc190SJeff Kirsher 
3865a2cc190SJeff Kirsher 	for (priv->cmd.token_mask = 1;
3875a2cc190SJeff Kirsher 	     priv->cmd.token_mask < priv->cmd.max_cmds;
3885a2cc190SJeff Kirsher 	     priv->cmd.token_mask <<= 1)
3895a2cc190SJeff Kirsher 		; /* nothing */
3905a2cc190SJeff Kirsher 	--priv->cmd.token_mask;
3915a2cc190SJeff Kirsher 
3925a2cc190SJeff Kirsher 	priv->cmd.use_events = 1;
3935a2cc190SJeff Kirsher 
3945a2cc190SJeff Kirsher 	down(&priv->cmd.poll_sem);
3955a2cc190SJeff Kirsher 
3965a2cc190SJeff Kirsher 	return 0;
3975a2cc190SJeff Kirsher }
3985a2cc190SJeff Kirsher 
3995a2cc190SJeff Kirsher /*
4005a2cc190SJeff Kirsher  * Switch back to polling (used when shutting down the device)
4015a2cc190SJeff Kirsher  */
4025a2cc190SJeff Kirsher void mlx4_cmd_use_polling(struct mlx4_dev *dev)
4035a2cc190SJeff Kirsher {
4045a2cc190SJeff Kirsher 	struct mlx4_priv *priv = mlx4_priv(dev);
4055a2cc190SJeff Kirsher 	int i;
4065a2cc190SJeff Kirsher 
4075a2cc190SJeff Kirsher 	priv->cmd.use_events = 0;
4085a2cc190SJeff Kirsher 
4095a2cc190SJeff Kirsher 	for (i = 0; i < priv->cmd.max_cmds; ++i)
4105a2cc190SJeff Kirsher 		down(&priv->cmd.event_sem);
4115a2cc190SJeff Kirsher 
4125a2cc190SJeff Kirsher 	kfree(priv->cmd.context);
4135a2cc190SJeff Kirsher 
4145a2cc190SJeff Kirsher 	up(&priv->cmd.poll_sem);
4155a2cc190SJeff Kirsher }
4165a2cc190SJeff Kirsher 
4175a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
4185a2cc190SJeff Kirsher {
4195a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
4205a2cc190SJeff Kirsher 
4215a2cc190SJeff Kirsher 	mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL);
4225a2cc190SJeff Kirsher 	if (!mailbox)
4235a2cc190SJeff Kirsher 		return ERR_PTR(-ENOMEM);
4245a2cc190SJeff Kirsher 
4255a2cc190SJeff Kirsher 	mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL,
4265a2cc190SJeff Kirsher 				      &mailbox->dma);
4275a2cc190SJeff Kirsher 	if (!mailbox->buf) {
4285a2cc190SJeff Kirsher 		kfree(mailbox);
4295a2cc190SJeff Kirsher 		return ERR_PTR(-ENOMEM);
4305a2cc190SJeff Kirsher 	}
4315a2cc190SJeff Kirsher 
4325a2cc190SJeff Kirsher 	return mailbox;
4335a2cc190SJeff Kirsher }
4345a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
4355a2cc190SJeff Kirsher 
4365a2cc190SJeff Kirsher void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox)
4375a2cc190SJeff Kirsher {
4385a2cc190SJeff Kirsher 	if (!mailbox)
4395a2cc190SJeff Kirsher 		return;
4405a2cc190SJeff Kirsher 
4415a2cc190SJeff Kirsher 	pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma);
4425a2cc190SJeff Kirsher 	kfree(mailbox);
4435a2cc190SJeff Kirsher }
4445a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox);
445