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> 31*ea78f07bSHans Petter Selasky #include <sys/mman.h> 32*ea78f07bSHans 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 149*ea78f07bSHans Petter Selasky static int 150*ea78f07bSHans Petter Selasky mlx5tool_fw_update(int ctldev, const struct mlx5_tool_addr *addr, 151*ea78f07bSHans Petter Selasky const char *img_fw_path) 152*ea78f07bSHans Petter Selasky { 153*ea78f07bSHans Petter Selasky struct stat st; 154*ea78f07bSHans Petter Selasky struct mlx5_fw_update fwup; 155*ea78f07bSHans Petter Selasky int error, fd, res; 156*ea78f07bSHans Petter Selasky 157*ea78f07bSHans Petter Selasky res = 0; 158*ea78f07bSHans Petter Selasky fd = open(img_fw_path, O_RDONLY); 159*ea78f07bSHans Petter Selasky if (fd == -1) { 160*ea78f07bSHans Petter Selasky warn("Unable to open %s", img_fw_path); 161*ea78f07bSHans Petter Selasky res = 1; 162*ea78f07bSHans Petter Selasky goto close_fd; 163*ea78f07bSHans Petter Selasky } 164*ea78f07bSHans Petter Selasky error = fstat(fd, &st); 165*ea78f07bSHans Petter Selasky if (error != 0) { 166*ea78f07bSHans Petter Selasky warn("Unable to stat %s", img_fw_path); 167*ea78f07bSHans Petter Selasky res = 1; 168*ea78f07bSHans Petter Selasky goto close_fd; 169*ea78f07bSHans Petter Selasky } 170*ea78f07bSHans Petter Selasky memset(&fwup, 0, sizeof(fwup)); 171*ea78f07bSHans Petter Selasky memcpy(&fwup.devaddr, addr, sizeof(fwup.devaddr)); 172*ea78f07bSHans Petter Selasky fwup.img_fw_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, 173*ea78f07bSHans Petter Selasky fd, 0); 174*ea78f07bSHans Petter Selasky if (fwup.img_fw_data == MAP_FAILED) { 175*ea78f07bSHans Petter Selasky warn("Unable to mmap %s", img_fw_path); 176*ea78f07bSHans Petter Selasky res = 1; 177*ea78f07bSHans Petter Selasky goto close_fd; 178*ea78f07bSHans Petter Selasky } 179*ea78f07bSHans Petter Selasky fwup.img_fw_data_len = st.st_size; 180*ea78f07bSHans Petter Selasky 181*ea78f07bSHans Petter Selasky error = ioctl(ctldev, MLX5_FW_UPDATE, &fwup); 182*ea78f07bSHans Petter Selasky if (error == -1) { 183*ea78f07bSHans Petter Selasky warn("MLX5_FW_UPDATE"); 184*ea78f07bSHans Petter Selasky } 185*ea78f07bSHans Petter Selasky 186*ea78f07bSHans Petter Selasky munmap(fwup.img_fw_data, st.st_size); 187*ea78f07bSHans Petter Selasky close_fd: 188*ea78f07bSHans Petter Selasky close(fd); 189*ea78f07bSHans Petter Selasky return (res); 190*ea78f07bSHans Petter Selasky } 191*ea78f07bSHans Petter Selasky 192e808190aSHans Petter Selasky static void 193e808190aSHans Petter Selasky usage(void) 194e808190aSHans Petter Selasky { 195e808190aSHans Petter Selasky 196e808190aSHans Petter Selasky fprintf(stderr, 197*ea78f07bSHans Petter Selasky "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |" 198*ea78f07bSHans Petter Selasky " -e | -f fw.mfa2]\n"); 199e808190aSHans Petter Selasky fprintf(stderr, "\t-w - write firmware dump to the specified file\n"); 200e808190aSHans Petter Selasky fprintf(stderr, "\t-r - reset dump\n"); 201e808190aSHans Petter Selasky fprintf(stderr, "\t-e - force dump\n"); 202*ea78f07bSHans Petter Selasky fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n"); 203e808190aSHans Petter Selasky exit(1); 204e808190aSHans Petter Selasky } 205e808190aSHans Petter Selasky 206e808190aSHans Petter Selasky enum mlx5_action { 207e808190aSHans Petter Selasky ACTION_DUMP_GET, 208e808190aSHans Petter Selasky ACTION_DUMP_RESET, 209e808190aSHans Petter Selasky ACTION_DUMP_FORCE, 210*ea78f07bSHans Petter Selasky ACTION_FW_UPDATE, 211e808190aSHans Petter Selasky ACTION_NONE, 212e808190aSHans Petter Selasky }; 213e808190aSHans Petter Selasky 214e808190aSHans Petter Selasky int 215e808190aSHans Petter Selasky main(int argc, char *argv[]) 216e808190aSHans Petter Selasky { 217b255ca09SHans Petter Selasky struct mlx5_tool_addr addr; 218e808190aSHans Petter Selasky char *dumpname; 219e808190aSHans Petter Selasky char *addrstr; 220*ea78f07bSHans Petter Selasky char *img_fw_path; 221e808190aSHans Petter Selasky int c, ctldev, res; 222e808190aSHans Petter Selasky enum mlx5_action act; 223e808190aSHans Petter Selasky 224e808190aSHans Petter Selasky act = ACTION_NONE; 225e808190aSHans Petter Selasky addrstr = NULL; 226e808190aSHans Petter Selasky dumpname = NULL; 227*ea78f07bSHans Petter Selasky img_fw_path = NULL; 228*ea78f07bSHans Petter Selasky while ((c = getopt(argc, argv, "d:ef:ho:rw")) != -1) { 229e808190aSHans Petter Selasky switch (c) { 230e808190aSHans Petter Selasky case 'd': 231e808190aSHans Petter Selasky addrstr = optarg; 232e808190aSHans Petter Selasky break; 233e808190aSHans Petter Selasky case 'w': 234e808190aSHans Petter Selasky act = ACTION_DUMP_GET; 235e808190aSHans Petter Selasky break; 236e808190aSHans Petter Selasky case 'e': 237e808190aSHans Petter Selasky act = ACTION_DUMP_FORCE; 238e808190aSHans Petter Selasky break; 239e808190aSHans Petter Selasky case 'o': 240e808190aSHans Petter Selasky dumpname = optarg; 241e808190aSHans Petter Selasky break; 242e808190aSHans Petter Selasky case 'r': 243e808190aSHans Petter Selasky act = ACTION_DUMP_RESET; 244e808190aSHans Petter Selasky break; 245*ea78f07bSHans Petter Selasky case 'f': 246*ea78f07bSHans Petter Selasky act = ACTION_FW_UPDATE; 247*ea78f07bSHans Petter Selasky img_fw_path = optarg; 248*ea78f07bSHans Petter Selasky break; 249e808190aSHans Petter Selasky case 'h': 250e808190aSHans Petter Selasky default: 251e808190aSHans Petter Selasky usage(); 252e808190aSHans Petter Selasky } 253e808190aSHans Petter Selasky } 254*ea78f07bSHans Petter Selasky if (act == ACTION_NONE || (dumpname != NULL && 255*ea78f07bSHans Petter Selasky act != ACTION_DUMP_GET) || (img_fw_path != NULL && 256*ea78f07bSHans Petter Selasky act != ACTION_FW_UPDATE)) 257e808190aSHans Petter Selasky usage(); 258e808190aSHans Petter Selasky if (parse_pci_addr(addrstr, &addr) != 0) 259e808190aSHans Petter Selasky exit(1); 260e808190aSHans Petter Selasky 261e808190aSHans Petter Selasky ctldev = open(MLX5_DEV_PATH, O_RDWR); 262e808190aSHans Petter Selasky if (ctldev == -1) 263e808190aSHans Petter Selasky err(1, "open "MLX5_DEV_PATH); 264e808190aSHans Petter Selasky switch (act) { 265e808190aSHans Petter Selasky case ACTION_DUMP_GET: 266e808190aSHans Petter Selasky res = mlx5tool_save_dump(ctldev, &addr, dumpname); 267e808190aSHans Petter Selasky break; 268e808190aSHans Petter Selasky case ACTION_DUMP_RESET: 269e808190aSHans Petter Selasky res = mlx5tool_dump_reset(ctldev, &addr); 270e808190aSHans Petter Selasky break; 271e808190aSHans Petter Selasky case ACTION_DUMP_FORCE: 272e808190aSHans Petter Selasky res = mlx5tool_dump_force(ctldev, &addr); 273e808190aSHans Petter Selasky break; 274*ea78f07bSHans Petter Selasky case ACTION_FW_UPDATE: 275*ea78f07bSHans Petter Selasky res = mlx5tool_fw_update(ctldev, &addr, img_fw_path); 276*ea78f07bSHans Petter Selasky break; 277e808190aSHans Petter Selasky default: 278e808190aSHans Petter Selasky res = 0; 279e808190aSHans Petter Selasky break; 280e808190aSHans Petter Selasky } 281e808190aSHans Petter Selasky close(ctldev); 282e808190aSHans Petter Selasky exit(res); 283e808190aSHans Petter Selasky } 284