// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
*/
#include "devl_internal.h"
struct devlink_region {
struct devlink *devlink;
struct devlink_port *port;
struct list_head list;
union {
const struct devlink_region_ops *ops;
const struct devlink_port_region_ops *port_ops;
};
struct mutex snapshot_lock; /* protects snapshot_list,
* max_snapshots and cur_snapshots
* consistency.
*/
struct list_head snapshot_list;
u32 max_snapshots;
u32 cur_snapshots;
u64 size;
};
struct devlink_snapshot {
struct list_head list;
struct devlink_region *region;
u8 *data;
u32 id;
};
static struct devlink_region *
devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
{
struct devlink_region *region;
list_for_each_entry(region, &devlink->region_list, list)
if (!strcmp(region->ops->name, region_name))
return region;
return NULL;
}
static struct devlink_region *
devlink_port_region_get_by_name(struct devlink_port *port,
const char *region_name)
{
struct devlink_region *region;
list_for_each_entry(region, &port->region_list, list)
if (!strcmp(region->ops->name, region_name))
return region;
return NULL;
}
static struct devlink_snapshot *
devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
{
struct devlink_snapshot *snapshot;
list_for_each_entry(snapshot, ®ion->snapshot_list, list)
if (snapshot->id == id)
return snapshot;
return NULL;
}
static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
struct devlink *devlink,
struct devlink_snapshot *snapshot)
{
struct nlattr *snap_attr;
int err;
snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
if (!snap_attr)
return -EINVAL;
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
if (err)
goto nla_put_failure;
nla_nest_end(msg, snap_attr);
return 0;
nla_put_failure:
nla_nest_cancel(msg, snap_attr);
return err;
}
static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
struct devlink *devlink,
struct devlink_region *region)
{
struct devlink_snapshot *snapshot;
struct nlattr *snapshots_attr;
int err;
snapshots_attr = nla_nest_start_noflag(msg,
DEVLINK_ATTR_REGION_SNAPSHOTS);
if (!snapshots_attr)
return -EINVAL;
list_for_each_entry(snapshot, ®ion->snapshot_list, list) {
err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
if (err)
goto nla_put_failure;
}
nla_nest_end(msg, snapshots_attr);
return 0;
nla_put_failure:
nla_nest_cancel(msg, snapshots_attr);
return err;
}
static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
enum devlink_command cmd, u32 portid,
u32 seq, int flags,
struct devlink_region *region)
{
void *hdr;
int