diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 5e8ea712caa2b99c6e669eb63415419b593fbdef..bfde93910f8248149ccb80035d5b2dc0139d9b1b 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 = { .resource_query_enable = 1, }; -static bool -mlxsw_sp_resource_kvd_granularity_validate(struct netlink_ext_ack *extack, - u64 size) -{ - const struct mlxsw_config_profile *profile; - - profile = &mlxsw_sp_config_profile; - if (size % profile->kvd_hash_granularity) { - NL_SET_ERR_MSG_MOD(extack, "resource set with wrong granularity"); - return false; - } - return true; -} - -static int -mlxsw_sp_resource_kvd_size_validate(struct devlink *devlink, u64 size, - struct netlink_ext_ack *extack) -{ - NL_SET_ERR_MSG_MOD(extack, "kvd size cannot be changed"); - return -EINVAL; -} - -static int -mlxsw_sp_resource_kvd_linear_size_validate(struct devlink *devlink, u64 size, - struct netlink_ext_ack *extack) -{ - if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size)) - return -EINVAL; - - return 0; -} - -static int -mlxsw_sp_resource_kvd_hash_single_size_validate(struct devlink *devlink, u64 size, - struct netlink_ext_ack *extack) -{ - struct mlxsw_core *mlxsw_core = devlink_priv(devlink); - - if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size)) - return -EINVAL; - - if (size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE)) { - NL_SET_ERR_MSG_MOD(extack, "hash single size is smaller than minimum"); - return -EINVAL; - } - return 0; -} - -static int -mlxsw_sp_resource_kvd_hash_double_size_validate(struct devlink *devlink, u64 size, - struct netlink_ext_ack *extack) -{ - struct mlxsw_core *mlxsw_core = devlink_priv(devlink); - - if (!mlxsw_sp_resource_kvd_granularity_validate(extack, size)) - return -EINVAL; - - if (size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE)) { - NL_SET_ERR_MSG_MOD(extack, "hash double size is smaller than minimum"); - return -EINVAL; - } - return 0; -} - static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink) { struct mlxsw_core *mlxsw_core = devlink_priv(devlink); @@ -3870,23 +3806,10 @@ static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink) return mlxsw_sp_kvdl_occ_get(mlxsw_sp); } -static struct devlink_resource_ops mlxsw_sp_resource_kvd_ops = { - .size_validate = mlxsw_sp_resource_kvd_size_validate, -}; - static struct devlink_resource_ops mlxsw_sp_resource_kvd_linear_ops = { - .size_validate = mlxsw_sp_resource_kvd_linear_size_validate, .occ_get = mlxsw_sp_resource_kvd_linear_occ_get, }; -static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_single_ops = { - .size_validate = mlxsw_sp_resource_kvd_hash_single_size_validate, -}; - -static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = { - .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate, -}; - static struct devlink_resource_size_params mlxsw_sp_kvd_size_params; static struct devlink_resource_size_params mlxsw_sp_linear_size_params; 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) MLXSW_SP_RESOURCE_KVD, DEVLINK_RESOURCE_ID_PARENT_TOP, &mlxsw_sp_kvd_size_params, - &mlxsw_sp_resource_kvd_ops); + NULL); if (err) return err; @@ -3962,6 +3885,10 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) if (err) return err; + err = mlxsw_sp_kvdl_resources_register(devlink); + if (err) + return err; + double_size = kvd_size - linear_size; double_size *= profile->kvd_hash_double_parts; double_size /= profile->kvd_hash_double_parts + @@ -3972,7 +3899,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, MLXSW_SP_RESOURCE_KVD, &mlxsw_sp_hash_double_size_params, - &mlxsw_sp_resource_kvd_hash_double_ops); + NULL); if (err) return err; @@ -3982,7 +3909,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, MLXSW_SP_RESOURCE_KVD, &mlxsw_sp_hash_single_size_params, - &mlxsw_sp_resource_kvd_hash_single_ops); + NULL); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 6718a1f0482c24c09705319876376f6e5f247805..675e03a892ed390358eda831c1ba518b98b976be 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -70,12 +70,18 @@ #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR "linear" #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE "hash_single" #define MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE "hash_double" +#define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES "singles" +#define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS "chunks" +#define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS "large_chunks" enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD, MLXSW_SP_RESOURCE_KVD_LINEAR, MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, + MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, + MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, + MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, }; struct mlxsw_sp_port; @@ -433,6 +439,7 @@ int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, unsigned int *p_alloc_size); u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp); +int mlxsw_sp_kvdl_resources_register(struct devlink *devlink); struct mlxsw_sp_acl_rule_info { unsigned int priority; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c index 55f9d2d70f9eef90071cb6683f355f8a81f1d3b2..d27fa57ad3c36f83f7b641e0a958ffefab059f82 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 { struct mlxsw_sp_kvdl_part { struct list_head list; - const struct mlxsw_sp_kvdl_part_info *info; + struct mlxsw_sp_kvdl_part_info *info; unsigned long usage[0]; /* Entries */ }; @@ -188,21 +188,27 @@ int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp, return 0; } +enum mlxsw_sp_kvdl_part_id { + MLXSW_SP_KVDL_PART_SINGLE, + MLXSW_SP_KVDL_PART_CHUNKS, + MLXSW_SP_KVDL_PART_LARGE_CHUNKS, +}; + static const struct mlxsw_sp_kvdl_part_info kvdl_parts_info[] = { { - .part_index = 0, + .part_index = MLXSW_SP_KVDL_PART_SINGLE, .start_index = MLXSW_SP_KVDL_SINGLE_BASE, .end_index = MLXSW_SP_KVDL_SINGLE_END, .alloc_size = 1, }, { - .part_index = 1, + .part_index = MLXSW_SP_KVDL_PART_CHUNKS, .start_index = MLXSW_SP_KVDL_CHUNKS_BASE, .end_index = MLXSW_SP_KVDL_CHUNKS_END, .alloc_size = MLXSW_SP_CHUNK_MAX, }, { - .part_index = 2, + .part_index = MLXSW_SP_KVDL_PART_LARGE_CHUNKS, .start_index = MLXSW_SP_KVDL_LARGE_CHUNKS_BASE, .end_index = MLXSW_SP_KVDL_LARGE_CHUNKS_END, .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) return NULL; } +static void +mlxsw_sp_kvdl_part_update(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_kvdl_part *part, unsigned int size) +{ + struct mlxsw_sp_kvdl_part_info *info = part->info; + + if (list_is_last(&part->list, &mlxsw_sp->kvdl->parts_list)) { + info->end_index = size - 1; + } else { + struct mlxsw_sp_kvdl_part *last_part; + + last_part = list_next_entry(part, list); + info->start_index = last_part->info->end_index + 1; + info->end_index = info->start_index + size - 1; + } +} + static int mlxsw_sp_kvdl_part_init(struct mlxsw_sp *mlxsw_sp, unsigned int part_index) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); const struct mlxsw_sp_kvdl_part_info *info; + enum mlxsw_sp_resource_id resource_id; struct mlxsw_sp_kvdl_part *part; + bool need_update = true; unsigned int nr_entries; size_t usage_size; + u64 resource_size; + int err; info = &kvdl_parts_info[part_index]; - nr_entries = (info->end_index - info->start_index + 1) / - info->alloc_size; + switch (part_index) { + case MLXSW_SP_KVDL_PART_SINGLE: + resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE; + break; + case MLXSW_SP_KVDL_PART_CHUNKS: + resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS; + break; + case MLXSW_SP_KVDL_PART_LARGE_CHUNKS: + resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS; + break; + } + + err = devlink_resource_size_get(devlink, resource_id, &resource_size); + if (err) { + need_update = false; + resource_size = info->end_index - info->start_index + 1; + } + + nr_entries = resource_size / info->alloc_size; usage_size = BITS_TO_LONGS(nr_entries) * sizeof(unsigned long); part = kzalloc(sizeof(*part) + usage_size, GFP_KERNEL); if (!part) return -ENOMEM; - part->info = info; - list_add(&part->list, &mlxsw_sp->kvdl->parts_list); + part->info = kmemdup(info, sizeof(*part->info), GFP_KERNEL); + if (!part->info) + goto err_part_info_alloc; + list_add(&part->list, &mlxsw_sp->kvdl->parts_list); + if (need_update) + mlxsw_sp_kvdl_part_update(mlxsw_sp, part, resource_size); return 0; + +err_part_info_alloc: + kfree(part); + return -ENOMEM; } 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, return; list_del(&part->list); + kfree(part->info); kfree(part); } @@ -312,6 +366,123 @@ u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp) return occ; } +u64 mlxsw_sp_kvdl_single_occ_get(struct devlink *devlink) +{ + struct mlxsw_core *mlxsw_core = devlink_priv(devlink); + struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + struct mlxsw_sp_kvdl_part *part; + + part = mlxsw_sp_kvdl_part_find(mlxsw_sp, MLXSW_SP_KVDL_PART_SINGLE); + if (!part) + return -EINVAL; + + return mlxsw_sp_kvdl_part_occ(part); +} + +u64 mlxsw_sp_kvdl_chunks_occ_get(struct devlink *devlink) +{ + struct mlxsw_core *mlxsw_core = devlink_priv(devlink); + struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + struct mlxsw_sp_kvdl_part *part; + + part = mlxsw_sp_kvdl_part_find(mlxsw_sp, MLXSW_SP_KVDL_PART_CHUNKS); + if (!part) + return -EINVAL; + + return mlxsw_sp_kvdl_part_occ(part); +} + +u64 mlxsw_sp_kvdl_large_chunks_occ_get(struct devlink *devlink) +{ + struct mlxsw_core *mlxsw_core = devlink_priv(devlink); + struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + struct mlxsw_sp_kvdl_part *part; + + part = mlxsw_sp_kvdl_part_find(mlxsw_sp, + MLXSW_SP_KVDL_PART_LARGE_CHUNKS); + if (!part) + return -EINVAL; + + return mlxsw_sp_kvdl_part_occ(part); +} + +static struct devlink_resource_ops mlxsw_sp_kvdl_single_ops = { + .occ_get = mlxsw_sp_kvdl_single_occ_get, +}; + +static struct devlink_resource_ops mlxsw_sp_kvdl_chunks_ops = { + .occ_get = mlxsw_sp_kvdl_chunks_occ_get, +}; + +static struct devlink_resource_ops mlxsw_sp_kvdl_chunks_large_ops = { + .occ_get = mlxsw_sp_kvdl_large_chunks_occ_get, +}; + +static struct devlink_resource_size_params mlxsw_sp_kvdl_single_size_params = { + .size_min = 0, + .size_granularity = 1, + .unit = DEVLINK_RESOURCE_UNIT_ENTRY, +}; + +static struct devlink_resource_size_params mlxsw_sp_kvdl_chunks_size_params = { + .size_min = 0, + .size_granularity = MLXSW_SP_CHUNK_MAX, + .unit = DEVLINK_RESOURCE_UNIT_ENTRY, +}; + +static struct devlink_resource_size_params mlxsw_sp_kvdl_large_chunks_size_params = { + .size_min = 0, + .size_granularity = MLXSW_SP_LARGE_CHUNK_MAX, + .unit = DEVLINK_RESOURCE_UNIT_ENTRY, +}; + +static void +mlxsw_sp_kvdl_resource_size_params_prepare(struct devlink *devlink) +{ + struct mlxsw_core *mlxsw_core = devlink_priv(devlink); + u32 kvdl_max_size; + + kvdl_max_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) - + MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) - + MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE); + + mlxsw_sp_kvdl_single_size_params.size_max = kvdl_max_size; + mlxsw_sp_kvdl_chunks_size_params.size_max = kvdl_max_size; + mlxsw_sp_kvdl_large_chunks_size_params.size_max = kvdl_max_size; +} + +int mlxsw_sp_kvdl_resources_register(struct devlink *devlink) +{ + int err; + + mlxsw_sp_kvdl_resource_size_params_prepare(devlink); + err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES, + false, MLXSW_SP_KVDL_SINGLE_SIZE, + MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, + MLXSW_SP_RESOURCE_KVD_LINEAR, + &mlxsw_sp_kvdl_single_size_params, + &mlxsw_sp_kvdl_single_ops); + if (err) + return err; + + err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS, + false, MLXSW_SP_KVDL_CHUNKS_SIZE, + MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, + MLXSW_SP_RESOURCE_KVD_LINEAR, + &mlxsw_sp_kvdl_chunks_size_params, + &mlxsw_sp_kvdl_chunks_ops); + if (err) + return err; + + err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS, + false, MLXSW_SP_KVDL_LARGE_CHUNKS_SIZE, + MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, + MLXSW_SP_RESOURCE_KVD_LINEAR, + &mlxsw_sp_kvdl_large_chunks_size_params, + &mlxsw_sp_kvdl_chunks_large_ops); + return err; +} + int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_kvdl *kvdl; diff --git a/include/net/devlink.h b/include/net/devlink.h index 6545b03e97f73fd5d439a092b9374dfea83d9319..8d1c3f276dea76f00c0d702463aa1f10c6ccb301 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -234,13 +234,9 @@ struct devlink_dpipe_headers { /** * struct devlink_resource_ops - resource ops * @occ_get: get the occupied size - * @size_validate: validate the size of the resource before update, reload - * is needed for changes to take place */ struct devlink_resource_ops { u64 (*occ_get)(struct devlink *devlink); - int (*size_validate)(struct devlink *devlink, u64 size, - struct netlink_ext_ack *extack); }; /** diff --git a/net/core/devlink.c b/net/core/devlink.c index 18d385ed82370a7b6a9a2e31023b785a054e9e9f..88e8467792691617b18899b9955ddbfb0447cf1b 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -2338,6 +2338,32 @@ devlink_resource_validate_children(struct devlink_resource *resource) resource->size_valid = size_valid; } +static int +devlink_resource_validate_size(struct devlink_resource *resource, u64 size, + struct netlink_ext_ack *extack) +{ + u64 reminder; + int err = 0; + + if (size > resource->size_params->size_max) { + NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum"); + err = -EINVAL; + } + + if (size < resource->size_params->size_min) { + NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum"); + err = -EINVAL; + } + + div64_u64_rem(size, resource->size_params->size_granularity, &reminder); + if (reminder) { + NL_SET_ERR_MSG_MOD(extack, "Wrong granularity"); + err = -EINVAL; + } + + return err; +} + static int devlink_nl_cmd_resource_set(struct sk_buff *skb, struct genl_info *info) { @@ -2356,12 +2382,8 @@ static int devlink_nl_cmd_resource_set(struct sk_buff *skb, if (!resource) return -EINVAL; - if (!resource->resource_ops->size_validate) - return -EINVAL; - size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]); - err = resource->resource_ops->size_validate(devlink, size, - info->extack); + err = devlink_resource_validate_size(resource, size, info->extack); if (err) return err;