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:
parent
b255ca093a
commit
ea78f07b5e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=347288
@ -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_fwdump_get *fwg;
|
||||||
struct mlx5_tool_addr *devaddr;
|
struct mlx5_tool_addr *devaddr;
|
||||||
struct mlx5_dump_data *dd;
|
struct mlx5_dump_data *dd;
|
||||||
|
struct mlx5_fw_update *fu;
|
||||||
|
struct firmware fake_fw;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
@ -275,6 +277,36 @@ mlx5_fwdump_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
|||||||
break;
|
break;
|
||||||
mlx5_fwdump(mdev);
|
mlx5_fwdump(mdev);
|
||||||
break;
|
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:
|
default:
|
||||||
error = ENOTTY;
|
error = ENOTTY;
|
||||||
break;
|
break;
|
||||||
|
@ -49,9 +49,16 @@ struct mlx5_fwdump_get {
|
|||||||
size_t reg_filled; /* out */
|
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_GET _IOWR('m', 1, struct mlx5_fwdump_get)
|
||||||
#define MLX5_FWDUMP_RESET _IOW('m', 2, struct mlx5_tool_addr)
|
#define MLX5_FWDUMP_RESET _IOW('m', 2, struct mlx5_tool_addr)
|
||||||
#define MLX5_FWDUMP_FORCE _IOW('m', 3, 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
|
#ifndef _KERNEL
|
||||||
#define MLX5_DEV_PATH _PATH_DEV"mlx5ctl"
|
#define MLX5_DEV_PATH _PATH_DEV"mlx5ctl"
|
||||||
|
@ -28,6 +28,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <dev/mlx5/mlx5io.h>
|
#include <dev/mlx5/mlx5io.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
@ -144,15 +146,60 @@ mlx5tool_dump_force(int ctldev, const struct mlx5_tool_addr *addr)
|
|||||||
return (0);
|
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
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(stderr,
|
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-w - write firmware dump to the specified file\n");
|
||||||
fprintf(stderr, "\t-r - reset dump\n");
|
fprintf(stderr, "\t-r - reset dump\n");
|
||||||
fprintf(stderr, "\t-e - force dump\n");
|
fprintf(stderr, "\t-e - force dump\n");
|
||||||
|
fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +207,7 @@ enum mlx5_action {
|
|||||||
ACTION_DUMP_GET,
|
ACTION_DUMP_GET,
|
||||||
ACTION_DUMP_RESET,
|
ACTION_DUMP_RESET,
|
||||||
ACTION_DUMP_FORCE,
|
ACTION_DUMP_FORCE,
|
||||||
|
ACTION_FW_UPDATE,
|
||||||
ACTION_NONE,
|
ACTION_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,13 +217,15 @@ main(int argc, char *argv[])
|
|||||||
struct mlx5_tool_addr addr;
|
struct mlx5_tool_addr addr;
|
||||||
char *dumpname;
|
char *dumpname;
|
||||||
char *addrstr;
|
char *addrstr;
|
||||||
|
char *img_fw_path;
|
||||||
int c, ctldev, res;
|
int c, ctldev, res;
|
||||||
enum mlx5_action act;
|
enum mlx5_action act;
|
||||||
|
|
||||||
act = ACTION_NONE;
|
act = ACTION_NONE;
|
||||||
addrstr = NULL;
|
addrstr = NULL;
|
||||||
dumpname = 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) {
|
switch (c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
addrstr = optarg;
|
addrstr = optarg;
|
||||||
@ -192,12 +242,18 @@ main(int argc, char *argv[])
|
|||||||
case 'r':
|
case 'r':
|
||||||
act = ACTION_DUMP_RESET;
|
act = ACTION_DUMP_RESET;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
act = ACTION_FW_UPDATE;
|
||||||
|
img_fw_path = optarg;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
usage();
|
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();
|
usage();
|
||||||
if (parse_pci_addr(addrstr, &addr) != 0)
|
if (parse_pci_addr(addrstr, &addr) != 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -215,6 +271,9 @@ main(int argc, char *argv[])
|
|||||||
case ACTION_DUMP_FORCE:
|
case ACTION_DUMP_FORCE:
|
||||||
res = mlx5tool_dump_force(ctldev, &addr);
|
res = mlx5tool_dump_force(ctldev, &addr);
|
||||||
break;
|
break;
|
||||||
|
case ACTION_FW_UPDATE:
|
||||||
|
res = mlx5tool_fw_update(ctldev, &addr, img_fw_path);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
res = 0;
|
res = 0;
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user