mlx5tool.c revision 353242
1330653Shselasky/*- 2330653Shselasky * Copyright (c) 2018, Mellanox Technologies, Ltd. All rights reserved. 3330653Shselasky * 4330653Shselasky * Redistribution and use in source and binary forms, with or without 5330653Shselasky * modification, are permitted provided that the following conditions 6330653Shselasky * are met: 7330653Shselasky * 1. Redistributions of source code must retain the above copyright 8330653Shselasky * notice, this list of conditions and the following disclaimer. 9330653Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10330653Shselasky * notice, this list of conditions and the following disclaimer in the 11330653Shselasky * documentation and/or other materials provided with the distribution. 12330653Shselasky * 13330653Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14330653Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15330653Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16330653Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17330653Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18330653Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19330653Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20330653Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21330653Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22330653Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23330653Shselasky * SUCH DAMAGE. 24330653Shselasky */ 25330653Shselasky 26330653Shselasky#include <sys/cdefs.h> 27330653Shselasky__FBSDID("$FreeBSD: stable/11/usr.sbin/mlx5tool/mlx5tool.c 353242 2019-10-07 09:49:03Z hselasky $"); 28330653Shselasky 29330653Shselasky#include <sys/param.h> 30330653Shselasky#include <sys/ioctl.h> 31347841Shselasky#include <sys/mman.h> 32347841Shselasky#include <sys/stat.h> 33330653Shselasky#include <dev/mlx5/mlx5io.h> 34330653Shselasky#include <ctype.h> 35330653Shselasky#include <err.h> 36330653Shselasky#include <errno.h> 37330653Shselasky#include <fcntl.h> 38330653Shselasky#include <paths.h> 39330653Shselasky#include <stdio.h> 40330653Shselasky#include <stdlib.h> 41330653Shselasky#include <string.h> 42330653Shselasky#include <unistd.h> 43330653Shselasky 44330653Shselasky/* stolen from pciconf.c: parsesel() */ 45330653Shselaskystatic int 46347840Shselaskyparse_pci_addr(const char *addrstr, struct mlx5_tool_addr *addr) 47330653Shselasky{ 48330653Shselasky char *eppos; 49330653Shselasky unsigned long selarr[4]; 50330653Shselasky int i; 51330653Shselasky 52331593Shselasky if (addrstr == NULL) { 53331593Shselasky warnx("no pci address specified"); 54331593Shselasky return (1); 55331593Shselasky } 56330653Shselasky if (strncmp(addrstr, "pci", 3) == 0) { 57330653Shselasky addrstr += 3; 58330653Shselasky i = 0; 59330653Shselasky while (isdigit(*addrstr) && i < 4) { 60330653Shselasky selarr[i++] = strtoul(addrstr, &eppos, 10); 61330653Shselasky addrstr = eppos; 62330653Shselasky if (*addrstr == ':') 63330653Shselasky addrstr++; 64330653Shselasky } 65330653Shselasky if (i > 0 && *addrstr == '\0') { 66330653Shselasky addr->func = (i > 2) ? selarr[--i] : 0; 67330653Shselasky addr->slot = (i > 0) ? selarr[--i] : 0; 68330653Shselasky addr->bus = (i > 0) ? selarr[--i] : 0; 69330653Shselasky addr->domain = (i > 0) ? selarr[--i] : 0; 70330653Shselasky return (0); 71330653Shselasky } 72330653Shselasky } 73330653Shselasky warnx("invalid pci address %s", addrstr); 74330653Shselasky return (1); 75330653Shselasky} 76330653Shselasky 77330653Shselaskystatic int 78347840Shselaskymlx5tool_save_dump(int ctldev, const struct mlx5_tool_addr *addr, 79330653Shselasky const char *dumpname) 80330653Shselasky{ 81330653Shselasky struct mlx5_fwdump_get fdg; 82330653Shselasky struct mlx5_fwdump_reg *rege; 83330653Shselasky FILE *dump; 84330653Shselasky size_t cnt; 85330653Shselasky int error, res; 86330653Shselasky 87330653Shselasky if (dumpname == NULL) 88330653Shselasky dump = stdout; 89330653Shselasky else 90330653Shselasky dump = fopen(dumpname, "w"); 91330653Shselasky if (dump == NULL) { 92330653Shselasky warn("open %s", dumpname); 93330653Shselasky return (1); 94330653Shselasky } 95330653Shselasky res = 1; 96330653Shselasky memset(&fdg, 0, sizeof(fdg)); 97330653Shselasky fdg.devaddr = *addr; 98330653Shselasky error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg); 99330653Shselasky if (error != 0) { 100330653Shselasky warn("MLX5_FWDUMP_GET dumpsize"); 101330653Shselasky goto out; 102330653Shselasky } 103330653Shselasky rege = calloc(fdg.reg_filled, sizeof(*rege)); 104330653Shselasky if (rege == NULL) { 105330653Shselasky warn("alloc rege"); 106330653Shselasky goto out; 107330653Shselasky } 108330653Shselasky fdg.buf = rege; 109330653Shselasky fdg.reg_cnt = fdg.reg_filled; 110330653Shselasky error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg); 111330653Shselasky if (error != 0) { 112330653Shselasky if (errno == ENOENT) 113330653Shselasky warnx("no dump recorded"); 114330653Shselasky else 115330653Shselasky warn("MLX5_FWDUMP_GET dump fetch"); 116330653Shselasky goto out; 117330653Shselasky } 118330653Shselasky for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++) 119330653Shselasky fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val); 120330653Shselasky res = 0; 121330653Shselaskyout: 122330653Shselasky if (dump != stdout) 123330653Shselasky fclose(dump); 124330653Shselasky return (res); 125330653Shselasky} 126330653Shselasky 127330653Shselaskystatic int 128347840Shselaskymlx5tool_dump_reset(int ctldev, const struct mlx5_tool_addr *addr) 129330653Shselasky{ 130330653Shselasky 131330653Shselasky if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) { 132330653Shselasky warn("MLX5_FWDUMP_RESET"); 133330653Shselasky return (1); 134330653Shselasky } 135330653Shselasky return (0); 136330653Shselasky} 137330653Shselasky 138330653Shselaskystatic int 139347840Shselaskymlx5tool_dump_force(int ctldev, const struct mlx5_tool_addr *addr) 140330653Shselasky{ 141330653Shselasky 142330653Shselasky if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) { 143330653Shselasky warn("MLX5_FWDUMP_FORCE"); 144330653Shselasky return (1); 145330653Shselasky } 146330653Shselasky return (0); 147330653Shselasky} 148330653Shselasky 149347841Shselaskystatic int 150347841Shselaskymlx5tool_fw_update(int ctldev, const struct mlx5_tool_addr *addr, 151347841Shselasky const char *img_fw_path) 152347841Shselasky{ 153347841Shselasky struct stat st; 154347841Shselasky struct mlx5_fw_update fwup; 155347841Shselasky int error, fd, res; 156347841Shselasky 157347841Shselasky res = 0; 158347841Shselasky fd = open(img_fw_path, O_RDONLY); 159347841Shselasky if (fd == -1) { 160347841Shselasky warn("Unable to open %s", img_fw_path); 161347841Shselasky res = 1; 162347841Shselasky goto close_fd; 163347841Shselasky } 164347841Shselasky error = fstat(fd, &st); 165347841Shselasky if (error != 0) { 166347841Shselasky warn("Unable to stat %s", img_fw_path); 167347841Shselasky res = 1; 168347841Shselasky goto close_fd; 169347841Shselasky } 170347841Shselasky memset(&fwup, 0, sizeof(fwup)); 171347841Shselasky memcpy(&fwup.devaddr, addr, sizeof(fwup.devaddr)); 172347841Shselasky fwup.img_fw_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, 173347841Shselasky fd, 0); 174347841Shselasky if (fwup.img_fw_data == MAP_FAILED) { 175347841Shselasky warn("Unable to mmap %s", img_fw_path); 176347841Shselasky res = 1; 177347841Shselasky goto close_fd; 178347841Shselasky } 179347841Shselasky fwup.img_fw_data_len = st.st_size; 180347841Shselasky 181347841Shselasky error = ioctl(ctldev, MLX5_FW_UPDATE, &fwup); 182347841Shselasky if (error == -1) { 183347841Shselasky warn("MLX5_FW_UPDATE"); 184347841Shselasky } 185347841Shselasky 186347841Shselasky munmap(fwup.img_fw_data, st.st_size); 187347841Shselaskyclose_fd: 188347841Shselasky close(fd); 189347841Shselasky return (res); 190347841Shselasky} 191347841Shselasky 192347869Shselaskystatic int 193347869Shselaskymlx5tool_fw_reset(int ctldev, const struct mlx5_tool_addr *addr) 194347869Shselasky{ 195347869Shselasky 196347869Shselasky if (ioctl(ctldev, MLX5_FW_RESET, addr) == -1) { 197347869Shselasky warn("MLX5_FW_RESET"); 198347869Shselasky return (1); 199347869Shselasky } 200347869Shselasky return (0); 201347869Shselasky} 202347869Shselasky 203353242Shselasky#define MLX5_EEPROM_HIGH_PAGE_OFFSET 128 204353242Shselasky#define MLX5_EEPROM_PAGE_LENGTH 256 205353242Shselasky 206330653Shselaskystatic void 207353242Shselaskymlx5tool_eeprom_print(struct mlx5_eeprom_get *eeprom_info) 208353242Shselasky{ 209353242Shselasky unsigned int byte_to_write, index_in_row, line_length, row; 210353242Shselasky 211353242Shselasky byte_to_write = 0; 212353242Shselasky line_length = 16; 213353242Shselasky 214353242Shselasky printf("\nOffset\t\tValues\n"); 215353242Shselasky printf("------\t\t------"); 216353242Shselasky while (byte_to_write < eeprom_info->eeprom_info_out_len) { 217353242Shselasky printf("\n0x%04X\t\t", byte_to_write); 218353242Shselasky for (index_in_row = 0; index_in_row < line_length; 219353242Shselasky index_in_row++) { 220353242Shselasky printf("%02X ", 221353242Shselasky ((uint8_t *)eeprom_info->eeprom_info_buf)[ 222353242Shselasky byte_to_write]); 223353242Shselasky byte_to_write++; 224353242Shselasky } 225353242Shselasky } 226353242Shselasky 227353242Shselasky if (eeprom_info->eeprom_info_page_valid) { 228353242Shselasky row = MLX5_EEPROM_HIGH_PAGE_OFFSET; 229353242Shselasky printf("\n\nUpper Page 0x03\n"); 230353242Shselasky printf("\nOffset\t\tValues\n"); 231353242Shselasky printf("------\t\t------"); 232353242Shselasky for (row = MLX5_EEPROM_HIGH_PAGE_OFFSET; 233353242Shselasky row < MLX5_EEPROM_PAGE_LENGTH;) { 234353242Shselasky printf("\n0x%04X\t\t", row); 235353242Shselasky for (index_in_row = 0; 236353242Shselasky index_in_row < line_length; 237353242Shselasky index_in_row++) { 238353242Shselasky printf("%02X ", 239353242Shselasky ((uint8_t *)eeprom_info-> 240353242Shselasky eeprom_info_buf)[byte_to_write]); 241353242Shselasky byte_to_write++; 242353242Shselasky row++; 243353242Shselasky } 244353242Shselasky } 245353242Shselasky } 246353242Shselasky printf("\n"); 247353242Shselasky} 248353242Shselasky 249353242Shselaskystatic int 250353242Shselaskymlx5tool_get_eeprom_info(int ctldev, const struct mlx5_tool_addr *addr) 251353242Shselasky{ 252353242Shselasky struct mlx5_eeprom_get eeprom_info; 253353242Shselasky int error; 254353242Shselasky 255353242Shselasky memset(&eeprom_info, 0, sizeof(eeprom_info)); 256353242Shselasky eeprom_info.devaddr = *addr; 257353242Shselasky 258353242Shselasky error = ioctl(ctldev, MLX5_EEPROM_GET, &eeprom_info); 259353242Shselasky if (error != 0) { 260353242Shselasky warn("MLX5_EEPROM_GET"); 261353242Shselasky return (error); 262353242Shselasky } 263353242Shselasky eeprom_info.eeprom_info_buf = 264353242Shselasky malloc(eeprom_info.eeprom_info_out_len + MLX5_EEPROM_PAGE_LENGTH); 265353242Shselasky if (eeprom_info.eeprom_info_buf == NULL) { 266353242Shselasky warn("alloc eeprom_info.eeprom_info_buf "); 267353242Shselasky return (ENOMEM); 268353242Shselasky } 269353242Shselasky error = ioctl(ctldev, MLX5_EEPROM_GET, &eeprom_info); 270353242Shselasky if (error != 0) { 271353242Shselasky warn("MLX5_EEPROM_GET"); 272353242Shselasky free(eeprom_info.eeprom_info_buf); 273353242Shselasky return (error); 274353242Shselasky } 275353242Shselasky 276353242Shselasky mlx5tool_eeprom_print(&eeprom_info); 277353242Shselasky 278353242Shselasky free(eeprom_info.eeprom_info_buf); 279353242Shselasky return (0); 280353242Shselasky} 281353242Shselasky 282353242Shselaskystatic void 283330653Shselaskyusage(void) 284330653Shselasky{ 285330653Shselasky 286330653Shselasky fprintf(stderr, 287347841Shselasky "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |" 288347869Shselasky " -e | -f fw.mfa2 | -z]\n"); 289330653Shselasky fprintf(stderr, "\t-w - write firmware dump to the specified file\n"); 290330653Shselasky fprintf(stderr, "\t-r - reset dump\n"); 291353242Shselasky fprintf(stderr, "\t-E - get eeprom info\n"); 292330653Shselasky fprintf(stderr, "\t-e - force dump\n"); 293347841Shselasky fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n"); 294347869Shselasky fprintf(stderr, "\t-z - initiate firmware reset\n"); 295330653Shselasky exit(1); 296330653Shselasky} 297330653Shselasky 298330653Shselaskyenum mlx5_action { 299330653Shselasky ACTION_DUMP_GET, 300330653Shselasky ACTION_DUMP_RESET, 301330653Shselasky ACTION_DUMP_FORCE, 302347841Shselasky ACTION_FW_UPDATE, 303347869Shselasky ACTION_FW_RESET, 304353242Shselasky ACTION_GET_EEPROM_INFO, 305330653Shselasky ACTION_NONE, 306330653Shselasky}; 307330653Shselasky 308330653Shselaskyint 309330653Shselaskymain(int argc, char *argv[]) 310330653Shselasky{ 311347840Shselasky struct mlx5_tool_addr addr; 312330653Shselasky char *dumpname; 313330653Shselasky char *addrstr; 314347841Shselasky char *img_fw_path; 315330653Shselasky int c, ctldev, res; 316330653Shselasky enum mlx5_action act; 317330653Shselasky 318330653Shselasky act = ACTION_NONE; 319330653Shselasky addrstr = NULL; 320330653Shselasky dumpname = NULL; 321347841Shselasky img_fw_path = NULL; 322353242Shselasky while ((c = getopt(argc, argv, "d:Eef:ho:rwz")) != -1) { 323330653Shselasky switch (c) { 324330653Shselasky case 'd': 325330653Shselasky addrstr = optarg; 326330653Shselasky break; 327330653Shselasky case 'w': 328347870Shselasky if (act != ACTION_NONE) 329347870Shselasky usage(); 330330653Shselasky act = ACTION_DUMP_GET; 331330653Shselasky break; 332353242Shselasky case 'E': 333353242Shselasky if (act != ACTION_NONE) 334353242Shselasky usage(); 335353242Shselasky act = ACTION_GET_EEPROM_INFO; 336353242Shselasky break; 337330653Shselasky case 'e': 338347870Shselasky if (act != ACTION_NONE) 339347870Shselasky usage(); 340347831Shselasky act = ACTION_DUMP_FORCE; 341330653Shselasky break; 342330653Shselasky case 'o': 343330653Shselasky dumpname = optarg; 344330653Shselasky break; 345330653Shselasky case 'r': 346347870Shselasky if (act != ACTION_NONE) 347347870Shselasky usage(); 348330653Shselasky act = ACTION_DUMP_RESET; 349330653Shselasky break; 350347841Shselasky case 'f': 351347870Shselasky if (act != ACTION_NONE) 352347870Shselasky usage(); 353347841Shselasky act = ACTION_FW_UPDATE; 354347841Shselasky img_fw_path = optarg; 355347841Shselasky break; 356347869Shselasky case 'z': 357347870Shselasky if (act != ACTION_NONE) 358347870Shselasky usage(); 359347869Shselasky act = ACTION_FW_RESET; 360347869Shselasky break; 361330653Shselasky case 'h': 362330653Shselasky default: 363330653Shselasky usage(); 364330653Shselasky } 365330653Shselasky } 366347841Shselasky if (act == ACTION_NONE || (dumpname != NULL && 367347841Shselasky act != ACTION_DUMP_GET) || (img_fw_path != NULL && 368347841Shselasky act != ACTION_FW_UPDATE)) 369330653Shselasky usage(); 370330653Shselasky if (parse_pci_addr(addrstr, &addr) != 0) 371330653Shselasky exit(1); 372330653Shselasky 373330653Shselasky ctldev = open(MLX5_DEV_PATH, O_RDWR); 374330653Shselasky if (ctldev == -1) 375330653Shselasky err(1, "open "MLX5_DEV_PATH); 376330653Shselasky switch (act) { 377330653Shselasky case ACTION_DUMP_GET: 378330653Shselasky res = mlx5tool_save_dump(ctldev, &addr, dumpname); 379330653Shselasky break; 380330653Shselasky case ACTION_DUMP_RESET: 381330653Shselasky res = mlx5tool_dump_reset(ctldev, &addr); 382330653Shselasky break; 383330653Shselasky case ACTION_DUMP_FORCE: 384330653Shselasky res = mlx5tool_dump_force(ctldev, &addr); 385330653Shselasky break; 386347841Shselasky case ACTION_FW_UPDATE: 387347841Shselasky res = mlx5tool_fw_update(ctldev, &addr, img_fw_path); 388347841Shselasky break; 389347869Shselasky case ACTION_FW_RESET: 390347869Shselasky res = mlx5tool_fw_reset(ctldev, &addr); 391347869Shselasky break; 392353242Shselasky case ACTION_GET_EEPROM_INFO: 393353242Shselasky res = mlx5tool_get_eeprom_info(ctldev, &addr); 394353242Shselasky break; 395330653Shselasky default: 396330653Shselasky res = 0; 397330653Shselasky break; 398330653Shselasky } 399330653Shselasky close(ctldev); 400330653Shselasky exit(res); 401330653Shselasky} 402