1 | /* |
---|---|
2 | * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. |
3 | * |
4 | * This software is available to you under a choice of one of two |
5 | * licenses. You may choose to be licensed under the terms of the GNU |
6 | * General Public License (GPL) Version 2, available from the file |
7 | * COPYING in the main directory of this source tree, or the |
8 | * OpenIB.org BSD license below: |
9 | * |
10 | * Redistribution and use in source and binary forms, with or |
11 | * without modification, are permitted provided that the following |
12 | * conditions are met: |
13 | * |
14 | * - Redistributions of source code must retain the above |
15 | * copyright notice, this list of conditions and the following |
16 | * disclaimer. |
17 | * |
18 | * - Redistributions in binary form must reproduce the above |
19 | * copyright notice, this list of conditions and the following |
20 | * disclaimer in the documentation and/or other materials |
21 | * provided with the distribution. |
22 | * |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
30 | * SOFTWARE. |
31 | */ |
32 | |
33 | #include <linux/highmem.h> |
34 | #include <linux/module.h> |
35 | #include <linux/init.h> |
36 | #include <linux/errno.h> |
37 | #include <linux/pci.h> |
38 | #include <linux/dma-mapping.h> |
39 | #include <linux/slab.h> |
40 | #include <linux/interrupt.h> |
41 | #include <linux/delay.h> |
42 | #include <linux/mlx5/driver.h> |
43 | #include <linux/mlx5/cq.h> |
44 | #include <linux/mlx5/qp.h> |
45 | #include <linux/debugfs.h> |
46 | #include <linux/kmod.h> |
47 | #include <linux/mlx5/mlx5_ifc.h> |
48 | #include <linux/mlx5/vport.h> |
49 | #include <linux/version.h> |
50 | #include <net/devlink.h> |
51 | #include "mlx5_core.h" |
52 | #include "lib/eq.h" |
53 | #include "fs_core.h" |
54 | #include "lib/mpfs.h" |
55 | #include "eswitch.h" |
56 | #include "devlink.h" |
57 | #include "fw_reset.h" |
58 | #include "lib/mlx5.h" |
59 | #include "lib/tout.h" |
60 | #include "fpga/core.h" |
61 | #include "en_accel/ipsec.h" |
62 | #include "lib/clock.h" |
63 | #include "lib/vxlan.h" |
64 | #include "lib/geneve.h" |
65 | #include "lib/devcom.h" |
66 | #include "lib/pci_vsc.h" |
67 | #include "diag/fw_tracer.h" |
68 | #include "ecpf.h" |
69 | #include "lib/hv_vhca.h" |
70 | #include "diag/rsc_dump.h" |
71 | #include "sf/vhca_event.h" |
72 | #include "sf/dev/dev.h" |
73 | #include "sf/sf.h" |
74 | #include "mlx5_irq.h" |
75 | #include "hwmon.h" |
76 | #include "lag/lag.h" |
77 | |
78 | MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); |
79 | MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver"); |
80 | MODULE_LICENSE("Dual BSD/GPL"); |
81 | |
82 | unsigned int mlx5_core_debug_mask; |
83 | module_param_named(debug_mask, mlx5_core_debug_mask, uint, 0644); |
84 | MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0"); |
85 | |
86 | static unsigned int prof_sel = MLX5_DEFAULT_PROF; |
87 | module_param_named(prof_sel, prof_sel, uint, 0444); |
88 | MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2"); |
89 | |
90 | static u32 sw_owner_id[4]; |
91 | #define MAX_SW_VHCA_ID (BIT(__mlx5_bit_sz(cmd_hca_cap_2, sw_vhca_id)) - 1) |
92 | static DEFINE_IDA(sw_vhca_ida); |
93 | |
94 | enum { |
95 | MLX5_ATOMIC_REQ_MODE_BE = 0x0, |
96 | MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS = 0x1, |
97 | }; |
98 | |
99 | #define LOG_MAX_SUPPORTED_QPS 0xff |
100 | |
101 | static struct mlx5_profile profile[] = { |
102 | [0] = { |
103 | .mask = 0, |
104 | .num_cmd_caches = MLX5_NUM_COMMAND_CACHES, |
105 | }, |
106 | [1] = { |
107 | .mask = MLX5_PROF_MASK_QP_SIZE, |
108 | .log_max_qp = 12, |
109 | .num_cmd_caches = MLX5_NUM_COMMAND_CACHES, |
110 | |
111 | }, |
112 | [2] = { |
113 | .mask = MLX5_PROF_MASK_QP_SIZE | |
114 | MLX5_PROF_MASK_MR_CACHE, |
115 | .log_max_qp = LOG_MAX_SUPPORTED_QPS, |
116 | .num_cmd_caches = MLX5_NUM_COMMAND_CACHES, |
117 | .mr_cache[0] = { |
118 | .size = 500, |
119 | .limit = 250 |
120 | }, |
121 | .mr_cache[1] = { |
122 | .size = 500, |
123 | .limit = 250 |
124 | }, |
125 | .mr_cache[2] = { |
126 | .size = 500, |
127 | .limit = 250 |
128 | }, |
129 | .mr_cache[3] = { |
130 | .size = 500, |
131 | .limit = 250 |
132 | }, |
133 | .mr_cache[4] = { |
134 | .size = 500, |
135 | .limit = 250 |
136 | }, |
137 | .mr_cache[5] = { |
138 | .size = 500, |
139 | .limit = 250 |
140 | }, |
141 | .mr_cache[6] = { |
142 | .size = 500, |
143 | .limit = 250 |
144 | }, |
145 | .mr_cache[7] = { |
146 | .size = 500, |
147 | .limit = 250 |
148 | }, |
149 | .mr_cache[8] = { |
150 | .size = 500, |
151 | .limit = 250 |
152 | }, |
153 | .mr_cache[9] = { |
154 | .size = 500, |
155 | .limit = 250 |
156 | }, |
157 | .mr_cache[10] = { |
158 | .size = 500, |
159 | .limit = 250 |
160 | }, |
161 | .mr_cache[11] = { |
162 | .size = 500, |
163 | .limit = 250 |
164 | }, |
165 | .mr_cache[12] = { |
166 | .size = 64, |
167 | .limit = 32 |
168 | }, |
169 | .mr_cache[13] = { |
170 | .size = 32, |
171 | .limit = 16 |
172 | }, |
173 | .mr_cache[14] = { |
174 | .size = 16, |
175 | .limit = 8 |
176 | }, |
177 | .mr_cache[15] = { |
178 | .size = 8, |
179 | .limit = 4 |
180 | }, |
181 | }, |
182 | [3] = { |
183 | .mask = MLX5_PROF_MASK_QP_SIZE, |
184 | .log_max_qp = LOG_MAX_SUPPORTED_QPS, |
185 | .num_cmd_caches = 0, |
186 | }, |
187 | }; |
188 | |
189 | static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili, |
190 | u32 warn_time_mili, const char *init_state) |
191 | { |
192 | unsigned long warn = jiffies + msecs_to_jiffies(m: warn_time_mili); |
193 | unsigned long end = jiffies + msecs_to_jiffies(m: max_wait_mili); |
194 | u32 fw_initializing; |
195 | |
196 | do { |
197 | fw_initializing = ioread32be(&dev->iseg->initializing); |
198 | if (!(fw_initializing >> 31)) |
199 | break; |
200 | if (time_after(jiffies, end)) { |
201 | mlx5_core_err(dev, "Firmware over %u MS in %s state, aborting\n", |
202 | max_wait_mili, init_state); |
203 | return -ETIMEDOUT; |
204 | } |
205 | if (test_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state)) { |
206 | mlx5_core_warn(dev, "device is being removed, stop waiting for FW %s\n", |
207 | init_state); |
208 | return -ENODEV; |
209 | } |
210 | if (warn_time_mili && time_after(jiffies, warn)) { |
211 | mlx5_core_warn(dev, "Waiting for FW %s, timeout abort in %ds (0x%x)\n", |
212 | init_state, jiffies_to_msecs(end - warn) / 1000, |
213 | fw_initializing); |
214 | warn = jiffies + msecs_to_jiffies(m: warn_time_mili); |
215 | } |
216 | msleep(mlx5_tout_ms(dev, FW_PRE_INIT_WAIT)); |
217 | } while (true); |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | static void mlx5_set_driver_version(struct mlx5_core_dev *dev) |
223 | { |
224 | int driver_ver_sz = MLX5_FLD_SZ_BYTES(set_driver_version_in, |
225 | driver_version); |
226 | u8 in[MLX5_ST_SZ_BYTES(set_driver_version_in)] = {}; |
227 | char *string; |
228 | |
229 | if (!MLX5_CAP_GEN(dev, driver_version)) |
230 | return; |
231 | |
232 | string = MLX5_ADDR_OF(set_driver_version_in, in, driver_version); |
233 | |
234 | snprintf(buf: string, size: driver_ver_sz, fmt: "Linux,%s,%u.%u.%u", |
235 | KBUILD_MODNAME, LINUX_VERSION_MAJOR, |
236 | LINUX_VERSION_PATCHLEVEL, LINUX_VERSION_SUBLEVEL); |
237 | |
238 | /*Send the command*/ |
239 | MLX5_SET(set_driver_version_in, in, opcode, |
240 | MLX5_CMD_OP_SET_DRIVER_VERSION); |
241 | |
242 | mlx5_cmd_exec_in(dev, set_driver_version, in); |
243 | } |
244 | |
245 | static int set_dma_caps(struct pci_dev *pdev) |
246 | { |
247 | int err; |
248 | |
249 | err = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
250 | if (err) { |
251 | dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask\n"); |
252 | err = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(32)); |
253 | if (err) { |
254 | dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting\n"); |
255 | return err; |
256 | } |
257 | } |
258 | |
259 | dma_set_max_seg_size(dev: &pdev->dev, size: 2u * 1024 * 1024 * 1024); |
260 | return err; |
261 | } |
262 | |
263 | static int mlx5_pci_enable_device(struct mlx5_core_dev *dev) |
264 | { |
265 | struct pci_dev *pdev = dev->pdev; |
266 | int err = 0; |
267 | |
268 | mutex_lock(&dev->pci_status_mutex); |
269 | if (dev->pci_status == MLX5_PCI_STATUS_DISABLED) { |
270 | err = pci_enable_device(dev: pdev); |
271 | if (!err) |
272 | dev->pci_status = MLX5_PCI_STATUS_ENABLED; |
273 | } |
274 | mutex_unlock(lock: &dev->pci_status_mutex); |
275 | |
276 | return err; |
277 | } |
278 | |
279 | static void mlx5_pci_disable_device(struct mlx5_core_dev *dev) |
280 | { |
281 | struct pci_dev *pdev = dev->pdev; |
282 | |
283 | mutex_lock(&dev->pci_status_mutex); |
284 | if (dev->pci_status == MLX5_PCI_STATUS_ENABLED) { |
285 | pci_disable_device(dev: pdev); |
286 | dev->pci_status = MLX5_PCI_STATUS_DISABLED; |
287 | } |
288 | mutex_unlock(lock: &dev->pci_status_mutex); |
289 | } |
290 | |
291 | static int request_bar(struct pci_dev *pdev) |
292 | { |
293 | int err = 0; |
294 | |
295 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { |
296 | dev_err(&pdev->dev, "Missing registers BAR, aborting\n"); |
297 | return -ENODEV; |
298 | } |
299 | |
300 | err = pci_request_regions(pdev, KBUILD_MODNAME); |
301 | if (err) |
302 | dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n"); |
303 | |
304 | return err; |
305 | } |
306 | |
307 | static void release_bar(struct pci_dev *pdev) |
308 | { |
309 | pci_release_regions(pdev); |
310 | } |
311 | |
312 | struct mlx5_reg_host_endianness { |
313 | u8 he; |
314 | u8 rsvd[15]; |
315 | }; |
316 | |
317 | static u16 to_fw_pkey_sz(struct mlx5_core_dev *dev, u32 size) |
318 | { |
319 | switch (size) { |
320 | case 128: |
321 | return 0; |
322 | case 256: |
323 | return 1; |
324 | case 512: |
325 | return 2; |
326 | case 1024: |
327 | return 3; |
328 | case 2048: |
329 | return 4; |
330 | case 4096: |
331 | return 5; |
332 | default: |
333 | mlx5_core_warn(dev, "invalid pkey table size %d\n", size); |
334 | return 0; |
335 | } |
336 | } |
337 | |
338 | void mlx5_core_uplink_netdev_set(struct mlx5_core_dev *dev, struct net_device *netdev) |
339 | { |
340 | mutex_lock(&dev->mlx5e_res.uplink_netdev_lock); |
341 | dev->mlx5e_res.uplink_netdev = netdev; |
342 | mlx5_blocking_notifier_call_chain(dev, event: MLX5_DRIVER_EVENT_UPLINK_NETDEV, |
343 | data: netdev); |
344 | mutex_unlock(lock: &dev->mlx5e_res.uplink_netdev_lock); |
345 | } |
346 | |
347 | void mlx5_core_uplink_netdev_event_replay(struct mlx5_core_dev *dev) |
348 | { |
349 | mutex_lock(&dev->mlx5e_res.uplink_netdev_lock); |
350 | mlx5_blocking_notifier_call_chain(dev, event: MLX5_DRIVER_EVENT_UPLINK_NETDEV, |
351 | data: dev->mlx5e_res.uplink_netdev); |
352 | mutex_unlock(lock: &dev->mlx5e_res.uplink_netdev_lock); |
353 | } |
354 | EXPORT_SYMBOL(mlx5_core_uplink_netdev_event_replay); |
355 | |
356 | void mlx5_core_mp_event_replay(struct mlx5_core_dev *dev, u32 event, void *data) |
357 | { |
358 | mlx5_blocking_notifier_call_chain(dev, event, data); |
359 | } |
360 | EXPORT_SYMBOL(mlx5_core_mp_event_replay); |
361 | |
362 | int mlx5_core_get_caps_mode(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type, |
363 | enum mlx5_cap_mode cap_mode) |
364 | { |
365 | u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)]; |
366 | int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); |
367 | void *out, *hca_caps; |
368 | u16 opmod = (cap_type << 1) | (cap_mode & 0x01); |
369 | int err; |
370 | |
371 | if (WARN_ON(!dev->caps.hca[cap_type])) |
372 | /* this cap_type must be added to mlx5_hca_caps_alloc() */ |
373 | return -EINVAL; |
374 | |
375 | memset(in, 0, sizeof(in)); |
376 | out = kzalloc(out_sz, GFP_KERNEL); |
377 | if (!out) |
378 | return -ENOMEM; |
379 | |
380 | MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); |
381 | MLX5_SET(query_hca_cap_in, in, op_mod, opmod); |
382 | err = mlx5_cmd_exec_inout(dev, query_hca_cap, in, out); |
383 | if (err) { |
384 | mlx5_core_warn(dev, |
385 | "QUERY_HCA_CAP : type(%x) opmode(%x) Failed(%d)\n", |
386 | cap_type, cap_mode, err); |
387 | goto query_ex; |
388 | } |
389 | |
390 | hca_caps = MLX5_ADDR_OF(query_hca_cap_out, out, capability); |
391 | |
392 | switch (cap_mode) { |
393 | case HCA_CAP_OPMOD_GET_MAX: |
394 | memcpy(dev->caps.hca[cap_type]->max, hca_caps, |
395 | MLX5_UN_SZ_BYTES(hca_cap_union)); |
396 | break; |
397 | case HCA_CAP_OPMOD_GET_CUR: |
398 | memcpy(dev->caps.hca[cap_type]->cur, hca_caps, |
399 | MLX5_UN_SZ_BYTES(hca_cap_union)); |
400 | break; |
401 | default: |
402 | mlx5_core_warn(dev, |
403 | "Tried to query dev cap type(%x) with wrong opmode(%x)\n", |
404 | cap_type, cap_mode); |
405 | err = -EINVAL; |
406 | break; |
407 | } |
408 | query_ex: |
409 | kfree(objp: out); |
410 | return err; |
411 | } |
412 | |
413 | int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type) |
414 | { |
415 | int ret; |
416 | |
417 | ret = mlx5_core_get_caps_mode(dev, cap_type, cap_mode: HCA_CAP_OPMOD_GET_CUR); |
418 | if (ret) |
419 | return ret; |
420 | return mlx5_core_get_caps_mode(dev, cap_type, cap_mode: HCA_CAP_OPMOD_GET_MAX); |
421 | } |
422 | |
423 | static int set_caps(struct mlx5_core_dev *dev, void *in, int opmod) |
424 | { |
425 | MLX5_SET(set_hca_cap_in, in, opcode, MLX5_CMD_OP_SET_HCA_CAP); |
426 | MLX5_SET(set_hca_cap_in, in, op_mod, opmod << 1); |
427 | return mlx5_cmd_exec_in(dev, set_hca_cap, in); |
428 | } |
429 | |
430 | static int handle_hca_cap_atomic(struct mlx5_core_dev *dev, void *set_ctx) |
431 | { |
432 | void *set_hca_cap; |
433 | int req_endianness; |
434 | int err; |
435 | |
436 | if (!MLX5_CAP_GEN(dev, atomic)) |
437 | return 0; |
438 | |
439 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_ATOMIC); |
440 | if (err) |
441 | return err; |
442 | |
443 | req_endianness = |
444 | MLX5_CAP_ATOMIC(dev, |
445 | supported_atomic_req_8B_endianness_mode_1); |
446 | |
447 | if (req_endianness != MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS) |
448 | return 0; |
449 | |
450 | set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); |
451 | |
452 | /* Set requestor to host endianness */ |
453 | MLX5_SET(atomic_caps, set_hca_cap, atomic_req_8B_endianness_mode, |
454 | MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS); |
455 | |
456 | return set_caps(dev, in: set_ctx, opmod: MLX5_SET_HCA_CAP_OP_MOD_ATOMIC); |
457 | } |
458 | |
459 | static int handle_hca_cap_odp(struct mlx5_core_dev *dev, void *set_ctx) |
460 | { |
461 | bool do_set = false, mem_page_fault = false; |
462 | void *set_hca_cap; |
463 | int err; |
464 | |
465 | if (!IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) || |
466 | !MLX5_CAP_GEN(dev, pg)) |
467 | return 0; |
468 | |
469 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_ODP); |
470 | if (err) |
471 | return err; |
472 | |
473 | set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); |
474 | memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_ODP]->cur, |
475 | MLX5_ST_SZ_BYTES(odp_cap)); |
476 | |
477 | /* For best performance, enable memory scheme ODP only when |
478 | * it has page prefetch enabled. |
479 | */ |
480 | if (MLX5_CAP_ODP_MAX(dev, mem_page_fault) && |
481 | MLX5_CAP_ODP_MAX(dev, memory_page_fault_scheme_cap.page_prefetch)) { |
482 | mem_page_fault = true; |
483 | do_set = true; |
484 | MLX5_SET(odp_cap, set_hca_cap, mem_page_fault, mem_page_fault); |
485 | goto set; |
486 | } |
487 | |
488 | #define ODP_CAP_SET_MAX(dev, field) \ |
489 | do { \ |
490 | u32 _res = MLX5_CAP_ODP_MAX(dev, field); \ |
491 | if (_res) { \ |
492 | do_set = true; \ |
493 | MLX5_SET(odp_cap, set_hca_cap, field, _res); \ |
494 | } \ |
495 | } while (0) |
496 | |
497 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.ud_odp_caps.srq_receive); |
498 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.rc_odp_caps.srq_receive); |
499 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.xrc_odp_caps.srq_receive); |
500 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.xrc_odp_caps.send); |
501 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.xrc_odp_caps.receive); |
502 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.xrc_odp_caps.write); |
503 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.xrc_odp_caps.read); |
504 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.xrc_odp_caps.atomic); |
505 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.dc_odp_caps.srq_receive); |
506 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.dc_odp_caps.send); |
507 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.dc_odp_caps.receive); |
508 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.dc_odp_caps.write); |
509 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.dc_odp_caps.read); |
510 | ODP_CAP_SET_MAX(dev, transport_page_fault_scheme_cap.dc_odp_caps.atomic); |
511 | |
512 | set: |
513 | if (do_set) |
514 | err = set_caps(dev, in: set_ctx, opmod: MLX5_SET_HCA_CAP_OP_MOD_ODP); |
515 | |
516 | mlx5_core_dbg(dev, "Using ODP %s scheme\n", |
517 | mem_page_fault ? "memory": "transport"); |
518 | return err; |
519 | } |
520 | |
521 | static int max_uc_list_get_devlink_param(struct mlx5_core_dev *dev) |
522 | { |
523 | struct devlink *devlink = priv_to_devlink(priv: dev); |
524 | union devlink_param_value val; |
525 | int err; |
526 | |
527 | err = devl_param_driverinit_value_get(devlink, |
528 | param_id: DEVLINK_PARAM_GENERIC_ID_MAX_MACS, |
529 | val: &val); |
530 | if (!err) |
531 | return val.vu32; |
532 | mlx5_core_dbg(dev, "Failed to get param. err = %d\n", err); |
533 | return err; |
534 | } |
535 | |
536 | bool mlx5_is_roce_on(struct mlx5_core_dev *dev) |
537 | { |
538 | struct devlink *devlink = priv_to_devlink(priv: dev); |
539 | union devlink_param_value val; |
540 | int err; |
541 | |
542 | err = devl_param_driverinit_value_get(devlink, |
543 | param_id: DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, |
544 | val: &val); |
545 | |
546 | if (!err) |
547 | return val.vbool; |
548 | |
549 | mlx5_core_dbg(dev, "Failed to get param. err = %d\n", err); |
550 | return MLX5_CAP_GEN(dev, roce); |
551 | } |
552 | EXPORT_SYMBOL(mlx5_is_roce_on); |
553 | |
554 | static int handle_hca_cap_2(struct mlx5_core_dev *dev, void *set_ctx) |
555 | { |
556 | void *set_hca_cap; |
557 | int err; |
558 | |
559 | if (!MLX5_CAP_GEN_MAX(dev, hca_cap_2)) |
560 | return 0; |
561 | |
562 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_GENERAL_2); |
563 | if (err) |
564 | return err; |
565 | |
566 | if (!MLX5_CAP_GEN_2_MAX(dev, sw_vhca_id_valid) || |
567 | !(dev->priv.sw_vhca_id > 0)) |
568 | return 0; |
569 | |
570 | set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, |
571 | capability); |
572 | memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_GENERAL_2]->cur, |
573 | MLX5_ST_SZ_BYTES(cmd_hca_cap_2)); |
574 | MLX5_SET(cmd_hca_cap_2, set_hca_cap, sw_vhca_id_valid, 1); |
575 | |
576 | return set_caps(dev, in: set_ctx, opmod: MLX5_CAP_GENERAL_2); |
577 | } |
578 | |
579 | static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) |
580 | { |
581 | struct mlx5_profile *prof = &dev->profile; |
582 | void *set_hca_cap; |
583 | int max_uc_list; |
584 | int err; |
585 | |
586 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_GENERAL); |
587 | if (err) |
588 | return err; |
589 | |
590 | set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, |
591 | capability); |
592 | memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_GENERAL]->cur, |
593 | MLX5_ST_SZ_BYTES(cmd_hca_cap)); |
594 | |
595 | mlx5_core_dbg(dev, "Current Pkey table size %d Setting new size %d\n", |
596 | mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)), |
597 | 128); |
598 | /* we limit the size of the pkey table to 128 entries for now */ |
599 | MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size, |
600 | to_fw_pkey_sz(dev, 128)); |
601 | |
602 | /* Check log_max_qp from HCA caps to set in current profile */ |
603 | if (prof->log_max_qp == LOG_MAX_SUPPORTED_QPS) { |
604 | prof->log_max_qp = min_t(u8, 18, MLX5_CAP_GEN_MAX(dev, log_max_qp)); |
605 | } else if (MLX5_CAP_GEN_MAX(dev, log_max_qp) < prof->log_max_qp) { |
606 | mlx5_core_warn(dev, "log_max_qp value in current profile is %d, changing it to HCA capability limit (%d)\n", |
607 | prof->log_max_qp, |
608 | MLX5_CAP_GEN_MAX(dev, log_max_qp)); |
609 | prof->log_max_qp = MLX5_CAP_GEN_MAX(dev, log_max_qp); |
610 | } |
611 | if (prof->mask & MLX5_PROF_MASK_QP_SIZE) |
612 | MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_qp, |
613 | prof->log_max_qp); |
614 | |
615 | /* disable cmdif checksum */ |
616 | MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0); |
617 | |
618 | /* Enable 4K UAR only when HCA supports it and page size is bigger |
619 | * than 4K. |
620 | */ |
621 | if (MLX5_CAP_GEN_MAX(dev, uar_4k) && PAGE_SIZE > 4096) |
622 | MLX5_SET(cmd_hca_cap, set_hca_cap, uar_4k, 1); |
623 | |
624 | MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12); |
625 | |
626 | if (MLX5_CAP_GEN_MAX(dev, cache_line_128byte)) |
627 | MLX5_SET(cmd_hca_cap, |
628 | set_hca_cap, |
629 | cache_line_128byte, |
630 | cache_line_size() >= 128 ? 1 : 0); |
631 | |
632 | if (MLX5_CAP_GEN_MAX(dev, dct)) |
633 | MLX5_SET(cmd_hca_cap, set_hca_cap, dct, 1); |
634 | |
635 | if (MLX5_CAP_GEN_MAX(dev, pci_sync_for_fw_update_event)) |
636 | MLX5_SET(cmd_hca_cap, set_hca_cap, pci_sync_for_fw_update_event, 1); |
637 | if (MLX5_CAP_GEN_MAX(dev, pci_sync_for_fw_update_with_driver_unload)) |
638 | MLX5_SET(cmd_hca_cap, set_hca_cap, |
639 | pci_sync_for_fw_update_with_driver_unload, 1); |
640 | if (MLX5_CAP_GEN_MAX(dev, pcie_reset_using_hotreset_method)) |
641 | MLX5_SET(cmd_hca_cap, set_hca_cap, |
642 | pcie_reset_using_hotreset_method, 1); |
643 | |
644 | if (MLX5_CAP_GEN_MAX(dev, num_vhca_ports)) |
645 | MLX5_SET(cmd_hca_cap, |
646 | set_hca_cap, |
647 | num_vhca_ports, |
648 | MLX5_CAP_GEN_MAX(dev, num_vhca_ports)); |
649 | |
650 | if (MLX5_CAP_GEN_MAX(dev, release_all_pages)) |
651 | MLX5_SET(cmd_hca_cap, set_hca_cap, release_all_pages, 1); |
652 | |
653 | if (MLX5_CAP_GEN_MAX(dev, mkey_by_name)) |
654 | MLX5_SET(cmd_hca_cap, set_hca_cap, mkey_by_name, 1); |
655 | |
656 | mlx5_vhca_state_cap_handle(dev, set_hca_cap); |
657 | |
658 | if (MLX5_CAP_GEN_MAX(dev, num_total_dynamic_vf_msix)) |
659 | MLX5_SET(cmd_hca_cap, set_hca_cap, num_total_dynamic_vf_msix, |
660 | MLX5_CAP_GEN_MAX(dev, num_total_dynamic_vf_msix)); |
661 | |
662 | if (MLX5_CAP_GEN(dev, roce_rw_supported) && MLX5_CAP_GEN_MAX(dev, roce)) |
663 | MLX5_SET(cmd_hca_cap, set_hca_cap, roce, |
664 | mlx5_is_roce_on(dev)); |
665 | |
666 | max_uc_list = max_uc_list_get_devlink_param(dev); |
667 | if (max_uc_list > 0) |
668 | MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_current_uc_list, |
669 | ilog2(max_uc_list)); |
670 | |
671 | /* enable absolute native port num */ |
672 | if (MLX5_CAP_GEN_MAX(dev, abs_native_port_num)) |
673 | MLX5_SET(cmd_hca_cap, set_hca_cap, abs_native_port_num, 1); |
674 | |
675 | return set_caps(dev, in: set_ctx, opmod: MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE); |
676 | } |
677 | |
678 | /* Cached MLX5_CAP_GEN(dev, roce) can be out of sync this early in the |
679 | * boot process. |
680 | * In case RoCE cap is writable in FW and user/devlink requested to change the |
681 | * cap, we are yet to query the final state of the above cap. |
682 | * Hence, the need for this function. |
683 | * |
684 | * Returns |
685 | * True: |
686 | * 1) RoCE cap is read only in FW and already disabled |
687 | * OR: |
688 | * 2) RoCE cap is writable in FW and user/devlink requested it off. |
689 | * |
690 | * In any other case, return False. |
691 | */ |
692 | static bool is_roce_fw_disabled(struct mlx5_core_dev *dev) |
693 | { |
694 | return (MLX5_CAP_GEN(dev, roce_rw_supported) && !mlx5_is_roce_on(dev)) || |
695 | (!MLX5_CAP_GEN(dev, roce_rw_supported) && !MLX5_CAP_GEN(dev, roce)); |
696 | } |
697 | |
698 | static int handle_hca_cap_roce(struct mlx5_core_dev *dev, void *set_ctx) |
699 | { |
700 | void *set_hca_cap; |
701 | int err; |
702 | |
703 | if (is_roce_fw_disabled(dev)) |
704 | return 0; |
705 | |
706 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_ROCE); |
707 | if (err) |
708 | return err; |
709 | |
710 | if (MLX5_CAP_ROCE(dev, sw_r_roce_src_udp_port) || |
711 | !MLX5_CAP_ROCE_MAX(dev, sw_r_roce_src_udp_port)) |
712 | return 0; |
713 | |
714 | set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); |
715 | memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_ROCE]->cur, |
716 | MLX5_ST_SZ_BYTES(roce_cap)); |
717 | MLX5_SET(roce_cap, set_hca_cap, sw_r_roce_src_udp_port, 1); |
718 | |
719 | if (MLX5_CAP_ROCE_MAX(dev, qp_ooo_transmit_default)) |
720 | MLX5_SET(roce_cap, set_hca_cap, qp_ooo_transmit_default, 1); |
721 | |
722 | err = set_caps(dev, in: set_ctx, opmod: MLX5_SET_HCA_CAP_OP_MOD_ROCE); |
723 | return err; |
724 | } |
725 | |
726 | static int handle_hca_cap_port_selection(struct mlx5_core_dev *dev, |
727 | void *set_ctx) |
728 | { |
729 | void *set_hca_cap; |
730 | int err; |
731 | |
732 | if (!MLX5_CAP_GEN(dev, port_selection_cap)) |
733 | return 0; |
734 | |
735 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_PORT_SELECTION); |
736 | if (err) |
737 | return err; |
738 | |
739 | if (MLX5_CAP_PORT_SELECTION(dev, port_select_flow_table_bypass) || |
740 | !MLX5_CAP_PORT_SELECTION_MAX(dev, port_select_flow_table_bypass)) |
741 | return 0; |
742 | |
743 | set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); |
744 | memcpy(set_hca_cap, dev->caps.hca[MLX5_CAP_PORT_SELECTION]->cur, |
745 | MLX5_ST_SZ_BYTES(port_selection_cap)); |
746 | MLX5_SET(port_selection_cap, set_hca_cap, port_select_flow_table_bypass, 1); |
747 | |
748 | err = set_caps(dev, in: set_ctx, opmod: MLX5_SET_HCA_CAP_OP_MOD_PORT_SELECTION); |
749 | |
750 | return err; |
751 | } |
752 | |
753 | static int set_hca_cap(struct mlx5_core_dev *dev) |
754 | { |
755 | int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); |
756 | void *set_ctx; |
757 | int err; |
758 | |
759 | set_ctx = kzalloc(set_sz, GFP_KERNEL); |
760 | if (!set_ctx) |
761 | return -ENOMEM; |
762 | |
763 | err = handle_hca_cap(dev, set_ctx); |
764 | if (err) { |
765 | mlx5_core_err(dev, "handle_hca_cap failed\n"); |
766 | goto out; |
767 | } |
768 | |
769 | memset(set_ctx, 0, set_sz); |
770 | err = handle_hca_cap_atomic(dev, set_ctx); |
771 | if (err) { |
772 | mlx5_core_err(dev, "handle_hca_cap_atomic failed\n"); |
773 | goto out; |
774 | } |
775 | |
776 | memset(set_ctx, 0, set_sz); |
777 | err = handle_hca_cap_odp(dev, set_ctx); |
778 | if (err) { |
779 | mlx5_core_err(dev, "handle_hca_cap_odp failed\n"); |
780 | goto out; |
781 | } |
782 | |
783 | memset(set_ctx, 0, set_sz); |
784 | err = handle_hca_cap_roce(dev, set_ctx); |
785 | if (err) { |
786 | mlx5_core_err(dev, "handle_hca_cap_roce failed\n"); |
787 | goto out; |
788 | } |
789 | |
790 | memset(set_ctx, 0, set_sz); |
791 | err = handle_hca_cap_2(dev, set_ctx); |
792 | if (err) { |
793 | mlx5_core_err(dev, "handle_hca_cap_2 failed\n"); |
794 | goto out; |
795 | } |
796 | |
797 | memset(set_ctx, 0, set_sz); |
798 | err = handle_hca_cap_port_selection(dev, set_ctx); |
799 | if (err) { |
800 | mlx5_core_err(dev, "handle_hca_cap_port_selection failed\n"); |
801 | goto out; |
802 | } |
803 | |
804 | out: |
805 | kfree(objp: set_ctx); |
806 | return err; |
807 | } |
808 | |
809 | static int set_hca_ctrl(struct mlx5_core_dev *dev) |
810 | { |
811 | struct mlx5_reg_host_endianness he_in; |
812 | struct mlx5_reg_host_endianness he_out; |
813 | int err; |
814 | |
815 | if (!mlx5_core_is_pf(dev)) |
816 | return 0; |
817 | |
818 | memset(&he_in, 0, sizeof(he_in)); |
819 | he_in.he = MLX5_SET_HOST_ENDIANNESS; |
820 | err = mlx5_core_access_reg(dev, data_in: &he_in, size_in: sizeof(he_in), |
821 | data_out: &he_out, size_out: sizeof(he_out), |
822 | reg_num: MLX5_REG_HOST_ENDIANNESS, arg: 0, write: 1); |
823 | return err; |
824 | } |
825 | |
826 | static int mlx5_core_set_hca_defaults(struct mlx5_core_dev *dev) |
827 | { |
828 | int ret = 0; |
829 | |
830 | /* Disable local_lb by default */ |
831 | if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH) |
832 | ret = mlx5_nic_vport_update_local_lb(mdev: dev, enable: false); |
833 | |
834 | return ret; |
835 | } |
836 | |
837 | int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id) |
838 | { |
839 | u32 in[MLX5_ST_SZ_DW(enable_hca_in)] = {}; |
840 | |
841 | MLX5_SET(enable_hca_in, in, opcode, MLX5_CMD_OP_ENABLE_HCA); |
842 | MLX5_SET(enable_hca_in, in, function_id, func_id); |
843 | MLX5_SET(enable_hca_in, in, embedded_cpu_function, |
844 | dev->caps.embedded_cpu); |
845 | return mlx5_cmd_exec_in(dev, enable_hca, in); |
846 | } |
847 | |
848 | int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id) |
849 | { |
850 | u32 in[MLX5_ST_SZ_DW(disable_hca_in)] = {}; |
851 | |
852 | MLX5_SET(disable_hca_in, in, opcode, MLX5_CMD_OP_DISABLE_HCA); |
853 | MLX5_SET(disable_hca_in, in, function_id, func_id); |
854 | MLX5_SET(enable_hca_in, in, embedded_cpu_function, |
855 | dev->caps.embedded_cpu); |
856 | return mlx5_cmd_exec_in(dev, disable_hca, in); |
857 | } |
858 | |
859 | static int mlx5_core_set_issi(struct mlx5_core_dev *dev) |
860 | { |
861 | u32 query_out[MLX5_ST_SZ_DW(query_issi_out)] = {}; |
862 | u32 query_in[MLX5_ST_SZ_DW(query_issi_in)] = {}; |
863 | u32 sup_issi; |
864 | int err; |
865 | |
866 | MLX5_SET(query_issi_in, query_in, opcode, MLX5_CMD_OP_QUERY_ISSI); |
867 | err = mlx5_cmd_exec_inout(dev, query_issi, query_in, query_out); |
868 | if (err) { |
869 | u32 syndrome = MLX5_GET(query_issi_out, query_out, syndrome); |
870 | u8 status = MLX5_GET(query_issi_out, query_out, status); |
871 | |
872 | if (!status || syndrome == MLX5_DRIVER_SYND) { |
873 | mlx5_core_err(dev, "Failed to query ISSI err(%d) status(%d) synd(%d)\n", |
874 | err, status, syndrome); |
875 | return err; |
876 | } |
877 | |
878 | mlx5_core_warn(dev, "Query ISSI is not supported by FW, ISSI is 0\n"); |
879 | dev->issi = 0; |
880 | return 0; |
881 | } |
882 | |
883 | sup_issi = MLX5_GET(query_issi_out, query_out, supported_issi_dw0); |
884 | |
885 | if (sup_issi & (1 << 1)) { |
886 | u32 set_in[MLX5_ST_SZ_DW(set_issi_in)] = {}; |
887 | |
888 | MLX5_SET(set_issi_in, set_in, opcode, MLX5_CMD_OP_SET_ISSI); |
889 | MLX5_SET(set_issi_in, set_in, current_issi, 1); |
890 | err = mlx5_cmd_exec_in(dev, set_issi, set_in); |
891 | if (err) { |
892 | mlx5_core_err(dev, "Failed to set ISSI to 1 err(%d)\n", |
893 | err); |
894 | return err; |
895 | } |
896 | |
897 | dev->issi = 1; |
898 | |
899 | return 0; |
900 | } else if (sup_issi & (1 << 0) || !sup_issi) { |
901 | return 0; |
902 | } |
903 | |
904 | return -EOPNOTSUPP; |
905 | } |
906 | |
907 | static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev, |
908 | const struct pci_device_id *id) |
909 | { |
910 | int err = 0; |
911 | |
912 | mutex_init(&dev->pci_status_mutex); |
913 | pci_set_drvdata(pdev: dev->pdev, data: dev); |
914 | |
915 | dev->bar_addr = pci_resource_start(pdev, 0); |
916 | |
917 | err = mlx5_pci_enable_device(dev); |
918 | if (err) { |
919 | mlx5_core_err(dev, "Cannot enable PCI device, aborting\n"); |
920 | return err; |
921 | } |
922 | |
923 | err = request_bar(pdev); |
924 | if (err) { |
925 | mlx5_core_err(dev, "error requesting BARs, aborting\n"); |
926 | goto err_disable; |
927 | } |
928 | |
929 | pci_set_master(dev: pdev); |
930 | |
931 | err = set_dma_caps(pdev); |
932 | if (err) { |
933 | mlx5_core_err(dev, "Failed setting DMA capabilities mask, aborting\n"); |
934 | goto err_clr_master; |
935 | } |
936 | |
937 | if (pci_enable_atomic_ops_to_root(dev: pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP32) && |
938 | pci_enable_atomic_ops_to_root(dev: pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64) && |
939 | pci_enable_atomic_ops_to_root(dev: pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP128)) |
940 | mlx5_core_dbg(dev, "Enabling pci atomics failed\n"); |
941 | |
942 | dev->iseg_base = dev->bar_addr; |
943 | dev->iseg = ioremap(offset: dev->iseg_base, size: sizeof(*dev->iseg)); |
944 | if (!dev->iseg) { |
945 | err = -ENOMEM; |
946 | mlx5_core_err(dev, "Failed mapping initialization segment, aborting\n"); |
947 | goto err_clr_master; |
948 | } |
949 | |
950 | mlx5_pci_vsc_init(dev); |
951 | |
952 | pci_enable_ptm(dev: pdev, NULL); |
953 | |
954 | return 0; |
955 | |
956 | err_clr_master: |
957 | release_bar(pdev: dev->pdev); |
958 | err_disable: |
959 | mlx5_pci_disable_device(dev); |
960 | return err; |
961 | } |
962 | |
963 | static void mlx5_pci_close(struct mlx5_core_dev *dev) |
964 | { |
965 | /* health work might still be active, and it needs pci bar in |
966 | * order to know the NIC state. Therefore, drain the health WQ |
967 | * before removing the pci bars |
968 | */ |
969 | mlx5_drain_health_wq(dev); |
970 | pci_disable_ptm(dev: dev->pdev); |
971 | iounmap(addr: dev->iseg); |
972 | release_bar(pdev: dev->pdev); |
973 | mlx5_pci_disable_device(dev); |
974 | } |
975 | |
976 | static void mlx5_register_hca_devcom_comp(struct mlx5_core_dev *dev) |
977 | { |
978 | /* This component is use to sync adding core_dev to lag_dev and to sync |
979 | * changes of mlx5_adev_devices between LAG layer and other layers. |
980 | */ |
981 | if (!mlx5_lag_is_supported(dev)) |
982 | return; |
983 | |
984 | dev->priv.hca_devcom_comp = |
985 | mlx5_devcom_register_component(devc: dev->priv.devc, id: MLX5_DEVCOM_HCA_PORTS, |
986 | key: mlx5_query_nic_system_image_guid(mdev: dev), |
987 | NULL, data: dev); |
988 | if (IS_ERR(ptr: dev->priv.hca_devcom_comp)) |
989 | mlx5_core_err(dev, "Failed to register devcom HCA component\n"); |
990 | } |
991 | |
992 | static void mlx5_unregister_hca_devcom_comp(struct mlx5_core_dev *dev) |
993 | { |
994 | mlx5_devcom_unregister_component(devcom: dev->priv.hca_devcom_comp); |
995 | } |
996 | |
997 | static int mlx5_init_once(struct mlx5_core_dev *dev) |
998 | { |
999 | int err; |
1000 | |
1001 | dev->priv.devc = mlx5_devcom_register_device(dev); |
1002 | if (IS_ERR(ptr: dev->priv.devc)) |
1003 | mlx5_core_warn(dev, "failed to register devcom device %ld\n", |
1004 | PTR_ERR(dev->priv.devc)); |
1005 | mlx5_register_hca_devcom_comp(dev); |
1006 | |
1007 | err = mlx5_query_board_id(dev); |
1008 | if (err) { |
1009 | mlx5_core_err(dev, "query board id failed\n"); |
1010 | goto err_devcom; |
1011 | } |
1012 | |
1013 | err = mlx5_irq_table_init(dev); |
1014 | if (err) { |
1015 | mlx5_core_err(dev, "failed to initialize irq table\n"); |
1016 | goto err_devcom; |
1017 | } |
1018 | |
1019 | err = mlx5_eq_table_init(dev); |
1020 | if (err) { |
1021 | mlx5_core_err(dev, "failed to initialize eq\n"); |
1022 | goto err_irq_cleanup; |
1023 | } |
1024 | |
1025 | err = mlx5_events_init(dev); |
1026 | if (err) { |
1027 | mlx5_core_err(dev, "failed to initialize events\n"); |
1028 | goto err_eq_cleanup; |
1029 | } |
1030 | |
1031 | err = mlx5_fw_reset_init(dev); |
1032 | if (err) { |
1033 | mlx5_core_err(dev, "failed to initialize fw reset events\n"); |
1034 | goto err_events_cleanup; |
1035 | } |
1036 | |
1037 | mlx5_cq_debugfs_init(dev); |
1038 | |
1039 | mlx5_init_reserved_gids(dev); |
1040 | |
1041 | err = mlx5_init_clock(mdev: dev); |
1042 | if (err) { |
1043 | mlx5_core_err(dev, "failed to initialize hardware clock\n"); |
1044 | goto err_tables_cleanup; |
1045 | } |
1046 | |
1047 | dev->vxlan = mlx5_vxlan_create(mdev: dev); |
1048 | dev->geneve = mlx5_geneve_create(mdev: dev); |
1049 | |
1050 | err = mlx5_init_rl_table(dev); |
1051 | if (err) { |
1052 | mlx5_core_err(dev, "Failed to init rate limiting\n"); |
1053 | goto err_clock_cleanup; |
1054 | } |
1055 | |
1056 | err = mlx5_mpfs_init(dev); |
1057 | if (err) { |
1058 | mlx5_core_err(dev, "Failed to init l2 table %d\n", err); |
1059 | goto err_rl_cleanup; |
1060 | } |
1061 | |
1062 | err = mlx5_sriov_init(dev); |
1063 | if (err) { |
1064 | mlx5_core_err(dev, "Failed to init sriov %d\n", err); |
1065 | goto err_mpfs_cleanup; |
1066 | } |
1067 | |
1068 | err = mlx5_eswitch_init(dev); |
1069 | if (err) { |
1070 | mlx5_core_err(dev, "Failed to init eswitch %d\n", err); |
1071 | goto err_sriov_cleanup; |
1072 | } |
1073 | |
1074 | err = mlx5_fpga_init(mdev: dev); |
1075 | if (err) { |
1076 | mlx5_core_err(dev, "Failed to init fpga device %d\n", err); |
1077 | goto err_eswitch_cleanup; |
1078 | } |
1079 | |
1080 | err = mlx5_vhca_event_init(dev); |
1081 | if (err) { |
1082 | mlx5_core_err(dev, "Failed to init vhca event notifier %d\n", err); |
1083 | goto err_fpga_cleanup; |
1084 | } |
1085 | |
1086 | err = mlx5_sf_hw_table_init(dev); |
1087 | if (err) { |
1088 | mlx5_core_err(dev, "Failed to init SF HW table %d\n", err); |
1089 | goto err_sf_hw_table_cleanup; |
1090 | } |
1091 | |
1092 | err = mlx5_sf_table_init(dev); |
1093 | if (err) { |
1094 | mlx5_core_err(dev, "Failed to init SF table %d\n", err); |
1095 | goto err_sf_table_cleanup; |
1096 | } |
1097 | |
1098 | err = mlx5_fs_core_alloc(dev); |
1099 | if (err) { |
1100 | mlx5_core_err(dev, "Failed to alloc flow steering\n"); |
1101 | goto err_fs; |
1102 | } |
1103 | |
1104 | dev->dm = mlx5_dm_create(dev); |
1105 | if (IS_ERR(ptr: dev->dm)) |
1106 | mlx5_core_warn(dev, "Failed to init device memory %ld\n", PTR_ERR(dev->dm)); |
1107 | |
1108 | dev->tracer = mlx5_fw_tracer_create(dev); |
1109 | dev->hv_vhca = mlx5_hv_vhca_create(dev); |
1110 | dev->rsc_dump = mlx5_rsc_dump_create(dev); |
1111 | |
1112 | return 0; |
1113 | |
1114 | err_fs: |
1115 | mlx5_sf_table_cleanup(dev); |
1116 | err_sf_table_cleanup: |
1117 | mlx5_sf_hw_table_cleanup(dev); |
1118 | err_sf_hw_table_cleanup: |
1119 | mlx5_vhca_event_cleanup(dev); |
1120 | err_fpga_cleanup: |
1121 | mlx5_fpga_cleanup(mdev: dev); |
1122 | err_eswitch_cleanup: |
1123 | mlx5_eswitch_cleanup(esw: dev->priv.eswitch); |
1124 | err_sriov_cleanup: |
1125 | mlx5_sriov_cleanup(dev); |
1126 | err_mpfs_cleanup: |
1127 | mlx5_mpfs_cleanup(dev); |
1128 | err_rl_cleanup: |
1129 | mlx5_cleanup_rl_table(dev); |
1130 | err_clock_cleanup: |
1131 | mlx5_geneve_destroy(geneve: dev->geneve); |
1132 | mlx5_vxlan_destroy(vxlan: dev->vxlan); |
1133 | mlx5_cleanup_clock(mdev: dev); |
1134 | err_tables_cleanup: |
1135 | mlx5_cleanup_reserved_gids(dev); |
1136 | mlx5_cq_debugfs_cleanup(dev); |
1137 | mlx5_fw_reset_cleanup(dev); |
1138 | err_events_cleanup: |
1139 | mlx5_events_cleanup(dev); |
1140 | err_eq_cleanup: |
1141 | mlx5_eq_table_cleanup(dev); |
1142 | err_irq_cleanup: |
1143 | mlx5_irq_table_cleanup(dev); |
1144 | err_devcom: |
1145 | mlx5_unregister_hca_devcom_comp(dev); |
1146 | mlx5_devcom_unregister_device(devc: dev->priv.devc); |
1147 | |
1148 | return err; |
1149 | } |
1150 | |
1151 | static void mlx5_cleanup_once(struct mlx5_core_dev *dev) |
1152 | { |
1153 | mlx5_rsc_dump_destroy(dev); |
1154 | mlx5_hv_vhca_destroy(hv_vhca: dev->hv_vhca); |
1155 | mlx5_fw_tracer_destroy(tracer: dev->tracer); |
1156 | mlx5_dm_cleanup(dev); |
1157 | mlx5_fs_core_free(dev); |
1158 | mlx5_sf_table_cleanup(dev); |
1159 | mlx5_sf_hw_table_cleanup(dev); |
1160 | mlx5_vhca_event_cleanup(dev); |
1161 | mlx5_fpga_cleanup(mdev: dev); |
1162 | mlx5_eswitch_cleanup(esw: dev->priv.eswitch); |
1163 | mlx5_sriov_cleanup(dev); |
1164 | mlx5_mpfs_cleanup(dev); |
1165 | mlx5_cleanup_rl_table(dev); |
1166 | mlx5_geneve_destroy(geneve: dev->geneve); |
1167 | mlx5_vxlan_destroy(vxlan: dev->vxlan); |
1168 | mlx5_cleanup_clock(mdev: dev); |
1169 | mlx5_cleanup_reserved_gids(dev); |
1170 | mlx5_cq_debugfs_cleanup(dev); |
1171 | mlx5_fw_reset_cleanup(dev); |
1172 | mlx5_events_cleanup(dev); |
1173 | mlx5_eq_table_cleanup(dev); |
1174 | mlx5_irq_table_cleanup(dev); |
1175 | mlx5_unregister_hca_devcom_comp(dev); |
1176 | mlx5_devcom_unregister_device(devc: dev->priv.devc); |
1177 | } |
1178 | |
1179 | static int mlx5_function_enable(struct mlx5_core_dev *dev, bool boot, u64 timeout) |
1180 | { |
1181 | int err; |
1182 | |
1183 | mlx5_core_info(dev, "firmware version: %d.%d.%d\n", fw_rev_maj(dev), |
1184 | fw_rev_min(dev), fw_rev_sub(dev)); |
1185 | |
1186 | /* Only PFs hold the relevant PCIe information for this query */ |
1187 | if (mlx5_core_is_pf(dev)) |
1188 | pcie_print_link_status(dev: dev->pdev); |
1189 | |
1190 | /* wait for firmware to accept initialization segments configurations |
1191 | */ |
1192 | err = wait_fw_init(dev, max_wait_mili: timeout, |
1193 | mlx5_tout_ms(dev, FW_PRE_INIT_WARN_MESSAGE_INTERVAL), |
1194 | init_state: "pre-initializing"); |
1195 | if (err) |
1196 | return err; |
1197 | |
1198 | err = mlx5_cmd_enable(dev); |
1199 | if (err) { |
1200 | mlx5_core_err(dev, "Failed initializing command interface, aborting\n"); |
1201 | return err; |
1202 | } |
1203 | |
1204 | mlx5_tout_query_iseg(dev); |
1205 | |
1206 | err = wait_fw_init(dev, mlx5_tout_ms(dev, FW_INIT), warn_time_mili: 0, init_state: "initializing"); |
1207 | if (err) |
1208 | goto err_cmd_cleanup; |
1209 | |
1210 | dev->caps.embedded_cpu = mlx5_read_embedded_cpu(dev); |
1211 | mlx5_cmd_set_state(dev, cmdif_state: MLX5_CMDIF_STATE_UP); |
1212 | |
1213 | err = mlx5_core_enable_hca(dev, func_id: 0); |
1214 | if (err) { |
1215 | mlx5_core_err(dev, "enable hca failed\n"); |
1216 | goto err_cmd_cleanup; |
1217 | } |
1218 | |
1219 | mlx5_start_health_poll(dev); |
1220 | |
1221 | err = mlx5_core_set_issi(dev); |
1222 | if (err) { |
1223 | mlx5_core_err(dev, "failed to set issi\n"); |
1224 | goto stop_health_poll; |
1225 | } |
1226 | |
1227 | err = mlx5_satisfy_startup_pages(dev, boot: 1); |
1228 | if (err) { |
1229 | mlx5_core_err(dev, "failed to allocate boot pages\n"); |
1230 | goto stop_health_poll; |
1231 | } |
1232 | |
1233 | err = mlx5_tout_query_dtor(dev); |
1234 | if (err) { |
1235 | mlx5_core_err(dev, "failed to read dtor\n"); |
1236 | goto reclaim_boot_pages; |
1237 | } |
1238 | |
1239 | return 0; |
1240 | |
1241 | reclaim_boot_pages: |
1242 | mlx5_reclaim_startup_pages(dev); |
1243 | stop_health_poll: |
1244 | mlx5_stop_health_poll(dev, disable_health: boot); |
1245 | mlx5_core_disable_hca(dev, func_id: 0); |
1246 | err_cmd_cleanup: |
1247 | mlx5_cmd_set_state(dev, cmdif_state: MLX5_CMDIF_STATE_DOWN); |
1248 | mlx5_cmd_disable(dev); |
1249 | |
1250 | return err; |
1251 | } |
1252 | |
1253 | static void mlx5_function_disable(struct mlx5_core_dev *dev, bool boot) |
1254 | { |
1255 | mlx5_reclaim_startup_pages(dev); |
1256 | mlx5_stop_health_poll(dev, disable_health: boot); |
1257 | mlx5_core_disable_hca(dev, func_id: 0); |
1258 | mlx5_cmd_set_state(dev, cmdif_state: MLX5_CMDIF_STATE_DOWN); |
1259 | mlx5_cmd_disable(dev); |
1260 | } |
1261 | |
1262 | static int mlx5_function_open(struct mlx5_core_dev *dev) |
1263 | { |
1264 | int err; |
1265 | |
1266 | err = set_hca_ctrl(dev); |
1267 | if (err) { |
1268 | mlx5_core_err(dev, "set_hca_ctrl failed\n"); |
1269 | return err; |
1270 | } |
1271 | |
1272 | err = set_hca_cap(dev); |
1273 | if (err) { |
1274 | mlx5_core_err(dev, "set_hca_cap failed\n"); |
1275 | return err; |
1276 | } |
1277 | |
1278 | err = mlx5_satisfy_startup_pages(dev, boot: 0); |
1279 | if (err) { |
1280 | mlx5_core_err(dev, "failed to allocate init pages\n"); |
1281 | return err; |
1282 | } |
1283 | |
1284 | err = mlx5_cmd_init_hca(dev, sw_owner_id); |
1285 | if (err) { |
1286 | mlx5_core_err(dev, "init hca failed\n"); |
1287 | return err; |
1288 | } |
1289 | |
1290 | mlx5_set_driver_version(dev); |
1291 | |
1292 | err = mlx5_query_hca_caps(dev); |
1293 | if (err) { |
1294 | mlx5_core_err(dev, "query hca failed\n"); |
1295 | return err; |
1296 | } |
1297 | mlx5_start_health_fw_log_up(dev); |
1298 | return 0; |
1299 | } |
1300 | |
1301 | static int mlx5_function_close(struct mlx5_core_dev *dev) |
1302 | { |
1303 | int err; |
1304 | |
1305 | err = mlx5_cmd_teardown_hca(dev); |
1306 | if (err) { |
1307 | mlx5_core_err(dev, "tear_down_hca failed, skip cleanup\n"); |
1308 | return err; |
1309 | } |
1310 | |
1311 | return 0; |
1312 | } |
1313 | |
1314 | static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout) |
1315 | { |
1316 | int err; |
1317 | |
1318 | err = mlx5_function_enable(dev, boot, timeout); |
1319 | if (err) |
1320 | return err; |
1321 | |
1322 | err = mlx5_function_open(dev); |
1323 | if (err) |
1324 | mlx5_function_disable(dev, boot); |
1325 | return err; |
1326 | } |
1327 | |
1328 | static int mlx5_function_teardown(struct mlx5_core_dev *dev, bool boot) |
1329 | { |
1330 | int err = mlx5_function_close(dev); |
1331 | |
1332 | if (!err) |
1333 | mlx5_function_disable(dev, boot); |
1334 | else |
1335 | mlx5_stop_health_poll(dev, disable_health: boot); |
1336 | |
1337 | return err; |
1338 | } |
1339 | |
1340 | static int mlx5_load(struct mlx5_core_dev *dev) |
1341 | { |
1342 | int err; |
1343 | |
1344 | dev->priv.uar = mlx5_get_uars_page(mdev: dev); |
1345 | if (IS_ERR(ptr: dev->priv.uar)) { |
1346 | mlx5_core_err(dev, "Failed allocating uar, aborting\n"); |
1347 | err = PTR_ERR(ptr: dev->priv.uar); |
1348 | return err; |
1349 | } |
1350 | |
1351 | mlx5_events_start(dev); |
1352 | mlx5_pagealloc_start(dev); |
1353 | |
1354 | err = mlx5_irq_table_create(dev); |
1355 | if (err) { |
1356 | mlx5_core_err(dev, "Failed to alloc IRQs\n"); |
1357 | goto err_irq_table; |
1358 | } |
1359 | |
1360 | err = mlx5_eq_table_create(dev); |
1361 | if (err) { |
1362 | mlx5_core_err(dev, "Failed to create EQs\n"); |
1363 | goto err_eq_table; |
1364 | } |
1365 | |
1366 | mlx5_clock_load(mdev: dev); |
1367 | |
1368 | err = mlx5_fw_tracer_init(tracer: dev->tracer); |
1369 | if (err) { |
1370 | mlx5_core_err(dev, "Failed to init FW tracer %d\n", err); |
1371 | mlx5_fw_tracer_destroy(tracer: dev->tracer); |
1372 | dev->tracer = NULL; |
1373 | } |
1374 | |
1375 | mlx5_fw_reset_events_start(dev); |
1376 | mlx5_hv_vhca_init(hv_vhca: dev->hv_vhca); |
1377 | |
1378 | err = mlx5_rsc_dump_init(dev); |
1379 | if (err) { |
1380 | mlx5_core_err(dev, "Failed to init Resource dump %d\n", err); |
1381 | mlx5_rsc_dump_destroy(dev); |
1382 | dev->rsc_dump = NULL; |
1383 | } |
1384 | |
1385 | err = mlx5_fpga_device_start(mdev: dev); |
1386 | if (err) { |
1387 | mlx5_core_err(dev, "fpga device start failed %d\n", err); |
1388 | goto err_fpga_start; |
1389 | } |
1390 | |
1391 | err = mlx5_fs_core_init(dev); |
1392 | if (err) { |
1393 | mlx5_core_err(dev, "Failed to init flow steering\n"); |
1394 | goto err_fs; |
1395 | } |
1396 | |
1397 | err = mlx5_core_set_hca_defaults(dev); |
1398 | if (err) { |
1399 | mlx5_core_err(dev, "Failed to set hca defaults\n"); |
1400 | goto err_set_hca; |
1401 | } |
1402 | |
1403 | mlx5_vhca_event_start(dev); |
1404 | |
1405 | err = mlx5_sf_hw_table_create(dev); |
1406 | if (err) { |
1407 | mlx5_core_err(dev, "sf table create failed %d\n", err); |
1408 | goto err_vhca; |
1409 | } |
1410 | |
1411 | err = mlx5_ec_init(dev); |
1412 | if (err) { |
1413 | mlx5_core_err(dev, "Failed to init embedded CPU\n"); |
1414 | goto err_ec; |
1415 | } |
1416 | |
1417 | mlx5_lag_add_mdev(dev); |
1418 | err = mlx5_sriov_attach(dev); |
1419 | if (err) { |
1420 | mlx5_core_err(dev, "sriov init failed %d\n", err); |
1421 | goto err_sriov; |
1422 | } |
1423 | |
1424 | mlx5_sf_dev_table_create(dev); |
1425 | |
1426 | err = mlx5_devlink_traps_register(devlink: priv_to_devlink(priv: dev)); |
1427 | if (err) |
1428 | goto err_traps_reg; |
1429 | |
1430 | return 0; |
1431 | |
1432 | err_traps_reg: |
1433 | mlx5_sf_dev_table_destroy(dev); |
1434 | mlx5_sriov_detach(dev); |
1435 | err_sriov: |
1436 | mlx5_lag_remove_mdev(dev); |
1437 | mlx5_ec_cleanup(dev); |
1438 | err_ec: |
1439 | mlx5_sf_hw_table_destroy(dev); |
1440 | err_vhca: |
1441 | mlx5_vhca_event_stop(dev); |
1442 | err_set_hca: |
1443 | mlx5_fs_core_cleanup(dev); |
1444 | err_fs: |
1445 | mlx5_fpga_device_stop(mdev: dev); |
1446 | err_fpga_start: |
1447 | mlx5_rsc_dump_cleanup(dev); |
1448 | mlx5_hv_vhca_cleanup(hv_vhca: dev->hv_vhca); |
1449 | mlx5_fw_reset_events_stop(dev); |
1450 | mlx5_fw_tracer_cleanup(tracer: dev->tracer); |
1451 | mlx5_clock_unload(mdev: dev); |
1452 | mlx5_eq_table_destroy(dev); |
1453 | err_eq_table: |
1454 | mlx5_irq_table_destroy(dev); |
1455 | err_irq_table: |
1456 | mlx5_pagealloc_stop(dev); |
1457 | mlx5_events_stop(dev); |
1458 | mlx5_put_uars_page(mdev: dev, up: dev->priv.uar); |
1459 | return err; |
1460 | } |
1461 | |
1462 | static void mlx5_unload(struct mlx5_core_dev *dev) |
1463 | { |
1464 | mlx5_eswitch_disable(esw: dev->priv.eswitch); |
1465 | mlx5_devlink_traps_unregister(devlink: priv_to_devlink(priv: dev)); |
1466 | mlx5_sf_dev_table_destroy(dev); |
1467 | mlx5_sriov_detach(dev); |
1468 | mlx5_lag_remove_mdev(dev); |
1469 | mlx5_ec_cleanup(dev); |
1470 | mlx5_sf_hw_table_destroy(dev); |
1471 | mlx5_vhca_event_stop(dev); |
1472 | mlx5_fs_core_cleanup(dev); |
1473 | mlx5_fpga_device_stop(mdev: dev); |
1474 | mlx5_rsc_dump_cleanup(dev); |
1475 | mlx5_hv_vhca_cleanup(hv_vhca: dev->hv_vhca); |
1476 | mlx5_fw_reset_events_stop(dev); |
1477 | mlx5_fw_tracer_cleanup(tracer: dev->tracer); |
1478 | mlx5_clock_unload(mdev: dev); |
1479 | mlx5_eq_table_destroy(dev); |
1480 | mlx5_irq_table_destroy(dev); |
1481 | mlx5_pagealloc_stop(dev); |
1482 | mlx5_events_stop(dev); |
1483 | mlx5_put_uars_page(mdev: dev, up: dev->priv.uar); |
1484 | } |
1485 | |
1486 | int mlx5_init_one_devl_locked(struct mlx5_core_dev *dev) |
1487 | { |
1488 | bool light_probe = mlx5_dev_is_lightweight(dev); |
1489 | int err = 0; |
1490 | |
1491 | mutex_lock(&dev->intf_state_mutex); |
1492 | dev->state = MLX5_DEVICE_STATE_UP; |
1493 | |
1494 | err = mlx5_function_setup(dev, boot: true, mlx5_tout_ms(dev, FW_PRE_INIT_TIMEOUT)); |
1495 | if (err) |
1496 | goto err_function; |
1497 | |
1498 | err = mlx5_init_once(dev); |
1499 | if (err) { |
1500 | mlx5_core_err(dev, "sw objs init failed\n"); |
1501 | goto function_teardown; |
1502 | } |
1503 | |
1504 | /* In case of light_probe, mlx5_devlink is already registered. |
1505 | * Hence, don't register devlink again. |
1506 | */ |
1507 | if (!light_probe) { |
1508 | err = mlx5_devlink_params_register(devlink: priv_to_devlink(priv: dev)); |
1509 | if (err) |
1510 | goto err_devlink_params_reg; |
1511 | } |
1512 | |
1513 | err = mlx5_load(dev); |
1514 | if (err) |
1515 | goto err_load; |
1516 | |
1517 | set_bit(nr: MLX5_INTERFACE_STATE_UP, addr: &dev->intf_state); |
1518 | |
1519 | err = mlx5_register_device(dev); |
1520 | if (err) |
1521 | goto err_register; |
1522 | |
1523 | err = mlx5_crdump_enable(dev); |
1524 | if (err) |
1525 | mlx5_core_err(dev, "mlx5_crdump_enable failed with error code %d\n", err); |
1526 | |
1527 | err = mlx5_hwmon_dev_register(mdev: dev); |
1528 | if (err) |
1529 | mlx5_core_err(dev, "mlx5_hwmon_dev_register failed with error code %d\n", err); |
1530 | |
1531 | mutex_unlock(lock: &dev->intf_state_mutex); |
1532 | return 0; |
1533 | |
1534 | err_register: |
1535 | clear_bit(nr: MLX5_INTERFACE_STATE_UP, addr: &dev->intf_state); |
1536 | mlx5_unload(dev); |
1537 | err_load: |
1538 | if (!light_probe) |
1539 | mlx5_devlink_params_unregister(devlink: priv_to_devlink(priv: dev)); |
1540 | err_devlink_params_reg: |
1541 | mlx5_cleanup_once(dev); |
1542 | function_teardown: |
1543 | mlx5_function_teardown(dev, boot: true); |
1544 | err_function: |
1545 | dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; |
1546 | mutex_unlock(lock: &dev->intf_state_mutex); |
1547 | return err; |
1548 | } |
1549 | |
1550 | int mlx5_init_one(struct mlx5_core_dev *dev) |
1551 | { |
1552 | struct devlink *devlink = priv_to_devlink(priv: dev); |
1553 | int err; |
1554 | |
1555 | devl_lock(devlink); |
1556 | devl_register(devlink); |
1557 | err = mlx5_init_one_devl_locked(dev); |
1558 | if (err) |
1559 | devl_unregister(devlink); |
1560 | devl_unlock(devlink); |
1561 | return err; |
1562 | } |
1563 | |
1564 | void mlx5_uninit_one(struct mlx5_core_dev *dev) |
1565 | { |
1566 | struct devlink *devlink = priv_to_devlink(priv: dev); |
1567 | |
1568 | devl_lock(devlink); |
1569 | mutex_lock(&dev->intf_state_mutex); |
1570 | |
1571 | mlx5_hwmon_dev_unregister(mdev: dev); |
1572 | mlx5_crdump_disable(dev); |
1573 | mlx5_unregister_device(dev); |
1574 | |
1575 | if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) { |
1576 | mlx5_core_warn(dev, "%s: interface is down, NOP\n", |
1577 | __func__); |
1578 | mlx5_devlink_params_unregister(devlink: priv_to_devlink(priv: dev)); |
1579 | mlx5_cleanup_once(dev); |
1580 | goto out; |
1581 | } |
1582 | |
1583 | clear_bit(nr: MLX5_INTERFACE_STATE_UP, addr: &dev->intf_state); |
1584 | mlx5_unload(dev); |
1585 | mlx5_devlink_params_unregister(devlink: priv_to_devlink(priv: dev)); |
1586 | mlx5_cleanup_once(dev); |
1587 | mlx5_function_teardown(dev, boot: true); |
1588 | out: |
1589 | mutex_unlock(lock: &dev->intf_state_mutex); |
1590 | devl_unregister(devlink); |
1591 | devl_unlock(devlink); |
1592 | } |
1593 | |
1594 | int mlx5_load_one_devl_locked(struct mlx5_core_dev *dev, bool recovery) |
1595 | { |
1596 | int err = 0; |
1597 | u64 timeout; |
1598 | |
1599 | devl_assert_locked(devlink: priv_to_devlink(priv: dev)); |
1600 | mutex_lock(&dev->intf_state_mutex); |
1601 | if (test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) { |
1602 | mlx5_core_warn(dev, "interface is up, NOP\n"); |
1603 | goto out; |
1604 | } |
1605 | /* remove any previous indication of internal error */ |
1606 | dev->state = MLX5_DEVICE_STATE_UP; |
1607 | |
1608 | if (recovery) |
1609 | timeout = mlx5_tout_ms(dev, FW_PRE_INIT_ON_RECOVERY_TIMEOUT); |
1610 | else |
1611 | timeout = mlx5_tout_ms(dev, FW_PRE_INIT_TIMEOUT); |
1612 | err = mlx5_function_setup(dev, boot: false, timeout); |
1613 | if (err) |
1614 | goto err_function; |
1615 | |
1616 | err = mlx5_load(dev); |
1617 | if (err) |
1618 | goto err_load; |
1619 | |
1620 | set_bit(nr: MLX5_INTERFACE_STATE_UP, addr: &dev->intf_state); |
1621 | |
1622 | err = mlx5_attach_device(dev); |
1623 | if (err) |
1624 | goto err_attach; |
1625 | |
1626 | mutex_unlock(lock: &dev->intf_state_mutex); |
1627 | return 0; |
1628 | |
1629 | err_attach: |
1630 | clear_bit(nr: MLX5_INTERFACE_STATE_UP, addr: &dev->intf_state); |
1631 | mlx5_unload(dev); |
1632 | err_load: |
1633 | mlx5_function_teardown(dev, boot: false); |
1634 | err_function: |
1635 | dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; |
1636 | out: |
1637 | mutex_unlock(lock: &dev->intf_state_mutex); |
1638 | return err; |
1639 | } |
1640 | |
1641 | int mlx5_load_one(struct mlx5_core_dev *dev, bool recovery) |
1642 | { |
1643 | struct devlink *devlink = priv_to_devlink(priv: dev); |
1644 | int ret; |
1645 | |
1646 | devl_lock(devlink); |
1647 | ret = mlx5_load_one_devl_locked(dev, recovery); |
1648 | devl_unlock(devlink); |
1649 | return ret; |
1650 | } |
1651 | |
1652 | void mlx5_unload_one_devl_locked(struct mlx5_core_dev *dev, bool suspend) |
1653 | { |
1654 | devl_assert_locked(devlink: priv_to_devlink(priv: dev)); |
1655 | mutex_lock(&dev->intf_state_mutex); |
1656 | |
1657 | mlx5_detach_device(dev, suspend); |
1658 | |
1659 | if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) { |
1660 | mlx5_core_warn(dev, "%s: interface is down, NOP\n", |
1661 | __func__); |
1662 | goto out; |
1663 | } |
1664 | |
1665 | clear_bit(nr: MLX5_INTERFACE_STATE_UP, addr: &dev->intf_state); |
1666 | mlx5_unload(dev); |
1667 | mlx5_function_teardown(dev, boot: false); |
1668 | out: |
1669 | mutex_unlock(lock: &dev->intf_state_mutex); |
1670 | } |
1671 | |
1672 | void mlx5_unload_one(struct mlx5_core_dev *dev, bool suspend) |
1673 | { |
1674 | struct devlink *devlink = priv_to_devlink(priv: dev); |
1675 | |
1676 | devl_lock(devlink); |
1677 | mlx5_unload_one_devl_locked(dev, suspend); |
1678 | devl_unlock(devlink); |
1679 | } |
1680 | |
1681 | /* In case of light probe, we don't need a full query of hca_caps, but only the bellow caps. |
1682 | * A full query of hca_caps will be done when the device will reload. |
1683 | */ |
1684 | static int mlx5_query_hca_caps_light(struct mlx5_core_dev *dev) |
1685 | { |
1686 | int err; |
1687 | |
1688 | err = mlx5_core_get_caps(dev, cap_type: MLX5_CAP_GENERAL); |
1689 | if (err) |
1690 | return err; |
1691 | |
1692 | if (MLX5_CAP_GEN(dev, eth_net_offloads)) { |
1693 | err = mlx5_core_get_caps_mode(dev, cap_type: MLX5_CAP_ETHERNET_OFFLOADS, |
1694 | cap_mode: HCA_CAP_OPMOD_GET_CUR); |
1695 | if (err) |
1696 | return err; |
1697 | } |
1698 | |
1699 | if (MLX5_CAP_GEN(dev, nic_flow_table) || |
1700 | MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) { |
1701 | err = mlx5_core_get_caps_mode(dev, cap_type: MLX5_CAP_FLOW_TABLE, |
1702 | cap_mode: HCA_CAP_OPMOD_GET_CUR); |
1703 | if (err) |
1704 | return err; |
1705 | } |
1706 | |
1707 | if (MLX5_CAP_GEN_64(dev, general_obj_types) & |
1708 | MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) { |
1709 | err = mlx5_core_get_caps_mode(dev, cap_type: MLX5_CAP_VDPA_EMULATION, |
1710 | cap_mode: HCA_CAP_OPMOD_GET_CUR); |
1711 | if (err) |
1712 | return err; |
1713 | } |
1714 | |
1715 | return 0; |
1716 | } |
1717 | |
1718 | int mlx5_init_one_light(struct mlx5_core_dev *dev) |
1719 | { |
1720 | struct devlink *devlink = priv_to_devlink(priv: dev); |
1721 | int err; |
1722 | |
1723 | devl_lock(devlink); |
1724 | devl_register(devlink); |
1725 | dev->state = MLX5_DEVICE_STATE_UP; |
1726 | err = mlx5_function_enable(dev, boot: true, mlx5_tout_ms(dev, FW_PRE_INIT_TIMEOUT)); |
1727 | if (err) { |
1728 | mlx5_core_warn(dev, "mlx5_function_enable err=%d\n", err); |
1729 | goto out; |
1730 | } |
1731 | |
1732 | err = mlx5_query_hca_caps_light(dev); |
1733 | if (err) { |
1734 | mlx5_core_warn(dev, "mlx5_query_hca_caps_light err=%d\n", err); |
1735 | goto query_hca_caps_err; |
1736 | } |
1737 | |
1738 | err = mlx5_devlink_params_register(devlink: priv_to_devlink(priv: dev)); |
1739 | if (err) { |
1740 | mlx5_core_warn(dev, "mlx5_devlink_param_reg err = %d\n", err); |
1741 | goto query_hca_caps_err; |
1742 | } |
1743 | |
1744 | devl_unlock(devlink); |
1745 | return 0; |
1746 | |
1747 | query_hca_caps_err: |
1748 | mlx5_function_disable(dev, boot: true); |
1749 | out: |
1750 | dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; |
1751 | devl_unregister(devlink); |
1752 | devl_unlock(devlink); |
1753 | return err; |
1754 | } |
1755 | |
1756 | void mlx5_uninit_one_light(struct mlx5_core_dev *dev) |
1757 | { |
1758 | struct devlink *devlink = priv_to_devlink(priv: dev); |
1759 | |
1760 | devl_lock(devlink); |
1761 | mlx5_devlink_params_unregister(devlink: priv_to_devlink(priv: dev)); |
1762 | devl_unregister(devlink); |
1763 | devl_unlock(devlink); |
1764 | if (dev->state != MLX5_DEVICE_STATE_UP) |
1765 | return; |
1766 | mlx5_function_disable(dev, boot: true); |
1767 | } |
1768 | |
1769 | /* xxx_light() function are used in order to configure the device without full |
1770 | * init (light init). e.g.: There isn't a point in reload a device to light state. |
1771 | * Hence, mlx5_load_one_light() isn't needed. |
1772 | */ |
1773 | |
1774 | void mlx5_unload_one_light(struct mlx5_core_dev *dev) |
1775 | { |
1776 | if (dev->state != MLX5_DEVICE_STATE_UP) |
1777 | return; |
1778 | mlx5_function_disable(dev, boot: false); |
1779 | dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; |
1780 | } |
1781 | |
1782 | static const int types[] = { |
1783 | MLX5_CAP_GENERAL, |
1784 | MLX5_CAP_GENERAL_2, |
1785 | MLX5_CAP_ETHERNET_OFFLOADS, |
1786 | MLX5_CAP_IPOIB_ENHANCED_OFFLOADS, |
1787 | MLX5_CAP_ODP, |
1788 | MLX5_CAP_ATOMIC, |
1789 | MLX5_CAP_ROCE, |
1790 | MLX5_CAP_IPOIB_OFFLOADS, |
1791 | MLX5_CAP_FLOW_TABLE, |
1792 | MLX5_CAP_ESWITCH_FLOW_TABLE, |
1793 | MLX5_CAP_ESWITCH, |
1794 | MLX5_CAP_QOS, |
1795 | MLX5_CAP_DEBUG, |
1796 | MLX5_CAP_DEV_MEM, |
1797 | MLX5_CAP_DEV_EVENT, |
1798 | MLX5_CAP_TLS, |
1799 | MLX5_CAP_VDPA_EMULATION, |
1800 | MLX5_CAP_IPSEC, |
1801 | MLX5_CAP_PORT_SELECTION, |
1802 | MLX5_CAP_MACSEC, |
1803 | MLX5_CAP_ADV_VIRTUALIZATION, |
1804 | MLX5_CAP_CRYPTO, |
1805 | MLX5_CAP_SHAMPO, |
1806 | MLX5_CAP_ADV_RDMA, |
1807 | }; |
1808 | |
1809 | static void mlx5_hca_caps_free(struct mlx5_core_dev *dev) |
1810 | { |
1811 | int type; |
1812 | int i; |
1813 | |
1814 | for (i = 0; i < ARRAY_SIZE(types); i++) { |
1815 | type = types[i]; |
1816 | kfree(objp: dev->caps.hca[type]); |
1817 | } |
1818 | } |
1819 | |
1820 | static int mlx5_hca_caps_alloc(struct mlx5_core_dev *dev) |
1821 | { |
1822 | struct mlx5_hca_cap *cap; |
1823 | int type; |
1824 | int i; |
1825 | |
1826 | for (i = 0; i < ARRAY_SIZE(types); i++) { |
1827 | cap = kzalloc(sizeof(*cap), GFP_KERNEL); |
1828 | if (!cap) |
1829 | goto err; |
1830 | type = types[i]; |
1831 | dev->caps.hca[type] = cap; |
1832 | } |
1833 | |
1834 | return 0; |
1835 | |
1836 | err: |
1837 | mlx5_hca_caps_free(dev); |
1838 | return -ENOMEM; |
1839 | } |
1840 | |
1841 | static int vhca_id_show(struct seq_file *file, void *priv) |
1842 | { |
1843 | struct mlx5_core_dev *dev = file->private; |
1844 | |
1845 | seq_printf(m: file, fmt: "0x%x\n", MLX5_CAP_GEN(dev, vhca_id)); |
1846 | return 0; |
1847 | } |
1848 | |
1849 | DEFINE_SHOW_ATTRIBUTE(vhca_id); |
1850 | |
1851 | int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) |
1852 | { |
1853 | struct mlx5_priv *priv = &dev->priv; |
1854 | int err; |
1855 | |
1856 | memcpy(&dev->profile, &profile[profile_idx], sizeof(dev->profile)); |
1857 | lockdep_register_key(key: &dev->lock_key); |
1858 | mutex_init(&dev->intf_state_mutex); |
1859 | lockdep_set_class(&dev->intf_state_mutex, &dev->lock_key); |
1860 | mutex_init(&dev->mlx5e_res.uplink_netdev_lock); |
1861 | mutex_init(&dev->wc_state_lock); |
1862 | |
1863 | mutex_init(&priv->bfregs.reg_head.lock); |
1864 | mutex_init(&priv->bfregs.wc_head.lock); |
1865 | INIT_LIST_HEAD(list: &priv->bfregs.reg_head.list); |
1866 | INIT_LIST_HEAD(list: &priv->bfregs.wc_head.list); |
1867 | |
1868 | mutex_init(&priv->alloc_mutex); |
1869 | mutex_init(&priv->pgdir_mutex); |
1870 | INIT_LIST_HEAD(list: &priv->pgdir_list); |
1871 | |
1872 | priv->numa_node = dev_to_node(dev: mlx5_core_dma_dev(dev)); |
1873 | priv->dbg.dbg_root = debugfs_create_dir(name: dev_name(dev: dev->device), |
1874 | parent: mlx5_debugfs_root); |
1875 | debugfs_create_file("vhca_id", 0400, priv->dbg.dbg_root, dev, &vhca_id_fops); |
1876 | INIT_LIST_HEAD(list: &priv->traps); |
1877 | |
1878 | err = mlx5_cmd_init(dev); |
1879 | if (err) { |
1880 | mlx5_core_err(dev, "Failed initializing cmdif SW structs, aborting\n"); |
1881 | goto err_cmd_init; |
1882 | } |
1883 | |
1884 | err = mlx5_tout_init(dev); |
1885 | if (err) { |
1886 | mlx5_core_err(dev, "Failed initializing timeouts, aborting\n"); |
1887 | goto err_timeout_init; |
1888 | } |
1889 | |
1890 | err = mlx5_health_init(dev); |
1891 | if (err) |
1892 | goto err_health_init; |
1893 | |
1894 | err = mlx5_pagealloc_init(dev); |
1895 | if (err) |
1896 | goto err_pagealloc_init; |
1897 | |
1898 | err = mlx5_adev_init(dev); |
1899 | if (err) |
1900 | goto err_adev_init; |
1901 | |
1902 | err = mlx5_hca_caps_alloc(dev); |
1903 | if (err) |
1904 | goto err_hca_caps; |
1905 | |
1906 | /* The conjunction of sw_vhca_id with sw_owner_id will be a global |
1907 | * unique id per function which uses mlx5_core. |
1908 | * Those values are supplied to FW as part of the init HCA command to |
1909 | * be used by both driver and FW when it's applicable. |
1910 | */ |
1911 | dev->priv.sw_vhca_id = ida_alloc_range(&sw_vhca_ida, min: 1, |
1912 | MAX_SW_VHCA_ID, |
1913 | GFP_KERNEL); |
1914 | if (dev->priv.sw_vhca_id < 0) |
1915 | mlx5_core_err(dev, "failed to allocate sw_vhca_id, err=%d\n", |
1916 | dev->priv.sw_vhca_id); |
1917 | |
1918 | return 0; |
1919 | |
1920 | err_hca_caps: |
1921 | mlx5_adev_cleanup(dev); |
1922 | err_adev_init: |
1923 | mlx5_pagealloc_cleanup(dev); |
1924 | err_pagealloc_init: |
1925 | mlx5_health_cleanup(dev); |
1926 | err_health_init: |
1927 | mlx5_tout_cleanup(dev); |
1928 | err_timeout_init: |
1929 | mlx5_cmd_cleanup(dev); |
1930 | err_cmd_init: |
1931 | debugfs_remove(dentry: dev->priv.dbg.dbg_root); |
1932 | mutex_destroy(lock: &priv->pgdir_mutex); |
1933 | mutex_destroy(lock: &priv->alloc_mutex); |
1934 | mutex_destroy(lock: &priv->bfregs.wc_head.lock); |
1935 | mutex_destroy(lock: &priv->bfregs.reg_head.lock); |
1936 | mutex_destroy(lock: &dev->intf_state_mutex); |
1937 | lockdep_unregister_key(key: &dev->lock_key); |
1938 | return err; |
1939 | } |
1940 | |
1941 | void mlx5_mdev_uninit(struct mlx5_core_dev *dev) |
1942 | { |
1943 | struct mlx5_priv *priv = &dev->priv; |
1944 | |
1945 | if (priv->sw_vhca_id > 0) |
1946 | ida_free(&sw_vhca_ida, id: dev->priv.sw_vhca_id); |
1947 | |
1948 | mlx5_hca_caps_free(dev); |
1949 | mlx5_adev_cleanup(dev); |
1950 | mlx5_pagealloc_cleanup(dev); |
1951 | mlx5_health_cleanup(dev); |
1952 | mlx5_tout_cleanup(dev); |
1953 | mlx5_cmd_cleanup(dev); |
1954 | debugfs_remove_recursive(dentry: dev->priv.dbg.dbg_root); |
1955 | mutex_destroy(lock: &priv->pgdir_mutex); |
1956 | mutex_destroy(lock: &priv->alloc_mutex); |
1957 | mutex_destroy(lock: &priv->bfregs.wc_head.lock); |
1958 | mutex_destroy(lock: &priv->bfregs.reg_head.lock); |
1959 | mutex_destroy(lock: &dev->wc_state_lock); |
1960 | mutex_destroy(lock: &dev->mlx5e_res.uplink_netdev_lock); |
1961 | mutex_destroy(lock: &dev->intf_state_mutex); |
1962 | lockdep_unregister_key(key: &dev->lock_key); |
1963 | } |
1964 | |
1965 | static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id) |
1966 | { |
1967 | struct mlx5_core_dev *dev; |
1968 | struct devlink *devlink; |
1969 | int err; |
1970 | |
1971 | devlink = mlx5_devlink_alloc(dev: &pdev->dev); |
1972 | if (!devlink) { |
1973 | dev_err(&pdev->dev, "devlink alloc failed\n"); |
1974 | return -ENOMEM; |
1975 | } |
1976 | |
1977 | dev = devlink_priv(devlink); |
1978 | dev->device = &pdev->dev; |
1979 | dev->pdev = pdev; |
1980 | |
1981 | dev->coredev_type = id->driver_data & MLX5_PCI_DEV_IS_VF ? |
1982 | MLX5_COREDEV_VF : MLX5_COREDEV_PF; |
1983 | |
1984 | dev->priv.adev_idx = mlx5_adev_idx_alloc(); |
1985 | if (dev->priv.adev_idx < 0) { |
1986 | err = dev->priv.adev_idx; |
1987 | goto adev_init_err; |
1988 | } |
1989 | |
1990 | err = mlx5_mdev_init(dev, profile_idx: prof_sel); |
1991 | if (err) |
1992 | goto mdev_init_err; |
1993 | |
1994 | err = mlx5_pci_init(dev, pdev, id); |
1995 | if (err) { |
1996 | mlx5_core_err(dev, "mlx5_pci_init failed with error code %d\n", |
1997 | err); |
1998 | goto pci_init_err; |
1999 | } |
2000 | |
2001 | err = mlx5_init_one(dev); |
2002 | if (err) { |
2003 | mlx5_core_err(dev, "mlx5_init_one failed with error code %d\n", |
2004 | err); |
2005 | goto err_init_one; |
2006 | } |
2007 | |
2008 | pci_save_state(dev: pdev); |
2009 | return 0; |
2010 | |
2011 | err_init_one: |
2012 | mlx5_pci_close(dev); |
2013 | pci_init_err: |
2014 | mlx5_mdev_uninit(dev); |
2015 | mdev_init_err: |
2016 | mlx5_adev_idx_free(idx: dev->priv.adev_idx); |
2017 | adev_init_err: |
2018 | mlx5_devlink_free(devlink); |
2019 | |
2020 | return err; |
2021 | } |
2022 | |
2023 | static void remove_one(struct pci_dev *pdev) |
2024 | { |
2025 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2026 | struct devlink *devlink = priv_to_devlink(priv: dev); |
2027 | |
2028 | set_bit(nr: MLX5_BREAK_FW_WAIT, addr: &dev->intf_state); |
2029 | mlx5_drain_fw_reset(dev); |
2030 | mlx5_drain_health_wq(dev); |
2031 | mlx5_sriov_disable(pdev, num_vf_change: false); |
2032 | mlx5_uninit_one(dev); |
2033 | mlx5_pci_close(dev); |
2034 | mlx5_mdev_uninit(dev); |
2035 | mlx5_adev_idx_free(idx: dev->priv.adev_idx); |
2036 | mlx5_devlink_free(devlink); |
2037 | } |
2038 | |
2039 | #define mlx5_pci_trace(dev, fmt, ...) ({ \ |
2040 | struct mlx5_core_dev *__dev = (dev); \ |
2041 | mlx5_core_info(__dev, "%s Device state = %d health sensors: %d pci_status: %d. " fmt, \ |
2042 | __func__, __dev->state, mlx5_health_check_fatal_sensors(__dev), \ |
2043 | __dev->pci_status, ##__VA_ARGS__); \ |
2044 | }) |
2045 | |
2046 | static const char *result2str(enum pci_ers_result result) |
2047 | { |
2048 | return result == PCI_ERS_RESULT_NEED_RESET ? "need reset": |
2049 | result == PCI_ERS_RESULT_DISCONNECT ? "disconnect": |
2050 | result == PCI_ERS_RESULT_RECOVERED ? "recovered": |
2051 | "unknown"; |
2052 | } |
2053 | |
2054 | static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, |
2055 | pci_channel_state_t state) |
2056 | { |
2057 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2058 | enum pci_ers_result res; |
2059 | |
2060 | mlx5_pci_trace(dev, "Enter, pci channel state = %d\n", state); |
2061 | |
2062 | mlx5_enter_error_state(dev, force: false); |
2063 | mlx5_error_sw_reset(dev); |
2064 | mlx5_unload_one(dev, suspend: false); |
2065 | mlx5_drain_health_wq(dev); |
2066 | mlx5_pci_disable_device(dev); |
2067 | |
2068 | res = state == pci_channel_io_perm_failure ? |
2069 | PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; |
2070 | |
2071 | mlx5_core_info(dev, "%s Device state = %d pci_status: %d. Exit, result = %d, %s\n", |
2072 | __func__, dev->state, dev->pci_status, res, result2str(res)); |
2073 | return res; |
2074 | } |
2075 | |
2076 | /* wait for the device to show vital signs by waiting |
2077 | * for the health counter to start counting. |
2078 | */ |
2079 | static int wait_vital(struct pci_dev *pdev) |
2080 | { |
2081 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2082 | struct mlx5_core_health *health = &dev->priv.health; |
2083 | const int niter = 100; |
2084 | u32 last_count = 0; |
2085 | u32 count; |
2086 | int i; |
2087 | |
2088 | for (i = 0; i < niter; i++) { |
2089 | count = ioread32be(health->health_counter); |
2090 | if (count && count != 0xffffffff) { |
2091 | if (last_count && last_count != count) { |
2092 | mlx5_core_info(dev, |
2093 | "wait vital counter value 0x%x after %d iterations\n", |
2094 | count, i); |
2095 | return 0; |
2096 | } |
2097 | last_count = count; |
2098 | } |
2099 | msleep(msecs: 50); |
2100 | } |
2101 | |
2102 | return -ETIMEDOUT; |
2103 | } |
2104 | |
2105 | static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev) |
2106 | { |
2107 | enum pci_ers_result res = PCI_ERS_RESULT_DISCONNECT; |
2108 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2109 | int err; |
2110 | |
2111 | mlx5_core_info(dev, "%s Device state = %d pci_status: %d. Enter\n", |
2112 | __func__, dev->state, dev->pci_status); |
2113 | |
2114 | err = mlx5_pci_enable_device(dev); |
2115 | if (err) { |
2116 | mlx5_core_err(dev, "%s: mlx5_pci_enable_device failed with error code: %d\n", |
2117 | __func__, err); |
2118 | goto out; |
2119 | } |
2120 | |
2121 | pci_set_master(dev: pdev); |
2122 | pci_restore_state(dev: pdev); |
2123 | pci_save_state(dev: pdev); |
2124 | |
2125 | err = wait_vital(pdev); |
2126 | if (err) { |
2127 | mlx5_core_err(dev, "%s: wait vital failed with error code: %d\n", |
2128 | __func__, err); |
2129 | goto out; |
2130 | } |
2131 | |
2132 | res = PCI_ERS_RESULT_RECOVERED; |
2133 | out: |
2134 | mlx5_core_info(dev, "%s Device state = %d pci_status: %d. Exit, err = %d, result = %d, %s\n", |
2135 | __func__, dev->state, dev->pci_status, err, res, result2str(res)); |
2136 | return res; |
2137 | } |
2138 | |
2139 | static void mlx5_pci_resume(struct pci_dev *pdev) |
2140 | { |
2141 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2142 | int err; |
2143 | |
2144 | mlx5_pci_trace(dev, "Enter, loading driver..\n"); |
2145 | |
2146 | err = mlx5_load_one(dev, recovery: false); |
2147 | |
2148 | if (!err) |
2149 | devlink_health_reporter_state_update(reporter: dev->priv.health.fw_fatal_reporter, |
2150 | state: DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); |
2151 | |
2152 | mlx5_pci_trace(dev, "Done, err = %d, device %s\n", err, |
2153 | !err ? "recovered": "Failed"); |
2154 | } |
2155 | |
2156 | static const struct pci_error_handlers mlx5_err_handler = { |
2157 | .error_detected = mlx5_pci_err_detected, |
2158 | .slot_reset = mlx5_pci_slot_reset, |
2159 | .resume = mlx5_pci_resume |
2160 | }; |
2161 | |
2162 | static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) |
2163 | { |
2164 | bool fast_teardown = false, force_teardown = false; |
2165 | int ret = 1; |
2166 | |
2167 | fast_teardown = MLX5_CAP_GEN(dev, fast_teardown); |
2168 | force_teardown = MLX5_CAP_GEN(dev, force_teardown); |
2169 | |
2170 | mlx5_core_dbg(dev, "force teardown firmware support=%d\n", force_teardown); |
2171 | mlx5_core_dbg(dev, "fast teardown firmware support=%d\n", fast_teardown); |
2172 | |
2173 | if (!fast_teardown && !force_teardown) |
2174 | return -EOPNOTSUPP; |
2175 | |
2176 | if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { |
2177 | mlx5_core_dbg(dev, "Device in internal error state, giving up\n"); |
2178 | return -EAGAIN; |
2179 | } |
2180 | |
2181 | /* Panic tear down fw command will stop the PCI bus communication |
2182 | * with the HCA, so the health poll is no longer needed. |
2183 | */ |
2184 | mlx5_stop_health_poll(dev, disable_health: false); |
2185 | |
2186 | ret = mlx5_cmd_fast_teardown_hca(dev); |
2187 | if (!ret) |
2188 | goto succeed; |
2189 | |
2190 | ret = mlx5_cmd_force_teardown_hca(dev); |
2191 | if (!ret) |
2192 | goto succeed; |
2193 | |
2194 | mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret); |
2195 | mlx5_start_health_poll(dev); |
2196 | return ret; |
2197 | |
2198 | succeed: |
2199 | mlx5_enter_error_state(dev, force: true); |
2200 | |
2201 | /* Some platforms requiring freeing the IRQ's in the shutdown |
2202 | * flow. If they aren't freed they can't be allocated after |
2203 | * kexec. There is no need to cleanup the mlx5_core software |
2204 | * contexts. |
2205 | */ |
2206 | mlx5_core_eq_free_irqs(dev); |
2207 | |
2208 | return 0; |
2209 | } |
2210 | |
2211 | static void shutdown(struct pci_dev *pdev) |
2212 | { |
2213 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2214 | int err; |
2215 | |
2216 | mlx5_core_info(dev, "Shutdown was called\n"); |
2217 | set_bit(nr: MLX5_BREAK_FW_WAIT, addr: &dev->intf_state); |
2218 | mlx5_drain_health_wq(dev); |
2219 | err = mlx5_try_fast_unload(dev); |
2220 | if (err) |
2221 | mlx5_unload_one(dev, suspend: false); |
2222 | mlx5_pci_disable_device(dev); |
2223 | } |
2224 | |
2225 | static int mlx5_suspend(struct pci_dev *pdev, pm_message_t state) |
2226 | { |
2227 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2228 | |
2229 | mlx5_unload_one(dev, suspend: true); |
2230 | |
2231 | return 0; |
2232 | } |
2233 | |
2234 | static int mlx5_resume(struct pci_dev *pdev) |
2235 | { |
2236 | struct mlx5_core_dev *dev = pci_get_drvdata(pdev); |
2237 | |
2238 | return mlx5_load_one(dev, recovery: false); |
2239 | } |
2240 | |
2241 | static const struct pci_device_id mlx5_core_pci_table[] = { |
2242 | { PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTIB) }, |
2243 | { PCI_VDEVICE(MELLANOX, 0x1012), .vendor: MLX5_PCI_DEV_IS_VF}, /* Connect-IB VF */ |
2244 | { PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTX4) }, |
2245 | { PCI_VDEVICE(MELLANOX, 0x1014), .vendor: MLX5_PCI_DEV_IS_VF}, /* ConnectX-4 VF */ |
2246 | { PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTX4_LX) }, |
2247 | { PCI_VDEVICE(MELLANOX, 0x1016), .vendor: MLX5_PCI_DEV_IS_VF}, /* ConnectX-4LX VF */ |
2248 | { PCI_VDEVICE(MELLANOX, 0x1017) }, /* ConnectX-5, PCIe 3.0 */ |
2249 | { PCI_VDEVICE(MELLANOX, 0x1018), .vendor: MLX5_PCI_DEV_IS_VF}, /* ConnectX-5 VF */ |
2250 | { PCI_VDEVICE(MELLANOX, 0x1019) }, /* ConnectX-5 Ex */ |
2251 | { PCI_VDEVICE(MELLANOX, 0x101a), .vendor: MLX5_PCI_DEV_IS_VF}, /* ConnectX-5 Ex VF */ |
2252 | { PCI_VDEVICE(MELLANOX, 0x101b) }, /* ConnectX-6 */ |
2253 | { PCI_VDEVICE(MELLANOX, 0x101c), .vendor: MLX5_PCI_DEV_IS_VF}, /* ConnectX-6 VF */ |
2254 | { PCI_VDEVICE(MELLANOX, 0x101d) }, /* ConnectX-6 Dx */ |
2255 | { PCI_VDEVICE(MELLANOX, 0x101e), .vendor: MLX5_PCI_DEV_IS_VF}, /* ConnectX Family mlx5Gen Virtual Function */ |
2256 | { PCI_VDEVICE(MELLANOX, 0x101f) }, /* ConnectX-6 LX */ |
2257 | { PCI_VDEVICE(MELLANOX, 0x1021) }, /* ConnectX-7 */ |
2258 | { PCI_VDEVICE(MELLANOX, 0x1023) }, /* ConnectX-8 */ |
2259 | { PCI_VDEVICE(MELLANOX, 0x1025) }, /* ConnectX-9 */ |
2260 | { PCI_VDEVICE(MELLANOX, 0xa2d2) }, /* BlueField integrated ConnectX-5 network controller */ |
2261 | { PCI_VDEVICE(MELLANOX, 0xa2d3), .vendor: MLX5_PCI_DEV_IS_VF}, /* BlueField integrated ConnectX-5 network controller VF */ |
2262 | { PCI_VDEVICE(MELLANOX, 0xa2d6) }, /* BlueField-2 integrated ConnectX-6 Dx network controller */ |
2263 | { PCI_VDEVICE(MELLANOX, 0xa2dc) }, /* BlueField-3 integrated ConnectX-7 network controller */ |
2264 | { PCI_VDEVICE(MELLANOX, 0xa2df) }, /* BlueField-4 integrated ConnectX-8 network controller */ |
2265 | { 0, } |
2266 | }; |
2267 | |
2268 | MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table); |
2269 | |
2270 | void mlx5_disable_device(struct mlx5_core_dev *dev) |
2271 | { |
2272 | mlx5_error_sw_reset(dev); |
2273 | mlx5_unload_one_devl_locked(dev, suspend: false); |
2274 | } |
2275 | |
2276 | int mlx5_recover_device(struct mlx5_core_dev *dev) |
2277 | { |
2278 | if (!mlx5_core_is_sf(dev)) { |
2279 | mlx5_pci_disable_device(dev); |
2280 | if (mlx5_pci_slot_reset(pdev: dev->pdev) != PCI_ERS_RESULT_RECOVERED) |
2281 | return -EIO; |
2282 | } |
2283 | |
2284 | return mlx5_load_one_devl_locked(dev, recovery: true); |
2285 | } |
2286 | |
2287 | static struct pci_driver mlx5_core_driver = { |
2288 | .name = KBUILD_MODNAME, |
2289 | .id_table = mlx5_core_pci_table, |
2290 | .probe = probe_one, |
2291 | .remove = remove_one, |
2292 | .suspend = mlx5_suspend, |
2293 | .resume = mlx5_resume, |
2294 | .shutdown = shutdown, |
2295 | .err_handler = &mlx5_err_handler, |
2296 | .sriov_configure = mlx5_core_sriov_configure, |
2297 | .sriov_get_vf_total_msix = mlx5_sriov_get_vf_total_msix, |
2298 | .sriov_set_msix_vec_count = mlx5_core_sriov_set_msix_vec_count, |
2299 | }; |
2300 | |
2301 | /** |
2302 | * mlx5_vf_get_core_dev - Get the mlx5 core device from a given VF PCI device if |
2303 | * mlx5_core is its driver. |
2304 | * @pdev: The associated PCI device. |
2305 | * |
2306 | * Upon return the interface state lock stay held to let caller uses it safely. |
2307 | * Caller must ensure to use the returned mlx5 device for a narrow window |
2308 | * and put it back with mlx5_vf_put_core_dev() immediately once usage was over. |
2309 | * |
2310 | * Return: Pointer to the associated mlx5_core_dev or NULL. |
2311 | */ |
2312 | struct mlx5_core_dev *mlx5_vf_get_core_dev(struct pci_dev *pdev) |
2313 | { |
2314 | struct mlx5_core_dev *mdev; |
2315 | |
2316 | mdev = pci_iov_get_pf_drvdata(dev: pdev, pf_driver: &mlx5_core_driver); |
2317 | if (IS_ERR(ptr: mdev)) |
2318 | return NULL; |
2319 | |
2320 | mutex_lock(&mdev->intf_state_mutex); |
2321 | if (!test_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state)) { |
2322 | mutex_unlock(lock: &mdev->intf_state_mutex); |
2323 | return NULL; |
2324 | } |
2325 | |
2326 | return mdev; |
2327 | } |
2328 | EXPORT_SYMBOL(mlx5_vf_get_core_dev); |
2329 | |
2330 | /** |
2331 | * mlx5_vf_put_core_dev - Put the mlx5 core device back. |
2332 | * @mdev: The mlx5 core device. |
2333 | * |
2334 | * Upon return the interface state lock is unlocked and caller should not |
2335 | * access the mdev any more. |
2336 | */ |
2337 | void mlx5_vf_put_core_dev(struct mlx5_core_dev *mdev) |
2338 | { |
2339 | mutex_unlock(lock: &mdev->intf_state_mutex); |
2340 | } |
2341 | EXPORT_SYMBOL(mlx5_vf_put_core_dev); |
2342 | |
2343 | static void mlx5_core_verify_params(void) |
2344 | { |
2345 | if (prof_sel >= ARRAY_SIZE(profile)) { |
2346 | pr_warn("mlx5_core: WARNING: Invalid module parameter prof_sel %d, valid range 0-%zu, changing back to default(%d)\n", |
2347 | prof_sel, |
2348 | ARRAY_SIZE(profile) - 1, |
2349 | MLX5_DEFAULT_PROF); |
2350 | prof_sel = MLX5_DEFAULT_PROF; |
2351 | } |
2352 | } |
2353 | |
2354 | static int __init mlx5_init(void) |
2355 | { |
2356 | int err; |
2357 | |
2358 | WARN_ONCE(strcmp(MLX5_ADEV_NAME, KBUILD_MODNAME), |
2359 | "mlx5_core name not in sync with kernel module name"); |
2360 | |
2361 | get_random_bytes(buf: &sw_owner_id, len: sizeof(sw_owner_id)); |
2362 | |
2363 | mlx5_core_verify_params(); |
2364 | mlx5_register_debugfs(); |
2365 | |
2366 | err = mlx5e_init(); |
2367 | if (err) |
2368 | goto err_debug; |
2369 | |
2370 | err = mlx5_sf_driver_register(); |
2371 | if (err) |
2372 | goto err_sf; |
2373 | |
2374 | err = pci_register_driver(&mlx5_core_driver); |
2375 | if (err) |
2376 | goto err_pci; |
2377 | |
2378 | return 0; |
2379 | |
2380 | err_pci: |
2381 | mlx5_sf_driver_unregister(); |
2382 | err_sf: |
2383 | mlx5e_cleanup(); |
2384 | err_debug: |
2385 | mlx5_unregister_debugfs(); |
2386 | return err; |
2387 | } |
2388 | |
2389 | static void __exit mlx5_cleanup(void) |
2390 | { |
2391 | pci_unregister_driver(dev: &mlx5_core_driver); |
2392 | mlx5_sf_driver_unregister(); |
2393 | mlx5e_cleanup(); |
2394 | mlx5_unregister_debugfs(); |
2395 | } |
2396 | |
2397 | module_init(mlx5_init); |
2398 | module_exit(mlx5_cleanup); |
2399 |
Definitions
- mlx5_core_debug_mask
- prof_sel
- sw_owner_id
- sw_vhca_ida
- profile
- wait_fw_init
- mlx5_set_driver_version
- set_dma_caps
- mlx5_pci_enable_device
- mlx5_pci_disable_device
- request_bar
- release_bar
- mlx5_reg_host_endianness
- to_fw_pkey_sz
- mlx5_core_uplink_netdev_set
- mlx5_core_uplink_netdev_event_replay
- mlx5_core_mp_event_replay
- mlx5_core_get_caps_mode
- mlx5_core_get_caps
- set_caps
- handle_hca_cap_atomic
- handle_hca_cap_odp
- max_uc_list_get_devlink_param
- mlx5_is_roce_on
- handle_hca_cap_2
- handle_hca_cap
- is_roce_fw_disabled
- handle_hca_cap_roce
- handle_hca_cap_port_selection
- set_hca_cap
- set_hca_ctrl
- mlx5_core_set_hca_defaults
- mlx5_core_enable_hca
- mlx5_core_disable_hca
- mlx5_core_set_issi
- mlx5_pci_init
- mlx5_pci_close
- mlx5_register_hca_devcom_comp
- mlx5_unregister_hca_devcom_comp
- mlx5_init_once
- mlx5_cleanup_once
- mlx5_function_enable
- mlx5_function_disable
- mlx5_function_open
- mlx5_function_close
- mlx5_function_setup
- mlx5_function_teardown
- mlx5_load
- mlx5_unload
- mlx5_init_one_devl_locked
- mlx5_init_one
- mlx5_uninit_one
- mlx5_load_one_devl_locked
- mlx5_load_one
- mlx5_unload_one_devl_locked
- mlx5_unload_one
- mlx5_query_hca_caps_light
- mlx5_init_one_light
- mlx5_uninit_one_light
- mlx5_unload_one_light
- types
- mlx5_hca_caps_free
- mlx5_hca_caps_alloc
- vhca_id_show
- mlx5_mdev_init
- mlx5_mdev_uninit
- probe_one
- remove_one
- result2str
- mlx5_pci_err_detected
- wait_vital
- mlx5_pci_slot_reset
- mlx5_pci_resume
- mlx5_err_handler
- mlx5_try_fast_unload
- shutdown
- mlx5_suspend
- mlx5_resume
- mlx5_core_pci_table
- mlx5_disable_device
- mlx5_recover_device
- mlx5_core_driver
- mlx5_vf_get_core_dev
- mlx5_vf_put_core_dev
- mlx5_core_verify_params
- mlx5_init
Improve your Profiling and Debugging skills
Find out more