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 <getopt.h>
 #include <limits.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <linux/genetlink.h>
 #include <linux/devlink.h>
 #include <libmnl/libmnl.h>
@@ -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 "<unknown cmd>";
 	}
 }
@@ -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 "<unknown obj>";
 	}
 }
@@ -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 <valex@mellanox.com>
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
