1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
5 #include <linux/bitops.h>
9 #define MLXSW_SP1_KVDL_SINGLE_BASE 0
10 #define MLXSW_SP1_KVDL_SINGLE_SIZE 16384
11 #define MLXSW_SP1_KVDL_SINGLE_END \
12 (MLXSW_SP1_KVDL_SINGLE_SIZE + MLXSW_SP1_KVDL_SINGLE_BASE - 1)
14 #define MLXSW_SP1_KVDL_CHUNKS_BASE \
15 (MLXSW_SP1_KVDL_SINGLE_BASE + MLXSW_SP1_KVDL_SINGLE_SIZE)
16 #define MLXSW_SP1_KVDL_CHUNKS_SIZE 49152
17 #define MLXSW_SP1_KVDL_CHUNKS_END \
18 (MLXSW_SP1_KVDL_CHUNKS_SIZE + MLXSW_SP1_KVDL_CHUNKS_BASE - 1)
20 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_BASE \
21 (MLXSW_SP1_KVDL_CHUNKS_BASE + MLXSW_SP1_KVDL_CHUNKS_SIZE)
22 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE \
23 (MLXSW_SP_KVD_LINEAR_SIZE - MLXSW_SP1_KVDL_LARGE_CHUNKS_BASE)
24 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_END \
25 (MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE + MLXSW_SP1_KVDL_LARGE_CHUNKS_BASE - 1)
27 #define MLXSW_SP1_KVDL_SINGLE_ALLOC_SIZE 1
28 #define MLXSW_SP1_KVDL_CHUNKS_ALLOC_SIZE 32
29 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_ALLOC_SIZE 512
31 struct mlxsw_sp1_kvdl_part_info
{
32 unsigned int part_index
;
33 unsigned int start_index
;
34 unsigned int end_index
;
35 unsigned int alloc_size
;
36 enum mlxsw_sp_resource_id resource_id
;
39 enum mlxsw_sp1_kvdl_part_id
{
40 MLXSW_SP1_KVDL_PART_ID_SINGLE
,
41 MLXSW_SP1_KVDL_PART_ID_CHUNKS
,
42 MLXSW_SP1_KVDL_PART_ID_LARGE_CHUNKS
,
45 #define MLXSW_SP1_KVDL_PART_INFO(id) \
46 [MLXSW_SP1_KVDL_PART_ID_##id] = { \
47 .start_index = MLXSW_SP1_KVDL_##id##_BASE, \
48 .end_index = MLXSW_SP1_KVDL_##id##_END, \
49 .alloc_size = MLXSW_SP1_KVDL_##id##_ALLOC_SIZE, \
50 .resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_##id, \
53 static const struct mlxsw_sp1_kvdl_part_info mlxsw_sp1_kvdl_parts_info
[] = {
54 MLXSW_SP1_KVDL_PART_INFO(SINGLE
),
55 MLXSW_SP1_KVDL_PART_INFO(CHUNKS
),
56 MLXSW_SP1_KVDL_PART_INFO(LARGE_CHUNKS
),
59 #define MLXSW_SP1_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp1_kvdl_parts_info)
61 struct mlxsw_sp1_kvdl_part
{
62 struct mlxsw_sp1_kvdl_part_info info
;
63 unsigned long usage
[]; /* Entries */
66 struct mlxsw_sp1_kvdl
{
67 struct mlxsw_sp1_kvdl_part
*parts
[MLXSW_SP1_KVDL_PARTS_INFO_LEN
];
70 static struct mlxsw_sp1_kvdl_part
*
71 mlxsw_sp1_kvdl_alloc_size_part(struct mlxsw_sp1_kvdl
*kvdl
,
72 unsigned int alloc_size
)
74 struct mlxsw_sp1_kvdl_part
*part
, *min_part
= NULL
;
77 for (i
= 0; i
< MLXSW_SP1_KVDL_PARTS_INFO_LEN
; i
++) {
78 part
= kvdl
->parts
[i
];
79 if (alloc_size
<= part
->info
.alloc_size
&&
81 part
->info
.alloc_size
<= min_part
->info
.alloc_size
))
85 return min_part
?: ERR_PTR(-ENOBUFS
);
88 static struct mlxsw_sp1_kvdl_part
*
89 mlxsw_sp1_kvdl_index_part(struct mlxsw_sp1_kvdl
*kvdl
, u32 kvdl_index
)
91 struct mlxsw_sp1_kvdl_part
*part
;
94 for (i
= 0; i
< MLXSW_SP1_KVDL_PARTS_INFO_LEN
; i
++) {
95 part
= kvdl
->parts
[i
];
96 if (kvdl_index
>= part
->info
.start_index
&&
97 kvdl_index
<= part
->info
.end_index
)
101 return ERR_PTR(-EINVAL
);
105 mlxsw_sp1_kvdl_to_kvdl_index(const struct mlxsw_sp1_kvdl_part_info
*info
,
106 unsigned int entry_index
)
108 return info
->start_index
+ entry_index
* info
->alloc_size
;
112 mlxsw_sp1_kvdl_to_entry_index(const struct mlxsw_sp1_kvdl_part_info
*info
,
115 return (kvdl_index
- info
->start_index
) / info
->alloc_size
;
118 static int mlxsw_sp1_kvdl_part_alloc(struct mlxsw_sp1_kvdl_part
*part
,
121 const struct mlxsw_sp1_kvdl_part_info
*info
= &part
->info
;
122 unsigned int entry_index
, nr_entries
;
124 nr_entries
= (info
->end_index
- info
->start_index
+ 1) /
126 entry_index
= find_first_zero_bit(part
->usage
, nr_entries
);
127 if (entry_index
== nr_entries
)
129 __set_bit(entry_index
, part
->usage
);
131 *p_kvdl_index
= mlxsw_sp1_kvdl_to_kvdl_index(info
, entry_index
);
136 static void mlxsw_sp1_kvdl_part_free(struct mlxsw_sp1_kvdl_part
*part
,
139 const struct mlxsw_sp1_kvdl_part_info
*info
= &part
->info
;
140 unsigned int entry_index
;
142 entry_index
= mlxsw_sp1_kvdl_to_entry_index(info
, kvdl_index
);
143 __clear_bit(entry_index
, part
->usage
);
146 static int mlxsw_sp1_kvdl_alloc(struct mlxsw_sp
*mlxsw_sp
, void *priv
,
147 enum mlxsw_sp_kvdl_entry_type type
,
148 unsigned int entry_count
,
151 struct mlxsw_sp1_kvdl
*kvdl
= priv
;
152 struct mlxsw_sp1_kvdl_part
*part
;
154 /* Find partition with smallest allocation size satisfying the
157 part
= mlxsw_sp1_kvdl_alloc_size_part(kvdl
, entry_count
);
159 return PTR_ERR(part
);
161 return mlxsw_sp1_kvdl_part_alloc(part
, p_entry_index
);
164 static void mlxsw_sp1_kvdl_free(struct mlxsw_sp
*mlxsw_sp
, void *priv
,
165 enum mlxsw_sp_kvdl_entry_type type
,
166 unsigned int entry_count
, int entry_index
)
168 struct mlxsw_sp1_kvdl
*kvdl
= priv
;
169 struct mlxsw_sp1_kvdl_part
*part
;
171 part
= mlxsw_sp1_kvdl_index_part(kvdl
, entry_index
);
174 mlxsw_sp1_kvdl_part_free(part
, entry_index
);
177 static int mlxsw_sp1_kvdl_alloc_size_query(struct mlxsw_sp
*mlxsw_sp
,
179 enum mlxsw_sp_kvdl_entry_type type
,
180 unsigned int entry_count
,
181 unsigned int *p_alloc_size
)
183 struct mlxsw_sp1_kvdl
*kvdl
= priv
;
184 struct mlxsw_sp1_kvdl_part
*part
;
186 part
= mlxsw_sp1_kvdl_alloc_size_part(kvdl
, entry_count
);
188 return PTR_ERR(part
);
190 *p_alloc_size
= part
->info
.alloc_size
;
195 static void mlxsw_sp1_kvdl_part_update(struct mlxsw_sp1_kvdl_part
*part
,
196 struct mlxsw_sp1_kvdl_part
*part_prev
,
200 part
->info
.end_index
= size
- 1;
202 part
->info
.start_index
= part_prev
->info
.end_index
+ 1;
203 part
->info
.end_index
= part
->info
.start_index
+ size
- 1;
207 static struct mlxsw_sp1_kvdl_part
*
208 mlxsw_sp1_kvdl_part_init(struct mlxsw_sp
*mlxsw_sp
,
209 const struct mlxsw_sp1_kvdl_part_info
*info
,
210 struct mlxsw_sp1_kvdl_part
*part_prev
)
212 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
213 struct mlxsw_sp1_kvdl_part
*part
;
214 bool need_update
= true;
215 unsigned int nr_entries
;
220 err
= devlink_resource_size_get(devlink
, info
->resource_id
,
224 resource_size
= info
->end_index
- info
->start_index
+ 1;
227 nr_entries
= div_u64(resource_size
, info
->alloc_size
);
228 usage_size
= BITS_TO_LONGS(nr_entries
) * sizeof(unsigned long);
229 part
= kzalloc(sizeof(*part
) + usage_size
, GFP_KERNEL
);
231 return ERR_PTR(-ENOMEM
);
233 memcpy(&part
->info
, info
, sizeof(part
->info
));
236 mlxsw_sp1_kvdl_part_update(part
, part_prev
, resource_size
);
240 static void mlxsw_sp1_kvdl_part_fini(struct mlxsw_sp1_kvdl_part
*part
)
245 static int mlxsw_sp1_kvdl_parts_init(struct mlxsw_sp
*mlxsw_sp
,
246 struct mlxsw_sp1_kvdl
*kvdl
)
248 const struct mlxsw_sp1_kvdl_part_info
*info
;
249 struct mlxsw_sp1_kvdl_part
*part_prev
= NULL
;
252 for (i
= 0; i
< MLXSW_SP1_KVDL_PARTS_INFO_LEN
; i
++) {
253 info
= &mlxsw_sp1_kvdl_parts_info
[i
];
254 kvdl
->parts
[i
] = mlxsw_sp1_kvdl_part_init(mlxsw_sp
, info
,
256 if (IS_ERR(kvdl
->parts
[i
])) {
257 err
= PTR_ERR(kvdl
->parts
[i
]);
258 goto err_kvdl_part_init
;
260 part_prev
= kvdl
->parts
[i
];
265 for (i
--; i
>= 0; i
--)
266 mlxsw_sp1_kvdl_part_fini(kvdl
->parts
[i
]);
270 static void mlxsw_sp1_kvdl_parts_fini(struct mlxsw_sp1_kvdl
*kvdl
)
274 for (i
= 0; i
< MLXSW_SP1_KVDL_PARTS_INFO_LEN
; i
++)
275 mlxsw_sp1_kvdl_part_fini(kvdl
->parts
[i
]);
278 static u64
mlxsw_sp1_kvdl_part_occ(struct mlxsw_sp1_kvdl_part
*part
)
280 const struct mlxsw_sp1_kvdl_part_info
*info
= &part
->info
;
281 unsigned int nr_entries
;
285 nr_entries
= (info
->end_index
-
286 info
->start_index
+ 1) /
288 while ((bit
= find_next_bit(part
->usage
, nr_entries
, bit
+ 1))
290 occ
+= info
->alloc_size
;
294 static u64
mlxsw_sp1_kvdl_occ_get(void *priv
)
296 const struct mlxsw_sp1_kvdl
*kvdl
= priv
;
300 for (i
= 0; i
< MLXSW_SP1_KVDL_PARTS_INFO_LEN
; i
++)
301 occ
+= mlxsw_sp1_kvdl_part_occ(kvdl
->parts
[i
]);
306 static u64
mlxsw_sp1_kvdl_single_occ_get(void *priv
)
308 const struct mlxsw_sp1_kvdl
*kvdl
= priv
;
309 struct mlxsw_sp1_kvdl_part
*part
;
311 part
= kvdl
->parts
[MLXSW_SP1_KVDL_PART_ID_SINGLE
];
312 return mlxsw_sp1_kvdl_part_occ(part
);
315 static u64
mlxsw_sp1_kvdl_chunks_occ_get(void *priv
)
317 const struct mlxsw_sp1_kvdl
*kvdl
= priv
;
318 struct mlxsw_sp1_kvdl_part
*part
;
320 part
= kvdl
->parts
[MLXSW_SP1_KVDL_PART_ID_CHUNKS
];
321 return mlxsw_sp1_kvdl_part_occ(part
);
324 static u64
mlxsw_sp1_kvdl_large_chunks_occ_get(void *priv
)
326 const struct mlxsw_sp1_kvdl
*kvdl
= priv
;
327 struct mlxsw_sp1_kvdl_part
*part
;
329 part
= kvdl
->parts
[MLXSW_SP1_KVDL_PART_ID_LARGE_CHUNKS
];
330 return mlxsw_sp1_kvdl_part_occ(part
);
333 static int mlxsw_sp1_kvdl_init(struct mlxsw_sp
*mlxsw_sp
, void *priv
)
335 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
336 struct mlxsw_sp1_kvdl
*kvdl
= priv
;
339 err
= mlxsw_sp1_kvdl_parts_init(mlxsw_sp
, kvdl
);
342 devlink_resource_occ_get_register(devlink
,
343 MLXSW_SP_RESOURCE_KVD_LINEAR
,
344 mlxsw_sp1_kvdl_occ_get
,
346 devlink_resource_occ_get_register(devlink
,
347 MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE
,
348 mlxsw_sp1_kvdl_single_occ_get
,
350 devlink_resource_occ_get_register(devlink
,
351 MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS
,
352 mlxsw_sp1_kvdl_chunks_occ_get
,
354 devlink_resource_occ_get_register(devlink
,
355 MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS
,
356 mlxsw_sp1_kvdl_large_chunks_occ_get
,
361 static void mlxsw_sp1_kvdl_fini(struct mlxsw_sp
*mlxsw_sp
, void *priv
)
363 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
364 struct mlxsw_sp1_kvdl
*kvdl
= priv
;
366 devlink_resource_occ_get_unregister(devlink
,
367 MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS
);
368 devlink_resource_occ_get_unregister(devlink
,
369 MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS
);
370 devlink_resource_occ_get_unregister(devlink
,
371 MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE
);
372 devlink_resource_occ_get_unregister(devlink
,
373 MLXSW_SP_RESOURCE_KVD_LINEAR
);
374 mlxsw_sp1_kvdl_parts_fini(kvdl
);
377 const struct mlxsw_sp_kvdl_ops mlxsw_sp1_kvdl_ops
= {
378 .priv_size
= sizeof(struct mlxsw_sp1_kvdl
),
379 .init
= mlxsw_sp1_kvdl_init
,
380 .fini
= mlxsw_sp1_kvdl_fini
,
381 .alloc
= mlxsw_sp1_kvdl_alloc
,
382 .free
= mlxsw_sp1_kvdl_free
,
383 .alloc_size_query
= mlxsw_sp1_kvdl_alloc_size_query
,
386 int mlxsw_sp1_kvdl_resources_register(struct mlxsw_core
*mlxsw_core
)
388 struct devlink
*devlink
= priv_to_devlink(mlxsw_core
);
389 static struct devlink_resource_size_params size_params
;
393 kvdl_max_size
= MLXSW_CORE_RES_GET(mlxsw_core
, KVD_SIZE
) -
394 MLXSW_CORE_RES_GET(mlxsw_core
, KVD_SINGLE_MIN_SIZE
) -
395 MLXSW_CORE_RES_GET(mlxsw_core
, KVD_DOUBLE_MIN_SIZE
);
397 devlink_resource_size_params_init(&size_params
, 0, kvdl_max_size
,
398 MLXSW_SP1_KVDL_SINGLE_ALLOC_SIZE
,
399 DEVLINK_RESOURCE_UNIT_ENTRY
);
400 err
= devlink_resource_register(devlink
, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES
,
401 MLXSW_SP1_KVDL_SINGLE_SIZE
,
402 MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE
,
403 MLXSW_SP_RESOURCE_KVD_LINEAR
,
408 devlink_resource_size_params_init(&size_params
, 0, kvdl_max_size
,
409 MLXSW_SP1_KVDL_CHUNKS_ALLOC_SIZE
,
410 DEVLINK_RESOURCE_UNIT_ENTRY
);
411 err
= devlink_resource_register(devlink
, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS
,
412 MLXSW_SP1_KVDL_CHUNKS_SIZE
,
413 MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS
,
414 MLXSW_SP_RESOURCE_KVD_LINEAR
,
419 devlink_resource_size_params_init(&size_params
, 0, kvdl_max_size
,
420 MLXSW_SP1_KVDL_LARGE_CHUNKS_ALLOC_SIZE
,
421 DEVLINK_RESOURCE_UNIT_ENTRY
);
422 err
= devlink_resource_register(devlink
, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS
,
423 MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE
,
424 MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS
,
425 MLXSW_SP_RESOURCE_KVD_LINEAR
,