xref: /freebsd/usr.sbin/mlx5tool/mlx5tool.c (revision b4b75592d633f8c99c0d1627e98d76dc6cd8557f)
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