Commit 8d92e4fb authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

devlink: introduce line card devices support



Line card can contain one or more devices that makes sense to make
visible to the user. For example, this can be a gearbox with
flash memory, which could be updated.

Provide the driver possibility to attach such devices to a line card
and expose those to user.

Example:
$ devlink lc show pci/0000:01:00.0 lc 8
pci/0000:01:00.0:
  lc 8 state active type 16x100G
    supported_types:
      16x100G
    devices:
      device 0
      device 1
      device 2
      device 3

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 cfc1d91a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1578,6 +1578,13 @@ 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);
struct devlink_linecard_device;
struct devlink_linecard_device *
devlink_linecard_device_create(struct devlink_linecard *linecard,
			       unsigned int device_index);
void
devlink_linecard_device_destroy(struct devlink_linecard *linecard,
				struct devlink_linecard_device *linecard_device);
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
				    const char *type);
void devlink_linecard_provision_clear(struct devlink_linecard *linecard);
+3 −0
Original line number Diff line number Diff line
@@ -575,6 +575,9 @@ enum devlink_attr {
	DEVLINK_ATTR_LINECARD_STATE,		/* u8 */
	DEVLINK_ATTR_LINECARD_TYPE,		/* string */
	DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES,	/* nested */
	DEVLINK_ATTR_LINECARD_DEVICE_LIST,	/* nested */
	DEVLINK_ATTR_LINECARD_DEVICE,		/* nested */
	DEVLINK_ATTR_LINECARD_DEVICE_INDEX,	/* u32 */

	/* add new attributes above here, update the policy in devlink.c */

+103 −1
Original line number Diff line number Diff line
@@ -83,10 +83,11 @@ struct devlink_linecard {
	const struct devlink_linecard_ops *ops;
	void *priv;
	enum devlink_linecard_state state;
	struct mutex state_lock; /* Protects state */
	struct mutex state_lock; /* Protects state and device_list */
	const char *type;
	struct devlink_linecard_type *types;
	unsigned int types_count;
	struct list_head device_list;
};

/**
@@ -2058,6 +2059,55 @@ struct devlink_linecard_type {
	const void *priv;
};

struct devlink_linecard_device {
	struct list_head list;
	unsigned int index;
};

static int
devlink_nl_linecard_device_fill(struct sk_buff *msg,
				struct devlink_linecard_device *linecard_device)
{
	struct nlattr *attr;

	attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE);
	if (!attr)
		return -EMSGSIZE;
	if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_DEVICE_INDEX,
			linecard_device->index)) {
		nla_nest_cancel(msg, attr);
		return -EMSGSIZE;
	}
	nla_nest_end(msg, attr);

	return 0;
}

static int devlink_nl_linecard_devices_fill(struct sk_buff *msg,
					    struct devlink_linecard *linecard)
{
	struct devlink_linecard_device *linecard_device;
	struct nlattr *attr;
	int err;

	if (list_empty(&linecard->device_list))
		return 0;

	attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_LIST);
	if (!attr)
		return -EMSGSIZE;
	list_for_each_entry(linecard_device, &linecard->device_list, list) {
		err = devlink_nl_linecard_device_fill(msg, linecard_device);
		if (err) {
			nla_nest_cancel(msg, attr);
			return err;
		}
	}
	nla_nest_end(msg, attr);

	return 0;
}

static int devlink_nl_linecard_fill(struct sk_buff *msg,
				    struct devlink *devlink,
				    struct devlink_linecard *linecard,
@@ -2068,6 +2118,7 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
	struct devlink_linecard_type *linecard_type;
	struct nlattr *attr;
	void *hdr;
	int err;
	int i;

	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
@@ -2100,6 +2151,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
		nla_nest_end(msg, attr);
	}

	err = devlink_nl_linecard_devices_fill(msg, linecard);
	if (err)
		goto nla_put_failure;

	genlmsg_end(msg, hdr);
	return 0;

@@ -10264,6 +10319,7 @@ devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
	linecard->priv = priv;
	linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
	mutex_init(&linecard->state_lock);
	INIT_LIST_HEAD(&linecard->device_list);

	err = devlink_linecard_types_init(linecard);
	if (err) {
@@ -10291,6 +10347,7 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard)
	struct devlink *devlink = linecard->devlink;

	devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
	WARN_ON(!list_empty(&linecard->device_list));
	mutex_lock(&devlink->linecards_lock);
	list_del(&linecard->list);
	devlink_linecard_types_fini(linecard);
@@ -10299,6 +10356,50 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard)
}
EXPORT_SYMBOL_GPL(devlink_linecard_destroy);

/**
 *	devlink_linecard_device_create - Create a device on linecard
 *
 *	@linecard: devlink linecard
 *	@device_index: index of the linecard device
 *
 *	Return: Line card device structure or an ERR_PTR() encoded error code.
 */
struct devlink_linecard_device *
devlink_linecard_device_create(struct devlink_linecard *linecard,
			       unsigned int device_index)
{
	struct devlink_linecard_device *linecard_device;

	linecard_device = kzalloc(sizeof(*linecard_device), GFP_KERNEL);
	if (!linecard_device)
		return ERR_PTR(-ENOMEM);
	linecard_device->index = device_index;
	mutex_lock(&linecard->state_lock);
	list_add_tail(&linecard_device->list, &linecard->device_list);
	devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
	mutex_unlock(&linecard->state_lock);
	return linecard_device;
}
EXPORT_SYMBOL_GPL(devlink_linecard_device_create);

/**
 *	devlink_linecard_device_destroy - Destroy device on linecard
 *
 *	@linecard: devlink linecard
 *	@linecard_device: devlink linecard device
 */
void
devlink_linecard_device_destroy(struct devlink_linecard *linecard,
				struct devlink_linecard_device *linecard_device)
{
	mutex_lock(&linecard->state_lock);
	list_del(&linecard_device->list);
	devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
	mutex_unlock(&linecard->state_lock);
	kfree(linecard_device);
}
EXPORT_SYMBOL_GPL(devlink_linecard_device_destroy);

/**
 *	devlink_linecard_provision_set - Set provisioning on linecard
 *
@@ -10331,6 +10432,7 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
{
	mutex_lock(&linecard->state_lock);
	WARN_ON(!list_empty(&linecard->device_list));
	linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
	linecard->type = NULL;
	devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);