2 * Copyright (c) 2018, Mellanox Technologies, Ltd. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/ioctl.h>
33 #include <dev/mlx5/mlx5io.h>
44 /* stolen from pciconf.c: parsesel() */
46 parse_pci_addr(const char *addrstr, struct mlx5_tool_addr *addr)
49 unsigned long selarr[4];
52 if (addrstr == NULL) {
53 warnx("no pci address specified");
56 if (strncmp(addrstr, "pci", 3) == 0) {
59 while (isdigit(*addrstr) && i < 4) {
60 selarr[i++] = strtoul(addrstr, &eppos, 10);
65 if (i > 0 && *addrstr == '\0') {
66 addr->func = (i > 2) ? selarr[--i] : 0;
67 addr->slot = (i > 0) ? selarr[--i] : 0;
68 addr->bus = (i > 0) ? selarr[--i] : 0;
69 addr->domain = (i > 0) ? selarr[--i] : 0;
73 warnx("invalid pci address %s", addrstr);
78 mlx5tool_save_dump(int ctldev, const struct mlx5_tool_addr *addr,
81 struct mlx5_fwdump_get fdg;
82 struct mlx5_fwdump_reg *rege;
90 dump = fopen(dumpname, "w");
92 warn("open %s", dumpname);
96 memset(&fdg, 0, sizeof(fdg));
98 error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
100 warn("MLX5_FWDUMP_GET dumpsize");
103 rege = calloc(fdg.reg_filled, sizeof(*rege));
109 fdg.reg_cnt = fdg.reg_filled;
110 error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
113 warnx("no dump recorded");
115 warn("MLX5_FWDUMP_GET dump fetch");
118 for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++)
119 fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val);
128 mlx5tool_dump_reset(int ctldev, const struct mlx5_tool_addr *addr)
131 if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) {
132 warn("MLX5_FWDUMP_RESET");
139 mlx5tool_dump_force(int ctldev, const struct mlx5_tool_addr *addr)
142 if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) {
143 warn("MLX5_FWDUMP_FORCE");
150 mlx5tool_fw_update(int ctldev, const struct mlx5_tool_addr *addr,
151 const char *img_fw_path)
154 struct mlx5_fw_update fwup;
158 fd = open(img_fw_path, O_RDONLY);
160 warn("Unable to open %s", img_fw_path);
164 error = fstat(fd, &st);
166 warn("Unable to stat %s", img_fw_path);
170 memset(&fwup, 0, sizeof(fwup));
171 memcpy(&fwup.devaddr, addr, sizeof(fwup.devaddr));
172 fwup.img_fw_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE,
174 if (fwup.img_fw_data == MAP_FAILED) {
175 warn("Unable to mmap %s", img_fw_path);
179 fwup.img_fw_data_len = st.st_size;
181 error = ioctl(ctldev, MLX5_FW_UPDATE, &fwup);
183 warn("MLX5_FW_UPDATE");
186 munmap(fwup.img_fw_data, st.st_size);
193 mlx5tool_fw_reset(int ctldev, const struct mlx5_tool_addr *addr)
196 if (ioctl(ctldev, MLX5_FW_RESET, addr) == -1) {
197 warn("MLX5_FW_RESET");
203 #define MLX5_EEPROM_HIGH_PAGE_OFFSET 128
204 #define MLX5_EEPROM_PAGE_LENGTH 256
207 mlx5tool_eeprom_print(struct mlx5_eeprom_get *eeprom_info)
209 int index_in_row, line_length, row;
210 size_t byte_to_write;
215 printf("\nOffset\t\tValues\n");
216 printf("------\t\t------");
217 while (byte_to_write < eeprom_info->eeprom_info_out_len) {
218 printf("\n0x%04zX\t\t", byte_to_write);
219 for (index_in_row = 0; index_in_row < line_length;
222 ((uint8_t *)eeprom_info->eeprom_info_buf)[
228 if (eeprom_info->eeprom_info_page_valid) {
229 row = MLX5_EEPROM_HIGH_PAGE_OFFSET;
230 printf("\n\nUpper Page 0x03\n");
231 printf("\nOffset\t\tValues\n");
232 printf("------\t\t------");
233 for (row = MLX5_EEPROM_HIGH_PAGE_OFFSET;
234 row < MLX5_EEPROM_PAGE_LENGTH;) {
235 printf("\n0x%04X\t\t", row);
236 for (index_in_row = 0;
237 index_in_row < line_length;
240 ((uint8_t *)eeprom_info->
241 eeprom_info_buf)[byte_to_write]);
251 mlx5tool_get_eeprom_info(int ctldev, const struct mlx5_tool_addr *addr)
253 struct mlx5_eeprom_get eeprom_info;
256 memset(&eeprom_info, 0, sizeof(eeprom_info));
257 eeprom_info.devaddr = *addr;
259 error = ioctl(ctldev, MLX5_EEPROM_GET, &eeprom_info);
261 warn("MLX5_EEPROM_GET");
264 eeprom_info.eeprom_info_buf =
265 malloc(eeprom_info.eeprom_info_out_len + MLX5_EEPROM_PAGE_LENGTH);
266 if (eeprom_info.eeprom_info_buf == NULL) {
267 warn("alloc eeprom_info.eeprom_info_buf ");
270 error = ioctl(ctldev, MLX5_EEPROM_GET, &eeprom_info);
272 warn("MLX5_EEPROM_GET");
273 free(eeprom_info.eeprom_info_buf);
277 mlx5tool_eeprom_print(&eeprom_info);
279 free(eeprom_info.eeprom_info_buf);
288 "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |"
289 " -e | -f fw.mfa2 | -z]\n");
290 fprintf(stderr, "\t-w - write firmware dump to the specified file\n");
291 fprintf(stderr, "\t-r - reset dump\n");
292 fprintf(stderr, "\t-E - get eeprom info\n");
293 fprintf(stderr, "\t-e - force dump\n");
294 fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n");
295 fprintf(stderr, "\t-z - initiate firmware reset\n");
305 ACTION_GET_EEPROM_INFO,
310 main(int argc, char *argv[])
312 struct mlx5_tool_addr addr;
317 enum mlx5_action act;
323 while ((c = getopt(argc, argv, "d:Eef:ho:rwz")) != -1) {
329 if (act != ACTION_NONE)
331 act = ACTION_DUMP_GET;
334 if (act != ACTION_NONE)
336 act = ACTION_GET_EEPROM_INFO;
339 if (act != ACTION_NONE)
341 act = ACTION_DUMP_FORCE;
347 if (act != ACTION_NONE)
349 act = ACTION_DUMP_RESET;
352 if (act != ACTION_NONE)
354 act = ACTION_FW_UPDATE;
355 img_fw_path = optarg;
358 if (act != ACTION_NONE)
360 act = ACTION_FW_RESET;
367 if (act == ACTION_NONE || (dumpname != NULL &&
368 act != ACTION_DUMP_GET) || (img_fw_path != NULL &&
369 act != ACTION_FW_UPDATE))
371 if (parse_pci_addr(addrstr, &addr) != 0)
374 ctldev = open(MLX5_DEV_PATH, O_RDWR);
376 err(1, "open "MLX5_DEV_PATH);
378 case ACTION_DUMP_GET:
379 res = mlx5tool_save_dump(ctldev, &addr, dumpname);
381 case ACTION_DUMP_RESET:
382 res = mlx5tool_dump_reset(ctldev, &addr);
384 case ACTION_DUMP_FORCE:
385 res = mlx5tool_dump_force(ctldev, &addr);
387 case ACTION_FW_UPDATE:
388 res = mlx5tool_fw_update(ctldev, &addr, img_fw_path);
390 case ACTION_FW_RESET:
391 res = mlx5tool_fw_reset(ctldev, &addr);
393 case ACTION_GET_EEPROM_INFO:
394 res = mlx5tool_get_eeprom_info(ctldev, &addr);