diff options
author | David S. Miller <davem@davemloft.net> | 2018-02-20 13:39:02 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-20 13:39:02 -0500 |
commit | a38bbe7d57b1d4d86e90823dd85d7883ae23be1d (patch) | |
tree | a2946ea73c8b92a701f4ee93e8dc3cc6a829bd1c | |
parent | b99fe0e28fe0ba7d6e17e234e1150f1d9e197632 (diff) | |
parent | 7f47b19bd744c7945ad554fc00665fdbd13794bc (diff) |
Merge branch 'net-Expose-KVD-linear-parts-as-resources'
Jiri Pirko says:
====================
net: Expose KVD linear parts as resources
Arkadi says:
Expose the KVD linear partitions via the devlink resource interface. This
will give the user the ability to control the linear memory division.
---
v1->v2:
- patch1:
- fixed u64 division error reported by kbuildbot
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 87 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c | 187 | ||||
-rw-r--r-- | include/net/devlink.h | 4 | ||||
-rw-r--r-- | net/core/devlink.c | 32 |
5 files changed, 220 insertions, 97 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 5e8ea712caa2..bfde93910f82 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c | |||
@@ -3798,70 +3798,6 @@ static const struct mlxsw_config_profile mlxsw_sp_config_profile = { | |||
3798 | .resource_query_enable = 1, | 3798 | .resource_query_enable = 1, |
3799 | }; | 3799 | }; |
3800 | 3800 | ||
3801 | static bool | ||
3802 | mlxsw_sp_resource_kvd_granularity_validate(struct netlink_ext_ack *extack, | ||
3803 | u64 size) | ||
3804 | { | ||
3805 | const struct mlxsw_config_profile *profile; | ||
3806 | |||
3807 | profile = &mlxsw_sp_config_profile; | ||
3808 | if (size % profile->kvd_hash_granularity) { | ||
3809 | NL_SET_ERR_MSG_MOD(extack, "resource set with wrong granularity"); | ||
3810 | return false; | ||
3811 | } | ||
3812 | return true; | ||
3813 | } | ||
3814 | |||
3815 | static int | ||
3816 | mlxsw_sp_resource_kvd_size_validate(struct devlink *devlink, u64 size, | ||
3817 | struct netlink_ext_ack *extack) | ||
3818 | { | ||
3819 | NL_SET_ERR_MSG_MOD(extack, "kvd size cannot be changed"); | ||
3820 | return -EINVAL; | ||
3821 | } | ||
3822 | |||
3823 | static int | ||
3824 | mlxsw_sp_resource_kvd_linear_size_validate(struct devlink *devlink, u64 size, | ||
3825 | struct netlink_ext_ack *extack) | ||
3826 | { | ||
3827 | if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size)) | ||
3828 | return -EINVAL; | ||
3829 | |||
3830 | return 0; | ||
3831 | } | ||
3832 | |||
3833 | static int | ||
3834 | mlxsw_sp_resource_kvd_hash_single_size_validate(struct devlink *devlink, u64 size, | ||
3835 | struct netlink_ext_ack *extack) | ||
3836 | { | ||
3837 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | ||
3838 | |||
3839 | if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size)) | ||
3840 | return -EINVAL; | ||
3841 | |||
3842 | if (size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE)) { | ||
3843 | NL_SET_ERR_MSG_MOD(extack, "hash single size is smaller than minimum"); | ||
3844 | return -EINVAL; | ||
3845 | } | ||
3846 | return 0; | ||
3847 | } | ||
3848 | |||
3849 | static int | ||
3850 | mlxsw_sp_resource_kvd_hash_double_size_validate(struct devlink *devlink, u64 size, | ||
3851 | struct netlink_ext_ack *extack) | ||
3852 | { | ||
3853 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | ||
3854 | |||
3855 | if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size)) | ||
3856 | return -EINVAL; | ||
3857 | |||
3858 | if (size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE)) { | ||
3859 | NL_SET_ERR_MSG_MOD(extack, "hash double size is smaller than minimum"); | ||
3860 | return -EINVAL; | ||
3861 | } | ||
3862 | return 0; | ||
3863 | } | ||
3864 | |||
3865 | static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink) | 3801 | static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink) |
3866 | { | 3802 | { |
3867 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | 3803 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); |
@@ -3870,23 +3806,10 @@ static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink) | |||
3870 | return mlxsw_sp_kvdl_occ_get(mlxsw_sp); | 3806 | return mlxsw_sp_kvdl_occ_get(mlxsw_sp); |
3871 | } | 3807 | } |
3872 | 3808 | ||
3873 | static struct devlink_resource_ops mlxsw_sp_resource_kvd_ops = { | ||
3874 | .size_validate = mlxsw_sp_resource_kvd_size_validate, | ||
3875 | }; | ||
3876 | |||
3877 | static struct devlink_resource_ops mlxsw_sp_resource_kvd_linear_ops = { | 3809 | static struct devlink_resource_ops mlxsw_sp_resource_kvd_linear_ops = { |
3878 | .size_validate = mlxsw_sp_resource_kvd_linear_size_validate, | ||
3879 | .occ_get = mlxsw_sp_resource_kvd_linear_occ_get, | 3810 | .occ_get = mlxsw_sp_resource_kvd_linear_occ_get, |
3880 | }; | 3811 | }; |
3881 | 3812 | ||
3882 | static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_single_ops = { | ||
3883 | .size_validate = mlxsw_sp_resource_kvd_hash_single_size_validate, | ||
3884 | }; | ||
3885 | |||
3886 | static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = { | ||
3887 | .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate, | ||
3888 | }; | ||
3889 | |||
3890 | static struct devlink_resource_size_params mlxsw_sp_kvd_size_params; | 3813 | static struct devlink_resource_size_params mlxsw_sp_kvd_size_params; |
3891 | static struct devlink_resource_size_params mlxsw_sp_linear_size_params; | 3814 | static struct devlink_resource_size_params mlxsw_sp_linear_size_params; |
3892 | static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params; | 3815 | static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params; |
@@ -3948,7 +3871,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
3948 | MLXSW_SP_RESOURCE_KVD, | 3871 | MLXSW_SP_RESOURCE_KVD, |
3949 | DEVLINK_RESOURCE_ID_PARENT_TOP, | 3872 | DEVLINK_RESOURCE_ID_PARENT_TOP, |
3950 | &mlxsw_sp_kvd_size_params, | 3873 | &mlxsw_sp_kvd_size_params, |
3951 | &mlxsw_sp_resource_kvd_ops); | 3874 | NULL); |
3952 | if (err) | 3875 | if (err) |
3953 | return err; | 3876 | return err; |
3954 | 3877 | ||
@@ -3962,6 +3885,10 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
3962 | if (err) | 3885 | if (err) |
3963 | return err; | 3886 | return err; |
3964 | 3887 | ||
3888 | err = mlxsw_sp_kvdl_resources_register(devlink); | ||
3889 | if (err) | ||
3890 | return err; | ||
3891 | |||
3965 | double_size = kvd_size - linear_size; | 3892 | double_size = kvd_size - linear_size; |
3966 | double_size *= profile->kvd_hash_double_parts; | 3893 | double_size *= profile->kvd_hash_double_parts; |
3967 | double_size /= profile->kvd_hash_double_parts + | 3894 | double_size /= profile->kvd_hash_double_parts + |
@@ -3972,7 +3899,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
3972 | MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, | 3899 | MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, |
3973 | MLXSW_SP_RESOURCE_KVD, | 3900 | MLXSW_SP_RESOURCE_KVD, |
3974 | &mlxsw_sp_hash_double_size_params, | 3901 | &mlxsw_sp_hash_double_size_params, |
3975 | &mlxsw_sp_resource_kvd_hash_double_ops); | 3902 | NULL); |
3976 | if (err) | 3903 | if (err) |
3977 | return err; | 3904 | return err; |
3978 | 3905 | ||
@@ -3982,7 +3909,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) | |||
3982 | MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, | 3909 | MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, |
3983 | MLXSW_SP_RESOURCE_KVD, | 3910 | MLXSW_SP_RESOURCE_KVD, |
3984 | &mlxsw_sp_hash_single_size_params, | 3911 | &mlxsw_sp_hash_single_size_params, |
3985 | &mlxsw_sp_resource_kvd_hash_single_ops); | 3912 | NULL); |
3986 | if (err) | 3913 | if (err) |
3987 | return err; | 3914 | return err; |
3988 | 3915 | ||
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 6718a1f0482c..675e03a892ed 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h | |||
@@ -70,12 +70,18 @@ | |||
70 | #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR "linear" | 70 | #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR "linear" |
71 | #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE "hash_single" | 71 | #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE "hash_single" |
72 | #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE "hash_double" | 72 | #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE "hash_double" |
73 | #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES "singles" | ||
74 | #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS "chunks" | ||
75 | #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS "large_chunks" | ||
73 | 76 | ||
74 | enum mlxsw_sp_resource_id { | 77 | enum mlxsw_sp_resource_id { |
75 | MLXSW_SP_RESOURCE_KVD, | 78 | MLXSW_SP_RESOURCE_KVD, |
76 | MLXSW_SP_RESOURCE_KVD_LINEAR, | 79 | MLXSW_SP_RESOURCE_KVD_LINEAR, |
77 | MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, | 80 | MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, |
78 | MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, | 81 | MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, |
82 | MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, | ||
83 | MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, | ||
84 | MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, | ||
79 | }; | 85 | }; |
80 | 86 | ||
81 | struct mlxsw_sp_port; | 87 | struct mlxsw_sp_port; |
@@ -433,6 +439,7 @@ int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp, | |||
433 | unsigned int entry_count, | 439 | unsigned int entry_count, |
434 | unsigned int *p_alloc_size); | 440 | unsigned int *p_alloc_size); |
435 | u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp); | 441 | u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp); |
442 | int mlxsw_sp_kvdl_resources_register(struct devlink *devlink); | ||
436 | 443 | ||
437 | struct mlxsw_sp_acl_rule_info { | 444 | struct mlxsw_sp_acl_rule_info { |
438 | unsigned int priority; | 445 | unsigned int priority; |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c index 55f9d2d70f9e..d27fa57ad3c3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c | |||
@@ -67,7 +67,7 @@ struct mlxsw_sp_kvdl_part_info { | |||
67 | 67 | ||
68 | struct mlxsw_sp_kvdl_part { | 68 | struct mlxsw_sp_kvdl_part { |
69 | struct list_head list; | 69 | struct list_head list; |
70 | const struct mlxsw_sp_kvdl_part_info *info; | 70 | struct mlxsw_sp_kvdl_part_info *info; |
71 | unsigned long usage[0]; /* Entries */ | 71 | unsigned long usage[0]; /* Entries */ |
72 | }; | 72 | }; |
73 | 73 | ||
@@ -188,21 +188,27 @@ int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp, | |||
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | enum mlxsw_sp_kvdl_part_id { | ||
192 | MLXSW_SP_KVDL_PART_SINGLE, | ||
193 | MLXSW_SP_KVDL_PART_CHUNKS, | ||
194 | MLXSW_SP_KVDL_PART_LARGE_CHUNKS, | ||
195 | }; | ||
196 | |||
191 | static const struct mlxsw_sp_kvdl_part_info kvdl_parts_info[] = { | 197 | static const struct mlxsw_sp_kvdl_part_info kvdl_parts_info[] = { |
192 | { | 198 | { |
193 | .part_index = 0, | 199 | .part_index = MLXSW_SP_KVDL_PART_SINGLE, |
194 | .start_index = MLXSW_SP_KVDL_SINGLE_BASE, | 200 | .start_index = MLXSW_SP_KVDL_SINGLE_BASE, |
195 | .end_index = MLXSW_SP_KVDL_SINGLE_END, | 201 | .end_index = MLXSW_SP_KVDL_SINGLE_END, |
196 | .alloc_size = 1, | 202 | .alloc_size = 1, |
197 | }, | 203 | }, |
198 | { | 204 | { |
199 | .part_index = 1, | 205 | .part_index = MLXSW_SP_KVDL_PART_CHUNKS, |
200 | .start_index = MLXSW_SP_KVDL_CHUNKS_BASE, | 206 | .start_index = MLXSW_SP_KVDL_CHUNKS_BASE, |
201 | .end_index = MLXSW_SP_KVDL_CHUNKS_END, | 207 | .end_index = MLXSW_SP_KVDL_CHUNKS_END, |
202 | .alloc_size = MLXSW_SP_CHUNK_MAX, | 208 | .alloc_size = MLXSW_SP_CHUNK_MAX, |
203 | }, | 209 | }, |
204 | { | 210 | { |
205 | .part_index = 2, | 211 | .part_index = MLXSW_SP_KVDL_PART_LARGE_CHUNKS, |
206 | .start_index = MLXSW_SP_KVDL_LARGE_CHUNKS_BASE, | 212 | .start_index = MLXSW_SP_KVDL_LARGE_CHUNKS_BASE, |
207 | .end_index = MLXSW_SP_KVDL_LARGE_CHUNKS_END, | 213 | .end_index = MLXSW_SP_KVDL_LARGE_CHUNKS_END, |
208 | .alloc_size = MLXSW_SP_LARGE_CHUNK_MAX, | 214 | .alloc_size = MLXSW_SP_LARGE_CHUNK_MAX, |
@@ -222,27 +228,74 @@ mlxsw_sp_kvdl_part_find(struct mlxsw_sp *mlxsw_sp, unsigned int part_index) | |||
222 | return NULL; | 228 | return NULL; |
223 | } | 229 | } |
224 | 230 | ||
231 | static void | ||
232 | mlxsw_sp_kvdl_part_update(struct mlxsw_sp *mlxsw_sp, | ||
233 | struct mlxsw_sp_kvdl_part *part, unsigned int size) | ||
234 | { | ||
235 | struct mlxsw_sp_kvdl_part_info *info = part->info; | ||
236 | |||
237 | if (list_is_last(&part->list, &mlxsw_sp->kvdl->parts_list)) { | ||
238 | info->end_index = size - 1; | ||
239 | } else { | ||
240 | struct mlxsw_sp_kvdl_part *last_part; | ||
241 | |||
242 | last_part = list_next_entry(part, list); | ||
243 | info->start_index = last_part->info->end_index + 1; | ||
244 | info->end_index = info->start_index + size - 1; | ||
245 | } | ||
246 | } | ||
247 | |||
225 | static int mlxsw_sp_kvdl_part_init(struct mlxsw_sp *mlxsw_sp, | 248 | static int mlxsw_sp_kvdl_part_init(struct mlxsw_sp *mlxsw_sp, |
226 | unsigned int part_index) | 249 | unsigned int part_index) |
227 | { | 250 | { |
251 | struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); | ||
228 | const struct mlxsw_sp_kvdl_part_info *info; | 252 | const struct mlxsw_sp_kvdl_part_info *info; |
253 | enum mlxsw_sp_resource_id resource_id; | ||
229 | struct mlxsw_sp_kvdl_part *part; | 254 | struct mlxsw_sp_kvdl_part *part; |
255 | bool need_update = true; | ||
230 | unsigned int nr_entries; | 256 | unsigned int nr_entries; |
231 | size_t usage_size; | 257 | size_t usage_size; |
258 | u64 resource_size; | ||
259 | int err; | ||
232 | 260 | ||
233 | info = &kvdl_parts_info[part_index]; | 261 | info = &kvdl_parts_info[part_index]; |
234 | 262 | ||
235 | nr_entries = (info->end_index - info->start_index + 1) / | 263 | switch (part_index) { |
236 | info->alloc_size; | 264 | case MLXSW_SP_KVDL_PART_SINGLE: |
265 | resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE; | ||
266 | break; | ||
267 | case MLXSW_SP_KVDL_PART_CHUNKS: | ||
268 | resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS; | ||
269 | break; | ||
270 | case MLXSW_SP_KVDL_PART_LARGE_CHUNKS: | ||
271 | resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS; | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | err = devlink_resource_size_get(devlink, resource_id, &resource_size); | ||
276 | if (err) { | ||
277 | need_update = false; | ||
278 | resource_size = info->end_index - info->start_index + 1; | ||
279 | } | ||
280 | |||
281 | nr_entries = resource_size / info->alloc_size; | ||
237 | usage_size = BITS_TO_LONGS(nr_entries) * sizeof(unsigned long); | 282 | usage_size = BITS_TO_LONGS(nr_entries) * sizeof(unsigned long); |
238 | part = kzalloc(sizeof(*part) + usage_size, GFP_KERNEL); | 283 | part = kzalloc(sizeof(*part) + usage_size, GFP_KERNEL); |
239 | if (!part) | 284 | if (!part) |
240 | return -ENOMEM; | 285 | return -ENOMEM; |
241 | 286 | ||
242 | part->info = info; | 287 | part->info = kmemdup(info, sizeof(*part->info), GFP_KERNEL); |
243 | list_add(&part->list, &mlxsw_sp->kvdl->parts_list); | 288 | if (!part->info) |
289 | goto err_part_info_alloc; | ||
244 | 290 | ||
291 | list_add(&part->list, &mlxsw_sp->kvdl->parts_list); | ||
292 | if (need_update) | ||
293 | mlxsw_sp_kvdl_part_update(mlxsw_sp, part, resource_size); | ||
245 | return 0; | 294 | return 0; |
295 | |||
296 | err_part_info_alloc: | ||
297 | kfree(part); | ||
298 | return -ENOMEM; | ||
246 | } | 299 | } |
247 | 300 | ||
248 | static void mlxsw_sp_kvdl_part_fini(struct mlxsw_sp *mlxsw_sp, | 301 | static void mlxsw_sp_kvdl_part_fini(struct mlxsw_sp *mlxsw_sp, |
@@ -255,6 +308,7 @@ static void mlxsw_sp_kvdl_part_fini(struct mlxsw_sp *mlxsw_sp, | |||
255 | return; | 308 | return; |
256 | 309 | ||
257 | list_del(&part->list); | 310 | list_del(&part->list); |
311 | kfree(part->info); | ||
258 | kfree(part); | 312 | kfree(part); |
259 | } | 313 | } |
260 | 314 | ||
@@ -312,6 +366,123 @@ u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp) | |||
312 | return occ; | 366 | return occ; |
313 | } | 367 | } |
314 | 368 | ||
369 | u64 mlxsw_sp_kvdl_single_occ_get(struct devlink *devlink) | ||
370 | { | ||
371 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | ||
372 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | ||
373 | struct mlxsw_sp_kvdl_part *part; | ||
374 | |||
375 | part = mlxsw_sp_kvdl_part_find(mlxsw_sp, MLXSW_SP_KVDL_PART_SINGLE); | ||
376 | if (!part) | ||
377 | return -EINVAL; | ||
378 | |||
379 | return mlxsw_sp_kvdl_part_occ(part); | ||
380 | } | ||
381 | |||
382 | u64 mlxsw_sp_kvdl_chunks_occ_get(struct devlink *devlink) | ||
383 | { | ||
384 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | ||
385 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | ||
386 | struct mlxsw_sp_kvdl_part *part; | ||
387 | |||
388 | part = mlxsw_sp_kvdl_part_find(mlxsw_sp, MLXSW_SP_KVDL_PART_CHUNKS); | ||
389 | if (!part) | ||
390 | return -EINVAL; | ||
391 | |||
392 | return mlxsw_sp_kvdl_part_occ(part); | ||
393 | } | ||
394 | |||
395 | u64 mlxsw_sp_kvdl_large_chunks_occ_get(struct devlink *devlink) | ||
396 | { | ||
397 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | ||
398 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | ||
399 | struct mlxsw_sp_kvdl_part *part; | ||
400 | |||
401 | part = mlxsw_sp_kvdl_part_find(mlxsw_sp, | ||
402 | MLXSW_SP_KVDL_PART_LARGE_CHUNKS); | ||
403 | if (!part) | ||
404 | return -EINVAL; | ||
405 | |||
406 | return mlxsw_sp_kvdl_part_occ(part); | ||
407 | } | ||
408 | |||
409 | static struct devlink_resource_ops mlxsw_sp_kvdl_single_ops = { | ||
410 | .occ_get = mlxsw_sp_kvdl_single_occ_get, | ||
411 | }; | ||
412 | |||
413 | static struct devlink_resource_ops mlxsw_sp_kvdl_chunks_ops = { | ||
414 | .occ_get = mlxsw_sp_kvdl_chunks_occ_get, | ||
415 | }; | ||
416 | |||
417 | static struct devlink_resource_ops mlxsw_sp_kvdl_chunks_large_ops = { | ||
418 | .occ_get = mlxsw_sp_kvdl_large_chunks_occ_get, | ||
419 | }; | ||
420 | |||
421 | static struct devlink_resource_size_params mlxsw_sp_kvdl_single_size_params = { | ||
422 | .size_min = 0, | ||
423 | .size_granularity = 1, | ||
424 | .unit = DEVLINK_RESOURCE_UNIT_ENTRY, | ||
425 | }; | ||
426 | |||
427 | static struct devlink_resource_size_params mlxsw_sp_kvdl_chunks_size_params = { | ||
428 | .size_min = 0, | ||
429 | .size_granularity = MLXSW_SP_CHUNK_MAX, | ||
430 | .unit = DEVLINK_RESOURCE_UNIT_ENTRY, | ||
431 | }; | ||
432 | |||
433 | static struct devlink_resource_size_params mlxsw_sp_kvdl_large_chunks_size_params = { | ||
434 | .size_min = 0, | ||
435 | .size_granularity = MLXSW_SP_LARGE_CHUNK_MAX, | ||
436 | .unit = DEVLINK_RESOURCE_UNIT_ENTRY, | ||
437 | }; | ||
438 | |||
439 | static void | ||
440 | mlxsw_sp_kvdl_resource_size_params_prepare(struct devlink *devlink) | ||
441 | { | ||
442 | struct mlxsw_core *mlxsw_core = devlink_priv(devlink); | ||
443 | u32 kvdl_max_size; | ||
444 | |||
445 | kvdl_max_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) - | ||
446 | MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) - | ||
447 | MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE); | ||
448 | |||
449 | mlxsw_sp_kvdl_single_size_params.size_max = kvdl_max_size; | ||
450 | mlxsw_sp_kvdl_chunks_size_params.size_max = kvdl_max_size; | ||
451 | mlxsw_sp_kvdl_large_chunks_size_params.size_max = kvdl_max_size; | ||
452 | } | ||
453 | |||
454 | int mlxsw_sp_kvdl_resources_register(struct devlink *devlink) | ||
455 | { | ||
456 | int err; | ||
457 | |||
458 | mlxsw_sp_kvdl_resource_size_params_prepare(devlink); | ||
459 | err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES, | ||
460 | false, MLXSW_SP_KVDL_SINGLE_SIZE, | ||
461 | MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, | ||
462 | MLXSW_SP_RESOURCE_KVD_LINEAR, | ||
463 | &mlxsw_sp_kvdl_single_size_params, | ||
464 | &mlxsw_sp_kvdl_single_ops); | ||
465 | if (err) | ||
466 | return err; | ||
467 | |||
468 | err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS, | ||
469 | false, MLXSW_SP_KVDL_CHUNKS_SIZE, | ||
470 | MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, | ||
471 | MLXSW_SP_RESOURCE_KVD_LINEAR, | ||
472 | &mlxsw_sp_kvdl_chunks_size_params, | ||
473 | &mlxsw_sp_kvdl_chunks_ops); | ||
474 | if (err) | ||
475 | return err; | ||
476 | |||
477 | err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS, | ||
478 | false, MLXSW_SP_KVDL_LARGE_CHUNKS_SIZE, | ||
479 | MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, | ||
480 | MLXSW_SP_RESOURCE_KVD_LINEAR, | ||
481 | &mlxsw_sp_kvdl_large_chunks_size_params, | ||
482 | &mlxsw_sp_kvdl_chunks_large_ops); | ||
483 | return err; | ||
484 | } | ||
485 | |||
315 | int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp) | 486 | int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp) |
316 | { | 487 | { |
317 | struct mlxsw_sp_kvdl *kvdl; | 488 | struct mlxsw_sp_kvdl *kvdl; |
diff --git a/include/net/devlink.h b/include/net/devlink.h index 6545b03e97f7..8d1c3f276dea 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h | |||
@@ -234,13 +234,9 @@ struct devlink_dpipe_headers { | |||
234 | /** | 234 | /** |
235 | * struct devlink_resource_ops - resource ops | 235 | * struct devlink_resource_ops - resource ops |
236 | * @occ_get: get the occupied size | 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 | */ | 237 | */ |
240 | struct devlink_resource_ops { | 238 | struct devlink_resource_ops { |
241 | u64 (*occ_get)(struct devlink *devlink); | 239 | u64 (*occ_get)(struct devlink *devlink); |
242 | int (*size_validate)(struct devlink *devlink, u64 size, | ||
243 | struct netlink_ext_ack *extack); | ||
244 | }; | 240 | }; |
245 | 241 | ||
246 | /** | 242 | /** |
diff --git a/net/core/devlink.c b/net/core/devlink.c index 18d385ed8237..88e846779269 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c | |||
@@ -2338,6 +2338,32 @@ out: | |||
2338 | resource->size_valid = size_valid; | 2338 | resource->size_valid = size_valid; |
2339 | } | 2339 | } |
2340 | 2340 | ||
2341 | static int | ||
2342 | devlink_resource_validate_size(struct devlink_resource *resource, u64 size, | ||
2343 | struct netlink_ext_ack *extack) | ||
2344 | { | ||
2345 | u64 reminder; | ||
2346 | int err = 0; | ||
2347 | |||
2348 | if (size > resource->size_params->size_max) { | ||
2349 | NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum"); | ||
2350 | err = -EINVAL; | ||
2351 | } | ||
2352 | |||
2353 | if (size < resource->size_params->size_min) { | ||
2354 | NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum"); | ||
2355 | err = -EINVAL; | ||
2356 | } | ||
2357 | |||
2358 | div64_u64_rem(size, resource->size_params->size_granularity, &reminder); | ||
2359 | if (reminder) { | ||
2360 | NL_SET_ERR_MSG_MOD(extack, "Wrong granularity"); | ||
2361 | err = -EINVAL; | ||
2362 | } | ||
2363 | |||
2364 | return err; | ||
2365 | } | ||
2366 | |||
2341 | static int devlink_nl_cmd_resource_set(struct sk_buff *skb, | 2367 | static int devlink_nl_cmd_resource_set(struct sk_buff *skb, |
2342 | struct genl_info *info) | 2368 | struct genl_info *info) |
2343 | { | 2369 | { |
@@ -2356,12 +2382,8 @@ static int devlink_nl_cmd_resource_set(struct sk_buff *skb, | |||
2356 | if (!resource) | 2382 | if (!resource) |
2357 | return -EINVAL; | 2383 | return -EINVAL; |
2358 | 2384 | ||
2359 | if (!resource->resource_ops->size_validate) | ||
2360 | return -EINVAL; | ||
2361 | |||
2362 | size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]); | 2385 | size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]); |
2363 | err = resource->resource_ops->size_validate(devlink, size, | 2386 | err = devlink_resource_validate_size(resource, size, info->extack); |
2364 | info->extack); | ||
2365 | if (err) | 2387 | if (err) |
2366 | return err; | 2388 | return err; |
2367 | 2389 | ||