1e808190aSHans Petter Selasky /*- 2e808190aSHans Petter Selasky * Copyright (c) 2018, Mellanox Technologies, Ltd. All rights reserved. 3e808190aSHans Petter Selasky * 4e808190aSHans Petter Selasky * Redistribution and use in source and binary forms, with or without 5e808190aSHans Petter Selasky * modification, are permitted provided that the following conditions 6e808190aSHans Petter Selasky * are met: 7e808190aSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 8e808190aSHans Petter Selasky * notice, this list of conditions and the following disclaimer. 9e808190aSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 10e808190aSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 11e808190aSHans Petter Selasky * documentation and/or other materials provided with the distribution. 12e808190aSHans Petter Selasky * 13e808190aSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14e808190aSHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15e808190aSHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16e808190aSHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17e808190aSHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18e808190aSHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19e808190aSHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20e808190aSHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21e808190aSHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22e808190aSHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23e808190aSHans Petter Selasky * SUCH DAMAGE. 24e808190aSHans Petter Selasky */ 25e808190aSHans Petter Selasky 26e808190aSHans Petter Selasky #include <sys/cdefs.h> 27e808190aSHans Petter Selasky __FBSDID("$FreeBSD$"); 28e808190aSHans Petter Selasky 29e808190aSHans Petter Selasky #include <sys/param.h> 30e808190aSHans Petter Selasky #include <sys/ioctl.h> 31ea78f07bSHans Petter Selasky #include <sys/mman.h> 32ea78f07bSHans Petter Selasky #include <sys/stat.h> 33e808190aSHans Petter Selasky #include <dev/mlx5/mlx5io.h> 34e808190aSHans Petter Selasky #include <ctype.h> 35e808190aSHans Petter Selasky #include <err.h> 36e808190aSHans Petter Selasky #include <errno.h> 37e808190aSHans Petter Selasky #include <fcntl.h> 38e808190aSHans Petter Selasky #include <paths.h> 39e808190aSHans Petter Selasky #include <stdio.h> 40e808190aSHans Petter Selasky #include <stdlib.h> 41e808190aSHans Petter Selasky #include <string.h> 42e808190aSHans Petter Selasky #include <unistd.h> 43e808190aSHans Petter Selasky 44e808190aSHans Petter Selasky /* stolen from pciconf.c: parsesel() */ 45e808190aSHans Petter Selasky static int 46b255ca09SHans Petter Selasky parse_pci_addr(const char *addrstr, struct mlx5_tool_addr *addr) 47e808190aSHans Petter Selasky { 48e808190aSHans Petter Selasky char *eppos; 49e808190aSHans Petter Selasky unsigned long selarr[4]; 50e808190aSHans Petter Selasky int i; 51e808190aSHans Petter Selasky 52f3365f07SHans Petter Selasky if (addrstr == NULL) { 53f3365f07SHans Petter Selasky warnx("no pci address specified"); 54f3365f07SHans Petter Selasky return (1); 55f3365f07SHans Petter Selasky } 56e808190aSHans Petter Selasky if (strncmp(addrstr, "pci", 3) == 0) { 57e808190aSHans Petter Selasky addrstr += 3; 58e808190aSHans Petter Selasky i = 0; 59e808190aSHans Petter Selasky while (isdigit(*addrstr) && i < 4) { 60e808190aSHans Petter Selasky selarr[i++] = strtoul(addrstr, &eppos, 10); 61e808190aSHans Petter Selasky addrstr = eppos; 62e808190aSHans Petter Selasky if (*addrstr == ':') 63e808190aSHans Petter Selasky addrstr++; 64e808190aSHans Petter Selasky } 65e808190aSHans Petter Selasky if (i > 0 && *addrstr == '\0') { 66e808190aSHans Petter Selasky addr->func = (i > 2) ? selarr[--i] : 0; 67e808190aSHans Petter Selasky addr->slot = (i > 0) ? selarr[--i] : 0; 68e808190aSHans Petter Selasky addr->bus = (i > 0) ? selarr[--i] : 0; 69e808190aSHans Petter Selasky addr->domain = (i > 0) ? selarr[--i] : 0; 70e808190aSHans Petter Selasky return (0); 71e808190aSHans Petter Selasky } 72e808190aSHans Petter Selasky } 73e808190aSHans Petter Selasky warnx("invalid pci address %s", addrstr); 74e808190aSHans Petter Selasky return (1); 75e808190aSHans Petter Selasky } 76e808190aSHans Petter Selasky 77e808190aSHans Petter Selasky static int 78b255ca09SHans Petter Selasky mlx5tool_save_dump(int ctldev, const struct mlx5_tool_addr *addr, 79e808190aSHans Petter Selasky const char *dumpname) 80e808190aSHans Petter Selasky { 81e808190aSHans Petter Selasky struct mlx5_fwdump_get fdg; 82e808190aSHans Petter Selasky struct mlx5_fwdump_reg *rege; 83e808190aSHans Petter Selasky FILE *dump; 84e808190aSHans Petter Selasky size_t cnt; 85e808190aSHans Petter Selasky int error, res; 86e808190aSHans Petter Selasky 87e808190aSHans Petter Selasky if (dumpname == NULL) 88e808190aSHans Petter Selasky dump = stdout; 89e808190aSHans Petter Selasky else 90e808190aSHans Petter Selasky dump = fopen(dumpname, "w"); 91e808190aSHans Petter Selasky if (dump == NULL) { 92e808190aSHans Petter Selasky warn("open %s", dumpname); 93e808190aSHans Petter Selasky return (1); 94e808190aSHans Petter Selasky } 95e808190aSHans Petter Selasky res = 1; 96e808190aSHans Petter Selasky memset(&fdg, 0, sizeof(fdg)); 97e808190aSHans Petter Selasky fdg.devaddr = *addr; 98e808190aSHans Petter Selasky error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg); 99e808190aSHans Petter Selasky if (error != 0) { 100e808190aSHans Petter Selasky warn("MLX5_FWDUMP_GET dumpsize"); 101e808190aSHans Petter Selasky goto out; 102e808190aSHans Petter Selasky } 103e808190aSHans Petter Selasky rege = calloc(fdg.reg_filled, sizeof(*rege)); 104e808190aSHans Petter Selasky if (rege == NULL) { 105e808190aSHans Petter Selasky warn("alloc rege"); 106e808190aSHans Petter Selasky goto out; 107e808190aSHans Petter Selasky } 108e808190aSHans Petter Selasky fdg.buf = rege; 109e808190aSHans Petter Selasky fdg.reg_cnt = fdg.reg_filled; 110e808190aSHans Petter Selasky error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg); 111e808190aSHans Petter Selasky if (error != 0) { 112e808190aSHans Petter Selasky if (errno == ENOENT) 113e808190aSHans Petter Selasky warnx("no dump recorded"); 114e808190aSHans Petter Selasky else 115e808190aSHans Petter Selasky warn("MLX5_FWDUMP_GET dump fetch"); 116e808190aSHans Petter Selasky goto out; 117e808190aSHans Petter Selasky } 118e808190aSHans Petter Selasky for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++) 119e808190aSHans Petter Selasky fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val); 120e808190aSHans Petter Selasky res = 0; 121e808190aSHans Petter Selasky out: 122e808190aSHans Petter Selasky if (dump != stdout) 123e808190aSHans Petter Selasky fclose(dump); 124e808190aSHans Petter Selasky return (res); 125e808190aSHans Petter Selasky } 126e808190aSHans Petter Selasky 127e808190aSHans Petter Selasky static int 128b255ca09SHans Petter Selasky mlx5tool_dump_reset(int ctldev, const struct mlx5_tool_addr *addr) 129e808190aSHans Petter Selasky { 130e808190aSHans Petter Selasky 131e808190aSHans Petter Selasky if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) { 132e808190aSHans Petter Selasky warn("MLX5_FWDUMP_RESET"); 133e808190aSHans Petter Selasky return (1); 134e808190aSHans Petter Selasky } 135e808190aSHans Petter Selasky return (0); 136e808190aSHans Petter Selasky } 137e808190aSHans Petter Selasky 138e808190aSHans Petter Selasky static int 139b255ca09SHans Petter Selasky mlx5tool_dump_force(int ctldev, const struct mlx5_tool_addr *addr) 140e808190aSHans Petter Selasky { 141e808190aSHans Petter Selasky 142e808190aSHans Petter Selasky if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) { 143e808190aSHans Petter Selasky warn("MLX5_FWDUMP_FORCE"); 144e808190aSHans Petter Selasky return (1); 145e808190aSHans Petter Selasky } 146e808190aSHans Petter Selasky return (0); 147e808190aSHans Petter Selasky } 148e808190aSHans Petter Selasky 149ea78f07bSHans Petter Selasky static int 150ea78f07bSHans Petter Selasky mlx5tool_fw_update(int ctldev, const struct mlx5_tool_addr *addr, 151ea78f07bSHans Petter Selasky const char *img_fw_path) 152ea78f07bSHans Petter Selasky { 153ea78f07bSHans Petter Selasky struct stat st; 154ea78f07bSHans Petter Selasky struct mlx5_fw_update fwup; 155ea78f07bSHans Petter Selasky int error, fd, res; 156ea78f07bSHans Petter Selasky 157ea78f07bSHans Petter Selasky res = 0; 158ea78f07bSHans Petter Selasky fd = open(img_fw_path, O_RDONLY); 159ea78f07bSHans Petter Selasky if (fd == -1) { 160ea78f07bSHans Petter Selasky warn("Unable to open %s", img_fw_path); 161ea78f07bSHans Petter Selasky res = 1; 162ea78f07bSHans Petter Selasky goto close_fd; 163ea78f07bSHans Petter Selasky } 164ea78f07bSHans Petter Selasky error = fstat(fd, &st); 165ea78f07bSHans Petter Selasky if (error != 0) { 166ea78f07bSHans Petter Selasky warn("Unable to stat %s", img_fw_path); 167ea78f07bSHans Petter Selasky res = 1; 168ea78f07bSHans Petter Selasky goto close_fd; 169ea78f07bSHans Petter Selasky } 170ea78f07bSHans Petter Selasky memset(&fwup, 0, sizeof(fwup)); 171ea78f07bSHans Petter Selasky memcpy(&fwup.devaddr, addr, sizeof(fwup.devaddr)); 172ea78f07bSHans Petter Selasky fwup.img_fw_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, 173ea78f07bSHans Petter Selasky fd, 0); 174ea78f07bSHans Petter Selasky if (fwup.img_fw_data == MAP_FAILED) { 175ea78f07bSHans Petter Selasky warn("Unable to mmap %s", img_fw_path); 176ea78f07bSHans Petter Selasky res = 1; 177ea78f07bSHans Petter Selasky goto close_fd; 178ea78f07bSHans Petter Selasky } 179ea78f07bSHans Petter Selasky fwup.img_fw_data_len = st.st_size; 180ea78f07bSHans Petter Selasky 181ea78f07bSHans Petter Selasky error = ioctl(ctldev, MLX5_FW_UPDATE, &fwup); 182ea78f07bSHans Petter Selasky if (error == -1) { 183ea78f07bSHans Petter Selasky warn("MLX5_FW_UPDATE"); 184ea78f07bSHans Petter Selasky } 185ea78f07bSHans Petter Selasky 186ea78f07bSHans Petter Selasky munmap(fwup.img_fw_data, st.st_size); 187ea78f07bSHans Petter Selasky close_fd: 188ea78f07bSHans Petter Selasky close(fd); 189ea78f07bSHans Petter Selasky return (res); 190ea78f07bSHans Petter Selasky } 191ea78f07bSHans Petter Selasky 192998c9a2bSHans Petter Selasky static int 193998c9a2bSHans Petter Selasky mlx5tool_fw_reset(int ctldev, const struct mlx5_tool_addr *addr) 194998c9a2bSHans Petter Selasky { 195998c9a2bSHans Petter Selasky 196998c9a2bSHans Petter Selasky if (ioctl(ctldev, MLX5_FW_RESET, addr) == -1) { 197998c9a2bSHans Petter Selasky warn("MLX5_FW_RESET"); 198998c9a2bSHans Petter Selasky return (1); 199998c9a2bSHans Petter Selasky } 200998c9a2bSHans Petter Selasky return (0); 201998c9a2bSHans Petter Selasky } 202998c9a2bSHans Petter Selasky 203e808190aSHans Petter Selasky static void 204e808190aSHans Petter Selasky usage(void) 205e808190aSHans Petter Selasky { 206e808190aSHans Petter Selasky 207e808190aSHans Petter Selasky fprintf(stderr, 208ea78f07bSHans Petter Selasky "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |" 209998c9a2bSHans Petter Selasky " -e | -f fw.mfa2 | -z]\n"); 210e808190aSHans Petter Selasky fprintf(stderr, "\t-w - write firmware dump to the specified file\n"); 211e808190aSHans Petter Selasky fprintf(stderr, "\t-r - reset dump\n"); 212e808190aSHans Petter Selasky fprintf(stderr, "\t-e - force dump\n"); 213ea78f07bSHans Petter Selasky fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n"); 214998c9a2bSHans Petter Selasky fprintf(stderr, "\t-z - initiate firmware reset\n"); 215e808190aSHans Petter Selasky exit(1); 216e808190aSHans Petter Selasky } 217e808190aSHans Petter Selasky 218e808190aSHans Petter Selasky enum mlx5_action { 219e808190aSHans Petter Selasky ACTION_DUMP_GET, 220e808190aSHans Petter Selasky ACTION_DUMP_RESET, 221e808190aSHans Petter Selasky ACTION_DUMP_FORCE, 222ea78f07bSHans Petter Selasky ACTION_FW_UPDATE, 223998c9a2bSHans Petter Selasky ACTION_FW_RESET, 224e808190aSHans Petter Selasky ACTION_NONE, 225e808190aSHans Petter Selasky }; 226e808190aSHans Petter Selasky 227e808190aSHans Petter Selasky int 228e808190aSHans Petter Selasky main(int argc, char *argv[]) 229e808190aSHans Petter Selasky { 230b255ca09SHans Petter Selasky struct mlx5_tool_addr addr; 231e808190aSHans Petter Selasky char *dumpname; 232e808190aSHans Petter Selasky char *addrstr; 233ea78f07bSHans Petter Selasky char *img_fw_path; 234e808190aSHans Petter Selasky int c, ctldev, res; 235e808190aSHans Petter Selasky enum mlx5_action act; 236e808190aSHans Petter Selasky 237e808190aSHans Petter Selasky act = ACTION_NONE; 238e808190aSHans Petter Selasky addrstr = NULL; 239e808190aSHans Petter Selasky dumpname = NULL; 240ea78f07bSHans Petter Selasky img_fw_path = NULL; 241998c9a2bSHans Petter Selasky while ((c = getopt(argc, argv, "d:ef:ho:rwz")) != -1) { 242e808190aSHans Petter Selasky switch (c) { 243e808190aSHans Petter Selasky case 'd': 244e808190aSHans Petter Selasky addrstr = optarg; 245e808190aSHans Petter Selasky break; 246e808190aSHans Petter Selasky case 'w': 247*b4b75592SHans Petter Selasky if (act != ACTION_NONE) 248*b4b75592SHans Petter Selasky usage(); 249e808190aSHans Petter Selasky act = ACTION_DUMP_GET; 250e808190aSHans Petter Selasky break; 251e808190aSHans Petter Selasky case 'e': 252*b4b75592SHans Petter Selasky if (act != ACTION_NONE) 253*b4b75592SHans Petter Selasky usage(); 254e808190aSHans Petter Selasky act = ACTION_DUMP_FORCE; 255e808190aSHans Petter Selasky break; 256e808190aSHans Petter Selasky case 'o': 257e808190aSHans Petter Selasky dumpname = optarg; 258e808190aSHans Petter Selasky break; 259e808190aSHans Petter Selasky case 'r': 260*b4b75592SHans Petter Selasky if (act != ACTION_NONE) 261*b4b75592SHans Petter Selasky usage(); 262e808190aSHans Petter Selasky act = ACTION_DUMP_RESET; 263e808190aSHans Petter Selasky break; 264ea78f07bSHans Petter Selasky case 'f': 265*b4b75592SHans Petter Selasky if (act != ACTION_NONE) 266*b4b75592SHans Petter Selasky usage(); 267ea78f07bSHans Petter Selasky act = ACTION_FW_UPDATE; 268ea78f07bSHans Petter Selasky img_fw_path = optarg; 269ea78f07bSHans Petter Selasky break; 270998c9a2bSHans Petter Selasky case 'z': 271*b4b75592SHans Petter Selasky if (act != ACTION_NONE) 272*b4b75592SHans Petter Selasky usage(); 273998c9a2bSHans Petter Selasky act = ACTION_FW_RESET; 274998c9a2bSHans Petter Selasky break; 275e808190aSHans Petter Selasky case 'h': 276e808190aSHans Petter Selasky default: 277e808190aSHans Petter Selasky usage(); 278e808190aSHans Petter Selasky } 279e808190aSHans Petter Selasky } 280ea78f07bSHans Petter Selasky if (act == ACTION_NONE || (dumpname != NULL && 281ea78f07bSHans Petter Selasky act != ACTION_DUMP_GET) || (img_fw_path != NULL && 282ea78f07bSHans Petter Selasky act != ACTION_FW_UPDATE)) 283e808190aSHans Petter Selasky usage(); 284e808190aSHans Petter Selasky if (parse_pci_addr(addrstr, &addr) != 0) 285e808190aSHans Petter Selasky exit(1); 286e808190aSHans Petter Selasky 287e808190aSHans Petter Selasky ctldev = open(MLX5_DEV_PATH, O_RDWR); 288e808190aSHans Petter Selasky if (ctldev == -1) 289e808190aSHans Petter Selasky err(1, "open "MLX5_DEV_PATH); 290e808190aSHans Petter Selasky switch (act) { 291e808190aSHans Petter Selasky case ACTION_DUMP_GET: 292e808190aSHans Petter Selasky res = mlx5tool_save_dump(ctldev, &addr, dumpname); 293e808190aSHans Petter Selasky break; 294e808190aSHans Petter Selasky case ACTION_DUMP_RESET: 295e808190aSHans Petter Selasky res = mlx5tool_dump_reset(ctldev, &addr); 296e808190aSHans Petter Selasky break; 297e808190aSHans Petter Selasky case ACTION_DUMP_FORCE: 298e808190aSHans Petter Selasky res = mlx5tool_dump_force(ctldev, &addr); 299e808190aSHans Petter Selasky break; 300ea78f07bSHans Petter Selasky case ACTION_FW_UPDATE: 301ea78f07bSHans Petter Selasky res = mlx5tool_fw_update(ctldev, &addr, img_fw_path); 302ea78f07bSHans Petter Selasky break; 303998c9a2bSHans Petter Selasky case ACTION_FW_RESET: 304998c9a2bSHans Petter Selasky res = mlx5tool_fw_reset(ctldev, &addr); 305998c9a2bSHans Petter Selasky break; 306e808190aSHans Petter Selasky default: 307e808190aSHans Petter Selasky res = 0; 308e808190aSHans Petter Selasky break; 309e808190aSHans Petter Selasky } 310e808190aSHans Petter Selasky close(ctldev); 311e808190aSHans Petter Selasky exit(res); 312e808190aSHans Petter Selasky } 313