1 /*-
2 * Copyright (c) 2018, 2019 Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include "opt_rss.h"
27 #include "opt_ratelimit.h"
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/conf.h>
32 #include <sys/fcntl.h>
33 #include <dev/mlx5/driver.h>
34 #include <dev/mlx5/device.h>
35 #include <dev/mlx5/port.h>
36 #include <dev/mlx5/mlx5_core/mlx5_core.h>
37 #include <dev/mlx5/mlx5io.h>
38 #include <dev/mlx5/diagnostics.h>
39
40 static MALLOC_DEFINE(M_MLX5_DUMP, "MLX5DUMP", "MLX5 Firmware dump");
41
42 static unsigned
mlx5_fwdump_getsize(const struct mlx5_crspace_regmap * rege)43 mlx5_fwdump_getsize(const struct mlx5_crspace_regmap *rege)
44 {
45 const struct mlx5_crspace_regmap *r;
46 unsigned sz;
47
48 for (sz = 0, r = rege; r->cnt != 0; r++)
49 sz += r->cnt;
50 return (sz);
51 }
52
53 static void
mlx5_fwdump_destroy_dd(struct mlx5_core_dev * mdev)54 mlx5_fwdump_destroy_dd(struct mlx5_core_dev *mdev)
55 {
56
57 mtx_assert(&mdev->dump_lock, MA_OWNED);
58 free(mdev->dump_data, M_MLX5_DUMP);
59 mdev->dump_data = NULL;
60 }
61
62 static int mlx5_fw_dump_enable = 1;
63 SYSCTL_INT(_hw_mlx5, OID_AUTO, fw_dump_enable, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
64 &mlx5_fw_dump_enable, 0,
65 "Enable fw dump setup and op");
66
67 void
mlx5_fwdump_prep(struct mlx5_core_dev * mdev)68 mlx5_fwdump_prep(struct mlx5_core_dev *mdev)
69 {
70 device_t dev;
71 int error, vsc_addr;
72 unsigned i, sz;
73 u32 addr, in, out, next_addr;
74
75 mdev->dump_data = NULL;
76
77 TUNABLE_INT_FETCH("hw.mlx5.fw_dump_enable", &mlx5_fw_dump_enable);
78 if (!mlx5_fw_dump_enable) {
79 mlx5_core_warn(mdev,
80 "Firmware dump administratively prohibited\n");
81 return;
82 }
83
84 DROP_GIANT();
85
86 error = mlx5_vsc_find_cap(mdev);
87 if (error != 0) {
88 /* Inability to create a firmware dump is not fatal. */
89 mlx5_core_warn(mdev,
90 "Unable to find vendor-specific capability, error %d\n",
91 error);
92 goto pickup_g;
93 }
94 error = mlx5_vsc_lock(mdev);
95 if (error != 0)
96 goto pickup_g;
97 error = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_SCAN_CRSPACE);
98 if (error != 0) {
99 mlx5_core_warn(mdev, "VSC scan space is not supported\n");
100 goto unlock_vsc;
101 }
102 dev = mdev->pdev->dev.bsddev;
103 vsc_addr = mdev->vsc_addr;
104 if (vsc_addr == 0) {
105 mlx5_core_warn(mdev, "Cannot read VSC, no address\n");
106 goto unlock_vsc;
107 }
108
109 in = 0;
110 for (sz = 1, addr = 0;;) {
111 MLX5_VSC_SET(vsc_addr, &in, address, addr);
112 pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
113 error = mlx5_vsc_wait_on_flag(mdev, 1);
114 if (error != 0) {
115 mlx5_core_warn(mdev,
116 "Failed waiting for read complete flag, error %d addr %#x\n",
117 error, addr);
118 goto unlock_vsc;
119 }
120 pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4);
121 out = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4);
122 next_addr = MLX5_VSC_GET(vsc_addr, &out, address);
123 if (next_addr == 0 || next_addr == addr)
124 break;
125 if (next_addr != addr + 4)
126 sz++;
127 addr = next_addr;
128 }
129 if (sz == 1) {
130 mlx5_core_warn(mdev, "no output from scan space\n");
131 goto unlock_vsc;
132 }
133
134 /*
135 * We add a sentinel element at the end of the array to
136 * terminate the read loop in mlx5_fwdump(), so allocate sz + 1.
137 */
138 mdev->dump_rege = malloc((sz + 1) * sizeof(struct mlx5_crspace_regmap),
139 M_MLX5_DUMP, M_WAITOK | M_ZERO);
140
141 for (i = 0, addr = 0;;) {
142 mdev->dump_rege[i].cnt++;
143 MLX5_VSC_SET(vsc_addr, &in, address, addr);
144 pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
145 error = mlx5_vsc_wait_on_flag(mdev, 1);
146 if (error != 0) {
147 mlx5_core_warn(mdev,
148 "Failed waiting for read complete flag, error %d addr %#x\n",
149 error, addr);
150 free(mdev->dump_rege, M_MLX5_DUMP);
151 mdev->dump_rege = NULL;
152 goto unlock_vsc;
153 }
154 pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4);
155 out = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4);
156 next_addr = MLX5_VSC_GET(vsc_addr, &out, address);
157 if (next_addr == 0 || next_addr == addr)
158 break;
159 if (next_addr != addr + 4) {
160 if (++i == sz) {
161 mlx5_core_err(mdev,
162 "Inconsistent hw crspace reads (1): sz %u i %u addr %#lx",
163 sz, i, (unsigned long)addr);
164 break;
165 }
166 mdev->dump_rege[i].addr = next_addr;
167 }
168 addr = next_addr;
169 }
170 /* i == sz case already reported by loop above */
171 if (i + 1 != sz && i != sz) {
172 mlx5_core_err(mdev,
173 "Inconsistent hw crspace reads (2): sz %u i %u addr %#lx",
174 sz, i, (unsigned long)addr);
175 }
176
177 mdev->dump_size = mlx5_fwdump_getsize(mdev->dump_rege);
178 mdev->dump_data = malloc(mdev->dump_size * sizeof(uint32_t),
179 M_MLX5_DUMP, M_WAITOK | M_ZERO);
180 mdev->dump_valid = false;
181 mdev->dump_copyout = false;
182
183 unlock_vsc:
184 mlx5_vsc_unlock(mdev);
185 pickup_g:
186 PICKUP_GIANT();
187 }
188
189 int
mlx5_fwdump(struct mlx5_core_dev * mdev)190 mlx5_fwdump(struct mlx5_core_dev *mdev)
191 {
192 const struct mlx5_crspace_regmap *r;
193 uint32_t i, ri;
194 int error;
195
196 mlx5_core_info(mdev, "Issuing FW dump\n");
197 mtx_lock(&mdev->dump_lock);
198 if (mdev->dump_data == NULL) {
199 error = EIO;
200 goto failed;
201 }
202 if (mdev->dump_valid) {
203 /* only one dump */
204 mlx5_core_warn(mdev,
205 "Only one FW dump can be captured aborting FW dump\n");
206 error = EEXIST;
207 goto failed;
208 }
209
210 /* mlx5_vsc already warns, be silent. */
211 error = mlx5_vsc_lock(mdev);
212 if (error != 0)
213 goto failed;
214 error = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_PROTECTED_CRSPACE);
215 if (error != 0)
216 goto unlock_vsc;
217 for (i = 0, r = mdev->dump_rege; r->cnt != 0; r++) {
218 for (ri = 0; ri < r->cnt; ri++) {
219 error = mlx5_vsc_read(mdev, r->addr + ri * 4,
220 &mdev->dump_data[i]);
221 if (error != 0)
222 goto unlock_vsc;
223 i++;
224 }
225 }
226 mdev->dump_valid = true;
227 unlock_vsc:
228 mlx5_vsc_unlock(mdev);
229 failed:
230 mtx_unlock(&mdev->dump_lock);
231 return (error);
232 }
233
234 void
mlx5_fwdump_clean(struct mlx5_core_dev * mdev)235 mlx5_fwdump_clean(struct mlx5_core_dev *mdev)
236 {
237
238 mtx_lock(&mdev->dump_lock);
239 while (mdev->dump_copyout)
240 msleep(&mdev->dump_copyout, &mdev->dump_lock, 0, "mlx5fwc", 0);
241 mlx5_fwdump_destroy_dd(mdev);
242 mtx_unlock(&mdev->dump_lock);
243 free(mdev->dump_rege, M_MLX5_DUMP);
244 }
245
246 static int
mlx5_fwdump_reset(struct mlx5_core_dev * mdev)247 mlx5_fwdump_reset(struct mlx5_core_dev *mdev)
248 {
249 int error;
250
251 error = 0;
252 mtx_lock(&mdev->dump_lock);
253 if (mdev->dump_data != NULL) {
254 while (mdev->dump_copyout) {
255 msleep(&mdev->dump_copyout, &mdev->dump_lock,
256 0, "mlx5fwr", 0);
257 }
258 mdev->dump_valid = false;
259 } else {
260 error = ENOENT;
261 }
262 mtx_unlock(&mdev->dump_lock);
263 return (error);
264 }
265
266 static int
mlx5_dbsf_to_core(const struct mlx5_tool_addr * devaddr,struct mlx5_core_dev ** mdev)267 mlx5_dbsf_to_core(const struct mlx5_tool_addr *devaddr,
268 struct mlx5_core_dev **mdev)
269 {
270 device_t dev;
271 struct pci_dev *pdev;
272
273 dev = pci_find_dbsf(devaddr->domain, devaddr->bus, devaddr->slot,
274 devaddr->func);
275 if (dev == NULL)
276 return (ENOENT);
277 if (device_get_devclass(dev) != mlx5_core_driver.bsdclass)
278 return (EINVAL);
279 pdev = device_get_softc(dev);
280 *mdev = pci_get_drvdata(pdev);
281 if (*mdev == NULL)
282 return (ENOENT);
283 return (0);
284 }
285
286 static int
mlx5_fwdump_copyout(struct mlx5_core_dev * mdev,struct mlx5_fwdump_get * fwg)287 mlx5_fwdump_copyout(struct mlx5_core_dev *mdev, struct mlx5_fwdump_get *fwg)
288 {
289 const struct mlx5_crspace_regmap *r;
290 struct mlx5_fwdump_reg rv, *urv;
291 uint32_t i, ri;
292 int error;
293
294 mtx_lock(&mdev->dump_lock);
295 if (mdev->dump_data == NULL) {
296 mtx_unlock(&mdev->dump_lock);
297 return (ENOENT);
298 }
299 if (fwg->buf == NULL) {
300 fwg->reg_filled = mdev->dump_size;
301 mtx_unlock(&mdev->dump_lock);
302 return (0);
303 }
304 if (!mdev->dump_valid) {
305 mtx_unlock(&mdev->dump_lock);
306 return (ENOENT);
307 }
308 mdev->dump_copyout = true;
309 mtx_unlock(&mdev->dump_lock);
310
311 urv = fwg->buf;
312 for (i = 0, r = mdev->dump_rege; r->cnt != 0; r++) {
313 for (ri = 0; ri < r->cnt; ri++) {
314 if (i >= fwg->reg_cnt)
315 goto out;
316 rv.addr = r->addr + ri * 4;
317 rv.val = mdev->dump_data[i];
318 error = copyout(&rv, urv, sizeof(rv));
319 if (error != 0)
320 return (error);
321 urv++;
322 i++;
323 }
324 }
325 out:
326 fwg->reg_filled = i;
327 mtx_lock(&mdev->dump_lock);
328 mdev->dump_copyout = false;
329 wakeup(&mdev->dump_copyout);
330 mtx_unlock(&mdev->dump_lock);
331 return (0);
332 }
333
334 static int
mlx5_fw_reset(struct mlx5_core_dev * mdev)335 mlx5_fw_reset(struct mlx5_core_dev *mdev)
336 {
337 device_t dev, bus;
338 int error;
339
340 error = -mlx5_set_mfrl_reg(mdev, MLX5_FRL_LEVEL3);
341 if (error == 0) {
342 dev = mdev->pdev->dev.bsddev;
343 bus_topo_lock();
344 bus = device_get_parent(dev);
345 error = BUS_RESET_CHILD(device_get_parent(bus), bus,
346 DEVF_RESET_DETACH);
347 bus_topo_unlock();
348 }
349 return (error);
350 }
351
352 static int
mlx5_eeprom_copyout(struct mlx5_core_dev * dev,struct mlx5_eeprom_get * eeprom_info)353 mlx5_eeprom_copyout(struct mlx5_core_dev *dev, struct mlx5_eeprom_get *eeprom_info)
354 {
355 struct mlx5_eeprom eeprom;
356 int error;
357
358 eeprom.i2c_addr = MLX5_I2C_ADDR_LOW;
359 eeprom.device_addr = 0;
360 eeprom.page_num = MLX5_EEPROM_LOW_PAGE;
361 eeprom.page_valid = 0;
362
363 /* Read three first bytes to get important info */
364 error = mlx5_get_eeprom_info(dev, &eeprom);
365 if (error != 0) {
366 mlx5_core_err(dev,
367 "Failed reading EEPROM initial information\n");
368 return (error);
369 }
370 eeprom_info->eeprom_info_page_valid = eeprom.page_valid;
371 eeprom_info->eeprom_info_out_len = eeprom.len;
372
373 if (eeprom_info->eeprom_info_buf == NULL)
374 return (0);
375 /*
376 * Allocate needed length buffer and additional space for
377 * page 0x03
378 */
379 eeprom.data = malloc(eeprom.len + MLX5_EEPROM_PAGE_LENGTH,
380 M_MLX5_EEPROM, M_WAITOK | M_ZERO);
381
382 /* Read the whole eeprom information */
383 error = mlx5_get_eeprom(dev, &eeprom);
384 if (error != 0) {
385 mlx5_core_err(dev, "Failed reading EEPROM error = %d\n",
386 error);
387 error = 0;
388 /*
389 * Continue printing partial information in case of
390 * an error
391 */
392 }
393 error = copyout(eeprom.data, eeprom_info->eeprom_info_buf,
394 eeprom.len);
395 free(eeprom.data, M_MLX5_EEPROM);
396
397 return (error);
398 }
399
400 static int
mlx5_ctl_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)401 mlx5_ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
402 struct thread *td)
403 {
404 struct mlx5_core_dev *mdev;
405 struct mlx5_fwdump_get *fwg;
406 struct mlx5_tool_addr *devaddr;
407 struct mlx5_fw_update *fu;
408 struct firmware fake_fw;
409 struct mlx5_eeprom_get *eeprom_info;
410 void *fw_data;
411 int error;
412
413 error = 0;
414 switch (cmd) {
415 case MLX5_FWDUMP_GET:
416 if ((fflag & FREAD) == 0) {
417 error = EBADF;
418 break;
419 }
420 fwg = (struct mlx5_fwdump_get *)data;
421 devaddr = &fwg->devaddr;
422 error = mlx5_dbsf_to_core(devaddr, &mdev);
423 if (error != 0)
424 break;
425 error = mlx5_fwdump_copyout(mdev, fwg);
426 break;
427 case MLX5_FWDUMP_RESET:
428 if ((fflag & FWRITE) == 0) {
429 error = EBADF;
430 break;
431 }
432 devaddr = (struct mlx5_tool_addr *)data;
433 error = mlx5_dbsf_to_core(devaddr, &mdev);
434 if (error == 0)
435 error = mlx5_fwdump_reset(mdev);
436 break;
437 case MLX5_FWDUMP_FORCE:
438 if ((fflag & FWRITE) == 0) {
439 error = EBADF;
440 break;
441 }
442 devaddr = (struct mlx5_tool_addr *)data;
443 error = mlx5_dbsf_to_core(devaddr, &mdev);
444 if (error != 0)
445 break;
446 error = mlx5_fwdump(mdev);
447 break;
448 case MLX5_FW_UPDATE:
449 if ((fflag & FWRITE) == 0) {
450 error = EBADF;
451 break;
452 }
453 fu = (struct mlx5_fw_update *)data;
454 if (fu->img_fw_data_len > 10 * 1024 * 1024) {
455 error = EINVAL;
456 break;
457 }
458 devaddr = &fu->devaddr;
459 error = mlx5_dbsf_to_core(devaddr, &mdev);
460 if (error != 0)
461 break;
462 fw_data = kmem_malloc(fu->img_fw_data_len, M_WAITOK);
463 if (fake_fw.data == NULL) {
464 error = ENOMEM;
465 break;
466 }
467 error = copyin(fu->img_fw_data, fw_data, fu->img_fw_data_len);
468 if (error == 0) {
469 bzero(&fake_fw, sizeof(fake_fw));
470 fake_fw.name = "umlx_fw_up";
471 fake_fw.datasize = fu->img_fw_data_len;
472 fake_fw.version = 1;
473 fake_fw.data = fw_data;
474 error = -mlx5_firmware_flash(mdev, &fake_fw);
475 }
476 kmem_free(fw_data, fu->img_fw_data_len);
477 break;
478 case MLX5_FW_RESET:
479 if ((fflag & FWRITE) == 0) {
480 error = EBADF;
481 break;
482 }
483 devaddr = (struct mlx5_tool_addr *)data;
484 error = mlx5_dbsf_to_core(devaddr, &mdev);
485 if (error != 0)
486 break;
487 error = mlx5_fw_reset(mdev);
488 break;
489 case MLX5_EEPROM_GET:
490 if ((fflag & FREAD) == 0) {
491 error = EBADF;
492 break;
493 }
494 eeprom_info = (struct mlx5_eeprom_get *)data;
495 devaddr = &eeprom_info->devaddr;
496 error = mlx5_dbsf_to_core(devaddr, &mdev);
497 if (error != 0)
498 break;
499 error = mlx5_eeprom_copyout(mdev, eeprom_info);
500 break;
501 default:
502 error = ENOTTY;
503 break;
504 }
505 return (error);
506 }
507
508 static struct cdevsw mlx5_ctl_devsw = {
509 .d_version = D_VERSION,
510 .d_ioctl = mlx5_ctl_ioctl,
511 };
512
513 static struct cdev *mlx5_ctl_dev;
514
515 int
mlx5_ctl_init(void)516 mlx5_ctl_init(void)
517 {
518 struct make_dev_args mda;
519 int error;
520
521 make_dev_args_init(&mda);
522 mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
523 mda.mda_devsw = &mlx5_ctl_devsw;
524 mda.mda_uid = UID_ROOT;
525 mda.mda_gid = GID_OPERATOR;
526 mda.mda_mode = 0640;
527 error = make_dev_s(&mda, &mlx5_ctl_dev, "mlx5ctl");
528 return (-error);
529 }
530
531 void
mlx5_ctl_fini(void)532 mlx5_ctl_fini(void)
533 {
534
535 if (mlx5_ctl_dev != NULL)
536 destroy_dev(mlx5_ctl_dev);
537
538 }
539