mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
devlink: implement line card provisioning
In order to be able to configure all needed stuff on a port/netdevice of a line card without the line card being present, introduce line card provisioning. Basically by setting a type, provisioning process will start and driver is supposed to create a placeholder for instances (ports/netdevices) for a line card type. Allow the user to query the supported line card types over line card get command. Then implement two netlink command SET to allow user to set/unset the card type. On the driver API side, add provision/unprovision ops and supported types array to be advertised. Upon provision op call, the driver should take care of creating the instances for the particular line card type. Introduce provision_set/clear() functions to be called by the driver once the provisioning/unprovisioning is done on its side. These helpers are not to be called directly due to the async nature of provisioning. Example: $ devlink port # No ports are listed $ devlink lc pci/0000:01:00.0: lc 1 state unprovisioned supported_types: 16x100G lc 2 state unprovisioned supported_types: 16x100G lc 3 state unprovisioned supported_types: 16x100G lc 4 state unprovisioned supported_types: 16x100G lc 5 state unprovisioned supported_types: 16x100G lc 6 state unprovisioned supported_types: 16x100G lc 7 state unprovisioned supported_types: 16x100G lc 8 state unprovisioned supported_types: 16x100G $ devlink lc set pci/0000:01:00.0 lc 8 type 16x100G $ devlink lc show pci/0000:01:00.0 lc 8 pci/0000:01:00.0: lc 8 state active type 16x100G supported_types: 16x100G $ devlink port pci/0000:01:00.0/0: type notset flavour cpu port 0 splittable false pci/0000:01:00.0/53: type eth netdev enp1s0nl8p1 flavour physical lc 8 port 1 splittable true lanes 4 pci/0000:01:00.0/54: type eth netdev enp1s0nl8p2 flavour physical lc 8 port 2 splittable true lanes 4 pci/0000:01:00.0/55: type eth netdev enp1s0nl8p3 flavour physical lc 8 port 3 splittable true lanes 4 pci/0000:01:00.0/56: type eth netdev enp1s0nl8p4 flavour physical lc 8 port 4 splittable true lanes 4 pci/0000:01:00.0/57: type eth netdev enp1s0nl8p5 flavour physical lc 8 port 5 splittable true lanes 4 pci/0000:01:00.0/58: type eth netdev enp1s0nl8p6 flavour physical lc 8 port 6 splittable true lanes 4 pci/0000:01:00.0/59: type eth netdev enp1s0nl8p7 flavour physical lc 8 port 7 splittable true lanes 4 pci/0000:01:00.0/60: type eth netdev enp1s0nl8p8 flavour physical lc 8 port 8 splittable true lanes 4 pci/0000:01:00.0/61: type eth netdev enp1s0nl8p9 flavour physical lc 8 port 9 splittable true lanes 4 pci/0000:01:00.0/62: type eth netdev enp1s0nl8p10 flavour physical lc 8 port 10 splittable true lanes 4 pci/0000:01:00.0/63: type eth netdev enp1s0nl8p11 flavour physical lc 8 port 11 splittable true lanes 4 pci/0000:01:00.0/64: type eth netdev enp1s0nl8p12 flavour physical lc 8 port 12 splittable true lanes 4 pci/0000:01:00.0/125: type eth netdev enp1s0nl8p13 flavour physical lc 8 port 13 splittable true lanes 4 pci/0000:01:00.0/126: type eth netdev enp1s0nl8p14 flavour physical lc 8 port 14 splittable true lanes 4 pci/0000:01:00.0/127: type eth netdev enp1s0nl8p15 flavour physical lc 8 port 15 splittable true lanes 4 pci/0000:01:00.0/128: type eth netdev enp1s0nl8p16 flavour physical lc 8 port 16 splittable true lanes 4 $ devlink lc set pci/0000:01:00.0 lc 8 notype Signed-off-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c246f9b5fd
commit
fcdc8ce23a
121
Documentation/networking/devlink/devlink-linecard.rst
Normal file
121
Documentation/networking/devlink/devlink-linecard.rst
Normal file
@ -0,0 +1,121 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=================
|
||||
Devlink Line card
|
||||
=================
|
||||
|
||||
Background
|
||||
==========
|
||||
|
||||
The ``devlink-linecard`` mechanism is targeted for manipulation of
|
||||
line cards that serve as a detachable PHY modules for modular switch
|
||||
system. Following operations are provided:
|
||||
|
||||
* Get a list of supported line card types.
|
||||
* Provision of a slot with specific line card type.
|
||||
* Get and monitor of line card state and its change.
|
||||
|
||||
Line card according to the type may contain one or more gearboxes
|
||||
to mux the lanes with certain speed to multiple ports with lanes
|
||||
of different speed. Line card ensures N:M mapping between
|
||||
the switch ASIC modules and physical front panel ports.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
Each line card devlink object is created by device driver,
|
||||
according to the physical line card slots available on the device.
|
||||
|
||||
Similar to splitter cable, where the device might have no way
|
||||
of detection of the splitter cable geometry, the device
|
||||
might not have a way to detect line card type. For that devices,
|
||||
concept of provisioning is introduced. It allows the user to:
|
||||
|
||||
* Provision a line card slot with certain line card type
|
||||
|
||||
- Device driver would instruct the ASIC to prepare all
|
||||
resources accordingly. The device driver would
|
||||
create all instances, namely devlink port and netdevices
|
||||
that reside on the line card, according to the line card type
|
||||
* Manipulate of line card entities even without line card
|
||||
being physically connected or powered-up
|
||||
* Setup splitter cable on line card ports
|
||||
|
||||
- As on the ordinary ports, user may provision a splitter
|
||||
cable of a certain type, without the need to
|
||||
be physically connected to the port
|
||||
* Configure devlink ports and netdevices
|
||||
|
||||
Netdevice carrier is decided as follows:
|
||||
|
||||
* Line card is not inserted or powered-down
|
||||
|
||||
- The carrier is always down
|
||||
* Line card is inserted and powered up
|
||||
|
||||
- The carrier is decided as for ordinary port netdevice
|
||||
|
||||
Line card state
|
||||
===============
|
||||
|
||||
The ``devlink-linecard`` mechanism supports the following line card states:
|
||||
|
||||
* ``unprovisioned``: Line card is not provisioned on the slot.
|
||||
* ``unprovisioning``: Line card slot is currently being unprovisioned.
|
||||
* ``provisioning``: Line card slot is currently in a process of being provisioned
|
||||
with a line card type.
|
||||
* ``provisioning_failed``: Provisioning was not successful.
|
||||
* ``provisioned``: Line card slot is provisioned with a type.
|
||||
|
||||
The following diagram provides a general overview of ``devlink-linecard``
|
||||
state transitions::
|
||||
|
||||
+-------------------------+
|
||||
| |
|
||||
+----------------------------------> unprovisioned |
|
||||
| | |
|
||||
| +--------|-------^--------+
|
||||
| | |
|
||||
| | |
|
||||
| +--------v-------|--------+
|
||||
| | |
|
||||
| | provisioning |
|
||||
| | |
|
||||
| +------------|------------+
|
||||
| |
|
||||
| +-----------------------------+
|
||||
| | |
|
||||
| +------------v------------+ +------------v------------+
|
||||
| | | | |
|
||||
+----- provisioning_failed | | provisioned |
|
||||
| | | | |
|
||||
| +------------^------------+ +------------|------------+
|
||||
| | |
|
||||
| | |
|
||||
| | +------------v------------+
|
||||
| | | |
|
||||
| | | unprovisioning |
|
||||
| | | |
|
||||
| | +------------|------------+
|
||||
| | |
|
||||
| +-----------------------------+
|
||||
| |
|
||||
+-----------------------------------------------+
|
||||
|
||||
|
||||
Example usage
|
||||
=============
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ devlink lc show [ DEV [ lc LC_INDEX ] ]
|
||||
$ devlink lc set DEV lc LC_INDEX [ { type LC_TYPE | notype } ]
|
||||
|
||||
# Show current line card configuration and status for all slots:
|
||||
$ devlink lc
|
||||
|
||||
# Set slot 8 to be provisioned with type "16x100G":
|
||||
$ devlink lc set pci/0000:01:00.0 lc 8 type 16x100G
|
||||
|
||||
# Set slot 8 to be unprovisioned:
|
||||
$ devlink lc set pci/0000:01:00.0 lc 8 notype
|
@ -39,6 +39,7 @@ general.
|
||||
devlink-resource
|
||||
devlink-reload
|
||||
devlink-trap
|
||||
devlink-linecard
|
||||
|
||||
Driver-specific documentation
|
||||
-----------------------------
|
||||
|
@ -149,6 +149,40 @@ struct devlink_port_new_attrs {
|
||||
sfnum_valid:1;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct devlink_linecard_ops - Linecard operations
|
||||
* @provision: callback to provision the linecard slot with certain
|
||||
* type of linecard. As a result of this operation,
|
||||
* driver is expected to eventually (could be after
|
||||
* the function call returns) call one of:
|
||||
* devlink_linecard_provision_set()
|
||||
* devlink_linecard_provision_fail()
|
||||
* @unprovision: callback to unprovision the linecard slot. As a result
|
||||
* of this operation, driver is expected to eventually
|
||||
* (could be after the function call returns) call
|
||||
* devlink_linecard_provision_clear()
|
||||
* devlink_linecard_provision_fail()
|
||||
* @same_provision: callback to ask the driver if linecard is already
|
||||
* provisioned in the same way user asks this linecard to be
|
||||
* provisioned.
|
||||
* @types_count: callback to get number of supported types
|
||||
* @types_get: callback to get next type in list
|
||||
*/
|
||||
struct devlink_linecard_ops {
|
||||
int (*provision)(struct devlink_linecard *linecard, void *priv,
|
||||
const char *type, const void *type_priv,
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*unprovision)(struct devlink_linecard *linecard, void *priv,
|
||||
struct netlink_ext_ack *extack);
|
||||
bool (*same_provision)(struct devlink_linecard *linecard, void *priv,
|
||||
const char *type, const void *type_priv);
|
||||
unsigned int (*types_count)(struct devlink_linecard *linecard,
|
||||
void *priv);
|
||||
void (*types_get)(struct devlink_linecard *linecard,
|
||||
void *priv, unsigned int index, const char **type,
|
||||
const void **type_priv);
|
||||
};
|
||||
|
||||
struct devlink_sb_pool_info {
|
||||
enum devlink_sb_pool_type pool_type;
|
||||
u32 size;
|
||||
@ -1537,9 +1571,14 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port,
|
||||
int devlink_rate_leaf_create(struct devlink_port *port, void *priv);
|
||||
void devlink_rate_leaf_destroy(struct devlink_port *devlink_port);
|
||||
void devlink_rate_nodes_destroy(struct devlink *devlink);
|
||||
struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
||||
unsigned int linecard_index);
|
||||
struct devlink_linecard *
|
||||
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
|
||||
const struct devlink_linecard_ops *ops, void *priv);
|
||||
void devlink_linecard_destroy(struct devlink_linecard *linecard);
|
||||
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
|
||||
const char *type);
|
||||
void devlink_linecard_provision_clear(struct devlink_linecard *linecard);
|
||||
void devlink_linecard_provision_fail(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,
|
||||
|
@ -343,6 +343,18 @@ enum devlink_reload_limit {
|
||||
|
||||
#define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1)
|
||||
|
||||
enum devlink_linecard_state {
|
||||
DEVLINK_LINECARD_STATE_UNSPEC,
|
||||
DEVLINK_LINECARD_STATE_UNPROVISIONED,
|
||||
DEVLINK_LINECARD_STATE_UNPROVISIONING,
|
||||
DEVLINK_LINECARD_STATE_PROVISIONING,
|
||||
DEVLINK_LINECARD_STATE_PROVISIONING_FAILED,
|
||||
DEVLINK_LINECARD_STATE_PROVISIONED,
|
||||
|
||||
__DEVLINK_LINECARD_STATE_MAX,
|
||||
DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1
|
||||
};
|
||||
|
||||
enum devlink_attr {
|
||||
/* don't change the order or add anything between, this is ABI! */
|
||||
DEVLINK_ATTR_UNSPEC,
|
||||
@ -559,6 +571,9 @@ enum devlink_attr {
|
||||
DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
|
||||
|
||||
DEVLINK_ATTR_LINECARD_INDEX, /* u32 */
|
||||
DEVLINK_ATTR_LINECARD_STATE, /* u8 */
|
||||
DEVLINK_ATTR_LINECARD_TYPE, /* string */
|
||||
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */
|
||||
|
||||
/* add new attributes above here, update the policy in devlink.c */
|
||||
|
||||
|
@ -72,11 +72,21 @@ struct devlink {
|
||||
char priv[] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
||||
struct devlink_linecard_ops;
|
||||
struct devlink_linecard_type;
|
||||
|
||||
struct devlink_linecard {
|
||||
struct list_head list;
|
||||
struct devlink *devlink;
|
||||
unsigned int index;
|
||||
refcount_t refcount;
|
||||
const struct devlink_linecard_ops *ops;
|
||||
void *priv;
|
||||
enum devlink_linecard_state state;
|
||||
struct mutex state_lock; /* Protects state */
|
||||
const char *type;
|
||||
struct devlink_linecard_type *types;
|
||||
unsigned int types_count;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -452,8 +462,10 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
|
||||
|
||||
static void devlink_linecard_put(struct devlink_linecard *linecard)
|
||||
{
|
||||
if (refcount_dec_and_test(&linecard->refcount))
|
||||
if (refcount_dec_and_test(&linecard->refcount)) {
|
||||
mutex_destroy(&linecard->state_lock);
|
||||
kfree(linecard);
|
||||
}
|
||||
}
|
||||
|
||||
struct devlink_sb {
|
||||
@ -2037,6 +2049,11 @@ static int devlink_nl_cmd_rate_del_doit(struct sk_buff *skb,
|
||||
return err;
|
||||
}
|
||||
|
||||
struct devlink_linecard_type {
|
||||
const char *type;
|
||||
const void *priv;
|
||||
};
|
||||
|
||||
static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
||||
struct devlink *devlink,
|
||||
struct devlink_linecard *linecard,
|
||||
@ -2044,7 +2061,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
||||
u32 seq, int flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct devlink_linecard_type *linecard_type;
|
||||
struct nlattr *attr;
|
||||
void *hdr;
|
||||
int i;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
||||
if (!hdr)
|
||||
@ -2054,6 +2074,27 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
|
||||
goto nla_put_failure;
|
||||
if (linecard->type &&
|
||||
nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (linecard->types_count) {
|
||||
attr = nla_nest_start(msg,
|
||||
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
|
||||
if (!attr)
|
||||
goto nla_put_failure;
|
||||
for (i = 0; i < linecard->types_count; i++) {
|
||||
linecard_type = &linecard->types[i];
|
||||
if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
|
||||
linecard_type->type)) {
|
||||
nla_nest_cancel(msg, attr);
|
||||
goto nla_put_failure;
|
||||
}
|
||||
}
|
||||
nla_nest_end(msg, attr);
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
@ -2103,10 +2144,12 @@ static int devlink_nl_cmd_linecard_get_doit(struct sk_buff *skb,
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&linecard->state_lock);
|
||||
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
||||
DEVLINK_CMD_LINECARD_NEW,
|
||||
info->snd_portid, info->snd_seq, 0,
|
||||
info->extack);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
if (err) {
|
||||
nlmsg_free(msg);
|
||||
return err;
|
||||
@ -2139,12 +2182,14 @@ static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg,
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
mutex_lock(&linecard->state_lock);
|
||||
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);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
if (err) {
|
||||
mutex_unlock(&devlink->linecards_lock);
|
||||
devlink_put(devlink);
|
||||
@ -2163,6 +2208,163 @@ out:
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
static struct devlink_linecard_type *
|
||||
devlink_linecard_type_lookup(struct devlink_linecard *linecard,
|
||||
const char *type)
|
||||
{
|
||||
struct devlink_linecard_type *linecard_type;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < linecard->types_count; i++) {
|
||||
linecard_type = &linecard->types[i];
|
||||
if (!strcmp(type, linecard_type->type))
|
||||
return linecard_type;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int devlink_linecard_type_set(struct devlink_linecard *linecard,
|
||||
const char *type,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct devlink_linecard_ops *ops = linecard->ops;
|
||||
struct devlink_linecard_type *linecard_type;
|
||||
int err;
|
||||
|
||||
mutex_lock(&linecard->state_lock);
|
||||
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being provisioned");
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being unprovisioned");
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
linecard_type = devlink_linecard_type_lookup(linecard, type);
|
||||
if (!linecard_type) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unsupported line card type provided");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
|
||||
linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Line card already provisioned");
|
||||
err = -EBUSY;
|
||||
/* Check if the line card is provisioned in the same
|
||||
* way the user asks. In case it is, make the operation
|
||||
* to return success.
|
||||
*/
|
||||
if (ops->same_provision &&
|
||||
ops->same_provision(linecard, linecard->priv,
|
||||
linecard_type->type,
|
||||
linecard_type->priv))
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
|
||||
linecard->type = linecard_type->type;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
err = ops->provision(linecard, linecard->priv, linecard_type->type,
|
||||
linecard_type->priv, extack);
|
||||
if (err) {
|
||||
/* Provisioning failed. Assume the linecard is unprovisioned
|
||||
* for future operations.
|
||||
*/
|
||||
mutex_lock(&linecard->state_lock);
|
||||
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||
linecard->type = NULL;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
}
|
||||
return err;
|
||||
|
||||
out:
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&linecard->state_lock);
|
||||
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being provisioned");
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being unprovisioned");
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
|
||||
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||
linecard->type = NULL;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Line card is not provisioned");
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
err = linecard->ops->unprovision(linecard, linecard->priv,
|
||||
extack);
|
||||
if (err) {
|
||||
/* Unprovisioning failed. Assume the linecard is unprovisioned
|
||||
* for future operations.
|
||||
*/
|
||||
mutex_lock(&linecard->state_lock);
|
||||
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||
linecard->type = NULL;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
}
|
||||
return err;
|
||||
|
||||
out:
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct devlink_linecard *linecard = info->user_ptr[1];
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
int err;
|
||||
|
||||
if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
|
||||
const char *type;
|
||||
|
||||
type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
|
||||
if (strcmp(type, "")) {
|
||||
err = devlink_linecard_type_set(linecard, type, extack);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = devlink_linecard_type_unset(linecard, extack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
|
||||
struct devlink_sb *devlink_sb,
|
||||
enum devlink_command cmd, u32 portid,
|
||||
@ -8789,6 +8991,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
|
||||
[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 },
|
||||
[DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING },
|
||||
};
|
||||
|
||||
static const struct genl_small_ops devlink_nl_ops[] = {
|
||||
@ -8871,6 +9074,12 @@ static const struct genl_small_ops devlink_nl_ops[] = {
|
||||
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
||||
/* can be retrieved by unprivileged users */
|
||||
},
|
||||
{
|
||||
.cmd = DEVLINK_CMD_LINECARD_SET,
|
||||
.doit = devlink_nl_cmd_linecard_set_doit,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
||||
},
|
||||
{
|
||||
.cmd = DEVLINK_CMD_SB_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -9962,19 +10171,56 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int devlink_linecard_types_init(struct devlink_linecard *linecard)
|
||||
{
|
||||
struct devlink_linecard_type *linecard_type;
|
||||
unsigned int count;
|
||||
int i;
|
||||
|
||||
count = linecard->ops->types_count(linecard, linecard->priv);
|
||||
linecard->types = kmalloc_array(count, sizeof(*linecard_type),
|
||||
GFP_KERNEL);
|
||||
if (!linecard->types)
|
||||
return -ENOMEM;
|
||||
linecard->types_count = count;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
linecard_type = &linecard->types[i];
|
||||
linecard->ops->types_get(linecard, linecard->priv, i,
|
||||
&linecard_type->type,
|
||||
&linecard_type->priv);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
|
||||
{
|
||||
kfree(linecard->types);
|
||||
}
|
||||
|
||||
/**
|
||||
* devlink_linecard_create - Create devlink linecard
|
||||
*
|
||||
* @devlink: devlink
|
||||
* @linecard_index: driver-specific numerical identifier of the linecard
|
||||
* @ops: linecards ops
|
||||
* @priv: user priv pointer
|
||||
*
|
||||
* Create devlink linecard instance with provided linecard index.
|
||||
* Caller can use any indexing, even hw-related one.
|
||||
*
|
||||
* Return: Line card structure or an ERR_PTR() encoded error code.
|
||||
*/
|
||||
struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
||||
unsigned int linecard_index)
|
||||
struct devlink_linecard *
|
||||
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
|
||||
const struct devlink_linecard_ops *ops, void *priv)
|
||||
{
|
||||
struct devlink_linecard *linecard;
|
||||
int err;
|
||||
|
||||
if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
|
||||
!ops->types_count || !ops->types_get))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&devlink->linecards_lock);
|
||||
if (devlink_linecard_index_exists(devlink, linecard_index)) {
|
||||
@ -9990,6 +10236,19 @@ struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
||||
|
||||
linecard->devlink = devlink;
|
||||
linecard->index = linecard_index;
|
||||
linecard->ops = ops;
|
||||
linecard->priv = priv;
|
||||
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||
mutex_init(&linecard->state_lock);
|
||||
|
||||
err = devlink_linecard_types_init(linecard);
|
||||
if (err) {
|
||||
mutex_destroy(&linecard->state_lock);
|
||||
kfree(linecard);
|
||||
mutex_unlock(&devlink->linecards_lock);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
list_add_tail(&linecard->list, &devlink->linecard_list);
|
||||
refcount_set(&linecard->refcount, 1);
|
||||
mutex_unlock(&devlink->linecards_lock);
|
||||
@ -10010,11 +10269,68 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard)
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
|
||||
mutex_lock(&devlink->linecards_lock);
|
||||
list_del(&linecard->list);
|
||||
devlink_linecard_types_fini(linecard);
|
||||
mutex_unlock(&devlink->linecards_lock);
|
||||
devlink_linecard_put(linecard);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_linecard_destroy);
|
||||
|
||||
/**
|
||||
* devlink_linecard_provision_set - Set provisioning on linecard
|
||||
*
|
||||
* @linecard: devlink linecard
|
||||
* @type: linecard type
|
||||
*
|
||||
* This is either called directly from the provision() op call or
|
||||
* as a result of the provision() op call asynchronously.
|
||||
*/
|
||||
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
|
||||
const char *type)
|
||||
{
|
||||
mutex_lock(&linecard->state_lock);
|
||||
WARN_ON(linecard->type && strcmp(linecard->type, type));
|
||||
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
|
||||
linecard->type = type;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
|
||||
|
||||
/**
|
||||
* devlink_linecard_provision_clear - Clear provisioning on linecard
|
||||
*
|
||||
* @linecard: devlink linecard
|
||||
*
|
||||
* This is either called directly from the unprovision() op call or
|
||||
* as a result of the unprovision() op call asynchronously.
|
||||
*/
|
||||
void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
|
||||
{
|
||||
mutex_lock(&linecard->state_lock);
|
||||
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||
linecard->type = NULL;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
|
||||
|
||||
/**
|
||||
* devlink_linecard_provision_fail - Fail provisioning on linecard
|
||||
*
|
||||
* @linecard: devlink linecard
|
||||
*
|
||||
* This is either called directly from the provision() op call or
|
||||
* as a result of the provision() op call asynchronously.
|
||||
*/
|
||||
void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
|
||||
{
|
||||
mutex_lock(&linecard->state_lock);
|
||||
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
|
||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||
mutex_unlock(&linecard->state_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
|
||||
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user