162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/completion.h>
3662306a36Sopenharmony_ci#include <linux/pci.h>
3762306a36Sopenharmony_ci#include <linux/errno.h>
3862306a36Sopenharmony_ci#include <linux/sched.h>
3962306a36Sopenharmony_ci#include <linux/module.h>
4062306a36Sopenharmony_ci#include <linux/slab.h>
4162306a36Sopenharmony_ci#include <asm/io.h>
4262306a36Sopenharmony_ci#include <rdma/ib_mad.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include "mthca_dev.h"
4562306a36Sopenharmony_ci#include "mthca_config_reg.h"
4662306a36Sopenharmony_ci#include "mthca_cmd.h"
4762306a36Sopenharmony_ci#include "mthca_memfree.h"
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define CMD_POLL_TOKEN 0xffff
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum {
5262306a36Sopenharmony_ci	HCR_IN_PARAM_OFFSET    = 0x00,
5362306a36Sopenharmony_ci	HCR_IN_MODIFIER_OFFSET = 0x08,
5462306a36Sopenharmony_ci	HCR_OUT_PARAM_OFFSET   = 0x0c,
5562306a36Sopenharmony_ci	HCR_TOKEN_OFFSET       = 0x14,
5662306a36Sopenharmony_ci	HCR_STATUS_OFFSET      = 0x18,
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	HCR_OPMOD_SHIFT        = 12,
5962306a36Sopenharmony_ci	HCA_E_BIT              = 22,
6062306a36Sopenharmony_ci	HCR_GO_BIT             = 23
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cienum {
6462306a36Sopenharmony_ci	/* initialization and general commands */
6562306a36Sopenharmony_ci	CMD_SYS_EN          = 0x1,
6662306a36Sopenharmony_ci	CMD_SYS_DIS         = 0x2,
6762306a36Sopenharmony_ci	CMD_MAP_FA          = 0xfff,
6862306a36Sopenharmony_ci	CMD_UNMAP_FA        = 0xffe,
6962306a36Sopenharmony_ci	CMD_RUN_FW          = 0xff6,
7062306a36Sopenharmony_ci	CMD_MOD_STAT_CFG    = 0x34,
7162306a36Sopenharmony_ci	CMD_QUERY_DEV_LIM   = 0x3,
7262306a36Sopenharmony_ci	CMD_QUERY_FW        = 0x4,
7362306a36Sopenharmony_ci	CMD_ENABLE_LAM      = 0xff8,
7462306a36Sopenharmony_ci	CMD_DISABLE_LAM     = 0xff7,
7562306a36Sopenharmony_ci	CMD_QUERY_DDR       = 0x5,
7662306a36Sopenharmony_ci	CMD_QUERY_ADAPTER   = 0x6,
7762306a36Sopenharmony_ci	CMD_INIT_HCA        = 0x7,
7862306a36Sopenharmony_ci	CMD_CLOSE_HCA       = 0x8,
7962306a36Sopenharmony_ci	CMD_INIT_IB         = 0x9,
8062306a36Sopenharmony_ci	CMD_CLOSE_IB        = 0xa,
8162306a36Sopenharmony_ci	CMD_QUERY_HCA       = 0xb,
8262306a36Sopenharmony_ci	CMD_SET_IB          = 0xc,
8362306a36Sopenharmony_ci	CMD_ACCESS_DDR      = 0x2e,
8462306a36Sopenharmony_ci	CMD_MAP_ICM         = 0xffa,
8562306a36Sopenharmony_ci	CMD_UNMAP_ICM       = 0xff9,
8662306a36Sopenharmony_ci	CMD_MAP_ICM_AUX     = 0xffc,
8762306a36Sopenharmony_ci	CMD_UNMAP_ICM_AUX   = 0xffb,
8862306a36Sopenharmony_ci	CMD_SET_ICM_SIZE    = 0xffd,
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* TPT commands */
9162306a36Sopenharmony_ci	CMD_SW2HW_MPT 	    = 0xd,
9262306a36Sopenharmony_ci	CMD_QUERY_MPT 	    = 0xe,
9362306a36Sopenharmony_ci	CMD_HW2SW_MPT 	    = 0xf,
9462306a36Sopenharmony_ci	CMD_READ_MTT        = 0x10,
9562306a36Sopenharmony_ci	CMD_WRITE_MTT       = 0x11,
9662306a36Sopenharmony_ci	CMD_SYNC_TPT        = 0x2f,
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* EQ commands */
9962306a36Sopenharmony_ci	CMD_MAP_EQ          = 0x12,
10062306a36Sopenharmony_ci	CMD_SW2HW_EQ 	    = 0x13,
10162306a36Sopenharmony_ci	CMD_HW2SW_EQ 	    = 0x14,
10262306a36Sopenharmony_ci	CMD_QUERY_EQ        = 0x15,
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* CQ commands */
10562306a36Sopenharmony_ci	CMD_SW2HW_CQ 	    = 0x16,
10662306a36Sopenharmony_ci	CMD_HW2SW_CQ 	    = 0x17,
10762306a36Sopenharmony_ci	CMD_QUERY_CQ 	    = 0x18,
10862306a36Sopenharmony_ci	CMD_RESIZE_CQ       = 0x2c,
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* SRQ commands */
11162306a36Sopenharmony_ci	CMD_SW2HW_SRQ 	    = 0x35,
11262306a36Sopenharmony_ci	CMD_HW2SW_SRQ 	    = 0x36,
11362306a36Sopenharmony_ci	CMD_QUERY_SRQ       = 0x37,
11462306a36Sopenharmony_ci	CMD_ARM_SRQ         = 0x40,
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* QP/EE commands */
11762306a36Sopenharmony_ci	CMD_RST2INIT_QPEE   = 0x19,
11862306a36Sopenharmony_ci	CMD_INIT2RTR_QPEE   = 0x1a,
11962306a36Sopenharmony_ci	CMD_RTR2RTS_QPEE    = 0x1b,
12062306a36Sopenharmony_ci	CMD_RTS2RTS_QPEE    = 0x1c,
12162306a36Sopenharmony_ci	CMD_SQERR2RTS_QPEE  = 0x1d,
12262306a36Sopenharmony_ci	CMD_2ERR_QPEE       = 0x1e,
12362306a36Sopenharmony_ci	CMD_RTS2SQD_QPEE    = 0x1f,
12462306a36Sopenharmony_ci	CMD_SQD2SQD_QPEE    = 0x38,
12562306a36Sopenharmony_ci	CMD_SQD2RTS_QPEE    = 0x20,
12662306a36Sopenharmony_ci	CMD_ERR2RST_QPEE    = 0x21,
12762306a36Sopenharmony_ci	CMD_QUERY_QPEE      = 0x22,
12862306a36Sopenharmony_ci	CMD_INIT2INIT_QPEE  = 0x2d,
12962306a36Sopenharmony_ci	CMD_SUSPEND_QPEE    = 0x32,
13062306a36Sopenharmony_ci	CMD_UNSUSPEND_QPEE  = 0x33,
13162306a36Sopenharmony_ci	/* special QPs and management commands */
13262306a36Sopenharmony_ci	CMD_CONF_SPECIAL_QP = 0x23,
13362306a36Sopenharmony_ci	CMD_MAD_IFC         = 0x24,
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* multicast commands */
13662306a36Sopenharmony_ci	CMD_READ_MGM        = 0x25,
13762306a36Sopenharmony_ci	CMD_WRITE_MGM       = 0x26,
13862306a36Sopenharmony_ci	CMD_MGID_HASH       = 0x27,
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* miscellaneous commands */
14162306a36Sopenharmony_ci	CMD_DIAG_RPRT       = 0x30,
14262306a36Sopenharmony_ci	CMD_NOP             = 0x31,
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* debug commands */
14562306a36Sopenharmony_ci	CMD_QUERY_DEBUG_MSG = 0x2a,
14662306a36Sopenharmony_ci	CMD_SET_DEBUG_MSG   = 0x2b,
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/*
15062306a36Sopenharmony_ci * According to Mellanox code, FW may be starved and never complete
15162306a36Sopenharmony_ci * commands.  So we can't use strict timeouts described in PRM -- we
15262306a36Sopenharmony_ci * just arbitrarily select 60 seconds for now.
15362306a36Sopenharmony_ci */
15462306a36Sopenharmony_ci#if 0
15562306a36Sopenharmony_ci/*
15662306a36Sopenharmony_ci * Round up and add 1 to make sure we get the full wait time (since we
15762306a36Sopenharmony_ci * will be starting in the middle of a jiffy)
15862306a36Sopenharmony_ci */
15962306a36Sopenharmony_cienum {
16062306a36Sopenharmony_ci	CMD_TIME_CLASS_A = (HZ + 999) / 1000 + 1,
16162306a36Sopenharmony_ci	CMD_TIME_CLASS_B = (HZ +  99) /  100 + 1,
16262306a36Sopenharmony_ci	CMD_TIME_CLASS_C = (HZ +   9) /   10 + 1,
16362306a36Sopenharmony_ci	CMD_TIME_CLASS_D = 60 * HZ
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci#else
16662306a36Sopenharmony_cienum {
16762306a36Sopenharmony_ci	CMD_TIME_CLASS_A = 60 * HZ,
16862306a36Sopenharmony_ci	CMD_TIME_CLASS_B = 60 * HZ,
16962306a36Sopenharmony_ci	CMD_TIME_CLASS_C = 60 * HZ,
17062306a36Sopenharmony_ci	CMD_TIME_CLASS_D = 60 * HZ
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci#endif
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cienum {
17562306a36Sopenharmony_ci	GO_BIT_TIMEOUT = HZ * 10
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistruct mthca_cmd_context {
17962306a36Sopenharmony_ci	struct completion done;
18062306a36Sopenharmony_ci	int               result;
18162306a36Sopenharmony_ci	int               next;
18262306a36Sopenharmony_ci	u64               out_param;
18362306a36Sopenharmony_ci	u16               token;
18462306a36Sopenharmony_ci	u8                status;
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int fw_cmd_doorbell = 0;
18862306a36Sopenharmony_cimodule_param(fw_cmd_doorbell, int, 0644);
18962306a36Sopenharmony_ciMODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
19062306a36Sopenharmony_ci		 "(and supported by FW)");
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic inline int go_bit(struct mthca_dev *dev)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return readl(dev->hcr + HCR_STATUS_OFFSET) &
19562306a36Sopenharmony_ci		swab32(1 << HCR_GO_BIT);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic void mthca_cmd_post_dbell(struct mthca_dev *dev,
19962306a36Sopenharmony_ci				 u64 in_param,
20062306a36Sopenharmony_ci				 u64 out_param,
20162306a36Sopenharmony_ci				 u32 in_modifier,
20262306a36Sopenharmony_ci				 u8 op_modifier,
20362306a36Sopenharmony_ci				 u16 op,
20462306a36Sopenharmony_ci				 u16 token)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	void __iomem *ptr = dev->cmd.dbell_map;
20762306a36Sopenharmony_ci	u16 *offs = dev->cmd.dbell_offsets;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),           ptr + offs[0]);
21062306a36Sopenharmony_ci	wmb();
21162306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  ptr + offs[1]);
21262306a36Sopenharmony_ci	wmb();
21362306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_modifier),              ptr + offs[2]);
21462306a36Sopenharmony_ci	wmb();
21562306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),          ptr + offs[3]);
21662306a36Sopenharmony_ci	wmb();
21762306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]);
21862306a36Sopenharmony_ci	wmb();
21962306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(token << 16),              ptr + offs[5]);
22062306a36Sopenharmony_ci	wmb();
22162306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
22262306a36Sopenharmony_ci					       (1 << HCA_E_BIT)                 |
22362306a36Sopenharmony_ci					       (op_modifier << HCR_OPMOD_SHIFT) |
22462306a36Sopenharmony_ci						op),			  ptr + offs[6]);
22562306a36Sopenharmony_ci	wmb();
22662306a36Sopenharmony_ci	__raw_writel((__force u32) 0,                                     ptr + offs[7]);
22762306a36Sopenharmony_ci	wmb();
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int mthca_cmd_post_hcr(struct mthca_dev *dev,
23162306a36Sopenharmony_ci			      u64 in_param,
23262306a36Sopenharmony_ci			      u64 out_param,
23362306a36Sopenharmony_ci			      u32 in_modifier,
23462306a36Sopenharmony_ci			      u8 op_modifier,
23562306a36Sopenharmony_ci			      u16 op,
23662306a36Sopenharmony_ci			      u16 token,
23762306a36Sopenharmony_ci			      int event)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	if (event) {
24062306a36Sopenharmony_ci		unsigned long end = jiffies + GO_BIT_TIMEOUT;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		while (go_bit(dev) && time_before(jiffies, end)) {
24362306a36Sopenharmony_ci			set_current_state(TASK_RUNNING);
24462306a36Sopenharmony_ci			schedule();
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (go_bit(dev))
24962306a36Sopenharmony_ci		return -EAGAIN;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * We use writel (instead of something like memcpy_toio)
25362306a36Sopenharmony_ci	 * because writes of less than 32 bits to the HCR don't work
25462306a36Sopenharmony_ci	 * (and some architectures such as ia64 implement memcpy_toio
25562306a36Sopenharmony_ci	 * in terms of writeb).
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),           dev->hcr + 0 * 4);
25862306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  dev->hcr + 1 * 4);
25962306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_modifier),              dev->hcr + 2 * 4);
26062306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),          dev->hcr + 3 * 4);
26162306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), dev->hcr + 4 * 4);
26262306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(token << 16),              dev->hcr + 5 * 4);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/* __raw_writel may not order writes. */
26562306a36Sopenharmony_ci	wmb();
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
26862306a36Sopenharmony_ci					       (event ? (1 << HCA_E_BIT) : 0)   |
26962306a36Sopenharmony_ci					       (op_modifier << HCR_OPMOD_SHIFT) |
27062306a36Sopenharmony_ci					       op),                       dev->hcr + 6 * 4);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return 0;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic int mthca_cmd_post(struct mthca_dev *dev,
27662306a36Sopenharmony_ci			  u64 in_param,
27762306a36Sopenharmony_ci			  u64 out_param,
27862306a36Sopenharmony_ci			  u32 in_modifier,
27962306a36Sopenharmony_ci			  u8 op_modifier,
28062306a36Sopenharmony_ci			  u16 op,
28162306a36Sopenharmony_ci			  u16 token,
28262306a36Sopenharmony_ci			  int event)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	int err = 0;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	mutex_lock(&dev->cmd.hcr_mutex);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell)
28962306a36Sopenharmony_ci		mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
29062306a36Sopenharmony_ci					   op_modifier, op, token);
29162306a36Sopenharmony_ci	else
29262306a36Sopenharmony_ci		err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
29362306a36Sopenharmony_ci					 op_modifier, op, token, event);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	mutex_unlock(&dev->cmd.hcr_mutex);
29662306a36Sopenharmony_ci	return err;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int mthca_status_to_errno(u8 status)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	static const int trans_table[] = {
30362306a36Sopenharmony_ci		[MTHCA_CMD_STAT_INTERNAL_ERR]   = -EIO,
30462306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_OP]         = -EPERM,
30562306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_PARAM]      = -EINVAL,
30662306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_SYS_STATE]  = -ENXIO,
30762306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_RESOURCE]   = -EBADF,
30862306a36Sopenharmony_ci		[MTHCA_CMD_STAT_RESOURCE_BUSY]  = -EBUSY,
30962306a36Sopenharmony_ci		[MTHCA_CMD_STAT_DDR_MEM_ERR]    = -ENOMEM,
31062306a36Sopenharmony_ci		[MTHCA_CMD_STAT_EXCEED_LIM]     = -ENOMEM,
31162306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_RES_STATE]  = -EBADF,
31262306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_INDEX]      = -EBADF,
31362306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_NVMEM]      = -EFAULT,
31462306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_QPEE_STATE] = -EINVAL,
31562306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_SEG_PARAM]  = -EFAULT,
31662306a36Sopenharmony_ci		[MTHCA_CMD_STAT_REG_BOUND]      = -EBUSY,
31762306a36Sopenharmony_ci		[MTHCA_CMD_STAT_LAM_NOT_PRE]    = -EAGAIN,
31862306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_PKT]        = -EBADMSG,
31962306a36Sopenharmony_ci		[MTHCA_CMD_STAT_BAD_SIZE]       = -ENOMEM,
32062306a36Sopenharmony_ci	};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (status >= ARRAY_SIZE(trans_table) ||
32362306a36Sopenharmony_ci			(status != MTHCA_CMD_STAT_OK
32462306a36Sopenharmony_ci			 && trans_table[status] == 0))
32562306a36Sopenharmony_ci		return -EINVAL;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return trans_table[status];
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic int mthca_cmd_poll(struct mthca_dev *dev,
33262306a36Sopenharmony_ci			  u64 in_param,
33362306a36Sopenharmony_ci			  u64 *out_param,
33462306a36Sopenharmony_ci			  int out_is_imm,
33562306a36Sopenharmony_ci			  u32 in_modifier,
33662306a36Sopenharmony_ci			  u8 op_modifier,
33762306a36Sopenharmony_ci			  u16 op,
33862306a36Sopenharmony_ci			  unsigned long timeout)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	int err = 0;
34162306a36Sopenharmony_ci	unsigned long end;
34262306a36Sopenharmony_ci	u8 status;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	down(&dev->cmd.poll_sem);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	err = mthca_cmd_post(dev, in_param,
34762306a36Sopenharmony_ci			     out_param ? *out_param : 0,
34862306a36Sopenharmony_ci			     in_modifier, op_modifier,
34962306a36Sopenharmony_ci			     op, CMD_POLL_TOKEN, 0);
35062306a36Sopenharmony_ci	if (err)
35162306a36Sopenharmony_ci		goto out;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	end = timeout + jiffies;
35462306a36Sopenharmony_ci	while (go_bit(dev) && time_before(jiffies, end)) {
35562306a36Sopenharmony_ci		set_current_state(TASK_RUNNING);
35662306a36Sopenharmony_ci		schedule();
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (go_bit(dev)) {
36062306a36Sopenharmony_ci		err = -EBUSY;
36162306a36Sopenharmony_ci		goto out;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (out_is_imm && out_param) {
36562306a36Sopenharmony_ci		*out_param =
36662306a36Sopenharmony_ci			(u64) be32_to_cpu((__force __be32)
36762306a36Sopenharmony_ci					  __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
36862306a36Sopenharmony_ci			(u64) be32_to_cpu((__force __be32)
36962306a36Sopenharmony_ci					  __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET + 4));
37062306a36Sopenharmony_ci	} else if (out_is_imm) {
37162306a36Sopenharmony_ci		err = -EINVAL;
37262306a36Sopenharmony_ci		goto out;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	status = be32_to_cpu((__force __be32) __raw_readl(dev->hcr + HCR_STATUS_OFFSET)) >> 24;
37662306a36Sopenharmony_ci	if (status) {
37762306a36Sopenharmony_ci		mthca_dbg(dev, "Command %02x completed with status %02x\n",
37862306a36Sopenharmony_ci			  op, status);
37962306a36Sopenharmony_ci		err = mthca_status_to_errno(status);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ciout:
38362306a36Sopenharmony_ci	up(&dev->cmd.poll_sem);
38462306a36Sopenharmony_ci	return err;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_civoid mthca_cmd_event(struct mthca_dev *dev,
38862306a36Sopenharmony_ci		     u16 token,
38962306a36Sopenharmony_ci		     u8  status,
39062306a36Sopenharmony_ci		     u64 out_param)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct mthca_cmd_context *context =
39362306a36Sopenharmony_ci		&dev->cmd.context[token & dev->cmd.token_mask];
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* previously timed out command completing at long last */
39662306a36Sopenharmony_ci	if (token != context->token)
39762306a36Sopenharmony_ci		return;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	context->result    = 0;
40062306a36Sopenharmony_ci	context->status    = status;
40162306a36Sopenharmony_ci	context->out_param = out_param;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	complete(&context->done);
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic int mthca_cmd_wait(struct mthca_dev *dev,
40762306a36Sopenharmony_ci			  u64 in_param,
40862306a36Sopenharmony_ci			  u64 *out_param,
40962306a36Sopenharmony_ci			  int out_is_imm,
41062306a36Sopenharmony_ci			  u32 in_modifier,
41162306a36Sopenharmony_ci			  u8 op_modifier,
41262306a36Sopenharmony_ci			  u16 op,
41362306a36Sopenharmony_ci			  unsigned long timeout)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	int err = 0;
41662306a36Sopenharmony_ci	struct mthca_cmd_context *context;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	down(&dev->cmd.event_sem);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	spin_lock(&dev->cmd.context_lock);
42162306a36Sopenharmony_ci	BUG_ON(dev->cmd.free_head < 0);
42262306a36Sopenharmony_ci	context = &dev->cmd.context[dev->cmd.free_head];
42362306a36Sopenharmony_ci	context->token += dev->cmd.token_mask + 1;
42462306a36Sopenharmony_ci	dev->cmd.free_head = context->next;
42562306a36Sopenharmony_ci	spin_unlock(&dev->cmd.context_lock);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	init_completion(&context->done);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	err = mthca_cmd_post(dev, in_param,
43062306a36Sopenharmony_ci			     out_param ? *out_param : 0,
43162306a36Sopenharmony_ci			     in_modifier, op_modifier,
43262306a36Sopenharmony_ci			     op, context->token, 1);
43362306a36Sopenharmony_ci	if (err)
43462306a36Sopenharmony_ci		goto out;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&context->done, timeout)) {
43762306a36Sopenharmony_ci		err = -EBUSY;
43862306a36Sopenharmony_ci		goto out;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	err = context->result;
44262306a36Sopenharmony_ci	if (err)
44362306a36Sopenharmony_ci		goto out;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (context->status) {
44662306a36Sopenharmony_ci		mthca_dbg(dev, "Command %02x completed with status %02x\n",
44762306a36Sopenharmony_ci			  op, context->status);
44862306a36Sopenharmony_ci		err = mthca_status_to_errno(context->status);
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (out_is_imm && out_param) {
45262306a36Sopenharmony_ci		*out_param = context->out_param;
45362306a36Sopenharmony_ci	} else if (out_is_imm) {
45462306a36Sopenharmony_ci		err = -EINVAL;
45562306a36Sopenharmony_ci		goto out;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ciout:
45962306a36Sopenharmony_ci	spin_lock(&dev->cmd.context_lock);
46062306a36Sopenharmony_ci	context->next = dev->cmd.free_head;
46162306a36Sopenharmony_ci	dev->cmd.free_head = context - dev->cmd.context;
46262306a36Sopenharmony_ci	spin_unlock(&dev->cmd.context_lock);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	up(&dev->cmd.event_sem);
46562306a36Sopenharmony_ci	return err;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci/* Invoke a command with an output mailbox */
46962306a36Sopenharmony_cistatic int mthca_cmd_box(struct mthca_dev *dev,
47062306a36Sopenharmony_ci			 u64 in_param,
47162306a36Sopenharmony_ci			 u64 out_param,
47262306a36Sopenharmony_ci			 u32 in_modifier,
47362306a36Sopenharmony_ci			 u8 op_modifier,
47462306a36Sopenharmony_ci			 u16 op,
47562306a36Sopenharmony_ci			 unsigned long timeout)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
47862306a36Sopenharmony_ci		return mthca_cmd_wait(dev, in_param, &out_param, 0,
47962306a36Sopenharmony_ci				      in_modifier, op_modifier, op,
48062306a36Sopenharmony_ci				      timeout);
48162306a36Sopenharmony_ci	else
48262306a36Sopenharmony_ci		return mthca_cmd_poll(dev, in_param, &out_param, 0,
48362306a36Sopenharmony_ci				      in_modifier, op_modifier, op,
48462306a36Sopenharmony_ci				      timeout);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/* Invoke a command with no output parameter */
48862306a36Sopenharmony_cistatic int mthca_cmd(struct mthca_dev *dev,
48962306a36Sopenharmony_ci		     u64 in_param,
49062306a36Sopenharmony_ci		     u32 in_modifier,
49162306a36Sopenharmony_ci		     u8 op_modifier,
49262306a36Sopenharmony_ci		     u16 op,
49362306a36Sopenharmony_ci		     unsigned long timeout)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	return mthca_cmd_box(dev, in_param, 0, in_modifier,
49662306a36Sopenharmony_ci			     op_modifier, op, timeout);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/*
50062306a36Sopenharmony_ci * Invoke a command with an immediate output parameter (and copy the
50162306a36Sopenharmony_ci * output into the caller's out_param pointer after the command
50262306a36Sopenharmony_ci * executes).
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_cistatic int mthca_cmd_imm(struct mthca_dev *dev,
50562306a36Sopenharmony_ci			 u64 in_param,
50662306a36Sopenharmony_ci			 u64 *out_param,
50762306a36Sopenharmony_ci			 u32 in_modifier,
50862306a36Sopenharmony_ci			 u8 op_modifier,
50962306a36Sopenharmony_ci			 u16 op,
51062306a36Sopenharmony_ci			 unsigned long timeout)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
51362306a36Sopenharmony_ci		return mthca_cmd_wait(dev, in_param, out_param, 1,
51462306a36Sopenharmony_ci				      in_modifier, op_modifier, op,
51562306a36Sopenharmony_ci				      timeout);
51662306a36Sopenharmony_ci	else
51762306a36Sopenharmony_ci		return mthca_cmd_poll(dev, in_param, out_param, 1,
51862306a36Sopenharmony_ci				      in_modifier, op_modifier, op,
51962306a36Sopenharmony_ci				      timeout);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ciint mthca_cmd_init(struct mthca_dev *dev)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	mutex_init(&dev->cmd.hcr_mutex);
52562306a36Sopenharmony_ci	sema_init(&dev->cmd.poll_sem, 1);
52662306a36Sopenharmony_ci	dev->cmd.flags = 0;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
52962306a36Sopenharmony_ci			   MTHCA_HCR_SIZE);
53062306a36Sopenharmony_ci	if (!dev->hcr) {
53162306a36Sopenharmony_ci		mthca_err(dev, "Couldn't map command register.");
53262306a36Sopenharmony_ci		return -ENOMEM;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	dev->cmd.pool = dma_pool_create("mthca_cmd", &dev->pdev->dev,
53662306a36Sopenharmony_ci					MTHCA_MAILBOX_SIZE,
53762306a36Sopenharmony_ci					MTHCA_MAILBOX_SIZE, 0);
53862306a36Sopenharmony_ci	if (!dev->cmd.pool) {
53962306a36Sopenharmony_ci		iounmap(dev->hcr);
54062306a36Sopenharmony_ci		return -ENOMEM;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_civoid mthca_cmd_cleanup(struct mthca_dev *dev)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	dma_pool_destroy(dev->cmd.pool);
54962306a36Sopenharmony_ci	iounmap(dev->hcr);
55062306a36Sopenharmony_ci	if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
55162306a36Sopenharmony_ci		iounmap(dev->cmd.dbell_map);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/*
55562306a36Sopenharmony_ci * Switch to using events to issue FW commands (should be called after
55662306a36Sopenharmony_ci * event queue to command events has been initialized).
55762306a36Sopenharmony_ci */
55862306a36Sopenharmony_ciint mthca_cmd_use_events(struct mthca_dev *dev)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	int i;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	dev->cmd.context = kmalloc_array(dev->cmd.max_cmds,
56362306a36Sopenharmony_ci					 sizeof(struct mthca_cmd_context),
56462306a36Sopenharmony_ci					 GFP_KERNEL);
56562306a36Sopenharmony_ci	if (!dev->cmd.context)
56662306a36Sopenharmony_ci		return -ENOMEM;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	for (i = 0; i < dev->cmd.max_cmds; ++i) {
56962306a36Sopenharmony_ci		dev->cmd.context[i].token = i;
57062306a36Sopenharmony_ci		dev->cmd.context[i].next = i + 1;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	dev->cmd.context[dev->cmd.max_cmds - 1].next = -1;
57462306a36Sopenharmony_ci	dev->cmd.free_head = 0;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	sema_init(&dev->cmd.event_sem, dev->cmd.max_cmds);
57762306a36Sopenharmony_ci	spin_lock_init(&dev->cmd.context_lock);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	for (dev->cmd.token_mask = 1;
58062306a36Sopenharmony_ci	     dev->cmd.token_mask < dev->cmd.max_cmds;
58162306a36Sopenharmony_ci	     dev->cmd.token_mask <<= 1)
58262306a36Sopenharmony_ci		; /* nothing */
58362306a36Sopenharmony_ci	--dev->cmd.token_mask;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	down(&dev->cmd.poll_sem);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/*
59362306a36Sopenharmony_ci * Switch back to polling (used when shutting down the device)
59462306a36Sopenharmony_ci */
59562306a36Sopenharmony_civoid mthca_cmd_use_polling(struct mthca_dev *dev)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	int i;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	for (i = 0; i < dev->cmd.max_cmds; ++i)
60262306a36Sopenharmony_ci		down(&dev->cmd.event_sem);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	kfree(dev->cmd.context);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	up(&dev->cmd.poll_sem);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistruct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
61062306a36Sopenharmony_ci					  gfp_t gfp_mask)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	mailbox = kmalloc(sizeof *mailbox, gfp_mask);
61562306a36Sopenharmony_ci	if (!mailbox)
61662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	mailbox->buf = dma_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
61962306a36Sopenharmony_ci	if (!mailbox->buf) {
62062306a36Sopenharmony_ci		kfree(mailbox);
62162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	return mailbox;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_civoid mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	if (!mailbox)
63062306a36Sopenharmony_ci		return;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	dma_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
63362306a36Sopenharmony_ci	kfree(mailbox);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ciint mthca_SYS_EN(struct mthca_dev *dev)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	u64 out = 0;
63962306a36Sopenharmony_ci	int ret;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (ret == -ENOMEM)
64462306a36Sopenharmony_ci		mthca_warn(dev, "SYS_EN DDR error: syn=%x, sock=%d, "
64562306a36Sopenharmony_ci			   "sladdr=%d, SPD source=%s\n",
64662306a36Sopenharmony_ci			   (int) (out >> 6) & 0xf, (int) (out >> 4) & 3,
64762306a36Sopenharmony_ci			   (int) (out >> 1) & 7, (int) out & 1 ? "NVMEM" : "DIMM");
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return ret;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ciint mthca_SYS_DIS(struct mthca_dev *dev)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, CMD_TIME_CLASS_C);
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
65862306a36Sopenharmony_ci			 u64 virt)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
66162306a36Sopenharmony_ci	struct mthca_icm_iter iter;
66262306a36Sopenharmony_ci	__be64 *pages;
66362306a36Sopenharmony_ci	int lg;
66462306a36Sopenharmony_ci	int nent = 0;
66562306a36Sopenharmony_ci	int i;
66662306a36Sopenharmony_ci	int err = 0;
66762306a36Sopenharmony_ci	int ts = 0, tc = 0;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
67062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
67162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
67262306a36Sopenharmony_ci	memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
67362306a36Sopenharmony_ci	pages = mailbox->buf;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	for (mthca_icm_first(icm, &iter);
67662306a36Sopenharmony_ci	     !mthca_icm_last(&iter);
67762306a36Sopenharmony_ci	     mthca_icm_next(&iter)) {
67862306a36Sopenharmony_ci		/*
67962306a36Sopenharmony_ci		 * We have to pass pages that are aligned to their
68062306a36Sopenharmony_ci		 * size, so find the least significant 1 in the
68162306a36Sopenharmony_ci		 * address or size and use that as our log2 size.
68262306a36Sopenharmony_ci		 */
68362306a36Sopenharmony_ci		lg = ffs(mthca_icm_addr(&iter) | mthca_icm_size(&iter)) - 1;
68462306a36Sopenharmony_ci		if (lg < MTHCA_ICM_PAGE_SHIFT) {
68562306a36Sopenharmony_ci			mthca_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
68662306a36Sopenharmony_ci				   MTHCA_ICM_PAGE_SIZE,
68762306a36Sopenharmony_ci				   (unsigned long long) mthca_icm_addr(&iter),
68862306a36Sopenharmony_ci				   mthca_icm_size(&iter));
68962306a36Sopenharmony_ci			err = -EINVAL;
69062306a36Sopenharmony_ci			goto out;
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci		for (i = 0; i < mthca_icm_size(&iter) >> lg; ++i) {
69362306a36Sopenharmony_ci			if (virt != -1) {
69462306a36Sopenharmony_ci				pages[nent * 2] = cpu_to_be64(virt);
69562306a36Sopenharmony_ci				virt += 1ULL << lg;
69662306a36Sopenharmony_ci			}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci			pages[nent * 2 + 1] =
69962306a36Sopenharmony_ci				cpu_to_be64((mthca_icm_addr(&iter) + (i << lg)) |
70062306a36Sopenharmony_ci					    (lg - MTHCA_ICM_PAGE_SHIFT));
70162306a36Sopenharmony_ci			ts += 1 << (lg - 10);
70262306a36Sopenharmony_ci			++tc;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci			if (++nent == MTHCA_MAILBOX_SIZE / 16) {
70562306a36Sopenharmony_ci				err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
70662306a36Sopenharmony_ci						CMD_TIME_CLASS_B);
70762306a36Sopenharmony_ci				if (err)
70862306a36Sopenharmony_ci					goto out;
70962306a36Sopenharmony_ci				nent = 0;
71062306a36Sopenharmony_ci			}
71162306a36Sopenharmony_ci		}
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (nent)
71562306a36Sopenharmony_ci		err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
71662306a36Sopenharmony_ci				CMD_TIME_CLASS_B);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	switch (op) {
71962306a36Sopenharmony_ci	case CMD_MAP_FA:
72062306a36Sopenharmony_ci		mthca_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts);
72162306a36Sopenharmony_ci		break;
72262306a36Sopenharmony_ci	case CMD_MAP_ICM_AUX:
72362306a36Sopenharmony_ci		mthca_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts);
72462306a36Sopenharmony_ci		break;
72562306a36Sopenharmony_ci	case CMD_MAP_ICM:
72662306a36Sopenharmony_ci		mthca_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n",
72762306a36Sopenharmony_ci			  tc, ts, (unsigned long long) virt - (ts << 10));
72862306a36Sopenharmony_ci		break;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ciout:
73262306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
73362306a36Sopenharmony_ci	return err;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ciint mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	return mthca_map_cmd(dev, CMD_MAP_FA, icm, -1);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ciint mthca_UNMAP_FA(struct mthca_dev *dev)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, 0, CMD_UNMAP_FA, CMD_TIME_CLASS_B);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ciint mthca_RUN_FW(struct mthca_dev *dev)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	phys_addr_t addr;
75462306a36Sopenharmony_ci	u16 max_off = 0;
75562306a36Sopenharmony_ci	int i;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	for (i = 0; i < 8; ++i)
75862306a36Sopenharmony_ci		max_off = max(max_off, dev->cmd.dbell_offsets[i]);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) {
76162306a36Sopenharmony_ci		mthca_warn(dev, "Firmware doorbell region at 0x%016llx, "
76262306a36Sopenharmony_ci			   "length 0x%x crosses a page boundary\n",
76362306a36Sopenharmony_ci			   (unsigned long long) base, max_off);
76462306a36Sopenharmony_ci		return;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	addr = pci_resource_start(dev->pdev, 2) +
76862306a36Sopenharmony_ci		((pci_resource_len(dev->pdev, 2) - 1) & base);
76962306a36Sopenharmony_ci	dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32));
77062306a36Sopenharmony_ci	if (!dev->cmd.dbell_map)
77162306a36Sopenharmony_ci		return;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
77462306a36Sopenharmony_ci	mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n");
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ciint mthca_QUERY_FW(struct mthca_dev *dev)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
78062306a36Sopenharmony_ci	u32 *outbox;
78162306a36Sopenharmony_ci	u64 base;
78262306a36Sopenharmony_ci	u32 tmp;
78362306a36Sopenharmony_ci	int err = 0;
78462306a36Sopenharmony_ci	u8 lg;
78562306a36Sopenharmony_ci	int i;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci#define QUERY_FW_OUT_SIZE             0x100
78862306a36Sopenharmony_ci#define QUERY_FW_VER_OFFSET            0x00
78962306a36Sopenharmony_ci#define QUERY_FW_MAX_CMD_OFFSET        0x0f
79062306a36Sopenharmony_ci#define QUERY_FW_ERR_START_OFFSET      0x30
79162306a36Sopenharmony_ci#define QUERY_FW_ERR_SIZE_OFFSET       0x38
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci#define QUERY_FW_CMD_DB_EN_OFFSET      0x10
79462306a36Sopenharmony_ci#define QUERY_FW_CMD_DB_OFFSET         0x50
79562306a36Sopenharmony_ci#define QUERY_FW_CMD_DB_BASE           0x60
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci#define QUERY_FW_START_OFFSET          0x20
79862306a36Sopenharmony_ci#define QUERY_FW_END_OFFSET            0x28
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci#define QUERY_FW_SIZE_OFFSET           0x00
80162306a36Sopenharmony_ci#define QUERY_FW_CLR_INT_BASE_OFFSET   0x20
80262306a36Sopenharmony_ci#define QUERY_FW_EQ_ARM_BASE_OFFSET    0x40
80362306a36Sopenharmony_ci#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
80662306a36Sopenharmony_ci	if (IS_ERR(mailbox))
80762306a36Sopenharmony_ci		return PTR_ERR(mailbox);
80862306a36Sopenharmony_ci	outbox = mailbox->buf;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
81162306a36Sopenharmony_ci			    CMD_TIME_CLASS_A);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	if (err)
81462306a36Sopenharmony_ci		goto out;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	MTHCA_GET(dev->fw_ver,   outbox, QUERY_FW_VER_OFFSET);
81762306a36Sopenharmony_ci	/*
81862306a36Sopenharmony_ci	 * FW subminor version is at more significant bits than minor
81962306a36Sopenharmony_ci	 * version, so swap here.
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	dev->fw_ver = (dev->fw_ver & 0xffff00000000ull) |
82262306a36Sopenharmony_ci		((dev->fw_ver & 0xffff0000ull) >> 16) |
82362306a36Sopenharmony_ci		((dev->fw_ver & 0x0000ffffull) << 16);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
82662306a36Sopenharmony_ci	dev->cmd.max_cmds = 1 << lg;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	mthca_dbg(dev, "FW version %012llx, max commands %d\n",
82962306a36Sopenharmony_ci		  (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
83262306a36Sopenharmony_ci	MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n",
83562306a36Sopenharmony_ci		  (unsigned long long) dev->catas_err.addr, dev->catas_err.size);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
83862306a36Sopenharmony_ci	if (tmp & 0x1) {
83962306a36Sopenharmony_ci		mthca_dbg(dev, "FW supports commands through doorbells\n");
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE);
84262306a36Sopenharmony_ci		for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
84362306a36Sopenharmony_ci			MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
84462306a36Sopenharmony_ci				  QUERY_FW_CMD_DB_OFFSET + (i << 1));
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		mthca_setup_cmd_doorbells(dev, base);
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (mthca_is_memfree(dev)) {
85062306a36Sopenharmony_ci		MTHCA_GET(dev->fw.arbel.fw_pages,       outbox, QUERY_FW_SIZE_OFFSET);
85162306a36Sopenharmony_ci		MTHCA_GET(dev->fw.arbel.clr_int_base,   outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
85262306a36Sopenharmony_ci		MTHCA_GET(dev->fw.arbel.eq_arm_base,    outbox, QUERY_FW_EQ_ARM_BASE_OFFSET);
85362306a36Sopenharmony_ci		MTHCA_GET(dev->fw.arbel.eq_set_ci_base, outbox, QUERY_FW_EQ_SET_CI_BASE_OFFSET);
85462306a36Sopenharmony_ci		mthca_dbg(dev, "FW size %d KB\n", dev->fw.arbel.fw_pages << 2);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		/*
85762306a36Sopenharmony_ci		 * Round up number of system pages needed in case
85862306a36Sopenharmony_ci		 * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
85962306a36Sopenharmony_ci		 */
86062306a36Sopenharmony_ci		dev->fw.arbel.fw_pages =
86162306a36Sopenharmony_ci			ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
86262306a36Sopenharmony_ci				(PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci		mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
86562306a36Sopenharmony_ci			  (unsigned long long) dev->fw.arbel.clr_int_base,
86662306a36Sopenharmony_ci			  (unsigned long long) dev->fw.arbel.eq_arm_base,
86762306a36Sopenharmony_ci			  (unsigned long long) dev->fw.arbel.eq_set_ci_base);
86862306a36Sopenharmony_ci	} else {
86962306a36Sopenharmony_ci		MTHCA_GET(dev->fw.tavor.fw_start, outbox, QUERY_FW_START_OFFSET);
87062306a36Sopenharmony_ci		MTHCA_GET(dev->fw.tavor.fw_end,   outbox, QUERY_FW_END_OFFSET);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		mthca_dbg(dev, "FW size %d KB (start %llx, end %llx)\n",
87362306a36Sopenharmony_ci			  (int) ((dev->fw.tavor.fw_end - dev->fw.tavor.fw_start) >> 10),
87462306a36Sopenharmony_ci			  (unsigned long long) dev->fw.tavor.fw_start,
87562306a36Sopenharmony_ci			  (unsigned long long) dev->fw.tavor.fw_end);
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ciout:
87962306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
88062306a36Sopenharmony_ci	return err;
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ciint mthca_ENABLE_LAM(struct mthca_dev *dev)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
88662306a36Sopenharmony_ci	u8 info;
88762306a36Sopenharmony_ci	u32 *outbox;
88862306a36Sopenharmony_ci	int err = 0;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci#define ENABLE_LAM_OUT_SIZE         0x100
89162306a36Sopenharmony_ci#define ENABLE_LAM_START_OFFSET     0x00
89262306a36Sopenharmony_ci#define ENABLE_LAM_END_OFFSET       0x08
89362306a36Sopenharmony_ci#define ENABLE_LAM_INFO_OFFSET      0x13
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
89662306a36Sopenharmony_ci#define ENABLE_LAM_INFO_ECC_MASK    0x3
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
89962306a36Sopenharmony_ci	if (IS_ERR(mailbox))
90062306a36Sopenharmony_ci		return PTR_ERR(mailbox);
90162306a36Sopenharmony_ci	outbox = mailbox->buf;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
90462306a36Sopenharmony_ci			    CMD_TIME_CLASS_C);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	if (err)
90762306a36Sopenharmony_ci		goto out;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	MTHCA_GET(dev->ddr_start, outbox, ENABLE_LAM_START_OFFSET);
91062306a36Sopenharmony_ci	MTHCA_GET(dev->ddr_end,   outbox, ENABLE_LAM_END_OFFSET);
91162306a36Sopenharmony_ci	MTHCA_GET(info,           outbox, ENABLE_LAM_INFO_OFFSET);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (!!(info & ENABLE_LAM_INFO_HIDDEN_FLAG) !=
91462306a36Sopenharmony_ci	    !!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
91562306a36Sopenharmony_ci		mthca_info(dev, "FW reports that HCA-attached memory "
91662306a36Sopenharmony_ci			   "is %s hidden; does not match PCI config\n",
91762306a36Sopenharmony_ci			   (info & ENABLE_LAM_INFO_HIDDEN_FLAG) ?
91862306a36Sopenharmony_ci			   "" : "not");
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci	if (info & ENABLE_LAM_INFO_HIDDEN_FLAG)
92162306a36Sopenharmony_ci		mthca_dbg(dev, "HCA-attached memory is hidden.\n");
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	mthca_dbg(dev, "HCA memory size %d KB (start %llx, end %llx)\n",
92462306a36Sopenharmony_ci		  (int) ((dev->ddr_end - dev->ddr_start) >> 10),
92562306a36Sopenharmony_ci		  (unsigned long long) dev->ddr_start,
92662306a36Sopenharmony_ci		  (unsigned long long) dev->ddr_end);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ciout:
92962306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
93062306a36Sopenharmony_ci	return err;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ciint mthca_DISABLE_LAM(struct mthca_dev *dev)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, CMD_TIME_CLASS_C);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ciint mthca_QUERY_DDR(struct mthca_dev *dev)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
94162306a36Sopenharmony_ci	u8 info;
94262306a36Sopenharmony_ci	u32 *outbox;
94362306a36Sopenharmony_ci	int err = 0;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci#define QUERY_DDR_OUT_SIZE         0x100
94662306a36Sopenharmony_ci#define QUERY_DDR_START_OFFSET     0x00
94762306a36Sopenharmony_ci#define QUERY_DDR_END_OFFSET       0x08
94862306a36Sopenharmony_ci#define QUERY_DDR_INFO_OFFSET      0x13
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
95162306a36Sopenharmony_ci#define QUERY_DDR_INFO_ECC_MASK    0x3
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
95462306a36Sopenharmony_ci	if (IS_ERR(mailbox))
95562306a36Sopenharmony_ci		return PTR_ERR(mailbox);
95662306a36Sopenharmony_ci	outbox = mailbox->buf;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
95962306a36Sopenharmony_ci			    CMD_TIME_CLASS_A);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (err)
96262306a36Sopenharmony_ci		goto out;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	MTHCA_GET(dev->ddr_start, outbox, QUERY_DDR_START_OFFSET);
96562306a36Sopenharmony_ci	MTHCA_GET(dev->ddr_end,   outbox, QUERY_DDR_END_OFFSET);
96662306a36Sopenharmony_ci	MTHCA_GET(info,           outbox, QUERY_DDR_INFO_OFFSET);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (!!(info & QUERY_DDR_INFO_HIDDEN_FLAG) !=
96962306a36Sopenharmony_ci	    !!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
97062306a36Sopenharmony_ci		mthca_info(dev, "FW reports that HCA-attached memory "
97162306a36Sopenharmony_ci			   "is %s hidden; does not match PCI config\n",
97262306a36Sopenharmony_ci			   (info & QUERY_DDR_INFO_HIDDEN_FLAG) ?
97362306a36Sopenharmony_ci			   "" : "not");
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci	if (info & QUERY_DDR_INFO_HIDDEN_FLAG)
97662306a36Sopenharmony_ci		mthca_dbg(dev, "HCA-attached memory is hidden.\n");
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	mthca_dbg(dev, "HCA memory size %d KB (start %llx, end %llx)\n",
97962306a36Sopenharmony_ci		  (int) ((dev->ddr_end - dev->ddr_start) >> 10),
98062306a36Sopenharmony_ci		  (unsigned long long) dev->ddr_start,
98162306a36Sopenharmony_ci		  (unsigned long long) dev->ddr_end);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ciout:
98462306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
98562306a36Sopenharmony_ci	return err;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ciint mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
98962306a36Sopenharmony_ci			struct mthca_dev_lim *dev_lim)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
99262306a36Sopenharmony_ci	u32 *outbox;
99362306a36Sopenharmony_ci	u8 field;
99462306a36Sopenharmony_ci	u16 size;
99562306a36Sopenharmony_ci	u16 stat_rate;
99662306a36Sopenharmony_ci	int err;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci#define QUERY_DEV_LIM_OUT_SIZE             0x100
99962306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET     0x10
100062306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_QP_SZ_OFFSET      0x11
100162306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_QP_OFFSET        0x12
100262306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_QP_OFFSET         0x13
100362306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_SRQ_OFFSET       0x14
100462306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_SRQ_OFFSET        0x15
100562306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_EEC_OFFSET       0x16
100662306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_EEC_OFFSET        0x17
100762306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_CQ_SZ_OFFSET      0x19
100862306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_CQ_OFFSET        0x1a
100962306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_CQ_OFFSET         0x1b
101062306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_MPT_OFFSET        0x1d
101162306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_EQ_OFFSET        0x1e
101262306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_EQ_OFFSET         0x1f
101362306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_MTT_OFFSET       0x20
101462306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET     0x21
101562306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_MRW_OFFSET       0x22
101662306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_MTT_SEG_OFFSET    0x23
101762306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_AV_OFFSET         0x27
101862306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_REQ_QP_OFFSET     0x29
101962306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_RES_QP_OFFSET     0x2b
102062306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_RDMA_OFFSET       0x2f
102162306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSZ_SRQ_OFFSET        0x33
102262306a36Sopenharmony_ci#define QUERY_DEV_LIM_ACK_DELAY_OFFSET      0x35
102362306a36Sopenharmony_ci#define QUERY_DEV_LIM_MTU_WIDTH_OFFSET      0x36
102462306a36Sopenharmony_ci#define QUERY_DEV_LIM_VL_PORT_OFFSET        0x37
102562306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_GID_OFFSET        0x3b
102662306a36Sopenharmony_ci#define QUERY_DEV_LIM_RATE_SUPPORT_OFFSET   0x3c
102762306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_PKEY_OFFSET       0x3f
102862306a36Sopenharmony_ci#define QUERY_DEV_LIM_FLAGS_OFFSET          0x44
102962306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_UAR_OFFSET       0x48
103062306a36Sopenharmony_ci#define QUERY_DEV_LIM_UAR_SZ_OFFSET         0x49
103162306a36Sopenharmony_ci#define QUERY_DEV_LIM_PAGE_SZ_OFFSET        0x4b
103262306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_SG_OFFSET         0x51
103362306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_DESC_SZ_OFFSET    0x52
103462306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_SG_RQ_OFFSET      0x55
103562306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET 0x56
103662306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_QP_MCG_OFFSET     0x61
103762306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_MCG_OFFSET       0x62
103862306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_MCG_OFFSET        0x63
103962306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_PD_OFFSET        0x64
104062306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_PD_OFFSET         0x65
104162306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_RDD_OFFSET       0x66
104262306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_RDD_OFFSET        0x67
104362306a36Sopenharmony_ci#define QUERY_DEV_LIM_EEC_ENTRY_SZ_OFFSET   0x80
104462306a36Sopenharmony_ci#define QUERY_DEV_LIM_QPC_ENTRY_SZ_OFFSET   0x82
104562306a36Sopenharmony_ci#define QUERY_DEV_LIM_EEEC_ENTRY_SZ_OFFSET  0x84
104662306a36Sopenharmony_ci#define QUERY_DEV_LIM_EQPC_ENTRY_SZ_OFFSET  0x86
104762306a36Sopenharmony_ci#define QUERY_DEV_LIM_EQC_ENTRY_SZ_OFFSET   0x88
104862306a36Sopenharmony_ci#define QUERY_DEV_LIM_CQC_ENTRY_SZ_OFFSET   0x8a
104962306a36Sopenharmony_ci#define QUERY_DEV_LIM_SRQ_ENTRY_SZ_OFFSET   0x8c
105062306a36Sopenharmony_ci#define QUERY_DEV_LIM_UAR_ENTRY_SZ_OFFSET   0x8e
105162306a36Sopenharmony_ci#define QUERY_DEV_LIM_MTT_ENTRY_SZ_OFFSET   0x90
105262306a36Sopenharmony_ci#define QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET   0x92
105362306a36Sopenharmony_ci#define QUERY_DEV_LIM_PBL_SZ_OFFSET         0x96
105462306a36Sopenharmony_ci#define QUERY_DEV_LIM_BMME_FLAGS_OFFSET     0x97
105562306a36Sopenharmony_ci#define QUERY_DEV_LIM_RSVD_LKEY_OFFSET      0x98
105662306a36Sopenharmony_ci#define QUERY_DEV_LIM_LAMR_OFFSET           0x9f
105762306a36Sopenharmony_ci#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET     0xa0
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
106062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
106162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
106262306a36Sopenharmony_ci	outbox = mailbox->buf;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
106562306a36Sopenharmony_ci			    CMD_TIME_CLASS_A);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (err)
106862306a36Sopenharmony_ci		goto out;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET);
107162306a36Sopenharmony_ci	dev_lim->reserved_qps = 1 << (field & 0xf);
107262306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET);
107362306a36Sopenharmony_ci	dev_lim->max_qps = 1 << (field & 0x1f);
107462306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_SRQ_OFFSET);
107562306a36Sopenharmony_ci	dev_lim->reserved_srqs = 1 << (field >> 4);
107662306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_OFFSET);
107762306a36Sopenharmony_ci	dev_lim->max_srqs = 1 << (field & 0x1f);
107862306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_EEC_OFFSET);
107962306a36Sopenharmony_ci	dev_lim->reserved_eecs = 1 << (field & 0xf);
108062306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EEC_OFFSET);
108162306a36Sopenharmony_ci	dev_lim->max_eecs = 1 << (field & 0x1f);
108262306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_CQ_SZ_OFFSET);
108362306a36Sopenharmony_ci	dev_lim->max_cq_sz = 1 << field;
108462306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_CQ_OFFSET);
108562306a36Sopenharmony_ci	dev_lim->reserved_cqs = 1 << (field & 0xf);
108662306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_CQ_OFFSET);
108762306a36Sopenharmony_ci	dev_lim->max_cqs = 1 << (field & 0x1f);
108862306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MPT_OFFSET);
108962306a36Sopenharmony_ci	dev_lim->max_mpts = 1 << (field & 0x3f);
109062306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_EQ_OFFSET);
109162306a36Sopenharmony_ci	dev_lim->reserved_eqs = 1 << (field & 0xf);
109262306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EQ_OFFSET);
109362306a36Sopenharmony_ci	dev_lim->max_eqs = 1 << (field & 0x7);
109462306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET);
109562306a36Sopenharmony_ci	if (mthca_is_memfree(dev))
109662306a36Sopenharmony_ci		dev_lim->reserved_mtts = ALIGN((1 << (field >> 4)) * sizeof(u64),
109762306a36Sopenharmony_ci					       dev->limits.mtt_seg_size) / dev->limits.mtt_seg_size;
109862306a36Sopenharmony_ci	else
109962306a36Sopenharmony_ci		dev_lim->reserved_mtts = 1 << (field >> 4);
110062306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET);
110162306a36Sopenharmony_ci	dev_lim->max_mrw_sz = 1 << field;
110262306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MRW_OFFSET);
110362306a36Sopenharmony_ci	dev_lim->reserved_mrws = 1 << (field & 0xf);
110462306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MTT_SEG_OFFSET);
110562306a36Sopenharmony_ci	dev_lim->max_mtt_seg = 1 << (field & 0x3f);
110662306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_REQ_QP_OFFSET);
110762306a36Sopenharmony_ci	dev_lim->max_requester_per_qp = 1 << (field & 0x3f);
110862306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RES_QP_OFFSET);
110962306a36Sopenharmony_ci	dev_lim->max_responder_per_qp = 1 << (field & 0x3f);
111062306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RDMA_OFFSET);
111162306a36Sopenharmony_ci	dev_lim->max_rdma_global = 1 << (field & 0x3f);
111262306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_ACK_DELAY_OFFSET);
111362306a36Sopenharmony_ci	dev_lim->local_ca_ack_delay = field & 0x1f;
111462306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MTU_WIDTH_OFFSET);
111562306a36Sopenharmony_ci	dev_lim->max_mtu        = field >> 4;
111662306a36Sopenharmony_ci	dev_lim->max_port_width = field & 0xf;
111762306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_VL_PORT_OFFSET);
111862306a36Sopenharmony_ci	dev_lim->max_vl    = field >> 4;
111962306a36Sopenharmony_ci	dev_lim->num_ports = field & 0xf;
112062306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_GID_OFFSET);
112162306a36Sopenharmony_ci	dev_lim->max_gids = 1 << (field & 0xf);
112262306a36Sopenharmony_ci	MTHCA_GET(stat_rate, outbox, QUERY_DEV_LIM_RATE_SUPPORT_OFFSET);
112362306a36Sopenharmony_ci	dev_lim->stat_rate_support = stat_rate;
112462306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PKEY_OFFSET);
112562306a36Sopenharmony_ci	dev_lim->max_pkeys = 1 << (field & 0xf);
112662306a36Sopenharmony_ci	MTHCA_GET(dev_lim->flags, outbox, QUERY_DEV_LIM_FLAGS_OFFSET);
112762306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_UAR_OFFSET);
112862306a36Sopenharmony_ci	dev_lim->reserved_uars = field >> 4;
112962306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_UAR_SZ_OFFSET);
113062306a36Sopenharmony_ci	dev_lim->uar_size = 1 << ((field & 0x3f) + 20);
113162306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_PAGE_SZ_OFFSET);
113262306a36Sopenharmony_ci	dev_lim->min_page_sz = 1 << field;
113362306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_OFFSET);
113462306a36Sopenharmony_ci	dev_lim->max_sg = field;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_OFFSET);
113762306a36Sopenharmony_ci	dev_lim->max_desc_sz = size;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_MCG_OFFSET);
114062306a36Sopenharmony_ci	dev_lim->max_qp_per_mcg = 1 << field;
114162306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MCG_OFFSET);
114262306a36Sopenharmony_ci	dev_lim->reserved_mgms = field & 0xf;
114362306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MCG_OFFSET);
114462306a36Sopenharmony_ci	dev_lim->max_mcgs = 1 << field;
114562306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_PD_OFFSET);
114662306a36Sopenharmony_ci	dev_lim->reserved_pds = field >> 4;
114762306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PD_OFFSET);
114862306a36Sopenharmony_ci	dev_lim->max_pds = 1 << (field & 0x3f);
114962306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_RDD_OFFSET);
115062306a36Sopenharmony_ci	dev_lim->reserved_rdds = field >> 4;
115162306a36Sopenharmony_ci	MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RDD_OFFSET);
115262306a36Sopenharmony_ci	dev_lim->max_rdds = 1 << (field & 0x3f);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_EEC_ENTRY_SZ_OFFSET);
115562306a36Sopenharmony_ci	dev_lim->eec_entry_sz = size;
115662306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_QPC_ENTRY_SZ_OFFSET);
115762306a36Sopenharmony_ci	dev_lim->qpc_entry_sz = size;
115862306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_EEEC_ENTRY_SZ_OFFSET);
115962306a36Sopenharmony_ci	dev_lim->eeec_entry_sz = size;
116062306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_EQPC_ENTRY_SZ_OFFSET);
116162306a36Sopenharmony_ci	dev_lim->eqpc_entry_sz = size;
116262306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_EQC_ENTRY_SZ_OFFSET);
116362306a36Sopenharmony_ci	dev_lim->eqc_entry_sz = size;
116462306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_CQC_ENTRY_SZ_OFFSET);
116562306a36Sopenharmony_ci	dev_lim->cqc_entry_sz = size;
116662306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_SRQ_ENTRY_SZ_OFFSET);
116762306a36Sopenharmony_ci	dev_lim->srq_entry_sz = size;
116862306a36Sopenharmony_ci	MTHCA_GET(size, outbox, QUERY_DEV_LIM_UAR_ENTRY_SZ_OFFSET);
116962306a36Sopenharmony_ci	dev_lim->uar_scratch_entry_sz = size;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (mthca_is_memfree(dev)) {
117262306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET);
117362306a36Sopenharmony_ci		dev_lim->max_srq_sz = 1 << field;
117462306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET);
117562306a36Sopenharmony_ci		dev_lim->max_qp_sz = 1 << field;
117662306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET);
117762306a36Sopenharmony_ci		dev_lim->hca.arbel.resize_srq = field & 1;
117862306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET);
117962306a36Sopenharmony_ci		dev_lim->max_sg = min_t(int, field, dev_lim->max_sg);
118062306a36Sopenharmony_ci		MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET);
118162306a36Sopenharmony_ci		dev_lim->max_desc_sz = min_t(int, size, dev_lim->max_desc_sz);
118262306a36Sopenharmony_ci		MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET);
118362306a36Sopenharmony_ci		dev_lim->mpt_entry_sz = size;
118462306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET);
118562306a36Sopenharmony_ci		dev_lim->hca.arbel.max_pbl_sz = 1 << (field & 0x3f);
118662306a36Sopenharmony_ci		MTHCA_GET(dev_lim->hca.arbel.bmme_flags, outbox,
118762306a36Sopenharmony_ci			  QUERY_DEV_LIM_BMME_FLAGS_OFFSET);
118862306a36Sopenharmony_ci		MTHCA_GET(dev_lim->hca.arbel.reserved_lkey, outbox,
118962306a36Sopenharmony_ci			  QUERY_DEV_LIM_RSVD_LKEY_OFFSET);
119062306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_LAMR_OFFSET);
119162306a36Sopenharmony_ci		dev_lim->hca.arbel.lam_required = field & 1;
119262306a36Sopenharmony_ci		MTHCA_GET(dev_lim->hca.arbel.max_icm_sz, outbox,
119362306a36Sopenharmony_ci			  QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci		if (dev_lim->hca.arbel.bmme_flags & 1)
119662306a36Sopenharmony_ci			mthca_dbg(dev, "Base MM extensions: yes "
119762306a36Sopenharmony_ci				  "(flags %d, max PBL %d, rsvd L_Key %08x)\n",
119862306a36Sopenharmony_ci				  dev_lim->hca.arbel.bmme_flags,
119962306a36Sopenharmony_ci				  dev_lim->hca.arbel.max_pbl_sz,
120062306a36Sopenharmony_ci				  dev_lim->hca.arbel.reserved_lkey);
120162306a36Sopenharmony_ci		else
120262306a36Sopenharmony_ci			mthca_dbg(dev, "Base MM extensions: no\n");
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		mthca_dbg(dev, "Max ICM size %lld MB\n",
120562306a36Sopenharmony_ci			  (unsigned long long) dev_lim->hca.arbel.max_icm_sz >> 20);
120662306a36Sopenharmony_ci	} else {
120762306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET);
120862306a36Sopenharmony_ci		dev_lim->max_srq_sz = (1 << field) - 1;
120962306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET);
121062306a36Sopenharmony_ci		dev_lim->max_qp_sz = (1 << field) - 1;
121162306a36Sopenharmony_ci		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET);
121262306a36Sopenharmony_ci		dev_lim->hca.tavor.max_avs = 1 << (field & 0x3f);
121362306a36Sopenharmony_ci		dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE;
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	mthca_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
121762306a36Sopenharmony_ci		  dev_lim->max_qps, dev_lim->reserved_qps, dev_lim->qpc_entry_sz);
121862306a36Sopenharmony_ci	mthca_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n",
121962306a36Sopenharmony_ci		  dev_lim->max_srqs, dev_lim->reserved_srqs, dev_lim->srq_entry_sz);
122062306a36Sopenharmony_ci	mthca_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
122162306a36Sopenharmony_ci		  dev_lim->max_cqs, dev_lim->reserved_cqs, dev_lim->cqc_entry_sz);
122262306a36Sopenharmony_ci	mthca_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n",
122362306a36Sopenharmony_ci		  dev_lim->max_eqs, dev_lim->reserved_eqs, dev_lim->eqc_entry_sz);
122462306a36Sopenharmony_ci	mthca_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
122562306a36Sopenharmony_ci		  dev_lim->reserved_mrws, dev_lim->reserved_mtts);
122662306a36Sopenharmony_ci	mthca_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
122762306a36Sopenharmony_ci		  dev_lim->max_pds, dev_lim->reserved_pds, dev_lim->reserved_uars);
122862306a36Sopenharmony_ci	mthca_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n",
122962306a36Sopenharmony_ci		  dev_lim->max_pds, dev_lim->reserved_mgms);
123062306a36Sopenharmony_ci	mthca_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
123162306a36Sopenharmony_ci		  dev_lim->max_cq_sz, dev_lim->max_qp_sz, dev_lim->max_srq_sz);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ciout:
123662306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
123762306a36Sopenharmony_ci	return err;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic void get_board_id(void *vsd, char *board_id)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	int i;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci#define VSD_OFFSET_SIG1		0x00
124562306a36Sopenharmony_ci#define VSD_OFFSET_SIG2		0xde
124662306a36Sopenharmony_ci#define VSD_OFFSET_MLX_BOARD_ID	0xd0
124762306a36Sopenharmony_ci#define VSD_OFFSET_TS_BOARD_ID	0x20
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci#define VSD_SIGNATURE_TOPSPIN	0x5ad
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	memset(board_id, 0, MTHCA_BOARD_ID_LEN);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN &&
125462306a36Sopenharmony_ci	    be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) {
125562306a36Sopenharmony_ci		strscpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MTHCA_BOARD_ID_LEN);
125662306a36Sopenharmony_ci	} else {
125762306a36Sopenharmony_ci		/*
125862306a36Sopenharmony_ci		 * The board ID is a string but the firmware byte
125962306a36Sopenharmony_ci		 * swaps each 4-byte word before passing it back to
126062306a36Sopenharmony_ci		 * us.  Therefore we need to swab it before printing.
126162306a36Sopenharmony_ci		 */
126262306a36Sopenharmony_ci		for (i = 0; i < 4; ++i)
126362306a36Sopenharmony_ci			((u32 *) board_id)[i] =
126462306a36Sopenharmony_ci				swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4));
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ciint mthca_QUERY_ADAPTER(struct mthca_dev *dev,
126962306a36Sopenharmony_ci			struct mthca_adapter *adapter)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
127262306a36Sopenharmony_ci	u32 *outbox;
127362306a36Sopenharmony_ci	int err;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci#define QUERY_ADAPTER_OUT_SIZE             0x100
127662306a36Sopenharmony_ci#define QUERY_ADAPTER_VENDOR_ID_OFFSET     0x00
127762306a36Sopenharmony_ci#define QUERY_ADAPTER_DEVICE_ID_OFFSET     0x04
127862306a36Sopenharmony_ci#define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
127962306a36Sopenharmony_ci#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
128062306a36Sopenharmony_ci#define QUERY_ADAPTER_VSD_OFFSET           0x20
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
128362306a36Sopenharmony_ci	if (IS_ERR(mailbox))
128462306a36Sopenharmony_ci		return PTR_ERR(mailbox);
128562306a36Sopenharmony_ci	outbox = mailbox->buf;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
128862306a36Sopenharmony_ci			    CMD_TIME_CLASS_A);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	if (err)
129162306a36Sopenharmony_ci		goto out;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (!mthca_is_memfree(dev)) {
129462306a36Sopenharmony_ci		MTHCA_GET(adapter->vendor_id, outbox,
129562306a36Sopenharmony_ci			  QUERY_ADAPTER_VENDOR_ID_OFFSET);
129662306a36Sopenharmony_ci		MTHCA_GET(adapter->device_id, outbox,
129762306a36Sopenharmony_ci			  QUERY_ADAPTER_DEVICE_ID_OFFSET);
129862306a36Sopenharmony_ci		MTHCA_GET(adapter->revision_id, outbox,
129962306a36Sopenharmony_ci			  QUERY_ADAPTER_REVISION_ID_OFFSET);
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci	MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
130462306a36Sopenharmony_ci		     adapter->board_id);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ciout:
130762306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
130862306a36Sopenharmony_ci	return err;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ciint mthca_INIT_HCA(struct mthca_dev *dev,
131262306a36Sopenharmony_ci		   struct mthca_init_hca_param *param)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
131562306a36Sopenharmony_ci	__be32 *inbox;
131662306a36Sopenharmony_ci	int err;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci#define INIT_HCA_IN_SIZE             	 0x200
131962306a36Sopenharmony_ci#define INIT_HCA_FLAGS1_OFFSET           0x00c
132062306a36Sopenharmony_ci#define INIT_HCA_FLAGS2_OFFSET           0x014
132162306a36Sopenharmony_ci#define INIT_HCA_QPC_OFFSET          	 0x020
132262306a36Sopenharmony_ci#define  INIT_HCA_QPC_BASE_OFFSET    	 (INIT_HCA_QPC_OFFSET + 0x10)
132362306a36Sopenharmony_ci#define  INIT_HCA_LOG_QP_OFFSET      	 (INIT_HCA_QPC_OFFSET + 0x17)
132462306a36Sopenharmony_ci#define  INIT_HCA_EEC_BASE_OFFSET    	 (INIT_HCA_QPC_OFFSET + 0x20)
132562306a36Sopenharmony_ci#define  INIT_HCA_LOG_EEC_OFFSET     	 (INIT_HCA_QPC_OFFSET + 0x27)
132662306a36Sopenharmony_ci#define  INIT_HCA_SRQC_BASE_OFFSET   	 (INIT_HCA_QPC_OFFSET + 0x28)
132762306a36Sopenharmony_ci#define  INIT_HCA_LOG_SRQ_OFFSET     	 (INIT_HCA_QPC_OFFSET + 0x2f)
132862306a36Sopenharmony_ci#define  INIT_HCA_CQC_BASE_OFFSET    	 (INIT_HCA_QPC_OFFSET + 0x30)
132962306a36Sopenharmony_ci#define  INIT_HCA_LOG_CQ_OFFSET      	 (INIT_HCA_QPC_OFFSET + 0x37)
133062306a36Sopenharmony_ci#define  INIT_HCA_EQPC_BASE_OFFSET   	 (INIT_HCA_QPC_OFFSET + 0x40)
133162306a36Sopenharmony_ci#define  INIT_HCA_EEEC_BASE_OFFSET   	 (INIT_HCA_QPC_OFFSET + 0x50)
133262306a36Sopenharmony_ci#define  INIT_HCA_EQC_BASE_OFFSET    	 (INIT_HCA_QPC_OFFSET + 0x60)
133362306a36Sopenharmony_ci#define  INIT_HCA_LOG_EQ_OFFSET      	 (INIT_HCA_QPC_OFFSET + 0x67)
133462306a36Sopenharmony_ci#define  INIT_HCA_RDB_BASE_OFFSET    	 (INIT_HCA_QPC_OFFSET + 0x70)
133562306a36Sopenharmony_ci#define INIT_HCA_UDAV_OFFSET         	 0x0b0
133662306a36Sopenharmony_ci#define  INIT_HCA_UDAV_LKEY_OFFSET   	 (INIT_HCA_UDAV_OFFSET + 0x0)
133762306a36Sopenharmony_ci#define  INIT_HCA_UDAV_PD_OFFSET     	 (INIT_HCA_UDAV_OFFSET + 0x4)
133862306a36Sopenharmony_ci#define INIT_HCA_MCAST_OFFSET        	 0x0c0
133962306a36Sopenharmony_ci#define  INIT_HCA_MC_BASE_OFFSET         (INIT_HCA_MCAST_OFFSET + 0x00)
134062306a36Sopenharmony_ci#define  INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12)
134162306a36Sopenharmony_ci#define  INIT_HCA_MC_HASH_SZ_OFFSET      (INIT_HCA_MCAST_OFFSET + 0x16)
134262306a36Sopenharmony_ci#define  INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b)
134362306a36Sopenharmony_ci#define INIT_HCA_TPT_OFFSET              0x0f0
134462306a36Sopenharmony_ci#define  INIT_HCA_MPT_BASE_OFFSET        (INIT_HCA_TPT_OFFSET + 0x00)
134562306a36Sopenharmony_ci#define  INIT_HCA_MTT_SEG_SZ_OFFSET      (INIT_HCA_TPT_OFFSET + 0x09)
134662306a36Sopenharmony_ci#define  INIT_HCA_LOG_MPT_SZ_OFFSET      (INIT_HCA_TPT_OFFSET + 0x0b)
134762306a36Sopenharmony_ci#define  INIT_HCA_MTT_BASE_OFFSET        (INIT_HCA_TPT_OFFSET + 0x10)
134862306a36Sopenharmony_ci#define INIT_HCA_UAR_OFFSET              0x120
134962306a36Sopenharmony_ci#define  INIT_HCA_UAR_BASE_OFFSET        (INIT_HCA_UAR_OFFSET + 0x00)
135062306a36Sopenharmony_ci#define  INIT_HCA_UARC_SZ_OFFSET         (INIT_HCA_UAR_OFFSET + 0x09)
135162306a36Sopenharmony_ci#define  INIT_HCA_LOG_UAR_SZ_OFFSET      (INIT_HCA_UAR_OFFSET + 0x0a)
135262306a36Sopenharmony_ci#define  INIT_HCA_UAR_PAGE_SZ_OFFSET     (INIT_HCA_UAR_OFFSET + 0x0b)
135362306a36Sopenharmony_ci#define  INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
135462306a36Sopenharmony_ci#define  INIT_HCA_UAR_CTX_BASE_OFFSET    (INIT_HCA_UAR_OFFSET + 0x18)
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
135762306a36Sopenharmony_ci	if (IS_ERR(mailbox))
135862306a36Sopenharmony_ci		return PTR_ERR(mailbox);
135962306a36Sopenharmony_ci	inbox = mailbox->buf;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	memset(inbox, 0, INIT_HCA_IN_SIZE);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
136462306a36Sopenharmony_ci		MTHCA_PUT(inbox, 0x1, INIT_HCA_FLAGS1_OFFSET);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
136762306a36Sopenharmony_ci	*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
136862306a36Sopenharmony_ci#elif defined(__BIG_ENDIAN)
136962306a36Sopenharmony_ci	*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1 << 1);
137062306a36Sopenharmony_ci#else
137162306a36Sopenharmony_ci#error Host endianness not defined
137262306a36Sopenharmony_ci#endif
137362306a36Sopenharmony_ci	/* Check port for UD address vector: */
137462306a36Sopenharmony_ci	*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* Enable IPoIB checksumming if we can: */
137762306a36Sopenharmony_ci	if (dev->device_cap_flags & IB_DEVICE_UD_IP_CSUM)
137862306a36Sopenharmony_ci		*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(7 << 3);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	/* We leave wqe_quota, responder_exu, etc as 0 (default) */
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	/* QPC/EEC/CQC/EQC/RDB attributes */
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->qpc_base,     INIT_HCA_QPC_BASE_OFFSET);
138562306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_num_qps,  INIT_HCA_LOG_QP_OFFSET);
138662306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->eec_base,     INIT_HCA_EEC_BASE_OFFSET);
138762306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_num_eecs, INIT_HCA_LOG_EEC_OFFSET);
138862306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->srqc_base,    INIT_HCA_SRQC_BASE_OFFSET);
138962306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET);
139062306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->cqc_base,     INIT_HCA_CQC_BASE_OFFSET);
139162306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_num_cqs,  INIT_HCA_LOG_CQ_OFFSET);
139262306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->eqpc_base,    INIT_HCA_EQPC_BASE_OFFSET);
139362306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->eeec_base,    INIT_HCA_EEEC_BASE_OFFSET);
139462306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->eqc_base,     INIT_HCA_EQC_BASE_OFFSET);
139562306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_num_eqs,  INIT_HCA_LOG_EQ_OFFSET);
139662306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->rdb_base,     INIT_HCA_RDB_BASE_OFFSET);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/* UD AV attributes */
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* multicast attributes */
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->mc_base,         INIT_HCA_MC_BASE_OFFSET);
140362306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
140462306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->mc_hash_sz,      INIT_HCA_MC_HASH_SZ_OFFSET);
140562306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	/* TPT attributes */
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->mpt_base,   INIT_HCA_MPT_BASE_OFFSET);
141062306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
141162306a36Sopenharmony_ci		MTHCA_PUT(inbox, param->mtt_seg_sz, INIT_HCA_MTT_SEG_SZ_OFFSET);
141262306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET);
141362306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->mtt_base,   INIT_HCA_MTT_BASE_OFFSET);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	/* UAR attributes */
141662306a36Sopenharmony_ci	{
141762306a36Sopenharmony_ci		u8 uar_page_sz = PAGE_SHIFT - 12;
141862306a36Sopenharmony_ci		MTHCA_PUT(inbox, uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET);
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->uar_scratch_base, INIT_HCA_UAR_SCATCH_BASE_OFFSET);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (mthca_is_memfree(dev)) {
142462306a36Sopenharmony_ci		MTHCA_PUT(inbox, param->log_uarc_sz, INIT_HCA_UARC_SZ_OFFSET);
142562306a36Sopenharmony_ci		MTHCA_PUT(inbox, param->log_uar_sz,  INIT_HCA_LOG_UAR_SZ_OFFSET);
142662306a36Sopenharmony_ci		MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
142762306a36Sopenharmony_ci	}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	err = mthca_cmd(dev, mailbox->dma, 0, 0,
143062306a36Sopenharmony_ci			CMD_INIT_HCA, CMD_TIME_CLASS_D);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
143362306a36Sopenharmony_ci	return err;
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ciint mthca_INIT_IB(struct mthca_dev *dev,
143762306a36Sopenharmony_ci		  struct mthca_init_ib_param *param,
143862306a36Sopenharmony_ci		  int port)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
144162306a36Sopenharmony_ci	u32 *inbox;
144262306a36Sopenharmony_ci	int err;
144362306a36Sopenharmony_ci	u32 flags;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci#define INIT_IB_IN_SIZE          56
144662306a36Sopenharmony_ci#define INIT_IB_FLAGS_OFFSET     0x00
144762306a36Sopenharmony_ci#define INIT_IB_FLAG_SIG         (1 << 18)
144862306a36Sopenharmony_ci#define INIT_IB_FLAG_NG          (1 << 17)
144962306a36Sopenharmony_ci#define INIT_IB_FLAG_G0          (1 << 16)
145062306a36Sopenharmony_ci#define INIT_IB_VL_SHIFT         4
145162306a36Sopenharmony_ci#define INIT_IB_PORT_WIDTH_SHIFT 8
145262306a36Sopenharmony_ci#define INIT_IB_MTU_SHIFT        12
145362306a36Sopenharmony_ci#define INIT_IB_MAX_GID_OFFSET   0x06
145462306a36Sopenharmony_ci#define INIT_IB_MAX_PKEY_OFFSET  0x0a
145562306a36Sopenharmony_ci#define INIT_IB_GUID0_OFFSET     0x10
145662306a36Sopenharmony_ci#define INIT_IB_NODE_GUID_OFFSET 0x18
145762306a36Sopenharmony_ci#define INIT_IB_SI_GUID_OFFSET   0x20
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
146062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
146162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
146262306a36Sopenharmony_ci	inbox = mailbox->buf;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	memset(inbox, 0, INIT_IB_IN_SIZE);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	flags = 0;
146762306a36Sopenharmony_ci	flags |= param->set_guid0     ? INIT_IB_FLAG_G0  : 0;
146862306a36Sopenharmony_ci	flags |= param->set_node_guid ? INIT_IB_FLAG_NG  : 0;
146962306a36Sopenharmony_ci	flags |= param->set_si_guid   ? INIT_IB_FLAG_SIG : 0;
147062306a36Sopenharmony_ci	flags |= param->vl_cap << INIT_IB_VL_SHIFT;
147162306a36Sopenharmony_ci	flags |= param->port_width << INIT_IB_PORT_WIDTH_SHIFT;
147262306a36Sopenharmony_ci	flags |= param->mtu_cap << INIT_IB_MTU_SHIFT;
147362306a36Sopenharmony_ci	MTHCA_PUT(inbox, flags, INIT_IB_FLAGS_OFFSET);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->gid_cap,   INIT_IB_MAX_GID_OFFSET);
147662306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->pkey_cap,  INIT_IB_MAX_PKEY_OFFSET);
147762306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->guid0,     INIT_IB_GUID0_OFFSET);
147862306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
147962306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->si_guid,   INIT_IB_SI_GUID_OFFSET);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
148262306a36Sopenharmony_ci			CMD_TIME_CLASS_A);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
148562306a36Sopenharmony_ci	return err;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ciint mthca_CLOSE_IB(struct mthca_dev *dev, int port)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	return mthca_cmd(dev, 0, port, 0, CMD_CLOSE_IB, CMD_TIME_CLASS_A);
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ciint mthca_CLOSE_HCA(struct mthca_dev *dev, int panic)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, panic, CMD_CLOSE_HCA, CMD_TIME_CLASS_C);
149662306a36Sopenharmony_ci}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ciint mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
149962306a36Sopenharmony_ci		 int port)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
150262306a36Sopenharmony_ci	u32 *inbox;
150362306a36Sopenharmony_ci	int err;
150462306a36Sopenharmony_ci	u32 flags = 0;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci#define SET_IB_IN_SIZE         0x40
150762306a36Sopenharmony_ci#define SET_IB_FLAGS_OFFSET    0x00
150862306a36Sopenharmony_ci#define SET_IB_FLAG_SIG        (1 << 18)
150962306a36Sopenharmony_ci#define SET_IB_FLAG_RQK        (1 <<  0)
151062306a36Sopenharmony_ci#define SET_IB_CAP_MASK_OFFSET 0x04
151162306a36Sopenharmony_ci#define SET_IB_SI_GUID_OFFSET  0x08
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
151462306a36Sopenharmony_ci	if (IS_ERR(mailbox))
151562306a36Sopenharmony_ci		return PTR_ERR(mailbox);
151662306a36Sopenharmony_ci	inbox = mailbox->buf;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	memset(inbox, 0, SET_IB_IN_SIZE);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	flags |= param->set_si_guid     ? SET_IB_FLAG_SIG : 0;
152162306a36Sopenharmony_ci	flags |= param->reset_qkey_viol ? SET_IB_FLAG_RQK : 0;
152262306a36Sopenharmony_ci	MTHCA_PUT(inbox, flags, SET_IB_FLAGS_OFFSET);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
152562306a36Sopenharmony_ci	MTHCA_PUT(inbox, param->si_guid,  SET_IB_SI_GUID_OFFSET);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
152862306a36Sopenharmony_ci			CMD_TIME_CLASS_B);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
153162306a36Sopenharmony_ci	return err;
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ciint mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	return mthca_map_cmd(dev, CMD_MAP_ICM, icm, virt);
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ciint mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
154262306a36Sopenharmony_ci	__be64 *inbox;
154362306a36Sopenharmony_ci	int err;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
154662306a36Sopenharmony_ci	if (IS_ERR(mailbox))
154762306a36Sopenharmony_ci		return PTR_ERR(mailbox);
154862306a36Sopenharmony_ci	inbox = mailbox->buf;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	inbox[0] = cpu_to_be64(virt);
155162306a36Sopenharmony_ci	inbox[1] = cpu_to_be64(dma_addr);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
155462306a36Sopenharmony_ci			CMD_TIME_CLASS_B);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (!err)
155962306a36Sopenharmony_ci		mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
156062306a36Sopenharmony_ci			  (unsigned long long) dma_addr, (unsigned long long) virt);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	return err;
156362306a36Sopenharmony_ci}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ciint mthca_UNMAP_ICM(struct mthca_dev *dev, u64 virt, u32 page_count)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	mthca_dbg(dev, "Unmapping %d pages at %llx from ICM.\n",
156862306a36Sopenharmony_ci		  page_count, (unsigned long long) virt);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	return mthca_cmd(dev, virt, page_count, 0,
157162306a36Sopenharmony_ci			CMD_UNMAP_ICM, CMD_TIME_CLASS_B);
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ciint mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	return mthca_map_cmd(dev, CMD_MAP_ICM_AUX, icm, -1);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ciint mthca_UNMAP_ICM_AUX(struct mthca_dev *dev)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, 0, CMD_UNMAP_ICM_AUX, CMD_TIME_CLASS_B);
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ciint mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	int ret = mthca_cmd_imm(dev, icm_size, aux_pages, 0,
158762306a36Sopenharmony_ci			0, CMD_SET_ICM_SIZE, CMD_TIME_CLASS_A);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	if (ret)
159062306a36Sopenharmony_ci		return ret;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	/*
159362306a36Sopenharmony_ci	 * Round up number of system pages needed in case
159462306a36Sopenharmony_ci	 * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
159562306a36Sopenharmony_ci	 */
159662306a36Sopenharmony_ci	*aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
159762306a36Sopenharmony_ci		(PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	return 0;
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ciint mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
160362306a36Sopenharmony_ci		    int mpt_index)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
160662306a36Sopenharmony_ci			 CMD_TIME_CLASS_B);
160762306a36Sopenharmony_ci}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ciint mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
161062306a36Sopenharmony_ci		    int mpt_index)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
161362306a36Sopenharmony_ci			     !mailbox, CMD_HW2SW_MPT,
161462306a36Sopenharmony_ci			     CMD_TIME_CLASS_B);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ciint mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
161862306a36Sopenharmony_ci		    int num_mtt)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
162162306a36Sopenharmony_ci			 CMD_TIME_CLASS_B);
162262306a36Sopenharmony_ci}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ciint mthca_SYNC_TPT(struct mthca_dev *dev)
162562306a36Sopenharmony_ci{
162662306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0, 0, CMD_SYNC_TPT, CMD_TIME_CLASS_B);
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ciint mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
163062306a36Sopenharmony_ci		 int eq_num)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	mthca_dbg(dev, "%s mask %016llx for eqn %d\n",
163362306a36Sopenharmony_ci		  unmap ? "Clearing" : "Setting",
163462306a36Sopenharmony_ci		  (unsigned long long) event_mask, eq_num);
163562306a36Sopenharmony_ci	return mthca_cmd(dev, event_mask, (unmap << 31) | eq_num,
163662306a36Sopenharmony_ci			 0, CMD_MAP_EQ, CMD_TIME_CLASS_B);
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ciint mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
164062306a36Sopenharmony_ci		   int eq_num)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
164362306a36Sopenharmony_ci			 CMD_TIME_CLASS_A);
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ciint mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
164762306a36Sopenharmony_ci		   int eq_num)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
165062306a36Sopenharmony_ci			     CMD_HW2SW_EQ,
165162306a36Sopenharmony_ci			     CMD_TIME_CLASS_A);
165262306a36Sopenharmony_ci}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ciint mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
165562306a36Sopenharmony_ci		   int cq_num)
165662306a36Sopenharmony_ci{
165762306a36Sopenharmony_ci	return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
165862306a36Sopenharmony_ci			CMD_TIME_CLASS_A);
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ciint mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
166262306a36Sopenharmony_ci		   int cq_num)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
166562306a36Sopenharmony_ci			     CMD_HW2SW_CQ,
166662306a36Sopenharmony_ci			     CMD_TIME_CLASS_A);
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ciint mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	struct mthca_mailbox *mailbox;
167262306a36Sopenharmony_ci	__be32 *inbox;
167362306a36Sopenharmony_ci	int err;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci#define RESIZE_CQ_IN_SIZE		0x40
167662306a36Sopenharmony_ci#define RESIZE_CQ_LOG_SIZE_OFFSET	0x0c
167762306a36Sopenharmony_ci#define RESIZE_CQ_LKEY_OFFSET		0x1c
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
168062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
168162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
168262306a36Sopenharmony_ci	inbox = mailbox->buf;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	memset(inbox, 0, RESIZE_CQ_IN_SIZE);
168562306a36Sopenharmony_ci	/*
168662306a36Sopenharmony_ci	 * Leave start address fields zeroed out -- mthca assumes that
168762306a36Sopenharmony_ci	 * MRs for CQs always start at virtual address 0.
168862306a36Sopenharmony_ci	 */
168962306a36Sopenharmony_ci	MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET);
169062306a36Sopenharmony_ci	MTHCA_PUT(inbox, lkey,     RESIZE_CQ_LKEY_OFFSET);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ,
169362306a36Sopenharmony_ci			CMD_TIME_CLASS_B);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
169662306a36Sopenharmony_ci	return err;
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ciint mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
170062306a36Sopenharmony_ci		    int srq_num)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	return mthca_cmd(dev, mailbox->dma, srq_num, 0, CMD_SW2HW_SRQ,
170362306a36Sopenharmony_ci			CMD_TIME_CLASS_A);
170462306a36Sopenharmony_ci}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ciint mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
170762306a36Sopenharmony_ci		    int srq_num)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox->dma, srq_num, 0,
171062306a36Sopenharmony_ci			     CMD_HW2SW_SRQ,
171162306a36Sopenharmony_ci			     CMD_TIME_CLASS_A);
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ciint mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
171562306a36Sopenharmony_ci		    struct mthca_mailbox *mailbox)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox->dma, num, 0,
171862306a36Sopenharmony_ci			     CMD_QUERY_SRQ, CMD_TIME_CLASS_A);
171962306a36Sopenharmony_ci}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ciint mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit)
172262306a36Sopenharmony_ci{
172362306a36Sopenharmony_ci	return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
172462306a36Sopenharmony_ci			 CMD_TIME_CLASS_B);
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ciint mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
172862306a36Sopenharmony_ci		    enum ib_qp_state next, u32 num, int is_ee,
172962306a36Sopenharmony_ci		    struct mthca_mailbox *mailbox, u32 optmask)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
173262306a36Sopenharmony_ci		[IB_QPS_RESET] = {
173362306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
173462306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
173562306a36Sopenharmony_ci			[IB_QPS_INIT]	= CMD_RST2INIT_QPEE,
173662306a36Sopenharmony_ci		},
173762306a36Sopenharmony_ci		[IB_QPS_INIT]  = {
173862306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
173962306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
174062306a36Sopenharmony_ci			[IB_QPS_INIT]	= CMD_INIT2INIT_QPEE,
174162306a36Sopenharmony_ci			[IB_QPS_RTR]	= CMD_INIT2RTR_QPEE,
174262306a36Sopenharmony_ci		},
174362306a36Sopenharmony_ci		[IB_QPS_RTR]   = {
174462306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
174562306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
174662306a36Sopenharmony_ci			[IB_QPS_RTS]	= CMD_RTR2RTS_QPEE,
174762306a36Sopenharmony_ci		},
174862306a36Sopenharmony_ci		[IB_QPS_RTS]   = {
174962306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
175062306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
175162306a36Sopenharmony_ci			[IB_QPS_RTS]	= CMD_RTS2RTS_QPEE,
175262306a36Sopenharmony_ci			[IB_QPS_SQD]	= CMD_RTS2SQD_QPEE,
175362306a36Sopenharmony_ci		},
175462306a36Sopenharmony_ci		[IB_QPS_SQD] = {
175562306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
175662306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
175762306a36Sopenharmony_ci			[IB_QPS_RTS]	= CMD_SQD2RTS_QPEE,
175862306a36Sopenharmony_ci			[IB_QPS_SQD]	= CMD_SQD2SQD_QPEE,
175962306a36Sopenharmony_ci		},
176062306a36Sopenharmony_ci		[IB_QPS_SQE] = {
176162306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
176262306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
176362306a36Sopenharmony_ci			[IB_QPS_RTS]	= CMD_SQERR2RTS_QPEE,
176462306a36Sopenharmony_ci		},
176562306a36Sopenharmony_ci		[IB_QPS_ERR] = {
176662306a36Sopenharmony_ci			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
176762306a36Sopenharmony_ci			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
176862306a36Sopenharmony_ci		}
176962306a36Sopenharmony_ci	};
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	u8 op_mod = 0;
177262306a36Sopenharmony_ci	int my_mailbox = 0;
177362306a36Sopenharmony_ci	int err;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	if (op[cur][next] == CMD_ERR2RST_QPEE) {
177662306a36Sopenharmony_ci		op_mod = 3;	/* don't write outbox, any->reset */
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		/* For debugging */
177962306a36Sopenharmony_ci		if (!mailbox) {
178062306a36Sopenharmony_ci			mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
178162306a36Sopenharmony_ci			if (!IS_ERR(mailbox)) {
178262306a36Sopenharmony_ci				my_mailbox = 1;
178362306a36Sopenharmony_ci				op_mod     = 2;	/* write outbox, any->reset */
178462306a36Sopenharmony_ci			} else
178562306a36Sopenharmony_ci				mailbox = NULL;
178662306a36Sopenharmony_ci		}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci		err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
178962306a36Sopenharmony_ci				    (!!is_ee << 24) | num, op_mod,
179062306a36Sopenharmony_ci				    op[cur][next], CMD_TIME_CLASS_C);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci		if (0 && mailbox) {
179362306a36Sopenharmony_ci			int i;
179462306a36Sopenharmony_ci			mthca_dbg(dev, "Dumping QP context:\n");
179562306a36Sopenharmony_ci			printk(" %08x\n", be32_to_cpup(mailbox->buf));
179662306a36Sopenharmony_ci			for (i = 0; i < 0x100 / 4; ++i) {
179762306a36Sopenharmony_ci				if (i % 8 == 0)
179862306a36Sopenharmony_ci					printk("[%02x] ", i * 4);
179962306a36Sopenharmony_ci				printk(" %08x",
180062306a36Sopenharmony_ci				       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
180162306a36Sopenharmony_ci				if ((i + 1) % 8 == 0)
180262306a36Sopenharmony_ci					printk("\n");
180362306a36Sopenharmony_ci			}
180462306a36Sopenharmony_ci		}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci		if (my_mailbox)
180762306a36Sopenharmony_ci			mthca_free_mailbox(dev, mailbox);
180862306a36Sopenharmony_ci	} else {
180962306a36Sopenharmony_ci		if (0) {
181062306a36Sopenharmony_ci			int i;
181162306a36Sopenharmony_ci			mthca_dbg(dev, "Dumping QP context:\n");
181262306a36Sopenharmony_ci			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
181362306a36Sopenharmony_ci			for (i = 0; i < 0x100 / 4; ++i) {
181462306a36Sopenharmony_ci				if (i % 8 == 0)
181562306a36Sopenharmony_ci					printk("  [%02x] ", i * 4);
181662306a36Sopenharmony_ci				printk(" %08x",
181762306a36Sopenharmony_ci				       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
181862306a36Sopenharmony_ci				if ((i + 1) % 8 == 0)
181962306a36Sopenharmony_ci					printk("\n");
182062306a36Sopenharmony_ci			}
182162306a36Sopenharmony_ci		}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num,
182462306a36Sopenharmony_ci				op_mod, op[cur][next], CMD_TIME_CLASS_C);
182562306a36Sopenharmony_ci	}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	return err;
182862306a36Sopenharmony_ci}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ciint mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
183162306a36Sopenharmony_ci		   struct mthca_mailbox *mailbox)
183262306a36Sopenharmony_ci{
183362306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
183462306a36Sopenharmony_ci			     CMD_QUERY_QPEE, CMD_TIME_CLASS_A);
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ciint mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	u8 op_mod;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	switch (type) {
184262306a36Sopenharmony_ci	case IB_QPT_SMI:
184362306a36Sopenharmony_ci		op_mod = 0;
184462306a36Sopenharmony_ci		break;
184562306a36Sopenharmony_ci	case IB_QPT_GSI:
184662306a36Sopenharmony_ci		op_mod = 1;
184762306a36Sopenharmony_ci		break;
184862306a36Sopenharmony_ci	case IB_QPT_RAW_IPV6:
184962306a36Sopenharmony_ci		op_mod = 2;
185062306a36Sopenharmony_ci		break;
185162306a36Sopenharmony_ci	case IB_QPT_RAW_ETHERTYPE:
185262306a36Sopenharmony_ci		op_mod = 3;
185362306a36Sopenharmony_ci		break;
185462306a36Sopenharmony_ci	default:
185562306a36Sopenharmony_ci		return -EINVAL;
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	return mthca_cmd(dev, 0, qpn, op_mod, CMD_CONF_SPECIAL_QP,
185962306a36Sopenharmony_ci			 CMD_TIME_CLASS_B);
186062306a36Sopenharmony_ci}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ciint mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
186362306a36Sopenharmony_ci		  int port, const struct ib_wc *in_wc, const struct ib_grh *in_grh,
186462306a36Sopenharmony_ci		  const void *in_mad, void *response_mad)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	struct mthca_mailbox *inmailbox, *outmailbox;
186762306a36Sopenharmony_ci	void *inbox;
186862306a36Sopenharmony_ci	int err;
186962306a36Sopenharmony_ci	u32 in_modifier = port;
187062306a36Sopenharmony_ci	u8 op_modifier = 0;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci#define MAD_IFC_BOX_SIZE      0x400
187362306a36Sopenharmony_ci#define MAD_IFC_MY_QPN_OFFSET 0x100
187462306a36Sopenharmony_ci#define MAD_IFC_RQPN_OFFSET   0x108
187562306a36Sopenharmony_ci#define MAD_IFC_SL_OFFSET     0x10c
187662306a36Sopenharmony_ci#define MAD_IFC_G_PATH_OFFSET 0x10d
187762306a36Sopenharmony_ci#define MAD_IFC_RLID_OFFSET   0x10e
187862306a36Sopenharmony_ci#define MAD_IFC_PKEY_OFFSET   0x112
187962306a36Sopenharmony_ci#define MAD_IFC_GRH_OFFSET    0x140
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
188262306a36Sopenharmony_ci	if (IS_ERR(inmailbox))
188362306a36Sopenharmony_ci		return PTR_ERR(inmailbox);
188462306a36Sopenharmony_ci	inbox = inmailbox->buf;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
188762306a36Sopenharmony_ci	if (IS_ERR(outmailbox)) {
188862306a36Sopenharmony_ci		mthca_free_mailbox(dev, inmailbox);
188962306a36Sopenharmony_ci		return PTR_ERR(outmailbox);
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	memcpy(inbox, in_mad, 256);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	/*
189562306a36Sopenharmony_ci	 * Key check traps can't be generated unless we have in_wc to
189662306a36Sopenharmony_ci	 * tell us where to send the trap.
189762306a36Sopenharmony_ci	 */
189862306a36Sopenharmony_ci	if (ignore_mkey || !in_wc)
189962306a36Sopenharmony_ci		op_modifier |= 0x1;
190062306a36Sopenharmony_ci	if (ignore_bkey || !in_wc)
190162306a36Sopenharmony_ci		op_modifier |= 0x2;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	if (in_wc) {
190462306a36Sopenharmony_ci		u8 val;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		memset(inbox + 256, 0, 256);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci		MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET);
190962306a36Sopenharmony_ci		MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci		val = in_wc->sl << 4;
191262306a36Sopenharmony_ci		MTHCA_PUT(inbox, val,               MAD_IFC_SL_OFFSET);
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci		val = in_wc->dlid_path_bits |
191562306a36Sopenharmony_ci			(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
191662306a36Sopenharmony_ci		MTHCA_PUT(inbox, val,               MAD_IFC_G_PATH_OFFSET);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci		MTHCA_PUT(inbox, ib_lid_cpu16(in_wc->slid), MAD_IFC_RLID_OFFSET);
191962306a36Sopenharmony_ci		MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci		if (in_grh)
192262306a36Sopenharmony_ci			memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci		op_modifier |= 0x4;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci		in_modifier |= ib_lid_cpu16(in_wc->slid) << 16;
192762306a36Sopenharmony_ci	}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
193062306a36Sopenharmony_ci			    in_modifier, op_modifier,
193162306a36Sopenharmony_ci			    CMD_MAD_IFC, CMD_TIME_CLASS_C);
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	if (!err)
193462306a36Sopenharmony_ci		memcpy(response_mad, outmailbox->buf, 256);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	mthca_free_mailbox(dev, inmailbox);
193762306a36Sopenharmony_ci	mthca_free_mailbox(dev, outmailbox);
193862306a36Sopenharmony_ci	return err;
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ciint mthca_READ_MGM(struct mthca_dev *dev, int index,
194262306a36Sopenharmony_ci		   struct mthca_mailbox *mailbox)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
194562306a36Sopenharmony_ci			     CMD_READ_MGM, CMD_TIME_CLASS_A);
194662306a36Sopenharmony_ci}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ciint mthca_WRITE_MGM(struct mthca_dev *dev, int index,
194962306a36Sopenharmony_ci		    struct mthca_mailbox *mailbox)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
195262306a36Sopenharmony_ci			 CMD_TIME_CLASS_A);
195362306a36Sopenharmony_ci}
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ciint mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
195662306a36Sopenharmony_ci		    u16 *hash)
195762306a36Sopenharmony_ci{
195862306a36Sopenharmony_ci	u64 imm = 0;
195962306a36Sopenharmony_ci	int err;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
196262306a36Sopenharmony_ci			    CMD_TIME_CLASS_A);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	*hash = imm;
196562306a36Sopenharmony_ci	return err;
196662306a36Sopenharmony_ci}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ciint mthca_NOP(struct mthca_dev *dev)
196962306a36Sopenharmony_ci{
197062306a36Sopenharmony_ci	return mthca_cmd(dev, 0, 0x1f, 0, CMD_NOP, msecs_to_jiffies(100));
197162306a36Sopenharmony_ci}
1972