From d326d79c223b66a841471472c9421c334fd6d167 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 26 Feb 2019 12:20:14 -0800 Subject: [PATCH] devlink: add support for updating device flash Add new command for updating flash of devices via devlink API. Example: $ cp flash-boot.bin /lib/firmware/ $ devlink dev flash pci/0000:05:00.0 file flash-boot.bin Signed-off-by: Jakub Kicinski Acked-by: Jiri Pirko Signed-off-by: David Ahern --- devlink/devlink.c | 54 ++++++++++++++++++++++++++++++++++++++++++ man/man8/devlink-dev.8 | 32 +++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/devlink/devlink.c b/devlink/devlink.c index 960cdda9..5c6cac1f 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -199,6 +199,8 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_REGION_SNAPSHOT_ID BIT(22) #define DL_OPT_REGION_ADDRESS BIT(23) #define DL_OPT_REGION_LENGTH BIT(24) +#define DL_OPT_FLASH_FILE_NAME BIT(25) +#define DL_OPT_FLASH_COMPONENT BIT(26) struct dl_opts { uint32_t present; /* flags of present items */ @@ -230,6 +232,8 @@ struct dl_opts { uint32_t region_snapshot_id; uint64_t region_address; uint64_t region_length; + const char *flash_file_name; + const char *flash_component; }; struct dl { @@ -1185,6 +1189,20 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_REGION_LENGTH; + } else if (dl_argv_match(dl, "file") && + (o_all & DL_OPT_FLASH_FILE_NAME)) { + dl_arg_inc(dl); + err = dl_argv_str(dl, &opts->flash_file_name); + if (err) + return err; + o_found |= DL_OPT_FLASH_FILE_NAME; + } else if (dl_argv_match(dl, "component") && + (o_all & DL_OPT_FLASH_COMPONENT)) { + dl_arg_inc(dl); + err = dl_argv_str(dl, &opts->flash_component); + if (err) + return err; + o_found |= DL_OPT_FLASH_COMPONENT; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -1389,6 +1407,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_REGION_LENGTH) mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN, opts->region_length); + if (opts->present & DL_OPT_FLASH_FILE_NAME) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME, + opts->flash_file_name); + if (opts->present & DL_OPT_FLASH_COMPONENT) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, + opts->flash_component); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1451,6 +1475,7 @@ static void cmd_dev_help(void) pr_err(" devlink dev param show [DEV name PARAMETER]\n"); pr_err(" devlink dev reload DEV\n"); pr_err(" devlink dev info [ DEV ]\n"); + pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n"); } static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, @@ -2583,6 +2608,32 @@ static int cmd_dev_info(struct dl *dl) return err; } +static void cmd_dev_flash_help(void) +{ + pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n"); +} + +static int cmd_dev_flash(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_dev_flash_help(); + return 0; + } + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME, + DL_OPT_FLASH_COMPONENT); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + static int cmd_dev(struct dl *dl) { if (dl_argv_match(dl, "help")) { @@ -2604,6 +2655,9 @@ static int cmd_dev(struct dl *dl) } else if (dl_argv_match(dl, "info")) { dl_arg_inc(dl); return cmd_dev_info(dl); + } else if (dl_argv_match(dl, "flash")) { + dl_arg_inc(dl); + return cmd_dev_flash(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 47838371..1804463b 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -69,6 +69,16 @@ devlink-dev \- devlink device configuration .IR DEV .RI "]" +.ti -8 +.BR "devlink dev flash" +.IR DEV +.BR file +.IR PATH +.RI "[" +.BR target +.IR ID +.RI "]" + .SH "DESCRIPTION" .SS devlink dev show - display devlink device attributes @@ -177,6 +187,28 @@ versions may differ after flash has been updated, but before reboot. - specifies the devlink device to show. If this argument is omitted all devices are listed. +.SS devlink dev flash - write device's non-volatile memory. + +.PP +.I "DEV" +- specifies the devlink device to write to. + +.BR file +.I PATH +- Path to the file which will be written into device's flash. The path needs +to be relative to one of the directories searched by the kernel firmware loaded, +such as /lib/firmware. + +.BR component +.I NAME +- If device stores multiple firmware images in non-volatile memory, this +parameter may be used to indicate which firmware image should be written. +The value of +.I NAME +should match the component names from +.B "devlink dev info" +and may be driver-dependent. + .SH "EXAMPLES" .PP devlink dev show -- 2.39.2