.. | .. |
---|
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 | } |
---|