From patchwork Tue Jul 17 08:34:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Vesker X-Patchwork-Id: 944812 X-Patchwork-Delegate: dsahern@gmail.com Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 41VD9G3L2Hz9s0n for ; Tue, 17 Jul 2018 18:34:42 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729473AbeGQJGI (ORCPT ); Tue, 17 Jul 2018 05:06:08 -0400 Received: from mail-il-dmz.mellanox.com ([193.47.165.129]:49150 "EHLO mellanox.co.il" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728288AbeGQJGI (ORCPT ); Tue, 17 Jul 2018 05:06:08 -0400 Received: from Internal Mail-Server by MTLPINE1 (envelope-from valex@mellanox.com) with ESMTPS (AES256-SHA encrypted); 17 Jul 2018 11:37:38 +0300 Received: from dev-l-vrt-144-018.mtl.labs.mlnx (dev-l-vrt-144-018.mtl.labs.mlnx [10.134.144.18]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id w6H8YW4u002825; Tue, 17 Jul 2018 11:34:32 +0300 Received: from dev-l-vrt-144-018.mtl.labs.mlnx (localhost [127.0.0.1]) by dev-l-vrt-144-018.mtl.labs.mlnx (8.14.7/8.14.7) with ESMTP id w6H8YWkp015901; Tue, 17 Jul 2018 11:34:32 +0300 Received: (from valex@localhost) by dev-l-vrt-144-018.mtl.labs.mlnx (8.14.7/8.14.7/Submit) id w6H8YSdP015899; Tue, 17 Jul 2018 11:34:28 +0300 From: Alex Vesker To: netdev@vger.kernel.org, jiri@mellanox.com Cc: Alex Vesker Subject: [PATCH iproute2 net-next] devlink: Add support for devlink-region access Date: Tue, 17 Jul 2018 11:34:27 +0300 Message-Id: <1531816467-15860-1-git-send-email-valex@mellanox.com> X-Mailer: git-send-email 1.8.3.1 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Devlink region allows access to driver defined address regions. Each device can create its supported address regions and register them. A device which exposes a region will allow access to it using devlink. This support allows reading and dumping regions snapshots as well as presenting information such as region size and current available snapshots. A snapshot represents a memory image of a region taken by the driver. If a device collects a snapshot of an address region it can be later exposed using devlink region read or dump commands. This functionality allows for future analyses on the snapshots. The dump command is designed to read the full address space of a region or of a snapshot unlike the read command which allows reading only a specific section in a region/snapshot indicated by an address and a length, current support is for reading and dumping for a previously taken snapshot ID. New commands added: devlink region show [ DEV/REGION ] devlink region delete DEV/REGION snapshot SNAPSHOT_ID devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ] devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length length Signed-off-by: Alex Vesker Signed-off-by: Jiri Pirko --- devlink/devlink.c | 485 +++++++++++++++++++++++++++++++++++++++++++++- man/man8/devlink-region.8 | 131 +++++++++++++ man/man8/devlink.8 | 1 + 3 files changed, 616 insertions(+), 1 deletion(-) create mode 100644 man/man8/devlink-region.8 diff --git a/devlink/devlink.c b/devlink/devlink.c index 42fa716..784bb84 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 0000000..ff10cdb --- /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 7986310..4cf6762 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