Commit a254c264 authored by Moshe Shemesh's avatar Moshe Shemesh Committed by Jakub Kicinski

devlink: Add reload stats

Add reload stats to hold the history per reload action type and limit.

For example, the number of times fw_activate has been performed on this
device since the driver module was added or if the firmware activation
was performed with or without reset.

Add devlink notification on stats update.

Expose devlink reload stats to the user through devlink dev get command.

Examples:
$ devlink dev show
pci/0000:82:00.0:
  stats:
      reload:
        driver_reinit 2 fw_activate 1 fw_activate_no_reset 0
pci/0000:82:00.1:
  stats:
      reload:
        driver_reinit 1 fw_activate 0 fw_activate_no_reset 0

$ devlink dev show -jp
{
    "dev": {
        "pci/0000:82:00.0": {
            "stats": {
                "reload": {
                    "driver_reinit": 2,
                    "fw_activate": 1,
                    "fw_activate_no_reset": 0
                }
            }
        },
        "pci/0000:82:00.1": {
            "stats": {
                "reload": {
                    "driver_reinit": 1,
                    "fw_activate": 0,
                    "fw_activate_no_reset": 0
                }
            }
        }
    }
}
Signed-off-by: default avatarMoshe Shemesh <moshe@mellanox.com>
Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent dc64cc7c
...@@ -20,6 +20,13 @@ ...@@ -20,6 +20,13 @@
#include <uapi/linux/devlink.h> #include <uapi/linux/devlink.h>
#include <linux/xarray.h> #include <linux/xarray.h>
#define DEVLINK_RELOAD_STATS_ARRAY_SIZE \
(__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX)
struct devlink_dev_stats {
u32 reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];
};
struct devlink_ops; struct devlink_ops;
struct devlink { struct devlink {
...@@ -38,6 +45,7 @@ struct devlink { ...@@ -38,6 +45,7 @@ struct devlink {
struct list_head trap_policer_list; struct list_head trap_policer_list;
const struct devlink_ops *ops; const struct devlink_ops *ops;
struct xarray snapshot_ids; struct xarray snapshot_ids;
struct devlink_dev_stats stats;
struct device *dev; struct device *dev;
possible_net_t _net; possible_net_t _net;
struct mutex lock; /* Serializes access to devlink instance specific objects such as struct mutex lock; /* Serializes access to devlink instance specific objects such as
......
...@@ -520,6 +520,12 @@ enum devlink_attr { ...@@ -520,6 +520,12 @@ enum devlink_attr {
DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, /* bitfield32 */ DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, /* bitfield32 */
DEVLINK_ATTR_RELOAD_LIMITS, /* bitfield32 */ DEVLINK_ATTR_RELOAD_LIMITS, /* bitfield32 */
DEVLINK_ATTR_DEV_STATS, /* nested */
DEVLINK_ATTR_RELOAD_STATS, /* nested */
DEVLINK_ATTR_RELOAD_STATS_ENTRY, /* nested */
DEVLINK_ATTR_RELOAD_STATS_LIMIT, /* u8 */
DEVLINK_ATTR_RELOAD_STATS_VALUE, /* u32 */
/* add new attributes above here, update the policy in devlink.c */ /* add new attributes above here, update the policy in devlink.c */
__DEVLINK_ATTR_MAX, __DEVLINK_ATTR_MAX,
......
...@@ -517,10 +517,66 @@ devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_l ...@@ -517,10 +517,66 @@ devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_l
return test_bit(limit, &devlink->ops->reload_limits); return test_bit(limit, &devlink->ops->reload_limits);
} }
static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_action action,
enum devlink_reload_limit limit, u32 value)
{
struct nlattr *reload_stats_entry;
reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY);
if (!reload_stats_entry)
return -EMSGSIZE;
if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, action) ||
nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) ||
nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value))
goto nla_put_failure;
nla_nest_end(msg, reload_stats_entry);
return 0;
nla_put_failure:
nla_nest_cancel(msg, reload_stats_entry);
return -EMSGSIZE;
}
static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink)
{
struct nlattr *reload_stats_attr;
int i, j, stat_idx;
u32 value;
reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS);
if (!reload_stats_attr)
return -EMSGSIZE;
for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) {
if (j != DEVLINK_RELOAD_LIMIT_UNSPEC &&
!devlink_reload_limit_is_supported(devlink, j))
continue;
for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) {
if (!devlink_reload_action_is_supported(devlink, i) ||
devlink_reload_combination_is_invalid(i, j))
continue;
stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i;
value = devlink->stats.reload_stats[stat_idx];
if (devlink_reload_stat_put(msg, i, j, value))
goto nla_put_failure;
}
}
nla_nest_end(msg, reload_stats_attr);
return 0;
nla_put_failure:
nla_nest_cancel(msg, reload_stats_attr);
return -EMSGSIZE;
}
static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
enum devlink_command cmd, u32 portid, enum devlink_command cmd, u32 portid,
u32 seq, int flags) u32 seq, int flags)
{ {
struct nlattr *dev_stats;
void *hdr; void *hdr;
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
...@@ -532,9 +588,19 @@ static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, ...@@ -532,9 +588,19 @@ static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed)) if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
goto nla_put_failure; goto nla_put_failure;
dev_stats = nla_nest_start(msg, DEVLINK_ATTR_DEV_STATS);
if (!dev_stats)
goto nla_put_failure;
if (devlink_reload_stats_put(msg, devlink))
goto dev_stats_nest_cancel;
nla_nest_end(msg, dev_stats);
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
return 0; return 0;
dev_stats_nest_cancel:
nla_nest_cancel(msg, dev_stats);
nla_put_failure: nla_put_failure:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
return -EMSGSIZE; return -EMSGSIZE;
...@@ -3021,6 +3087,29 @@ bool devlink_is_reload_failed(const struct devlink *devlink) ...@@ -3021,6 +3087,29 @@ bool devlink_is_reload_failed(const struct devlink *devlink)
} }
EXPORT_SYMBOL_GPL(devlink_is_reload_failed); EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
static void
__devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats,
enum devlink_reload_limit limit, u32 actions_performed)
{
unsigned long actions = actions_performed;
int stat_idx;
int action;
for_each_set_bit(action, &actions, __DEVLINK_RELOAD_ACTION_MAX) {
stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action;
reload_stats[stat_idx]++;
}
devlink_notify(devlink, DEVLINK_CMD_NEW);
}
static void
devlink_reload_stats_update(struct devlink *devlink, enum devlink_reload_limit limit,
u32 actions_performed)
{
__devlink_reload_stats_update(devlink, devlink->stats.reload_stats, limit,
actions_performed);
}
static int devlink_reload(struct devlink *devlink, struct net *dest_net, static int devlink_reload(struct devlink *devlink, struct net *dest_net,
enum devlink_reload_action action, enum devlink_reload_limit limit, enum devlink_reload_action action, enum devlink_reload_limit limit,
u32 *actions_performed, struct netlink_ext_ack *extack) u32 *actions_performed, struct netlink_ext_ack *extack)
...@@ -3043,6 +3132,7 @@ static int devlink_reload(struct devlink *devlink, struct net *dest_net, ...@@ -3043,6 +3132,7 @@ static int devlink_reload(struct devlink *devlink, struct net *dest_net,
return err; return err;
WARN_ON(!(*actions_performed & BIT(action))); WARN_ON(!(*actions_performed & BIT(action)));
devlink_reload_stats_update(devlink, limit, *actions_performed);
return 0; return 0;
} }
......
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