| @@ -83,10 +83,11 @@ struct devlink_linecard { · 82 unmodified lines |
| 83 | 83 | const struct devlink_linecard_ops *ops; |
| 84 | 84 | void *priv; |
| 85 | 85 | enum devlink_linecard_state state; |
| 86 | | − struct mutex state_lock; /* Protects state */ |
| 86 | + struct mutex state_lock; /* Protects state and device_list */ |
| 87 | 87 | const char *type; |
| 88 | 88 | struct devlink_linecard_type *types; |
| 89 | 89 | unsigned int types_count; |
| 90 | + struct list_head device_list; |
| 90 | 91 | }; |
| 91 | 92 | |
| 92 | 93 | /** |
| @@ -2058,6 +2059,55 @@ struct devlink_linecard_type { · 1965 unmodified lines |
| 2058 | 2059 | const void *priv; |
| 2059 | 2060 | }; |
| 2060 | 2061 | |
| 2062 | +struct devlink_linecard_device { |
| 2063 | + struct list_head list; |
| 2064 | + unsigned int index; |
| 2065 | +}; |
| 2066 | + |
| 2067 | +static int |
| 2068 | +devlink_nl_linecard_device_fill(struct sk_buff *msg, |
| 2069 | + struct devlink_linecard_device *linecard_device) |
| 2070 | +{ |
| 2071 | + struct nlattr *attr; |
| 2072 | + |
| 2073 | + attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE); |
| 2074 | + if (!attr) |
| 2075 | + return -EMSGSIZE; |
| 2076 | + if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_DEVICE_INDEX, |
| 2077 | + linecard_device->index)) { |
| 2078 | + nla_nest_cancel(msg, attr); |
| 2079 | + return -EMSGSIZE; |
| 2080 | + } |
| 2081 | + nla_nest_end(msg, attr); |
| 2082 | + |
| 2083 | + return 0; |
| 2084 | +} |
| 2085 | + |
| 2086 | +static int devlink_nl_linecard_devices_fill(struct sk_buff *msg, |
| 2087 | + struct devlink_linecard *linecard) |
| 2088 | +{ |
| 2089 | + struct devlink_linecard_device *linecard_device; |
| 2090 | + struct nlattr *attr; |
| 2091 | + int err; |
| 2092 | + |
| 2093 | + if (list_empty(&linecard->device_list)) |
| 2094 | + return 0; |
| 2095 | + |
| 2096 | + attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_LIST); |
| 2097 | + if (!attr) |
| 2098 | + return -EMSGSIZE; |
| 2099 | + list_for_each_entry(linecard_device, &linecard->device_list, list) { |
| 2100 | + err = devlink_nl_linecard_device_fill(msg, linecard_device); |
| 2101 | + if (err) { |
| 2102 | + nla_nest_cancel(msg, attr); |
| 2103 | + return err; |
| 2104 | + } |
| 2105 | + } |
| 2106 | + nla_nest_end(msg, attr); |
| 2107 | + |
| 2108 | + return 0; |
| 2109 | +} |
| 2110 | + |
| 2061 | 2111 | static int devlink_nl_linecard_fill(struct sk_buff *msg, |
| 2062 | 2112 | struct devlink *devlink, |
| 2063 | 2113 | struct devlink_linecard *linecard, |
| @@ -2068,6 +2118,7 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, · 4 unmodified lines |
| 2068 | 2118 | struct devlink_linecard_type *linecard_type; |
| 2069 | 2119 | struct nlattr *attr; |
| 2070 | 2120 | void *hdr; |
| 2121 | + int err; |
| 2071 | 2122 | int i; |
| 2072 | 2123 | |
| 2073 | 2124 | 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, · 26 unmodified lines |
| 2100 | 2151 | nla_nest_end(msg, attr); |
| 2101 | 2152 | } |
| 2102 | 2153 | |
| 2154 | + err = devlink_nl_linecard_devices_fill(msg, linecard); |
| 2155 | + if (err) |
| 2156 | + goto nla_put_failure; |
| 2157 | + |
| 2103 | 2158 | genlmsg_end(msg, hdr); |
| 2104 | 2159 | return 0; |
| 2105 | 2160 | |
| @@ -10264,6 +10319,7 @@ devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, · 8158 unmodified lines |
| 10264 | 10319 | linecard->priv = priv; |
| 10265 | 10320 | linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; |
| 10266 | 10321 | mutex_init(&linecard->state_lock); |
| 10322 | + INIT_LIST_HEAD(&linecard->device_list); |
| 10267 | 10323 | |
| 10268 | 10324 | err = devlink_linecard_types_init(linecard); |
| 10269 | 10325 | if (err) { |
| @@ -10291,6 +10347,7 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) · 21 unmodified lines |
| 10291 | 10347 | struct devlink *devlink = linecard->devlink; |
| 10292 | 10348 | |
| 10293 | 10349 | devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); |
| 10350 | + WARN_ON(!list_empty(&linecard->device_list)); |
| 10294 | 10351 | mutex_lock(&devlink->linecards_lock); |
| 10295 | 10352 | list_del(&linecard->list); |
| 10296 | 10353 | devlink_linecard_types_fini(linecard); |
| @@ -10299,6 +10356,50 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) · 2 unmodified lines |
| 10299 | 10356 | } |
| 10300 | 10357 | EXPORT_SYMBOL_GPL(devlink_linecard_destroy); |
| 10301 | 10358 | |
| 10359 | +/** |
| 10360 | + * devlink_linecard_device_create - Create a device on linecard |
| 10361 | + * |
| 10362 | + * @linecard: devlink linecard |
| 10363 | + * @device_index: index of the linecard device |
| 10364 | + * |
| 10365 | + * Return: Line card device structure or an ERR_PTR() encoded error code. |
| 10366 | + */ |
| 10367 | +struct devlink_linecard_device * |
| 10368 | +devlink_linecard_device_create(struct devlink_linecard *linecard, |
| 10369 | + unsigned int device_index) |
| 10370 | +{ |
| 10371 | + struct devlink_linecard_device *linecard_device; |
| 10372 | + |
| 10373 | + linecard_device = kzalloc(sizeof(*linecard_device), GFP_KERNEL); |
| 10374 | + if (!linecard_device) |
| 10375 | + return ERR_PTR(-ENOMEM); |
| 10376 | + linecard_device->index = device_index; |
| 10377 | + mutex_lock(&linecard->state_lock); |
| 10378 | + list_add_tail(&linecard_device->list, &linecard->device_list); |
| 10379 | + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); |
| 10380 | + mutex_unlock(&linecard->state_lock); |
| 10381 | + return linecard_device; |
| 10382 | +} |
| 10383 | +EXPORT_SYMBOL_GPL(devlink_linecard_device_create); |
| 10384 | + |
| 10385 | +/** |
| 10386 | + * devlink_linecard_device_destroy - Destroy device on linecard |
| 10387 | + * |
| 10388 | + * @linecard: devlink linecard |
| 10389 | + * @linecard_device: devlink linecard device |
| 10390 | + */ |
| 10391 | +void |
| 10392 | +devlink_linecard_device_destroy(struct devlink_linecard *linecard, |
| 10393 | + struct devlink_linecard_device *linecard_device) |
| 10394 | +{ |
| 10395 | + mutex_lock(&linecard->state_lock); |
| 10396 | + list_del(&linecard_device->list); |
| 10397 | + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); |
| 10398 | + mutex_unlock(&linecard->state_lock); |
| 10399 | + kfree(linecard_device); |
| 10400 | +} |
| 10401 | +EXPORT_SYMBOL_GPL(devlink_linecard_device_destroy); |
| 10402 | + |
| 10302 | 10403 | /** |
| 10303 | 10404 | * devlink_linecard_provision_set - Set provisioning on linecard |
| 10304 | 10405 | * |
| @@ -10331,6 +10432,7 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); · 26 unmodified lines |
| 10331 | 10432 | void devlink_linecard_provision_clear(struct devlink_linecard *linecard) |
| 10332 | 10433 | { |
| 10333 | 10434 | mutex_lock(&linecard->state_lock); |
| 10435 | + WARN_ON(!list_empty(&linecard->device_list)); |
| 10334 | 10436 | linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; |
| 10335 | 10437 | linecard->type = NULL; |
| 10336 | 10438 | devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); |