@@ -306,6 +306,9 @@ static void ifname_map_free(struct ifname_map *ifname_map)
#define DL_OPT_FLASH_OVERWRITE BIT(39)
#define DL_OPT_RELOAD_ACTION BIT(40)
#define DL_OPT_RELOAD_LIMIT BIT(41)
+#define DL_OPT_PORT_FLAVOUR BIT(42)
+#define DL_OPT_PORT_PFNUMBER BIT(43)
+#define DL_OPT_PORT_SFNUMBER BIT(44)
struct dl_opts {
uint64_t present; /* flags of present items */
@@ -356,6 +359,9 @@ struct dl_opts {
uint32_t overwrite_mask;
enum devlink_reload_action reload_action;
enum devlink_reload_limit reload_limit;
+ uint32_t port_sfnumber;
+ uint16_t port_flavour;
+ uint16_t port_pfnumber;
};
struct dl {
@@ -1383,6 +1389,37 @@ static int reload_limit_get(struct dl *dl, const char *limitstr,
return 0;
}
+static int port_flavour_parse(const char *flavour, uint16_t *value)
+{
+ if (!flavour)
+ return -EINVAL;
+
+ if (strcmp(flavour, "physical") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+ return 0;
+ } else if (strcmp(flavour, "cpu") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_CPU;
+ return 0;
+ } else if (strcmp(flavour, "dsa") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_DSA;
+ return 0;
+ } else if (strcmp(flavour, "pcipf") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_PCI_PF;
+ return 0;
+ } else if (strcmp(flavour, "pcivf") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_PCI_VF;
+ return 0;
+ } else if (strcmp(flavour, "pcisf") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_PCI_SF;
+ return 0;
+ } else if (strcmp(flavour, "virtual") == 0) {
+ *value = DEVLINK_PORT_FLAVOUR_VIRTUAL;
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
struct dl_args_metadata {
uint64_t o_flag;
char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
@@ -1414,6 +1451,8 @@ static const struct dl_args_metadata dl_args_required[] = {
{DL_OPT_TRAP_NAME, "Trap's name is expected."},
{DL_OPT_TRAP_GROUP_NAME, "Trap group's name is expected."},
{DL_OPT_PORT_FUNCTION_HW_ADDR, "Port function's hardware address is expected."},
+ {DL_OPT_PORT_FLAVOUR, "Port flavour is expected."},
+ {DL_OPT_PORT_PFNUMBER, "Port PCI PF number is expected."},
};
static int dl_args_finding_required_validate(uint64_t o_required,
@@ -1832,7 +1871,29 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
if (err)
return err;
o_found |= DL_OPT_PORT_FUNCTION_HW_ADDR;
+ } else if (dl_argv_match(dl, "flavour") && (o_all & DL_OPT_PORT_FLAVOUR)) {
+ const char *flavourstr;
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &flavourstr);
+ if (err)
+ return err;
+ err = port_flavour_parse(flavourstr, &opts->port_flavour);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PORT_FLAVOUR;
+ } else if (dl_argv_match(dl, "pfnum") && (o_all & DL_OPT_PORT_PFNUMBER)) {
+ dl_arg_inc(dl);
+ err = dl_argv_uint16_t(dl, &opts->port_pfnumber);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PORT_PFNUMBER;
+ } else if (dl_argv_match(dl, "sfnum") && (o_all & DL_OPT_PORT_SFNUMBER)) {
+ dl_arg_inc(dl);
+ err = dl_argv_uint32_t(dl, &opts->port_sfnumber);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PORT_SFNUMBER;
} else {
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
return -EINVAL;
@@ -2015,6 +2076,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
opts->trap_policer_burst);
if (opts->present & DL_OPT_PORT_FUNCTION_HW_ADDR)
dl_function_attr_put(nlh, opts);
+ if (opts->present & DL_OPT_PORT_FLAVOUR)
+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_FLAVOUR, opts->port_flavour);
+ if (opts->present & DL_OPT_PORT_PFNUMBER)
+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, opts->port_pfnumber);
+ if (opts->present & DL_OPT_PORT_SFNUMBER)
+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, opts->port_sfnumber);
}
static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
@@ -3702,6 +3769,8 @@ static void cmd_port_help(void)
pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
pr_err(" devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
+ pr_err(" devlink port add DEV/PORT_INDEX flavour FLAVOUR [ controller CNUM ] pfnum PFNUM [ sfnum SFNUM ]\n");
+ pr_err(" devlink port del DEV/PORT_INDEX\n");
}
static const char *port_type_name(uint32_t type)
@@ -3977,6 +4046,58 @@ static int cmd_port_function(struct dl *dl)
static int cmd_health(struct dl *dl);
static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
+static void cmd_port_add_help(void)
+{
+ pr_err(" devlink port add { DEV | DEV/PORT_INDEX } flavour FLAVOUR pfnum PFNUM [ sfnum SFNUM ]\n");
+}
+
+static int cmd_port_add(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ int err;
+
+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+ cmd_port_add_help();
+ return 0;
+ }
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_NEW,
+ NLM_F_REQUEST | NLM_F_ACK);
+
+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP |
+ DL_OPT_PORT_FLAVOUR | DL_OPT_PORT_PFNUMBER,
+ DL_OPT_PORT_SFNUMBER);
+ if (err)
+ return err;
+
+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
+}
+
+static void cmd_port_del_help(void)
+{
+ pr_err(" devlink port del DEV/PORT_INDEX\n");
+}
+
+static int cmd_port_del(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ int err;
+
+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+ cmd_port_del_help();
+ return 0;
+ }
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_DEL,
+ NLM_F_REQUEST | NLM_F_ACK);
+
+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
+ if (err)
+ return err;
+
+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
static int cmd_port(struct dl *dl)
{
if (dl_argv_match(dl, "help")) {
@@ -4007,7 +4128,14 @@ static int cmd_port(struct dl *dl)
} else {
return cmd_health(dl);
}
+ } else if (dl_argv_match(dl, "add")) {
+ dl_arg_inc(dl);
+ return cmd_port_add(dl);
+ } else if (dl_argv_match(dl, "del")) {
+ dl_arg_inc(dl);
+ return cmd_port_del(dl);
}
+
pr_err("Command \"%s\" not found\n", dl_argv(dl));
return -ENOENT;
}
@@ -43,6 +43,23 @@ devlink-port \- devlink port configuration
.B devlink port health
.RI "{ " show " | " recover " | " diagnose " | " dump " | " set " }"
+.ti -8
+.BI "devlink port add"
+.RB "["
+.IR "DEV | DEV/PORT_INDEX"
+.RB "] "
+.RB "[ " flavour
+.IR FLAVOUR " ]"
+.RB "[ " pcipf
+.IR PFNUMBER " ]"
+.RB "{ " pcisf
+.IR SFNUMBER " }"
+.br
+
+.ti -8
+.B devlink port del
+.IR DEV/PORT_INDEX
+
.ti -8
.B devlink port help
@@ -99,6 +116,42 @@ If this argument is omitted all ports are listed.
Is an alias for
.BR devlink-health (8).
+.ti -8
+.SS devlink port add - add a devlink port
+.PP
+.B "DEV"
+- specifies the devlink device to operate on. or
+
+.PP
+.B "DEV/PORT_INDEX"
+- specifies the devlink port index to use for the requested new port.
+This is optional. When ommited, driver allocates unique port index.
+
+.TP
+.BR flavour " { " pcipf " | " pcisf " } "
+set port flavour
+
+.I pcipf
+- PCI PF port
+
+.I pcisf
+- PCI SF port
+
+.TP
+.BR pfnum " { " pfnumber " } "
+Specifies PCI pfnumber to use on which a SF device to create
+
+.TP
+.BR sfnum " { " sfnumber " } "
+Specifies sfnumber to assign to the device of the SF.
+This field is optional for those devices which supports auto assignment of the SF number.
+
+.ti -8
+.SS devlink port del - delete a devlink port
+.PP
+.B "DEV/PORT_INDEX"
+- specifies the devlink port to delete.
+
.SH "EXAMPLES"
.PP
devlink port show
@@ -135,6 +188,16 @@ devlink port health show pci/0000:01:00.0/1 reporter tx
.RS 4
Shows status and configuration of tx reporter registered on pci/0000:01:00.0/1 devlink port.
.RE
+.PP
+devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
+.RS 4
+Add a devlink port of flavour PCI SF on PCI PF having number 0 with SF number 88.
+.RE
+.PP
+devlink port del pci/0000:06:00.0/1
+.RS 4
+Delete previously created devlink port.
+.RE
.SH SEE ALSO
.BR devlink (8),