Implement userspace firmware update for ConnectX-4/5/6.

Submitted by:	kib@
MFC after:	3 days
Sponsored by:	Mellanox Technologies
This commit is contained in:
Hans Petter Selasky 2019-05-08 10:50:35 +00:00
parent b255ca093a
commit ea78f07b5e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=347288
3 changed files with 101 additions and 3 deletions

View File

@ -233,6 +233,8 @@ mlx5_fwdump_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
struct mlx5_fwdump_get *fwg;
struct mlx5_tool_addr *devaddr;
struct mlx5_dump_data *dd;
struct mlx5_fw_update *fu;
struct firmware fake_fw;
int error;
error = 0;
@ -275,6 +277,36 @@ mlx5_fwdump_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
break;
mlx5_fwdump(mdev);
break;
case MLX5_FW_UPDATE:
if ((fflag & FWRITE) == 0) {
error = EBADF;
break;
}
fu = (struct mlx5_fw_update *)data;
if (fu->img_fw_data_len > 10 * 1024 * 1024) {
error = EINVAL;
break;
}
devaddr = &fu->devaddr;
error = mlx5_dbsf_to_core(devaddr, &mdev);
if (error != 0)
break;
bzero(&fake_fw, sizeof(fake_fw));
fake_fw.name = "umlx_fw_up";
fake_fw.datasize = fu->img_fw_data_len;
fake_fw.version = 1;
fake_fw.data = (void *)kmem_malloc(fu->img_fw_data_len,
M_WAITOK);
if (fake_fw.data == NULL) {
error = ENOMEM;
break;
}
error = copyin(fu->img_fw_data, __DECONST(void *, fake_fw.data),
fu->img_fw_data_len);
if (error == 0)
error = -mlx5_firmware_flash(mdev, &fake_fw);
kmem_free((vm_offset_t)fake_fw.data, fu->img_fw_data_len);
break;
default:
error = ENOTTY;
break;

View File

@ -49,9 +49,16 @@ struct mlx5_fwdump_get {
size_t reg_filled; /* out */
};
struct mlx5_fw_update {
struct mlx5_tool_addr devaddr;
void *img_fw_data;
size_t img_fw_data_len;
};
#define MLX5_FWDUMP_GET _IOWR('m', 1, struct mlx5_fwdump_get)
#define MLX5_FWDUMP_RESET _IOW('m', 2, struct mlx5_tool_addr)
#define MLX5_FWDUMP_FORCE _IOW('m', 3, struct mlx5_tool_addr)
#define MLX5_FW_UPDATE _IOW('m', 4, struct mlx5_fw_update)
#ifndef _KERNEL
#define MLX5_DEV_PATH _PATH_DEV"mlx5ctl"

View File

@ -28,6 +28,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <dev/mlx5/mlx5io.h>
#include <ctype.h>
#include <err.h>
@ -144,15 +146,60 @@ mlx5tool_dump_force(int ctldev, const struct mlx5_tool_addr *addr)
return (0);
}
static int
mlx5tool_fw_update(int ctldev, const struct mlx5_tool_addr *addr,
const char *img_fw_path)
{
struct stat st;
struct mlx5_fw_update fwup;
int error, fd, res;
res = 0;
fd = open(img_fw_path, O_RDONLY);
if (fd == -1) {
warn("Unable to open %s", img_fw_path);
res = 1;
goto close_fd;
}
error = fstat(fd, &st);
if (error != 0) {
warn("Unable to stat %s", img_fw_path);
res = 1;
goto close_fd;
}
memset(&fwup, 0, sizeof(fwup));
memcpy(&fwup.devaddr, addr, sizeof(fwup.devaddr));
fwup.img_fw_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE,
fd, 0);
if (fwup.img_fw_data == MAP_FAILED) {
warn("Unable to mmap %s", img_fw_path);
res = 1;
goto close_fd;
}
fwup.img_fw_data_len = st.st_size;
error = ioctl(ctldev, MLX5_FW_UPDATE, &fwup);
if (error == -1) {
warn("MLX5_FW_UPDATE");
}
munmap(fwup.img_fw_data, st.st_size);
close_fd:
close(fd);
return (res);
}
static void
usage(void)
{
fprintf(stderr,
"Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r | -e]\n");
"Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |"
" -e | -f fw.mfa2]\n");
fprintf(stderr, "\t-w - write firmware dump to the specified file\n");
fprintf(stderr, "\t-r - reset dump\n");
fprintf(stderr, "\t-e - force dump\n");
fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n");
exit(1);
}
@ -160,6 +207,7 @@ enum mlx5_action {
ACTION_DUMP_GET,
ACTION_DUMP_RESET,
ACTION_DUMP_FORCE,
ACTION_FW_UPDATE,
ACTION_NONE,
};
@ -169,13 +217,15 @@ main(int argc, char *argv[])
struct mlx5_tool_addr addr;
char *dumpname;
char *addrstr;
char *img_fw_path;
int c, ctldev, res;
enum mlx5_action act;
act = ACTION_NONE;
addrstr = NULL;
dumpname = NULL;
while ((c = getopt(argc, argv, "d:eho:rw")) != -1) {
img_fw_path = NULL;
while ((c = getopt(argc, argv, "d:ef:ho:rw")) != -1) {
switch (c) {
case 'd':
addrstr = optarg;
@ -192,12 +242,18 @@ main(int argc, char *argv[])
case 'r':
act = ACTION_DUMP_RESET;
break;
case 'f':
act = ACTION_FW_UPDATE;
img_fw_path = optarg;
break;
case 'h':
default:
usage();
}
}
if (act == ACTION_NONE || (dumpname != NULL && act != ACTION_DUMP_GET))
if (act == ACTION_NONE || (dumpname != NULL &&
act != ACTION_DUMP_GET) || (img_fw_path != NULL &&
act != ACTION_FW_UPDATE))
usage();
if (parse_pci_addr(addrstr, &addr) != 0)
exit(1);
@ -215,6 +271,9 @@ main(int argc, char *argv[])
case ACTION_DUMP_FORCE:
res = mlx5tool_dump_force(ctldev, &addr);
break;
case ACTION_FW_UPDATE:
res = mlx5tool_fw_update(ctldev, &addr, img_fw_path);
break;
default:
res = 0;
break;