1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies. */
3
4 #include "rsc_dump.h"
5 #include "lib/mlx5.h"
6
7 #define MLX5_SGMT_TYPE(SGMT) MLX5_SGMT_TYPE_##SGMT
8 #define MLX5_SGMT_STR_ASSING(SGMT)[MLX5_SGMT_TYPE(SGMT)] = #SGMT
9 static const char *const mlx5_rsc_sgmt_name[] = {
10 MLX5_SGMT_STR_ASSING(HW_CQPC),
11 MLX5_SGMT_STR_ASSING(HW_SQPC),
12 MLX5_SGMT_STR_ASSING(HW_RQPC),
13 MLX5_SGMT_STR_ASSING(FULL_SRQC),
14 MLX5_SGMT_STR_ASSING(FULL_CQC),
15 MLX5_SGMT_STR_ASSING(FULL_EQC),
16 MLX5_SGMT_STR_ASSING(FULL_QPC),
17 MLX5_SGMT_STR_ASSING(SND_BUFF),
18 MLX5_SGMT_STR_ASSING(RCV_BUFF),
19 MLX5_SGMT_STR_ASSING(SRQ_BUFF),
20 MLX5_SGMT_STR_ASSING(CQ_BUFF),
21 MLX5_SGMT_STR_ASSING(EQ_BUFF),
22 MLX5_SGMT_STR_ASSING(SX_SLICE),
23 MLX5_SGMT_STR_ASSING(SX_SLICE_ALL),
24 MLX5_SGMT_STR_ASSING(RDB),
25 MLX5_SGMT_STR_ASSING(RX_SLICE_ALL),
26 MLX5_SGMT_STR_ASSING(PRM_QUERY_QP),
27 MLX5_SGMT_STR_ASSING(PRM_QUERY_CQ),
28 MLX5_SGMT_STR_ASSING(PRM_QUERY_MKEY),
29 };
30
31 struct mlx5_rsc_dump {
32 u32 pdn;
33 u32 mkey;
34 u16 fw_segment_type[MLX5_SGMT_TYPE_NUM];
35 };
36
37 struct mlx5_rsc_dump_cmd {
38 u64 mem_size;
39 u8 cmd[MLX5_ST_SZ_BYTES(resource_dump)];
40 };
41
mlx5_rsc_dump_sgmt_get_by_name(char * name)42 static int mlx5_rsc_dump_sgmt_get_by_name(char *name)
43 {
44 int i;
45
46 for (i = 0; i < ARRAY_SIZE(mlx5_rsc_sgmt_name); i++)
47 if (!strcmp(name, mlx5_rsc_sgmt_name[i]))
48 return i;
49
50 return -EINVAL;
51 }
52
mlx5_rsc_dump_read_menu_sgmt(struct mlx5_rsc_dump * rsc_dump,struct page * page)53 static void mlx5_rsc_dump_read_menu_sgmt(struct mlx5_rsc_dump *rsc_dump, struct page *page)
54 {
55 void *data = page_address(page);
56 enum mlx5_sgmt_type sgmt_idx;
57 int num_of_items;
58 char *sgmt_name;
59 void *member;
60 void *menu;
61 int i;
62
63 menu = MLX5_ADDR_OF(menu_resource_dump_response, data, menu);
64 num_of_items = MLX5_GET(resource_dump_menu_segment, menu, num_of_records);
65
66 for (i = 0; i < num_of_items; i++) {
67 member = MLX5_ADDR_OF(resource_dump_menu_segment, menu, record[i]);
68 sgmt_name = MLX5_ADDR_OF(resource_dump_menu_record, member, segment_name);
69 sgmt_idx = mlx5_rsc_dump_sgmt_get_by_name(sgmt_name);
70 if (sgmt_idx == -EINVAL)
71 continue;
72 rsc_dump->fw_segment_type[sgmt_idx] = MLX5_GET(resource_dump_menu_record,
73 member, segment_type);
74 }
75 }
76
mlx5_rsc_dump_trigger(struct mlx5_core_dev * dev,struct mlx5_rsc_dump_cmd * cmd,struct page * page)77 static int mlx5_rsc_dump_trigger(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
78 struct page *page)
79 {
80 struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump;
81 struct device *ddev = mlx5_core_dma_dev(dev);
82 u32 out_seq_num;
83 u32 in_seq_num;
84 dma_addr_t dma;
85 int err;
86
87 dma = dma_map_page(ddev, page, 0, cmd->mem_size, DMA_FROM_DEVICE);
88 if (unlikely(dma_mapping_error(ddev, dma)))
89 return -ENOMEM;
90
91 in_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num);
92 MLX5_SET(resource_dump, cmd->cmd, mkey, rsc_dump->mkey);
93 MLX5_SET64(resource_dump, cmd->cmd, address, dma);
94
95 err = mlx5_core_access_reg(dev, cmd->cmd, sizeof(cmd->cmd), cmd->cmd,
96 sizeof(cmd->cmd), MLX5_REG_RESOURCE_DUMP, 0, 1);
97 if (err) {
98 mlx5_core_err(dev, "Resource dump: Failed to access err %d\n", err);
99 goto out;
100 }
101 out_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num);
102 if (out_seq_num && (in_seq_num + 1 != out_seq_num))
103 err = -EIO;
104 out:
105 dma_unmap_page(ddev, dma, cmd->mem_size, DMA_FROM_DEVICE);
106 return err;
107 }
108
mlx5_rsc_dump_cmd_create(struct mlx5_core_dev * dev,struct mlx5_rsc_key * key)109 struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev,
110 struct mlx5_rsc_key *key)
111 {
112 struct mlx5_rsc_dump_cmd *cmd;
113 int sgmt_type;
114
115 if (IS_ERR_OR_NULL(dev->rsc_dump))
116 return ERR_PTR(-EOPNOTSUPP);
117
118 sgmt_type = dev->rsc_dump->fw_segment_type[key->rsc];
119 if (!sgmt_type && key->rsc != MLX5_SGMT_TYPE_MENU)
120 return ERR_PTR(-EOPNOTSUPP);
121
122 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
123 if (!cmd) {
124 mlx5_core_err(dev, "Resource dump: Failed to allocate command\n");
125 return ERR_PTR(-ENOMEM);
126 }
127 MLX5_SET(resource_dump, cmd->cmd, segment_type, sgmt_type);
128 MLX5_SET(resource_dump, cmd->cmd, index1, key->index1);
129 MLX5_SET(resource_dump, cmd->cmd, index2, key->index2);
130 MLX5_SET(resource_dump, cmd->cmd, num_of_obj1, key->num_of_obj1);
131 MLX5_SET(resource_dump, cmd->cmd, num_of_obj2, key->num_of_obj2);
132 MLX5_SET(resource_dump, cmd->cmd, size, key->size);
133 cmd->mem_size = key->size;
134 return cmd;
135 }
136 EXPORT_SYMBOL(mlx5_rsc_dump_cmd_create);
137
mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd * cmd)138 void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd)
139 {
140 kfree(cmd);
141 }
142 EXPORT_SYMBOL(mlx5_rsc_dump_cmd_destroy);
143
mlx5_rsc_dump_next(struct mlx5_core_dev * dev,struct mlx5_rsc_dump_cmd * cmd,struct page * page,int * size)144 int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
145 struct page *page, int *size)
146 {
147 bool more_dump;
148 int err;
149
150 if (IS_ERR_OR_NULL(dev->rsc_dump))
151 return -EOPNOTSUPP;
152
153 err = mlx5_rsc_dump_trigger(dev, cmd, page);
154 if (err) {
155 mlx5_core_err(dev, "Resource dump: Failed to trigger dump, %d\n", err);
156 return err;
157 }
158 *size = MLX5_GET(resource_dump, cmd->cmd, size);
159 more_dump = MLX5_GET(resource_dump, cmd->cmd, more_dump);
160
161 return more_dump;
162 }
163 EXPORT_SYMBOL(mlx5_rsc_dump_next);
164
165 #define MLX5_RSC_DUMP_MENU_SEGMENT 0xffff
mlx5_rsc_dump_menu(struct mlx5_core_dev * dev)166 static int mlx5_rsc_dump_menu(struct mlx5_core_dev *dev)
167 {
168 struct mlx5_rsc_dump_cmd *cmd = NULL;
169 struct mlx5_rsc_key key = {};
170 struct page *page;
171 int size;
172 int err;
173
174 page = alloc_page(GFP_KERNEL);
175 if (!page)
176 return -ENOMEM;
177
178 key.rsc = MLX5_SGMT_TYPE_MENU;
179 key.size = PAGE_SIZE;
180 cmd = mlx5_rsc_dump_cmd_create(dev, &key);
181 if (IS_ERR(cmd)) {
182 err = PTR_ERR(cmd);
183 goto free_page;
184 }
185 MLX5_SET(resource_dump, cmd->cmd, segment_type, MLX5_RSC_DUMP_MENU_SEGMENT);
186
187 do {
188 err = mlx5_rsc_dump_next(dev, cmd, page, &size);
189 if (err < 0)
190 goto destroy_cmd;
191
192 mlx5_rsc_dump_read_menu_sgmt(dev->rsc_dump, page);
193
194 } while (err > 0);
195
196 destroy_cmd:
197 mlx5_rsc_dump_cmd_destroy(cmd);
198 free_page:
199 __free_page(page);
200
201 return err;
202 }
203
mlx5_rsc_dump_create_mkey(struct mlx5_core_dev * mdev,u32 pdn,u32 * mkey)204 static int mlx5_rsc_dump_create_mkey(struct mlx5_core_dev *mdev, u32 pdn,
205 u32 *mkey)
206 {
207 int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
208 void *mkc;
209 u32 *in;
210 int err;
211
212 in = kvzalloc(inlen, GFP_KERNEL);
213 if (!in)
214 return -ENOMEM;
215
216 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
217 MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
218 MLX5_SET(mkc, mkc, lw, 1);
219 MLX5_SET(mkc, mkc, lr, 1);
220
221 MLX5_SET(mkc, mkc, pd, pdn);
222 MLX5_SET(mkc, mkc, length64, 1);
223 MLX5_SET(mkc, mkc, qpn, 0xffffff);
224
225 err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
226
227 kvfree(in);
228 return err;
229 }
230
mlx5_rsc_dump_create(struct mlx5_core_dev * dev)231 struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev)
232 {
233 struct mlx5_rsc_dump *rsc_dump;
234
235 if (!MLX5_CAP_DEBUG(dev, resource_dump)) {
236 mlx5_core_dbg(dev, "Resource dump: capability not present\n");
237 return NULL;
238 }
239 rsc_dump = kzalloc(sizeof(*rsc_dump), GFP_KERNEL);
240 if (!rsc_dump)
241 return ERR_PTR(-ENOMEM);
242
243 return rsc_dump;
244 }
245
mlx5_rsc_dump_destroy(struct mlx5_core_dev * dev)246 void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev)
247 {
248 if (IS_ERR_OR_NULL(dev->rsc_dump))
249 return;
250 kfree(dev->rsc_dump);
251 }
252
mlx5_rsc_dump_init(struct mlx5_core_dev * dev)253 int mlx5_rsc_dump_init(struct mlx5_core_dev *dev)
254 {
255 struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump;
256 int err;
257
258 if (IS_ERR_OR_NULL(dev->rsc_dump))
259 return 0;
260
261 err = mlx5_core_alloc_pd(dev, &rsc_dump->pdn);
262 if (err) {
263 mlx5_core_warn(dev, "Resource dump: Failed to allocate PD %d\n", err);
264 return err;
265 }
266 err = mlx5_rsc_dump_create_mkey(dev, rsc_dump->pdn, &rsc_dump->mkey);
267 if (err) {
268 mlx5_core_err(dev, "Resource dump: Failed to create mkey, %d\n", err);
269 goto free_pd;
270 }
271 err = mlx5_rsc_dump_menu(dev);
272 if (err) {
273 mlx5_core_err(dev, "Resource dump: Failed to read menu, %d\n", err);
274 goto destroy_mkey;
275 }
276 return err;
277
278 destroy_mkey:
279 mlx5_core_destroy_mkey(dev, rsc_dump->mkey);
280 free_pd:
281 mlx5_core_dealloc_pd(dev, rsc_dump->pdn);
282 return err;
283 }
284
mlx5_rsc_dump_cleanup(struct mlx5_core_dev * dev)285 void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev)
286 {
287 if (IS_ERR_OR_NULL(dev->rsc_dump))
288 return;
289
290 mlx5_core_destroy_mkey(dev, dev->rsc_dump->mkey);
291 mlx5_core_dealloc_pd(dev, dev->rsc_dump->pdn);
292 }
293