| .. | .. |
|---|
| 3 | 3 | |
|---|
| 4 | 4 | #include <linux/kernel.h> |
|---|
| 5 | 5 | #include <linux/bitops.h> |
|---|
| 6 | +#include <linux/spinlock.h> |
|---|
| 6 | 7 | |
|---|
| 7 | 8 | #include "spectrum_cnt.h" |
|---|
| 8 | 9 | |
|---|
| 9 | | -#define MLXSW_SP_COUNTER_POOL_BANK_SIZE 4096 |
|---|
| 10 | | - |
|---|
| 11 | 10 | struct mlxsw_sp_counter_sub_pool { |
|---|
| 11 | + u64 size; |
|---|
| 12 | 12 | unsigned int base_index; |
|---|
| 13 | | - unsigned int size; |
|---|
| 13 | + enum mlxsw_res_id entry_size_res_id; |
|---|
| 14 | + const char *resource_name; /* devlink resource name */ |
|---|
| 15 | + u64 resource_id; /* devlink resource id */ |
|---|
| 14 | 16 | unsigned int entry_size; |
|---|
| 15 | 17 | unsigned int bank_count; |
|---|
| 18 | + atomic_t active_entries_count; |
|---|
| 16 | 19 | }; |
|---|
| 17 | 20 | |
|---|
| 18 | 21 | struct mlxsw_sp_counter_pool { |
|---|
| 19 | | - unsigned int pool_size; |
|---|
| 22 | + u64 pool_size; |
|---|
| 20 | 23 | unsigned long *usage; /* Usage bitmap */ |
|---|
| 21 | | - struct mlxsw_sp_counter_sub_pool *sub_pools; |
|---|
| 24 | + spinlock_t counter_pool_lock; /* Protects counter pool allocations */ |
|---|
| 25 | + atomic_t active_entries_count; |
|---|
| 26 | + unsigned int sub_pools_count; |
|---|
| 27 | + struct mlxsw_sp_counter_sub_pool sub_pools[]; |
|---|
| 22 | 28 | }; |
|---|
| 23 | 29 | |
|---|
| 24 | | -static struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = { |
|---|
| 30 | +static const struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = { |
|---|
| 25 | 31 | [MLXSW_SP_COUNTER_SUB_POOL_FLOW] = { |
|---|
| 32 | + .entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES, |
|---|
| 33 | + .resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_FLOW, |
|---|
| 34 | + .resource_id = MLXSW_SP_RESOURCE_COUNTERS_FLOW, |
|---|
| 26 | 35 | .bank_count = 6, |
|---|
| 27 | 36 | }, |
|---|
| 28 | 37 | [MLXSW_SP_COUNTER_SUB_POOL_RIF] = { |
|---|
| 38 | + .entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC, |
|---|
| 39 | + .resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_RIF, |
|---|
| 40 | + .resource_id = MLXSW_SP_RESOURCE_COUNTERS_RIF, |
|---|
| 29 | 41 | .bank_count = 2, |
|---|
| 30 | 42 | } |
|---|
| 31 | 43 | }; |
|---|
| 32 | 44 | |
|---|
| 33 | | -static int mlxsw_sp_counter_pool_validate(struct mlxsw_sp *mlxsw_sp) |
|---|
| 45 | +static u64 mlxsw_sp_counter_sub_pool_occ_get(void *priv) |
|---|
| 34 | 46 | { |
|---|
| 35 | | - unsigned int total_bank_config = 0; |
|---|
| 36 | | - unsigned int pool_size; |
|---|
| 37 | | - int i; |
|---|
| 47 | + const struct mlxsw_sp_counter_sub_pool *sub_pool = priv; |
|---|
| 38 | 48 | |
|---|
| 39 | | - pool_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, COUNTER_POOL_SIZE); |
|---|
| 40 | | - /* Check config is valid, no bank over subscription */ |
|---|
| 41 | | - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) |
|---|
| 42 | | - total_bank_config += mlxsw_sp_counter_sub_pools[i].bank_count; |
|---|
| 43 | | - if (total_bank_config > pool_size / MLXSW_SP_COUNTER_POOL_BANK_SIZE + 1) |
|---|
| 44 | | - return -EINVAL; |
|---|
| 45 | | - return 0; |
|---|
| 49 | + return atomic_read(&sub_pool->active_entries_count); |
|---|
| 46 | 50 | } |
|---|
| 47 | 51 | |
|---|
| 48 | | -static int mlxsw_sp_counter_sub_pools_prepare(struct mlxsw_sp *mlxsw_sp) |
|---|
| 52 | +static int mlxsw_sp_counter_sub_pools_init(struct mlxsw_sp *mlxsw_sp) |
|---|
| 49 | 53 | { |
|---|
| 54 | + struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool; |
|---|
| 55 | + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); |
|---|
| 50 | 56 | struct mlxsw_sp_counter_sub_pool *sub_pool; |
|---|
| 57 | + unsigned int base_index = 0; |
|---|
| 58 | + enum mlxsw_res_id res_id; |
|---|
| 59 | + int err; |
|---|
| 60 | + int i; |
|---|
| 51 | 61 | |
|---|
| 52 | | - /* Prepare generic flow pool*/ |
|---|
| 53 | | - sub_pool = &mlxsw_sp_counter_sub_pools[MLXSW_SP_COUNTER_SUB_POOL_FLOW]; |
|---|
| 54 | | - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_SIZE_PACKETS_BYTES)) |
|---|
| 55 | | - return -EIO; |
|---|
| 56 | | - sub_pool->entry_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, |
|---|
| 57 | | - COUNTER_SIZE_PACKETS_BYTES); |
|---|
| 58 | | - /* Prepare erif pool*/ |
|---|
| 59 | | - sub_pool = &mlxsw_sp_counter_sub_pools[MLXSW_SP_COUNTER_SUB_POOL_RIF]; |
|---|
| 60 | | - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_SIZE_ROUTER_BASIC)) |
|---|
| 61 | | - return -EIO; |
|---|
| 62 | | - sub_pool->entry_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, |
|---|
| 63 | | - COUNTER_SIZE_ROUTER_BASIC); |
|---|
| 62 | + for (i = 0; i < pool->sub_pools_count; i++) { |
|---|
| 63 | + sub_pool = &pool->sub_pools[i]; |
|---|
| 64 | + res_id = sub_pool->entry_size_res_id; |
|---|
| 65 | + |
|---|
| 66 | + if (!mlxsw_core_res_valid(mlxsw_sp->core, res_id)) |
|---|
| 67 | + return -EIO; |
|---|
| 68 | + sub_pool->entry_size = mlxsw_core_res_get(mlxsw_sp->core, |
|---|
| 69 | + res_id); |
|---|
| 70 | + err = devlink_resource_size_get(devlink, |
|---|
| 71 | + sub_pool->resource_id, |
|---|
| 72 | + &sub_pool->size); |
|---|
| 73 | + if (err) |
|---|
| 74 | + goto err_resource_size_get; |
|---|
| 75 | + |
|---|
| 76 | + devlink_resource_occ_get_register(devlink, |
|---|
| 77 | + sub_pool->resource_id, |
|---|
| 78 | + mlxsw_sp_counter_sub_pool_occ_get, |
|---|
| 79 | + sub_pool); |
|---|
| 80 | + |
|---|
| 81 | + sub_pool->base_index = base_index; |
|---|
| 82 | + base_index += sub_pool->size; |
|---|
| 83 | + atomic_set(&sub_pool->active_entries_count, 0); |
|---|
| 84 | + } |
|---|
| 64 | 85 | return 0; |
|---|
| 86 | + |
|---|
| 87 | +err_resource_size_get: |
|---|
| 88 | + for (i--; i >= 0; i--) { |
|---|
| 89 | + sub_pool = &pool->sub_pools[i]; |
|---|
| 90 | + |
|---|
| 91 | + devlink_resource_occ_get_unregister(devlink, |
|---|
| 92 | + sub_pool->resource_id); |
|---|
| 93 | + } |
|---|
| 94 | + return err; |
|---|
| 95 | +} |
|---|
| 96 | + |
|---|
| 97 | +static void mlxsw_sp_counter_sub_pools_fini(struct mlxsw_sp *mlxsw_sp) |
|---|
| 98 | +{ |
|---|
| 99 | + struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool; |
|---|
| 100 | + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); |
|---|
| 101 | + struct mlxsw_sp_counter_sub_pool *sub_pool; |
|---|
| 102 | + int i; |
|---|
| 103 | + |
|---|
| 104 | + for (i = 0; i < pool->sub_pools_count; i++) { |
|---|
| 105 | + sub_pool = &pool->sub_pools[i]; |
|---|
| 106 | + |
|---|
| 107 | + WARN_ON(atomic_read(&sub_pool->active_entries_count)); |
|---|
| 108 | + devlink_resource_occ_get_unregister(devlink, |
|---|
| 109 | + sub_pool->resource_id); |
|---|
| 110 | + } |
|---|
| 111 | +} |
|---|
| 112 | + |
|---|
| 113 | +static u64 mlxsw_sp_counter_pool_occ_get(void *priv) |
|---|
| 114 | +{ |
|---|
| 115 | + const struct mlxsw_sp_counter_pool *pool = priv; |
|---|
| 116 | + |
|---|
| 117 | + return atomic_read(&pool->active_entries_count); |
|---|
| 65 | 118 | } |
|---|
| 66 | 119 | |
|---|
| 67 | 120 | int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp) |
|---|
| 68 | 121 | { |
|---|
| 69 | | - struct mlxsw_sp_counter_sub_pool *sub_pool; |
|---|
| 122 | + unsigned int sub_pools_count = ARRAY_SIZE(mlxsw_sp_counter_sub_pools); |
|---|
| 123 | + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); |
|---|
| 70 | 124 | struct mlxsw_sp_counter_pool *pool; |
|---|
| 71 | | - unsigned int base_index; |
|---|
| 72 | 125 | unsigned int map_size; |
|---|
| 73 | | - int i; |
|---|
| 74 | 126 | int err; |
|---|
| 75 | 127 | |
|---|
| 76 | | - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_POOL_SIZE)) |
|---|
| 77 | | - return -EIO; |
|---|
| 78 | | - |
|---|
| 79 | | - err = mlxsw_sp_counter_pool_validate(mlxsw_sp); |
|---|
| 80 | | - if (err) |
|---|
| 81 | | - return err; |
|---|
| 82 | | - |
|---|
| 83 | | - err = mlxsw_sp_counter_sub_pools_prepare(mlxsw_sp); |
|---|
| 84 | | - if (err) |
|---|
| 85 | | - return err; |
|---|
| 86 | | - |
|---|
| 87 | | - pool = kzalloc(sizeof(*pool), GFP_KERNEL); |
|---|
| 128 | + pool = kzalloc(struct_size(pool, sub_pools, sub_pools_count), |
|---|
| 129 | + GFP_KERNEL); |
|---|
| 88 | 130 | if (!pool) |
|---|
| 89 | 131 | return -ENOMEM; |
|---|
| 132 | + mlxsw_sp->counter_pool = pool; |
|---|
| 133 | + pool->sub_pools_count = sub_pools_count; |
|---|
| 134 | + memcpy(pool->sub_pools, mlxsw_sp_counter_sub_pools, |
|---|
| 135 | + flex_array_size(pool, sub_pools, pool->sub_pools_count)); |
|---|
| 136 | + spin_lock_init(&pool->counter_pool_lock); |
|---|
| 137 | + atomic_set(&pool->active_entries_count, 0); |
|---|
| 90 | 138 | |
|---|
| 91 | | - pool->pool_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, COUNTER_POOL_SIZE); |
|---|
| 139 | + err = devlink_resource_size_get(devlink, MLXSW_SP_RESOURCE_COUNTERS, |
|---|
| 140 | + &pool->pool_size); |
|---|
| 141 | + if (err) |
|---|
| 142 | + goto err_pool_resource_size_get; |
|---|
| 143 | + devlink_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_COUNTERS, |
|---|
| 144 | + mlxsw_sp_counter_pool_occ_get, pool); |
|---|
| 145 | + |
|---|
| 92 | 146 | map_size = BITS_TO_LONGS(pool->pool_size) * sizeof(unsigned long); |
|---|
| 93 | 147 | |
|---|
| 94 | 148 | pool->usage = kzalloc(map_size, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 97 | 151 | goto err_usage_alloc; |
|---|
| 98 | 152 | } |
|---|
| 99 | 153 | |
|---|
| 100 | | - pool->sub_pools = mlxsw_sp_counter_sub_pools; |
|---|
| 101 | | - /* Allocation is based on bank count which should be |
|---|
| 102 | | - * specified for each sub pool statically. |
|---|
| 103 | | - */ |
|---|
| 104 | | - base_index = 0; |
|---|
| 105 | | - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) { |
|---|
| 106 | | - sub_pool = &pool->sub_pools[i]; |
|---|
| 107 | | - sub_pool->size = sub_pool->bank_count * |
|---|
| 108 | | - MLXSW_SP_COUNTER_POOL_BANK_SIZE; |
|---|
| 109 | | - sub_pool->base_index = base_index; |
|---|
| 110 | | - base_index += sub_pool->size; |
|---|
| 111 | | - /* The last bank can't be fully used */ |
|---|
| 112 | | - if (sub_pool->base_index + sub_pool->size > pool->pool_size) |
|---|
| 113 | | - sub_pool->size = pool->pool_size - sub_pool->base_index; |
|---|
| 114 | | - } |
|---|
| 154 | + err = mlxsw_sp_counter_sub_pools_init(mlxsw_sp); |
|---|
| 155 | + if (err) |
|---|
| 156 | + goto err_sub_pools_init; |
|---|
| 115 | 157 | |
|---|
| 116 | | - mlxsw_sp->counter_pool = pool; |
|---|
| 117 | 158 | return 0; |
|---|
| 118 | 159 | |
|---|
| 160 | +err_sub_pools_init: |
|---|
| 161 | + kfree(pool->usage); |
|---|
| 119 | 162 | err_usage_alloc: |
|---|
| 163 | + devlink_resource_occ_get_unregister(devlink, |
|---|
| 164 | + MLXSW_SP_RESOURCE_COUNTERS); |
|---|
| 165 | +err_pool_resource_size_get: |
|---|
| 120 | 166 | kfree(pool); |
|---|
| 121 | 167 | return err; |
|---|
| 122 | 168 | } |
|---|
| .. | .. |
|---|
| 124 | 170 | void mlxsw_sp_counter_pool_fini(struct mlxsw_sp *mlxsw_sp) |
|---|
| 125 | 171 | { |
|---|
| 126 | 172 | struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool; |
|---|
| 173 | + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); |
|---|
| 127 | 174 | |
|---|
| 175 | + mlxsw_sp_counter_sub_pools_fini(mlxsw_sp); |
|---|
| 128 | 176 | WARN_ON(find_first_bit(pool->usage, pool->pool_size) != |
|---|
| 129 | 177 | pool->pool_size); |
|---|
| 178 | + WARN_ON(atomic_read(&pool->active_entries_count)); |
|---|
| 130 | 179 | kfree(pool->usage); |
|---|
| 180 | + devlink_resource_occ_get_unregister(devlink, |
|---|
| 181 | + MLXSW_SP_RESOURCE_COUNTERS); |
|---|
| 131 | 182 | kfree(pool); |
|---|
| 132 | 183 | } |
|---|
| 133 | 184 | |
|---|
| .. | .. |
|---|
| 139 | 190 | struct mlxsw_sp_counter_sub_pool *sub_pool; |
|---|
| 140 | 191 | unsigned int entry_index; |
|---|
| 141 | 192 | unsigned int stop_index; |
|---|
| 142 | | - int i; |
|---|
| 193 | + int i, err; |
|---|
| 143 | 194 | |
|---|
| 144 | | - sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id]; |
|---|
| 195 | + sub_pool = &pool->sub_pools[sub_pool_id]; |
|---|
| 145 | 196 | stop_index = sub_pool->base_index + sub_pool->size; |
|---|
| 146 | 197 | entry_index = sub_pool->base_index; |
|---|
| 147 | 198 | |
|---|
| 199 | + spin_lock(&pool->counter_pool_lock); |
|---|
| 148 | 200 | entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index); |
|---|
| 149 | | - if (entry_index == stop_index) |
|---|
| 150 | | - return -ENOBUFS; |
|---|
| 201 | + if (entry_index == stop_index) { |
|---|
| 202 | + err = -ENOBUFS; |
|---|
| 203 | + goto err_alloc; |
|---|
| 204 | + } |
|---|
| 151 | 205 | /* The sub-pools can contain non-integer number of entries |
|---|
| 152 | 206 | * so we must check for overflow |
|---|
| 153 | 207 | */ |
|---|
| 154 | | - if (entry_index + sub_pool->entry_size > stop_index) |
|---|
| 155 | | - return -ENOBUFS; |
|---|
| 208 | + if (entry_index + sub_pool->entry_size > stop_index) { |
|---|
| 209 | + err = -ENOBUFS; |
|---|
| 210 | + goto err_alloc; |
|---|
| 211 | + } |
|---|
| 156 | 212 | for (i = 0; i < sub_pool->entry_size; i++) |
|---|
| 157 | 213 | __set_bit(entry_index + i, pool->usage); |
|---|
| 214 | + spin_unlock(&pool->counter_pool_lock); |
|---|
| 158 | 215 | |
|---|
| 159 | 216 | *p_counter_index = entry_index; |
|---|
| 217 | + atomic_add(sub_pool->entry_size, &sub_pool->active_entries_count); |
|---|
| 218 | + atomic_add(sub_pool->entry_size, &pool->active_entries_count); |
|---|
| 160 | 219 | return 0; |
|---|
| 220 | + |
|---|
| 221 | +err_alloc: |
|---|
| 222 | + spin_unlock(&pool->counter_pool_lock); |
|---|
| 223 | + return err; |
|---|
| 161 | 224 | } |
|---|
| 162 | 225 | |
|---|
| 163 | 226 | void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp, |
|---|
| .. | .. |
|---|
| 170 | 233 | |
|---|
| 171 | 234 | if (WARN_ON(counter_index >= pool->pool_size)) |
|---|
| 172 | 235 | return; |
|---|
| 173 | | - sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id]; |
|---|
| 236 | + sub_pool = &pool->sub_pools[sub_pool_id]; |
|---|
| 237 | + spin_lock(&pool->counter_pool_lock); |
|---|
| 174 | 238 | for (i = 0; i < sub_pool->entry_size; i++) |
|---|
| 175 | 239 | __clear_bit(counter_index + i, pool->usage); |
|---|
| 240 | + spin_unlock(&pool->counter_pool_lock); |
|---|
| 241 | + atomic_sub(sub_pool->entry_size, &sub_pool->active_entries_count); |
|---|
| 242 | + atomic_sub(sub_pool->entry_size, &pool->active_entries_count); |
|---|
| 243 | +} |
|---|
| 244 | + |
|---|
| 245 | +int mlxsw_sp_counter_resources_register(struct mlxsw_core *mlxsw_core) |
|---|
| 246 | +{ |
|---|
| 247 | + static struct devlink_resource_size_params size_params; |
|---|
| 248 | + struct devlink *devlink = priv_to_devlink(mlxsw_core); |
|---|
| 249 | + const struct mlxsw_sp_counter_sub_pool *sub_pool; |
|---|
| 250 | + unsigned int total_bank_config; |
|---|
| 251 | + u64 sub_pool_size; |
|---|
| 252 | + u64 base_index; |
|---|
| 253 | + u64 pool_size; |
|---|
| 254 | + u64 bank_size; |
|---|
| 255 | + int err; |
|---|
| 256 | + int i; |
|---|
| 257 | + |
|---|
| 258 | + if (!MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_POOL_SIZE) || |
|---|
| 259 | + !MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_BANK_SIZE)) |
|---|
| 260 | + return -EIO; |
|---|
| 261 | + |
|---|
| 262 | + pool_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_POOL_SIZE); |
|---|
| 263 | + bank_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_BANK_SIZE); |
|---|
| 264 | + |
|---|
| 265 | + devlink_resource_size_params_init(&size_params, pool_size, |
|---|
| 266 | + pool_size, bank_size, |
|---|
| 267 | + DEVLINK_RESOURCE_UNIT_ENTRY); |
|---|
| 268 | + err = devlink_resource_register(devlink, |
|---|
| 269 | + MLXSW_SP_RESOURCE_NAME_COUNTERS, |
|---|
| 270 | + pool_size, |
|---|
| 271 | + MLXSW_SP_RESOURCE_COUNTERS, |
|---|
| 272 | + DEVLINK_RESOURCE_ID_PARENT_TOP, |
|---|
| 273 | + &size_params); |
|---|
| 274 | + if (err) |
|---|
| 275 | + return err; |
|---|
| 276 | + |
|---|
| 277 | + /* Allocation is based on bank count which should be |
|---|
| 278 | + * specified for each sub pool statically. |
|---|
| 279 | + */ |
|---|
| 280 | + total_bank_config = 0; |
|---|
| 281 | + base_index = 0; |
|---|
| 282 | + for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) { |
|---|
| 283 | + sub_pool = &mlxsw_sp_counter_sub_pools[i]; |
|---|
| 284 | + sub_pool_size = sub_pool->bank_count * bank_size; |
|---|
| 285 | + /* The last bank can't be fully used */ |
|---|
| 286 | + if (base_index + sub_pool_size > pool_size) |
|---|
| 287 | + sub_pool_size = pool_size - base_index; |
|---|
| 288 | + base_index += sub_pool_size; |
|---|
| 289 | + |
|---|
| 290 | + devlink_resource_size_params_init(&size_params, sub_pool_size, |
|---|
| 291 | + sub_pool_size, bank_size, |
|---|
| 292 | + DEVLINK_RESOURCE_UNIT_ENTRY); |
|---|
| 293 | + err = devlink_resource_register(devlink, |
|---|
| 294 | + sub_pool->resource_name, |
|---|
| 295 | + sub_pool_size, |
|---|
| 296 | + sub_pool->resource_id, |
|---|
| 297 | + MLXSW_SP_RESOURCE_COUNTERS, |
|---|
| 298 | + &size_params); |
|---|
| 299 | + if (err) |
|---|
| 300 | + return err; |
|---|
| 301 | + total_bank_config += sub_pool->bank_count; |
|---|
| 302 | + } |
|---|
| 303 | + |
|---|
| 304 | + /* Check config is valid, no bank over subscription */ |
|---|
| 305 | + if (WARN_ON(total_bank_config > div64_u64(pool_size, bank_size) + 1)) |
|---|
| 306 | + return -EINVAL; |
|---|
| 307 | + |
|---|
| 308 | + return 0; |
|---|
| 176 | 309 | } |
|---|