mlx5_main.c revision 331815
1199989Srdivacky/*-
2199989Srdivacky * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
3199989Srdivacky *
4199989Srdivacky * Redistribution and use in source and binary forms, with or without
5199989Srdivacky * modification, are permitted provided that the following conditions
6199989Srdivacky * are met:
7199989Srdivacky * 1. Redistributions of source code must retain the above copyright
8199989Srdivacky *    notice, this list of conditions and the following disclaimer.
9199989Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
10199989Srdivacky *    notice, this list of conditions and the following disclaimer in the
11199989Srdivacky *    documentation and/or other materials provided with the distribution.
12199989Srdivacky *
13199989Srdivacky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14199989Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15199989Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16199989Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18249423Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19249423Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22199989Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23210299Sed * SUCH DAMAGE.
24249423Sdim *
25200581Srdivacky * $FreeBSD: stable/11/sys/dev/mlx5/mlx5_core/mlx5_main.c 331815 2018-03-30 19:23:46Z hselasky $
26200581Srdivacky */
27239462Sdim
28249423Sdim#define	LINUXKPI_PARAM_PREFIX mlx5_
29199989Srdivacky
30199989Srdivacky#include <linux/kmod.h>
31200581Srdivacky#include <linux/module.h>
32199989Srdivacky#include <linux/errno.h>
33249423Sdim#include <linux/pci.h>
34249423Sdim#include <linux/dma-mapping.h>
35199989Srdivacky#include <linux/slab.h>
36199989Srdivacky#include <linux/io-mapping.h>
37200581Srdivacky#include <linux/interrupt.h>
38199989Srdivacky#include <dev/mlx5/driver.h>
39199989Srdivacky#include <dev/mlx5/cq.h>
40199989Srdivacky#include <dev/mlx5/qp.h>
41223017Sdim#include <dev/mlx5/srq.h>
42199989Srdivacky#include <linux/delay.h>
43199989Srdivacky#include <dev/mlx5/mlx5_ifc.h>
44199989Srdivacky#include "mlx5_core.h"
45199989Srdivacky#include "fs_core.h"
46199989Srdivacky
47199989SrdivackyMODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
48199989SrdivackyMODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver");
49200581SrdivackyMODULE_LICENSE("Dual BSD/GPL");
50200581Srdivacky#if (__FreeBSD_version >= 1100000)
51200581SrdivackyMODULE_DEPEND(mlx5, linuxkpi, 1, 1, 1);
52200581Srdivacky#endif
53200581SrdivackyMODULE_VERSION(mlx5, 1);
54200581Srdivacky
55200581Srdivackyint mlx5_core_debug_mask;
56200581Srdivackymodule_param_named(debug_mask, mlx5_core_debug_mask, int, 0644);
57200581SrdivackyMODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0");
58200581Srdivacky
59199989Srdivacky#define MLX5_DEFAULT_PROF	2
60199989Srdivackystatic int prof_sel = MLX5_DEFAULT_PROF;
61199989Srdivackymodule_param_named(prof_sel, prof_sel, int, 0444);
62199989SrdivackyMODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
63239462Sdim
64199989Srdivacky#define NUMA_NO_NODE       -1
65200581Srdivacky
66239462Sdimstatic LIST_HEAD(intf_list);
67234353Sdimstatic LIST_HEAD(dev_list);
68199989Srdivackystatic DEFINE_MUTEX(intf_mutex);
69200581Srdivacky
70200581Srdivackystruct mlx5_device_context {
71200581Srdivacky	struct list_head	list;
72200581Srdivacky	struct mlx5_interface  *intf;
73200581Srdivacky	void		       *context;
74200581Srdivacky};
75200581Srdivacky
76199989Srdivackyenum {
77199989Srdivacky	MLX5_ATOMIC_REQ_MODE_BE = 0x0,
78234353Sdim	MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS = 0x1,
79234353Sdim};
80199989Srdivacky
81199989Srdivackystatic struct mlx5_profile profiles[] = {
82199989Srdivacky	[0] = {
83199989Srdivacky		.mask           = 0,
84200581Srdivacky	},
85200581Srdivacky	[1] = {
86200581Srdivacky		.mask		= MLX5_PROF_MASK_QP_SIZE,
87200581Srdivacky		.log_max_qp	= 12,
88200581Srdivacky	},
89263508Sdim	[2] = {
90223017Sdim		.mask		= MLX5_PROF_MASK_QP_SIZE |
91223017Sdim				  MLX5_PROF_MASK_MR_CACHE,
92200581Srdivacky		.log_max_qp	= 17,
93200581Srdivacky		.mr_cache[0]	= {
94200581Srdivacky			.size	= 500,
95200581Srdivacky			.limit	= 250
96223017Sdim		},
97223017Sdim		.mr_cache[1]	= {
98200581Srdivacky			.size	= 500,
99263508Sdim			.limit	= 250
100200581Srdivacky		},
101199989Srdivacky		.mr_cache[2]	= {
102223017Sdim			.size	= 500,
103224145Sdim			.limit	= 250
104224145Sdim		},
105224145Sdim		.mr_cache[3]	= {
106224145Sdim			.size	= 500,
107263508Sdim			.limit	= 250
108224145Sdim		},
109263508Sdim		.mr_cache[4]	= {
110224145Sdim			.size	= 500,
111224145Sdim			.limit	= 250
112224145Sdim		},
113263508Sdim		.mr_cache[5]	= {
114263508Sdim			.size	= 500,
115224145Sdim			.limit	= 250
116224145Sdim		},
117224145Sdim		.mr_cache[6]	= {
118224145Sdim			.size	= 500,
119199989Srdivacky			.limit	= 250
120199989Srdivacky		},
121199989Srdivacky		.mr_cache[7]	= {
122199989Srdivacky			.size	= 500,
123199989Srdivacky			.limit	= 250
124199989Srdivacky		},
125234353Sdim		.mr_cache[8]	= {
126199989Srdivacky			.size	= 500,
127234353Sdim			.limit	= 250
128234353Sdim		},
129234353Sdim		.mr_cache[9]	= {
130199989Srdivacky			.size	= 500,
131199989Srdivacky			.limit	= 250
132239462Sdim		},
133200581Srdivacky		.mr_cache[10]	= {
134199989Srdivacky			.size	= 500,
135234353Sdim			.limit	= 250
136239462Sdim		},
137239462Sdim		.mr_cache[11]	= {
138239462Sdim			.size	= 500,
139199989Srdivacky			.limit	= 250
140199989Srdivacky		},
141202878Srdivacky		.mr_cache[12]	= {
142202878Srdivacky			.size	= 64,
143199989Srdivacky			.limit	= 32
144199989Srdivacky		},
145199989Srdivacky		.mr_cache[13]	= {
146199989Srdivacky			.size	= 32,
147200581Srdivacky			.limit	= 16
148200581Srdivacky		},
149200581Srdivacky		.mr_cache[14]	= {
150200581Srdivacky			.size	= 16,
151200581Srdivacky			.limit	= 8
152200581Srdivacky		},
153200581Srdivacky	},
154203954Srdivacky	[3] = {
155200581Srdivacky		.mask		= MLX5_PROF_MASK_QP_SIZE,
156200581Srdivacky		.log_max_qp	= 17,
157200581Srdivacky	},
158200581Srdivacky};
159200581Srdivacky
160200581Srdivackystatic int set_dma_caps(struct pci_dev *pdev)
161200581Srdivacky{
162200581Srdivacky	int err;
163200581Srdivacky
164200581Srdivacky	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
165200581Srdivacky	if (err) {
166200581Srdivacky		device_printf((&pdev->dev)->bsddev, "WARN: ""Warning: couldn't set 64-bit PCI DMA mask\n");
167200581Srdivacky		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
168202375Srdivacky		if (err) {
169202375Srdivacky			device_printf((&pdev->dev)->bsddev, "ERR: ""Can't set PCI DMA mask, aborting\n");
170200581Srdivacky			return err;
171200581Srdivacky		}
172200581Srdivacky	}
173200581Srdivacky
174200581Srdivacky	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
175200581Srdivacky	if (err) {
176200581Srdivacky		device_printf((&pdev->dev)->bsddev, "WARN: ""Warning: couldn't set 64-bit consistent PCI DMA mask\n");
177200581Srdivacky		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
178202375Srdivacky		if (err) {
179200581Srdivacky			device_printf((&pdev->dev)->bsddev, "ERR: ""Can't set consistent PCI DMA mask, aborting\n");
180202375Srdivacky			return err;
181200581Srdivacky		}
182223017Sdim	}
183200581Srdivacky
184200581Srdivacky	dma_set_max_seg_size(&pdev->dev, 2u * 1024 * 1024 * 1024);
185202375Srdivacky	return err;
186202375Srdivacky}
187200581Srdivacky
188200581Srdivackystatic int mlx5_pci_enable_device(struct mlx5_core_dev *dev)
189200581Srdivacky{
190200581Srdivacky	struct pci_dev *pdev = dev->pdev;
191200581Srdivacky	int err = 0;
192200581Srdivacky
193200581Srdivacky	mutex_lock(&dev->pci_status_mutex);
194200581Srdivacky	if (dev->pci_status == MLX5_PCI_STATUS_DISABLED) {
195224145Sdim		err = pci_enable_device(pdev);
196224145Sdim		if (!err)
197224145Sdim			dev->pci_status = MLX5_PCI_STATUS_ENABLED;
198224145Sdim	}
199224145Sdim	mutex_unlock(&dev->pci_status_mutex);
200224145Sdim
201224145Sdim	return err;
202224145Sdim}
203224145Sdim
204224145Sdimstatic void mlx5_pci_disable_device(struct mlx5_core_dev *dev)
205224145Sdim{
206224145Sdim	struct pci_dev *pdev = dev->pdev;
207224145Sdim
208224145Sdim	mutex_lock(&dev->pci_status_mutex);
209224145Sdim	if (dev->pci_status == MLX5_PCI_STATUS_ENABLED) {
210224145Sdim		pci_disable_device(pdev);
211224145Sdim		dev->pci_status = MLX5_PCI_STATUS_DISABLED;
212224145Sdim	}
213224145Sdim	mutex_unlock(&dev->pci_status_mutex);
214224145Sdim}
215224145Sdim
216224145Sdimstatic int request_bar(struct pci_dev *pdev)
217224145Sdim{
218224145Sdim	int err = 0;
219224145Sdim
220224145Sdim	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
221224145Sdim		device_printf((&pdev->dev)->bsddev, "ERR: ""Missing registers BAR, aborting\n");
222224145Sdim		return -ENODEV;
223224145Sdim	}
224224145Sdim
225224145Sdim	err = pci_request_regions(pdev, DRIVER_NAME);
226224145Sdim	if (err)
227224145Sdim		device_printf((&pdev->dev)->bsddev, "ERR: ""Couldn't get PCI resources, aborting\n");
228224145Sdim
229224145Sdim	return err;
230224145Sdim}
231224145Sdim
232224145Sdimstatic void release_bar(struct pci_dev *pdev)
233224145Sdim{
234224145Sdim	pci_release_regions(pdev);
235224145Sdim}
236224145Sdim
237224145Sdimstatic int mlx5_enable_msix(struct mlx5_core_dev *dev)
238224145Sdim{
239224145Sdim	struct mlx5_priv *priv = &dev->priv;
240224145Sdim	struct mlx5_eq_table *table = &priv->eq_table;
241224145Sdim	int num_eqs = 1 << MLX5_CAP_GEN(dev, log_max_eq);
242224145Sdim	int nvec;
243224145Sdim	int i;
244224145Sdim
245224145Sdim	nvec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() +
246224145Sdim	       MLX5_EQ_VEC_COMP_BASE;
247224145Sdim	nvec = min_t(int, nvec, num_eqs);
248224145Sdim	if (nvec <= MLX5_EQ_VEC_COMP_BASE)
249224145Sdim		return -ENOMEM;
250224145Sdim
251224145Sdim	priv->msix_arr = kzalloc(nvec * sizeof(*priv->msix_arr), GFP_KERNEL);
252224145Sdim
253224145Sdim	priv->irq_info = kzalloc(nvec * sizeof(*priv->irq_info), GFP_KERNEL);
254224145Sdim
255224145Sdim	for (i = 0; i < nvec; i++)
256224145Sdim		priv->msix_arr[i].entry = i;
257224145Sdim
258224145Sdim	nvec = pci_enable_msix_range(dev->pdev, priv->msix_arr,
259224145Sdim				     MLX5_EQ_VEC_COMP_BASE + 1, nvec);
260224145Sdim	if (nvec < 0)
261224145Sdim		return nvec;
262224145Sdim
263224145Sdim	table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
264224145Sdim
265224145Sdim	return 0;
266224145Sdim
267224145Sdim}
268224145Sdim
269224145Sdimstatic void mlx5_disable_msix(struct mlx5_core_dev *dev)
270224145Sdim{
271224145Sdim	struct mlx5_priv *priv = &dev->priv;
272224145Sdim
273224145Sdim	pci_disable_msix(dev->pdev);
274224145Sdim	kfree(priv->irq_info);
275224145Sdim	kfree(priv->msix_arr);
276224145Sdim}
277224145Sdim
278224145Sdimstruct mlx5_reg_host_endianess {
279224145Sdim	u8	he;
280224145Sdim	u8      rsvd[15];
281224145Sdim};
282224145Sdim
283224145Sdim
284239462Sdim#define CAP_MASK(pos, size) ((u64)((1 << (size)) - 1) << (pos))
285239462Sdim
286224145Sdimenum {
287224145Sdim	MLX5_CAP_BITS_RW_MASK = CAP_MASK(MLX5_CAP_OFF_CMDIF_CSUM, 2) |
288224145Sdim				MLX5_DEV_CAP_FLAG_DCT |
289224145Sdim				MLX5_DEV_CAP_FLAG_DRAIN_SIGERR,
290224145Sdim};
291224145Sdim
292224145Sdimstatic u16 to_fw_pkey_sz(u32 size)
293224145Sdim{
294224145Sdim	switch (size) {
295224145Sdim	case 128:
296224145Sdim		return 0;
297224145Sdim	case 256:
298199989Srdivacky		return 1;
299199989Srdivacky	case 512:
300199989Srdivacky		return 2;
301199989Srdivacky	case 1024:
302199989Srdivacky		return 3;
303199989Srdivacky	case 2048:
304200581Srdivacky		return 4;
305202375Srdivacky	case 4096:
306200581Srdivacky		return 5;
307200581Srdivacky	default:
308200581Srdivacky		printf("mlx5_core: WARN: ""invalid pkey table size %d\n", size);
309199989Srdivacky		return 0;
310199989Srdivacky	}
311199989Srdivacky}
312200581Srdivacky
313200581Srdivackystatic int mlx5_core_get_caps_mode(struct mlx5_core_dev *dev,
314200581Srdivacky				   enum mlx5_cap_type cap_type,
315224145Sdim				   enum mlx5_cap_mode cap_mode)
316199989Srdivacky{
317224145Sdim	u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)];
318224145Sdim	int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
319200581Srdivacky	void *out, *hca_caps;
320224145Sdim	u16 opmod = (cap_type << 1) | (cap_mode & 0x01);
321224145Sdim	int err;
322200581Srdivacky
323224145Sdim	memset(in, 0, sizeof(in));
324224145Sdim	out = kzalloc(out_sz, GFP_KERNEL);
325200581Srdivacky
326199989Srdivacky	MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
327199989Srdivacky	MLX5_SET(query_hca_cap_in, in, op_mod, opmod);
328199989Srdivacky	err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz);
329200581Srdivacky	if (err) {
330200581Srdivacky		mlx5_core_warn(dev,
331200581Srdivacky			       "QUERY_HCA_CAP : type(%x) opmode(%x) Failed(%d)\n",
332200581Srdivacky			       cap_type, cap_mode, err);
333200581Srdivacky		goto query_ex;
334224145Sdim	}
335224145Sdim
336200581Srdivacky	hca_caps =  MLX5_ADDR_OF(query_hca_cap_out, out, capability);
337200581Srdivacky
338200581Srdivacky	switch (cap_mode) {
339200581Srdivacky	case HCA_CAP_OPMOD_GET_MAX:
340200581Srdivacky		memcpy(dev->hca_caps_max[cap_type], hca_caps,
341200581Srdivacky		       MLX5_UN_SZ_BYTES(hca_cap_union));
342200581Srdivacky		break;
343200581Srdivacky	case HCA_CAP_OPMOD_GET_CUR:
344200581Srdivacky		memcpy(dev->hca_caps_cur[cap_type], hca_caps,
345200581Srdivacky		       MLX5_UN_SZ_BYTES(hca_cap_union));
346200581Srdivacky		break;
347200581Srdivacky	default:
348200581Srdivacky		mlx5_core_warn(dev,
349223017Sdim			       "Tried to query dev cap type(%x) with wrong opmode(%x)\n",
350223017Sdim			       cap_type, cap_mode);
351223017Sdim		err = -EINVAL;
352223017Sdim		break;
353223017Sdim	}
354223017Sdimquery_ex:
355223017Sdim	kfree(out);
356223017Sdim	return err;
357223017Sdim}
358223017Sdim
359223017Sdimint mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type)
360223017Sdim{
361223017Sdim	int ret;
362223017Sdim
363223017Sdim	ret = mlx5_core_get_caps_mode(dev, cap_type, HCA_CAP_OPMOD_GET_CUR);
364223017Sdim	if (ret)
365223017Sdim		return ret;
366223017Sdim
367200581Srdivacky	return mlx5_core_get_caps_mode(dev, cap_type, HCA_CAP_OPMOD_GET_MAX);
368200581Srdivacky}
369200581Srdivacky
370200581Srdivackystatic int set_caps(struct mlx5_core_dev *dev, void *in, int in_sz)
371200581Srdivacky{
372200581Srdivacky	u32 out[MLX5_ST_SZ_DW(set_hca_cap_out)] = {0};
373200581Srdivacky
374200581Srdivacky	MLX5_SET(set_hca_cap_in, in, opcode, MLX5_CMD_OP_SET_HCA_CAP);
375200581Srdivacky
376200581Srdivacky	return mlx5_cmd_exec(dev, in, in_sz, out, sizeof(out));
377200581Srdivacky}
378200581Srdivacky
379200581Srdivackystatic int handle_hca_cap(struct mlx5_core_dev *dev)
380200581Srdivacky{
381200581Srdivacky	void *set_ctx = NULL;
382200581Srdivacky	struct mlx5_profile *prof = dev->profile;
383200581Srdivacky	int err = -ENOMEM;
384200581Srdivacky	int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
385263508Sdim	void *set_hca_cap;
386263508Sdim
387263508Sdim	set_ctx = kzalloc(set_sz, GFP_KERNEL);
388263508Sdim
389263508Sdim	err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
390200581Srdivacky	if (err)
391200581Srdivacky		goto query_ex;
392200581Srdivacky
393200581Srdivacky	set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx,
394200581Srdivacky				   capability);
395200581Srdivacky	memcpy(set_hca_cap, dev->hca_caps_cur[MLX5_CAP_GENERAL],
396200581Srdivacky	       MLX5_ST_SZ_BYTES(cmd_hca_cap));
397200581Srdivacky
398200581Srdivacky	mlx5_core_dbg(dev, "Current Pkey table size %d Setting new size %d\n",
399200581Srdivacky		      mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)),
400200581Srdivacky		      128);
401223017Sdim	/* we limit the size of the pkey table to 128 entries for now */
402200581Srdivacky	MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size,
403200581Srdivacky		 to_fw_pkey_sz(128));
404223017Sdim
405223017Sdim	if (prof->mask & MLX5_PROF_MASK_QP_SIZE)
406223017Sdim		MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_qp,
407200581Srdivacky			 prof->log_max_qp);
408200581Srdivacky
409200581Srdivacky	/* disable cmdif checksum */
410200581Srdivacky	MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0);
411200581Srdivacky
412200581Srdivacky	/* enable drain sigerr */
413200581Srdivacky	MLX5_SET(cmd_hca_cap, set_hca_cap, drain_sigerr, 1);
414200581Srdivacky
415200581Srdivacky	MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12);
416200581Srdivacky
417200581Srdivacky	err = set_caps(dev, set_ctx, set_sz);
418200581Srdivacky
419200581Srdivackyquery_ex:
420223017Sdim	kfree(set_ctx);
421223017Sdim	return err;
422202375Srdivacky}
423200581Srdivacky
424200581Srdivackystatic int handle_hca_cap_atomic(struct mlx5_core_dev *dev)
425200581Srdivacky{
426200581Srdivacky	void *set_ctx;
427200581Srdivacky	void *set_hca_cap;
428218893Sdim	int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
429200581Srdivacky	int req_endianness;
430200581Srdivacky	int err;
431200581Srdivacky
432200581Srdivacky	if (MLX5_CAP_GEN(dev, atomic)) {
433200581Srdivacky		err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
434200581Srdivacky		if (err)
435223017Sdim			return err;
436200581Srdivacky	} else {
437200581Srdivacky		return 0;
438200581Srdivacky	}
439239462Sdim
440200581Srdivacky	req_endianness =
441239462Sdim		MLX5_CAP_ATOMIC(dev,
442239462Sdim				supported_atomic_req_8B_endianess_mode_1);
443200581Srdivacky
444200581Srdivacky	if (req_endianness != MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS)
445234353Sdim		return 0;
446200581Srdivacky
447200581Srdivacky	set_ctx = kzalloc(set_sz, GFP_KERNEL);
448200581Srdivacky	if (!set_ctx)
449200581Srdivacky		return -ENOMEM;
450200581Srdivacky
451200581Srdivacky	MLX5_SET(set_hca_cap_in, set_ctx, op_mod,
452200581Srdivacky		 MLX5_SET_HCA_CAP_OP_MOD_ATOMIC << 1);
453263508Sdim	set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability);
454200581Srdivacky
455200581Srdivacky	/* Set requestor to host endianness */
456200581Srdivacky	MLX5_SET(atomic_caps, set_hca_cap, atomic_req_8B_endianess_mode,
457200581Srdivacky		 MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS);
458200581Srdivacky
459200581Srdivacky	err = set_caps(dev, set_ctx, set_sz);
460203954Srdivacky
461200581Srdivacky	kfree(set_ctx);
462249423Sdim	return err;
463200581Srdivacky}
464200581Srdivacky
465200581Srdivackystatic int set_hca_ctrl(struct mlx5_core_dev *dev)
466200581Srdivacky{
467200581Srdivacky	struct mlx5_reg_host_endianess he_in;
468200581Srdivacky	struct mlx5_reg_host_endianess he_out;
469200581Srdivacky	int err;
470200581Srdivacky
471200581Srdivacky	if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH &&
472200581Srdivacky	    !MLX5_CAP_GEN(dev, roce))
473200581Srdivacky		return 0;
474200581Srdivacky
475200581Srdivacky	memset(&he_in, 0, sizeof(he_in));
476200581Srdivacky	he_in.he = MLX5_SET_HOST_ENDIANNESS;
477200581Srdivacky	err = mlx5_core_access_reg(dev, &he_in,  sizeof(he_in),
478200581Srdivacky					&he_out, sizeof(he_out),
479200581Srdivacky					MLX5_REG_HOST_ENDIANNESS, 0, 1);
480200581Srdivacky	return err;
481200581Srdivacky}
482200581Srdivacky
483200581Srdivackystatic int mlx5_core_enable_hca(struct mlx5_core_dev *dev)
484200581Srdivacky{
485200581Srdivacky	u32 out[MLX5_ST_SZ_DW(enable_hca_out)] = {0};
486203954Srdivacky	u32 in[MLX5_ST_SZ_DW(enable_hca_in)] = {0};
487203954Srdivacky
488203954Srdivacky	MLX5_SET(enable_hca_in, in, opcode, MLX5_CMD_OP_ENABLE_HCA);
489203954Srdivacky	return mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
490203954Srdivacky}
491203954Srdivacky
492200581Srdivackystatic int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
493200581Srdivacky{
494200581Srdivacky	u32 out[MLX5_ST_SZ_DW(disable_hca_out)] = {0};
495200581Srdivacky	u32 in[MLX5_ST_SZ_DW(disable_hca_in)] = {0};
496200581Srdivacky
497223017Sdim	MLX5_SET(disable_hca_in, in, opcode, MLX5_CMD_OP_DISABLE_HCA);
498223017Sdim	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
499223017Sdim}
500223017Sdim
501223017Sdimstatic int mlx5_core_set_issi(struct mlx5_core_dev *dev)
502223017Sdim{
503223017Sdim	u32 query_in[MLX5_ST_SZ_DW(query_issi_in)] = {0};
504200581Srdivacky	u32 query_out[MLX5_ST_SZ_DW(query_issi_out)] = {0};
505203954Srdivacky	u32 sup_issi;
506203954Srdivacky	int err;
507203954Srdivacky
508203954Srdivacky	MLX5_SET(query_issi_in, query_in, opcode, MLX5_CMD_OP_QUERY_ISSI);
509203954Srdivacky
510249423Sdim	err = mlx5_cmd_exec(dev, query_in, sizeof(query_in), query_out, sizeof(query_out));
511203954Srdivacky	if (err) {
512200581Srdivacky		u32 syndrome;
513200581Srdivacky		u8 status;
514200581Srdivacky
515200581Srdivacky		mlx5_cmd_mbox_status(query_out, &status, &syndrome);
516200581Srdivacky		if (status == MLX5_CMD_STAT_BAD_OP_ERR) {
517203954Srdivacky			pr_debug("Only ISSI 0 is supported\n");
518203954Srdivacky			return 0;
519203954Srdivacky		}
520203954Srdivacky
521203954Srdivacky		printf("mlx5_core: ERR: ""failed to query ISSI\n");
522249423Sdim		return err;
523203954Srdivacky	}
524200581Srdivacky
525200581Srdivacky	sup_issi = MLX5_GET(query_issi_out, query_out, supported_issi_dw0);
526203954Srdivacky
527203954Srdivacky	if (sup_issi & (1 << 1)) {
528203954Srdivacky		u32 set_in[MLX5_ST_SZ_DW(set_issi_in)]	 = {0};
529203954Srdivacky		u32 set_out[MLX5_ST_SZ_DW(set_issi_out)] = {0};
530200581Srdivacky
531200581Srdivacky		MLX5_SET(set_issi_in, set_in, opcode, MLX5_CMD_OP_SET_ISSI);
532200581Srdivacky		MLX5_SET(set_issi_in, set_in, current_issi, 1);
533200581Srdivacky
534223017Sdim		err = mlx5_cmd_exec(dev, set_in, sizeof(set_in), set_out, sizeof(set_out));
535200581Srdivacky		if (err) {
536223017Sdim			printf("mlx5_core: ERR: ""failed to set ISSI=1 err(%d)\n", err);
537224145Sdim			return err;
538223017Sdim		}
539223017Sdim
540223017Sdim		dev->issi = 1;
541223017Sdim
542223017Sdim		return 0;
543224145Sdim	} else if (sup_issi & (1 << 0)) {
544224145Sdim		return 0;
545224145Sdim	}
546224145Sdim
547223017Sdim	return -ENOTSUPP;
548199989Srdivacky}
549199989Srdivacky
550199989Srdivacky
551218893Sdimint mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn)
552249423Sdim{
553249423Sdim	struct mlx5_eq_table *table = &dev->priv.eq_table;
554202878Srdivacky	struct mlx5_eq *eq;
555202878Srdivacky	int err = -ENOENT;
556202878Srdivacky
557202878Srdivacky	spin_lock(&table->lock);
558224145Sdim	list_for_each_entry(eq, &table->comp_eqs_list, list) {
559224145Sdim		if (eq->index == vector) {
560224145Sdim			*eqn = eq->eqn;
561224145Sdim			*irqn = eq->irqn;
562224145Sdim			err = 0;
563224145Sdim			break;
564224145Sdim		}
565224145Sdim	}
566234353Sdim	spin_unlock(&table->lock);
567224145Sdim
568224145Sdim	return err;
569199989Srdivacky}
570199989SrdivackyEXPORT_SYMBOL(mlx5_vector2eqn);
571199989Srdivacky
572199989Srdivackyint mlx5_rename_eq(struct mlx5_core_dev *dev, int eq_ix, char *name)
573200581Srdivacky{
574234353Sdim	struct mlx5_priv *priv = &dev->priv;
575199989Srdivacky	struct mlx5_eq_table *table = &priv->eq_table;
576234353Sdim	struct mlx5_eq *eq;
577224145Sdim	int err = -ENOENT;
578224145Sdim
579200581Srdivacky	spin_lock(&table->lock);
580200581Srdivacky	list_for_each_entry(eq, &table->comp_eqs_list, list) {
581200581Srdivacky		if (eq->index == eq_ix) {
582234353Sdim			int irq_ix = eq_ix + MLX5_EQ_VEC_COMP_BASE;
583224145Sdim
584224145Sdim			snprintf(priv->irq_info[irq_ix].name, MLX5_MAX_IRQ_NAME,
585224145Sdim				 "%s-%d", name, eq_ix);
586224145Sdim
587224145Sdim			err = 0;
588234353Sdim			break;
589224145Sdim		}
590224145Sdim	}
591205407Srdivacky	spin_unlock(&table->lock);
592200581Srdivacky
593224145Sdim	return err;
594224145Sdim}
595224145Sdim
596199989Srdivackystatic void free_comp_eqs(struct mlx5_core_dev *dev)
597224145Sdim{
598224145Sdim	struct mlx5_eq_table *table = &dev->priv.eq_table;
599224145Sdim	struct mlx5_eq *eq, *n;
600224145Sdim
601224145Sdim	spin_lock(&table->lock);
602224145Sdim	list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) {
603224145Sdim		list_del(&eq->list);
604224145Sdim		spin_unlock(&table->lock);
605224145Sdim		if (mlx5_destroy_unmap_eq(dev, eq))
606224145Sdim			mlx5_core_warn(dev, "failed to destroy EQ 0x%x\n",
607224145Sdim				       eq->eqn);
608224145Sdim		kfree(eq);
609224145Sdim		spin_lock(&table->lock);
610224145Sdim	}
611224145Sdim	spin_unlock(&table->lock);
612224145Sdim}
613224145Sdim
614199989Srdivackystatic int alloc_comp_eqs(struct mlx5_core_dev *dev)
615224145Sdim{
616224145Sdim	struct mlx5_eq_table *table = &dev->priv.eq_table;
617224145Sdim	char name[MLX5_MAX_IRQ_NAME];
618224145Sdim	struct mlx5_eq *eq;
619224145Sdim	int ncomp_vec;
620224145Sdim	int nent;
621224145Sdim	int err;
622224145Sdim	int i;
623234353Sdim
624224145Sdim	INIT_LIST_HEAD(&table->comp_eqs_list);
625199989Srdivacky	ncomp_vec = table->num_comp_vectors;
626224145Sdim	nent = MLX5_COMP_EQ_SIZE;
627224145Sdim	for (i = 0; i < ncomp_vec; i++) {
628224145Sdim		eq = kzalloc(sizeof(*eq), GFP_KERNEL);
629224145Sdim
630224145Sdim		snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d", i);
631224145Sdim		err = mlx5_create_map_eq(dev, eq,
632224145Sdim					 i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
633224145Sdim					 name, &dev->priv.uuari.uars[0]);
634224145Sdim		if (err) {
635224145Sdim			kfree(eq);
636224145Sdim			goto clean;
637224145Sdim		}
638224145Sdim		mlx5_core_dbg(dev, "allocated completion EQN %d\n", eq->eqn);
639224145Sdim		eq->index = i;
640224145Sdim		spin_lock(&table->lock);
641224145Sdim		list_add_tail(&eq->list, &table->comp_eqs_list);
642224145Sdim		spin_unlock(&table->lock);
643224145Sdim	}
644224145Sdim
645224145Sdim	return 0;
646224145Sdim
647224145Sdimclean:
648224145Sdim	free_comp_eqs(dev);
649224145Sdim	return err;
650224145Sdim}
651224145Sdim
652224145Sdimstatic int map_bf_area(struct mlx5_core_dev *dev)
653224145Sdim{
654224145Sdim	resource_size_t bf_start = pci_resource_start(dev->pdev, 0);
655224145Sdim	resource_size_t bf_len = pci_resource_len(dev->pdev, 0);
656223017Sdim
657223017Sdim	dev->priv.bf_mapping = io_mapping_create_wc(bf_start, bf_len);
658223017Sdim
659224145Sdim	return dev->priv.bf_mapping ? 0 : -ENOMEM;
660224145Sdim}
661263508Sdim
662263508Sdimstatic void unmap_bf_area(struct mlx5_core_dev *dev)
663263508Sdim{
664224145Sdim	if (dev->priv.bf_mapping)
665224145Sdim		io_mapping_free(dev->priv.bf_mapping);
666224145Sdim}
667224145Sdim
668224145Sdimstatic inline int fw_initializing(struct mlx5_core_dev *dev)
669224145Sdim{
670224145Sdim	return ioread32be(&dev->iseg->initializing) >> 31;
671224145Sdim}
672224145Sdim
673224145Sdimstatic int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili)
674224145Sdim{
675224145Sdim	u64 end = jiffies + msecs_to_jiffies(max_wait_mili);
676224145Sdim	int err = 0;
677224145Sdim
678224145Sdim	while (fw_initializing(dev)) {
679224145Sdim		if (time_after(jiffies, end)) {
680224145Sdim			err = -EBUSY;
681224145Sdim			break;
682224145Sdim		}
683224145Sdim		msleep(FW_INIT_WAIT_MS);
684224145Sdim	}
685224145Sdim
686224145Sdim	return err;
687224145Sdim}
688224145Sdim
689224145Sdimstatic void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
690224145Sdim{
691224145Sdim	struct mlx5_device_context *dev_ctx;
692224145Sdim	struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv);
693224145Sdim
694224145Sdim	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
695224145Sdim	if (!dev_ctx)
696224145Sdim		return;
697224145Sdim
698224145Sdim	dev_ctx->intf    = intf;
699224145Sdim	CURVNET_SET_QUIET(vnet0);
700224145Sdim	dev_ctx->context = intf->add(dev);
701224145Sdim	CURVNET_RESTORE();
702224145Sdim
703224145Sdim	if (dev_ctx->context) {
704224145Sdim		spin_lock_irq(&priv->ctx_lock);
705224145Sdim		list_add_tail(&dev_ctx->list, &priv->ctx_list);
706224145Sdim		spin_unlock_irq(&priv->ctx_lock);
707224145Sdim	} else {
708224145Sdim		kfree(dev_ctx);
709224145Sdim	}
710224145Sdim}
711224145Sdim
712224145Sdimstatic void mlx5_remove_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
713224145Sdim{
714224145Sdim	struct mlx5_device_context *dev_ctx;
715224145Sdim	struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv);
716224145Sdim
717224145Sdim	list_for_each_entry(dev_ctx, &priv->ctx_list, list)
718224145Sdim		if (dev_ctx->intf == intf) {
719224145Sdim			spin_lock_irq(&priv->ctx_lock);
720224145Sdim			list_del(&dev_ctx->list);
721224145Sdim			spin_unlock_irq(&priv->ctx_lock);
722224145Sdim
723224145Sdim			intf->remove(dev, dev_ctx->context);
724224145Sdim			kfree(dev_ctx);
725224145Sdim			return;
726224145Sdim		}
727224145Sdim}
728224145Sdim
729224145Sdimstatic int mlx5_register_device(struct mlx5_core_dev *dev)
730224145Sdim{
731224145Sdim	struct mlx5_priv *priv = &dev->priv;
732224145Sdim	struct mlx5_interface *intf;
733224145Sdim
734224145Sdim	mutex_lock(&intf_mutex);
735223017Sdim	list_add_tail(&priv->dev_list, &dev_list);
736223017Sdim	list_for_each_entry(intf, &intf_list, list)
737223017Sdim		mlx5_add_device(intf, priv);
738224145Sdim	mutex_unlock(&intf_mutex);
739224145Sdim
740224145Sdim	return 0;
741263508Sdim}
742263508Sdim
743202375Srdivackystatic void mlx5_unregister_device(struct mlx5_core_dev *dev)
744200581Srdivacky{
745224145Sdim	struct mlx5_priv *priv = &dev->priv;
746224145Sdim	struct mlx5_interface *intf;
747224145Sdim
748224145Sdim	mutex_lock(&intf_mutex);
749224145Sdim	list_for_each_entry(intf, &intf_list, list)
750224145Sdim		mlx5_remove_device(intf, priv);
751199989Srdivacky	list_del(&priv->dev_list);
752199989Srdivacky	mutex_unlock(&intf_mutex);
753199989Srdivacky}
754199989Srdivacky
755200581Srdivackyint mlx5_register_interface(struct mlx5_interface *intf)
756200581Srdivacky{
757199989Srdivacky	struct mlx5_priv *priv;
758199989Srdivacky
759199989Srdivacky	if (!intf->add || !intf->remove)
760199989Srdivacky		return -EINVAL;
761199989Srdivacky
762199989Srdivacky	mutex_lock(&intf_mutex);
763223017Sdim	list_add_tail(&intf->list, &intf_list);
764223017Sdim	list_for_each_entry(priv, &dev_list, dev_list)
765223017Sdim		mlx5_add_device(intf, priv);
766199989Srdivacky	mutex_unlock(&intf_mutex);
767199989Srdivacky
768199989Srdivacky	return 0;
769199989Srdivacky}
770199989SrdivackyEXPORT_SYMBOL(mlx5_register_interface);
771199989Srdivacky
772199989Srdivackyvoid mlx5_unregister_interface(struct mlx5_interface *intf)
773199989Srdivacky{
774199989Srdivacky	struct mlx5_priv *priv;
775199989Srdivacky
776199989Srdivacky	mutex_lock(&intf_mutex);
777202375Srdivacky	list_for_each_entry(priv, &dev_list, dev_list)
778199989Srdivacky		mlx5_remove_device(intf, priv);
779199989Srdivacky	list_del(&intf->list);
780200581Srdivacky	mutex_unlock(&intf_mutex);
781200581Srdivacky}
782199989SrdivackyEXPORT_SYMBOL(mlx5_unregister_interface);
783199989Srdivacky
784200581Srdivackyvoid *mlx5_get_protocol_dev(struct mlx5_core_dev *mdev, int protocol)
785239462Sdim{
786239462Sdim	struct mlx5_priv *priv = &mdev->priv;
787239462Sdim	struct mlx5_device_context *dev_ctx;
788239462Sdim	unsigned long flags;
789239462Sdim	void *result = NULL;
790239462Sdim
791239462Sdim	spin_lock_irqsave(&priv->ctx_lock, flags);
792239462Sdim
793239462Sdim	list_for_each_entry(dev_ctx, &mdev->priv.ctx_list, list)
794239462Sdim		if ((dev_ctx->intf->protocol == protocol) &&
795239462Sdim		    dev_ctx->intf->get_dev) {
796239462Sdim			result = dev_ctx->intf->get_dev(dev_ctx->context);
797239462Sdim			break;
798239462Sdim		}
799239462Sdim
800239462Sdim	spin_unlock_irqrestore(&priv->ctx_lock, flags);
801239462Sdim
802199989Srdivacky	return result;
803200581Srdivacky}
804200581SrdivackyEXPORT_SYMBOL(mlx5_get_protocol_dev);
805234353Sdim
806234353Sdimstatic int mlx5_pci_init(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
807234353Sdim{
808234353Sdim	struct pci_dev *pdev = dev->pdev;
809200581Srdivacky	int err = 0;
810200581Srdivacky
811203954Srdivacky	pci_set_drvdata(dev->pdev, dev);
812200581Srdivacky	strncpy(priv->name, dev_name(&pdev->dev), MLX5_MAX_NAME_LEN);
813200581Srdivacky	priv->name[MLX5_MAX_NAME_LEN - 1] = 0;
814223017Sdim
815200581Srdivacky	mutex_init(&priv->pgdir_mutex);
816200581Srdivacky	INIT_LIST_HEAD(&priv->pgdir_list);
817200581Srdivacky	spin_lock_init(&priv->mkey_lock);
818223017Sdim
819200581Srdivacky	priv->numa_node = NUMA_NO_NODE;
820199989Srdivacky
821200581Srdivacky	err = mlx5_pci_enable_device(dev);
822200581Srdivacky	if (err) {
823210299Sed		device_printf((&pdev->dev)->bsddev, "ERR: ""Cannot enable PCI device, aborting\n");
824210299Sed		goto err_dbg;
825210299Sed	}
826200581Srdivacky
827224145Sdim	err = request_bar(pdev);
828224145Sdim	if (err) {
829224145Sdim		device_printf((&pdev->dev)->bsddev, "ERR: ""error requesting BARs, aborting\n");
830224145Sdim		goto err_disable;
831199989Srdivacky	}
832199989Srdivacky
833199989Srdivacky	pci_set_master(pdev);
834199989Srdivacky
835199989Srdivacky	err = set_dma_caps(pdev);
836199989Srdivacky	if (err) {
837199989Srdivacky		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed setting DMA capabilities mask, aborting\n");
838200581Srdivacky		goto err_clr_master;
839200581Srdivacky	}
840199989Srdivacky
841199989Srdivacky	dev->iseg_base = pci_resource_start(dev->pdev, 0);
842199989Srdivacky	dev->iseg = ioremap(dev->iseg_base, sizeof(*dev->iseg));
843199989Srdivacky	if (!dev->iseg) {
844199989Srdivacky		err = -ENOMEM;
845199989Srdivacky		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed mapping initialization segment, aborting\n");
846199989Srdivacky		goto err_clr_master;
847199989Srdivacky	}
848200581Srdivacky
849199989Srdivacky	if (mlx5_vsc_find_cap(dev))
850199989Srdivacky		dev_err(&pdev->dev, "Unable to find vendor specific capabilities\n");
851199989Srdivacky
852199989Srdivacky        return 0;
853234353Sdim
854223017Sdimerr_clr_master:
855223017Sdim	pci_clear_master(dev->pdev);
856199989Srdivacky	release_bar(dev->pdev);
857202375Srdivackyerr_disable:
858199989Srdivacky	mlx5_pci_disable_device(dev);
859200581Srdivackyerr_dbg:
860200581Srdivacky	return err;
861200581Srdivacky}
862200581Srdivacky
863200581Srdivackystatic void mlx5_pci_close(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
864203954Srdivacky{
865200581Srdivacky	iounmap(dev->iseg);
866200581Srdivacky	pci_clear_master(dev->pdev);
867200581Srdivacky	release_bar(dev->pdev);
868223017Sdim	mlx5_pci_disable_device(dev);
869200581Srdivacky}
870200581Srdivacky
871200581Srdivackystatic int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
872200581Srdivacky{
873200581Srdivacky	struct pci_dev *pdev = dev->pdev;
874200581Srdivacky	int err;
875200581Srdivacky
876200581Srdivacky	mlx5_vsec_init(dev);
877200581Srdivacky
878234353Sdim	err = mlx5_query_hca_caps(dev);
879223017Sdim	if (err) {
880200581Srdivacky		dev_err(&pdev->dev, "query hca failed\n");
881200581Srdivacky		goto out;
882200581Srdivacky	}
883200581Srdivacky
884210299Sed	err = mlx5_query_board_id(dev);
885210299Sed	if (err) {
886210299Sed		dev_err(&pdev->dev, "query board id failed\n");
887210299Sed		goto out;
888200581Srdivacky	}
889200581Srdivacky
890200581Srdivacky	err = mlx5_eq_init(dev);
891200581Srdivacky	if (err) {
892200581Srdivacky		dev_err(&pdev->dev, "failed to initialize eq\n");
893200581Srdivacky		goto out;
894200581Srdivacky	}
895200581Srdivacky
896200581Srdivacky	MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock);
897199989Srdivacky
898199989Srdivacky	err = mlx5_init_cq_table(dev);
899199989Srdivacky	if (err) {
900223017Sdim		dev_err(&pdev->dev, "failed to initialize cq table\n");
901223017Sdim		goto err_eq_cleanup;
902223017Sdim	}
903223017Sdim
904223017Sdim	mlx5_init_qp_table(dev);
905223017Sdim	mlx5_init_srq_table(dev);
906223017Sdim	mlx5_init_mr_table(dev);
907223017Sdim
908223017Sdim	return 0;
909223017Sdim
910223017Sdimerr_eq_cleanup:
911223017Sdim	mlx5_eq_cleanup(dev);
912223017Sdim
913223017Sdimout:
914223017Sdim	return err;
915223017Sdim}
916223017Sdim
917223017Sdimstatic void mlx5_cleanup_once(struct mlx5_core_dev *dev)
918223017Sdim{
919223017Sdim	mlx5_cleanup_mr_table(dev);
920223017Sdim	mlx5_cleanup_srq_table(dev);
921223017Sdim	mlx5_cleanup_qp_table(dev);
922223017Sdim	mlx5_cleanup_cq_table(dev);
923223017Sdim	mlx5_eq_cleanup(dev);
924223017Sdim}
925223017Sdim
926223017Sdimstatic int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
927223017Sdim			 bool boot)
928223017Sdim{
929223017Sdim	struct pci_dev *pdev = dev->pdev;
930223017Sdim	int err;
931223017Sdim
932223017Sdim	mutex_lock(&dev->intf_state_mutex);
933223017Sdim	if (test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) {
934223017Sdim		dev_warn(&dev->pdev->dev, "%s: interface is up, NOP\n",
935223017Sdim			 __func__);
936223017Sdim		goto out;
937223017Sdim	}
938223017Sdim
939223017Sdim	device_printf((&pdev->dev)->bsddev, "INFO: ""firmware version: %d.%d.%d\n", fw_rev_maj(dev), fw_rev_min(dev), fw_rev_sub(dev));
940223017Sdim
941223017Sdim	/*
942223017Sdim	 * On load removing any previous indication of internal error,
943223017Sdim	 * device is up
944223017Sdim	 */
945223017Sdim	dev->state = MLX5_DEVICE_STATE_UP;
946223017Sdim
947223017Sdim	err = mlx5_cmd_init(dev);
948223017Sdim	if (err) {
949223017Sdim		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed initializing command interface, aborting\n");
950223017Sdim		goto out_err;
951199989Srdivacky	}
952199989Srdivacky
953199989Srdivacky	err = wait_fw_init(dev, FW_INIT_TIMEOUT_MILI);
954199989Srdivacky	if (err) {
955199989Srdivacky		device_printf((&dev->pdev->dev)->bsddev, "ERR: ""Firmware over %d MS in initializing state, aborting\n", FW_INIT_TIMEOUT_MILI);
956199989Srdivacky		goto err_cmd_cleanup;
957199989Srdivacky	}
958202375Srdivacky
959199989Srdivacky	err = mlx5_core_enable_hca(dev);
960199989Srdivacky	if (err) {
961199989Srdivacky		device_printf((&pdev->dev)->bsddev, "ERR: ""enable hca failed\n");
962199989Srdivacky		goto err_cmd_cleanup;
963199989Srdivacky	}
964199989Srdivacky
965199989Srdivacky	err = mlx5_core_set_issi(dev);
966199989Srdivacky	if (err) {
967		device_printf((&pdev->dev)->bsddev, "ERR: ""failed to set issi\n");
968		goto err_disable_hca;
969	}
970
971	err = mlx5_pagealloc_start(dev);
972	if (err) {
973		device_printf((&pdev->dev)->bsddev, "ERR: ""mlx5_pagealloc_start failed\n");
974		goto err_disable_hca;
975	}
976
977	err = mlx5_satisfy_startup_pages(dev, 1);
978	if (err) {
979		device_printf((&pdev->dev)->bsddev, "ERR: ""failed to allocate boot pages\n");
980		goto err_pagealloc_stop;
981	}
982
983	err = set_hca_ctrl(dev);
984	if (err) {
985		device_printf((&pdev->dev)->bsddev, "ERR: ""set_hca_ctrl failed\n");
986		goto reclaim_boot_pages;
987	}
988
989	err = handle_hca_cap(dev);
990	if (err) {
991		device_printf((&pdev->dev)->bsddev, "ERR: ""handle_hca_cap failed\n");
992		goto reclaim_boot_pages;
993	}
994
995	err = handle_hca_cap_atomic(dev);
996	if (err) {
997		device_printf((&pdev->dev)->bsddev, "ERR: ""handle_hca_cap_atomic failed\n");
998		goto reclaim_boot_pages;
999	}
1000
1001	err = mlx5_satisfy_startup_pages(dev, 0);
1002	if (err) {
1003		device_printf((&pdev->dev)->bsddev, "ERR: ""failed to allocate init pages\n");
1004		goto reclaim_boot_pages;
1005	}
1006
1007	err = mlx5_cmd_init_hca(dev);
1008	if (err) {
1009		device_printf((&pdev->dev)->bsddev, "ERR: ""init hca failed\n");
1010		goto reclaim_boot_pages;
1011	}
1012
1013	mlx5_start_health_poll(dev);
1014
1015	if (boot && mlx5_init_once(dev, priv)) {
1016		dev_err(&pdev->dev, "sw objs init failed\n");
1017		goto err_stop_poll;
1018	}
1019
1020	err = mlx5_enable_msix(dev);
1021	if (err) {
1022		device_printf((&pdev->dev)->bsddev, "ERR: ""enable msix failed\n");
1023		goto err_cleanup_once;
1024	}
1025
1026	err = mlx5_alloc_uuars(dev, &priv->uuari);
1027	if (err) {
1028		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed allocating uar, aborting\n");
1029		goto err_disable_msix;
1030	}
1031
1032	err = mlx5_start_eqs(dev);
1033	if (err) {
1034		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed to start pages and async EQs\n");
1035		goto err_free_uar;
1036	}
1037
1038	err = alloc_comp_eqs(dev);
1039	if (err) {
1040		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed to alloc completion EQs\n");
1041		goto err_stop_eqs;
1042	}
1043
1044	if (map_bf_area(dev))
1045		device_printf((&pdev->dev)->bsddev, "ERR: ""Failed to map blue flame area\n");
1046
1047	err = mlx5_init_fs(dev);
1048	if (err) {
1049		mlx5_core_err(dev, "flow steering init %d\n", err);
1050		goto err_free_comp_eqs;
1051	}
1052
1053	err = mlx5_register_device(dev);
1054	if (err) {
1055		dev_err(&pdev->dev, "mlx5_register_device failed %d\n", err);
1056		goto err_fs;
1057	}
1058
1059	mlx5_fwdump_prep(dev);
1060
1061	clear_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state);
1062	set_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state);
1063
1064out:
1065	mutex_unlock(&dev->intf_state_mutex);
1066	return 0;
1067
1068err_fs:
1069	mlx5_cleanup_fs(dev);
1070
1071err_free_comp_eqs:
1072	free_comp_eqs(dev);
1073	unmap_bf_area(dev);
1074
1075err_stop_eqs:
1076	mlx5_stop_eqs(dev);
1077
1078err_free_uar:
1079	mlx5_free_uuars(dev, &priv->uuari);
1080
1081err_disable_msix:
1082	mlx5_disable_msix(dev);
1083
1084err_cleanup_once:
1085	if (boot)
1086		mlx5_cleanup_once(dev);
1087
1088err_stop_poll:
1089	mlx5_stop_health_poll(dev);
1090	if (mlx5_cmd_teardown_hca(dev)) {
1091		device_printf((&dev->pdev->dev)->bsddev, "ERR: ""tear_down_hca failed, skip cleanup\n");
1092		goto out_err;
1093	}
1094
1095reclaim_boot_pages:
1096	mlx5_reclaim_startup_pages(dev);
1097
1098err_pagealloc_stop:
1099	mlx5_pagealloc_stop(dev);
1100
1101err_disable_hca:
1102	mlx5_core_disable_hca(dev);
1103
1104err_cmd_cleanup:
1105	mlx5_cmd_cleanup(dev);
1106
1107out_err:
1108	dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
1109	mutex_unlock(&dev->intf_state_mutex);
1110
1111	return err;
1112}
1113
1114static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
1115			   bool cleanup)
1116{
1117	int err = 0;
1118
1119	if (cleanup)
1120		mlx5_drain_health_recovery(dev);
1121
1122	mutex_lock(&dev->intf_state_mutex);
1123	if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) {
1124		dev_warn(&dev->pdev->dev, "%s: interface is down, NOP\n", __func__);
1125                if (cleanup)
1126                        mlx5_cleanup_once(dev);
1127		goto out;
1128	}
1129
1130	mlx5_fwdump_clean(dev);
1131	mlx5_unregister_device(dev);
1132
1133	mlx5_cleanup_fs(dev);
1134	unmap_bf_area(dev);
1135	mlx5_wait_for_reclaim_vfs_pages(dev);
1136	free_comp_eqs(dev);
1137	mlx5_stop_eqs(dev);
1138	mlx5_free_uuars(dev, &priv->uuari);
1139	mlx5_disable_msix(dev);
1140        if (cleanup)
1141                mlx5_cleanup_once(dev);
1142	mlx5_stop_health_poll(dev);
1143	err = mlx5_cmd_teardown_hca(dev);
1144	if (err) {
1145		device_printf((&dev->pdev->dev)->bsddev, "ERR: ""tear_down_hca failed, skip cleanup\n");
1146		goto out;
1147	}
1148	mlx5_pagealloc_stop(dev);
1149	mlx5_reclaim_startup_pages(dev);
1150	mlx5_core_disable_hca(dev);
1151	mlx5_cmd_cleanup(dev);
1152
1153out:
1154	clear_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state);
1155	set_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state);
1156	mutex_unlock(&dev->intf_state_mutex);
1157	return err;
1158}
1159
1160void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
1161		     unsigned long param)
1162{
1163	struct mlx5_priv *priv = &dev->priv;
1164	struct mlx5_device_context *dev_ctx;
1165	unsigned long flags;
1166
1167	spin_lock_irqsave(&priv->ctx_lock, flags);
1168
1169	list_for_each_entry(dev_ctx, &priv->ctx_list, list)
1170		if (dev_ctx->intf->event)
1171			dev_ctx->intf->event(dev, dev_ctx->context, event, param);
1172
1173	spin_unlock_irqrestore(&priv->ctx_lock, flags);
1174}
1175
1176struct mlx5_core_event_handler {
1177	void (*event)(struct mlx5_core_dev *dev,
1178		      enum mlx5_dev_event event,
1179		      void *data);
1180};
1181
1182
1183static int init_one(struct pci_dev *pdev,
1184		    const struct pci_device_id *id)
1185{
1186	struct mlx5_core_dev *dev;
1187	struct mlx5_priv *priv;
1188	int err;
1189
1190	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1191	priv = &dev->priv;
1192	if (id)
1193		priv->pci_dev_data = id->driver_data;
1194
1195	if (prof_sel < 0 || prof_sel >= ARRAY_SIZE(profiles)) {
1196		printf("mlx5_core: WARN: ""selected profile out of range, selecting default (%d)\n", MLX5_DEFAULT_PROF);
1197		prof_sel = MLX5_DEFAULT_PROF;
1198	}
1199	dev->profile = &profiles[prof_sel];
1200	dev->pdev = pdev;
1201	dev->event = mlx5_core_event;
1202
1203	INIT_LIST_HEAD(&priv->ctx_list);
1204	spin_lock_init(&priv->ctx_lock);
1205        mutex_init(&dev->pci_status_mutex);
1206        mutex_init(&dev->intf_state_mutex);
1207	err = mlx5_pci_init(dev, priv);
1208	if (err) {
1209		device_printf((&pdev->dev)->bsddev, "ERR: ""mlx5_pci_init failed %d\n", err);
1210		goto clean_dev;
1211	}
1212
1213        err = mlx5_health_init(dev);
1214        if (err) {
1215                device_printf((&pdev->dev)->bsddev, "ERR: ""mlx5_health_init failed %d\n", err);
1216                goto close_pci;
1217        }
1218
1219	mlx5_pagealloc_init(dev);
1220
1221	err = mlx5_load_one(dev, priv, true);
1222	if (err) {
1223		device_printf((&pdev->dev)->bsddev, "ERR: ""mlx5_register_device failed %d\n", err);
1224		goto clean_health;
1225	}
1226
1227	return 0;
1228
1229clean_health:
1230	mlx5_pagealloc_cleanup(dev);
1231        mlx5_health_cleanup(dev);
1232close_pci:
1233        mlx5_pci_close(dev, priv);
1234clean_dev:
1235	kfree(dev);
1236	return err;
1237}
1238
1239static void remove_one(struct pci_dev *pdev)
1240{
1241	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
1242	struct mlx5_priv *priv = &dev->priv;
1243
1244	if (mlx5_unload_one(dev, priv, true)) {
1245		dev_err(&dev->pdev->dev, "mlx5_unload_one failed\n");
1246		mlx5_health_cleanup(dev);
1247		return;
1248	}
1249
1250	mlx5_pagealloc_cleanup(dev);
1251	mlx5_health_cleanup(dev);
1252	mlx5_pci_close(dev, priv);
1253	pci_set_drvdata(pdev, NULL);
1254	kfree(dev);
1255}
1256
1257static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
1258					      pci_channel_state_t state)
1259{
1260	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
1261	struct mlx5_priv *priv = &dev->priv;
1262
1263	dev_info(&pdev->dev, "%s was called\n", __func__);
1264	mlx5_enter_error_state(dev, false);
1265	mlx5_unload_one(dev, priv, false);
1266	if (state) {
1267		pci_save_state(pdev->dev.bsddev);
1268		mlx5_drain_health_wq(dev);
1269		mlx5_pci_disable_device(dev);
1270	}
1271
1272	return state == pci_channel_io_perm_failure ?
1273		PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
1274}
1275
1276static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
1277{
1278	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
1279	int err = 0;
1280
1281	dev_info(&pdev->dev, "%s was called\n", __func__);
1282
1283	err = mlx5_pci_enable_device(dev);
1284	if (err) {
1285		dev_err(&pdev->dev, "%s: mlx5_pci_enable_device failed with error code: %d\n"
1286			, __func__, err);
1287		return PCI_ERS_RESULT_DISCONNECT;
1288	}
1289	pci_set_master(pdev);
1290	pci_set_powerstate(pdev->dev.bsddev, PCI_POWERSTATE_D0);
1291	pci_restore_state(pdev->dev.bsddev);
1292
1293	return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
1294}
1295
1296/* wait for the device to show vital signs. For now we check
1297 * that we can read the device ID and that the health buffer
1298 * shows a non zero value which is different than 0xffffffff
1299 */
1300static void wait_vital(struct pci_dev *pdev)
1301{
1302	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
1303	struct mlx5_core_health *health = &dev->priv.health;
1304	const int niter = 100;
1305	u32 count;
1306	u16 did;
1307	int i;
1308
1309	/* Wait for firmware to be ready after reset */
1310	msleep(1000);
1311	for (i = 0; i < niter; i++) {
1312		if (pci_read_config_word(pdev, 2, &did)) {
1313			dev_warn(&pdev->dev, "failed reading config word\n");
1314			break;
1315		}
1316		if (did == pdev->device) {
1317			dev_info(&pdev->dev, "device ID correctly read after %d iterations\n", i);
1318			break;
1319		}
1320		msleep(50);
1321	}
1322	if (i == niter)
1323		dev_warn(&pdev->dev, "%s-%d: could not read device ID\n", __func__, __LINE__);
1324
1325	for (i = 0; i < niter; i++) {
1326		count = ioread32be(health->health_counter);
1327		if (count && count != 0xffffffff) {
1328			dev_info(&pdev->dev, "Counter value 0x%x after %d iterations\n", count, i);
1329			break;
1330		}
1331		msleep(50);
1332	}
1333
1334	if (i == niter)
1335		dev_warn(&pdev->dev, "%s-%d: could not read device ID\n", __func__, __LINE__);
1336}
1337
1338static void mlx5_pci_resume(struct pci_dev *pdev)
1339{
1340	struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
1341	struct mlx5_priv *priv = &dev->priv;
1342	int err;
1343
1344	dev_info(&pdev->dev, "%s was called\n", __func__);
1345
1346	pci_save_state(pdev->dev.bsddev);
1347	wait_vital(pdev);
1348
1349	err = mlx5_load_one(dev, priv, false);
1350	if (err)
1351		dev_err(&pdev->dev, "%s: mlx5_load_one failed with error code: %d\n"
1352			, __func__, err);
1353	else
1354		dev_info(&pdev->dev, "%s: device recovered\n", __func__);
1355}
1356
1357static const struct pci_error_handlers mlx5_err_handler = {
1358	.error_detected = mlx5_pci_err_detected,
1359	.slot_reset	= mlx5_pci_slot_reset,
1360	.resume		= mlx5_pci_resume
1361};
1362
1363static int mlx5_try_fast_unload(struct mlx5_core_dev *dev)
1364{
1365	int err;
1366
1367	if (!MLX5_CAP_GEN(dev, force_teardown)) {
1368		mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
1369		return -EOPNOTSUPP;
1370	}
1371
1372	if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
1373		mlx5_core_dbg(dev, "Device in internal error state, giving up\n");
1374		return -EAGAIN;
1375	}
1376
1377	err = mlx5_cmd_force_teardown_hca(dev);
1378	if (err) {
1379		mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", err);
1380		return err;
1381	}
1382
1383	mlx5_enter_error_state(dev, true);
1384
1385	return 0;
1386}
1387
1388static void shutdown_one(struct pci_dev *pdev)
1389{
1390	struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
1391	struct mlx5_priv *priv = &dev->priv;
1392	int err;
1393
1394	set_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &dev->intf_state);
1395	err = mlx5_try_fast_unload(dev);
1396	if (err)
1397	        mlx5_unload_one(dev, priv, false);
1398	mlx5_pci_disable_device(dev);
1399}
1400
1401static const struct pci_device_id mlx5_core_pci_table[] = {
1402	{ PCI_VDEVICE(MELLANOX, 4113) }, /* Connect-IB */
1403	{ PCI_VDEVICE(MELLANOX, 4114) }, /* Connect-IB VF */
1404	{ PCI_VDEVICE(MELLANOX, 4115) }, /* ConnectX-4 */
1405	{ PCI_VDEVICE(MELLANOX, 4116) }, /* ConnectX-4 VF */
1406	{ PCI_VDEVICE(MELLANOX, 4117) }, /* ConnectX-4LX */
1407	{ PCI_VDEVICE(MELLANOX, 4118) }, /* ConnectX-4LX VF */
1408	{ PCI_VDEVICE(MELLANOX, 4119) }, /* ConnectX-5 */
1409	{ PCI_VDEVICE(MELLANOX, 4120) }, /* ConnectX-5 VF */
1410	{ PCI_VDEVICE(MELLANOX, 4121) },
1411	{ PCI_VDEVICE(MELLANOX, 4122) },
1412	{ PCI_VDEVICE(MELLANOX, 4123) },
1413	{ PCI_VDEVICE(MELLANOX, 4124) },
1414	{ PCI_VDEVICE(MELLANOX, 4125) },
1415	{ PCI_VDEVICE(MELLANOX, 4126) },
1416	{ PCI_VDEVICE(MELLANOX, 4127) },
1417	{ PCI_VDEVICE(MELLANOX, 4128) },
1418	{ PCI_VDEVICE(MELLANOX, 4129) },
1419	{ PCI_VDEVICE(MELLANOX, 4130) },
1420	{ PCI_VDEVICE(MELLANOX, 4131) },
1421	{ PCI_VDEVICE(MELLANOX, 4132) },
1422	{ PCI_VDEVICE(MELLANOX, 4133) },
1423	{ PCI_VDEVICE(MELLANOX, 4134) },
1424	{ PCI_VDEVICE(MELLANOX, 4135) },
1425	{ PCI_VDEVICE(MELLANOX, 4136) },
1426	{ PCI_VDEVICE(MELLANOX, 4137) },
1427	{ PCI_VDEVICE(MELLANOX, 4138) },
1428	{ PCI_VDEVICE(MELLANOX, 4139) },
1429	{ PCI_VDEVICE(MELLANOX, 4140) },
1430	{ PCI_VDEVICE(MELLANOX, 4141) },
1431	{ PCI_VDEVICE(MELLANOX, 4142) },
1432	{ PCI_VDEVICE(MELLANOX, 4143) },
1433	{ PCI_VDEVICE(MELLANOX, 4144) },
1434	{ 0, }
1435};
1436
1437MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table);
1438
1439void mlx5_disable_device(struct mlx5_core_dev *dev)
1440{
1441	mlx5_pci_err_detected(dev->pdev, 0);
1442}
1443
1444void mlx5_recover_device(struct mlx5_core_dev *dev)
1445{
1446	mlx5_pci_disable_device(dev);
1447	if (mlx5_pci_slot_reset(dev->pdev) == PCI_ERS_RESULT_RECOVERED)
1448		mlx5_pci_resume(dev->pdev);
1449}
1450
1451struct pci_driver mlx5_core_driver = {
1452	.name           = DRIVER_NAME,
1453	.id_table       = mlx5_core_pci_table,
1454	.shutdown	= shutdown_one,
1455	.probe          = init_one,
1456	.remove         = remove_one,
1457	.err_handler	= &mlx5_err_handler
1458};
1459
1460static int __init init(void)
1461{
1462	int err;
1463
1464	err = pci_register_driver(&mlx5_core_driver);
1465	if (err)
1466		goto err_debug;
1467
1468	err = mlx5_fwdump_init();
1469	if (err)
1470		goto err_fwdump;
1471
1472 	return 0;
1473
1474err_fwdump:
1475	pci_unregister_driver(&mlx5_core_driver);
1476
1477err_debug:
1478	return err;
1479}
1480
1481static void __exit cleanup(void)
1482{
1483	mlx5_fwdump_fini();
1484	pci_unregister_driver(&mlx5_core_driver);
1485}
1486
1487module_init(init);
1488module_exit(cleanup);
1489