1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3272407Shselasky * Copyright (c) 2005, 2006, 2007, 2008, 2014 Mellanox Technologies. All rights reserved.
4219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff */
34219820Sjeff
35324685Shselasky#define	LINUXKPI_PARAM_PREFIX mlx4_
36324685Shselasky
37272407Shselasky#include <linux/etherdevice.h>
38219820Sjeff#include <linux/mlx4/cmd.h>
39255932Salfred#include <linux/module.h>
40272407Shselasky#include <linux/cache.h>
41219820Sjeff
42219820Sjeff#include "fw.h"
43219820Sjeff#include "icm.h"
44219820Sjeff
45219820Sjeffenum {
46219820Sjeff	MLX4_COMMAND_INTERFACE_MIN_REV		= 2,
47219820Sjeff	MLX4_COMMAND_INTERFACE_MAX_REV		= 3,
48219820Sjeff	MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS	= 3,
49219820Sjeff};
50219820Sjeff
51219820Sjeffextern void __buggy_use_of_MLX4_GET(void);
52219820Sjeffextern void __buggy_use_of_MLX4_PUT(void);
53219820Sjeff
54324685Shselaskystatic int enable_qos;
55324685Shselaskymodule_param(enable_qos, int, 0444);
56219820SjeffMODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)");
57219820Sjeff
58219820Sjeff#define MLX4_GET(dest, source, offset)				      \
59219820Sjeff	do {							      \
60219820Sjeff		void *__p = (char *) (source) + (offset);	      \
61219820Sjeff		switch (sizeof (dest)) {			      \
62219820Sjeff		case 1: (dest) = *(u8 *) __p;	    break;	      \
63219820Sjeff		case 2: (dest) = be16_to_cpup(__p); break;	      \
64219820Sjeff		case 4: (dest) = be32_to_cpup(__p); break;	      \
65219820Sjeff		case 8: (dest) = be64_to_cpup(__p); break;	      \
66219820Sjeff		default: __buggy_use_of_MLX4_GET();		      \
67219820Sjeff		}						      \
68219820Sjeff	} while (0)
69219820Sjeff
70219820Sjeff#define MLX4_PUT(dest, source, offset)				      \
71219820Sjeff	do {							      \
72219820Sjeff		void *__d = ((char *) (dest) + (offset));	      \
73219820Sjeff		switch (sizeof(source)) {			      \
74219820Sjeff		case 1: *(u8 *) __d = (source);		       break; \
75219820Sjeff		case 2:	*(__be16 *) __d = cpu_to_be16(source); break; \
76219820Sjeff		case 4:	*(__be32 *) __d = cpu_to_be32(source); break; \
77219820Sjeff		case 8:	*(__be64 *) __d = cpu_to_be64(source); break; \
78219820Sjeff		default: __buggy_use_of_MLX4_PUT();		      \
79219820Sjeff		}						      \
80219820Sjeff	} while (0)
81219820Sjeff
82219820Sjeffstatic void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
83219820Sjeff{
84219820Sjeff	static const char *fname[] = {
85219820Sjeff		[ 0] = "RC transport",
86219820Sjeff		[ 1] = "UC transport",
87219820Sjeff		[ 2] = "UD transport",
88219820Sjeff		[ 3] = "XRC transport",
89219820Sjeff		[ 4] = "reliable multicast",
90219820Sjeff		[ 5] = "FCoIB support",
91219820Sjeff		[ 6] = "SRQ support",
92219820Sjeff		[ 7] = "IPoIB checksum offload",
93219820Sjeff		[ 8] = "P_Key violation counter",
94219820Sjeff		[ 9] = "Q_Key violation counter",
95219820Sjeff		[10] = "VMM",
96219820Sjeff		[12] = "DPDP",
97255932Salfred		[15] = "Big LSO headers",
98219820Sjeff		[16] = "MW support",
99219820Sjeff		[17] = "APM support",
100219820Sjeff		[18] = "Atomic ops support",
101219820Sjeff		[19] = "Raw multicast support",
102219820Sjeff		[20] = "Address vector port checking support",
103219820Sjeff		[21] = "UD multicast support",
104219820Sjeff		[24] = "Demand paging support",
105219820Sjeff		[25] = "Router support",
106219820Sjeff		[30] = "IBoE support",
107255932Salfred		[32] = "Unicast loopback support",
108255932Salfred		[34] = "FCS header control",
109255932Salfred		[38] = "Wake On LAN support",
110255932Salfred		[40] = "UDP RSS support",
111255932Salfred		[41] = "Unicast VEP steering support",
112255932Salfred		[42] = "Multicast VEP steering support",
113272407Shselasky		[44] = "Cross-channel (sync_qp) operations support",
114255932Salfred		[48] = "Counters support",
115255932Salfred		[59] = "Port management change event support",
116255932Salfred		[60] = "eSwitch support",
117255932Salfred		[61] = "64 byte EQE support",
118255932Salfred		[62] = "64 byte CQE support",
119219820Sjeff	};
120219820Sjeff	int i;
121219820Sjeff
122219820Sjeff	mlx4_dbg(dev, "DEV_CAP flags:\n");
123219820Sjeff	for (i = 0; i < ARRAY_SIZE(fname); ++i)
124219820Sjeff		if (fname[i] && (flags & (1LL << i)))
125219820Sjeff			mlx4_dbg(dev, "    %s\n", fname[i]);
126219820Sjeff}
127219820Sjeff
128255932Salfredstatic void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
129255932Salfred{
130255932Salfred	static const char * const fname[] = {
131255932Salfred		[0] = "RSS support",
132255932Salfred		[1] = "RSS Toeplitz Hash Function support",
133255932Salfred		[2] = "RSS XOR Hash Function support",
134272407Shselasky		[3] = "Device manage flow steering support",
135272407Shselasky		[4] = "FSM (MAC unti-spoofing) support",
136272407Shselasky		[5] = "VST (control vlan insertion/stripping) support",
137272407Shselasky		[6] = "Dynamic QP updates support",
138272407Shselasky		[7] = "Loopback source checks support",
139272407Shselasky		[8] = "Device managed flow steering IPoIB support",
140272407Shselasky		[9] = "ETS configuration support",
141272407Shselasky		[10] = "ETH backplane autoneg report",
142272407Shselasky		[11] = "Ethernet Flow control statistics support",
143272407Shselasky		[12] = "Recoverable error events support",
144272407Shselasky		[13] = "Time stamping support",
145272407Shselasky		[14] = "Report driver version to FW support"
146255932Salfred	};
147255932Salfred	int i;
148255932Salfred
149255932Salfred	for (i = 0; i < ARRAY_SIZE(fname); ++i)
150255932Salfred		if (fname[i] && (flags & (1LL << i)))
151255932Salfred			mlx4_dbg(dev, "    %s\n", fname[i]);
152255932Salfred}
153255932Salfred
154219820Sjeffint mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
155219820Sjeff{
156219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
157219820Sjeff	u32 *inbox;
158219820Sjeff	int err = 0;
159219820Sjeff
160219820Sjeff#define MOD_STAT_CFG_IN_SIZE		0x100
161219820Sjeff
162219820Sjeff#define MOD_STAT_CFG_PG_SZ_M_OFFSET	0x002
163219820Sjeff#define MOD_STAT_CFG_PG_SZ_OFFSET	0x003
164219820Sjeff
165219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
166219820Sjeff	if (IS_ERR(mailbox))
167219820Sjeff		return PTR_ERR(mailbox);
168219820Sjeff	inbox = mailbox->buf;
169219820Sjeff
170219820Sjeff	memset(inbox, 0, MOD_STAT_CFG_IN_SIZE);
171219820Sjeff
172219820Sjeff	MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET);
173219820Sjeff	MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET);
174219820Sjeff
175219820Sjeff	err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG,
176255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
177219820Sjeff
178219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
179219820Sjeff	return err;
180219820Sjeff}
181219820Sjeff
182318536Shselaskyint mlx4_QUERY_FUNC(struct mlx4_dev *dev, struct mlx4_func *func, int slave)
183318536Shselasky{
184318536Shselasky	struct mlx4_cmd_mailbox *mailbox;
185318536Shselasky	u32 *outbox;
186318536Shselasky	u8 in_modifier;
187318536Shselasky	u8 field;
188318536Shselasky	u16 field16;
189318536Shselasky	int err;
190318536Shselasky
191318536Shselasky#define QUERY_FUNC_BUS_OFFSET			0x00
192318536Shselasky#define QUERY_FUNC_DEVICE_OFFSET		0x01
193318536Shselasky#define QUERY_FUNC_FUNCTION_OFFSET		0x01
194318536Shselasky#define QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET	0x03
195318536Shselasky#define QUERY_FUNC_RSVD_EQS_OFFSET		0x04
196318536Shselasky#define QUERY_FUNC_MAX_EQ_OFFSET		0x06
197318536Shselasky#define QUERY_FUNC_RSVD_UARS_OFFSET		0x0b
198318536Shselasky
199318536Shselasky	mailbox = mlx4_alloc_cmd_mailbox(dev);
200318536Shselasky	if (IS_ERR(mailbox))
201318536Shselasky		return PTR_ERR(mailbox);
202318536Shselasky	outbox = mailbox->buf;
203318536Shselasky
204318536Shselasky	in_modifier = slave;
205318536Shselasky
206318536Shselasky	err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, 0,
207318536Shselasky			MLX4_CMD_QUERY_FUNC,
208318536Shselasky			MLX4_CMD_TIME_CLASS_A,
209318536Shselasky			MLX4_CMD_NATIVE);
210318536Shselasky	if (err)
211318536Shselasky	        goto out;
212318536Shselasky
213318536Shselasky	MLX4_GET(field, outbox, QUERY_FUNC_BUS_OFFSET);
214318536Shselasky	func->bus = field & 0xf;
215318536Shselasky	MLX4_GET(field, outbox, QUERY_FUNC_DEVICE_OFFSET);
216318536Shselasky	func->device = field & 0xf1;
217318536Shselasky	MLX4_GET(field, outbox, QUERY_FUNC_FUNCTION_OFFSET);
218318536Shselasky	func->function = field & 0x7;
219318536Shselasky	MLX4_GET(field, outbox, QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET);
220318536Shselasky	func->physical_function = field & 0xf;
221318536Shselasky	MLX4_GET(field16, outbox, QUERY_FUNC_RSVD_EQS_OFFSET);
222318536Shselasky	func->rsvd_eqs = field16 & 0xffff;
223318536Shselasky	MLX4_GET(field16, outbox, QUERY_FUNC_MAX_EQ_OFFSET);
224318536Shselasky	func->max_eq = field16 & 0xffff;
225318536Shselasky	MLX4_GET(field, outbox, QUERY_FUNC_RSVD_UARS_OFFSET);
226318536Shselasky	func->rsvd_uars = field & 0x0f;
227318536Shselasky
228318536Shselasky	mlx4_dbg(dev, "Bus: %d, Device: %d, Function: %d, Physical function: %d, Max EQs: %d, Reserved EQs: %d, Reserved UARs: %d\n",
229318536Shselasky		func->bus, func->device, func->function, func->physical_function,
230318536Shselasky		func->max_eq, func->rsvd_eqs, func->rsvd_uars);
231318536Shselaskyout:
232318536Shselasky	mlx4_free_cmd_mailbox(dev, mailbox);
233318536Shselasky	return err;
234318536Shselasky}
235318536Shselasky
236255932Salfredint mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
237255932Salfred				struct mlx4_vhcr *vhcr,
238255932Salfred				struct mlx4_cmd_mailbox *inbox,
239255932Salfred				struct mlx4_cmd_mailbox *outbox,
240255932Salfred				struct mlx4_cmd_info *cmd)
241255932Salfred{
242255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
243272407Shselasky	u8	field, port;
244255932Salfred	u32	size;
245255932Salfred	int	err = 0;
246318536Shselasky	struct mlx4_func func;
247255932Salfred
248255932Salfred#define QUERY_FUNC_CAP_FLAGS_OFFSET		0x0
249255932Salfred#define QUERY_FUNC_CAP_NUM_PORTS_OFFSET		0x1
250255932Salfred#define QUERY_FUNC_CAP_PF_BHVR_OFFSET		0x4
251255932Salfred#define QUERY_FUNC_CAP_FMR_OFFSET		0x8
252272407Shselasky#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP	0x10
253272407Shselasky#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP	0x14
254272407Shselasky#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP	0x18
255272407Shselasky#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP	0x20
256272407Shselasky#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP	0x24
257272407Shselasky#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP	0x28
258255932Salfred#define QUERY_FUNC_CAP_MAX_EQ_OFFSET		0x2c
259255932Salfred#define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET	0x30
260255932Salfred
261272407Shselasky#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET		0x50
262272407Shselasky#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET		0x54
263272407Shselasky#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET		0x58
264272407Shselasky#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET		0x60
265272407Shselasky#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET		0x64
266272407Shselasky#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET		0x68
267272407Shselasky
268318533Shselasky#define QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET	0x6c
269318533Shselasky
270255932Salfred#define QUERY_FUNC_CAP_FMR_FLAG			0x80
271255932Salfred#define QUERY_FUNC_CAP_FLAG_RDMA		0x40
272255932Salfred#define QUERY_FUNC_CAP_FLAG_ETH			0x80
273272407Shselasky#define QUERY_FUNC_CAP_FLAG_QUOTAS		0x10
274318533Shselasky#define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX	0x04
275255932Salfred
276318533Shselasky#define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG	(1UL << 31)
277318533Shselasky
278255932Salfred/* when opcode modifier = 1 */
279255932Salfred#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET		0x3
280272407Shselasky#define QUERY_FUNC_CAP_FLAGS0_OFFSET		0x8
281272407Shselasky#define QUERY_FUNC_CAP_FLAGS1_OFFSET		0xc
282272407Shselasky#define QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET	0xd
283255932Salfred
284255932Salfred#define QUERY_FUNC_CAP_QP0_TUNNEL		0x10
285255932Salfred#define QUERY_FUNC_CAP_QP0_PROXY		0x14
286255932Salfred#define QUERY_FUNC_CAP_QP1_TUNNEL		0x18
287255932Salfred#define QUERY_FUNC_CAP_QP1_PROXY		0x1c
288255932Salfred
289255932Salfred#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC	0x40
290255932Salfred#define QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN	0x80
291272407Shselasky#define QUERY_FUNC_CAP_PROPS_DEF_COUNTER	0x20
292255932Salfred
293255932Salfred#define QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID 0x80
294318536Shselasky#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS (1 << 31)
295255932Salfred
296255932Salfred	if (vhcr->op_modifier == 1) {
297272407Shselasky		port = vhcr->in_modifier; /* phys-port = logical-port */
298272407Shselasky		MLX4_PUT(outbox->buf, port, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
299272407Shselasky
300255932Salfred		field = 0;
301255932Salfred		/* ensure that phy_wqe_gid bit is not set */
302272407Shselasky		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS0_OFFSET);
303255932Salfred
304272407Shselasky		/* ensure force vlan and force mac bits are not set
305272407Shselasky		 * and that default counter bit is set
306272407Shselasky		 */
307272407Shselasky		field = QUERY_FUNC_CAP_PROPS_DEF_COUNTER; /* def counter */
308272407Shselasky		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
309255932Salfred
310272407Shselasky		/* There is always default counter legal or sink counter */
311272407Shselasky		field = mlx4_get_default_counter_index(dev, slave, vhcr->in_modifier);
312272407Shselasky		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET);
313272407Shselasky
314255932Salfred		/* size is now the QP number */
315272407Shselasky		size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1;
316255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL);
317255932Salfred
318255932Salfred		size += 2;
319255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL);
320255932Salfred
321272407Shselasky		size = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1;
322255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_PROXY);
323255932Salfred
324255932Salfred		size += 2;
325255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_PROXY);
326255932Salfred
327255932Salfred	} else if (vhcr->op_modifier == 0) {
328272407Shselasky		/* enable rdma and ethernet interfaces, and new quota locations */
329272407Shselasky		field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
330318533Shselasky			 QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX);
331255932Salfred		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
332255932Salfred
333255932Salfred		field = dev->caps.num_ports;
334255932Salfred		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
335255932Salfred
336255932Salfred		size = dev->caps.function_caps; /* set PF behaviours */
337255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_PF_BHVR_OFFSET);
338255932Salfred
339255932Salfred		field = 0; /* protected FMR support not available as yet */
340255932Salfred		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FMR_OFFSET);
341255932Salfred
342255932Salfred		size = priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[slave];
343255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET);
344272407Shselasky		size = dev->caps.num_qps;
345272407Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP);
346255932Salfred
347255932Salfred		size = priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[slave];
348255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET);
349272407Shselasky		size = dev->caps.num_srqs;
350272407Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP);
351255932Salfred
352255932Salfred		size = priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[slave];
353255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET);
354272407Shselasky		size = dev->caps.num_cqs;
355272407Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP);
356255932Salfred
357318536Shselasky		if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) ||
358318536Shselasky		    mlx4_QUERY_FUNC(dev, &func, slave)) {
359318536Shselasky			size = vhcr->in_modifier &
360318536Shselasky				QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
361318536Shselasky				dev->caps.num_eqs :
362318536Shselasky				rounddown_pow_of_two(dev->caps.num_eqs);
363318536Shselasky			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
364318536Shselasky			size = dev->caps.reserved_eqs;
365318536Shselasky			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
366318536Shselasky		} else {
367318536Shselasky			size = vhcr->in_modifier &
368318536Shselasky				QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
369318536Shselasky				func.max_eq :
370318536Shselasky				rounddown_pow_of_two(func.max_eq);
371318536Shselasky			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
372318536Shselasky			size = func.rsvd_eqs;
373318536Shselasky			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
374318536Shselasky		}
375255932Salfred
376255932Salfred		size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave];
377255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET);
378272407Shselasky		size = dev->caps.num_mpts;
379272407Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP);
380255932Salfred
381255932Salfred		size = priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[slave];
382255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET);
383272407Shselasky		size = dev->caps.num_mtts;
384272407Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP);
385255932Salfred
386255932Salfred		size = dev->caps.num_mgms + dev->caps.num_amgms;
387255932Salfred		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
388272407Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
389255932Salfred
390318533Shselasky		size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG;
391318533Shselasky		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
392255932Salfred	} else
393255932Salfred		err = -EINVAL;
394255932Salfred
395255932Salfred	return err;
396255932Salfred}
397255932Salfred
398255932Salfredint mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
399255932Salfred			struct mlx4_func_cap *func_cap)
400255932Salfred{
401255932Salfred	struct mlx4_cmd_mailbox *mailbox;
402255932Salfred	u32			*outbox;
403255932Salfred	u8			field, op_modifier;
404255932Salfred	u32			size;
405272407Shselasky	int			err = 0, quotas = 0;
406318536Shselasky	u32                     in_modifier;
407255932Salfred
408255932Salfred	op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
409318536Shselasky	in_modifier = op_modifier ? gen_or_port :
410318536Shselasky		QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS;
411255932Salfred
412255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
413255932Salfred	if (IS_ERR(mailbox))
414255932Salfred		return PTR_ERR(mailbox);
415255932Salfred
416318536Shselasky	err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, op_modifier,
417255932Salfred			   MLX4_CMD_QUERY_FUNC_CAP,
418255932Salfred			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
419255932Salfred	if (err)
420255932Salfred		goto out;
421255932Salfred
422255932Salfred	outbox = mailbox->buf;
423255932Salfred
424255932Salfred	if (!op_modifier) {
425255932Salfred		MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS_OFFSET);
426255932Salfred		if (!(field & (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA))) {
427255932Salfred			mlx4_err(dev, "The host supports neither eth nor rdma interfaces\n");
428255932Salfred			err = -EPROTONOSUPPORT;
429255932Salfred			goto out;
430255932Salfred		}
431255932Salfred		func_cap->flags = field;
432272407Shselasky		quotas = !!(func_cap->flags & QUERY_FUNC_CAP_FLAG_QUOTAS);
433255932Salfred
434255932Salfred		MLX4_GET(field, outbox, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
435255932Salfred		func_cap->num_ports = field;
436255932Salfred
437255932Salfred		MLX4_GET(size, outbox, QUERY_FUNC_CAP_PF_BHVR_OFFSET);
438255932Salfred		func_cap->pf_context_behaviour = size;
439255932Salfred
440272407Shselasky		if (quotas) {
441272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET);
442272407Shselasky			func_cap->qp_quota = size & 0xFFFFFF;
443255932Salfred
444272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET);
445272407Shselasky			func_cap->srq_quota = size & 0xFFFFFF;
446255932Salfred
447272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET);
448272407Shselasky			func_cap->cq_quota = size & 0xFFFFFF;
449255932Salfred
450272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET);
451272407Shselasky			func_cap->mpt_quota = size & 0xFFFFFF;
452272407Shselasky
453272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET);
454272407Shselasky			func_cap->mtt_quota = size & 0xFFFFFF;
455272407Shselasky
456272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
457272407Shselasky			func_cap->mcg_quota = size & 0xFFFFFF;
458272407Shselasky
459272407Shselasky		} else {
460272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP);
461272407Shselasky			func_cap->qp_quota = size & 0xFFFFFF;
462272407Shselasky
463272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP);
464272407Shselasky			func_cap->srq_quota = size & 0xFFFFFF;
465272407Shselasky
466272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP);
467272407Shselasky			func_cap->cq_quota = size & 0xFFFFFF;
468272407Shselasky
469272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP);
470272407Shselasky			func_cap->mpt_quota = size & 0xFFFFFF;
471272407Shselasky
472272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP);
473272407Shselasky			func_cap->mtt_quota = size & 0xFFFFFF;
474272407Shselasky
475272407Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
476272407Shselasky			func_cap->mcg_quota = size & 0xFFFFFF;
477272407Shselasky		}
478255932Salfred		MLX4_GET(size, outbox, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
479255932Salfred		func_cap->max_eq = size & 0xFFFFFF;
480255932Salfred
481255932Salfred		MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
482255932Salfred		func_cap->reserved_eq = size & 0xFFFFFF;
483255932Salfred
484318533Shselasky		func_cap->extra_flags = 0;
485318533Shselasky
486318533Shselasky		/* Mailbox data from 0x6c and onward should only be treated if
487318533Shselasky		 * QUERY_FUNC_CAP_FLAG_VALID_MAILBOX is set in func_cap->flags
488318533Shselasky		 */
489318533Shselasky		if (func_cap->flags & QUERY_FUNC_CAP_FLAG_VALID_MAILBOX) {
490318533Shselasky			MLX4_GET(size, outbox, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
491318533Shselasky			if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG)
492318533Shselasky				func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_BF_RES_QP;
493318533Shselasky		}
494318533Shselasky
495255932Salfred		goto out;
496255932Salfred	}
497255932Salfred
498255932Salfred	/* logical port query */
499255932Salfred	if (gen_or_port > dev->caps.num_ports) {
500255932Salfred		err = -EINVAL;
501255932Salfred		goto out;
502255932Salfred	}
503255932Salfred
504255932Salfred	if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) {
505272407Shselasky		MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET);
506255932Salfred		if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_VLAN) {
507255932Salfred			mlx4_err(dev, "VLAN is enforced on this port\n");
508255932Salfred			err = -EPROTONOSUPPORT;
509255932Salfred			goto out;
510255932Salfred		}
511255932Salfred
512255932Salfred		if (field & QUERY_FUNC_CAP_ETH_PROPS_FORCE_MAC) {
513255932Salfred			mlx4_err(dev, "Force mac is enabled on this port\n");
514255932Salfred			err = -EPROTONOSUPPORT;
515255932Salfred			goto out;
516255932Salfred		}
517255932Salfred	} else if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_IB) {
518272407Shselasky		MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
519255932Salfred		if (field & QUERY_FUNC_CAP_RDMA_PROPS_FORCE_PHY_WQE_GID) {
520255932Salfred			mlx4_err(dev, "phy_wqe_gid is "
521255932Salfred				 "enforced on this ib port\n");
522255932Salfred			err = -EPROTONOSUPPORT;
523255932Salfred			goto out;
524255932Salfred		}
525255932Salfred	}
526255932Salfred
527255932Salfred	MLX4_GET(field, outbox, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
528255932Salfred	func_cap->physical_port = field;
529255932Salfred	if (func_cap->physical_port != gen_or_port) {
530255932Salfred		err = -ENOSYS;
531255932Salfred		goto out;
532255932Salfred	}
533255932Salfred
534272407Shselasky	MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET);
535272407Shselasky	if (field & QUERY_FUNC_CAP_PROPS_DEF_COUNTER) {
536272407Shselasky		MLX4_GET(field, outbox, QUERY_FUNC_CAP_COUNTER_INDEX_OFFSET);
537272407Shselasky		func_cap->def_counter_index = field;
538272407Shselasky	} else {
539272407Shselasky		func_cap->def_counter_index = MLX4_SINK_COUNTER_INDEX;
540272407Shselasky	}
541272407Shselasky
542255932Salfred	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL);
543255932Salfred	func_cap->qp0_tunnel_qpn = size & 0xFFFFFF;
544255932Salfred
545255932Salfred	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_PROXY);
546255932Salfred	func_cap->qp0_proxy_qpn = size & 0xFFFFFF;
547255932Salfred
548255932Salfred	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_TUNNEL);
549255932Salfred	func_cap->qp1_tunnel_qpn = size & 0xFFFFFF;
550255932Salfred
551255932Salfred	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY);
552255932Salfred	func_cap->qp1_proxy_qpn = size & 0xFFFFFF;
553255932Salfred
554255932Salfred	/* All other resources are allocated by the master, but we still report
555255932Salfred	 * 'num' and 'reserved' capabilities as follows:
556255932Salfred	 * - num remains the maximum resource index
557255932Salfred	 * - 'num - reserved' is the total available objects of a resource, but
558255932Salfred	 *   resource indices may be less than 'reserved'
559255932Salfred	 * TODO: set per-resource quotas */
560255932Salfred
561255932Salfredout:
562255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
563255932Salfred
564255932Salfred	return err;
565255932Salfred}
566255932Salfred
567219820Sjeffint mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
568219820Sjeff{
569219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
570219820Sjeff	u32 *outbox;
571219820Sjeff	u8 field;
572255932Salfred	u32 field32, flags, ext_flags;
573219820Sjeff	u16 size;
574219820Sjeff	u16 stat_rate;
575219820Sjeff	int err;
576219820Sjeff	int i;
577219820Sjeff
578219820Sjeff#define QUERY_DEV_CAP_OUT_SIZE		       0x100
579219820Sjeff#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET		0x10
580219820Sjeff#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET		0x11
581219820Sjeff#define QUERY_DEV_CAP_RSVD_QP_OFFSET		0x12
582219820Sjeff#define QUERY_DEV_CAP_MAX_QP_OFFSET		0x13
583219820Sjeff#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET		0x14
584219820Sjeff#define QUERY_DEV_CAP_MAX_SRQ_OFFSET		0x15
585219820Sjeff#define QUERY_DEV_CAP_RSVD_EEC_OFFSET		0x16
586219820Sjeff#define QUERY_DEV_CAP_MAX_EEC_OFFSET		0x17
587219820Sjeff#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET		0x19
588219820Sjeff#define QUERY_DEV_CAP_RSVD_CQ_OFFSET		0x1a
589219820Sjeff#define QUERY_DEV_CAP_MAX_CQ_OFFSET		0x1b
590219820Sjeff#define QUERY_DEV_CAP_MAX_MPT_OFFSET		0x1d
591219820Sjeff#define QUERY_DEV_CAP_RSVD_EQ_OFFSET		0x1e
592219820Sjeff#define QUERY_DEV_CAP_MAX_EQ_OFFSET		0x1f
593219820Sjeff#define QUERY_DEV_CAP_RSVD_MTT_OFFSET		0x20
594219820Sjeff#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET		0x21
595219820Sjeff#define QUERY_DEV_CAP_RSVD_MRW_OFFSET		0x22
596219820Sjeff#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET	0x23
597318536Shselasky#define QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET		0x26
598219820Sjeff#define QUERY_DEV_CAP_MAX_AV_OFFSET		0x27
599219820Sjeff#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET		0x29
600219820Sjeff#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET		0x2b
601219820Sjeff#define QUERY_DEV_CAP_MAX_GSO_OFFSET		0x2d
602255932Salfred#define QUERY_DEV_CAP_RSS_OFFSET		0x2e
603219820Sjeff#define QUERY_DEV_CAP_MAX_RDMA_OFFSET		0x2f
604219820Sjeff#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET		0x33
605219820Sjeff#define QUERY_DEV_CAP_ACK_DELAY_OFFSET		0x35
606219820Sjeff#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET		0x36
607219820Sjeff#define QUERY_DEV_CAP_VL_PORT_OFFSET		0x37
608219820Sjeff#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET		0x38
609219820Sjeff#define QUERY_DEV_CAP_MAX_GID_OFFSET		0x3b
610219820Sjeff#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET	0x3c
611255932Salfred#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET	0x3e
612219820Sjeff#define QUERY_DEV_CAP_MAX_PKEY_OFFSET		0x3f
613219820Sjeff#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET		0x40
614255932Salfred#define QUERY_DEV_CAP_SYNC_QP_OFFSET		0x42
615219820Sjeff#define QUERY_DEV_CAP_FLAGS_OFFSET		0x44
616219820Sjeff#define QUERY_DEV_CAP_RSVD_UAR_OFFSET		0x48
617219820Sjeff#define QUERY_DEV_CAP_UAR_SZ_OFFSET		0x49
618219820Sjeff#define QUERY_DEV_CAP_PAGE_SZ_OFFSET		0x4b
619219820Sjeff#define QUERY_DEV_CAP_BF_OFFSET			0x4c
620219820Sjeff#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET	0x4d
621219820Sjeff#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET	0x4e
622219820Sjeff#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET	0x4f
623219820Sjeff#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET		0x51
624219820Sjeff#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET	0x52
625219820Sjeff#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET		0x55
626219820Sjeff#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET	0x56
627219820Sjeff#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET		0x61
628219820Sjeff#define QUERY_DEV_CAP_RSVD_MCG_OFFSET		0x62
629219820Sjeff#define QUERY_DEV_CAP_MAX_MCG_OFFSET		0x63
630219820Sjeff#define QUERY_DEV_CAP_RSVD_PD_OFFSET		0x64
631219820Sjeff#define QUERY_DEV_CAP_MAX_PD_OFFSET		0x65
632219820Sjeff#define QUERY_DEV_CAP_RSVD_XRC_OFFSET		0x66
633219820Sjeff#define QUERY_DEV_CAP_MAX_XRC_OFFSET		0x67
634255932Salfred#define QUERY_DEV_CAP_MAX_BASIC_COUNTERS_OFFSET	0x68
635255932Salfred#define QUERY_DEV_CAP_MAX_EXTENDED_COUNTERS_OFFSET	0x6c
636272407Shselasky#define QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET	0x70
637255932Salfred#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET	0x76
638272407Shselasky#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET		0x70
639272407Shselasky#define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET	0x74
640255932Salfred#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET	0x77
641219820Sjeff#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET	0x80
642219820Sjeff#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET	0x82
643219820Sjeff#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET	0x84
644219820Sjeff#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET	0x86
645219820Sjeff#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET	0x88
646219820Sjeff#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET	0x8a
647219820Sjeff#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET	0x8c
648219820Sjeff#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET	0x8e
649219820Sjeff#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET	0x90
650219820Sjeff#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET	0x92
651219820Sjeff#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET		0x94
652219820Sjeff#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET		0x98
653272407Shselasky#define QUERY_DEV_CAP_ETS_CFG_OFFSET		0x9c
654219820Sjeff#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET		0xa0
655219820Sjeff
656255932Salfred	dev_cap->flags2 = 0;
657219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
658219820Sjeff	if (IS_ERR(mailbox))
659219820Sjeff		return PTR_ERR(mailbox);
660219820Sjeff	outbox = mailbox->buf;
661219820Sjeff
662219820Sjeff	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
663255932Salfred			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
664219820Sjeff	if (err)
665219820Sjeff		goto out;
666219820Sjeff
667219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET);
668219820Sjeff	dev_cap->reserved_qps = 1 << (field & 0xf);
669219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET);
670219820Sjeff	dev_cap->max_qps = 1 << (field & 0x1f);
671219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET);
672219820Sjeff	dev_cap->reserved_srqs = 1 << (field >> 4);
673219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET);
674219820Sjeff	dev_cap->max_srqs = 1 << (field & 0x1f);
675219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET);
676219820Sjeff	dev_cap->max_cq_sz = 1 << field;
677219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET);
678219820Sjeff	dev_cap->reserved_cqs = 1 << (field & 0xf);
679219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET);
680219820Sjeff	dev_cap->max_cqs = 1 << (field & 0x1f);
681219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET);
682219820Sjeff	dev_cap->max_mpts = 1 << (field & 0x3f);
683219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
684255932Salfred	dev_cap->reserved_eqs = field & 0xf;
685219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
686219820Sjeff	dev_cap->max_eqs = 1 << (field & 0xf);
687219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
688219820Sjeff	dev_cap->reserved_mtts = 1 << (field >> 4);
689219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
690219820Sjeff	dev_cap->max_mrw_sz = 1 << field;
691219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET);
692219820Sjeff	dev_cap->reserved_mrws = 1 << (field & 0xf);
693219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET);
694219820Sjeff	dev_cap->max_mtt_seg = 1 << (field & 0x3f);
695318536Shselasky	MLX4_GET(size, outbox, QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET);
696318536Shselasky	dev_cap->num_sys_eqs = size & 0xfff;
697219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
698219820Sjeff	dev_cap->max_requester_per_qp = 1 << (field & 0x3f);
699219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET);
700219820Sjeff	dev_cap->max_responder_per_qp = 1 << (field & 0x3f);
701219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET);
702219820Sjeff	field &= 0x1f;
703219820Sjeff	if (!field)
704219820Sjeff		dev_cap->max_gso_sz = 0;
705219820Sjeff	else
706219820Sjeff		dev_cap->max_gso_sz = 1 << field;
707219820Sjeff
708255932Salfred	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET);
709255932Salfred	if (field & 0x20)
710255932Salfred		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR;
711255932Salfred	if (field & 0x10)
712255932Salfred		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP;
713255932Salfred	field &= 0xf;
714255932Salfred	if (field) {
715255932Salfred		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS;
716255932Salfred		dev_cap->max_rss_tbl_sz = 1 << field;
717255932Salfred	} else
718255932Salfred		dev_cap->max_rss_tbl_sz = 0;
719219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET);
720219820Sjeff	dev_cap->max_rdma_global = 1 << (field & 0x3f);
721219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
722219820Sjeff	dev_cap->local_ca_ack_delay = field & 0x1f;
723219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
724219820Sjeff	dev_cap->num_ports = field & 0xf;
725219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET);
726219820Sjeff	dev_cap->max_msg_sz = 1 << (field & 0x1f);
727272407Shselasky	MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET);
728272407Shselasky	if (field & 0x10)
729272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN;
730255932Salfred	MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
731255932Salfred	if (field & 0x80)
732255932Salfred		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN;
733272407Shselasky	MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
734272407Shselasky	if (field & 0x80)
735272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB;
736255932Salfred	dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f;
737255932Salfred	MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET);
738255932Salfred	dev_cap->fs_max_num_qp_per_entry = field;
739219820Sjeff	MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
740219820Sjeff	dev_cap->stat_rate_support = stat_rate;
741255932Salfred	MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
742272407Shselasky	if (field & 0x80)
743272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS;
744255932Salfred	MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
745255932Salfred	MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
746255932Salfred	dev_cap->flags = flags | (u64)ext_flags << 32;
747255932Salfred	MLX4_GET(field, outbox, QUERY_DEV_CAP_SYNC_QP_OFFSET);
748255932Salfred	dev_cap->sync_qp = field & 0x10;
749219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
750219820Sjeff	dev_cap->reserved_uars = field >> 4;
751219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET);
752219820Sjeff	dev_cap->uar_size = 1 << ((field & 0x3f) + 20);
753219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET);
754219820Sjeff	dev_cap->min_page_sz = 1 << field;
755219820Sjeff
756219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET);
757219820Sjeff	if (field & 0x80) {
758219820Sjeff		MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET);
759219820Sjeff		dev_cap->bf_reg_size = 1 << (field & 0x1f);
760219820Sjeff		MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET);
761255932Salfred		if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size))
762219820Sjeff			field = 3;
763219820Sjeff		dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
764219820Sjeff		mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
765219820Sjeff			 dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
766219820Sjeff	} else {
767219820Sjeff		dev_cap->bf_reg_size = 0;
768219820Sjeff		mlx4_dbg(dev, "BlueFlame not available\n");
769219820Sjeff	}
770219820Sjeff
771219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET);
772219820Sjeff	dev_cap->max_sq_sg = field;
773219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET);
774219820Sjeff	dev_cap->max_sq_desc_sz = size;
775219820Sjeff
776219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET);
777219820Sjeff	dev_cap->max_qp_per_mcg = 1 << field;
778219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET);
779219820Sjeff	dev_cap->reserved_mgms = field & 0xf;
780219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET);
781219820Sjeff	dev_cap->max_mcgs = 1 << field;
782219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET);
783219820Sjeff	dev_cap->reserved_pds = field >> 4;
784219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET);
785219820Sjeff	dev_cap->max_pds = 1 << (field & 0x3f);
786219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET);
787219820Sjeff	dev_cap->reserved_xrcds = field >> 4;
788219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_XRC_OFFSET);
789219820Sjeff	dev_cap->max_xrcds = 1 << (field & 0x1f);
790219820Sjeff
791219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET);
792219820Sjeff	dev_cap->rdmarc_entry_sz = size;
793219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET);
794219820Sjeff	dev_cap->qpc_entry_sz = size;
795219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET);
796219820Sjeff	dev_cap->aux_entry_sz = size;
797219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET);
798219820Sjeff	dev_cap->altc_entry_sz = size;
799219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET);
800219820Sjeff	dev_cap->eqc_entry_sz = size;
801219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET);
802219820Sjeff	dev_cap->cqc_entry_sz = size;
803219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET);
804219820Sjeff	dev_cap->srq_entry_sz = size;
805219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET);
806219820Sjeff	dev_cap->cmpt_entry_sz = size;
807219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET);
808219820Sjeff	dev_cap->mtt_entry_sz = size;
809219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET);
810219820Sjeff	dev_cap->dmpt_entry_sz = size;
811219820Sjeff
812219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET);
813219820Sjeff	dev_cap->max_srq_sz = 1 << field;
814219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET);
815219820Sjeff	dev_cap->max_qp_sz = 1 << field;
816219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET);
817219820Sjeff	dev_cap->resize_srq = field & 1;
818219820Sjeff	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET);
819219820Sjeff	dev_cap->max_rq_sg = field;
820219820Sjeff	MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET);
821219820Sjeff	dev_cap->max_rq_desc_sz = size;
822219820Sjeff
823219820Sjeff	MLX4_GET(dev_cap->bmme_flags, outbox,
824219820Sjeff		 QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
825219820Sjeff	MLX4_GET(dev_cap->reserved_lkey, outbox,
826219820Sjeff		 QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
827272407Shselasky	MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETS_CFG_OFFSET);
828272407Shselasky	if (field32 & (1 << 0))
829272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP;
830272407Shselasky	if (field32 & (1 << 7))
831272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT;
832272407Shselasky	if (field32 & (1 << 8))
833272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW;
834272407Shselasky	if (field32 & (1 << 13))
835272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG;
836272407Shselasky
837219820Sjeff	MLX4_GET(dev_cap->max_icm_sz, outbox,
838219820Sjeff		 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
839255932Salfred	if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
840255932Salfred		MLX4_GET(dev_cap->max_basic_counters, outbox,
841255932Salfred			 QUERY_DEV_CAP_MAX_BASIC_COUNTERS_OFFSET);
842255932Salfred	/* FW reports 256 however real value is 255 */
843255932Salfred	dev_cap->max_basic_counters = min_t(u32, dev_cap->max_basic_counters, 255);
844255932Salfred	if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS_EXT)
845255932Salfred		MLX4_GET(dev_cap->max_extended_counters, outbox,
846255932Salfred			 QUERY_DEV_CAP_MAX_EXTENDED_COUNTERS_OFFSET);
847219820Sjeff
848272407Shselasky	MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
849272407Shselasky	if (field32 & (1 << 16))
850272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
851272407Shselasky	if (field32 & (1 << 19))
852272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK;
853272407Shselasky	if (field32 & (1 << 20))
854272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM;
855272407Shselasky	if (field32 & (1 << 26))
856272407Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
857272407Shselasky
858219820Sjeff	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
859219820Sjeff		for (i = 1; i <= dev_cap->num_ports; ++i) {
860219820Sjeff			MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
861219820Sjeff			dev_cap->max_vl[i]	   = field >> 4;
862219820Sjeff			MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
863219820Sjeff			dev_cap->ib_mtu[i]	   = field >> 4;
864219820Sjeff			dev_cap->max_port_width[i] = field & 0xf;
865219820Sjeff			MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
866219820Sjeff			dev_cap->max_gids[i]	   = 1 << (field & 0xf);
867219820Sjeff			MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
868219820Sjeff			dev_cap->max_pkeys[i]	   = 1 << (field & 0xf);
869219820Sjeff		}
870219820Sjeff	} else {
871219820Sjeff#define QUERY_PORT_SUPPORTED_TYPE_OFFSET	0x00
872219820Sjeff#define QUERY_PORT_MTU_OFFSET			0x01
873219820Sjeff#define QUERY_PORT_ETH_MTU_OFFSET		0x02
874219820Sjeff#define QUERY_PORT_WIDTH_OFFSET			0x06
875219820Sjeff#define QUERY_PORT_MAX_GID_PKEY_OFFSET		0x07
876219820Sjeff#define QUERY_PORT_MAX_MACVLAN_OFFSET		0x0a
877219820Sjeff#define QUERY_PORT_MAX_VL_OFFSET		0x0b
878219820Sjeff#define QUERY_PORT_MAC_OFFSET			0x10
879219820Sjeff#define QUERY_PORT_TRANS_VENDOR_OFFSET		0x18
880219820Sjeff#define QUERY_PORT_WAVELENGTH_OFFSET		0x1c
881219820Sjeff#define QUERY_PORT_TRANS_CODE_OFFSET		0x20
882219820Sjeff
883219820Sjeff		for (i = 1; i <= dev_cap->num_ports; ++i) {
884219820Sjeff			err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT,
885255932Salfred					   MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
886219820Sjeff			if (err)
887219820Sjeff				goto out;
888219820Sjeff
889219820Sjeff			MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
890219820Sjeff			dev_cap->supported_port_types[i] = field & 3;
891255932Salfred			dev_cap->suggested_type[i] = (field >> 3) & 1;
892255932Salfred			dev_cap->default_sense[i] = (field >> 4) & 1;
893219820Sjeff			MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
894219820Sjeff			dev_cap->ib_mtu[i]	   = field & 0xf;
895219820Sjeff			MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
896219820Sjeff			dev_cap->max_port_width[i] = field & 0xf;
897219820Sjeff			MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
898219820Sjeff			dev_cap->max_gids[i]	   = 1 << (field >> 4);
899219820Sjeff			dev_cap->max_pkeys[i]	   = 1 << (field & 0xf);
900219820Sjeff			MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
901219820Sjeff			dev_cap->max_vl[i]	   = field & 0xf;
902219820Sjeff			MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
903219820Sjeff			dev_cap->log_max_macs[i]  = field & 0xf;
904219820Sjeff			dev_cap->log_max_vlans[i] = field >> 4;
905219820Sjeff			MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
906219820Sjeff			MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
907219820Sjeff			MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
908219820Sjeff			dev_cap->trans_type[i] = field32 >> 24;
909219820Sjeff			dev_cap->vendor_oui[i] = field32 & 0xffffff;
910219820Sjeff			MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET);
911219820Sjeff			MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET);
912219820Sjeff		}
913219820Sjeff	}
914219820Sjeff
915219820Sjeff	mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
916219820Sjeff		 dev_cap->bmme_flags, dev_cap->reserved_lkey);
917219820Sjeff
918219820Sjeff	/*
919219820Sjeff	 * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then
920219820Sjeff	 * we can't use any EQs whose doorbell falls on that page,
921219820Sjeff	 * even if the EQ itself isn't reserved.
922219820Sjeff	 */
923318536Shselasky	if (dev_cap->num_sys_eqs == 0)
924318536Shselasky		dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
925318536Shselasky					    dev_cap->reserved_eqs);
926318536Shselasky	else
927318536Shselasky		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SYS_EQS;
928219820Sjeff
929219820Sjeff	mlx4_dbg(dev, "Max ICM size %lld MB\n",
930219820Sjeff		 (unsigned long long) dev_cap->max_icm_sz >> 20);
931219820Sjeff	mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
932219820Sjeff		 dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz);
933219820Sjeff	mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n",
934219820Sjeff		 dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz);
935219820Sjeff	mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
936219820Sjeff		 dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz);
937318536Shselasky	mlx4_dbg(dev, "Num sys EQs: %d, max EQs: %d, reserved EQs: %d, entry size: %d\n",
938318536Shselasky		dev_cap->num_sys_eqs, dev_cap->max_eqs, dev_cap->reserved_eqs,
939318536Shselasky		dev_cap->eqc_entry_sz);
940219820Sjeff	mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
941219820Sjeff		 dev_cap->reserved_mrws, dev_cap->reserved_mtts);
942219820Sjeff	mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
943219820Sjeff		 dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars);
944219820Sjeff	mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n",
945219820Sjeff		 dev_cap->max_pds, dev_cap->reserved_mgms);
946219820Sjeff	mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
947219820Sjeff		 dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
948219820Sjeff	mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
949219820Sjeff		 dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1],
950219820Sjeff		 dev_cap->max_port_width[1]);
951219820Sjeff	mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
952219820Sjeff		 dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
953219820Sjeff	mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
954219820Sjeff		 dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
955219820Sjeff	mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
956255932Salfred	mlx4_dbg(dev, "Max basic counters: %d\n", dev_cap->max_basic_counters);
957255932Salfred	mlx4_dbg(dev, "Max extended counters: %d\n", dev_cap->max_extended_counters);
958255932Salfred	mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
959219820Sjeff
960219820Sjeff	dump_dev_cap_flags(dev, dev_cap->flags);
961255932Salfred	dump_dev_cap_flags2(dev, dev_cap->flags2);
962219820Sjeff
963219820Sjeffout:
964219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
965219820Sjeff	return err;
966219820Sjeff}
967219820Sjeff
968255932Salfredint mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
969255932Salfred			       struct mlx4_vhcr *vhcr,
970255932Salfred			       struct mlx4_cmd_mailbox *inbox,
971255932Salfred			       struct mlx4_cmd_mailbox *outbox,
972255932Salfred			       struct mlx4_cmd_info *cmd)
973255932Salfred{
974255932Salfred	u64	flags;
975255932Salfred	int	err = 0;
976255932Salfred	u8	field;
977255932Salfred
978255932Salfred	err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
979255932Salfred			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
980255932Salfred	if (err)
981255932Salfred		return err;
982255932Salfred
983255932Salfred	/* add port mng change event capability unconditionally to slaves */
984255932Salfred	MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
985255932Salfred	flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV;
986255932Salfred	MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
987255932Salfred
988255932Salfred	/* For guests, report Blueflame disabled */
989255932Salfred	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET);
990255932Salfred	field &= 0x7f;
991255932Salfred	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
992255932Salfred
993272407Shselasky	/* turn off device-managed steering capability if not enabled */
994272407Shselasky	if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {
995272407Shselasky		MLX4_GET(field, outbox->buf,
996272407Shselasky			 QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
997272407Shselasky		field &= 0x7f;
998272407Shselasky		MLX4_PUT(outbox->buf, field,
999272407Shselasky			 QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
1000272407Shselasky	}
1001255932Salfred	return 0;
1002255932Salfred}
1003255932Salfred
1004255932Salfredint mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
1005255932Salfred			    struct mlx4_vhcr *vhcr,
1006255932Salfred			    struct mlx4_cmd_mailbox *inbox,
1007255932Salfred			    struct mlx4_cmd_mailbox *outbox,
1008255932Salfred			    struct mlx4_cmd_info *cmd)
1009255932Salfred{
1010255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1011255932Salfred	u64 def_mac;
1012255932Salfred	u8 port_type;
1013255932Salfred	u16 short_field;
1014255932Salfred	int err;
1015272407Shselasky	int admin_link_state;
1016255932Salfred
1017255932Salfred#define MLX4_VF_PORT_NO_LINK_SENSE_MASK	0xE0
1018272407Shselasky#define MLX4_PORT_LINK_UP_MASK		0x80
1019255932Salfred#define QUERY_PORT_CUR_MAX_PKEY_OFFSET	0x0c
1020255932Salfred#define QUERY_PORT_CUR_MAX_GID_OFFSET	0x0e
1021255932Salfred
1022255932Salfred	err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0,
1023255932Salfred			   MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
1024255932Salfred			   MLX4_CMD_NATIVE);
1025255932Salfred
1026255932Salfred	if (!err && dev->caps.function != slave) {
1027272407Shselasky		/* set slave default_mac address to be zero MAC */
1028272407Shselasky		def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
1029255932Salfred		MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
1030255932Salfred
1031255932Salfred		/* get port type - currently only eth is enabled */
1032255932Salfred		MLX4_GET(port_type, outbox->buf,
1033255932Salfred			 QUERY_PORT_SUPPORTED_TYPE_OFFSET);
1034255932Salfred
1035255932Salfred		/* No link sensing allowed */
1036255932Salfred		port_type &= MLX4_VF_PORT_NO_LINK_SENSE_MASK;
1037255932Salfred		/* set port type to currently operating port type */
1038255932Salfred		port_type |= (dev->caps.port_type[vhcr->in_modifier] & 0x3);
1039255932Salfred
1040272407Shselasky		admin_link_state = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.link_state;
1041272407Shselasky		if (IFLA_VF_LINK_STATE_ENABLE == admin_link_state)
1042272407Shselasky			port_type |= MLX4_PORT_LINK_UP_MASK;
1043272407Shselasky		else if (IFLA_VF_LINK_STATE_DISABLE == admin_link_state)
1044272407Shselasky			port_type &= ~MLX4_PORT_LINK_UP_MASK;
1045272407Shselasky
1046255932Salfred		MLX4_PUT(outbox->buf, port_type,
1047255932Salfred			 QUERY_PORT_SUPPORTED_TYPE_OFFSET);
1048255932Salfred
1049255932Salfred		if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH)
1050255932Salfred			short_field = mlx4_get_slave_num_gids(dev, slave);
1051255932Salfred		else
1052255932Salfred			short_field = 1; /* slave max gids */
1053255932Salfred		MLX4_PUT(outbox->buf, short_field,
1054255932Salfred			 QUERY_PORT_CUR_MAX_GID_OFFSET);
1055255932Salfred
1056255932Salfred		short_field = dev->caps.pkey_table_len[vhcr->in_modifier];
1057255932Salfred		MLX4_PUT(outbox->buf, short_field,
1058255932Salfred			 QUERY_PORT_CUR_MAX_PKEY_OFFSET);
1059255932Salfred	}
1060255932Salfred
1061255932Salfred	return err;
1062255932Salfred}
1063255932Salfred
1064255932Salfredint mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port,
1065255932Salfred				    int *gid_tbl_len, int *pkey_tbl_len)
1066255932Salfred{
1067255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1068255932Salfred	u32			*outbox;
1069255932Salfred	u16			field;
1070255932Salfred	int			err;
1071255932Salfred
1072255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1073255932Salfred	if (IS_ERR(mailbox))
1074255932Salfred		return PTR_ERR(mailbox);
1075255932Salfred
1076255932Salfred	err =  mlx4_cmd_box(dev, 0, mailbox->dma, port, 0,
1077255932Salfred			    MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
1078255932Salfred			    MLX4_CMD_WRAPPED);
1079255932Salfred	if (err)
1080255932Salfred		goto out;
1081255932Salfred
1082255932Salfred	outbox = mailbox->buf;
1083255932Salfred
1084255932Salfred	MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_GID_OFFSET);
1085255932Salfred	*gid_tbl_len = field;
1086255932Salfred
1087255932Salfred	MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_PKEY_OFFSET);
1088255932Salfred	*pkey_tbl_len = field;
1089255932Salfred
1090255932Salfredout:
1091255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1092255932Salfred	return err;
1093255932Salfred}
1094255932SalfredEXPORT_SYMBOL(mlx4_get_slave_pkey_gid_tbl_len);
1095255932Salfred
1096219820Sjeffint mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
1097219820Sjeff{
1098219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1099219820Sjeff	struct mlx4_icm_iter iter;
1100219820Sjeff	__be64 *pages;
1101219820Sjeff	int lg;
1102219820Sjeff	int nent = 0;
1103219820Sjeff	int i;
1104219820Sjeff	int err = 0;
1105219820Sjeff	int ts = 0, tc = 0;
1106219820Sjeff
1107219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1108219820Sjeff	if (IS_ERR(mailbox))
1109219820Sjeff		return PTR_ERR(mailbox);
1110219820Sjeff	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
1111219820Sjeff	pages = mailbox->buf;
1112219820Sjeff
1113219820Sjeff	for (mlx4_icm_first(icm, &iter);
1114219820Sjeff	     !mlx4_icm_last(&iter);
1115219820Sjeff	     mlx4_icm_next(&iter)) {
1116219820Sjeff		/*
1117219820Sjeff		 * We have to pass pages that are aligned to their
1118219820Sjeff		 * size, so find the least significant 1 in the
1119219820Sjeff		 * address or size and use that as our log2 size.
1120219820Sjeff		 */
1121219820Sjeff		lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1;
1122219820Sjeff		if (lg < MLX4_ICM_PAGE_SHIFT) {
1123219820Sjeff			mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
1124219820Sjeff				   MLX4_ICM_PAGE_SIZE,
1125219820Sjeff				   (unsigned long long) mlx4_icm_addr(&iter),
1126219820Sjeff				   mlx4_icm_size(&iter));
1127219820Sjeff			err = -EINVAL;
1128219820Sjeff			goto out;
1129219820Sjeff		}
1130219820Sjeff
1131219820Sjeff		for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) {
1132219820Sjeff			if (virt != -1) {
1133219820Sjeff				pages[nent * 2] = cpu_to_be64(virt);
1134219820Sjeff				virt += 1 << lg;
1135219820Sjeff			}
1136219820Sjeff
1137219820Sjeff			pages[nent * 2 + 1] =
1138219820Sjeff				cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) |
1139219820Sjeff					    (lg - MLX4_ICM_PAGE_SHIFT));
1140219820Sjeff			ts += 1 << (lg - 10);
1141219820Sjeff			++tc;
1142219820Sjeff
1143219820Sjeff			if (++nent == MLX4_MAILBOX_SIZE / 16) {
1144219820Sjeff				err = mlx4_cmd(dev, mailbox->dma, nent, 0, op,
1145255932Salfred						MLX4_CMD_TIME_CLASS_B,
1146255932Salfred						MLX4_CMD_NATIVE);
1147219820Sjeff				if (err)
1148219820Sjeff					goto out;
1149219820Sjeff				nent = 0;
1150219820Sjeff			}
1151219820Sjeff		}
1152219820Sjeff	}
1153219820Sjeff
1154219820Sjeff	if (nent)
1155255932Salfred		err = mlx4_cmd(dev, mailbox->dma, nent, 0, op,
1156255932Salfred			       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1157219820Sjeff	if (err)
1158219820Sjeff		goto out;
1159219820Sjeff
1160219820Sjeff	switch (op) {
1161219820Sjeff	case MLX4_CMD_MAP_FA:
1162219820Sjeff		mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts);
1163219820Sjeff		break;
1164219820Sjeff	case MLX4_CMD_MAP_ICM_AUX:
1165219820Sjeff		mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts);
1166219820Sjeff		break;
1167219820Sjeff	case MLX4_CMD_MAP_ICM:
1168219820Sjeff		mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n",
1169219820Sjeff			  tc, ts, (unsigned long long) virt - (ts << 10));
1170219820Sjeff		break;
1171219820Sjeff	}
1172219820Sjeff
1173219820Sjeffout:
1174219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1175219820Sjeff	return err;
1176219820Sjeff}
1177219820Sjeff
1178219820Sjeffint mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm)
1179219820Sjeff{
1180219820Sjeff	return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1);
1181219820Sjeff}
1182219820Sjeff
1183219820Sjeffint mlx4_UNMAP_FA(struct mlx4_dev *dev)
1184219820Sjeff{
1185255932Salfred	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA,
1186255932Salfred			MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1187219820Sjeff}
1188219820Sjeff
1189219820Sjeff
1190219820Sjeffint mlx4_RUN_FW(struct mlx4_dev *dev)
1191219820Sjeff{
1192255932Salfred	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW,
1193255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1194219820Sjeff}
1195219820Sjeff
1196219820Sjeffint mlx4_QUERY_FW(struct mlx4_dev *dev)
1197219820Sjeff{
1198219820Sjeff	struct mlx4_fw  *fw  = &mlx4_priv(dev)->fw;
1199219820Sjeff	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
1200219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1201219820Sjeff	u32 *outbox;
1202219820Sjeff	int err = 0;
1203219820Sjeff	u64 fw_ver;
1204219820Sjeff	u16 cmd_if_rev;
1205219820Sjeff	u8 lg;
1206219820Sjeff
1207219820Sjeff#define QUERY_FW_OUT_SIZE             0x100
1208219820Sjeff#define QUERY_FW_VER_OFFSET            0x00
1209255932Salfred#define QUERY_FW_PPF_ID		       0x09
1210219820Sjeff#define QUERY_FW_CMD_IF_REV_OFFSET     0x0a
1211219820Sjeff#define QUERY_FW_MAX_CMD_OFFSET        0x0f
1212219820Sjeff#define QUERY_FW_ERR_START_OFFSET      0x30
1213219820Sjeff#define QUERY_FW_ERR_SIZE_OFFSET       0x38
1214219820Sjeff#define QUERY_FW_ERR_BAR_OFFSET        0x3c
1215219820Sjeff
1216219820Sjeff#define QUERY_FW_SIZE_OFFSET           0x00
1217219820Sjeff#define QUERY_FW_CLR_INT_BASE_OFFSET   0x20
1218219820Sjeff#define QUERY_FW_CLR_INT_BAR_OFFSET    0x28
1219219820Sjeff
1220255932Salfred#define QUERY_FW_COMM_BASE_OFFSET      0x40
1221255932Salfred#define QUERY_FW_COMM_BAR_OFFSET       0x48
1222255932Salfred
1223255932Salfred#define QUERY_FW_CLOCK_OFFSET	       0x50
1224255932Salfred#define QUERY_FW_CLOCK_BAR	       0x58
1225255932Salfred
1226219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1227219820Sjeff	if (IS_ERR(mailbox))
1228219820Sjeff		return PTR_ERR(mailbox);
1229219820Sjeff	outbox = mailbox->buf;
1230219820Sjeff
1231219820Sjeff	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW,
1232255932Salfred			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1233219820Sjeff	if (err)
1234219820Sjeff		goto out;
1235219820Sjeff
1236219820Sjeff	MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET);
1237219820Sjeff	/*
1238219820Sjeff	 * FW subminor version is at more significant bits than minor
1239219820Sjeff	 * version, so swap here.
1240219820Sjeff	 */
1241219820Sjeff	dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) |
1242219820Sjeff		((fw_ver & 0xffff0000ull) >> 16) |
1243219820Sjeff		((fw_ver & 0x0000ffffull) << 16);
1244219820Sjeff
1245255932Salfred	MLX4_GET(lg, outbox, QUERY_FW_PPF_ID);
1246255932Salfred	dev->caps.function = lg;
1247255932Salfred
1248255932Salfred	if (mlx4_is_slave(dev))
1249255932Salfred		goto out;
1250255932Salfred
1251255932Salfred
1252219820Sjeff	MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET);
1253219820Sjeff	if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV ||
1254219820Sjeff	    cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) {
1255219820Sjeff		mlx4_err(dev, "Installed FW has unsupported "
1256219820Sjeff			 "command interface revision %d.\n",
1257219820Sjeff			 cmd_if_rev);
1258219820Sjeff		mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n",
1259219820Sjeff			 (int) (dev->caps.fw_ver >> 32),
1260219820Sjeff			 (int) (dev->caps.fw_ver >> 16) & 0xffff,
1261219820Sjeff			 (int) dev->caps.fw_ver & 0xffff);
1262219820Sjeff		mlx4_err(dev, "This driver version supports only revisions %d to %d.\n",
1263219820Sjeff			 MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV);
1264219820Sjeff		err = -ENODEV;
1265219820Sjeff		goto out;
1266219820Sjeff	}
1267219820Sjeff
1268219820Sjeff	if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS)
1269219820Sjeff		dev->flags |= MLX4_FLAG_OLD_PORT_CMDS;
1270219820Sjeff
1271219820Sjeff	MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
1272219820Sjeff	cmd->max_cmds = 1 << lg;
1273219820Sjeff
1274219820Sjeff	mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n",
1275219820Sjeff		 (int) (dev->caps.fw_ver >> 32),
1276219820Sjeff		 (int) (dev->caps.fw_ver >> 16) & 0xffff,
1277219820Sjeff		 (int) dev->caps.fw_ver & 0xffff,
1278219820Sjeff		 cmd_if_rev, cmd->max_cmds);
1279219820Sjeff
1280219820Sjeff	MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET);
1281219820Sjeff	MLX4_GET(fw->catas_size,   outbox, QUERY_FW_ERR_SIZE_OFFSET);
1282219820Sjeff	MLX4_GET(fw->catas_bar,    outbox, QUERY_FW_ERR_BAR_OFFSET);
1283219820Sjeff	fw->catas_bar = (fw->catas_bar >> 6) * 2;
1284219820Sjeff
1285219820Sjeff	mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n",
1286219820Sjeff		 (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar);
1287219820Sjeff
1288219820Sjeff	MLX4_GET(fw->fw_pages,     outbox, QUERY_FW_SIZE_OFFSET);
1289219820Sjeff	MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
1290219820Sjeff	MLX4_GET(fw->clr_int_bar,  outbox, QUERY_FW_CLR_INT_BAR_OFFSET);
1291219820Sjeff	fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2;
1292219820Sjeff
1293255932Salfred	MLX4_GET(fw->comm_base, outbox, QUERY_FW_COMM_BASE_OFFSET);
1294255932Salfred	MLX4_GET(fw->comm_bar,  outbox, QUERY_FW_COMM_BAR_OFFSET);
1295255932Salfred	fw->comm_bar = (fw->comm_bar >> 6) * 2;
1296255932Salfred	mlx4_dbg(dev, "Communication vector bar:%d offset:0x%llx\n",
1297272407Shselasky		 fw->comm_bar, (unsigned long long)fw->comm_base);
1298219820Sjeff	mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2);
1299219820Sjeff
1300255932Salfred	MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET);
1301255932Salfred	MLX4_GET(fw->clock_bar,    outbox, QUERY_FW_CLOCK_BAR);
1302255932Salfred	fw->clock_bar = (fw->clock_bar >> 6) * 2;
1303255932Salfred	mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n",
1304272407Shselasky		 fw->comm_bar, (unsigned long long)fw->comm_base);
1305255932Salfred
1306219820Sjeff	/*
1307219820Sjeff	 * Round up number of system pages needed in case
1308219820Sjeff	 * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
1309219820Sjeff	 */
1310219820Sjeff	fw->fw_pages =
1311219820Sjeff		ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
1312219820Sjeff		(PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
1313219820Sjeff
1314219820Sjeff	mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n",
1315219820Sjeff		 (unsigned long long) fw->clr_int_base, fw->clr_int_bar);
1316219820Sjeff
1317219820Sjeffout:
1318219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1319219820Sjeff	return err;
1320219820Sjeff}
1321219820Sjeff
1322255932Salfredint mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave,
1323255932Salfred			  struct mlx4_vhcr *vhcr,
1324255932Salfred			  struct mlx4_cmd_mailbox *inbox,
1325255932Salfred			  struct mlx4_cmd_mailbox *outbox,
1326255932Salfred			  struct mlx4_cmd_info *cmd)
1327255932Salfred{
1328255932Salfred	u8 *outbuf;
1329255932Salfred	int err;
1330255932Salfred
1331255932Salfred	outbuf = outbox->buf;
1332255932Salfred	err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_FW,
1333255932Salfred			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1334255932Salfred	if (err)
1335255932Salfred		return err;
1336255932Salfred
1337255932Salfred	/* for slaves, set pci PPF ID to invalid and zero out everything
1338255932Salfred	 * else except FW version */
1339255932Salfred	outbuf[0] = outbuf[1] = 0;
1340255932Salfred	memset(&outbuf[8], 0, QUERY_FW_OUT_SIZE - 8);
1341255932Salfred	outbuf[QUERY_FW_PPF_ID] = MLX4_INVALID_SLAVE_ID;
1342255932Salfred
1343255932Salfred	return 0;
1344255932Salfred}
1345255932Salfred
1346272407Shselaskystatic void get_board_id(void *vsd, char *board_id, char *vsdstr)
1347219820Sjeff{
1348219820Sjeff	int i;
1349219820Sjeff
1350219820Sjeff#define VSD_OFFSET_SIG1		0x00
1351219820Sjeff#define VSD_OFFSET_SIG2		0xde
1352219820Sjeff#define VSD_OFFSET_MLX_BOARD_ID	0xd0
1353219820Sjeff#define VSD_OFFSET_TS_BOARD_ID	0x20
1354272407Shselasky#define VSD_LEN			0xd0
1355219820Sjeff
1356219820Sjeff#define VSD_SIGNATURE_TOPSPIN	0x5ad
1357219820Sjeff
1358272407Shselasky	memset(vsdstr, 0, MLX4_VSD_LEN);
1359272407Shselasky
1360272407Shselasky	for (i = 0; i < VSD_LEN / 4; i++)
1361272407Shselasky		((u32 *)vsdstr)[i] =
1362272407Shselasky			swab32(*(u32 *)(vsd + i * 4));
1363272407Shselasky
1364219820Sjeff	memset(board_id, 0, MLX4_BOARD_ID_LEN);
1365219820Sjeff
1366219820Sjeff	if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN &&
1367219820Sjeff	    be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) {
1368219820Sjeff		strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN);
1369219820Sjeff	} else {
1370219820Sjeff		/*
1371219820Sjeff		 * The board ID is a string but the firmware byte
1372219820Sjeff		 * swaps each 4-byte word before passing it back to
1373219820Sjeff		 * us.  Therefore we need to swab it before printing.
1374219820Sjeff		 */
1375219820Sjeff		for (i = 0; i < 4; ++i)
1376219820Sjeff			((u32 *) board_id)[i] =
1377219820Sjeff				swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4));
1378219820Sjeff	}
1379219820Sjeff}
1380219820Sjeff
1381219820Sjeffint mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter)
1382219820Sjeff{
1383219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1384219820Sjeff	u32 *outbox;
1385219820Sjeff	int err;
1386219820Sjeff
1387219820Sjeff#define QUERY_ADAPTER_OUT_SIZE             0x100
1388219820Sjeff#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
1389219820Sjeff#define QUERY_ADAPTER_VSD_OFFSET           0x20
1390272407Shselasky#define QUERY_ADAPTER_VSD_VENDOR_ID_OFFSET 0x1e
1391219820Sjeff
1392219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1393219820Sjeff	if (IS_ERR(mailbox))
1394219820Sjeff		return PTR_ERR(mailbox);
1395219820Sjeff	outbox = mailbox->buf;
1396219820Sjeff
1397219820Sjeff	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER,
1398255932Salfred			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1399219820Sjeff	if (err)
1400219820Sjeff		goto out;
1401219820Sjeff
1402219820Sjeff	MLX4_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
1403219820Sjeff
1404272407Shselasky	adapter->vsd_vendor_id = be16_to_cpup((u16 *)outbox +
1405272407Shselasky				QUERY_ADAPTER_VSD_VENDOR_ID_OFFSET / 2);
1406272407Shselasky
1407219820Sjeff	get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
1408272407Shselasky		     adapter->board_id, adapter->vsd);
1409219820Sjeff
1410219820Sjeffout:
1411219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1412219820Sjeff	return err;
1413219820Sjeff}
1414219820Sjeff
1415219820Sjeffint mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
1416219820Sjeff{
1417219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1418219820Sjeff	__be32 *inbox;
1419272407Shselasky	u32 mw_enable;
1420219820Sjeff	int err;
1421219820Sjeff
1422219820Sjeff#define INIT_HCA_IN_SIZE		 0x200
1423272407Shselasky#define INIT_HCA_DRV_NAME_FOR_FW_MAX_SIZE 64
1424219820Sjeff#define INIT_HCA_VERSION_OFFSET		 0x000
1425219820Sjeff#define	 INIT_HCA_VERSION		 2
1426219820Sjeff#define INIT_HCA_CACHELINE_SZ_OFFSET	 0x0e
1427219820Sjeff#define INIT_HCA_FLAGS_OFFSET		 0x014
1428272407Shselasky#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018
1429219820Sjeff#define INIT_HCA_QPC_OFFSET		 0x020
1430219820Sjeff#define	 INIT_HCA_QPC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x10)
1431219820Sjeff#define	 INIT_HCA_LOG_QP_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x17)
1432219820Sjeff#define	 INIT_HCA_SRQC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x28)
1433219820Sjeff#define	 INIT_HCA_LOG_SRQ_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x2f)
1434219820Sjeff#define	 INIT_HCA_CQC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x30)
1435219820Sjeff#define	 INIT_HCA_LOG_CQ_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x37)
1436255932Salfred#define	 INIT_HCA_EQE_CQE_OFFSETS	 (INIT_HCA_QPC_OFFSET + 0x38)
1437219820Sjeff#define	 INIT_HCA_ALTC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x40)
1438219820Sjeff#define	 INIT_HCA_AUXC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x50)
1439219820Sjeff#define	 INIT_HCA_EQC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x60)
1440219820Sjeff#define	 INIT_HCA_LOG_EQ_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x67)
1441318536Shselasky#define	INIT_HCA_NUM_SYS_EQS_OFFSET	(INIT_HCA_QPC_OFFSET + 0x6a)
1442219820Sjeff#define	 INIT_HCA_RDMARC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x70)
1443219820Sjeff#define	 INIT_HCA_LOG_RD_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x77)
1444219820Sjeff#define INIT_HCA_MCAST_OFFSET		 0x0c0
1445219820Sjeff#define	 INIT_HCA_MC_BASE_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x00)
1446219820Sjeff#define	 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12)
1447219820Sjeff#define	 INIT_HCA_LOG_MC_HASH_SZ_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x16)
1448255932Salfred#define  INIT_HCA_UC_STEERING_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x18)
1449219820Sjeff#define	 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b)
1450255932Salfred#define  INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN	0x6
1451272407Shselasky#define  INIT_HCA_DRIVER_VERSION_OFFSET   0x140
1452255932Salfred#define  INIT_HCA_FS_PARAM_OFFSET         0x1d0
1453255932Salfred#define  INIT_HCA_FS_BASE_OFFSET          (INIT_HCA_FS_PARAM_OFFSET + 0x00)
1454255932Salfred#define  INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x12)
1455255932Salfred#define  INIT_HCA_FS_LOG_TABLE_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x1b)
1456255932Salfred#define  INIT_HCA_FS_ETH_BITS_OFFSET      (INIT_HCA_FS_PARAM_OFFSET + 0x21)
1457255932Salfred#define  INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22)
1458255932Salfred#define  INIT_HCA_FS_IB_BITS_OFFSET       (INIT_HCA_FS_PARAM_OFFSET + 0x25)
1459255932Salfred#define  INIT_HCA_FS_IB_NUM_ADDRS_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x26)
1460219820Sjeff#define INIT_HCA_TPT_OFFSET		 0x0f0
1461219820Sjeff#define	 INIT_HCA_DMPT_BASE_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x00)
1462272407Shselasky#define  INIT_HCA_TPT_MW_OFFSET		 (INIT_HCA_TPT_OFFSET + 0x08)
1463272407Shselasky#define  INIT_HCA_TPT_MW_ENABLE		 (1 << 31)
1464219820Sjeff#define	 INIT_HCA_LOG_MPT_SZ_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x0b)
1465219820Sjeff#define	 INIT_HCA_MTT_BASE_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x10)
1466219820Sjeff#define	 INIT_HCA_CMPT_BASE_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x18)
1467219820Sjeff#define INIT_HCA_UAR_OFFSET		 0x120
1468219820Sjeff#define	 INIT_HCA_LOG_UAR_SZ_OFFSET	 (INIT_HCA_UAR_OFFSET + 0x0a)
1469219820Sjeff#define  INIT_HCA_UAR_PAGE_SZ_OFFSET     (INIT_HCA_UAR_OFFSET + 0x0b)
1470219820Sjeff
1471219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1472219820Sjeff	if (IS_ERR(mailbox))
1473219820Sjeff		return PTR_ERR(mailbox);
1474219820Sjeff	inbox = mailbox->buf;
1475219820Sjeff
1476219820Sjeff	memset(inbox, 0, INIT_HCA_IN_SIZE);
1477219820Sjeff
1478219820Sjeff	*((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION;
1479219820Sjeff
1480255932Salfred	*((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) =
1481272407Shselasky		((ilog2(cache_line_size()) - 4) << 5) | (1 << 4);
1482255932Salfred
1483219820Sjeff#if defined(__LITTLE_ENDIAN)
1484219820Sjeff	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
1485219820Sjeff#elif defined(__BIG_ENDIAN)
1486219820Sjeff	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
1487219820Sjeff#else
1488219820Sjeff#error Host endianness not defined
1489219820Sjeff#endif
1490219820Sjeff	/* Check port for UD address vector: */
1491219820Sjeff	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
1492219820Sjeff
1493219820Sjeff	/* Enable IPoIB checksumming if we can: */
1494219820Sjeff	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM)
1495219820Sjeff		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3);
1496219820Sjeff
1497219820Sjeff	/* Enable QoS support if module parameter set */
1498219820Sjeff	if (enable_qos)
1499219820Sjeff		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2);
1500219820Sjeff
1501255932Salfred	/* Enable fast drop performance optimization */
1502255932Salfred	if (dev->caps.fast_drop)
1503255932Salfred		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 7);
1504219820Sjeff
1505255932Salfred	/* enable counters */
1506255932Salfred	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)
1507255932Salfred		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4);
1508255932Salfred
1509255932Salfred	/* CX3 is capable of extending CQEs\EQEs from 32 to 64 bytes */
1510255932Salfred	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) {
1511255932Salfred		*(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29);
1512255932Salfred		dev->caps.eqe_size   = 64;
1513255932Salfred		dev->caps.eqe_factor = 1;
1514255932Salfred	} else {
1515255932Salfred		dev->caps.eqe_size   = 32;
1516255932Salfred		dev->caps.eqe_factor = 0;
1517255932Salfred	}
1518255932Salfred
1519255932Salfred	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_CQE) {
1520255932Salfred		*(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 30);
1521255932Salfred		dev->caps.cqe_size   = 64;
1522255932Salfred		dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_64B_CQE;
1523255932Salfred	} else {
1524255932Salfred		dev->caps.cqe_size   = 32;
1525255932Salfred	}
1526255932Salfred
1527272407Shselasky	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT)
1528272407Shselasky		*(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31);
1529272407Shselasky
1530272407Shselasky	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW) {
1531272407Shselasky		strncpy((u8 *)mailbox->buf + INIT_HCA_DRIVER_VERSION_OFFSET,
1532272407Shselasky			DRV_NAME_FOR_FW,
1533272407Shselasky			INIT_HCA_DRV_NAME_FOR_FW_MAX_SIZE - 1);
1534272407Shselasky		mlx4_dbg(dev, "Reporting Driver Version to FW: %s\n",
1535272407Shselasky			 (u8 *)mailbox->buf + INIT_HCA_DRIVER_VERSION_OFFSET);
1536272407Shselasky	}
1537272407Shselasky
1538219820Sjeff	/* QPC/EEC/CQC/EQC/RDMARC attributes */
1539219820Sjeff
1540219820Sjeff	MLX4_PUT(inbox, param->qpc_base,      INIT_HCA_QPC_BASE_OFFSET);
1541219820Sjeff	MLX4_PUT(inbox, param->log_num_qps,   INIT_HCA_LOG_QP_OFFSET);
1542219820Sjeff	MLX4_PUT(inbox, param->srqc_base,     INIT_HCA_SRQC_BASE_OFFSET);
1543219820Sjeff	MLX4_PUT(inbox, param->log_num_srqs,  INIT_HCA_LOG_SRQ_OFFSET);
1544219820Sjeff	MLX4_PUT(inbox, param->cqc_base,      INIT_HCA_CQC_BASE_OFFSET);
1545219820Sjeff	MLX4_PUT(inbox, param->log_num_cqs,   INIT_HCA_LOG_CQ_OFFSET);
1546219820Sjeff	MLX4_PUT(inbox, param->altc_base,     INIT_HCA_ALTC_BASE_OFFSET);
1547219820Sjeff	MLX4_PUT(inbox, param->auxc_base,     INIT_HCA_AUXC_BASE_OFFSET);
1548219820Sjeff	MLX4_PUT(inbox, param->eqc_base,      INIT_HCA_EQC_BASE_OFFSET);
1549219820Sjeff	MLX4_PUT(inbox, param->log_num_eqs,   INIT_HCA_LOG_EQ_OFFSET);
1550318536Shselasky	MLX4_PUT(inbox, param->num_sys_eqs,   INIT_HCA_NUM_SYS_EQS_OFFSET);
1551219820Sjeff	MLX4_PUT(inbox, param->rdmarc_base,   INIT_HCA_RDMARC_BASE_OFFSET);
1552219820Sjeff	MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET);
1553219820Sjeff
1554255932Salfred	/* steering attributes */
1555255932Salfred	if (dev->caps.steering_mode ==
1556255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
1557255932Salfred		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |=
1558255932Salfred			cpu_to_be32(1 <<
1559255932Salfred				    INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN);
1560219820Sjeff
1561255932Salfred		MLX4_PUT(inbox, param->mc_base, INIT_HCA_FS_BASE_OFFSET);
1562255932Salfred		MLX4_PUT(inbox, param->log_mc_entry_sz,
1563255932Salfred			 INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
1564255932Salfred		MLX4_PUT(inbox, param->log_mc_table_sz,
1565255932Salfred			 INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
1566255932Salfred		/* Enable Ethernet flow steering
1567255932Salfred		 * with udp unicast and tcp unicast
1568255932Salfred		 */
1569255932Salfred		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
1570255932Salfred			 INIT_HCA_FS_ETH_BITS_OFFSET);
1571255932Salfred		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
1572255932Salfred			 INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
1573255932Salfred		/* Enable IPoIB flow steering
1574255932Salfred		 * with udp unicast and tcp unicast
1575255932Salfred		 */
1576255932Salfred		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
1577255932Salfred			 INIT_HCA_FS_IB_BITS_OFFSET);
1578255932Salfred		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
1579255932Salfred			 INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
1580255932Salfred	} else {
1581255932Salfred		MLX4_PUT(inbox, param->mc_base,	INIT_HCA_MC_BASE_OFFSET);
1582255932Salfred		MLX4_PUT(inbox, param->log_mc_entry_sz,
1583255932Salfred			 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
1584255932Salfred		MLX4_PUT(inbox, param->log_mc_hash_sz,
1585255932Salfred			 INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
1586255932Salfred		MLX4_PUT(inbox, param->log_mc_table_sz,
1587255932Salfred			 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
1588272407Shselasky		if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0)
1589255932Salfred			MLX4_PUT(inbox, (u8) (1 << 3),
1590255932Salfred				 INIT_HCA_UC_STEERING_OFFSET);
1591255932Salfred	}
1592219820Sjeff
1593219820Sjeff	/* TPT attributes */
1594219820Sjeff
1595219820Sjeff	MLX4_PUT(inbox, param->dmpt_base,  INIT_HCA_DMPT_BASE_OFFSET);
1596272407Shselasky	mw_enable = param->mw_enable ? INIT_HCA_TPT_MW_ENABLE : 0;
1597272407Shselasky	MLX4_PUT(inbox, mw_enable,	   INIT_HCA_TPT_MW_OFFSET);
1598219820Sjeff	MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET);
1599219820Sjeff	MLX4_PUT(inbox, param->mtt_base,   INIT_HCA_MTT_BASE_OFFSET);
1600219820Sjeff	MLX4_PUT(inbox, param->cmpt_base,  INIT_HCA_CMPT_BASE_OFFSET);
1601219820Sjeff
1602219820Sjeff	/* UAR attributes */
1603219820Sjeff
1604255932Salfred	MLX4_PUT(inbox, param->uar_page_sz,	INIT_HCA_UAR_PAGE_SZ_OFFSET);
1605219820Sjeff	MLX4_PUT(inbox, param->log_uar_sz,      INIT_HCA_LOG_UAR_SZ_OFFSET);
1606219820Sjeff
1607255932Salfred	err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000,
1608255932Salfred		       MLX4_CMD_NATIVE);
1609219820Sjeff
1610219820Sjeff	if (err)
1611219820Sjeff		mlx4_err(dev, "INIT_HCA returns %d\n", err);
1612219820Sjeff
1613219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1614219820Sjeff	return err;
1615219820Sjeff}
1616219820Sjeff
1617255932Salfredint mlx4_QUERY_HCA(struct mlx4_dev *dev,
1618255932Salfred		   struct mlx4_init_hca_param *param)
1619255932Salfred{
1620255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1621255932Salfred	__be32 *outbox;
1622255932Salfred	u32 dword_field;
1623272407Shselasky	u32 mw_enable;
1624255932Salfred	int err;
1625255932Salfred	u8 byte_field;
1626255932Salfred
1627255932Salfred#define QUERY_HCA_GLOBAL_CAPS_OFFSET	0x04
1628255932Salfred#define QUERY_HCA_CORE_CLOCK_OFFSET	0x0c
1629255932Salfred
1630255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1631255932Salfred	if (IS_ERR(mailbox))
1632255932Salfred		return PTR_ERR(mailbox);
1633255932Salfred	outbox = mailbox->buf;
1634255932Salfred
1635255932Salfred	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
1636255932Salfred			   MLX4_CMD_QUERY_HCA,
1637255932Salfred			   MLX4_CMD_TIME_CLASS_B,
1638255932Salfred			   !mlx4_is_slave(dev));
1639255932Salfred	if (err)
1640255932Salfred		goto out;
1641255932Salfred
1642255932Salfred	MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET);
1643255932Salfred	MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET);
1644255932Salfred
1645255932Salfred	/* QPC/EEC/CQC/EQC/RDMARC attributes */
1646255932Salfred
1647255932Salfred	MLX4_GET(param->qpc_base,      outbox, INIT_HCA_QPC_BASE_OFFSET);
1648255932Salfred	MLX4_GET(param->log_num_qps,   outbox, INIT_HCA_LOG_QP_OFFSET);
1649255932Salfred	MLX4_GET(param->srqc_base,     outbox, INIT_HCA_SRQC_BASE_OFFSET);
1650255932Salfred	MLX4_GET(param->log_num_srqs,  outbox, INIT_HCA_LOG_SRQ_OFFSET);
1651255932Salfred	MLX4_GET(param->cqc_base,      outbox, INIT_HCA_CQC_BASE_OFFSET);
1652255932Salfred	MLX4_GET(param->log_num_cqs,   outbox, INIT_HCA_LOG_CQ_OFFSET);
1653255932Salfred	MLX4_GET(param->altc_base,     outbox, INIT_HCA_ALTC_BASE_OFFSET);
1654255932Salfred	MLX4_GET(param->auxc_base,     outbox, INIT_HCA_AUXC_BASE_OFFSET);
1655255932Salfred	MLX4_GET(param->eqc_base,      outbox, INIT_HCA_EQC_BASE_OFFSET);
1656255932Salfred	MLX4_GET(param->log_num_eqs,   outbox, INIT_HCA_LOG_EQ_OFFSET);
1657318536Shselasky	MLX4_GET(param->num_sys_eqs,   outbox, INIT_HCA_NUM_SYS_EQS_OFFSET);
1658255932Salfred	MLX4_GET(param->rdmarc_base,   outbox, INIT_HCA_RDMARC_BASE_OFFSET);
1659255932Salfred	MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET);
1660255932Salfred
1661255932Salfred	MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET);
1662255932Salfred	if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) {
1663255932Salfred		param->steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED;
1664255932Salfred	} else {
1665255932Salfred		MLX4_GET(byte_field, outbox, INIT_HCA_UC_STEERING_OFFSET);
1666272407Shselasky		if (byte_field & 0x8)
1667255932Salfred			param->steering_mode = MLX4_STEERING_MODE_B0;
1668272407Shselasky		else
1669255932Salfred			param->steering_mode = MLX4_STEERING_MODE_A0;
1670255932Salfred	}
1671272407Shselasky	/* steering attributes */
1672255932Salfred	if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
1673255932Salfred		MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET);
1674255932Salfred		MLX4_GET(param->log_mc_entry_sz, outbox,
1675255932Salfred			 INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
1676255932Salfred		MLX4_GET(param->log_mc_table_sz, outbox,
1677255932Salfred			 INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
1678255932Salfred	} else {
1679255932Salfred		MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
1680255932Salfred		MLX4_GET(param->log_mc_entry_sz, outbox,
1681255932Salfred			 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
1682255932Salfred		MLX4_GET(param->log_mc_hash_sz,  outbox,
1683255932Salfred			 INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
1684255932Salfred		MLX4_GET(param->log_mc_table_sz, outbox,
1685255932Salfred			 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
1686255932Salfred	}
1687255932Salfred
1688255932Salfred	/* CX3 is capable of extending CQEs\EQEs from 32 to 64 bytes */
1689255932Salfred	MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_OFFSETS);
1690255932Salfred	if (byte_field & 0x20) /* 64-bytes eqe enabled */
1691255932Salfred		param->dev_cap_enabled |= MLX4_DEV_CAP_64B_EQE_ENABLED;
1692255932Salfred	if (byte_field & 0x40) /* 64-bytes cqe enabled */
1693255932Salfred		param->dev_cap_enabled |= MLX4_DEV_CAP_64B_CQE_ENABLED;
1694255932Salfred
1695255932Salfred	/* TPT attributes */
1696255932Salfred
1697255932Salfred	MLX4_GET(param->dmpt_base,  outbox, INIT_HCA_DMPT_BASE_OFFSET);
1698272407Shselasky	MLX4_GET(mw_enable,	    outbox, INIT_HCA_TPT_MW_OFFSET);
1699272407Shselasky	param->mw_enable = (mw_enable & INIT_HCA_TPT_MW_ENABLE) ==
1700272407Shselasky			   INIT_HCA_TPT_MW_ENABLE;
1701255932Salfred	MLX4_GET(param->log_mpt_sz, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET);
1702255932Salfred	MLX4_GET(param->mtt_base,   outbox, INIT_HCA_MTT_BASE_OFFSET);
1703255932Salfred	MLX4_GET(param->cmpt_base,  outbox, INIT_HCA_CMPT_BASE_OFFSET);
1704255932Salfred
1705255932Salfred	/* UAR attributes */
1706255932Salfred
1707255932Salfred	MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET);
1708255932Salfred	MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET);
1709255932Salfred
1710255932Salfredout:
1711255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1712255932Salfred
1713255932Salfred	return err;
1714255932Salfred}
1715255932Salfred
1716255932Salfred/* for IB-type ports only in SRIOV mode. Checks that both proxy QP0
1717255932Salfred * and real QP0 are active, so that the paravirtualized QP0 is ready
1718255932Salfred * to operate */
1719255932Salfredstatic int check_qp0_state(struct mlx4_dev *dev, int function, int port)
1720255932Salfred{
1721255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1722255932Salfred	/* irrelevant if not infiniband */
1723255932Salfred	if (priv->mfunc.master.qp0_state[port].proxy_qp0_active &&
1724255932Salfred	    priv->mfunc.master.qp0_state[port].qp0_active)
1725255932Salfred		return 1;
1726255932Salfred	return 0;
1727255932Salfred}
1728255932Salfred
1729255932Salfredint mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave,
1730255932Salfred			   struct mlx4_vhcr *vhcr,
1731255932Salfred			   struct mlx4_cmd_mailbox *inbox,
1732255932Salfred			   struct mlx4_cmd_mailbox *outbox,
1733255932Salfred			   struct mlx4_cmd_info *cmd)
1734255932Salfred{
1735255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1736255932Salfred	int port = vhcr->in_modifier;
1737255932Salfred	int err;
1738255932Salfred
1739255932Salfred	if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port))
1740255932Salfred		return 0;
1741255932Salfred
1742255932Salfred	if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) {
1743255932Salfred		/* Enable port only if it was previously disabled */
1744255932Salfred		if (!priv->mfunc.master.init_port_ref[port]) {
1745255932Salfred			err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
1746255932Salfred				       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1747255932Salfred			if (err)
1748255932Salfred				return err;
1749255932Salfred		}
1750255932Salfred		priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port);
1751255932Salfred	} else {
1752255932Salfred		if (slave == mlx4_master_func_num(dev)) {
1753255932Salfred			if (check_qp0_state(dev, slave, port) &&
1754255932Salfred			    !priv->mfunc.master.qp0_state[port].port_active) {
1755255932Salfred				err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
1756255932Salfred					       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1757255932Salfred				if (err)
1758255932Salfred					return err;
1759255932Salfred				priv->mfunc.master.qp0_state[port].port_active = 1;
1760255932Salfred				priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port);
1761255932Salfred			}
1762255932Salfred		} else
1763255932Salfred			priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port);
1764255932Salfred	}
1765255932Salfred	++priv->mfunc.master.init_port_ref[port];
1766255932Salfred	return 0;
1767255932Salfred}
1768255932Salfred
1769219820Sjeffint mlx4_INIT_PORT(struct mlx4_dev *dev, int port)
1770219820Sjeff{
1771219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1772219820Sjeff	u32 *inbox;
1773219820Sjeff	int err;
1774219820Sjeff	u32 flags;
1775219820Sjeff	u16 field;
1776219820Sjeff
1777219820Sjeff	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1778219820Sjeff#define INIT_PORT_IN_SIZE          256
1779219820Sjeff#define INIT_PORT_FLAGS_OFFSET     0x00
1780219820Sjeff#define INIT_PORT_FLAG_SIG         (1 << 18)
1781219820Sjeff#define INIT_PORT_FLAG_NG          (1 << 17)
1782219820Sjeff#define INIT_PORT_FLAG_G0          (1 << 16)
1783219820Sjeff#define INIT_PORT_VL_SHIFT         4
1784219820Sjeff#define INIT_PORT_PORT_WIDTH_SHIFT 8
1785219820Sjeff#define INIT_PORT_MTU_OFFSET       0x04
1786219820Sjeff#define INIT_PORT_MAX_GID_OFFSET   0x06
1787219820Sjeff#define INIT_PORT_MAX_PKEY_OFFSET  0x0a
1788219820Sjeff#define INIT_PORT_GUID0_OFFSET     0x10
1789219820Sjeff#define INIT_PORT_NODE_GUID_OFFSET 0x18
1790219820Sjeff#define INIT_PORT_SI_GUID_OFFSET   0x20
1791219820Sjeff
1792219820Sjeff		mailbox = mlx4_alloc_cmd_mailbox(dev);
1793219820Sjeff		if (IS_ERR(mailbox))
1794219820Sjeff			return PTR_ERR(mailbox);
1795219820Sjeff		inbox = mailbox->buf;
1796219820Sjeff
1797219820Sjeff		memset(inbox, 0, INIT_PORT_IN_SIZE);
1798219820Sjeff
1799219820Sjeff		flags = 0;
1800219820Sjeff		flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT;
1801219820Sjeff		flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT;
1802219820Sjeff		MLX4_PUT(inbox, flags,		  INIT_PORT_FLAGS_OFFSET);
1803219820Sjeff
1804219820Sjeff		field = 128 << dev->caps.ib_mtu_cap[port];
1805219820Sjeff		MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET);
1806219820Sjeff		field = dev->caps.gid_table_len[port];
1807219820Sjeff		MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET);
1808219820Sjeff		field = dev->caps.pkey_table_len[port];
1809219820Sjeff		MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET);
1810219820Sjeff
1811219820Sjeff		err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT,
1812255932Salfred			       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1813219820Sjeff
1814219820Sjeff		mlx4_free_cmd_mailbox(dev, mailbox);
1815219820Sjeff	} else
1816219820Sjeff		err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
1817255932Salfred			       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
1818219820Sjeff
1819219820Sjeff	return err;
1820219820Sjeff}
1821219820SjeffEXPORT_SYMBOL_GPL(mlx4_INIT_PORT);
1822219820Sjeff
1823255932Salfredint mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
1824255932Salfred			    struct mlx4_vhcr *vhcr,
1825255932Salfred			    struct mlx4_cmd_mailbox *inbox,
1826255932Salfred			    struct mlx4_cmd_mailbox *outbox,
1827255932Salfred			    struct mlx4_cmd_info *cmd)
1828255932Salfred{
1829255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1830255932Salfred	int port = vhcr->in_modifier;
1831255932Salfred	int err;
1832255932Salfred
1833255932Salfred	if (!(priv->mfunc.master.slave_state[slave].init_port_mask &
1834255932Salfred	    (1 << port)))
1835255932Salfred		return 0;
1836255932Salfred
1837255932Salfred	if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) {
1838255932Salfred		if (priv->mfunc.master.init_port_ref[port] == 1) {
1839255932Salfred			err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
1840255932Salfred				       1000, MLX4_CMD_NATIVE);
1841255932Salfred			if (err)
1842255932Salfred				return err;
1843255932Salfred		}
1844255932Salfred		priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
1845255932Salfred	} else {
1846255932Salfred		/* infiniband port */
1847255932Salfred		if (slave == mlx4_master_func_num(dev)) {
1848255932Salfred			if (!priv->mfunc.master.qp0_state[port].qp0_active &&
1849255932Salfred			    priv->mfunc.master.qp0_state[port].port_active) {
1850255932Salfred				err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
1851255932Salfred					       1000, MLX4_CMD_NATIVE);
1852255932Salfred				if (err)
1853255932Salfred					return err;
1854255932Salfred				priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
1855255932Salfred				priv->mfunc.master.qp0_state[port].port_active = 0;
1856255932Salfred			}
1857255932Salfred		} else
1858255932Salfred			priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
1859255932Salfred	}
1860255932Salfred	--priv->mfunc.master.init_port_ref[port];
1861255932Salfred	return 0;
1862255932Salfred}
1863255932Salfred
1864219820Sjeffint mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port)
1865219820Sjeff{
1866255932Salfred	return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000,
1867255932Salfred			MLX4_CMD_WRAPPED);
1868219820Sjeff}
1869219820SjeffEXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT);
1870219820Sjeff
1871219820Sjeffint mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
1872219820Sjeff{
1873255932Salfred	return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000,
1874255932Salfred			MLX4_CMD_NATIVE);
1875219820Sjeff}
1876219820Sjeff
1877219820Sjeffint mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
1878219820Sjeff{
1879219820Sjeff	int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
1880219820Sjeff			       MLX4_CMD_SET_ICM_SIZE,
1881255932Salfred			       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1882219820Sjeff	if (ret)
1883219820Sjeff		return ret;
1884219820Sjeff
1885219820Sjeff	/*
1886219820Sjeff	 * Round up number of system pages needed in case
1887219820Sjeff	 * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
1888219820Sjeff	 */
1889219820Sjeff	*aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
1890219820Sjeff		(PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
1891219820Sjeff
1892219820Sjeff	return 0;
1893219820Sjeff}
1894219820Sjeff
1895219820Sjeffint mlx4_NOP(struct mlx4_dev *dev)
1896219820Sjeff{
1897219820Sjeff	/* Input modifier of 0x1f means "finish as soon as possible." */
1898255932Salfred	return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1899219820Sjeff}
1900219820Sjeff
1901255932Salfredint mlx4_query_diag_counters(struct mlx4_dev *dev, int array_length,
1902255932Salfred			     u8 op_modifier, u32 in_offset[],
1903255932Salfred			     u32 counter_out[])
1904255932Salfred{
1905255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1906255932Salfred	u32 *outbox;
1907255932Salfred	int ret;
1908255932Salfred	int i;
1909255932Salfred
1910255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1911255932Salfred	if (IS_ERR(mailbox))
1912255932Salfred		return PTR_ERR(mailbox);
1913255932Salfred	outbox = mailbox->buf;
1914255932Salfred
1915255932Salfred	ret = mlx4_cmd_box(dev, 0, mailbox->dma, 0, op_modifier,
1916255932Salfred			   MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A,
1917255932Salfred			   MLX4_CMD_NATIVE);
1918255932Salfred	if (ret)
1919255932Salfred		goto out;
1920255932Salfred
1921255932Salfred	for (i = 0; i < array_length; i++) {
1922255932Salfred		if (in_offset[i] > MLX4_MAILBOX_SIZE) {
1923255932Salfred			ret = -EINVAL;
1924255932Salfred			goto out;
1925255932Salfred		}
1926255932Salfred
1927255932Salfred		MLX4_GET(counter_out[i], outbox, in_offset[i]);
1928255932Salfred	}
1929255932Salfred
1930255932Salfredout:
1931255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1932255932Salfred	return ret;
1933255932Salfred}
1934255932SalfredEXPORT_SYMBOL_GPL(mlx4_query_diag_counters);
1935255932Salfred
1936272407Shselaskyint mlx4_MOD_STAT_CFG_wrapper(struct mlx4_dev *dev, int slave,
1937272407Shselasky			  struct mlx4_vhcr *vhcr,
1938272407Shselasky			  struct mlx4_cmd_mailbox *inbox,
1939272407Shselasky			  struct mlx4_cmd_mailbox *outbox,
1940272407Shselasky			  struct mlx4_cmd_info *cmd)
1941272407Shselasky{
1942272407Shselasky	return -EPERM;
1943272407Shselasky}
1944272407Shselasky
1945220016Sjeff#define MLX4_WOL_SETUP_MODE (5 << 28)
1946220016Sjeffint mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port)
1947220016Sjeff{
1948220016Sjeff	u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
1949220016Sjeff
1950220016Sjeff	return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3,
1951255932Salfred			    MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A,
1952255932Salfred			    MLX4_CMD_NATIVE);
1953220016Sjeff}
1954220016SjeffEXPORT_SYMBOL_GPL(mlx4_wol_read);
1955220016Sjeff
1956220016Sjeffint mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port)
1957220016Sjeff{
1958220016Sjeff	u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
1959220016Sjeff
1960220016Sjeff	return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG,
1961255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1962220016Sjeff}
1963220016SjeffEXPORT_SYMBOL_GPL(mlx4_wol_write);
1964220016Sjeff
1965255932Salfredenum {
1966255932Salfred	ADD_TO_MCG = 0x26,
1967255932Salfred};
1968255932Salfred
1969255932Salfred
1970255932Salfredvoid mlx4_opreq_action(struct work_struct *work)
1971219820Sjeff{
1972255932Salfred	struct mlx4_priv *priv = container_of(work, struct mlx4_priv, opreq_task);
1973255932Salfred	struct mlx4_dev *dev = &priv->dev;
1974255932Salfred	int num_tasks = atomic_read(&priv->opreq_count);
1975219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1976255932Salfred	struct mlx4_mgm *mgm;
1977219820Sjeff	u32 *outbox;
1978255932Salfred	u32 modifier;
1979255932Salfred	u16 token;
1980255932Salfred	u16 type_m;
1981255932Salfred	u16 type;
1982255932Salfred	int err;
1983255932Salfred	u32 num_qps;
1984255932Salfred	struct mlx4_qp qp;
1985219820Sjeff	int i;
1986255932Salfred	u8 rem_mcg;
1987255932Salfred	u8 prot;
1988219820Sjeff
1989255932Salfred#define GET_OP_REQ_MODIFIER_OFFSET	0x08
1990255932Salfred#define GET_OP_REQ_TOKEN_OFFSET		0x14
1991255932Salfred#define GET_OP_REQ_TYPE_OFFSET		0x1a
1992255932Salfred#define GET_OP_REQ_DATA_OFFSET		0x20
1993255932Salfred
1994219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1995255932Salfred	if (IS_ERR(mailbox)) {
1996255932Salfred		mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n");
1997255932Salfred		return;
1998255932Salfred	}
1999219820Sjeff	outbox = mailbox->buf;
2000219820Sjeff
2001255932Salfred	while (num_tasks) {
2002255932Salfred		err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
2003255932Salfred				   MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
2004255932Salfred				   MLX4_CMD_NATIVE);
2005255932Salfred		if (err) {
2006255932Salfred			mlx4_err(dev, "Failed to retreive required operation: %d\n", err);
2007255932Salfred			return;
2008255932Salfred		}
2009255932Salfred		MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET);
2010255932Salfred		MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET);
2011255932Salfred		MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET);
2012255932Salfred		type_m = type >> 12;
2013255932Salfred		type &= 0xfff;
2014219820Sjeff
2015255932Salfred		switch (type) {
2016255932Salfred		case ADD_TO_MCG:
2017255932Salfred			if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
2018255932Salfred				mlx4_warn(dev, "ADD MCG operation is not supported in "
2019255932Salfred					       "DEVICE_MANAGED steerign mode\n");
2020255932Salfred				err = EPERM;
2021255932Salfred				break;
2022255932Salfred			}
2023255932Salfred			mgm = (struct mlx4_mgm *) ((u8 *) (outbox) + GET_OP_REQ_DATA_OFFSET);
2024255932Salfred			num_qps = be32_to_cpu(mgm->members_count) & MGM_QPN_MASK;
2025255932Salfred			rem_mcg = ((u8 *) (&mgm->members_count))[0] & 1;
2026255932Salfred			prot = ((u8 *) (&mgm->members_count))[0] >> 6;
2027255932Salfred
2028255932Salfred			for (i = 0; i < num_qps; i++) {
2029255932Salfred				qp.qpn = be32_to_cpu(mgm->qp[i]);
2030255932Salfred				if (rem_mcg)
2031255932Salfred					err = mlx4_multicast_detach(dev, &qp, mgm->gid, prot, 0);
2032255932Salfred				else
2033255932Salfred					err = mlx4_multicast_attach(dev, &qp, mgm->gid, mgm->gid[5] ,0, prot, NULL);
2034255932Salfred				if (err)
2035255932Salfred					break;
2036255932Salfred			}
2037255932Salfred			break;
2038255932Salfred		default:
2039255932Salfred			mlx4_warn(dev, "Bad type for required operation\n");
2040255932Salfred			err = EINVAL;
2041255932Salfred			break;
2042255932Salfred		}
2043255932Salfred		err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16), 1,
2044255932Salfred			       MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
2045255932Salfred			       MLX4_CMD_NATIVE);
2046255932Salfred		if (err) {
2047255932Salfred			mlx4_err(dev, "Failed to acknowledge required request: %d\n", err);
2048219820Sjeff			goto out;
2049219820Sjeff		}
2050255932Salfred		memset(outbox, 0, 0xffc);
2051255932Salfred		num_tasks = atomic_dec_return(&priv->opreq_count);
2052219820Sjeff	}
2053219820Sjeff
2054219820Sjeffout:
2055219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
2056219820Sjeff}
2057