1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2019 Mellanox Technologies */
3
4#include <linux/mlx5/driver.h>
5#include "mlx5_core.h"
6#include "lib/pci_vsc.h"
7#include "lib/mlx5.h"
8
9#define BAD_ACCESS 0xBADACCE5
10#define MLX5_PROTECTED_CR_SCAN_CRSPACE 0x7
11
12static bool mlx5_crdump_enabled(struct mlx5_core_dev *dev)
13{
14 return !!dev->priv.health.crdump_size;
15}
16
17static int mlx5_crdump_fill(struct mlx5_core_dev *dev, u32 *cr_data)
18{
19 u32 crdump_size = dev->priv.health.crdump_size;
20 int i, ret;
21
22 for (i = 0; i < (crdump_size / 4); i++)
23 cr_data[i] = BAD_ACCESS;
24
25 ret = mlx5_vsc_gw_read_block_fast(dev, data: cr_data, length: crdump_size);
26 if (ret <= 0) {
27 if (ret == 0)
28 return -EIO;
29 return ret;
30 }
31
32 if (crdump_size != ret) {
33 mlx5_core_warn(dev, "failed to read full dump, read %d out of %u\n",
34 ret, crdump_size);
35 return -EINVAL;
36 }
37
38 return 0;
39}
40
41int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data)
42{
43 int ret;
44
45 if (!mlx5_crdump_enabled(dev))
46 return -ENODEV;
47
48 ret = mlx5_vsc_gw_lock(dev);
49 if (ret) {
50 mlx5_core_warn(dev, "crdump: failed to lock vsc gw err %d\n",
51 ret);
52 return ret;
53 }
54 /* Verify no other PF is running cr-dump or sw reset */
55 ret = mlx5_vsc_sem_set_space(dev, space: MLX5_SEMAPHORE_SW_RESET,
56 state: MLX5_VSC_LOCK);
57 if (ret) {
58 if (ret == -EBUSY)
59 mlx5_core_info(dev, "SW reset semaphore is already in use\n");
60 else
61 mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
62 goto unlock_gw;
63 }
64
65 ret = mlx5_vsc_gw_set_space(dev, space: MLX5_VSC_SPACE_SCAN_CRSPACE, NULL);
66 if (ret)
67 goto unlock_sem;
68
69 ret = mlx5_crdump_fill(dev, cr_data);
70
71unlock_sem:
72 mlx5_vsc_sem_set_space(dev, space: MLX5_SEMAPHORE_SW_RESET, state: MLX5_VSC_UNLOCK);
73unlock_gw:
74 mlx5_vsc_gw_unlock(dev);
75 return ret;
76}
77
78int mlx5_crdump_enable(struct mlx5_core_dev *dev)
79{
80 struct mlx5_priv *priv = &dev->priv;
81 u32 space_size;
82 int ret;
83
84 if (!mlx5_core_is_pf(dev) || !mlx5_vsc_accessible(dev) ||
85 mlx5_crdump_enabled(dev))
86 return 0;
87
88 ret = mlx5_vsc_gw_lock(dev);
89 if (ret)
90 return ret;
91
92 /* Check if space is supported and get space size */
93 ret = mlx5_vsc_gw_set_space(dev, space: MLX5_VSC_SPACE_SCAN_CRSPACE,
94 ret_space_size: &space_size);
95 if (ret) {
96 /* Unlock and mask error since space is not supported */
97 mlx5_vsc_gw_unlock(dev);
98 return 0;
99 }
100
101 if (!space_size) {
102 mlx5_core_warn(dev, "Invalid Crspace size, zero\n");
103 mlx5_vsc_gw_unlock(dev);
104 return -EINVAL;
105 }
106
107 ret = mlx5_vsc_gw_unlock(dev);
108 if (ret)
109 return ret;
110
111 priv->health.crdump_size = space_size;
112 return 0;
113}
114
115void mlx5_crdump_disable(struct mlx5_core_dev *dev)
116{
117 dev->priv.health.crdump_size = 0;
118}
119

source code of linux/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c