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