1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/slab.h> 6 #include <linux/list.h> 7 #include <linux/errno.h> 8 9 #include "item.h" 10 #include "core_acl_flex_keys.h" 11 12 struct mlxsw_afk { 13 struct list_head key_info_list; 14 unsigned int max_blocks; 15 const struct mlxsw_afk_ops *ops; 16 const struct mlxsw_afk_block *blocks; 17 unsigned int blocks_count; 18 }; 19 20 static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk) 21 { 22 int i; 23 int j; 24 25 for (i = 0; i < mlxsw_afk->blocks_count; i++) { 26 const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i]; 27 28 for (j = 0; j < block->instances_count; j++) { 29 struct mlxsw_afk_element_inst *elinst; 30 31 elinst = &block->instances[j]; 32 if (elinst->type != elinst->info->type || 33 elinst->item.size.bits != 34 elinst->info->item.size.bits) 35 return false; 36 } 37 } 38 return true; 39 } 40 41 struct mlxsw_afk *mlxsw_afk_create(unsigned int max_blocks, 42 const struct mlxsw_afk_ops *ops) 43 { 44 struct mlxsw_afk *mlxsw_afk; 45 46 mlxsw_afk = kzalloc(sizeof(*mlxsw_afk), GFP_KERNEL); 47 if (!mlxsw_afk) 48 return NULL; 49 INIT_LIST_HEAD(&mlxsw_afk->key_info_list); 50 mlxsw_afk->max_blocks = max_blocks; 51 mlxsw_afk->ops = ops; 52 mlxsw_afk->blocks = ops->blocks; 53 mlxsw_afk->blocks_count = ops->blocks_count; 54 WARN_ON(!mlxsw_afk_blocks_check(mlxsw_afk)); 55 return mlxsw_afk; 56 } 57 EXPORT_SYMBOL(mlxsw_afk_create); 58 59 void mlxsw_afk_destroy(struct mlxsw_afk *mlxsw_afk) 60 { 61 WARN_ON(!list_empty(&mlxsw_afk->key_info_list)); 62 kfree(mlxsw_afk); 63 } 64 EXPORT_SYMBOL(mlxsw_afk_destroy); 65 66 struct mlxsw_afk_key_info { 67 struct list_head list; 68 unsigned int ref_count; 69 unsigned int blocks_count; 70 int element_to_block[MLXSW_AFK_ELEMENT_MAX]; /* index is element, value 71 * is index inside "blocks" 72 */ 73 struct mlxsw_afk_element_usage elusage; 74 const struct mlxsw_afk_block *blocks[0]; 75 }; 76 77 static bool 78 mlxsw_afk_key_info_elements_eq(struct mlxsw_afk_key_info *key_info, 79 struct mlxsw_afk_element_usage *elusage) 80 { 81 return memcmp(&key_info->elusage, elusage, sizeof(*elusage)) == 0; 82 } 83 84 static struct mlxsw_afk_key_info * 85 mlxsw_afk_key_info_find(struct mlxsw_afk *mlxsw_afk, 86 struct mlxsw_afk_element_usage *elusage) 87 { 88 struct mlxsw_afk_key_info *key_info; 89 90 list_for_each_entry(key_info, &mlxsw_afk->key_info_list, list) { 91 if (mlxsw_afk_key_info_elements_eq(key_info, elusage)) 92 return key_info; 93 } 94 return NULL; 95 } 96 97 struct mlxsw_afk_picker { 98 struct { 99 DECLARE_BITMAP(element, MLXSW_AFK_ELEMENT_MAX); 100 unsigned int total; 101 } hits[0]; 102 }; 103 104 static void mlxsw_afk_picker_count_hits(struct mlxsw_afk *mlxsw_afk, 105 struct mlxsw_afk_picker *picker, 106 enum mlxsw_afk_element element) 107 { 108 int i; 109 int j; 110 111 for (i = 0; i < mlxsw_afk->blocks_count; i++) { 112 const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i]; 113 114 for (j = 0; j < block->instances_count; j++) { 115 struct mlxsw_afk_element_inst *elinst; 116 117 elinst = &block->instances[j]; 118 if (elinst->info->element == element) { 119 __set_bit(element, picker->hits[i].element); 120 picker->hits[i].total++; 121 } 122 } 123 } 124 } 125 126 static void mlxsw_afk_picker_subtract_hits(struct mlxsw_afk *mlxsw_afk, 127 struct mlxsw_afk_picker *picker, 128 int block_index) 129 { 130 DECLARE_BITMAP(hits_element, MLXSW_AFK_ELEMENT_MAX); 131 int i; 132 int j; 133 134 memcpy(&hits_element, &picker->hits[block_index].element, 135 sizeof(hits_element)); 136 137 for (i = 0; i < mlxsw_afk->blocks_count; i++) { 138 for_each_set_bit(j, hits_element, MLXSW_AFK_ELEMENT_MAX) { 139 if (__test_and_clear_bit(j, picker->hits[i].element)) 140 picker->hits[i].total--; 141 } 142 } 143 } 144 145 static int mlxsw_afk_picker_most_hits_get(struct mlxsw_afk *mlxsw_afk, 146 struct mlxsw_afk_picker *picker) 147 { 148 int most_index = -EINVAL; /* Should never happen to return this */ 149 int most_hits = 0; 150 int i; 151 152 for (i = 0; i < mlxsw_afk->blocks_count; i++) { 153 if (picker->hits[i].total > most_hits) { 154 most_hits = picker->hits[i].total; 155 most_index = i; 156 } 157 } 158 return most_index; 159 } 160 161 static int mlxsw_afk_picker_key_info_add(struct mlxsw_afk *mlxsw_afk, 162 struct mlxsw_afk_picker *picker, 163 int block_index, 164 struct mlxsw_afk_key_info *key_info) 165 { 166 enum mlxsw_afk_element element; 167 168 if (key_info->blocks_count == mlxsw_afk->max_blocks) 169 return -EINVAL; 170 171 for_each_set_bit(element, picker->hits[block_index].element, 172 MLXSW_AFK_ELEMENT_MAX) { 173 key_info->element_to_block[element] = key_info->blocks_count; 174 mlxsw_afk_element_usage_add(&key_info->elusage, element); 175 } 176 177 key_info->blocks[key_info->blocks_count] = 178 &mlxsw_afk->blocks[block_index]; 179 key_info->blocks_count++; 180 return 0; 181 } 182 183 static int mlxsw_afk_picker(struct mlxsw_afk *mlxsw_afk, 184 struct mlxsw_afk_key_info *key_info, 185 struct mlxsw_afk_element_usage *elusage) 186 { 187 struct mlxsw_afk_picker *picker; 188 enum mlxsw_afk_element element; 189 size_t alloc_size; 190 int err; 191 192 alloc_size = sizeof(picker->hits[0]) * mlxsw_afk->blocks_count; 193 picker = kzalloc(alloc_size, GFP_KERNEL); 194 if (!picker) 195 return -ENOMEM; 196 197 /* Since the same elements could be present in multiple blocks, 198 * we must find out optimal block list in order to make the 199 * block count as low as possible. 200 * 201 * First, we count hits. We go over all available blocks and count 202 * how many of requested elements are covered by each. 203 * 204 * Then in loop, we find block with most hits and add it to 205 * output key_info. Then we have to subtract this block hits so 206 * the next iteration will find most suitable block for 207 * the rest of requested elements. 208 */ 209 210 mlxsw_afk_element_usage_for_each(element, elusage) 211 mlxsw_afk_picker_count_hits(mlxsw_afk, picker, element); 212 213 do { 214 int block_index; 215 216 block_index = mlxsw_afk_picker_most_hits_get(mlxsw_afk, picker); 217 if (block_index < 0) { 218 err = block_index; 219 goto out; 220 } 221 err = mlxsw_afk_picker_key_info_add(mlxsw_afk, picker, 222 block_index, key_info); 223 if (err) 224 goto out; 225 mlxsw_afk_picker_subtract_hits(mlxsw_afk, picker, block_index); 226 } while (!mlxsw_afk_key_info_elements_eq(key_info, elusage)); 227 228 err = 0; 229 out: 230 kfree(picker); 231 return err; 232 } 233 234 static struct mlxsw_afk_key_info * 235 mlxsw_afk_key_info_create(struct mlxsw_afk *mlxsw_afk, 236 struct mlxsw_afk_element_usage *elusage) 237 { 238 struct mlxsw_afk_key_info *key_info; 239 int err; 240 241 key_info = kzalloc(struct_size(key_info, blocks, mlxsw_afk->max_blocks), 242 GFP_KERNEL); 243 if (!key_info) 244 return ERR_PTR(-ENOMEM); 245 err = mlxsw_afk_picker(mlxsw_afk, key_info, elusage); 246 if (err) 247 goto err_picker; 248 list_add(&key_info->list, &mlxsw_afk->key_info_list); 249 key_info->ref_count = 1; 250 return key_info; 251 252 err_picker: 253 kfree(key_info); 254 return ERR_PTR(err); 255 } 256 257 static void mlxsw_afk_key_info_destroy(struct mlxsw_afk_key_info *key_info) 258 { 259 list_del(&key_info->list); 260 kfree(key_info); 261 } 262 263 struct mlxsw_afk_key_info * 264 mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk, 265 struct mlxsw_afk_element_usage *elusage) 266 { 267 struct mlxsw_afk_key_info *key_info; 268 269 key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage); 270 if (key_info) { 271 key_info->ref_count++; 272 return key_info; 273 } 274 return mlxsw_afk_key_info_create(mlxsw_afk, elusage); 275 } 276 EXPORT_SYMBOL(mlxsw_afk_key_info_get); 277 278 void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info) 279 { 280 if (--key_info->ref_count) 281 return; 282 mlxsw_afk_key_info_destroy(key_info); 283 } 284 EXPORT_SYMBOL(mlxsw_afk_key_info_put); 285 286 bool mlxsw_afk_key_info_subset(struct mlxsw_afk_key_info *key_info, 287 struct mlxsw_afk_element_usage *elusage) 288 { 289 return mlxsw_afk_element_usage_subset(elusage, &key_info->elusage); 290 } 291 EXPORT_SYMBOL(mlxsw_afk_key_info_subset); 292 293 static const struct mlxsw_afk_element_inst * 294 mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block, 295 enum mlxsw_afk_element element) 296 { 297 int i; 298 299 for (i = 0; i < block->instances_count; i++) { 300 struct mlxsw_afk_element_inst *elinst; 301 302 elinst = &block->instances[i]; 303 if (elinst->info->element == element) 304 return elinst; 305 } 306 return NULL; 307 } 308 309 static const struct mlxsw_afk_element_inst * 310 mlxsw_afk_key_info_elinst_get(struct mlxsw_afk_key_info *key_info, 311 enum mlxsw_afk_element element, 312 int *p_block_index) 313 { 314 const struct mlxsw_afk_element_inst *elinst; 315 const struct mlxsw_afk_block *block; 316 int block_index; 317 318 if (WARN_ON(!test_bit(element, key_info->elusage.usage))) 319 return NULL; 320 block_index = key_info->element_to_block[element]; 321 block = key_info->blocks[block_index]; 322 323 elinst = mlxsw_afk_block_elinst_get(block, element); 324 if (WARN_ON(!elinst)) 325 return NULL; 326 327 *p_block_index = block_index; 328 return elinst; 329 } 330 331 u16 332 mlxsw_afk_key_info_block_encoding_get(const struct mlxsw_afk_key_info *key_info, 333 int block_index) 334 { 335 return key_info->blocks[block_index]->encoding; 336 } 337 EXPORT_SYMBOL(mlxsw_afk_key_info_block_encoding_get); 338 339 unsigned int 340 mlxsw_afk_key_info_blocks_count_get(const struct mlxsw_afk_key_info *key_info) 341 { 342 return key_info->blocks_count; 343 } 344 EXPORT_SYMBOL(mlxsw_afk_key_info_blocks_count_get); 345 346 void mlxsw_afk_values_add_u32(struct mlxsw_afk_element_values *values, 347 enum mlxsw_afk_element element, 348 u32 key_value, u32 mask_value) 349 { 350 const struct mlxsw_afk_element_info *elinfo = 351 &mlxsw_afk_element_infos[element]; 352 const struct mlxsw_item *storage_item = &elinfo->item; 353 354 if (!mask_value) 355 return; 356 if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_U32)) 357 return; 358 __mlxsw_item_set32(values->storage.key, storage_item, 0, key_value); 359 __mlxsw_item_set32(values->storage.mask, storage_item, 0, mask_value); 360 mlxsw_afk_element_usage_add(&values->elusage, element); 361 } 362 EXPORT_SYMBOL(mlxsw_afk_values_add_u32); 363 364 void mlxsw_afk_values_add_buf(struct mlxsw_afk_element_values *values, 365 enum mlxsw_afk_element element, 366 const char *key_value, const char *mask_value, 367 unsigned int len) 368 { 369 const struct mlxsw_afk_element_info *elinfo = 370 &mlxsw_afk_element_infos[element]; 371 const struct mlxsw_item *storage_item = &elinfo->item; 372 373 if (!memchr_inv(mask_value, 0, len)) /* If mask is zero */ 374 return; 375 if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_BUF) || 376 WARN_ON(elinfo->item.size.bytes != len)) 377 return; 378 __mlxsw_item_memcpy_to(values->storage.key, key_value, 379 storage_item, 0); 380 __mlxsw_item_memcpy_to(values->storage.mask, mask_value, 381 storage_item, 0); 382 mlxsw_afk_element_usage_add(&values->elusage, element); 383 } 384 EXPORT_SYMBOL(mlxsw_afk_values_add_buf); 385 386 static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item, 387 const struct mlxsw_item *output_item, 388 char *storage, char *output) 389 { 390 u32 value; 391 392 value = __mlxsw_item_get32(storage, storage_item, 0); 393 __mlxsw_item_set32(output, output_item, 0, value); 394 } 395 396 static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item, 397 const struct mlxsw_item *output_item, 398 char *storage, char *output) 399 { 400 char *storage_data = __mlxsw_item_data(storage, storage_item, 0); 401 char *output_data = __mlxsw_item_data(output, output_item, 0); 402 size_t len = output_item->size.bytes; 403 404 memcpy(output_data, storage_data, len); 405 } 406 407 static void 408 mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst, 409 char *output, char *storage) 410 { 411 const struct mlxsw_item *storage_item = &elinst->info->item; 412 const struct mlxsw_item *output_item = &elinst->item; 413 414 if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32) 415 mlxsw_sp_afk_encode_u32(storage_item, output_item, 416 storage, output); 417 else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF) 418 mlxsw_sp_afk_encode_buf(storage_item, output_item, 419 storage, output); 420 } 421 422 #define MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE 16 423 424 void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk, 425 struct mlxsw_afk_key_info *key_info, 426 struct mlxsw_afk_element_values *values, 427 char *key, char *mask) 428 { 429 unsigned int blocks_count = 430 mlxsw_afk_key_info_blocks_count_get(key_info); 431 char block_mask[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE]; 432 char block_key[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE]; 433 const struct mlxsw_afk_element_inst *elinst; 434 enum mlxsw_afk_element element; 435 int block_index, i; 436 437 for (i = 0; i < blocks_count; i++) { 438 memset(block_key, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE); 439 memset(block_mask, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE); 440 441 mlxsw_afk_element_usage_for_each(element, &values->elusage) { 442 elinst = mlxsw_afk_key_info_elinst_get(key_info, 443 element, 444 &block_index); 445 if (!elinst || block_index != i) 446 continue; 447 448 mlxsw_sp_afk_encode_one(elinst, block_key, 449 values->storage.key); 450 mlxsw_sp_afk_encode_one(elinst, block_mask, 451 values->storage.mask); 452 } 453 454 mlxsw_afk->ops->encode_block(key, i, block_key); 455 mlxsw_afk->ops->encode_block(mask, i, block_mask); 456 } 457 } 458 EXPORT_SYMBOL(mlxsw_afk_encode); 459 460 void mlxsw_afk_clear(struct mlxsw_afk *mlxsw_afk, char *key, 461 int block_start, int block_end) 462 { 463 int i; 464 465 for (i = block_start; i <= block_end; i++) 466 mlxsw_afk->ops->clear_block(key, i); 467 } 468 EXPORT_SYMBOL(mlxsw_afk_clear); 469