diff --git a/devlink/devlink.c b/devlink/devlink.c index 42fa7167..784bb84b 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,10 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_PARAM_NAME BIT(18) #define DL_OPT_PARAM_VALUE BIT(19) #define DL_OPT_PARAM_CMODE BIT(20) +#define DL_OPT_HANDLE_REGION BIT(21) +#define DL_OPT_REGION_SNAPSHOT_ID BIT(22) +#define DL_OPT_REGION_ADDRESS BIT(23) +#define DL_OPT_REGION_LENGTH BIT(24) struct dl_opts { uint32_t present; /* flags of present items */ @@ -221,6 +226,10 @@ struct dl_opts { const char *param_name; const char *param_value; enum devlink_param_cmode cmode; + char *region_name; + uint32_t region_snapshot_id; + uint64_t region_address; + uint64_t region_length; }; struct dl { @@ -364,6 +373,16 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED, [DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED, [DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8, + [DEVLINK_ATTR_REGION_NAME] = MNL_TYPE_STRING, + [DEVLINK_ATTR_REGION_SIZE] = MNL_TYPE_U64, + [DEVLINK_ATTR_REGION_SNAPSHOTS] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_REGION_SNAPSHOT] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = MNL_TYPE_U32, + [DEVLINK_ATTR_REGION_CHUNKS] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_REGION_CHUNK] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_REGION_CHUNK_DATA] = MNL_TYPE_BINARY, + [DEVLINK_ATTR_REGION_CHUNK_ADDR] = MNL_TYPE_U64, + [DEVLINK_ATTR_REGION_CHUNK_LEN] = MNL_TYPE_U64, }; static int attr_cb(const struct nlattr *attr, void *data) @@ -502,6 +521,20 @@ static int strslashrsplit(char *str, char **before, char **after) return 0; } +static int strtouint64_t(const char *str, uint64_t *p_val) +{ + char *endptr; + unsigned long long int val; + + val = strtoull(str, &endptr, 10); + if (endptr == str || *endptr != '\0') + return -EINVAL; + if (val > ULONG_MAX) + return -ERANGE; + *p_val = val; + return 0; +} + static int strtouint32_t(const char *str, uint32_t *p_val) { char *endptr; @@ -687,6 +720,64 @@ static int dl_argv_handle_both(struct dl *dl, char **p_bus_name, return 0; } +static int __dl_argv_handle_region(char *str, char **p_bus_name, + char **p_dev_name, char **p_region) +{ + char *handlestr; + int err; + + err = strslashrsplit(str, &handlestr, p_region); + if (err) { + pr_err("Region identification \"%s\" is invalid\n", str); + return err; + } + err = strslashrsplit(handlestr, p_bus_name, p_dev_name); + if (err) { + pr_err("Region identification \"%s\" is invalid\n", str); + return err; + } + return 0; +} + +static int dl_argv_handle_region(struct dl *dl, char **p_bus_name, + char **p_dev_name, char **p_region) +{ + char *str = dl_argv_next(dl); + unsigned int slash_count; + + if (!str) { + pr_err("Expected \"bus_name/dev_name/region\" identification.\n"); + return -EINVAL; + } + + slash_count = strslashcount(str); + if (slash_count != 2) { + pr_err("Wrong region identification string format.\n"); + pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n"); + return -EINVAL; + } + + return __dl_argv_handle_region(str, p_bus_name, p_dev_name, p_region); +} + +static int dl_argv_uint64_t(struct dl *dl, uint64_t *p_val) +{ + char *str = dl_argv_next(dl); + int err; + + if (!str) { + pr_err("Unsigned number argument expected\n"); + return -EINVAL; + } + + err = strtouint64_t(str, p_val); + if (err) { + pr_err("\"%s\" is not a number or not within range\n", str); + return err; + } + return 0; +} + static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) { char *str = dl_argv_next(dl); @@ -879,6 +970,13 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_HANDLEP; + } else if (o_required & DL_OPT_HANDLE_REGION) { + err = dl_argv_handle_region(dl, &opts->bus_name, + &opts->dev_name, + &opts->region_name); + if (err) + return err; + o_found |= DL_OPT_HANDLE_REGION; } while (dl_argc(dl)) { @@ -1059,6 +1157,27 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_PARAM_CMODE; + } else if (dl_argv_match(dl, "snapshot") && + (o_all & DL_OPT_REGION_SNAPSHOT_ID)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->region_snapshot_id); + if (err) + return err; + o_found |= DL_OPT_REGION_SNAPSHOT_ID; + } else if (dl_argv_match(dl, "address") && + (o_all & DL_OPT_REGION_ADDRESS)) { + dl_arg_inc(dl); + err = dl_argv_uint64_t(dl, &opts->region_address); + if (err) + return err; + o_found |= DL_OPT_REGION_ADDRESS; + } else if (dl_argv_match(dl, "length") && + (o_all & DL_OPT_REGION_LENGTH)) { + dl_arg_inc(dl); + err = dl_argv_uint64_t(dl, &opts->region_length); + if (err) + return err; + o_found |= DL_OPT_REGION_LENGTH; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -1161,6 +1280,24 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } + if ((o_required & DL_OPT_REGION_SNAPSHOT_ID) && + !(o_found & DL_OPT_REGION_SNAPSHOT_ID)) { + pr_err("Region snapshot id expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_REGION_ADDRESS) && + !(o_found & DL_OPT_REGION_ADDRESS)) { + pr_err("Region address value expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_REGION_LENGTH) && + !(o_found & DL_OPT_REGION_LENGTH)) { + pr_err("Region length value expected.\n"); + return -EINVAL; + } + return 0; } @@ -1176,6 +1313,11 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name); mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, opts->port_index); + } else if (opts->present & DL_OPT_HANDLE_REGION) { + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, + opts->region_name); } if (opts->present & DL_OPT_PORT_TYPE) mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, @@ -1231,6 +1373,15 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_PARAM_CMODE) mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, opts->cmode); + if (opts->present & DL_OPT_REGION_SNAPSHOT_ID) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, + opts->region_snapshot_id); + if (opts->present & DL_OPT_REGION_ADDRESS) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR, + opts->region_address); + if (opts->present & DL_OPT_REGION_LENGTH) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN, + opts->region_length); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1533,6 +1684,49 @@ static void pr_out_u64(struct dl *dl, const char *name, uint64_t val) return pr_out_uint(dl, name, val); } +static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr) +{ + if (dl->json_output) { + jsonw_name(dl->jw, "address"); + jsonw_uint(dl->jw, addr); + jsonw_name(dl->jw, "data"); + jsonw_start_array(dl->jw); + } +} + +static void pr_out_region_chunk_end(struct dl *dl) +{ + if (dl->json_output) + jsonw_end_array(dl->jw); +} + +static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len, + uint64_t addr) +{ + static uint64_t align_val; + uint32_t i = 0; + + pr_out_region_chunk_start(dl, addr); + while (i < len) { + if (!dl->json_output) + if (!(align_val % 16)) + pr_out("%s%016"PRIx64" ", + align_val ? "\n" : "", + addr); + + align_val++; + + if (dl->json_output) + jsonw_printf(dl->jw, "%d", data[i]); + else + pr_out("%02x ", data[i]); + + addr++; + i++; + } + pr_out_region_chunk_end(dl); +} + static void pr_out_dev(struct dl *dl, struct nlattr **tb) { pr_out_handle(dl, tb); @@ -3070,6 +3264,10 @@ static const char *cmd_name(uint8_t cmd) case DEVLINK_CMD_PARAM_SET: return "set"; case DEVLINK_CMD_PARAM_NEW: return "new"; case DEVLINK_CMD_PARAM_DEL: return "del"; + case DEVLINK_CMD_REGION_GET: return "get"; + case DEVLINK_CMD_REGION_SET: return "set"; + case DEVLINK_CMD_REGION_NEW: return "new"; + case DEVLINK_CMD_REGION_DEL: return "del"; default: return ""; } } @@ -3093,6 +3291,11 @@ static const char *cmd_obj(uint8_t cmd) case DEVLINK_CMD_PARAM_NEW: case DEVLINK_CMD_PARAM_DEL: return "param"; + case DEVLINK_CMD_REGION_GET: + case DEVLINK_CMD_REGION_SET: + case DEVLINK_CMD_REGION_NEW: + case DEVLINK_CMD_REGION_DEL: + return "region"; default: return ""; } } @@ -3117,6 +3320,8 @@ static bool cmd_filter_check(struct dl *dl, uint8_t cmd) return false; } +static void pr_out_region(struct dl *dl, struct nlattr **tb); + static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) { struct dl *dl = data; @@ -3160,6 +3365,17 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) pr_out_mon_header(genl->cmd); pr_out_param(dl, tb, false); break; + case DEVLINK_CMD_REGION_GET: /* fall through */ + case DEVLINK_CMD_REGION_SET: /* fall through */ + case DEVLINK_CMD_REGION_NEW: /* fall through */ + case DEVLINK_CMD_REGION_DEL: + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_REGION_NAME]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); + pr_out_region(dl, tb); + break; } return MNL_CB_OK; } @@ -4941,11 +5157,275 @@ static int cmd_resource(struct dl *dl) return -ENOENT; } +static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb) +{ + const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]); + char buf[256]; + + sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name); + if (dl->json_output) { + jsonw_name(dl->jw, buf); + jsonw_start_object(dl->jw); + } else { + pr_out("%s:", buf); + } +} + +static void pr_out_region_handle_end(struct dl *dl) +{ + if (dl->json_output) + jsonw_end_object(dl->jw); + else + pr_out("\n"); +} + +static void pr_out_region_snapshots_start(struct dl *dl, bool array) +{ + if (dl->json_output) { + jsonw_name(dl->jw, "snapshot"); + jsonw_start_array(dl->jw); + } else { + if (g_indent_newline) + pr_out("snapshot %s", array ? "[" : ""); + else + pr_out(" snapshot %s", array ? "[" : ""); + } +} + +static void pr_out_region_snapshots_end(struct dl *dl, bool array) +{ + if (dl->json_output) + jsonw_end_array(dl->jw); + else if (array) + pr_out("]"); +} + +static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index) +{ + uint32_t snapshot_id; + + if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) + return; + + snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]); + + if (dl->json_output) + jsonw_uint(dl->jw, snapshot_id); + else + pr_out("%s%u", index ? " " : "", snapshot_id); +} + +static void pr_out_snapshots(struct dl *dl, struct nlattr **tb) +{ + struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {}; + struct nlattr *nla_sanpshot; + int err, index = 0; + + pr_out_region_snapshots_start(dl, true); + mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) { + err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot); + if (err != MNL_CB_OK) + return; + pr_out_region_snapshots_id(dl, tb_snapshot, index++); + } + pr_out_region_snapshots_end(dl, true); +} + +static void pr_out_snapshot(struct dl *dl, struct nlattr **tb) +{ + pr_out_region_snapshots_start(dl, false); + pr_out_region_snapshots_id(dl, tb, 0); + pr_out_region_snapshots_end(dl, false); +} + +static void pr_out_region(struct dl *dl, struct nlattr **tb) +{ + pr_out_region_handle_start(dl, tb); + + if (tb[DEVLINK_ATTR_REGION_SIZE]) + pr_out_u64(dl, "size", + mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE])); + + if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) + pr_out_snapshots(dl, tb); + + if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) + pr_out_snapshot(dl, tb); + + pr_out_region_handle_end(dl); +} + +static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct dl *dl = data; + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE]) + return MNL_CB_ERROR; + + pr_out_region(dl, tb); + + return MNL_CB_OK; +} + +static int cmd_region_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0); + if (err) + return err; + } + + pr_out_section_start(dl, "regions"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl); + pr_out_section_end(dl); + return err; +} + +static int cmd_region_snapshot_del(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION | + DL_OPT_REGION_SNAPSHOT_ID, 0); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {}; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct dl *dl = data; + int err; + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_REGION_CHUNKS]) + return MNL_CB_ERROR; + + mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) { + err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field); + if (err != MNL_CB_OK) + return MNL_CB_ERROR; + + nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA]; + if (!nla_chunk_data) + continue; + + nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR]; + if (!nla_chunk_addr) + continue; + + pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data), + mnl_attr_get_payload_len(nla_chunk_data), + mnl_attr_get_u64(nla_chunk_addr)); + } + return MNL_CB_OK; +} + +static int cmd_region_dump(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ, + NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION | + DL_OPT_REGION_SNAPSHOT_ID, 0); + if (err) + return err; + + pr_out_section_start(dl, "dump"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl); + pr_out_section_end(dl); + if (!dl->json_output) + pr_out("\n"); + return err; +} + +static int cmd_region_read(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ, + NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION | + DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH | + DL_OPT_REGION_SNAPSHOT_ID, 0); + if (err) + return err; + + pr_out_section_start(dl, "read"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl); + pr_out_section_end(dl); + if (!dl->json_output) + pr_out("\n"); + return err; +} + +static void cmd_region_help(void) +{ + pr_err("Usage: devlink region show [ DEV/REGION ]\n"); + pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n"); + pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n"); + pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n"); +} + +static int cmd_region(struct dl *dl) +{ + if (dl_no_arg(dl)) { + return cmd_region_show(dl); + } else if (dl_argv_match(dl, "help")) { + cmd_region_help(); + return 0; + } else if (dl_argv_match(dl, "show")) { + dl_arg_inc(dl); + return cmd_region_show(dl); + } else if (dl_argv_match(dl, "del")) { + dl_arg_inc(dl); + return cmd_region_snapshot_del(dl); + } else if (dl_argv_match(dl, "dump")) { + dl_arg_inc(dl); + return cmd_region_dump(dl); + } else if (dl_argv_match(dl, "read")) { + dl_arg_inc(dl); + return cmd_region_read(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static void help(void) { pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" " devlink [ -f[orce] ] -b[atch] filename\n" - "where OBJECT := { dev | port | sb | monitor | dpipe | resource }\n" + "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region }\n" " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\n"); } @@ -4975,6 +5455,9 @@ static int dl_cmd(struct dl *dl, int argc, char **argv) } else if (dl_argv_match(dl, "resource")) { dl_arg_inc(dl); return cmd_resource(dl); + } else if (dl_argv_match(dl, "region")) { + dl_arg_inc(dl); + return cmd_region(dl); } pr_err("Object \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/man/man8/devlink-region.8 b/man/man8/devlink-region.8 new file mode 100644 index 00000000..ff10cdbd --- /dev/null +++ b/man/man8/devlink-region.8 @@ -0,0 +1,131 @@ +.TH DEVLINK\-REGION 8 "10 Jan 2018" "iproute2" "Linux" +.SH NAME +devlink-region \- devlink address region access +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.B devlink +.RI "[ " OPTIONS " ]" +.B region +.RI " { " COMMAND " | " +.BR help " }" +.sp + +.ti -8 +.IR OPTIONS " := { " +\fB\-V\fR[\fIersion\fR] | +\fB\-n\fR[\fIno-nice-names\fR] } + +.ti -8 +.BR "devlink region show" +.RI "[ " DEV/REGION " ]" + +.ti -8 +.BR "devlink region del" +.RI "" DEV/REGION "" +.BR "snapshot" +.RI "" SNAPSHOT_ID "" + +.ti -8 +.BR "devlink region dump" +.RI "" DEV/REGION "" +.BR "snapshot" +.RI "" SNAPSHOT_ID "" + +.ti -8 +.BR "devlink region read" +.RI "" DEV/REGION "" +.BR "[ " +.BR "snapshot" +.RI "" SNAPSHOT_ID "" +.BR "]" +.BR "address" +.RI "" ADDRESS " +.BR "length" +.RI "" LENGTH "" + +.ti -8 +.B devlink region help + +.SH "DESCRIPTION" +.SS devlink region show - Show all supported address regions names, snapshots and sizes + +.PP +.I "DEV/REGION" +- specifies the devlink device and address-region to query. + +.SS devlink region del - Delete a snapshot specified by address-region name and snapshot ID + +.PP +.I "DEV/REGION" +- specifies the devlink device and address-region to delete the snapshot from + +.PP +snapshot +.I "SNAPSHOT_ID" +- specifies the snapshot ID to delete + +.SS devlink region dump - Dump all the available data from a region or from snapshot of a region + +.PP +.I "DEV/REGION" +- specifies the device and address-region to dump from. + +.PP +snapshot +.I "SNAPSHOT_ID" +- specifies the snapshot-id of the region to dump. + +.SS devlink region read - Read from a specific region address for a given length + +.PP +.I "DEV/REGION" +- specifies the device and address-region to read from. + +.PP +snapshot +.I "SNAPSHOT_ID" +- specifies the snapshot-id of the region to read. + +.PP +address +.I "ADDRESS" +- specifies the address to read from. + +.PP +length +.I "LENGTH" +- specifies the length of data to read. + +.SH "EXAMPLES" +.PP +devlink region show +.RS 4 +List available address regions and snapshot. +.RE +.PP +devlink region del pci/0000:00:05.0/cr-space snapshot 1 +.RS 4 +Delete snapshot id 1 from cr-space address region from device pci/0000:00:05.0. +.RE +.PP +devlink region dump pci/0000:00:05.0/cr-space snapshot 1 +.RS 4 +Dump the snapshot taken from cr-space address region with ID 1 +.RE +.PP +devlink region read pci/0000:00:05.0/cr-space snapshot 1 address 0x10 legth 16 +.RS 4 +Read from address 0x10, 16 Bytes of snapshot ID 1 taken from cr-space address region + +.SH SEE ALSO +.BR devlink (8), +.BR devlink-dev (8), +.BR devlink-port (8), +.BR devlink-monitor (8), +.br + +.SH AUTHOR +Alex Vesker diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 index 7986310f..4cf6762a 100644 --- a/man/man8/devlink.8 +++ b/man/man8/devlink.8 @@ -112,6 +112,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR devlink-monitor (8), .BR devlink-sb (8), .BR devlink-resource (8), +.BR devlink-region (8), .br .SH REPORTING BUGS