1b2fdf3d0SPaul Blakey // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2b2fdf3d0SPaul Blakey // Copyright (c) 2020 Mellanox Technologies 3b2fdf3d0SPaul Blakey 4b2fdf3d0SPaul Blakey #include <linux/jhash.h> 5b2fdf3d0SPaul Blakey #include "mod_hdr.h" 6b2fdf3d0SPaul Blakey 7b2fdf3d0SPaul Blakey #define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) 8b2fdf3d0SPaul Blakey 9b2fdf3d0SPaul Blakey struct mod_hdr_key { 10b2fdf3d0SPaul Blakey int num_actions; 11b2fdf3d0SPaul Blakey void *actions; 12b2fdf3d0SPaul Blakey }; 13b2fdf3d0SPaul Blakey 14b2fdf3d0SPaul Blakey struct mlx5e_mod_hdr_handle { 15b2fdf3d0SPaul Blakey /* a node of a hash table which keeps all the mod_hdr entries */ 16b2fdf3d0SPaul Blakey struct hlist_node mod_hdr_hlist; 17b2fdf3d0SPaul Blakey 18b2fdf3d0SPaul Blakey struct mod_hdr_key key; 19b2fdf3d0SPaul Blakey 20b2fdf3d0SPaul Blakey struct mlx5_modify_hdr *modify_hdr; 21b2fdf3d0SPaul Blakey 22b2fdf3d0SPaul Blakey refcount_t refcnt; 23b2fdf3d0SPaul Blakey struct completion res_ready; 24b2fdf3d0SPaul Blakey int compl_result; 25b2fdf3d0SPaul Blakey }; 26b2fdf3d0SPaul Blakey 27b2fdf3d0SPaul Blakey static u32 hash_mod_hdr_info(struct mod_hdr_key *key) 28b2fdf3d0SPaul Blakey { 29b2fdf3d0SPaul Blakey return jhash(key->actions, 30b2fdf3d0SPaul Blakey key->num_actions * MLX5_MH_ACT_SZ, 0); 31b2fdf3d0SPaul Blakey } 32b2fdf3d0SPaul Blakey 33b2fdf3d0SPaul Blakey static int cmp_mod_hdr_info(struct mod_hdr_key *a, struct mod_hdr_key *b) 34b2fdf3d0SPaul Blakey { 35b2fdf3d0SPaul Blakey if (a->num_actions != b->num_actions) 36b2fdf3d0SPaul Blakey return 1; 37b2fdf3d0SPaul Blakey 38b2fdf3d0SPaul Blakey return memcmp(a->actions, b->actions, 39b2fdf3d0SPaul Blakey a->num_actions * MLX5_MH_ACT_SZ); 40b2fdf3d0SPaul Blakey } 41b2fdf3d0SPaul Blakey 42b2fdf3d0SPaul Blakey void mlx5e_mod_hdr_tbl_init(struct mod_hdr_tbl *tbl) 43b2fdf3d0SPaul Blakey { 44b2fdf3d0SPaul Blakey mutex_init(&tbl->lock); 45b2fdf3d0SPaul Blakey hash_init(tbl->hlist); 46b2fdf3d0SPaul Blakey } 47b2fdf3d0SPaul Blakey 48b2fdf3d0SPaul Blakey void mlx5e_mod_hdr_tbl_destroy(struct mod_hdr_tbl *tbl) 49b2fdf3d0SPaul Blakey { 50b2fdf3d0SPaul Blakey mutex_destroy(&tbl->lock); 51b2fdf3d0SPaul Blakey } 52b2fdf3d0SPaul Blakey 53b2fdf3d0SPaul Blakey static struct mlx5e_mod_hdr_handle *mod_hdr_get(struct mod_hdr_tbl *tbl, 54b2fdf3d0SPaul Blakey struct mod_hdr_key *key, 55b2fdf3d0SPaul Blakey u32 hash_key) 56b2fdf3d0SPaul Blakey { 57b2fdf3d0SPaul Blakey struct mlx5e_mod_hdr_handle *mh, *found = NULL; 58b2fdf3d0SPaul Blakey 59b2fdf3d0SPaul Blakey hash_for_each_possible(tbl->hlist, mh, mod_hdr_hlist, hash_key) { 60b2fdf3d0SPaul Blakey if (!cmp_mod_hdr_info(&mh->key, key)) { 61b2fdf3d0SPaul Blakey refcount_inc(&mh->refcnt); 62b2fdf3d0SPaul Blakey found = mh; 63b2fdf3d0SPaul Blakey break; 64b2fdf3d0SPaul Blakey } 65b2fdf3d0SPaul Blakey } 66b2fdf3d0SPaul Blakey 67b2fdf3d0SPaul Blakey return found; 68b2fdf3d0SPaul Blakey } 69b2fdf3d0SPaul Blakey 70b2fdf3d0SPaul Blakey struct mlx5e_mod_hdr_handle * 71b2fdf3d0SPaul Blakey mlx5e_mod_hdr_attach(struct mlx5_core_dev *mdev, 72b2fdf3d0SPaul Blakey struct mod_hdr_tbl *tbl, 73b2fdf3d0SPaul Blakey enum mlx5_flow_namespace_type namespace, 74b2fdf3d0SPaul Blakey struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts) 75b2fdf3d0SPaul Blakey { 76b2fdf3d0SPaul Blakey int num_actions, actions_size, err; 77b2fdf3d0SPaul Blakey struct mlx5e_mod_hdr_handle *mh; 78b2fdf3d0SPaul Blakey struct mod_hdr_key key; 79b2fdf3d0SPaul Blakey u32 hash_key; 80b2fdf3d0SPaul Blakey 81b2fdf3d0SPaul Blakey num_actions = mod_hdr_acts->num_actions; 82b2fdf3d0SPaul Blakey actions_size = MLX5_MH_ACT_SZ * num_actions; 83b2fdf3d0SPaul Blakey 84b2fdf3d0SPaul Blakey key.actions = mod_hdr_acts->actions; 85b2fdf3d0SPaul Blakey key.num_actions = num_actions; 86b2fdf3d0SPaul Blakey 87b2fdf3d0SPaul Blakey hash_key = hash_mod_hdr_info(&key); 88b2fdf3d0SPaul Blakey 89b2fdf3d0SPaul Blakey mutex_lock(&tbl->lock); 90b2fdf3d0SPaul Blakey mh = mod_hdr_get(tbl, &key, hash_key); 91b2fdf3d0SPaul Blakey if (mh) { 92b2fdf3d0SPaul Blakey mutex_unlock(&tbl->lock); 93b2fdf3d0SPaul Blakey wait_for_completion(&mh->res_ready); 94b2fdf3d0SPaul Blakey 95b2fdf3d0SPaul Blakey if (mh->compl_result < 0) { 96b2fdf3d0SPaul Blakey err = -EREMOTEIO; 97b2fdf3d0SPaul Blakey goto attach_header_err; 98b2fdf3d0SPaul Blakey } 99b2fdf3d0SPaul Blakey goto attach_header; 100b2fdf3d0SPaul Blakey } 101b2fdf3d0SPaul Blakey 102b2fdf3d0SPaul Blakey mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL); 103b2fdf3d0SPaul Blakey if (!mh) { 104b2fdf3d0SPaul Blakey mutex_unlock(&tbl->lock); 105b2fdf3d0SPaul Blakey return ERR_PTR(-ENOMEM); 106b2fdf3d0SPaul Blakey } 107b2fdf3d0SPaul Blakey 108b2fdf3d0SPaul Blakey mh->key.actions = (void *)mh + sizeof(*mh); 109b2fdf3d0SPaul Blakey memcpy(mh->key.actions, key.actions, actions_size); 110b2fdf3d0SPaul Blakey mh->key.num_actions = num_actions; 111b2fdf3d0SPaul Blakey refcount_set(&mh->refcnt, 1); 112b2fdf3d0SPaul Blakey init_completion(&mh->res_ready); 113b2fdf3d0SPaul Blakey 114b2fdf3d0SPaul Blakey hash_add(tbl->hlist, &mh->mod_hdr_hlist, hash_key); 115b2fdf3d0SPaul Blakey mutex_unlock(&tbl->lock); 116b2fdf3d0SPaul Blakey 117b2fdf3d0SPaul Blakey mh->modify_hdr = mlx5_modify_header_alloc(mdev, namespace, 118b2fdf3d0SPaul Blakey mh->key.num_actions, 119b2fdf3d0SPaul Blakey mh->key.actions); 120b2fdf3d0SPaul Blakey if (IS_ERR(mh->modify_hdr)) { 121b2fdf3d0SPaul Blakey err = PTR_ERR(mh->modify_hdr); 122b2fdf3d0SPaul Blakey mh->compl_result = err; 123b2fdf3d0SPaul Blakey goto alloc_header_err; 124b2fdf3d0SPaul Blakey } 125b2fdf3d0SPaul Blakey mh->compl_result = 1; 126b2fdf3d0SPaul Blakey complete_all(&mh->res_ready); 127b2fdf3d0SPaul Blakey 128b2fdf3d0SPaul Blakey attach_header: 129b2fdf3d0SPaul Blakey return mh; 130b2fdf3d0SPaul Blakey 131b2fdf3d0SPaul Blakey alloc_header_err: 132b2fdf3d0SPaul Blakey complete_all(&mh->res_ready); 133b2fdf3d0SPaul Blakey attach_header_err: 134b2fdf3d0SPaul Blakey mlx5e_mod_hdr_detach(mdev, tbl, mh); 135b2fdf3d0SPaul Blakey return ERR_PTR(err); 136b2fdf3d0SPaul Blakey } 137b2fdf3d0SPaul Blakey 138b2fdf3d0SPaul Blakey void mlx5e_mod_hdr_detach(struct mlx5_core_dev *mdev, 139b2fdf3d0SPaul Blakey struct mod_hdr_tbl *tbl, 140b2fdf3d0SPaul Blakey struct mlx5e_mod_hdr_handle *mh) 141b2fdf3d0SPaul Blakey { 142b2fdf3d0SPaul Blakey if (!refcount_dec_and_mutex_lock(&mh->refcnt, &tbl->lock)) 143b2fdf3d0SPaul Blakey return; 144b2fdf3d0SPaul Blakey hash_del(&mh->mod_hdr_hlist); 145b2fdf3d0SPaul Blakey mutex_unlock(&tbl->lock); 146b2fdf3d0SPaul Blakey 147b2fdf3d0SPaul Blakey if (mh->compl_result > 0) 148b2fdf3d0SPaul Blakey mlx5_modify_header_dealloc(mdev, mh->modify_hdr); 149b2fdf3d0SPaul Blakey 150b2fdf3d0SPaul Blakey kfree(mh); 151b2fdf3d0SPaul Blakey } 152b2fdf3d0SPaul Blakey 153b2fdf3d0SPaul Blakey struct mlx5_modify_hdr *mlx5e_mod_hdr_get(struct mlx5e_mod_hdr_handle *mh) 154b2fdf3d0SPaul Blakey { 155b2fdf3d0SPaul Blakey return mh->modify_hdr; 156b2fdf3d0SPaul Blakey } 157b2fdf3d0SPaul Blakey 158*2c0e5cf5SPaul Blakey char * 159*2c0e5cf5SPaul Blakey mlx5e_mod_hdr_alloc(struct mlx5_core_dev *mdev, int namespace, 160*2c0e5cf5SPaul Blakey struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts) 161*2c0e5cf5SPaul Blakey { 162*2c0e5cf5SPaul Blakey int new_num_actions, max_hw_actions; 163*2c0e5cf5SPaul Blakey size_t new_sz, old_sz; 164*2c0e5cf5SPaul Blakey void *ret; 165*2c0e5cf5SPaul Blakey 166*2c0e5cf5SPaul Blakey if (mod_hdr_acts->num_actions < mod_hdr_acts->max_actions) 167*2c0e5cf5SPaul Blakey goto out; 168*2c0e5cf5SPaul Blakey 169*2c0e5cf5SPaul Blakey max_hw_actions = mlx5e_mod_hdr_max_actions(mdev, namespace); 170*2c0e5cf5SPaul Blakey new_num_actions = min(max_hw_actions, 171*2c0e5cf5SPaul Blakey mod_hdr_acts->actions ? 172*2c0e5cf5SPaul Blakey mod_hdr_acts->max_actions * 2 : 1); 173*2c0e5cf5SPaul Blakey if (mod_hdr_acts->max_actions == new_num_actions) 174*2c0e5cf5SPaul Blakey return ERR_PTR(-ENOSPC); 175*2c0e5cf5SPaul Blakey 176*2c0e5cf5SPaul Blakey new_sz = MLX5_MH_ACT_SZ * new_num_actions; 177*2c0e5cf5SPaul Blakey old_sz = mod_hdr_acts->max_actions * MLX5_MH_ACT_SZ; 178*2c0e5cf5SPaul Blakey 179*2c0e5cf5SPaul Blakey ret = krealloc(mod_hdr_acts->actions, new_sz, GFP_KERNEL); 180*2c0e5cf5SPaul Blakey if (!ret) 181*2c0e5cf5SPaul Blakey return ERR_PTR(-ENOMEM); 182*2c0e5cf5SPaul Blakey 183*2c0e5cf5SPaul Blakey memset(ret + old_sz, 0, new_sz - old_sz); 184*2c0e5cf5SPaul Blakey mod_hdr_acts->actions = ret; 185*2c0e5cf5SPaul Blakey mod_hdr_acts->max_actions = new_num_actions; 186*2c0e5cf5SPaul Blakey 187*2c0e5cf5SPaul Blakey out: 188*2c0e5cf5SPaul Blakey return mod_hdr_acts->actions + (mod_hdr_acts->num_actions * MLX5_MH_ACT_SZ); 189*2c0e5cf5SPaul Blakey } 190*2c0e5cf5SPaul Blakey 191*2c0e5cf5SPaul Blakey void 192*2c0e5cf5SPaul Blakey mlx5e_mod_hdr_dealloc(struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts) 193*2c0e5cf5SPaul Blakey { 194*2c0e5cf5SPaul Blakey kfree(mod_hdr_acts->actions); 195*2c0e5cf5SPaul Blakey mod_hdr_acts->actions = NULL; 196*2c0e5cf5SPaul Blakey mod_hdr_acts->num_actions = 0; 197*2c0e5cf5SPaul Blakey mod_hdr_acts->max_actions = 0; 198*2c0e5cf5SPaul Blakey } 199*2c0e5cf5SPaul Blakey 200*2c0e5cf5SPaul Blakey char * 201*2c0e5cf5SPaul Blakey mlx5e_mod_hdr_get_item(struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts, int pos) 202*2c0e5cf5SPaul Blakey { 203*2c0e5cf5SPaul Blakey return mod_hdr_acts->actions + (pos * MLX5_MH_ACT_SZ); 204*2c0e5cf5SPaul Blakey } 205