aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-01-16 14:15:36 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-16 14:15:36 -0500
commitfedae6d7e6b4e05928b228b7f1c85407aa37fd04 (patch)
treeb1961af26dd36e7675639accebb89fc48dca4965
parentd98c8ccdebda9de011d3ea29ffb5aac57cd2b69a (diff)
parentf261708b92fbc51200fee782845a2a891f67234d (diff)
Merge branch 'devlink-resource'
Jiri Pirko says: ==================== devlink: Add support for resource abstraction Arkadi says: Many of the ASIC's internal resources are limited and are shared between several hardware procedures. For example, unified hash-based memory can be used for many lookup purposes, like FDB and LPM. In many cases the user can provide a partitioning scheme for such a resource in order to perform fine tuning for his application. In such cases performing driver reload is needed for the changes to take place, thus this patchset also adds support for hot reload. Such an abstraction can be coupled with devlink's dpipe interface, which models the ASIC's pipeline as a graph of match/action tables. By modeling the hardware resource object, and by coupling it to several dpipe tables, further visibility can be achieved in order to debug ASIC-wide issues. The proposed interface will provide the user the ability to understand the limitations of the hardware, and receive notification regarding its occupancy. Furthermore, monitoring the resource occupancy can be done in real-time and can be useful in many cases. --- v2->v3 - Mix/Max/Gran attributes. - Add resource consumption per table. - Change basic resource unit to 'entry'. - ABI documentation. v1->v2 - Add resource size attribute. - Fix split bug. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/ABI/testing/devlink-resource-mlxsw33
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c92
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.h16
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/i2c.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c98
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c249
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h13
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c81
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c26
-rw-r--r--include/net/devlink.h115
-rw-r--r--include/uapi/linux/devlink.h25
-rw-r--r--net/core/devlink.c594
12 files changed, 1213 insertions, 134 deletions
diff --git a/Documentation/ABI/testing/devlink-resource-mlxsw b/Documentation/ABI/testing/devlink-resource-mlxsw
new file mode 100644
index 000000000000..259ed2948ec0
--- /dev/null
+++ b/Documentation/ABI/testing/devlink-resource-mlxsw
@@ -0,0 +1,33 @@
1What: /kvd/
2Date: 08-Jan-2018
3KernelVersion: v4.16
4Contact: mlxsw@mellanox.com
5Description: The main database in the Spectrum device is a centralized
6 KVD database used for many of the tables used to configure
7 the chip including L2 FDB, L3 LPM, ECMP and more. The KVD
8 is divided into two sections, the first is hash-based table
9 and the second is a linear access table. The division
10 between the linear and hash-based sections is static and
11 require reload before the changes take effect.
12
13What: /kvd/linear
14Date: 08-Jan-2018
15KernelVersion: v4.16
16Contact: mlxsw@mellanox.com
17Description: The linear section of the KVD is managed by software as a
18 flat memory accessed using an index.
19
20What: /kvd/hash_single
21Date: 08-Jan-2018
22KernelVersion: v4.16
23Contact: mlxsw@mellanox.com
24Description: The hash based section of the KVD is managed by the switch
25 device. Used in case the key size is smaller or equal to
26 64bit.
27
28What: /kvd/hash_double
29Date: 08-Jan-2018
30KernelVersion: v4.16
31Contact: mlxsw@mellanox.com
32Description: The hash based section of the KVD is managed by the switch
33 device. Used in case the key is larger than 64 bit.
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index f3315bc874ad..3529b545675d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -113,6 +113,7 @@ struct mlxsw_core {
113 struct mlxsw_thermal *thermal; 113 struct mlxsw_thermal *thermal;
114 struct mlxsw_core_port *ports; 114 struct mlxsw_core_port *ports;
115 unsigned int max_ports; 115 unsigned int max_ports;
116 bool reload_fail;
116 unsigned long driver_priv[0]; 117 unsigned long driver_priv[0];
117 /* driver_priv has to be always the last item */ 118 /* driver_priv has to be always the last item */
118}; 119};
@@ -962,7 +963,28 @@ mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port,
962 pool_type, p_cur, p_max); 963 pool_type, p_cur, p_max);
963} 964}
964 965
966static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink)
967{
968 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
969 const struct mlxsw_bus *mlxsw_bus = mlxsw_core->bus;
970 int err;
971
972 if (!mlxsw_bus->reset)
973 return -EOPNOTSUPP;
974
975 mlxsw_core_bus_device_unregister(mlxsw_core, true);
976 mlxsw_bus->reset(mlxsw_core->bus_priv);
977 err = mlxsw_core_bus_device_register(mlxsw_core->bus_info,
978 mlxsw_core->bus,
979 mlxsw_core->bus_priv, true,
980 devlink);
981 if (err)
982 mlxsw_core->reload_fail = true;
983 return err;
984}
985
965static const struct devlink_ops mlxsw_devlink_ops = { 986static const struct devlink_ops mlxsw_devlink_ops = {
987 .reload = mlxsw_devlink_core_bus_device_reload,
966 .port_type_set = mlxsw_devlink_port_type_set, 988 .port_type_set = mlxsw_devlink_port_type_set,
967 .port_split = mlxsw_devlink_port_split, 989 .port_split = mlxsw_devlink_port_split,
968 .port_unsplit = mlxsw_devlink_port_unsplit, 990 .port_unsplit = mlxsw_devlink_port_unsplit,
@@ -980,23 +1002,26 @@ static const struct devlink_ops mlxsw_devlink_ops = {
980 1002
981int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, 1003int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
982 const struct mlxsw_bus *mlxsw_bus, 1004 const struct mlxsw_bus *mlxsw_bus,
983 void *bus_priv) 1005 void *bus_priv, bool reload,
1006 struct devlink *devlink)
984{ 1007{
985 const char *device_kind = mlxsw_bus_info->device_kind; 1008 const char *device_kind = mlxsw_bus_info->device_kind;
986 struct mlxsw_core *mlxsw_core; 1009 struct mlxsw_core *mlxsw_core;
987 struct mlxsw_driver *mlxsw_driver; 1010 struct mlxsw_driver *mlxsw_driver;
988 struct devlink *devlink;
989 size_t alloc_size; 1011 size_t alloc_size;
990 int err; 1012 int err;
991 1013
992 mlxsw_driver = mlxsw_core_driver_get(device_kind); 1014 mlxsw_driver = mlxsw_core_driver_get(device_kind);
993 if (!mlxsw_driver) 1015 if (!mlxsw_driver)
994 return -EINVAL; 1016 return -EINVAL;
995 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size; 1017
996 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size); 1018 if (!reload) {
997 if (!devlink) { 1019 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
998 err = -ENOMEM; 1020 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
999 goto err_devlink_alloc; 1021 if (!devlink) {
1022 err = -ENOMEM;
1023 goto err_devlink_alloc;
1024 }
1000 } 1025 }
1001 1026
1002 mlxsw_core = devlink_priv(devlink); 1027 mlxsw_core = devlink_priv(devlink);
@@ -1012,6 +1037,12 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1012 if (err) 1037 if (err)
1013 goto err_bus_init; 1038 goto err_bus_init;
1014 1039
1040 if (mlxsw_driver->resources_register && !reload) {
1041 err = mlxsw_driver->resources_register(mlxsw_core);
1042 if (err)
1043 goto err_register_resources;
1044 }
1045
1015 err = mlxsw_ports_init(mlxsw_core); 1046 err = mlxsw_ports_init(mlxsw_core);
1016 if (err) 1047 if (err)
1017 goto err_ports_init; 1048 goto err_ports_init;
@@ -1032,9 +1063,11 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1032 if (err) 1063 if (err)
1033 goto err_emad_init; 1064 goto err_emad_init;
1034 1065
1035 err = devlink_register(devlink, mlxsw_bus_info->dev); 1066 if (!reload) {
1036 if (err) 1067 err = devlink_register(devlink, mlxsw_bus_info->dev);
1037 goto err_devlink_register; 1068 if (err)
1069 goto err_devlink_register;
1070 }
1038 1071
1039 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); 1072 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
1040 if (err) 1073 if (err)
@@ -1057,7 +1090,8 @@ err_driver_init:
1057 mlxsw_thermal_fini(mlxsw_core->thermal); 1090 mlxsw_thermal_fini(mlxsw_core->thermal);
1058err_thermal_init: 1091err_thermal_init:
1059err_hwmon_init: 1092err_hwmon_init:
1060 devlink_unregister(devlink); 1093 if (!reload)
1094 devlink_unregister(devlink);
1061err_devlink_register: 1095err_devlink_register:
1062 mlxsw_emad_fini(mlxsw_core); 1096 mlxsw_emad_fini(mlxsw_core);
1063err_emad_init: 1097err_emad_init:
@@ -1067,26 +1101,40 @@ err_alloc_lag_mapping:
1067err_ports_init: 1101err_ports_init:
1068 mlxsw_bus->fini(bus_priv); 1102 mlxsw_bus->fini(bus_priv);
1069err_bus_init: 1103err_bus_init:
1070 devlink_free(devlink); 1104 if (!reload)
1105 devlink_resources_unregister(devlink, NULL);
1106err_register_resources:
1107 if (!reload)
1108 devlink_free(devlink);
1071err_devlink_alloc: 1109err_devlink_alloc:
1072 mlxsw_core_driver_put(device_kind); 1110 mlxsw_core_driver_put(device_kind);
1073 return err; 1111 return err;
1074} 1112}
1075EXPORT_SYMBOL(mlxsw_core_bus_device_register); 1113EXPORT_SYMBOL(mlxsw_core_bus_device_register);
1076 1114
1077void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core) 1115void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
1116 bool reload)
1078{ 1117{
1079 const char *device_kind = mlxsw_core->bus_info->device_kind; 1118 const char *device_kind = mlxsw_core->bus_info->device_kind;
1080 struct devlink *devlink = priv_to_devlink(mlxsw_core); 1119 struct devlink *devlink = priv_to_devlink(mlxsw_core);
1081 1120
1121 if (mlxsw_core->reload_fail)
1122 goto reload_fail;
1123
1082 if (mlxsw_core->driver->fini) 1124 if (mlxsw_core->driver->fini)
1083 mlxsw_core->driver->fini(mlxsw_core); 1125 mlxsw_core->driver->fini(mlxsw_core);
1084 mlxsw_thermal_fini(mlxsw_core->thermal); 1126 mlxsw_thermal_fini(mlxsw_core->thermal);
1085 devlink_unregister(devlink); 1127 if (!reload)
1128 devlink_unregister(devlink);
1086 mlxsw_emad_fini(mlxsw_core); 1129 mlxsw_emad_fini(mlxsw_core);
1087 kfree(mlxsw_core->lag.mapping); 1130 kfree(mlxsw_core->lag.mapping);
1088 mlxsw_ports_fini(mlxsw_core); 1131 mlxsw_ports_fini(mlxsw_core);
1132 if (!reload)
1133 devlink_resources_unregister(devlink, NULL);
1089 mlxsw_core->bus->fini(mlxsw_core->bus_priv); 1134 mlxsw_core->bus->fini(mlxsw_core->bus_priv);
1135 if (reload)
1136 return;
1137reload_fail:
1090 devlink_free(devlink); 1138 devlink_free(devlink);
1091 mlxsw_core_driver_put(device_kind); 1139 mlxsw_core_driver_put(device_kind);
1092} 1140}
@@ -1791,6 +1839,22 @@ void mlxsw_core_flush_owq(void)
1791} 1839}
1792EXPORT_SYMBOL(mlxsw_core_flush_owq); 1840EXPORT_SYMBOL(mlxsw_core_flush_owq);
1793 1841
1842int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
1843 const struct mlxsw_config_profile *profile,
1844 u64 *p_single_size, u64 *p_double_size,
1845 u64 *p_linear_size)
1846{
1847 struct mlxsw_driver *driver = mlxsw_core->driver;
1848
1849 if (!driver->kvd_sizes_get)
1850 return -EINVAL;
1851
1852 return driver->kvd_sizes_get(mlxsw_core, profile,
1853 p_single_size, p_double_size,
1854 p_linear_size);
1855}
1856EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get);
1857
1794static int __init mlxsw_core_module_init(void) 1858static int __init mlxsw_core_module_init(void)
1795{ 1859{
1796 int err; 1860 int err;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index 6e966af72fc4..5ddafd74dc00 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -66,8 +66,9 @@ void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver);
66 66
67int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, 67int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
68 const struct mlxsw_bus *mlxsw_bus, 68 const struct mlxsw_bus *mlxsw_bus,
69 void *bus_priv); 69 void *bus_priv, bool reload,
70void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core); 70 struct devlink *devlink);
71void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, bool reload);
71 72
72struct mlxsw_tx_info { 73struct mlxsw_tx_info {
73 u8 local_port; 74 u8 local_port;
@@ -308,10 +309,20 @@ struct mlxsw_driver {
308 u32 *p_cur, u32 *p_max); 309 u32 *p_cur, u32 *p_max);
309 void (*txhdr_construct)(struct sk_buff *skb, 310 void (*txhdr_construct)(struct sk_buff *skb,
310 const struct mlxsw_tx_info *tx_info); 311 const struct mlxsw_tx_info *tx_info);
312 int (*resources_register)(struct mlxsw_core *mlxsw_core);
313 int (*kvd_sizes_get)(struct mlxsw_core *mlxsw_core,
314 const struct mlxsw_config_profile *profile,
315 u64 *p_single_size, u64 *p_double_size,
316 u64 *p_linear_size);
311 u8 txhdr_len; 317 u8 txhdr_len;
312 const struct mlxsw_config_profile *profile; 318 const struct mlxsw_config_profile *profile;
313}; 319};
314 320
321int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
322 const struct mlxsw_config_profile *profile,
323 u64 *p_single_size, u64 *p_double_size,
324 u64 *p_linear_size);
325
315bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core, 326bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
316 enum mlxsw_res_id res_id); 327 enum mlxsw_res_id res_id);
317 328
@@ -332,6 +343,7 @@ struct mlxsw_bus {
332 const struct mlxsw_config_profile *profile, 343 const struct mlxsw_config_profile *profile,
333 struct mlxsw_res *res); 344 struct mlxsw_res *res);
334 void (*fini)(void *bus_priv); 345 void (*fini)(void *bus_priv);
346 void (*reset)(void *bus_priv);
335 bool (*skb_transmit_busy)(void *bus_priv, 347 bool (*skb_transmit_busy)(void *bus_priv,
336 const struct mlxsw_tx_info *tx_info); 348 const struct mlxsw_tx_info *tx_info);
337 int (*skb_transmit)(void *bus_priv, struct sk_buff *skb, 349 int (*skb_transmit)(void *bus_priv, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
index c0dcfa05b077..25f9915ebd82 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
@@ -539,7 +539,8 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
539 mlxsw_i2c->dev = &client->dev; 539 mlxsw_i2c->dev = &client->dev;
540 540
541 err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, 541 err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
542 &mlxsw_i2c_bus, mlxsw_i2c); 542 &mlxsw_i2c_bus, mlxsw_i2c, false,
543 NULL);
543 if (err) { 544 if (err) {
544 dev_err(&client->dev, "Fail to register core bus\n"); 545 dev_err(&client->dev, "Fail to register core bus\n");
545 return err; 546 return err;
@@ -557,7 +558,7 @@ static int mlxsw_i2c_remove(struct i2c_client *client)
557{ 558{
558 struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); 559 struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
559 560
560 mlxsw_core_bus_device_unregister(mlxsw_i2c->core); 561 mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false);
561 mutex_destroy(&mlxsw_i2c->cmd.lock); 562 mutex_destroy(&mlxsw_i2c->cmd.lock);
562 563
563 return 0; 564 return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 6ef20e5cc77d..85faa87bf42d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -154,6 +154,7 @@ struct mlxsw_pci {
154 } comp; 154 } comp;
155 } cmd; 155 } cmd;
156 struct mlxsw_bus_info bus_info; 156 struct mlxsw_bus_info bus_info;
157 const struct pci_device_id *id;
157}; 158};
158 159
159static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q) 160static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q)
@@ -1052,38 +1053,18 @@ static int mlxsw_pci_resources_query(struct mlxsw_pci *mlxsw_pci, char *mbox,
1052} 1053}
1053 1054
1054static int 1055static int
1055mlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_config_profile *profile, 1056mlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_pci *mlxsw_pci,
1057 const struct mlxsw_config_profile *profile,
1056 struct mlxsw_res *res) 1058 struct mlxsw_res *res)
1057{ 1059{
1058 u32 single_size, double_size, linear_size; 1060 u64 single_size, double_size, linear_size;
1059 1061 int err;
1060 if (!MLXSW_RES_VALID(res, KVD_SINGLE_MIN_SIZE) ||
1061 !MLXSW_RES_VALID(res, KVD_DOUBLE_MIN_SIZE) ||
1062 !profile->used_kvd_split_data)
1063 return -EIO;
1064
1065 linear_size = profile->kvd_linear_size;
1066 1062
1067 /* The hash part is what left of the kvd without the 1063 err = mlxsw_core_kvd_sizes_get(mlxsw_pci->core, profile,
1068 * linear part. It is split to the single size and 1064 &single_size, &double_size,
1069 * double size by the parts ratio from the profile. 1065 &linear_size);
1070 * Both sizes must be a multiplications of the 1066 if (err)
1071 * granularity from the profile. 1067 return err;
1072 */
1073 double_size = MLXSW_RES_GET(res, KVD_SIZE) - linear_size;
1074 double_size *= profile->kvd_hash_double_parts;
1075 double_size /= profile->kvd_hash_double_parts +
1076 profile->kvd_hash_single_parts;
1077 double_size /= profile->kvd_hash_granularity;
1078 double_size *= profile->kvd_hash_granularity;
1079 single_size = MLXSW_RES_GET(res, KVD_SIZE) - double_size -
1080 linear_size;
1081
1082 /* Check results are legal. */
1083 if (single_size < MLXSW_RES_GET(res, KVD_SINGLE_MIN_SIZE) ||
1084 double_size < MLXSW_RES_GET(res, KVD_DOUBLE_MIN_SIZE) ||
1085 MLXSW_RES_GET(res, KVD_SIZE) < linear_size)
1086 return -EIO;
1087 1068
1088 MLXSW_RES_SET(res, KVD_SINGLE_SIZE, single_size); 1069 MLXSW_RES_SET(res, KVD_SINGLE_SIZE, single_size);
1089 MLXSW_RES_SET(res, KVD_DOUBLE_SIZE, double_size); 1070 MLXSW_RES_SET(res, KVD_DOUBLE_SIZE, double_size);
@@ -1184,7 +1165,7 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
1184 mbox, profile->adaptive_routing_group_cap); 1165 mbox, profile->adaptive_routing_group_cap);
1185 } 1166 }
1186 if (MLXSW_RES_VALID(res, KVD_SIZE)) { 1167 if (MLXSW_RES_VALID(res, KVD_SIZE)) {
1187 err = mlxsw_pci_profile_get_kvd_sizes(profile, res); 1168 err = mlxsw_pci_profile_get_kvd_sizes(mlxsw_pci, profile, res);
1188 if (err) 1169 if (err)
1189 return err; 1170 return err;
1190 1171
@@ -1622,16 +1603,6 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
1622 return err; 1603 return err;
1623} 1604}
1624 1605
1625static const struct mlxsw_bus mlxsw_pci_bus = {
1626 .kind = "pci",
1627 .init = mlxsw_pci_init,
1628 .fini = mlxsw_pci_fini,
1629 .skb_transmit_busy = mlxsw_pci_skb_transmit_busy,
1630 .skb_transmit = mlxsw_pci_skb_transmit,
1631 .cmd_exec = mlxsw_pci_cmd_exec,
1632 .features = MLXSW_BUS_F_TXRX,
1633};
1634
1635static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, 1606static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
1636 const struct pci_device_id *id) 1607 const struct pci_device_id *id)
1637{ 1608{
@@ -1660,6 +1631,41 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
1660 return 0; 1631 return 0;
1661} 1632}
1662 1633
1634static void mlxsw_pci_free_irq_vectors(struct mlxsw_pci *mlxsw_pci)
1635{
1636 pci_free_irq_vectors(mlxsw_pci->pdev);
1637}
1638
1639static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci)
1640{
1641 int err;
1642
1643 err = pci_alloc_irq_vectors(mlxsw_pci->pdev, 1, 1, PCI_IRQ_MSIX);
1644 if (err < 0)
1645 dev_err(&mlxsw_pci->pdev->dev, "MSI-X init failed\n");
1646 return err;
1647}
1648
1649static void mlxsw_pci_reset(void *bus_priv)
1650{
1651 struct mlxsw_pci *mlxsw_pci = bus_priv;
1652
1653 mlxsw_pci_free_irq_vectors(mlxsw_pci);
1654 mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id);
1655 mlxsw_pci_alloc_irq_vectors(mlxsw_pci);
1656}
1657
1658static const struct mlxsw_bus mlxsw_pci_bus = {
1659 .kind = "pci",
1660 .init = mlxsw_pci_init,
1661 .fini = mlxsw_pci_fini,
1662 .skb_transmit_busy = mlxsw_pci_skb_transmit_busy,
1663 .skb_transmit = mlxsw_pci_skb_transmit,
1664 .cmd_exec = mlxsw_pci_cmd_exec,
1665 .features = MLXSW_BUS_F_TXRX,
1666 .reset = mlxsw_pci_reset,
1667};
1668
1663static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 1669static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1664{ 1670{
1665 const char *driver_name = pdev->driver->name; 1671 const char *driver_name = pdev->driver->name;
@@ -1721,7 +1727,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1721 goto err_sw_reset; 1727 goto err_sw_reset;
1722 } 1728 }
1723 1729
1724 err = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); 1730 err = mlxsw_pci_alloc_irq_vectors(mlxsw_pci);
1725 if (err < 0) { 1731 if (err < 0) {
1726 dev_err(&pdev->dev, "MSI-X init failed\n"); 1732 dev_err(&pdev->dev, "MSI-X init failed\n");
1727 goto err_msix_init; 1733 goto err_msix_init;
@@ -1730,9 +1736,11 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1730 mlxsw_pci->bus_info.device_kind = driver_name; 1736 mlxsw_pci->bus_info.device_kind = driver_name;
1731 mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); 1737 mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev);
1732 mlxsw_pci->bus_info.dev = &pdev->dev; 1738 mlxsw_pci->bus_info.dev = &pdev->dev;
1739 mlxsw_pci->id = id;
1733 1740
1734 err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, 1741 err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info,
1735 &mlxsw_pci_bus, mlxsw_pci); 1742 &mlxsw_pci_bus, mlxsw_pci, false,
1743 NULL);
1736 if (err) { 1744 if (err) {
1737 dev_err(&pdev->dev, "cannot register bus device\n"); 1745 dev_err(&pdev->dev, "cannot register bus device\n");
1738 goto err_bus_device_register; 1746 goto err_bus_device_register;
@@ -1741,7 +1749,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1741 return 0; 1749 return 0;
1742 1750
1743err_bus_device_register: 1751err_bus_device_register:
1744 pci_free_irq_vectors(mlxsw_pci->pdev); 1752 mlxsw_pci_free_irq_vectors(mlxsw_pci);
1745err_msix_init: 1753err_msix_init:
1746err_sw_reset: 1754err_sw_reset:
1747 iounmap(mlxsw_pci->hw_addr); 1755 iounmap(mlxsw_pci->hw_addr);
@@ -1760,8 +1768,8 @@ static void mlxsw_pci_remove(struct pci_dev *pdev)
1760{ 1768{
1761 struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); 1769 struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);
1762 1770
1763 mlxsw_core_bus_device_unregister(mlxsw_pci->core); 1771 mlxsw_core_bus_device_unregister(mlxsw_pci->core, false);
1764 pci_free_irq_vectors(mlxsw_pci->pdev); 1772 mlxsw_pci_free_irq_vectors(mlxsw_pci);
1765 iounmap(mlxsw_pci->hw_addr); 1773 iounmap(mlxsw_pci->hw_addr);
1766 pci_release_regions(mlxsw_pci->pdev); 1774 pci_release_regions(mlxsw_pci->pdev);
1767 pci_disable_device(mlxsw_pci->pdev); 1775 pci_disable_device(mlxsw_pci->pdev);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index f78bfe394966..ed92e04309ba 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3991,6 +3991,253 @@ static const struct mlxsw_config_profile mlxsw_sp_config_profile = {
3991 .resource_query_enable = 1, 3991 .resource_query_enable = 1,
3992}; 3992};
3993 3993
3994static bool
3995mlxsw_sp_resource_kvd_granularity_validate(struct netlink_ext_ack *extack,
3996 u64 size)
3997{
3998 const struct mlxsw_config_profile *profile;
3999
4000 profile = &mlxsw_sp_config_profile;
4001 if (size % profile->kvd_hash_granularity) {
4002 NL_SET_ERR_MSG_MOD(extack, "resource set with wrong granularity");
4003 return false;
4004 }
4005 return true;
4006}
4007
4008static int
4009mlxsw_sp_resource_kvd_size_validate(struct devlink *devlink, u64 size,
4010 struct netlink_ext_ack *extack)
4011{
4012 NL_SET_ERR_MSG_MOD(extack, "kvd size cannot be changed");
4013 return -EINVAL;
4014}
4015
4016static int
4017mlxsw_sp_resource_kvd_linear_size_validate(struct devlink *devlink, u64 size,
4018 struct netlink_ext_ack *extack)
4019{
4020 if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size))
4021 return -EINVAL;
4022
4023 return 0;
4024}
4025
4026static int
4027mlxsw_sp_resource_kvd_hash_single_size_validate(struct devlink *devlink, u64 size,
4028 struct netlink_ext_ack *extack)
4029{
4030 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
4031
4032 if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size))
4033 return -EINVAL;
4034
4035 if (size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE)) {
4036 NL_SET_ERR_MSG_MOD(extack, "hash single size is smaller than minimum");
4037 return -EINVAL;
4038 }
4039 return 0;
4040}
4041
4042static int
4043mlxsw_sp_resource_kvd_hash_double_size_validate(struct devlink *devlink, u64 size,
4044 struct netlink_ext_ack *extack)
4045{
4046 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
4047
4048 if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size))
4049 return -EINVAL;
4050
4051 if (size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE)) {
4052 NL_SET_ERR_MSG_MOD(extack, "hash double size is smaller than minimum");
4053 return -EINVAL;
4054 }
4055 return 0;
4056}
4057
4058static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink)
4059{
4060 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
4061 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
4062
4063 return mlxsw_sp_kvdl_occ_get(mlxsw_sp);
4064}
4065
4066static struct devlink_resource_ops mlxsw_sp_resource_kvd_ops = {
4067 .size_validate = mlxsw_sp_resource_kvd_size_validate,
4068};
4069
4070static struct devlink_resource_ops mlxsw_sp_resource_kvd_linear_ops = {
4071 .size_validate = mlxsw_sp_resource_kvd_linear_size_validate,
4072 .occ_get = mlxsw_sp_resource_kvd_linear_occ_get,
4073};
4074
4075static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_single_ops = {
4076 .size_validate = mlxsw_sp_resource_kvd_hash_single_size_validate,
4077};
4078
4079static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = {
4080 .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate,
4081};
4082
4083static struct devlink_resource_size_params mlxsw_sp_kvd_size_params;
4084static struct devlink_resource_size_params mlxsw_sp_linear_size_params;
4085static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params;
4086static struct devlink_resource_size_params mlxsw_sp_hash_double_size_params;
4087
4088static void
4089mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core)
4090{
4091 u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
4092 KVD_SINGLE_MIN_SIZE);
4093 u32 double_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
4094 KVD_DOUBLE_MIN_SIZE);
4095 u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
4096 u32 linear_size_min = 0;
4097
4098 /* KVD top resource */
4099 mlxsw_sp_kvd_size_params.size_min = kvd_size;
4100 mlxsw_sp_kvd_size_params.size_max = kvd_size;
4101 mlxsw_sp_kvd_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
4102 mlxsw_sp_kvd_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
4103
4104 /* Linear part init */
4105 mlxsw_sp_linear_size_params.size_min = linear_size_min;
4106 mlxsw_sp_linear_size_params.size_max = kvd_size - single_size_min -
4107 double_size_min;
4108 mlxsw_sp_linear_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
4109 mlxsw_sp_linear_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
4110
4111 /* Hash double part init */
4112 mlxsw_sp_hash_double_size_params.size_min = double_size_min;
4113 mlxsw_sp_hash_double_size_params.size_max = kvd_size - single_size_min -
4114 linear_size_min;
4115 mlxsw_sp_hash_double_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
4116 mlxsw_sp_hash_double_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
4117
4118 /* Hash single part init */
4119 mlxsw_sp_hash_single_size_params.size_min = single_size_min;
4120 mlxsw_sp_hash_single_size_params.size_max = kvd_size - double_size_min -
4121 linear_size_min;
4122 mlxsw_sp_hash_single_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
4123 mlxsw_sp_hash_single_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
4124}
4125
4126static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
4127{
4128 struct devlink *devlink = priv_to_devlink(mlxsw_core);
4129 u32 kvd_size, single_size, double_size, linear_size;
4130 const struct mlxsw_config_profile *profile;
4131 int err;
4132
4133 profile = &mlxsw_sp_config_profile;
4134 if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))
4135 return -EIO;
4136
4137 mlxsw_sp_resource_size_params_prepare(mlxsw_core);
4138 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
4139 err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
4140 true, kvd_size,
4141 MLXSW_SP_RESOURCE_KVD,
4142 DEVLINK_RESOURCE_ID_PARENT_TOP,
4143 &mlxsw_sp_kvd_size_params,
4144 &mlxsw_sp_resource_kvd_ops);
4145 if (err)
4146 return err;
4147
4148 linear_size = profile->kvd_linear_size;
4149 err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR,
4150 false, linear_size,
4151 MLXSW_SP_RESOURCE_KVD_LINEAR,
4152 MLXSW_SP_RESOURCE_KVD,
4153 &mlxsw_sp_linear_size_params,
4154 &mlxsw_sp_resource_kvd_linear_ops);
4155 if (err)
4156 return err;
4157
4158 double_size = kvd_size - linear_size;
4159 double_size *= profile->kvd_hash_double_parts;
4160 double_size /= profile->kvd_hash_double_parts +
4161 profile->kvd_hash_single_parts;
4162 double_size = rounddown(double_size, profile->kvd_hash_granularity);
4163 err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE,
4164 false, double_size,
4165 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
4166 MLXSW_SP_RESOURCE_KVD,
4167 &mlxsw_sp_hash_double_size_params,
4168 &mlxsw_sp_resource_kvd_hash_double_ops);
4169 if (err)
4170 return err;
4171
4172 single_size = kvd_size - double_size - linear_size;
4173 err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE,
4174 false, single_size,
4175 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
4176 MLXSW_SP_RESOURCE_KVD,
4177 &mlxsw_sp_hash_single_size_params,
4178 &mlxsw_sp_resource_kvd_hash_single_ops);
4179 if (err)
4180 return err;
4181
4182 return 0;
4183}
4184
4185static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
4186 const struct mlxsw_config_profile *profile,
4187 u64 *p_single_size, u64 *p_double_size,
4188 u64 *p_linear_size)
4189{
4190 struct devlink *devlink = priv_to_devlink(mlxsw_core);
4191 u32 double_size;
4192 int err;
4193
4194 if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||
4195 !MLXSW_CORE_RES_VALID(mlxsw_core, KVD_DOUBLE_MIN_SIZE) ||
4196 !profile->used_kvd_split_data)
4197 return -EIO;
4198
4199 /* The hash part is what left of the kvd without the
4200 * linear part. It is split to the single size and
4201 * double size by the parts ratio from the profile.
4202 * Both sizes must be a multiplications of the
4203 * granularity from the profile. In case the user
4204 * provided the sizes they are obtained via devlink.
4205 */
4206 err = devlink_resource_size_get(devlink,
4207 MLXSW_SP_RESOURCE_KVD_LINEAR,
4208 p_linear_size);
4209 if (err)
4210 *p_linear_size = profile->kvd_linear_size;
4211
4212 err = devlink_resource_size_get(devlink,
4213 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
4214 p_double_size);
4215 if (err) {
4216 double_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
4217 *p_linear_size;
4218 double_size *= profile->kvd_hash_double_parts;
4219 double_size /= profile->kvd_hash_double_parts +
4220 profile->kvd_hash_single_parts;
4221 *p_double_size = rounddown(double_size,
4222 profile->kvd_hash_granularity);
4223 }
4224
4225 err = devlink_resource_size_get(devlink,
4226 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
4227 p_single_size);
4228 if (err)
4229 *p_single_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
4230 *p_double_size - *p_linear_size;
4231
4232 /* Check results are legal. */
4233 if (*p_single_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||
4234 *p_double_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE) ||
4235 MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) < *p_linear_size)
4236 return -EIO;
4237
4238 return 0;
4239}
4240
3994static struct mlxsw_driver mlxsw_sp_driver = { 4241static struct mlxsw_driver mlxsw_sp_driver = {
3995 .kind = mlxsw_sp_driver_name, 4242 .kind = mlxsw_sp_driver_name,
3996 .priv_size = sizeof(struct mlxsw_sp), 4243 .priv_size = sizeof(struct mlxsw_sp),
@@ -4010,6 +4257,8 @@ static struct mlxsw_driver mlxsw_sp_driver = {
4010 .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 4257 .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
4011 .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 4258 .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
4012 .txhdr_construct = mlxsw_sp_txhdr_construct, 4259 .txhdr_construct = mlxsw_sp_txhdr_construct,
4260 .resources_register = mlxsw_sp_resources_register,
4261 .kvd_sizes_get = mlxsw_sp_kvd_sizes_get,
4013 .txhdr_len = MLXSW_TXHDR_LEN, 4262 .txhdr_len = MLXSW_TXHDR_LEN,
4014 .profile = &mlxsw_sp_config_profile, 4263 .profile = &mlxsw_sp_config_profile,
4015}; 4264};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 16f8fbda0891..237cad373dbe 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -66,6 +66,18 @@
66#define MLXSW_SP_KVD_LINEAR_SIZE 98304 /* entries */ 66#define MLXSW_SP_KVD_LINEAR_SIZE 98304 /* entries */
67#define MLXSW_SP_KVD_GRANULARITY 128 67#define MLXSW_SP_KVD_GRANULARITY 128
68 68
69#define MLXSW_SP_RESOURCE_NAME_KVD "kvd"
70#define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR "linear"
71#define MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE "hash_single"
72#define MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE "hash_double"
73
74enum mlxsw_sp_resource_id {
75 MLXSW_SP_RESOURCE_KVD,
76 MLXSW_SP_RESOURCE_KVD_LINEAR,
77 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
78 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
79};
80
69struct mlxsw_sp_port; 81struct mlxsw_sp_port;
70struct mlxsw_sp_rif; 82struct mlxsw_sp_rif;
71 83
@@ -436,6 +448,7 @@ void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
436int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp, 448int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp,
437 unsigned int entry_count, 449 unsigned int entry_count,
438 unsigned int *p_alloc_size); 450 unsigned int *p_alloc_size);
451u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp);
439 452
440struct mlxsw_sp_acl_rule_info { 453struct mlxsw_sp_acl_rule_info {
441 unsigned int priority; 454 unsigned int priority;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
index 96fdba78acab..f56fa18d6b26 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
@@ -771,14 +771,33 @@ static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
771 .size_get = mlxsw_sp_dpipe_table_host4_size_get, 771 .size_get = mlxsw_sp_dpipe_table_host4_size_get,
772}; 772};
773 773
774#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
775
774static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp) 776static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
775{ 777{
776 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 778 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
779 int err;
777 780
778 return devlink_dpipe_table_register(devlink, 781 err = devlink_dpipe_table_register(devlink,
779 MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 782 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
780 &mlxsw_sp_host4_ops, 783 &mlxsw_sp_host4_ops,
781 mlxsw_sp, false); 784 mlxsw_sp, false);
785 if (err)
786 return err;
787
788 err = devlink_dpipe_table_resource_set(devlink,
789 MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
790 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
791 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
792 if (err)
793 goto err_resource_set;
794
795 return 0;
796
797err_resource_set:
798 devlink_dpipe_table_unregister(devlink,
799 MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
800 return err;
782} 801}
783 802
784static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp) 803static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
@@ -829,14 +848,33 @@ static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
829 .size_get = mlxsw_sp_dpipe_table_host6_size_get, 848 .size_get = mlxsw_sp_dpipe_table_host6_size_get,
830}; 849};
831 850
851#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
852
832static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp) 853static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
833{ 854{
834 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 855 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
856 int err;
835 857
836 return devlink_dpipe_table_register(devlink, 858 err = devlink_dpipe_table_register(devlink,
837 MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 859 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
838 &mlxsw_sp_host6_ops, 860 &mlxsw_sp_host6_ops,
839 mlxsw_sp, false); 861 mlxsw_sp, false);
862 if (err)
863 return err;
864
865 err = devlink_dpipe_table_resource_set(devlink,
866 MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
867 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
868 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
869 if (err)
870 goto err_resource_set;
871
872 return 0;
873
874err_resource_set:
875 devlink_dpipe_table_unregister(devlink,
876 MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
877 return err;
840} 878}
841 879
842static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp) 880static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
@@ -1213,14 +1251,33 @@ static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1213 .size_get = mlxsw_sp_dpipe_table_adj_size_get, 1251 .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1214}; 1252};
1215 1253
1254#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1255
1216static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp) 1256static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1217{ 1257{
1218 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1258 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1259 int err;
1219 1260
1220 return devlink_dpipe_table_register(devlink, 1261 err = devlink_dpipe_table_register(devlink,
1221 MLXSW_SP_DPIPE_TABLE_NAME_ADJ, 1262 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1222 &mlxsw_sp_dpipe_table_adj_ops, 1263 &mlxsw_sp_dpipe_table_adj_ops,
1223 mlxsw_sp, false); 1264 mlxsw_sp, false);
1265 if (err)
1266 return err;
1267
1268 err = devlink_dpipe_table_resource_set(devlink,
1269 MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1270 MLXSW_SP_RESOURCE_KVD_LINEAR,
1271 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1272 if (err)
1273 goto err_resource_set;
1274
1275 return 0;
1276
1277err_resource_set:
1278 devlink_dpipe_table_unregister(devlink,
1279 MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1280 return err;
1224} 1281}
1225 1282
1226static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp) 1283static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
index 310c38247b5c..cfacc176a1bd 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
@@ -286,6 +286,32 @@ static void mlxsw_sp_kvdl_parts_fini(struct mlxsw_sp *mlxsw_sp)
286 mlxsw_sp_kvdl_part_fini(mlxsw_sp, i); 286 mlxsw_sp_kvdl_part_fini(mlxsw_sp, i);
287} 287}
288 288
289u64 mlxsw_sp_kvdl_part_occ(struct mlxsw_sp_kvdl_part *part)
290{
291 unsigned int nr_entries;
292 int bit = -1;
293 u64 occ = 0;
294
295 nr_entries = (part->info->end_index -
296 part->info->start_index + 1) /
297 part->info->alloc_size;
298 while ((bit = find_next_bit(part->usage, nr_entries, bit + 1))
299 < nr_entries)
300 occ += part->info->alloc_size;
301 return occ;
302}
303
304u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp)
305{
306 struct mlxsw_sp_kvdl_part *part;
307 u64 occ = 0;
308
309 list_for_each_entry(part, &mlxsw_sp->kvdl->parts_list, list)
310 occ += mlxsw_sp_kvdl_part_occ(part);
311
312 return occ;
313}
314
289int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp) 315int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
290{ 316{
291 struct mlxsw_sp_kvdl *kvdl; 317 struct mlxsw_sp_kvdl *kvdl;
diff --git a/include/net/devlink.h b/include/net/devlink.h
index b9654e133599..6545b03e97f7 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -26,10 +26,12 @@ struct devlink {
26 struct list_head port_list; 26 struct list_head port_list;
27 struct list_head sb_list; 27 struct list_head sb_list;
28 struct list_head dpipe_table_list; 28 struct list_head dpipe_table_list;
29 struct list_head resource_list;
29 struct devlink_dpipe_headers *dpipe_headers; 30 struct devlink_dpipe_headers *dpipe_headers;
30 const struct devlink_ops *ops; 31 const struct devlink_ops *ops;
31 struct device *dev; 32 struct device *dev;
32 possible_net_t _net; 33 possible_net_t _net;
34 struct mutex lock;
33 char priv[0] __aligned(NETDEV_ALIGN); 35 char priv[0] __aligned(NETDEV_ALIGN);
34}; 36};
35 37
@@ -181,6 +183,9 @@ struct devlink_dpipe_table_ops;
181 * @counters_enabled: indicates if counters are active 183 * @counters_enabled: indicates if counters are active
182 * @counter_control_extern: indicates if counter control is in dpipe or 184 * @counter_control_extern: indicates if counter control is in dpipe or
183 * external tool 185 * external tool
186 * @resource_valid: Indicate that the resource id is valid
187 * @resource_id: relative resource this table is related to
188 * @resource_units: number of resource's unit consumed per table's entry
184 * @table_ops: table operations 189 * @table_ops: table operations
185 * @rcu: rcu 190 * @rcu: rcu
186 */ 191 */
@@ -190,6 +195,9 @@ struct devlink_dpipe_table {
190 const char *name; 195 const char *name;
191 bool counters_enabled; 196 bool counters_enabled;
192 bool counter_control_extern; 197 bool counter_control_extern;
198 bool resource_valid;
199 u64 resource_id;
200 u64 resource_units;
193 struct devlink_dpipe_table_ops *table_ops; 201 struct devlink_dpipe_table_ops *table_ops;
194 struct rcu_head rcu; 202 struct rcu_head rcu;
195}; 203};
@@ -223,7 +231,63 @@ struct devlink_dpipe_headers {
223 unsigned int headers_count; 231 unsigned int headers_count;
224}; 232};
225 233
234/**
235 * struct devlink_resource_ops - resource ops
236 * @occ_get: get the occupied size
237 * @size_validate: validate the size of the resource before update, reload
238 * is needed for changes to take place
239 */
240struct devlink_resource_ops {
241 u64 (*occ_get)(struct devlink *devlink);
242 int (*size_validate)(struct devlink *devlink, u64 size,
243 struct netlink_ext_ack *extack);
244};
245
246/**
247 * struct devlink_resource_size_params - resource's size parameters
248 * @size_min: minimum size which can be set
249 * @size_max: maximum size which can be set
250 * @size_granularity: size granularity
251 * @size_unit: resource's basic unit
252 */
253struct devlink_resource_size_params {
254 u64 size_min;
255 u64 size_max;
256 u64 size_granularity;
257 enum devlink_resource_unit unit;
258};
259
260/**
261 * struct devlink_resource - devlink resource
262 * @name: name of the resource
263 * @id: id, per devlink instance
264 * @size: size of the resource
265 * @size_new: updated size of the resource, reload is needed
266 * @size_valid: valid in case the total size of the resource is valid
267 * including its children
268 * @parent: parent resource
269 * @size_params: size parameters
270 * @list: parent list
271 * @resource_list: list of child resources
272 * @resource_ops: resource ops
273 */
274struct devlink_resource {
275 const char *name;
276 u64 id;
277 u64 size;
278 u64 size_new;
279 bool size_valid;
280 struct devlink_resource *parent;
281 struct devlink_resource_size_params *size_params;
282 struct list_head list;
283 struct list_head resource_list;
284 const struct devlink_resource_ops *resource_ops;
285};
286
287#define DEVLINK_RESOURCE_ID_PARENT_TOP 0
288
226struct devlink_ops { 289struct devlink_ops {
290 int (*reload)(struct devlink *devlink);
227 int (*port_type_set)(struct devlink_port *devlink_port, 291 int (*port_type_set)(struct devlink_port *devlink_port,
228 enum devlink_port_type port_type); 292 enum devlink_port_type port_type);
229 int (*port_split)(struct devlink *devlink, unsigned int port_index, 293 int (*port_split)(struct devlink *devlink, unsigned int port_index,
@@ -332,6 +396,23 @@ extern struct devlink_dpipe_header devlink_dpipe_header_ethernet;
332extern struct devlink_dpipe_header devlink_dpipe_header_ipv4; 396extern struct devlink_dpipe_header devlink_dpipe_header_ipv4;
333extern struct devlink_dpipe_header devlink_dpipe_header_ipv6; 397extern struct devlink_dpipe_header devlink_dpipe_header_ipv6;
334 398
399int devlink_resource_register(struct devlink *devlink,
400 const char *resource_name,
401 bool top_hierarchy,
402 u64 resource_size,
403 u64 resource_id,
404 u64 parent_resource_id,
405 struct devlink_resource_size_params *size_params,
406 const struct devlink_resource_ops *resource_ops);
407void devlink_resources_unregister(struct devlink *devlink,
408 struct devlink_resource *resource);
409int devlink_resource_size_get(struct devlink *devlink,
410 u64 resource_id,
411 u64 *p_resource_size);
412int devlink_dpipe_table_resource_set(struct devlink *devlink,
413 const char *table_name, u64 resource_id,
414 u64 resource_units);
415
335#else 416#else
336 417
337static inline struct devlink *devlink_alloc(const struct devlink_ops *ops, 418static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
@@ -468,6 +549,40 @@ devlink_dpipe_match_put(struct sk_buff *skb,
468 return 0; 549 return 0;
469} 550}
470 551
552static inline int
553devlink_resource_register(struct devlink *devlink,
554 const char *resource_name,
555 bool top_hierarchy,
556 u64 resource_size,
557 u64 resource_id,
558 u64 parent_resource_id,
559 struct devlink_resource_size_params *size_params,
560 const struct devlink_resource_ops *resource_ops)
561{
562 return 0;
563}
564
565static inline void
566devlink_resources_unregister(struct devlink *devlink,
567 struct devlink_resource *resource)
568{
569}
570
571static inline int
572devlink_resource_size_get(struct devlink *devlink, u64 resource_id,
573 u64 *p_resource_size)
574{
575 return -EOPNOTSUPP;
576}
577
578static inline int
579devlink_dpipe_table_resource_set(struct devlink *devlink,
580 const char *table_name, u64 resource_id,
581 u64 resource_units)
582{
583 return -EOPNOTSUPP;
584}
585
471#endif 586#endif
472 587
473#endif /* _NET_DEVLINK_H_ */ 588#endif /* _NET_DEVLINK_H_ */
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 6665df69e26a..1df65a4c2044 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -70,6 +70,13 @@ enum devlink_command {
70 DEVLINK_CMD_DPIPE_ENTRIES_GET, 70 DEVLINK_CMD_DPIPE_ENTRIES_GET,
71 DEVLINK_CMD_DPIPE_HEADERS_GET, 71 DEVLINK_CMD_DPIPE_HEADERS_GET,
72 DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, 72 DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
73 DEVLINK_CMD_RESOURCE_SET,
74 DEVLINK_CMD_RESOURCE_DUMP,
75
76 /* Hot driver reload, makes configuration changes take place. The
77 * devlink instance is not released during the process.
78 */
79 DEVLINK_CMD_RELOAD,
73 80
74 /* add new commands above here */ 81 /* add new commands above here */
75 __DEVLINK_CMD_MAX, 82 __DEVLINK_CMD_MAX,
@@ -202,6 +209,20 @@ enum devlink_attr {
202 DEVLINK_ATTR_PAD, 209 DEVLINK_ATTR_PAD,
203 210
204 DEVLINK_ATTR_ESWITCH_ENCAP_MODE, /* u8 */ 211 DEVLINK_ATTR_ESWITCH_ENCAP_MODE, /* u8 */
212 DEVLINK_ATTR_RESOURCE_LIST, /* nested */
213 DEVLINK_ATTR_RESOURCE, /* nested */
214 DEVLINK_ATTR_RESOURCE_NAME, /* string */
215 DEVLINK_ATTR_RESOURCE_ID, /* u64 */
216 DEVLINK_ATTR_RESOURCE_SIZE, /* u64 */
217 DEVLINK_ATTR_RESOURCE_SIZE_NEW, /* u64 */
218 DEVLINK_ATTR_RESOURCE_SIZE_VALID, /* u8 */
219 DEVLINK_ATTR_RESOURCE_SIZE_MIN, /* u64 */
220 DEVLINK_ATTR_RESOURCE_SIZE_MAX, /* u64 */
221 DEVLINK_ATTR_RESOURCE_SIZE_GRAN, /* u64 */
222 DEVLINK_ATTR_RESOURCE_UNIT, /* u8 */
223 DEVLINK_ATTR_RESOURCE_OCC, /* u64 */
224 DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, /* u64 */
225 DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,/* u64 */
205 226
206 /* add new attributes above here, update the policy in devlink.c */ 227 /* add new attributes above here, update the policy in devlink.c */
207 228
@@ -245,4 +266,8 @@ enum devlink_dpipe_header_id {
245 DEVLINK_DPIPE_HEADER_IPV6, 266 DEVLINK_DPIPE_HEADER_IPV6,
246}; 267};
247 268
269enum devlink_resource_unit {
270 DEVLINK_RESOURCE_UNIT_ENTRY,
271};
272
248#endif /* _UAPI_LINUX_DEVLINK_H_ */ 273#endif /* _UAPI_LINUX_DEVLINK_H_ */
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 7d430c1d9c3e..dd7d6dd07bfb 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -92,12 +92,6 @@ static LIST_HEAD(devlink_list);
92 */ 92 */
93static DEFINE_MUTEX(devlink_mutex); 93static DEFINE_MUTEX(devlink_mutex);
94 94
95/* devlink_port_mutex
96 *
97 * Shared lock to guard lists of ports in all devlink devices.
98 */
99static DEFINE_MUTEX(devlink_port_mutex);
100
101static struct net *devlink_net(const struct devlink *devlink) 95static struct net *devlink_net(const struct devlink *devlink)
102{ 96{
103 return read_pnet(&devlink->_net); 97 return read_pnet(&devlink->_net);
@@ -335,15 +329,18 @@ devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
335#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) 329#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
336#define DEVLINK_NL_FLAG_NEED_PORT BIT(1) 330#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
337#define DEVLINK_NL_FLAG_NEED_SB BIT(2) 331#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
338#define DEVLINK_NL_FLAG_LOCK_PORTS BIT(3) 332
339 /* port is not needed but we need to ensure they don't 333/* The per devlink instance lock is taken by default in the pre-doit
340 * change in the middle of command 334 * operation, yet several commands do not require this. The global
341 */ 335 * devlink lock is taken and protects from disruption by user-calls.
336 */
337#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
342 338
343static int devlink_nl_pre_doit(const struct genl_ops *ops, 339static int devlink_nl_pre_doit(const struct genl_ops *ops,
344 struct sk_buff *skb, struct genl_info *info) 340 struct sk_buff *skb, struct genl_info *info)
345{ 341{
346 struct devlink *devlink; 342 struct devlink *devlink;
343 int err;
347 344
348 mutex_lock(&devlink_mutex); 345 mutex_lock(&devlink_mutex);
349 devlink = devlink_get_from_info(info); 346 devlink = devlink_get_from_info(info);
@@ -351,44 +348,47 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
351 mutex_unlock(&devlink_mutex); 348 mutex_unlock(&devlink_mutex);
352 return PTR_ERR(devlink); 349 return PTR_ERR(devlink);
353 } 350 }
351 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
352 mutex_lock(&devlink->lock);
354 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) { 353 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
355 info->user_ptr[0] = devlink; 354 info->user_ptr[0] = devlink;
356 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) { 355 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
357 struct devlink_port *devlink_port; 356 struct devlink_port *devlink_port;
358 357
359 mutex_lock(&devlink_port_mutex);
360 devlink_port = devlink_port_get_from_info(devlink, info); 358 devlink_port = devlink_port_get_from_info(devlink, info);
361 if (IS_ERR(devlink_port)) { 359 if (IS_ERR(devlink_port)) {
362 mutex_unlock(&devlink_port_mutex); 360 err = PTR_ERR(devlink_port);
363 mutex_unlock(&devlink_mutex); 361 goto unlock;
364 return PTR_ERR(devlink_port);
365 } 362 }
366 info->user_ptr[0] = devlink_port; 363 info->user_ptr[0] = devlink_port;
367 } 364 }
368 if (ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) {
369 mutex_lock(&devlink_port_mutex);
370 }
371 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) { 365 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
372 struct devlink_sb *devlink_sb; 366 struct devlink_sb *devlink_sb;
373 367
374 devlink_sb = devlink_sb_get_from_info(devlink, info); 368 devlink_sb = devlink_sb_get_from_info(devlink, info);
375 if (IS_ERR(devlink_sb)) { 369 if (IS_ERR(devlink_sb)) {
376 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) 370 err = PTR_ERR(devlink_sb);
377 mutex_unlock(&devlink_port_mutex); 371 goto unlock;
378 mutex_unlock(&devlink_mutex);
379 return PTR_ERR(devlink_sb);
380 } 372 }
381 info->user_ptr[1] = devlink_sb; 373 info->user_ptr[1] = devlink_sb;
382 } 374 }
383 return 0; 375 return 0;
376
377unlock:
378 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
379 mutex_unlock(&devlink->lock);
380 mutex_unlock(&devlink_mutex);
381 return err;
384} 382}
385 383
386static void devlink_nl_post_doit(const struct genl_ops *ops, 384static void devlink_nl_post_doit(const struct genl_ops *ops,
387 struct sk_buff *skb, struct genl_info *info) 385 struct sk_buff *skb, struct genl_info *info)
388{ 386{
389 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT || 387 struct devlink *devlink;
390 ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) 388
391 mutex_unlock(&devlink_port_mutex); 389 devlink = devlink_get_from_info(info);
390 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
391 mutex_unlock(&devlink->lock);
392 mutex_unlock(&devlink_mutex); 392 mutex_unlock(&devlink_mutex);
393} 393}
394 394
@@ -614,10 +614,10 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
614 int err; 614 int err;
615 615
616 mutex_lock(&devlink_mutex); 616 mutex_lock(&devlink_mutex);
617 mutex_lock(&devlink_port_mutex);
618 list_for_each_entry(devlink, &devlink_list, list) { 617 list_for_each_entry(devlink, &devlink_list, list) {
619 if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 618 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
620 continue; 619 continue;
620 mutex_lock(&devlink->lock);
621 list_for_each_entry(devlink_port, &devlink->port_list, list) { 621 list_for_each_entry(devlink_port, &devlink->port_list, list) {
622 if (idx < start) { 622 if (idx < start) {
623 idx++; 623 idx++;
@@ -628,13 +628,15 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
628 NETLINK_CB(cb->skb).portid, 628 NETLINK_CB(cb->skb).portid,
629 cb->nlh->nlmsg_seq, 629 cb->nlh->nlmsg_seq,
630 NLM_F_MULTI); 630 NLM_F_MULTI);
631 if (err) 631 if (err) {
632 mutex_unlock(&devlink->lock);
632 goto out; 633 goto out;
634 }
633 idx++; 635 idx++;
634 } 636 }
637 mutex_unlock(&devlink->lock);
635 } 638 }
636out: 639out:
637 mutex_unlock(&devlink_port_mutex);
638 mutex_unlock(&devlink_mutex); 640 mutex_unlock(&devlink_mutex);
639 641
640 cb->args[0] = idx; 642 cb->args[0] = idx;
@@ -801,6 +803,7 @@ static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
801 list_for_each_entry(devlink, &devlink_list, list) { 803 list_for_each_entry(devlink, &devlink_list, list) {
802 if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 804 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
803 continue; 805 continue;
806 mutex_lock(&devlink->lock);
804 list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 807 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
805 if (idx < start) { 808 if (idx < start) {
806 idx++; 809 idx++;
@@ -811,10 +814,13 @@ static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
811 NETLINK_CB(cb->skb).portid, 814 NETLINK_CB(cb->skb).portid,
812 cb->nlh->nlmsg_seq, 815 cb->nlh->nlmsg_seq,
813 NLM_F_MULTI); 816 NLM_F_MULTI);
814 if (err) 817 if (err) {
818 mutex_unlock(&devlink->lock);
815 goto out; 819 goto out;
820 }
816 idx++; 821 idx++;
817 } 822 }
823 mutex_unlock(&devlink->lock);
818 } 824 }
819out: 825out:
820 mutex_unlock(&devlink_mutex); 826 mutex_unlock(&devlink_mutex);
@@ -935,14 +941,18 @@ static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
935 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || 941 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
936 !devlink->ops || !devlink->ops->sb_pool_get) 942 !devlink->ops || !devlink->ops->sb_pool_get)
937 continue; 943 continue;
944 mutex_lock(&devlink->lock);
938 list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 945 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
939 err = __sb_pool_get_dumpit(msg, start, &idx, devlink, 946 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
940 devlink_sb, 947 devlink_sb,
941 NETLINK_CB(cb->skb).portid, 948 NETLINK_CB(cb->skb).portid,
942 cb->nlh->nlmsg_seq); 949 cb->nlh->nlmsg_seq);
943 if (err && err != -EOPNOTSUPP) 950 if (err && err != -EOPNOTSUPP) {
951 mutex_unlock(&devlink->lock);
944 goto out; 952 goto out;
953 }
945 } 954 }
955 mutex_unlock(&devlink->lock);
946 } 956 }
947out: 957out:
948 mutex_unlock(&devlink_mutex); 958 mutex_unlock(&devlink_mutex);
@@ -1123,22 +1133,24 @@ static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1123 int err; 1133 int err;
1124 1134
1125 mutex_lock(&devlink_mutex); 1135 mutex_lock(&devlink_mutex);
1126 mutex_lock(&devlink_port_mutex);
1127 list_for_each_entry(devlink, &devlink_list, list) { 1136 list_for_each_entry(devlink, &devlink_list, list) {
1128 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || 1137 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1129 !devlink->ops || !devlink->ops->sb_port_pool_get) 1138 !devlink->ops || !devlink->ops->sb_port_pool_get)
1130 continue; 1139 continue;
1140 mutex_lock(&devlink->lock);
1131 list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 1141 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1132 err = __sb_port_pool_get_dumpit(msg, start, &idx, 1142 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1133 devlink, devlink_sb, 1143 devlink, devlink_sb,
1134 NETLINK_CB(cb->skb).portid, 1144 NETLINK_CB(cb->skb).portid,
1135 cb->nlh->nlmsg_seq); 1145 cb->nlh->nlmsg_seq);
1136 if (err && err != -EOPNOTSUPP) 1146 if (err && err != -EOPNOTSUPP) {
1147 mutex_unlock(&devlink->lock);
1137 goto out; 1148 goto out;
1149 }
1138 } 1150 }
1151 mutex_unlock(&devlink->lock);
1139 } 1152 }
1140out: 1153out:
1141 mutex_unlock(&devlink_port_mutex);
1142 mutex_unlock(&devlink_mutex); 1154 mutex_unlock(&devlink_mutex);
1143 1155
1144 cb->args[0] = idx; 1156 cb->args[0] = idx;
@@ -1347,23 +1359,26 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1347 int err; 1359 int err;
1348 1360
1349 mutex_lock(&devlink_mutex); 1361 mutex_lock(&devlink_mutex);
1350 mutex_lock(&devlink_port_mutex);
1351 list_for_each_entry(devlink, &devlink_list, list) { 1362 list_for_each_entry(devlink, &devlink_list, list) {
1352 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || 1363 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
1353 !devlink->ops || !devlink->ops->sb_tc_pool_bind_get) 1364 !devlink->ops || !devlink->ops->sb_tc_pool_bind_get)
1354 continue; 1365 continue;
1366
1367 mutex_lock(&devlink->lock);
1355 list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 1368 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1356 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx, 1369 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1357 devlink, 1370 devlink,
1358 devlink_sb, 1371 devlink_sb,
1359 NETLINK_CB(cb->skb).portid, 1372 NETLINK_CB(cb->skb).portid,
1360 cb->nlh->nlmsg_seq); 1373 cb->nlh->nlmsg_seq);
1361 if (err && err != -EOPNOTSUPP) 1374 if (err && err != -EOPNOTSUPP) {
1375 mutex_unlock(&devlink->lock);
1362 goto out; 1376 goto out;
1377 }
1363 } 1378 }
1379 mutex_unlock(&devlink->lock);
1364 } 1380 }
1365out: 1381out:
1366 mutex_unlock(&devlink_port_mutex);
1367 mutex_unlock(&devlink_mutex); 1382 mutex_unlock(&devlink_mutex);
1368 1383
1369 cb->args[0] = idx; 1384 cb->args[0] = idx;
@@ -1679,6 +1694,12 @@ static int devlink_dpipe_table_put(struct sk_buff *skb,
1679 table->counters_enabled)) 1694 table->counters_enabled))
1680 goto nla_put_failure; 1695 goto nla_put_failure;
1681 1696
1697 if (table->resource_valid) {
1698 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1699 table->resource_id, DEVLINK_ATTR_PAD);
1700 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1701 table->resource_units, DEVLINK_ATTR_PAD);
1702 }
1682 if (devlink_dpipe_matches_put(table, skb)) 1703 if (devlink_dpipe_matches_put(table, skb))
1683 goto nla_put_failure; 1704 goto nla_put_failure;
1684 1705
@@ -2273,6 +2294,272 @@ static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2273 counters_enable); 2294 counters_enable);
2274} 2295}
2275 2296
2297struct devlink_resource *
2298devlink_resource_find(struct devlink *devlink,
2299 struct devlink_resource *resource, u64 resource_id)
2300{
2301 struct list_head *resource_list;
2302
2303 if (resource)
2304 resource_list = &resource->resource_list;
2305 else
2306 resource_list = &devlink->resource_list;
2307
2308 list_for_each_entry(resource, resource_list, list) {
2309 struct devlink_resource *child_resource;
2310
2311 if (resource->id == resource_id)
2312 return resource;
2313
2314 child_resource = devlink_resource_find(devlink, resource,
2315 resource_id);
2316 if (child_resource)
2317 return child_resource;
2318 }
2319 return NULL;
2320}
2321
2322void devlink_resource_validate_children(struct devlink_resource *resource)
2323{
2324 struct devlink_resource *child_resource;
2325 bool size_valid = true;
2326 u64 parts_size = 0;
2327
2328 if (list_empty(&resource->resource_list))
2329 goto out;
2330
2331 list_for_each_entry(child_resource, &resource->resource_list, list)
2332 parts_size += child_resource->size_new;
2333
2334 if (parts_size > resource->size)
2335 size_valid = false;
2336out:
2337 resource->size_valid = size_valid;
2338}
2339
2340static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2341 struct genl_info *info)
2342{
2343 struct devlink *devlink = info->user_ptr[0];
2344 struct devlink_resource *resource;
2345 u64 resource_id;
2346 u64 size;
2347 int err;
2348
2349 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2350 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2351 return -EINVAL;
2352 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2353
2354 resource = devlink_resource_find(devlink, NULL, resource_id);
2355 if (!resource)
2356 return -EINVAL;
2357
2358 if (!resource->resource_ops->size_validate)
2359 return -EINVAL;
2360
2361 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
2362 err = resource->resource_ops->size_validate(devlink, size,
2363 info->extack);
2364 if (err)
2365 return err;
2366
2367 resource->size_new = size;
2368 devlink_resource_validate_children(resource);
2369 if (resource->parent)
2370 devlink_resource_validate_children(resource->parent);
2371 return 0;
2372}
2373
2374static void
2375devlink_resource_size_params_put(struct devlink_resource *resource,
2376 struct sk_buff *skb)
2377{
2378 struct devlink_resource_size_params *size_params;
2379
2380 size_params = resource->size_params;
2381 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2382 size_params->size_granularity, DEVLINK_ATTR_PAD);
2383 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2384 size_params->size_max, DEVLINK_ATTR_PAD);
2385 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2386 size_params->size_min, DEVLINK_ATTR_PAD);
2387 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit);
2388}
2389
2390static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2391 struct devlink_resource *resource)
2392{
2393 struct devlink_resource *child_resource;
2394 struct nlattr *child_resource_attr;
2395 struct nlattr *resource_attr;
2396
2397 resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE);
2398 if (!resource_attr)
2399 return -EMSGSIZE;
2400
2401 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2402 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2403 DEVLINK_ATTR_PAD) ||
2404 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2405 DEVLINK_ATTR_PAD))
2406 goto nla_put_failure;
2407 if (resource->size != resource->size_new)
2408 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2409 resource->size_new, DEVLINK_ATTR_PAD);
2410 if (resource->resource_ops && resource->resource_ops->occ_get)
2411 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2412 resource->resource_ops->occ_get(devlink),
2413 DEVLINK_ATTR_PAD);
2414 devlink_resource_size_params_put(resource, skb);
2415 if (list_empty(&resource->resource_list))
2416 goto out;
2417
2418 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2419 resource->size_valid))
2420 goto nla_put_failure;
2421
2422 child_resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2423 if (!child_resource_attr)
2424 goto nla_put_failure;
2425
2426 list_for_each_entry(child_resource, &resource->resource_list, list) {
2427 if (devlink_resource_put(devlink, skb, child_resource))
2428 goto resource_put_failure;
2429 }
2430
2431 nla_nest_end(skb, child_resource_attr);
2432out:
2433 nla_nest_end(skb, resource_attr);
2434 return 0;
2435
2436resource_put_failure:
2437 nla_nest_cancel(skb, child_resource_attr);
2438nla_put_failure:
2439 nla_nest_cancel(skb, resource_attr);
2440 return -EMSGSIZE;
2441}
2442
2443static int devlink_resource_fill(struct genl_info *info,
2444 enum devlink_command cmd, int flags)
2445{
2446 struct devlink *devlink = info->user_ptr[0];
2447 struct devlink_resource *resource;
2448 struct nlattr *resources_attr;
2449 struct sk_buff *skb = NULL;
2450 struct nlmsghdr *nlh;
2451 bool incomplete;
2452 void *hdr;
2453 int i;
2454 int err;
2455
2456 resource = list_first_entry(&devlink->resource_list,
2457 struct devlink_resource, list);
2458start_again:
2459 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2460 if (err)
2461 return err;
2462
2463 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2464 &devlink_nl_family, NLM_F_MULTI, cmd);
2465 if (!hdr) {
2466 nlmsg_free(skb);
2467 return -EMSGSIZE;
2468 }
2469
2470 if (devlink_nl_put_handle(skb, devlink))
2471 goto nla_put_failure;
2472
2473 resources_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2474 if (!resources_attr)
2475 goto nla_put_failure;
2476
2477 incomplete = false;
2478 i = 0;
2479 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2480 err = devlink_resource_put(devlink, skb, resource);
2481 if (err) {
2482 if (!i)
2483 goto err_resource_put;
2484 incomplete = true;
2485 break;
2486 }
2487 i++;
2488 }
2489 nla_nest_end(skb, resources_attr);
2490 genlmsg_end(skb, hdr);
2491 if (incomplete)
2492 goto start_again;
2493send_done:
2494 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2495 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2496 if (!nlh) {
2497 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2498 if (err)
2499 goto err_skb_send_alloc;
2500 goto send_done;
2501 }
2502 return genlmsg_reply(skb, info);
2503
2504nla_put_failure:
2505 err = -EMSGSIZE;
2506err_resource_put:
2507err_skb_send_alloc:
2508 genlmsg_cancel(skb, hdr);
2509 nlmsg_free(skb);
2510 return err;
2511}
2512
2513static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2514 struct genl_info *info)
2515{
2516 struct devlink *devlink = info->user_ptr[0];
2517
2518 if (list_empty(&devlink->resource_list))
2519 return -EOPNOTSUPP;
2520
2521 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2522}
2523
2524static int
2525devlink_resources_validate(struct devlink *devlink,
2526 struct devlink_resource *resource,
2527 struct genl_info *info)
2528{
2529 struct list_head *resource_list;
2530 int err = 0;
2531
2532 if (resource)
2533 resource_list = &resource->resource_list;
2534 else
2535 resource_list = &devlink->resource_list;
2536
2537 list_for_each_entry(resource, resource_list, list) {
2538 if (!resource->size_valid)
2539 return -EINVAL;
2540 err = devlink_resources_validate(devlink, resource, info);
2541 if (err)
2542 return err;
2543 }
2544 return err;
2545}
2546
2547static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2548{
2549 struct devlink *devlink = info->user_ptr[0];
2550 int err;
2551
2552 if (!devlink->ops->reload)
2553 return -EOPNOTSUPP;
2554
2555 err = devlink_resources_validate(devlink, NULL, info);
2556 if (err) {
2557 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2558 return err;
2559 }
2560 return devlink->ops->reload(devlink);
2561}
2562
2276static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { 2563static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
2277 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, 2564 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
2278 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, 2565 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -2291,6 +2578,8 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
2291 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 }, 2578 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
2292 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING }, 2579 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
2293 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 }, 2580 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
2581 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
2582 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
2294}; 2583};
2295 2584
2296static const struct genl_ops devlink_nl_ops[] = { 2585static const struct genl_ops devlink_nl_ops[] = {
@@ -2322,14 +2611,16 @@ static const struct genl_ops devlink_nl_ops[] = {
2322 .doit = devlink_nl_cmd_port_split_doit, 2611 .doit = devlink_nl_cmd_port_split_doit,
2323 .policy = devlink_nl_policy, 2612 .policy = devlink_nl_policy,
2324 .flags = GENL_ADMIN_PERM, 2613 .flags = GENL_ADMIN_PERM,
2325 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, 2614 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2615 DEVLINK_NL_FLAG_NO_LOCK,
2326 }, 2616 },
2327 { 2617 {
2328 .cmd = DEVLINK_CMD_PORT_UNSPLIT, 2618 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
2329 .doit = devlink_nl_cmd_port_unsplit_doit, 2619 .doit = devlink_nl_cmd_port_unsplit_doit,
2330 .policy = devlink_nl_policy, 2620 .policy = devlink_nl_policy,
2331 .flags = GENL_ADMIN_PERM, 2621 .flags = GENL_ADMIN_PERM,
2332 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, 2622 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2623 DEVLINK_NL_FLAG_NO_LOCK,
2333 }, 2624 },
2334 { 2625 {
2335 .cmd = DEVLINK_CMD_SB_GET, 2626 .cmd = DEVLINK_CMD_SB_GET,
@@ -2397,8 +2688,7 @@ static const struct genl_ops devlink_nl_ops[] = {
2397 .policy = devlink_nl_policy, 2688 .policy = devlink_nl_policy,
2398 .flags = GENL_ADMIN_PERM, 2689 .flags = GENL_ADMIN_PERM,
2399 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | 2690 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2400 DEVLINK_NL_FLAG_NEED_SB | 2691 DEVLINK_NL_FLAG_NEED_SB,
2401 DEVLINK_NL_FLAG_LOCK_PORTS,
2402 }, 2692 },
2403 { 2693 {
2404 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR, 2694 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
@@ -2406,8 +2696,7 @@ static const struct genl_ops devlink_nl_ops[] = {
2406 .policy = devlink_nl_policy, 2696 .policy = devlink_nl_policy,
2407 .flags = GENL_ADMIN_PERM, 2697 .flags = GENL_ADMIN_PERM,
2408 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | 2698 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2409 DEVLINK_NL_FLAG_NEED_SB | 2699 DEVLINK_NL_FLAG_NEED_SB,
2410 DEVLINK_NL_FLAG_LOCK_PORTS,
2411 }, 2700 },
2412 { 2701 {
2413 .cmd = DEVLINK_CMD_ESWITCH_GET, 2702 .cmd = DEVLINK_CMD_ESWITCH_GET,
@@ -2451,6 +2740,28 @@ static const struct genl_ops devlink_nl_ops[] = {
2451 .flags = GENL_ADMIN_PERM, 2740 .flags = GENL_ADMIN_PERM,
2452 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, 2741 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
2453 }, 2742 },
2743 {
2744 .cmd = DEVLINK_CMD_RESOURCE_SET,
2745 .doit = devlink_nl_cmd_resource_set,
2746 .policy = devlink_nl_policy,
2747 .flags = GENL_ADMIN_PERM,
2748 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
2749 },
2750 {
2751 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
2752 .doit = devlink_nl_cmd_resource_dump,
2753 .policy = devlink_nl_policy,
2754 .flags = GENL_ADMIN_PERM,
2755 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
2756 },
2757 {
2758 .cmd = DEVLINK_CMD_RELOAD,
2759 .doit = devlink_nl_cmd_reload,
2760 .policy = devlink_nl_policy,
2761 .flags = GENL_ADMIN_PERM,
2762 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2763 DEVLINK_NL_FLAG_NO_LOCK,
2764 },
2454}; 2765};
2455 2766
2456static struct genl_family devlink_nl_family __ro_after_init = { 2767static struct genl_family devlink_nl_family __ro_after_init = {
@@ -2488,6 +2799,8 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
2488 INIT_LIST_HEAD(&devlink->port_list); 2799 INIT_LIST_HEAD(&devlink->port_list);
2489 INIT_LIST_HEAD(&devlink->sb_list); 2800 INIT_LIST_HEAD(&devlink->sb_list);
2490 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list); 2801 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
2802 INIT_LIST_HEAD(&devlink->resource_list);
2803 mutex_init(&devlink->lock);
2491 return devlink; 2804 return devlink;
2492} 2805}
2493EXPORT_SYMBOL_GPL(devlink_alloc); 2806EXPORT_SYMBOL_GPL(devlink_alloc);
@@ -2550,16 +2863,16 @@ int devlink_port_register(struct devlink *devlink,
2550 struct devlink_port *devlink_port, 2863 struct devlink_port *devlink_port,
2551 unsigned int port_index) 2864 unsigned int port_index)
2552{ 2865{
2553 mutex_lock(&devlink_port_mutex); 2866 mutex_lock(&devlink->lock);
2554 if (devlink_port_index_exists(devlink, port_index)) { 2867 if (devlink_port_index_exists(devlink, port_index)) {
2555 mutex_unlock(&devlink_port_mutex); 2868 mutex_unlock(&devlink->lock);
2556 return -EEXIST; 2869 return -EEXIST;
2557 } 2870 }
2558 devlink_port->devlink = devlink; 2871 devlink_port->devlink = devlink;
2559 devlink_port->index = port_index; 2872 devlink_port->index = port_index;
2560 devlink_port->registered = true; 2873 devlink_port->registered = true;
2561 list_add_tail(&devlink_port->list, &devlink->port_list); 2874 list_add_tail(&devlink_port->list, &devlink->port_list);
2562 mutex_unlock(&devlink_port_mutex); 2875 mutex_unlock(&devlink->lock);
2563 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); 2876 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
2564 return 0; 2877 return 0;
2565} 2878}
@@ -2572,10 +2885,12 @@ EXPORT_SYMBOL_GPL(devlink_port_register);
2572 */ 2885 */
2573void devlink_port_unregister(struct devlink_port *devlink_port) 2886void devlink_port_unregister(struct devlink_port *devlink_port)
2574{ 2887{
2888 struct devlink *devlink = devlink_port->devlink;
2889
2575 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL); 2890 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
2576 mutex_lock(&devlink_port_mutex); 2891 mutex_lock(&devlink->lock);
2577 list_del(&devlink_port->list); 2892 list_del(&devlink_port->list);
2578 mutex_unlock(&devlink_port_mutex); 2893 mutex_unlock(&devlink->lock);
2579} 2894}
2580EXPORT_SYMBOL_GPL(devlink_port_unregister); 2895EXPORT_SYMBOL_GPL(devlink_port_unregister);
2581 2896
@@ -2651,7 +2966,7 @@ int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
2651 struct devlink_sb *devlink_sb; 2966 struct devlink_sb *devlink_sb;
2652 int err = 0; 2967 int err = 0;
2653 2968
2654 mutex_lock(&devlink_mutex); 2969 mutex_lock(&devlink->lock);
2655 if (devlink_sb_index_exists(devlink, sb_index)) { 2970 if (devlink_sb_index_exists(devlink, sb_index)) {
2656 err = -EEXIST; 2971 err = -EEXIST;
2657 goto unlock; 2972 goto unlock;
@@ -2670,7 +2985,7 @@ int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
2670 devlink_sb->egress_tc_count = egress_tc_count; 2985 devlink_sb->egress_tc_count = egress_tc_count;
2671 list_add_tail(&devlink_sb->list, &devlink->sb_list); 2986 list_add_tail(&devlink_sb->list, &devlink->sb_list);
2672unlock: 2987unlock:
2673 mutex_unlock(&devlink_mutex); 2988 mutex_unlock(&devlink->lock);
2674 return err; 2989 return err;
2675} 2990}
2676EXPORT_SYMBOL_GPL(devlink_sb_register); 2991EXPORT_SYMBOL_GPL(devlink_sb_register);
@@ -2679,11 +2994,11 @@ void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
2679{ 2994{
2680 struct devlink_sb *devlink_sb; 2995 struct devlink_sb *devlink_sb;
2681 2996
2682 mutex_lock(&devlink_mutex); 2997 mutex_lock(&devlink->lock);
2683 devlink_sb = devlink_sb_get_by_index(devlink, sb_index); 2998 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
2684 WARN_ON(!devlink_sb); 2999 WARN_ON(!devlink_sb);
2685 list_del(&devlink_sb->list); 3000 list_del(&devlink_sb->list);
2686 mutex_unlock(&devlink_mutex); 3001 mutex_unlock(&devlink->lock);
2687 kfree(devlink_sb); 3002 kfree(devlink_sb);
2688} 3003}
2689EXPORT_SYMBOL_GPL(devlink_sb_unregister); 3004EXPORT_SYMBOL_GPL(devlink_sb_unregister);
@@ -2699,9 +3014,9 @@ EXPORT_SYMBOL_GPL(devlink_sb_unregister);
2699int devlink_dpipe_headers_register(struct devlink *devlink, 3014int devlink_dpipe_headers_register(struct devlink *devlink,
2700 struct devlink_dpipe_headers *dpipe_headers) 3015 struct devlink_dpipe_headers *dpipe_headers)
2701{ 3016{
2702 mutex_lock(&devlink_mutex); 3017 mutex_lock(&devlink->lock);
2703 devlink->dpipe_headers = dpipe_headers; 3018 devlink->dpipe_headers = dpipe_headers;
2704 mutex_unlock(&devlink_mutex); 3019 mutex_unlock(&devlink->lock);
2705 return 0; 3020 return 0;
2706} 3021}
2707EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register); 3022EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
@@ -2715,9 +3030,9 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
2715 */ 3030 */
2716void devlink_dpipe_headers_unregister(struct devlink *devlink) 3031void devlink_dpipe_headers_unregister(struct devlink *devlink)
2717{ 3032{
2718 mutex_lock(&devlink_mutex); 3033 mutex_lock(&devlink->lock);
2719 devlink->dpipe_headers = NULL; 3034 devlink->dpipe_headers = NULL;
2720 mutex_unlock(&devlink_mutex); 3035 mutex_unlock(&devlink->lock);
2721} 3036}
2722EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister); 3037EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
2723 3038
@@ -2783,9 +3098,9 @@ int devlink_dpipe_table_register(struct devlink *devlink,
2783 table->priv = priv; 3098 table->priv = priv;
2784 table->counter_control_extern = counter_control_extern; 3099 table->counter_control_extern = counter_control_extern;
2785 3100
2786 mutex_lock(&devlink_mutex); 3101 mutex_lock(&devlink->lock);
2787 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list); 3102 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
2788 mutex_unlock(&devlink_mutex); 3103 mutex_unlock(&devlink->lock);
2789 return 0; 3104 return 0;
2790} 3105}
2791EXPORT_SYMBOL_GPL(devlink_dpipe_table_register); 3106EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
@@ -2801,20 +3116,181 @@ void devlink_dpipe_table_unregister(struct devlink *devlink,
2801{ 3116{
2802 struct devlink_dpipe_table *table; 3117 struct devlink_dpipe_table *table;
2803 3118
2804 mutex_lock(&devlink_mutex); 3119 mutex_lock(&devlink->lock);
2805 table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 3120 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2806 table_name); 3121 table_name);
2807 if (!table) 3122 if (!table)
2808 goto unlock; 3123 goto unlock;
2809 list_del_rcu(&table->list); 3124 list_del_rcu(&table->list);
2810 mutex_unlock(&devlink_mutex); 3125 mutex_unlock(&devlink->lock);
2811 kfree_rcu(table, rcu); 3126 kfree_rcu(table, rcu);
2812 return; 3127 return;
2813unlock: 3128unlock:
2814 mutex_unlock(&devlink_mutex); 3129 mutex_unlock(&devlink->lock);
2815} 3130}
2816EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister); 3131EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
2817 3132
3133/**
3134 * devlink_resource_register - devlink resource register
3135 *
3136 * @devlink: devlink
3137 * @resource_name: resource's name
3138 * @top_hierarchy: top hierarchy
3139 * @reload_required: reload is required for new configuration to
3140 * apply
3141 * @resource_size: resource's size
3142 * @resource_id: resource's id
3143 * @parent_reosurce_id: resource's parent id
3144 * @size params: size parameters
3145 * @resource_ops: resource ops
3146 */
3147int devlink_resource_register(struct devlink *devlink,
3148 const char *resource_name,
3149 bool top_hierarchy,
3150 u64 resource_size,
3151 u64 resource_id,
3152 u64 parent_resource_id,
3153 struct devlink_resource_size_params *size_params,
3154 const struct devlink_resource_ops *resource_ops)
3155{
3156 struct devlink_resource *resource;
3157 struct list_head *resource_list;
3158 int err = 0;
3159
3160 mutex_lock(&devlink->lock);
3161 resource = devlink_resource_find(devlink, NULL, resource_id);
3162 if (resource) {
3163 err = -EINVAL;
3164 goto out;
3165 }
3166
3167 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
3168 if (!resource) {
3169 err = -ENOMEM;
3170 goto out;
3171 }
3172
3173 if (top_hierarchy) {
3174 resource_list = &devlink->resource_list;
3175 } else {
3176 struct devlink_resource *parent_resource;
3177
3178 parent_resource = devlink_resource_find(devlink, NULL,
3179 parent_resource_id);
3180 if (parent_resource) {
3181 resource_list = &parent_resource->resource_list;
3182 resource->parent = parent_resource;
3183 } else {
3184 err = -EINVAL;
3185 goto out;
3186 }
3187 }
3188
3189 resource->name = resource_name;
3190 resource->size = resource_size;
3191 resource->size_new = resource_size;
3192 resource->id = resource_id;
3193 resource->resource_ops = resource_ops;
3194 resource->size_valid = true;
3195 resource->size_params = size_params;
3196 INIT_LIST_HEAD(&resource->resource_list);
3197 list_add_tail(&resource->list, resource_list);
3198out:
3199 mutex_unlock(&devlink->lock);
3200 return err;
3201}
3202EXPORT_SYMBOL_GPL(devlink_resource_register);
3203
3204/**
3205 * devlink_resources_unregister - free all resources
3206 *
3207 * @devlink: devlink
3208 * @resource: resource
3209 */
3210void devlink_resources_unregister(struct devlink *devlink,
3211 struct devlink_resource *resource)
3212{
3213 struct devlink_resource *tmp, *child_resource;
3214 struct list_head *resource_list;
3215
3216 if (resource)
3217 resource_list = &resource->resource_list;
3218 else
3219 resource_list = &devlink->resource_list;
3220
3221 if (!resource)
3222 mutex_lock(&devlink->lock);
3223
3224 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
3225 devlink_resources_unregister(devlink, child_resource);
3226 list_del(&child_resource->list);
3227 kfree(child_resource);
3228 }
3229
3230 if (!resource)
3231 mutex_unlock(&devlink->lock);
3232}
3233EXPORT_SYMBOL_GPL(devlink_resources_unregister);
3234
3235/**
3236 * devlink_resource_size_get - get and update size
3237 *
3238 * @devlink: devlink
3239 * @resource_id: the requested resource id
3240 * @p_resource_size: ptr to update
3241 */
3242int devlink_resource_size_get(struct devlink *devlink,
3243 u64 resource_id,
3244 u64 *p_resource_size)
3245{
3246 struct devlink_resource *resource;
3247 int err = 0;
3248
3249 mutex_lock(&devlink->lock);
3250 resource = devlink_resource_find(devlink, NULL, resource_id);
3251 if (!resource) {
3252 err = -EINVAL;
3253 goto out;
3254 }
3255 *p_resource_size = resource->size_new;
3256 resource->size = resource->size_new;
3257out:
3258 mutex_unlock(&devlink->lock);
3259 return err;
3260}
3261EXPORT_SYMBOL_GPL(devlink_resource_size_get);
3262
3263/**
3264 * devlink_dpipe_table_resource_set - set the resource id
3265 *
3266 * @devlink: devlink
3267 * @table_name: table name
3268 * @resource_id: resource id
3269 * @resource_units: number of resource's units consumed per table's entry
3270 */
3271int devlink_dpipe_table_resource_set(struct devlink *devlink,
3272 const char *table_name, u64 resource_id,
3273 u64 resource_units)
3274{
3275 struct devlink_dpipe_table *table;
3276 int err = 0;
3277
3278 mutex_lock(&devlink->lock);
3279 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
3280 table_name);
3281 if (!table) {
3282 err = -EINVAL;
3283 goto out;
3284 }
3285 table->resource_id = resource_id;
3286 table->resource_units = resource_units;
3287 table->resource_valid = true;
3288out:
3289 mutex_unlock(&devlink->lock);
3290 return err;
3291}
3292EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
3293
2818static int __init devlink_module_init(void) 3294static int __init devlink_module_init(void)
2819{ 3295{
2820 return genl_register_family(&devlink_nl_family); 3296 return genl_register_family(&devlink_nl_family);