Commit 276910ae authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

devlink: introduce line card info get message

Allow the driver to provide per line card info get op to fill-up info,
similar to the "devlink dev info".

Example:

$ devlink lc info pci/0000:01:00.0 lc 8
pci/0000:01:00.0:
  lc 8
    versions:
        fixed:
          hw.revision 0
        running:
          ini.version 4
Signed-off-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8d92e4fb
...@@ -14,6 +14,7 @@ system. Following operations are provided: ...@@ -14,6 +14,7 @@ system. Following operations are provided:
* Get a list of supported line card types. * Get a list of supported line card types.
* Provision of a slot with specific line card type. * Provision of a slot with specific line card type.
* Get and monitor of line card state and its change. * Get and monitor of line card state and its change.
* Get information about line card versions.
Line card according to the type may contain one or more gearboxes Line card according to the type may contain one or more gearboxes
to mux the lanes with certain speed to multiple ports with lanes to mux the lanes with certain speed to multiple ports with lanes
...@@ -120,3 +121,6 @@ Example usage ...@@ -120,3 +121,6 @@ Example usage
# Set slot 8 to be unprovisioned: # Set slot 8 to be unprovisioned:
$ devlink lc set pci/0000:01:00.0 lc 8 notype $ devlink lc set pci/0000:01:00.0 lc 8 notype
# Set info for slot 8:
$ devlink lc info pci/0000:01:00.0 lc 8
...@@ -150,6 +150,8 @@ struct devlink_port_new_attrs { ...@@ -150,6 +150,8 @@ struct devlink_port_new_attrs {
sfnum_valid:1; sfnum_valid:1;
}; };
struct devlink_info_req;
/** /**
* struct devlink_linecard_ops - Linecard operations * struct devlink_linecard_ops - Linecard operations
* @provision: callback to provision the linecard slot with certain * @provision: callback to provision the linecard slot with certain
...@@ -168,6 +170,7 @@ struct devlink_port_new_attrs { ...@@ -168,6 +170,7 @@ struct devlink_port_new_attrs {
* provisioned. * provisioned.
* @types_count: callback to get number of supported types * @types_count: callback to get number of supported types
* @types_get: callback to get next type in list * @types_get: callback to get next type in list
* @info_get: callback to get linecard info
*/ */
struct devlink_linecard_ops { struct devlink_linecard_ops {
int (*provision)(struct devlink_linecard *linecard, void *priv, int (*provision)(struct devlink_linecard *linecard, void *priv,
...@@ -182,6 +185,9 @@ struct devlink_linecard_ops { ...@@ -182,6 +185,9 @@ struct devlink_linecard_ops {
void (*types_get)(struct devlink_linecard *linecard, void (*types_get)(struct devlink_linecard *linecard,
void *priv, unsigned int index, const char **type, void *priv, unsigned int index, const char **type,
const void **type_priv); const void **type_priv);
int (*info_get)(struct devlink_linecard *linecard, void *priv,
struct devlink_info_req *req,
struct netlink_ext_ack *extack);
}; };
struct devlink_sb_pool_info { struct devlink_sb_pool_info {
...@@ -628,7 +634,6 @@ struct devlink_flash_update_params { ...@@ -628,7 +634,6 @@ struct devlink_flash_update_params {
#define DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK BIT(1) #define DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK BIT(1)
struct devlink_region; struct devlink_region;
struct devlink_info_req;
/** /**
* struct devlink_region_ops - Region operations * struct devlink_region_ops - Region operations
......
...@@ -136,6 +136,8 @@ enum devlink_command { ...@@ -136,6 +136,8 @@ enum devlink_command {
DEVLINK_CMD_LINECARD_NEW, DEVLINK_CMD_LINECARD_NEW,
DEVLINK_CMD_LINECARD_DEL, DEVLINK_CMD_LINECARD_DEL,
DEVLINK_CMD_LINECARD_INFO_GET, /* can dump */
/* add new commands above here */ /* add new commands above here */
__DEVLINK_CMD_MAX, __DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
......
...@@ -2424,6 +2424,125 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, ...@@ -2424,6 +2424,125 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
return 0; return 0;
} }
struct devlink_info_req {
struct sk_buff *msg;
};
static int
devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink,
struct devlink_linecard *linecard,
enum devlink_command cmd, u32 portid,
u32 seq, int flags, struct netlink_ext_ack *extack)
{
struct devlink_info_req req;
void *hdr;
int err;
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
if (!hdr)
return -EMSGSIZE;
err = -EMSGSIZE;
if (devlink_nl_put_handle(msg, devlink))
goto nla_put_failure;
if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
goto nla_put_failure;
req.msg = msg;
err = linecard->ops->info_get(linecard, linecard->priv, &req, extack);
if (err)
goto nla_put_failure;
genlmsg_end(msg, hdr);
return 0;
nla_put_failure:
genlmsg_cancel(msg, hdr);
return err;
}
static int devlink_nl_cmd_linecard_info_get_doit(struct sk_buff *skb,
struct genl_info *info)
{
struct devlink_linecard *linecard = info->user_ptr[1];
struct devlink *devlink = linecard->devlink;
struct sk_buff *msg;
int err;
if (!linecard->ops->info_get)
return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
mutex_lock(&linecard->state_lock);
err = devlink_nl_linecard_info_fill(msg, devlink, linecard,
DEVLINK_CMD_LINECARD_INFO_GET,
info->snd_portid, info->snd_seq, 0,
info->extack);
mutex_unlock(&linecard->state_lock);
if (err) {
nlmsg_free(msg);
return err;
}
return genlmsg_reply(msg, info);
}
static int devlink_nl_cmd_linecard_info_get_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
{
struct devlink_linecard *linecard;
struct devlink *devlink;
int start = cb->args[0];
unsigned long index;
int idx = 0;
int err = 0;
mutex_lock(&devlink_mutex);
xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
if (!devlink_try_get(devlink))
continue;
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
goto retry;
mutex_lock(&devlink->linecards_lock);
list_for_each_entry(linecard, &devlink->linecard_list, list) {
if (idx < start || !linecard->ops->info_get) {
idx++;
continue;
}
mutex_lock(&linecard->state_lock);
err = devlink_nl_linecard_info_fill(msg, devlink, linecard,
DEVLINK_CMD_LINECARD_INFO_GET,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI,
cb->extack);
mutex_unlock(&linecard->state_lock);
if (err) {
mutex_unlock(&devlink->linecards_lock);
devlink_put(devlink);
goto out;
}
idx++;
}
mutex_unlock(&devlink->linecards_lock);
retry:
devlink_put(devlink);
}
out:
mutex_unlock(&devlink_mutex);
if (err != -EMSGSIZE)
return err;
cb->args[0] = idx;
return msg->len;
}
static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
struct devlink_sb *devlink_sb, struct devlink_sb *devlink_sb,
enum devlink_command cmd, u32 portid, enum devlink_command cmd, u32 portid,
...@@ -6416,10 +6535,6 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb, ...@@ -6416,10 +6535,6 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
return err; return err;
} }
struct devlink_info_req {
struct sk_buff *msg;
};
int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name) int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
{ {
return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name); return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
...@@ -9139,6 +9254,13 @@ static const struct genl_small_ops devlink_nl_ops[] = { ...@@ -9139,6 +9254,13 @@ static const struct genl_small_ops devlink_nl_ops[] = {
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD, .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
}, },
{
.cmd = DEVLINK_CMD_LINECARD_INFO_GET,
.doit = devlink_nl_cmd_linecard_info_get_doit,
.dumpit = devlink_nl_cmd_linecard_info_get_dumpit,
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
/* can be retrieved by unprivileged users */
},
{ {
.cmd = DEVLINK_CMD_SB_GET, .cmd = DEVLINK_CMD_SB_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment