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 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 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 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 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 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 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 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 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 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 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 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 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 532 mlx5_ctl_fini(void) 533 { 534 535 if (mlx5_ctl_dev != NULL) 536 destroy_dev(mlx5_ctl_dev); 537 538 } 539