532 lines
17 KiB
Diff
532 lines
17 KiB
Diff
From 242d6e2b00a25ec4184a63cec76c9f7f7c235594 Mon Sep 17 00:00:00 2001
|
|
From: Vadim Pasternak <vadimp@nvidia.com>
|
|
Date: Wed, 22 Dec 2021 08:57:27 +0000
|
|
Subject: [PATCH] devlink: add support to create line card and expose to user
|
|
|
|
Extend the devlink API so the driver is going to be able to create and
|
|
destroy linecard instances. There can be multiple line cards per devlink
|
|
device. Expose this new type of object over devlink netlink API to the
|
|
userspace, with notifications.
|
|
|
|
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
|
|
---
|
|
include/net/devlink.h | 15 ++
|
|
include/uapi/linux/devlink.h | 22 +++
|
|
net/core/devlink.c | 303 ++++++++++++++++++++++++++++++++++-
|
|
3 files changed, 339 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/include/net/devlink.h b/include/net/devlink.h
|
|
index b01bb9bca..e8f046590 100644
|
|
--- a/include/net/devlink.h
|
|
+++ b/include/net/devlink.h
|
|
@@ -31,6 +31,7 @@ struct devlink_dev_stats {
|
|
struct devlink_ops;
|
|
|
|
struct devlink {
|
|
+ u32 index;
|
|
struct list_head list;
|
|
struct list_head port_list;
|
|
struct list_head sb_list;
|
|
@@ -44,6 +45,8 @@ struct devlink {
|
|
struct list_head trap_list;
|
|
struct list_head trap_group_list;
|
|
struct list_head trap_policer_list;
|
|
+ struct list_head linecard_list;
|
|
+ struct mutex linecards_lock; /* protects linecard_list */
|
|
const struct devlink_ops *ops;
|
|
struct xarray snapshot_ids;
|
|
struct devlink_dev_stats stats;
|
|
@@ -55,6 +58,8 @@ struct devlink {
|
|
u8 reload_failed:1,
|
|
reload_enabled:1,
|
|
registered:1;
|
|
+ refcount_t refcount;
|
|
+ struct completion comp;
|
|
char priv[0] __aligned(NETDEV_ALIGN);
|
|
};
|
|
|
|
@@ -137,6 +142,13 @@ struct devlink_port {
|
|
struct mutex reporters_lock; /* Protects reporter_list */
|
|
};
|
|
|
|
+struct devlink_linecard {
|
|
+ struct list_head list;
|
|
+ struct devlink *devlink;
|
|
+ unsigned int index;
|
|
+ refcount_t refcount;
|
|
+};
|
|
+
|
|
struct devlink_sb_pool_info {
|
|
enum devlink_sb_pool_type pool_type;
|
|
u32 size;
|
|
@@ -1401,6 +1413,9 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro
|
|
u16 pf, bool external);
|
|
void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
|
|
u16 pf, u16 vf, bool external);
|
|
+struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
|
+ unsigned int linecard_index);
|
|
+void devlink_linecard_destroy(struct devlink_linecard *linecard);
|
|
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
|
u32 size, u16 ingress_pools_count,
|
|
u16 egress_pools_count, u16 ingress_tc_count,
|
|
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
|
|
index cf89c318f..ff07ad596 100644
|
|
--- a/include/uapi/linux/devlink.h
|
|
+++ b/include/uapi/linux/devlink.h
|
|
@@ -126,6 +126,16 @@ enum devlink_command {
|
|
|
|
DEVLINK_CMD_HEALTH_REPORTER_TEST,
|
|
|
|
+ DEVLINK_CMD_RATE_GET, /* can dump */
|
|
+ DEVLINK_CMD_RATE_SET,
|
|
+ DEVLINK_CMD_RATE_NEW,
|
|
+ DEVLINK_CMD_RATE_DEL,
|
|
+
|
|
+ DEVLINK_CMD_LINECARD_GET, /* can dump */
|
|
+ DEVLINK_CMD_LINECARD_SET,
|
|
+ DEVLINK_CMD_LINECARD_NEW,
|
|
+ DEVLINK_CMD_LINECARD_DEL,
|
|
+
|
|
/* add new commands above here */
|
|
__DEVLINK_CMD_MAX,
|
|
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
|
|
@@ -529,6 +539,18 @@ enum devlink_attr {
|
|
DEVLINK_ATTR_RELOAD_ACTION_INFO, /* nested */
|
|
DEVLINK_ATTR_RELOAD_ACTION_STATS, /* nested */
|
|
|
|
+ DEVLINK_ATTR_PORT_PCI_SF_NUMBER, /* u32 */
|
|
+
|
|
+ DEVLINK_ATTR_RATE_TYPE, /* u16 */
|
|
+ DEVLINK_ATTR_RATE_TX_SHARE, /* u64 */
|
|
+ DEVLINK_ATTR_RATE_TX_MAX, /* u64 */
|
|
+ DEVLINK_ATTR_RATE_NODE_NAME, /* string */
|
|
+ DEVLINK_ATTR_RATE_PARENT_NODE_NAME, /* string */
|
|
+
|
|
+ DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
|
|
+
|
|
+ DEVLINK_ATTR_LINECARD_INDEX, /* u32 */
|
|
+
|
|
/* add new attributes above here, update the policy in devlink.c */
|
|
|
|
__DEVLINK_ATTR_MAX,
|
|
diff --git a/net/core/devlink.c b/net/core/devlink.c
|
|
index 72047750d..645fe0612 100644
|
|
--- a/net/core/devlink.c
|
|
+++ b/net/core/devlink.c
|
|
@@ -91,6 +91,25 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_
|
|
|
|
static LIST_HEAD(devlink_list);
|
|
|
|
+static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC);
|
|
+#define DEVLINK_REGISTERED XA_MARK_1
|
|
+
|
|
+/* devlink instances are open to the access from the user space after
|
|
+ * devlink_register() call. Such logical barrier allows us to have certain
|
|
+ * expectations related to locking.
|
|
+ *
|
|
+ * Before *_register() - we are in initialization stage and no parallel
|
|
+ * access possible to the devlink instance. All drivers perform that phase
|
|
+ * by implicitly holding device_lock.
|
|
+ *
|
|
+ * After *_register() - users and driver can access devlink instance at
|
|
+ * the same time.
|
|
+ */
|
|
+#define ASSERT_DEVLINK_REGISTERED(d) \
|
|
+ WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED))
|
|
+#define ASSERT_DEVLINK_NOT_REGISTERED(d) \
|
|
+ WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED))
|
|
+
|
|
/* devlink_mutex
|
|
*
|
|
* An overall lock guarding every operation coming from userspace.
|
|
@@ -105,6 +124,19 @@ struct net *devlink_net(const struct devlink *devlink)
|
|
}
|
|
EXPORT_SYMBOL_GPL(devlink_net);
|
|
|
|
+void devlink_put(struct devlink *devlink)
|
|
+{
|
|
+ if (refcount_dec_and_test(&devlink->refcount))
|
|
+ complete(&devlink->comp);
|
|
+}
|
|
+
|
|
+struct devlink *__must_check devlink_try_get(struct devlink *devlink)
|
|
+{
|
|
+ if (refcount_inc_not_zero(&devlink->refcount))
|
|
+ return devlink;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static void __devlink_net_set(struct devlink *devlink, struct net *net)
|
|
{
|
|
write_pnet(&devlink->_net, net);
|
|
@@ -187,6 +219,56 @@ static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
|
|
return devlink_port_get_from_attrs(devlink, info->attrs);
|
|
}
|
|
|
|
+static struct devlink_linecard *
|
|
+devlink_linecard_get_by_index(struct devlink *devlink,
|
|
+ unsigned int linecard_index)
|
|
+{
|
|
+ struct devlink_linecard *devlink_linecard;
|
|
+
|
|
+ list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) {
|
|
+ if (devlink_linecard->index == linecard_index)
|
|
+ return devlink_linecard;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static bool devlink_linecard_index_exists(struct devlink *devlink,
|
|
+ unsigned int linecard_index)
|
|
+{
|
|
+ return devlink_linecard_get_by_index(devlink, linecard_index);
|
|
+}
|
|
+
|
|
+static struct devlink_linecard *
|
|
+devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
|
|
+{
|
|
+ if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) {
|
|
+ u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
|
|
+ struct devlink_linecard *linecard;
|
|
+
|
|
+ mutex_lock(&devlink->linecards_lock);
|
|
+ linecard = devlink_linecard_get_by_index(devlink, linecard_index);
|
|
+ if (linecard)
|
|
+ refcount_inc(&linecard->refcount);
|
|
+ mutex_unlock(&devlink->linecards_lock);
|
|
+ if (!linecard)
|
|
+ return ERR_PTR(-ENODEV);
|
|
+ return linecard;
|
|
+ }
|
|
+ return ERR_PTR(-EINVAL);
|
|
+}
|
|
+
|
|
+static struct devlink_linecard *
|
|
+devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
|
|
+{
|
|
+ return devlink_linecard_get_from_attrs(devlink, info->attrs);
|
|
+}
|
|
+
|
|
+static void devlink_linecard_put(struct devlink_linecard *linecard)
|
|
+{
|
|
+ if (refcount_dec_and_test(&linecard->refcount))
|
|
+ kfree(linecard);
|
|
+}
|
|
+
|
|
struct devlink_sb {
|
|
struct list_head list;
|
|
unsigned int index;
|
|
@@ -405,16 +487,20 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
|
|
|
|
#define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
|
|
#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1)
|
|
+#define DEVLINK_NL_FLAG_NEED_RATE BIT(2)
|
|
+#define DEVLINK_NL_FLAG_NEED_RATE_NODE BIT(3)
|
|
+#define DEVLINK_NL_FLAG_NEED_LINECARD BIT(4)
|
|
|
|
/* The per devlink instance lock is taken by default in the pre-doit
|
|
* operation, yet several commands do not require this. The global
|
|
* devlink lock is taken and protects from disruption by user-calls.
|
|
*/
|
|
-#define DEVLINK_NL_FLAG_NO_LOCK BIT(2)
|
|
+#define DEVLINK_NL_FLAG_NO_LOCK BIT(5)
|
|
|
|
static int devlink_nl_pre_doit(const struct genl_ops *ops,
|
|
struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
+ struct devlink_linecard *linecard;
|
|
struct devlink_port *devlink_port;
|
|
struct devlink *devlink;
|
|
int err;
|
|
@@ -439,6 +525,13 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
|
|
devlink_port = devlink_port_get_from_info(devlink, info);
|
|
if (!IS_ERR(devlink_port))
|
|
info->user_ptr[1] = devlink_port;
|
|
+ } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) {
|
|
+ linecard = devlink_linecard_get_from_info(devlink, info);
|
|
+ if (IS_ERR(linecard)) {
|
|
+ err = PTR_ERR(linecard);
|
|
+ goto unlock;
|
|
+ }
|
|
+ info->user_ptr[1] = linecard;
|
|
}
|
|
return 0;
|
|
|
|
@@ -452,9 +545,14 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
|
|
static void devlink_nl_post_doit(const struct genl_ops *ops,
|
|
struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
+ struct devlink_linecard *linecard;
|
|
struct devlink *devlink;
|
|
|
|
devlink = info->user_ptr[0];
|
|
+ if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) {
|
|
+ linecard = info->user_ptr[1];
|
|
+ devlink_linecard_put(linecard);
|
|
+ }
|
|
if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
|
|
mutex_unlock(&devlink->lock);
|
|
mutex_unlock(&devlink_mutex);
|
|
@@ -1135,6 +1233,132 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
|
|
return devlink_port_unsplit(devlink, port_index, info->extack);
|
|
}
|
|
|
|
+static int devlink_nl_linecard_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)
|
|
+{
|
|
+ void *hdr;
|
|
+
|
|
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
+ if (!hdr)
|
|
+ return -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;
|
|
+
|
|
+ genlmsg_end(msg, hdr);
|
|
+ return 0;
|
|
+
|
|
+nla_put_failure:
|
|
+ genlmsg_cancel(msg, hdr);
|
|
+ return -EMSGSIZE;
|
|
+}
|
|
+
|
|
+static void devlink_linecard_notify(struct devlink_linecard *linecard,
|
|
+ enum devlink_command cmd)
|
|
+{
|
|
+ struct devlink *devlink = linecard->devlink;
|
|
+ struct sk_buff *msg;
|
|
+ int err;
|
|
+
|
|
+ WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
|
|
+ cmd != DEVLINK_CMD_LINECARD_DEL);
|
|
+
|
|
+ if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
+ return;
|
|
+
|
|
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
+ if (!msg)
|
|
+ return;
|
|
+
|
|
+ err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
|
|
+ NULL);
|
|
+ if (err) {
|
|
+ nlmsg_free(msg);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
|
|
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
|
+}
|
|
+
|
|
+static int devlink_nl_cmd_linecard_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;
|
|
+
|
|
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
+ if (!msg)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
|
+ DEVLINK_CMD_LINECARD_NEW,
|
|
+ info->snd_portid, info->snd_seq, 0,
|
|
+ info->extack);
|
|
+ if (err) {
|
|
+ nlmsg_free(msg);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ return genlmsg_reply(msg, info);
|
|
+}
|
|
+
|
|
+static int devlink_nl_cmd_linecard_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;
|
|
+
|
|
+ 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) {
|
|
+ idx++;
|
|
+ continue;
|
|
+ }
|
|
+ err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
|
+ DEVLINK_CMD_LINECARD_NEW,
|
|
+ NETLINK_CB(cb->skb).portid,
|
|
+ cb->nlh->nlmsg_seq,
|
|
+ NLM_F_MULTI,
|
|
+ cb->extack);
|
|
+ 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);
|
|
+
|
|
+ cb->args[0] = idx;
|
|
+ return msg->len;
|
|
+}
|
|
+
|
|
static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
struct devlink_sb *devlink_sb,
|
|
enum devlink_command cmd, u32 portid,
|
|
@@ -7594,6 +7818,19 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
|
|
[DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
|
|
DEVLINK_RELOAD_ACTION_MAX),
|
|
[DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
|
|
+//<<<<<<< HEAD
|
|
+//=======
|
|
+ [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 },
|
|
+ [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 },
|
|
+ [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 },
|
|
+ [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 },
|
|
+ [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 },
|
|
+ [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 },
|
|
+ [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 },
|
|
+ [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING },
|
|
+ [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
|
|
+ [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
|
|
+//>>>>>>> 1180815a3831... devlink: add support to create line card and expose to user
|
|
};
|
|
|
|
static const struct genl_small_ops devlink_nl_ops[] = {
|
|
@@ -7633,6 +7870,14 @@ static const struct genl_small_ops devlink_nl_ops[] = {
|
|
.flags = GENL_ADMIN_PERM,
|
|
.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
|
|
},
|
|
+ {
|
|
+ .cmd = DEVLINK_CMD_LINECARD_GET,
|
|
+ .doit = devlink_nl_cmd_linecard_get_doit,
|
|
+ .dumpit = devlink_nl_cmd_linecard_get_dumpit,
|
|
+ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD |
|
|
+ DEVLINK_NL_FLAG_NO_LOCK,
|
|
+ /* can be retrieved by unprivileged users */
|
|
+ },
|
|
{
|
|
.cmd = DEVLINK_CMD_SB_GET,
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
|
@@ -7980,6 +8225,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
|
|
xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
|
|
__devlink_net_set(devlink, &init_net);
|
|
INIT_LIST_HEAD(&devlink->port_list);
|
|
+ INIT_LIST_HEAD(&devlink->linecard_list);
|
|
INIT_LIST_HEAD(&devlink->sb_list);
|
|
INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
|
|
INIT_LIST_HEAD(&devlink->resource_list);
|
|
@@ -7991,6 +8237,8 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
|
|
INIT_LIST_HEAD(&devlink->trap_policer_list);
|
|
mutex_init(&devlink->lock);
|
|
mutex_init(&devlink->reporters_lock);
|
|
+ mutex_init(&devlink->linecards_lock);
|
|
+
|
|
return devlink;
|
|
}
|
|
EXPORT_SYMBOL_GPL(devlink_alloc);
|
|
@@ -8071,6 +8319,7 @@ EXPORT_SYMBOL_GPL(devlink_reload_disable);
|
|
*/
|
|
void devlink_free(struct devlink *devlink)
|
|
{
|
|
+ mutex_destroy(&devlink->linecards_lock);
|
|
mutex_destroy(&devlink->reporters_lock);
|
|
mutex_destroy(&devlink->lock);
|
|
WARN_ON(!list_empty(&devlink->trap_policer_list));
|
|
@@ -8082,6 +8331,7 @@ void devlink_free(struct devlink *devlink)
|
|
WARN_ON(!list_empty(&devlink->resource_list));
|
|
WARN_ON(!list_empty(&devlink->dpipe_table_list));
|
|
WARN_ON(!list_empty(&devlink->sb_list));
|
|
+ WARN_ON(!list_empty(&devlink->linecard_list));
|
|
WARN_ON(!list_empty(&devlink->port_list));
|
|
|
|
xa_destroy(&devlink->snapshot_ids);
|
|
@@ -8427,6 +8677,57 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
|
|
return 0;
|
|
}
|
|
|
|
+/**
|
|
+ * devlink_linecard_create - Create devlink linecard
|
|
+ *
|
|
+ * @devlink: devlink
|
|
+ * @linecard_index: driver-specific numerical identifier of the linecard
|
|
+ *
|
|
+ * Create devlink linecard instance with provided linecard index.
|
|
+ * Caller can use any indexing, even hw-related one.
|
|
+ */
|
|
+struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
|
+ unsigned int linecard_index)
|
|
+{
|
|
+ struct devlink_linecard *linecard;
|
|
+
|
|
+ mutex_lock(&devlink->linecards_lock);
|
|
+ if (devlink_linecard_index_exists(devlink, linecard_index)) {
|
|
+ mutex_unlock(&devlink->linecards_lock);
|
|
+ return ERR_PTR(-EEXIST);
|
|
+ }
|
|
+
|
|
+ linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
|
|
+ if (!linecard)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ linecard->devlink = devlink;
|
|
+ linecard->index = linecard_index;
|
|
+ list_add_tail(&linecard->list, &devlink->linecard_list);
|
|
+ refcount_set(&linecard->refcount, 1);
|
|
+ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
+ mutex_unlock(&devlink->linecards_lock);
|
|
+ return linecard;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(devlink_linecard_create);
|
|
+
|
|
+/**
|
|
+ * devlink_linecard_destroy - Destroy devlink linecard
|
|
+ *
|
|
+ * @linecard: devlink linecard
|
|
+ */
|
|
+void devlink_linecard_destroy(struct devlink_linecard *linecard)
|
|
+{
|
|
+ struct devlink *devlink = linecard->devlink;
|
|
+
|
|
+ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
|
|
+ mutex_lock(&devlink->linecards_lock);
|
|
+ list_del(&linecard->list);
|
|
+ mutex_unlock(&devlink->linecards_lock);
|
|
+ devlink_linecard_put(linecard);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(devlink_linecard_destroy);
|
|
+
|
|
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
|
u32 size, u16 ingress_pools_count,
|
|
u16 egress_pools_count, u16 ingress_tc_count,
|
|
--
|
|
2.30.2
|
|
|