1c9da1ac1SSteen Hegelund // SPDX-License-Identifier: GPL-2.0+ 2c9da1ac1SSteen Hegelund /* Microchip VCAP API 3c9da1ac1SSteen Hegelund * 4c9da1ac1SSteen Hegelund * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5c9da1ac1SSteen Hegelund */ 6c9da1ac1SSteen Hegelund 7c9da1ac1SSteen Hegelund #include <linux/types.h> 8c9da1ac1SSteen Hegelund 9c9da1ac1SSteen Hegelund #include "vcap_api.h" 10c9da1ac1SSteen Hegelund #include "vcap_api_client.h" 11c9da1ac1SSteen Hegelund 12c9da1ac1SSteen Hegelund #define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data) 13c9da1ac1SSteen Hegelund 14c9da1ac1SSteen Hegelund /* Private VCAP API rule data */ 15c9da1ac1SSteen Hegelund struct vcap_rule_internal { 16c9da1ac1SSteen Hegelund struct vcap_rule data; /* provided by the client */ 17c9da1ac1SSteen Hegelund struct list_head list; /* for insertion in the vcap admin list of rules */ 18c9da1ac1SSteen Hegelund struct vcap_admin *admin; /* vcap hw instance */ 19c9da1ac1SSteen Hegelund struct net_device *ndev; /* the interface that the rule applies to */ 20c9da1ac1SSteen Hegelund struct vcap_control *vctrl; /* the client control */ 218e10490bSSteen Hegelund u32 sort_key; /* defines the position in the VCAP */ 228e10490bSSteen Hegelund int keyset_sw; /* subwords in a keyset */ 238e10490bSSteen Hegelund int actionset_sw; /* subwords in an actionset */ 248e10490bSSteen Hegelund int keyset_sw_regs; /* registers in a subword in an keyset */ 258e10490bSSteen Hegelund int actionset_sw_regs; /* registers in a subword in an actionset */ 268e10490bSSteen Hegelund int size; /* the size of the rule: max(entry, action) */ 27c9da1ac1SSteen Hegelund u32 addr; /* address in the VCAP at insertion */ 28c9da1ac1SSteen Hegelund }; 29c9da1ac1SSteen Hegelund 308e10490bSSteen Hegelund /* Moving a rule in the VCAP address space */ 318e10490bSSteen Hegelund struct vcap_rule_move { 328e10490bSSteen Hegelund int addr; /* address to move */ 338e10490bSSteen Hegelund int offset; /* change in address */ 348e10490bSSteen Hegelund int count; /* blocksize of addresses to move */ 358e10490bSSteen Hegelund }; 368e10490bSSteen Hegelund 37683e05c0SSteen Hegelund /* Bit iterator for the VCAP cache streams */ 38683e05c0SSteen Hegelund struct vcap_stream_iter { 39683e05c0SSteen Hegelund u32 offset; /* bit offset from the stream start */ 40683e05c0SSteen Hegelund u32 sw_width; /* subword width in bits */ 41683e05c0SSteen Hegelund u32 regs_per_sw; /* registers per subword */ 42683e05c0SSteen Hegelund u32 reg_idx; /* current register index */ 43683e05c0SSteen Hegelund u32 reg_bitpos; /* bit offset in current register */ 44683e05c0SSteen Hegelund const struct vcap_typegroup *tg; /* current typegroup */ 45683e05c0SSteen Hegelund }; 46683e05c0SSteen Hegelund 47683e05c0SSteen Hegelund static void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width, 48683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset) 49683e05c0SSteen Hegelund { 50683e05c0SSteen Hegelund memset(itr, 0, sizeof(*itr)); 51683e05c0SSteen Hegelund itr->offset = offset; 52683e05c0SSteen Hegelund itr->sw_width = sw_width; 53683e05c0SSteen Hegelund itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32); 54683e05c0SSteen Hegelund itr->tg = tg; 55683e05c0SSteen Hegelund } 56683e05c0SSteen Hegelund 57683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr) 58683e05c0SSteen Hegelund { 59683e05c0SSteen Hegelund /* Compensate the field offset for preceding typegroups. 60683e05c0SSteen Hegelund * A typegroup table ends with an all-zero terminator. 61683e05c0SSteen Hegelund */ 62683e05c0SSteen Hegelund while (itr->tg->width && itr->offset >= itr->tg->offset) { 63683e05c0SSteen Hegelund itr->offset += itr->tg->width; 64683e05c0SSteen Hegelund itr->tg++; /* next typegroup */ 65683e05c0SSteen Hegelund } 66683e05c0SSteen Hegelund } 67683e05c0SSteen Hegelund 68683e05c0SSteen Hegelund static void vcap_iter_update(struct vcap_stream_iter *itr) 69683e05c0SSteen Hegelund { 70683e05c0SSteen Hegelund int sw_idx, sw_bitpos; 71683e05c0SSteen Hegelund 72683e05c0SSteen Hegelund /* Calculate the subword index and bitposition for current bit */ 73683e05c0SSteen Hegelund sw_idx = itr->offset / itr->sw_width; 74683e05c0SSteen Hegelund sw_bitpos = itr->offset % itr->sw_width; 75683e05c0SSteen Hegelund /* Calculate the register index and bitposition for current bit */ 76683e05c0SSteen Hegelund itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32); 77683e05c0SSteen Hegelund itr->reg_bitpos = sw_bitpos % 32; 78683e05c0SSteen Hegelund } 79683e05c0SSteen Hegelund 80683e05c0SSteen Hegelund static void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width, 81683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset) 82683e05c0SSteen Hegelund { 83683e05c0SSteen Hegelund vcap_iter_set(itr, sw_width, tg, offset); 84683e05c0SSteen Hegelund vcap_iter_skip_tg(itr); 85683e05c0SSteen Hegelund vcap_iter_update(itr); 86683e05c0SSteen Hegelund } 87683e05c0SSteen Hegelund 88683e05c0SSteen Hegelund static void vcap_iter_next(struct vcap_stream_iter *itr) 89683e05c0SSteen Hegelund { 90683e05c0SSteen Hegelund itr->offset++; 91683e05c0SSteen Hegelund vcap_iter_skip_tg(itr); 92683e05c0SSteen Hegelund vcap_iter_update(itr); 93683e05c0SSteen Hegelund } 94683e05c0SSteen Hegelund 95683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value) 96683e05c0SSteen Hegelund { 97683e05c0SSteen Hegelund u32 mask = BIT(itr->reg_bitpos); 98683e05c0SSteen Hegelund u32 *p = &stream[itr->reg_idx]; 99683e05c0SSteen Hegelund 100683e05c0SSteen Hegelund if (value) 101683e05c0SSteen Hegelund *p |= mask; 102683e05c0SSteen Hegelund else 103683e05c0SSteen Hegelund *p &= ~mask; 104683e05c0SSteen Hegelund } 105683e05c0SSteen Hegelund 106683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val) 107683e05c0SSteen Hegelund { 108683e05c0SSteen Hegelund /* When intersected by a type group field, stream the type group bits 109683e05c0SSteen Hegelund * before continuing with the value bit 110683e05c0SSteen Hegelund */ 111683e05c0SSteen Hegelund while (itr->tg->width && 112683e05c0SSteen Hegelund itr->offset >= itr->tg->offset && 113683e05c0SSteen Hegelund itr->offset < itr->tg->offset + itr->tg->width) { 114683e05c0SSteen Hegelund int tg_bitpos = itr->tg->offset - itr->offset; 115683e05c0SSteen Hegelund 116683e05c0SSteen Hegelund vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1); 117683e05c0SSteen Hegelund itr->offset++; 118683e05c0SSteen Hegelund vcap_iter_update(itr); 119683e05c0SSteen Hegelund } 120683e05c0SSteen Hegelund vcap_set_bit(stream, itr, val); 121683e05c0SSteen Hegelund } 122683e05c0SSteen Hegelund 123683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr, 124683e05c0SSteen Hegelund int width, const u8 *value) 125683e05c0SSteen Hegelund { 126683e05c0SSteen Hegelund int idx; 127683e05c0SSteen Hegelund 128683e05c0SSteen Hegelund /* Loop over the field value bits and add the value bits one by one to 129683e05c0SSteen Hegelund * the output stream. 130683e05c0SSteen Hegelund */ 131683e05c0SSteen Hegelund for (idx = 0; idx < width; idx++) { 132683e05c0SSteen Hegelund u8 bidx = idx & GENMASK(2, 0); 133683e05c0SSteen Hegelund 134683e05c0SSteen Hegelund /* Encode one field value bit */ 135683e05c0SSteen Hegelund vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1); 136683e05c0SSteen Hegelund vcap_iter_next(itr); 137683e05c0SSteen Hegelund } 138683e05c0SSteen Hegelund } 139683e05c0SSteen Hegelund 140683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width, 141683e05c0SSteen Hegelund const struct vcap_typegroup *tg, 142683e05c0SSteen Hegelund bool mask) 143683e05c0SSteen Hegelund { 144683e05c0SSteen Hegelund struct vcap_stream_iter iter; 145683e05c0SSteen Hegelund int idx; 146683e05c0SSteen Hegelund 147683e05c0SSteen Hegelund /* Mask bits must be set to zeros (inverted later when writing to the 148683e05c0SSteen Hegelund * mask cache register), so that the mask typegroup bits consist of 149683e05c0SSteen Hegelund * match-1 or match-0, or both 150683e05c0SSteen Hegelund */ 151683e05c0SSteen Hegelund vcap_iter_set(&iter, sw_width, tg, 0); 152683e05c0SSteen Hegelund while (iter.tg->width) { 153683e05c0SSteen Hegelund /* Set position to current typegroup bit */ 154683e05c0SSteen Hegelund iter.offset = iter.tg->offset; 155683e05c0SSteen Hegelund vcap_iter_update(&iter); 156683e05c0SSteen Hegelund for (idx = 0; idx < iter.tg->width; idx++) { 157683e05c0SSteen Hegelund /* Iterate over current typegroup bits. Mask typegroup 158683e05c0SSteen Hegelund * bits are always set 159683e05c0SSteen Hegelund */ 160683e05c0SSteen Hegelund if (mask) 161683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 0x1); 162683e05c0SSteen Hegelund else 163683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 164683e05c0SSteen Hegelund (iter.tg->value >> idx) & 0x1); 165683e05c0SSteen Hegelund iter.offset++; 166683e05c0SSteen Hegelund vcap_iter_update(&iter); 167683e05c0SSteen Hegelund } 168683e05c0SSteen Hegelund iter.tg++; /* next typegroup */ 169683e05c0SSteen Hegelund } 170683e05c0SSteen Hegelund } 171683e05c0SSteen Hegelund 17246be056eSSteen Hegelund /* Return the list of keyfields for the keyset */ 17346be056eSSteen Hegelund static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl, 17446be056eSSteen Hegelund enum vcap_type vt, 17546be056eSSteen Hegelund enum vcap_keyfield_set keyset) 17646be056eSSteen Hegelund { 17746be056eSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 17846be056eSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 17946be056eSSteen Hegelund return NULL; 18046be056eSSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map[keyset]; 18146be056eSSteen Hegelund } 18246be056eSSteen Hegelund 1838e10490bSSteen Hegelund /* Return the keyset information for the keyset */ 1848e10490bSSteen Hegelund static const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl, 1858e10490bSSteen Hegelund enum vcap_type vt, 1868e10490bSSteen Hegelund enum vcap_keyfield_set keyset) 1878e10490bSSteen Hegelund { 1888e10490bSSteen Hegelund const struct vcap_set *kset; 1898e10490bSSteen Hegelund 1908e10490bSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 1918e10490bSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 1928e10490bSSteen Hegelund return NULL; 1938e10490bSSteen Hegelund kset = &vctrl->vcaps[vt].keyfield_set[keyset]; 1948e10490bSSteen Hegelund if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count) 1958e10490bSSteen Hegelund return NULL; 1968e10490bSSteen Hegelund return kset; 1978e10490bSSteen Hegelund } 1988e10490bSSteen Hegelund 199683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */ 200683e05c0SSteen Hegelund static const struct vcap_typegroup * 201683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl, 202683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset) 203683e05c0SSteen Hegelund { 204683e05c0SSteen Hegelund const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset); 205683e05c0SSteen Hegelund 206683e05c0SSteen Hegelund /* Check that the keyset is valid */ 207683e05c0SSteen Hegelund if (!kset) 208683e05c0SSteen Hegelund return NULL; 209683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item]; 210683e05c0SSteen Hegelund } 211683e05c0SSteen Hegelund 212683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */ 213683e05c0SSteen Hegelund static int vcap_keyfield_count(struct vcap_control *vctrl, 214683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset) 215683e05c0SSteen Hegelund { 216683e05c0SSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 217683e05c0SSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 218683e05c0SSteen Hegelund return 0; 219683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map_size[keyset]; 220683e05c0SSteen Hegelund } 221683e05c0SSteen Hegelund 222683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri, 223683e05c0SSteen Hegelund const struct vcap_client_keyfield *kf, 224683e05c0SSteen Hegelund const struct vcap_field *rf, 225683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 226683e05c0SSteen Hegelund { 227683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; 228683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 229683e05c0SSteen Hegelund struct vcap_stream_iter iter; 230683e05c0SSteen Hegelund const u8 *value, *mask; 231683e05c0SSteen Hegelund 232683e05c0SSteen Hegelund /* Encode the fields for the key and the mask in their respective 233683e05c0SSteen Hegelund * streams, respecting the subword width. 234683e05c0SSteen Hegelund */ 235683e05c0SSteen Hegelund switch (kf->ctrl.type) { 236683e05c0SSteen Hegelund case VCAP_FIELD_BIT: 237683e05c0SSteen Hegelund value = &kf->data.u1.value; 238683e05c0SSteen Hegelund mask = &kf->data.u1.mask; 239683e05c0SSteen Hegelund break; 240683e05c0SSteen Hegelund case VCAP_FIELD_U32: 241683e05c0SSteen Hegelund value = (const u8 *)&kf->data.u32.value; 242683e05c0SSteen Hegelund mask = (const u8 *)&kf->data.u32.mask; 243683e05c0SSteen Hegelund break; 244683e05c0SSteen Hegelund case VCAP_FIELD_U48: 245683e05c0SSteen Hegelund value = kf->data.u48.value; 246683e05c0SSteen Hegelund mask = kf->data.u48.mask; 247683e05c0SSteen Hegelund break; 248683e05c0SSteen Hegelund case VCAP_FIELD_U56: 249683e05c0SSteen Hegelund value = kf->data.u56.value; 250683e05c0SSteen Hegelund mask = kf->data.u56.mask; 251683e05c0SSteen Hegelund break; 252683e05c0SSteen Hegelund case VCAP_FIELD_U64: 253683e05c0SSteen Hegelund value = kf->data.u64.value; 254683e05c0SSteen Hegelund mask = kf->data.u64.mask; 255683e05c0SSteen Hegelund break; 256683e05c0SSteen Hegelund case VCAP_FIELD_U72: 257683e05c0SSteen Hegelund value = kf->data.u72.value; 258683e05c0SSteen Hegelund mask = kf->data.u72.mask; 259683e05c0SSteen Hegelund break; 260683e05c0SSteen Hegelund case VCAP_FIELD_U112: 261683e05c0SSteen Hegelund value = kf->data.u112.value; 262683e05c0SSteen Hegelund mask = kf->data.u112.mask; 263683e05c0SSteen Hegelund break; 264683e05c0SSteen Hegelund case VCAP_FIELD_U128: 265683e05c0SSteen Hegelund value = kf->data.u128.value; 266683e05c0SSteen Hegelund mask = kf->data.u128.mask; 267683e05c0SSteen Hegelund break; 268683e05c0SSteen Hegelund } 269683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset); 270683e05c0SSteen Hegelund vcap_encode_field(cache->keystream, &iter, rf->width, value); 271683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset); 272683e05c0SSteen Hegelund vcap_encode_field(cache->maskstream, &iter, rf->width, mask); 273683e05c0SSteen Hegelund } 274683e05c0SSteen Hegelund 275683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl, 276683e05c0SSteen Hegelund struct vcap_rule_internal *ri, 277683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 278683e05c0SSteen Hegelund { 279683e05c0SSteen Hegelund int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width; 280683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 281683e05c0SSteen Hegelund 282683e05c0SSteen Hegelund /* Encode the typegroup bits for the key and the mask in their streams, 283683e05c0SSteen Hegelund * respecting the subword width. 284683e05c0SSteen Hegelund */ 285683e05c0SSteen Hegelund vcap_encode_typegroups(cache->keystream, sw_width, tgt, false); 286683e05c0SSteen Hegelund vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true); 287683e05c0SSteen Hegelund } 288683e05c0SSteen Hegelund 289683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri) 290683e05c0SSteen Hegelund { 291683e05c0SSteen Hegelund const struct vcap_client_keyfield *ckf; 292683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table; 293683e05c0SSteen Hegelund const struct vcap_field *kf_table; 294683e05c0SSteen Hegelund int keyset_size; 295683e05c0SSteen Hegelund 296683e05c0SSteen Hegelund /* Get a valid set of fields for the specific keyset */ 297683e05c0SSteen Hegelund kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset); 298683e05c0SSteen Hegelund if (!kf_table) { 299683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this keyset: %d\n", 300683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 301683e05c0SSteen Hegelund return -EINVAL; 302683e05c0SSteen Hegelund } 303683e05c0SSteen Hegelund /* Get a valid typegroup for the specific keyset */ 304683e05c0SSteen Hegelund tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype, 305683e05c0SSteen Hegelund ri->data.keyset); 306683e05c0SSteen Hegelund if (!tg_table) { 307683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this keyset: %d\n", 308683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 309683e05c0SSteen Hegelund return -EINVAL; 310683e05c0SSteen Hegelund } 311683e05c0SSteen Hegelund /* Get a valid size for the specific keyset */ 312683e05c0SSteen Hegelund keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype, 313683e05c0SSteen Hegelund ri->data.keyset); 314683e05c0SSteen Hegelund if (keyset_size == 0) { 315683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this keyset: %d\n", 316683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 317683e05c0SSteen Hegelund return -EINVAL; 318683e05c0SSteen Hegelund } 319683e05c0SSteen Hegelund /* Iterate over the keyfields (key, mask) in the rule 320683e05c0SSteen Hegelund * and encode these bits 321683e05c0SSteen Hegelund */ 322683e05c0SSteen Hegelund if (list_empty(&ri->data.keyfields)) { 323683e05c0SSteen Hegelund pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__); 324683e05c0SSteen Hegelund return -EINVAL; 325683e05c0SSteen Hegelund } 326683e05c0SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 327683e05c0SSteen Hegelund /* Check that the client entry exists in the keyset */ 328683e05c0SSteen Hegelund if (ckf->ctrl.key >= keyset_size) { 329683e05c0SSteen Hegelund pr_err("%s:%d: key %d is not in vcap\n", 330683e05c0SSteen Hegelund __func__, __LINE__, ckf->ctrl.key); 331683e05c0SSteen Hegelund return -EINVAL; 332683e05c0SSteen Hegelund } 333683e05c0SSteen Hegelund vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table); 334683e05c0SSteen Hegelund } 335683e05c0SSteen Hegelund /* Add typegroup bits to the key/mask bitstreams */ 336683e05c0SSteen Hegelund vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table); 337683e05c0SSteen Hegelund return 0; 338683e05c0SSteen Hegelund } 339683e05c0SSteen Hegelund 340683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */ 341683e05c0SSteen Hegelund static const struct vcap_field * 342683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl, 343683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 344683e05c0SSteen Hegelund { 345683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 346683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 347683e05c0SSteen Hegelund return NULL; 348683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map[actionset]; 349683e05c0SSteen Hegelund } 350683e05c0SSteen Hegelund 3518e10490bSSteen Hegelund static const struct vcap_set * 3528e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl, 3538e10490bSSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 3548e10490bSSteen Hegelund { 3558e10490bSSteen Hegelund const struct vcap_set *aset; 3568e10490bSSteen Hegelund 3578e10490bSSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 3588e10490bSSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 3598e10490bSSteen Hegelund return NULL; 3608e10490bSSteen Hegelund aset = &vctrl->vcaps[vt].actionfield_set[actionset]; 3618e10490bSSteen Hegelund if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count) 3628e10490bSSteen Hegelund return NULL; 3638e10490bSSteen Hegelund return aset; 3648e10490bSSteen Hegelund } 3658e10490bSSteen Hegelund 366683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */ 367683e05c0SSteen Hegelund static const struct vcap_typegroup * 368683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl, 369683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 370683e05c0SSteen Hegelund { 371683e05c0SSteen Hegelund const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset); 372683e05c0SSteen Hegelund 373683e05c0SSteen Hegelund /* Check that the actionset is valid */ 374683e05c0SSteen Hegelund if (!aset) 375683e05c0SSteen Hegelund return NULL; 376683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item]; 377683e05c0SSteen Hegelund } 378683e05c0SSteen Hegelund 379683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */ 380683e05c0SSteen Hegelund static int vcap_actionfield_count(struct vcap_control *vctrl, 381683e05c0SSteen Hegelund enum vcap_type vt, 382683e05c0SSteen Hegelund enum vcap_actionfield_set actionset) 383683e05c0SSteen Hegelund { 384683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 385683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 386683e05c0SSteen Hegelund return 0; 387683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map_size[actionset]; 388683e05c0SSteen Hegelund } 389683e05c0SSteen Hegelund 390683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri, 391683e05c0SSteen Hegelund const struct vcap_client_actionfield *af, 392683e05c0SSteen Hegelund const struct vcap_field *rf, 393683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 394683e05c0SSteen Hegelund { 395683e05c0SSteen Hegelund int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 396683e05c0SSteen Hegelund 397683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 398683e05c0SSteen Hegelund struct vcap_stream_iter iter; 399683e05c0SSteen Hegelund const u8 *value; 400683e05c0SSteen Hegelund 401683e05c0SSteen Hegelund /* Encode the action field in the stream, respecting the subword width */ 402683e05c0SSteen Hegelund switch (af->ctrl.type) { 403683e05c0SSteen Hegelund case VCAP_FIELD_BIT: 404683e05c0SSteen Hegelund value = &af->data.u1.value; 405683e05c0SSteen Hegelund break; 406683e05c0SSteen Hegelund case VCAP_FIELD_U32: 407683e05c0SSteen Hegelund value = (const u8 *)&af->data.u32.value; 408683e05c0SSteen Hegelund break; 409683e05c0SSteen Hegelund case VCAP_FIELD_U48: 410683e05c0SSteen Hegelund value = af->data.u48.value; 411683e05c0SSteen Hegelund break; 412683e05c0SSteen Hegelund case VCAP_FIELD_U56: 413683e05c0SSteen Hegelund value = af->data.u56.value; 414683e05c0SSteen Hegelund break; 415683e05c0SSteen Hegelund case VCAP_FIELD_U64: 416683e05c0SSteen Hegelund value = af->data.u64.value; 417683e05c0SSteen Hegelund break; 418683e05c0SSteen Hegelund case VCAP_FIELD_U72: 419683e05c0SSteen Hegelund value = af->data.u72.value; 420683e05c0SSteen Hegelund break; 421683e05c0SSteen Hegelund case VCAP_FIELD_U112: 422683e05c0SSteen Hegelund value = af->data.u112.value; 423683e05c0SSteen Hegelund break; 424683e05c0SSteen Hegelund case VCAP_FIELD_U128: 425683e05c0SSteen Hegelund value = af->data.u128.value; 426683e05c0SSteen Hegelund break; 427683e05c0SSteen Hegelund } 428683e05c0SSteen Hegelund vcap_iter_init(&iter, act_width, tgt, rf->offset); 429683e05c0SSteen Hegelund vcap_encode_field(cache->actionstream, &iter, rf->width, value); 430683e05c0SSteen Hegelund } 431683e05c0SSteen Hegelund 432683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri, 433683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 434683e05c0SSteen Hegelund { 435683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 436683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 437683e05c0SSteen Hegelund 438683e05c0SSteen Hegelund /* Encode the typegroup bits for the actionstream respecting the subword 439683e05c0SSteen Hegelund * width. 440683e05c0SSteen Hegelund */ 441683e05c0SSteen Hegelund vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false); 442683e05c0SSteen Hegelund } 443683e05c0SSteen Hegelund 444683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri) 445683e05c0SSteen Hegelund { 446683e05c0SSteen Hegelund const struct vcap_client_actionfield *caf; 447683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table; 448683e05c0SSteen Hegelund const struct vcap_field *af_table; 449683e05c0SSteen Hegelund int actionset_size; 450683e05c0SSteen Hegelund 451683e05c0SSteen Hegelund /* Get a valid set of actionset fields for the specific actionset */ 452683e05c0SSteen Hegelund af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype, 453683e05c0SSteen Hegelund ri->data.actionset); 454683e05c0SSteen Hegelund if (!af_table) { 455683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this actionset: %d\n", 456683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 457683e05c0SSteen Hegelund return -EINVAL; 458683e05c0SSteen Hegelund } 459683e05c0SSteen Hegelund /* Get a valid typegroup for the specific actionset */ 460683e05c0SSteen Hegelund tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype, 461683e05c0SSteen Hegelund ri->data.actionset); 462683e05c0SSteen Hegelund if (!tg_table) { 463683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this actionset: %d\n", 464683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 465683e05c0SSteen Hegelund return -EINVAL; 466683e05c0SSteen Hegelund } 467683e05c0SSteen Hegelund /* Get a valid actionset size for the specific actionset */ 468683e05c0SSteen Hegelund actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype, 469683e05c0SSteen Hegelund ri->data.actionset); 470683e05c0SSteen Hegelund if (actionset_size == 0) { 471683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this actionset: %d\n", 472683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 473683e05c0SSteen Hegelund return -EINVAL; 474683e05c0SSteen Hegelund } 475683e05c0SSteen Hegelund /* Iterate over the actionfields in the rule 476683e05c0SSteen Hegelund * and encode these bits 477683e05c0SSteen Hegelund */ 478683e05c0SSteen Hegelund if (list_empty(&ri->data.actionfields)) 479683e05c0SSteen Hegelund pr_warn("%s:%d: no actionfields in the rule\n", 480683e05c0SSteen Hegelund __func__, __LINE__); 481683e05c0SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 482683e05c0SSteen Hegelund /* Check that the client action exists in the actionset */ 483683e05c0SSteen Hegelund if (caf->ctrl.action >= actionset_size) { 484683e05c0SSteen Hegelund pr_err("%s:%d: action %d is not in vcap\n", 485683e05c0SSteen Hegelund __func__, __LINE__, caf->ctrl.action); 486683e05c0SSteen Hegelund return -EINVAL; 487683e05c0SSteen Hegelund } 488683e05c0SSteen Hegelund vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action], 489683e05c0SSteen Hegelund tg_table); 490683e05c0SSteen Hegelund } 491683e05c0SSteen Hegelund /* Add typegroup bits to the entry bitstreams */ 492683e05c0SSteen Hegelund vcap_encode_actionfield_typegroups(ri, tg_table); 493683e05c0SSteen Hegelund return 0; 494683e05c0SSteen Hegelund } 495683e05c0SSteen Hegelund 4968e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri) 4978e10490bSSteen Hegelund { 498683e05c0SSteen Hegelund int err; 499683e05c0SSteen Hegelund 500683e05c0SSteen Hegelund err = vcap_encode_rule_keyset(ri); 501683e05c0SSteen Hegelund if (err) 502683e05c0SSteen Hegelund return err; 503683e05c0SSteen Hegelund err = vcap_encode_rule_actionset(ri); 504683e05c0SSteen Hegelund if (err) 505683e05c0SSteen Hegelund return err; 5068e10490bSSteen Hegelund return 0; 5078e10490bSSteen Hegelund } 5088e10490bSSteen Hegelund 5098e10490bSSteen Hegelund static int vcap_api_check(struct vcap_control *ctrl) 5108e10490bSSteen Hegelund { 5118e10490bSSteen Hegelund if (!ctrl) { 5128e10490bSSteen Hegelund pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__); 5138e10490bSSteen Hegelund return -EINVAL; 5148e10490bSSteen Hegelund } 5158e10490bSSteen Hegelund if (!ctrl->ops || !ctrl->ops->validate_keyset || 5168e10490bSSteen Hegelund !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase || 5178e10490bSSteen Hegelund !ctrl->ops->cache_write || !ctrl->ops->cache_read || 5188e10490bSSteen Hegelund !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move || 5198e10490bSSteen Hegelund !ctrl->ops->port_info) { 5208e10490bSSteen Hegelund pr_err("%s:%d: client operations are missing\n", 5218e10490bSSteen Hegelund __func__, __LINE__); 5228e10490bSSteen Hegelund return -ENOENT; 5238e10490bSSteen Hegelund } 5248e10490bSSteen Hegelund return 0; 5258e10490bSSteen Hegelund } 5268e10490bSSteen Hegelund 5278e10490bSSteen Hegelund static void vcap_erase_cache(struct vcap_rule_internal *ri) 5288e10490bSSteen Hegelund { 5298e10490bSSteen Hegelund ri->vctrl->ops->cache_erase(ri->admin); 5308e10490bSSteen Hegelund } 5318e10490bSSteen Hegelund 532c9da1ac1SSteen Hegelund /* Update the keyset for the rule */ 533c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule, 534c9da1ac1SSteen Hegelund enum vcap_keyfield_set keyset) 535c9da1ac1SSteen Hegelund { 5368e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 5378e10490bSSteen Hegelund const struct vcap_set *kset; 5388e10490bSSteen Hegelund int sw_width; 5398e10490bSSteen Hegelund 5408e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset); 5418e10490bSSteen Hegelund /* Check that the keyset is valid */ 5428e10490bSSteen Hegelund if (!kset) 5438e10490bSSteen Hegelund return -EINVAL; 5448e10490bSSteen Hegelund ri->keyset_sw = kset->sw_per_item; 5458e10490bSSteen Hegelund sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; 5468e10490bSSteen Hegelund ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32); 5478e10490bSSteen Hegelund ri->data.keyset = keyset; 548c9da1ac1SSteen Hegelund return 0; 549c9da1ac1SSteen Hegelund } 550c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset); 551c9da1ac1SSteen Hegelund 552c9da1ac1SSteen Hegelund /* Update the actionset for the rule */ 553c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule, 554c9da1ac1SSteen Hegelund enum vcap_actionfield_set actionset) 555c9da1ac1SSteen Hegelund { 5568e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 5578e10490bSSteen Hegelund const struct vcap_set *aset; 5588e10490bSSteen Hegelund int act_width; 5598e10490bSSteen Hegelund 5608e10490bSSteen Hegelund aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset); 5618e10490bSSteen Hegelund /* Check that the actionset is valid */ 5628e10490bSSteen Hegelund if (!aset) 5638e10490bSSteen Hegelund return -EINVAL; 5648e10490bSSteen Hegelund ri->actionset_sw = aset->sw_per_item; 5658e10490bSSteen Hegelund act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 5668e10490bSSteen Hegelund ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32); 5678e10490bSSteen Hegelund ri->data.actionset = actionset; 568c9da1ac1SSteen Hegelund return 0; 569c9da1ac1SSteen Hegelund } 570c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset); 571c9da1ac1SSteen Hegelund 572c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */ 573c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl, 574c9da1ac1SSteen Hegelund u32 id) 575c9da1ac1SSteen Hegelund { 576c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 577c9da1ac1SSteen Hegelund struct vcap_admin *admin; 578c9da1ac1SSteen Hegelund 579c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 580c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 581c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 582c9da1ac1SSteen Hegelund if (ri->data.id == id) 583c9da1ac1SSteen Hegelund return ri; 584c9da1ac1SSteen Hegelund return NULL; 585c9da1ac1SSteen Hegelund } 586c9da1ac1SSteen Hegelund 587c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */ 588c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie) 589c9da1ac1SSteen Hegelund { 590c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 591c9da1ac1SSteen Hegelund struct vcap_admin *admin; 592c9da1ac1SSteen Hegelund 593c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 594c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 595c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 596c9da1ac1SSteen Hegelund if (ri->data.cookie == cookie) 597c9da1ac1SSteen Hegelund return ri->data.id; 598c9da1ac1SSteen Hegelund return -ENOENT; 599c9da1ac1SSteen Hegelund } 600c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); 601c9da1ac1SSteen Hegelund 6028e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */ 6038e10490bSSteen Hegelund static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri) 6048e10490bSSteen Hegelund { 6058e10490bSSteen Hegelund struct vcap_rule_internal *duprule; 6068e10490bSSteen Hegelund 6078e10490bSSteen Hegelund /* Allocate the client part */ 6088e10490bSSteen Hegelund duprule = kzalloc(sizeof(*duprule), GFP_KERNEL); 6098e10490bSSteen Hegelund if (!duprule) 6108e10490bSSteen Hegelund return ERR_PTR(-ENOMEM); 6118e10490bSSteen Hegelund *duprule = *ri; 6128e10490bSSteen Hegelund /* Not inserted in the VCAP */ 6138e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->list); 6148e10490bSSteen Hegelund /* No elements in these lists */ 6158e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.keyfields); 6168e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.actionfields); 6178e10490bSSteen Hegelund return duprule; 6188e10490bSSteen Hegelund } 6198e10490bSSteen Hegelund 6208e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */ 6218e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri) 6228e10490bSSteen Hegelund { 6238e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin; 6248e10490bSSteen Hegelund int sw_idx, ent_idx = 0, act_idx = 0; 6258e10490bSSteen Hegelund u32 addr = ri->addr; 6268e10490bSSteen Hegelund 6278e10490bSSteen Hegelund if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) { 6288e10490bSSteen Hegelund pr_err("%s:%d: rule is empty\n", __func__, __LINE__); 6298e10490bSSteen Hegelund return -EINVAL; 6308e10490bSSteen Hegelund } 6318e10490bSSteen Hegelund /* Use the values in the streams to write the VCAP cache */ 6328e10490bSSteen Hegelund for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) { 6338e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, 6348e10490bSSteen Hegelund VCAP_SEL_ENTRY, ent_idx, 6358e10490bSSteen Hegelund ri->keyset_sw_regs); 6368e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, 6378e10490bSSteen Hegelund VCAP_SEL_ACTION, act_idx, 6388e10490bSSteen Hegelund ri->actionset_sw_regs); 6398e10490bSSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE, 6408e10490bSSteen Hegelund VCAP_SEL_ALL, addr); 6418e10490bSSteen Hegelund ent_idx += ri->keyset_sw_regs; 6428e10490bSSteen Hegelund act_idx += ri->actionset_sw_regs; 6438e10490bSSteen Hegelund } 6448e10490bSSteen Hegelund return 0; 6458e10490bSSteen Hegelund } 6468e10490bSSteen Hegelund 6477de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */ 6487de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid) 6497de1dcadSSteen Hegelund { 6507de1dcadSSteen Hegelund int lookup_first = admin->vinst * admin->lookups_per_instance; 6517de1dcadSSteen Hegelund int lookup_last = lookup_first + admin->lookups_per_instance; 6527de1dcadSSteen Hegelund int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE; 6537de1dcadSSteen Hegelund int cid = admin->first_cid; 6547de1dcadSSteen Hegelund int lookup; 6557de1dcadSSteen Hegelund 6567de1dcadSSteen Hegelund for (lookup = lookup_first; lookup < lookup_last; ++lookup, 6577de1dcadSSteen Hegelund cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE) 6587de1dcadSSteen Hegelund if (cur_cid >= cid && cur_cid < cid_next) 6597de1dcadSSteen Hegelund return lookup; 6607de1dcadSSteen Hegelund return 0; 6617de1dcadSSteen Hegelund } 6627de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup); 6637de1dcadSSteen Hegelund 664c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */ 665c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) 666c9da1ac1SSteen Hegelund { 667c9da1ac1SSteen Hegelund struct vcap_admin *admin; 668c9da1ac1SSteen Hegelund 6698e10490bSSteen Hegelund if (vcap_api_check(vctrl)) 6708e10490bSSteen Hegelund return NULL; 6718e10490bSSteen Hegelund 672c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) { 673c9da1ac1SSteen Hegelund if (cid >= admin->first_cid && cid <= admin->last_cid) 674c9da1ac1SSteen Hegelund return admin; 675c9da1ac1SSteen Hegelund } 676c9da1ac1SSteen Hegelund return NULL; 677c9da1ac1SSteen Hegelund } 678c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin); 679c9da1ac1SSteen Hegelund 680392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */ 681392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid) 682392d0ab0SSteen Hegelund { 683392d0ab0SSteen Hegelund struct vcap_admin *admin, *next_admin; 684392d0ab0SSteen Hegelund int lookup, next_lookup; 685392d0ab0SSteen Hegelund 686392d0ab0SSteen Hegelund /* The offset must be at least one lookup */ 687392d0ab0SSteen Hegelund if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE) 688392d0ab0SSteen Hegelund return false; 689392d0ab0SSteen Hegelund 690392d0ab0SSteen Hegelund if (vcap_api_check(vctrl)) 691392d0ab0SSteen Hegelund return false; 692392d0ab0SSteen Hegelund 693392d0ab0SSteen Hegelund admin = vcap_find_admin(vctrl, cur_cid); 694392d0ab0SSteen Hegelund if (!admin) 695392d0ab0SSteen Hegelund return false; 696392d0ab0SSteen Hegelund 697392d0ab0SSteen Hegelund /* If no VCAP contains the next chain, the next chain must be beyond 698392d0ab0SSteen Hegelund * the last chain in the current VCAP 699392d0ab0SSteen Hegelund */ 700392d0ab0SSteen Hegelund next_admin = vcap_find_admin(vctrl, next_cid); 701392d0ab0SSteen Hegelund if (!next_admin) 702392d0ab0SSteen Hegelund return next_cid > admin->last_cid; 703392d0ab0SSteen Hegelund 704392d0ab0SSteen Hegelund lookup = vcap_chain_id_to_lookup(admin, cur_cid); 705392d0ab0SSteen Hegelund next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid); 706392d0ab0SSteen Hegelund 707392d0ab0SSteen Hegelund /* Next lookup must be the following lookup */ 708392d0ab0SSteen Hegelund if (admin == next_admin || admin->vtype == next_admin->vtype) 709392d0ab0SSteen Hegelund return next_lookup == lookup + 1; 710392d0ab0SSteen Hegelund 711392d0ab0SSteen Hegelund /* Must be the first lookup in the next VCAP instance */ 712392d0ab0SSteen Hegelund return next_lookup == 0; 713392d0ab0SSteen Hegelund } 714392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup); 715392d0ab0SSteen Hegelund 7168e10490bSSteen Hegelund /* Check if there is room for a new rule */ 7178e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size) 7188e10490bSSteen Hegelund { 7198e10490bSSteen Hegelund if (admin->last_used_addr - size < admin->first_valid_addr) { 7208e10490bSSteen Hegelund pr_err("%s:%d: No room for rule size: %u, %u\n", 7218e10490bSSteen Hegelund __func__, __LINE__, size, admin->first_valid_addr); 7228e10490bSSteen Hegelund return -ENOSPC; 7238e10490bSSteen Hegelund } 7248e10490bSSteen Hegelund return 0; 7258e10490bSSteen Hegelund } 7268e10490bSSteen Hegelund 7278e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */ 7288e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule) 7298e10490bSSteen Hegelund { 7308e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 7318e10490bSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 7328e10490bSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 7338e10490bSSteen Hegelund const struct vcap_field *fields; 7348e10490bSSteen Hegelund const struct vcap_set *kset; 7358e10490bSSteen Hegelund int ret = -EINVAL; 7368e10490bSSteen Hegelund 7378e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, vt, keyset); 7388e10490bSSteen Hegelund if (!kset) 7398e10490bSSteen Hegelund return ret; 7408e10490bSSteen Hegelund if (kset->type_id == (u8)-1) /* No type field is needed */ 7418e10490bSSteen Hegelund return 0; 7428e10490bSSteen Hegelund 7438e10490bSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 7448e10490bSSteen Hegelund if (!fields) 7458e10490bSSteen Hegelund return -EINVAL; 7468e10490bSSteen Hegelund if (fields[VCAP_KF_TYPE].width > 1) { 7478e10490bSSteen Hegelund ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 7488e10490bSSteen Hegelund kset->type_id, 0xff); 7498e10490bSSteen Hegelund } else { 7508e10490bSSteen Hegelund if (kset->type_id) 7518e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, 7528e10490bSSteen Hegelund VCAP_BIT_1); 7538e10490bSSteen Hegelund else 7548e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, 7558e10490bSSteen Hegelund VCAP_BIT_0); 7568e10490bSSteen Hegelund } 7578e10490bSSteen Hegelund return 0; 7588e10490bSSteen Hegelund } 7598e10490bSSteen Hegelund 760*abc4010dSSteen Hegelund /* Add a keyset to a keyset list */ 761*abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist, 762*abc4010dSSteen Hegelund enum vcap_keyfield_set keyset) 763*abc4010dSSteen Hegelund { 764*abc4010dSSteen Hegelund int idx; 765*abc4010dSSteen Hegelund 766*abc4010dSSteen Hegelund if (keysetlist->cnt < keysetlist->max) { 767*abc4010dSSteen Hegelund /* Avoid duplicates */ 768*abc4010dSSteen Hegelund for (idx = 0; idx < keysetlist->cnt; ++idx) 769*abc4010dSSteen Hegelund if (keysetlist->keysets[idx] == keyset) 770*abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max; 771*abc4010dSSteen Hegelund keysetlist->keysets[keysetlist->cnt++] = keyset; 772*abc4010dSSteen Hegelund } 773*abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max; 774*abc4010dSSteen Hegelund } 775*abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add); 776*abc4010dSSteen Hegelund 777*abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */ 778*abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl, 779*abc4010dSSteen Hegelund enum vcap_keyfield_set keyset) 780*abc4010dSSteen Hegelund { 781*abc4010dSSteen Hegelund return vctrl->stats->keyfield_set_names[keyset]; 782*abc4010dSSteen Hegelund } 783*abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name); 784*abc4010dSSteen Hegelund 785*abc4010dSSteen Hegelund /* map key field id to a string with the key name */ 786*abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl, 787*abc4010dSSteen Hegelund enum vcap_key_field key) 788*abc4010dSSteen Hegelund { 789*abc4010dSSteen Hegelund return vctrl->stats->keyfield_names[key]; 790*abc4010dSSteen Hegelund } 791*abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name); 792*abc4010dSSteen Hegelund 793*abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */ 794*abc4010dSSteen Hegelund static const struct vcap_field * 795*abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl, 796*abc4010dSSteen Hegelund enum vcap_type vtype, 797*abc4010dSSteen Hegelund enum vcap_keyfield_set keyset, 798*abc4010dSSteen Hegelund enum vcap_key_field key) 799*abc4010dSSteen Hegelund { 800*abc4010dSSteen Hegelund const struct vcap_field *fields; 801*abc4010dSSteen Hegelund int idx, count; 802*abc4010dSSteen Hegelund 803*abc4010dSSteen Hegelund fields = vcap_keyfields(vctrl, vtype, keyset); 804*abc4010dSSteen Hegelund if (!fields) 805*abc4010dSSteen Hegelund return NULL; 806*abc4010dSSteen Hegelund 807*abc4010dSSteen Hegelund /* Iterate the keyfields of the keyset */ 808*abc4010dSSteen Hegelund count = vcap_keyfield_count(vctrl, vtype, keyset); 809*abc4010dSSteen Hegelund for (idx = 0; idx < count; ++idx) { 810*abc4010dSSteen Hegelund if (fields[idx].width == 0) 811*abc4010dSSteen Hegelund continue; 812*abc4010dSSteen Hegelund 813*abc4010dSSteen Hegelund if (key == idx) 814*abc4010dSSteen Hegelund return &fields[idx]; 815*abc4010dSSteen Hegelund } 816*abc4010dSSteen Hegelund 817*abc4010dSSteen Hegelund return NULL; 818*abc4010dSSteen Hegelund } 819*abc4010dSSteen Hegelund 820*abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */ 821*abc4010dSSteen Hegelund static bool vcap_rule_find_keysets(struct vcap_rule_internal *ri, 822*abc4010dSSteen Hegelund struct vcap_keyset_list *matches) 823*abc4010dSSteen Hegelund { 824*abc4010dSSteen Hegelund const struct vcap_client_keyfield *ckf; 825*abc4010dSSteen Hegelund int keyset, found, keycount, map_size; 826*abc4010dSSteen Hegelund const struct vcap_field **map; 827*abc4010dSSteen Hegelund enum vcap_type vtype; 828*abc4010dSSteen Hegelund 829*abc4010dSSteen Hegelund vtype = ri->admin->vtype; 830*abc4010dSSteen Hegelund map = ri->vctrl->vcaps[vtype].keyfield_set_map; 831*abc4010dSSteen Hegelund map_size = ri->vctrl->vcaps[vtype].keyfield_set_size; 832*abc4010dSSteen Hegelund 833*abc4010dSSteen Hegelund /* Get a count of the keyfields we want to match */ 834*abc4010dSSteen Hegelund keycount = 0; 835*abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 836*abc4010dSSteen Hegelund ++keycount; 837*abc4010dSSteen Hegelund 838*abc4010dSSteen Hegelund matches->cnt = 0; 839*abc4010dSSteen Hegelund /* Iterate the keysets of the VCAP */ 840*abc4010dSSteen Hegelund for (keyset = 0; keyset < map_size; ++keyset) { 841*abc4010dSSteen Hegelund if (!map[keyset]) 842*abc4010dSSteen Hegelund continue; 843*abc4010dSSteen Hegelund 844*abc4010dSSteen Hegelund /* Iterate the keys in the rule */ 845*abc4010dSSteen Hegelund found = 0; 846*abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 847*abc4010dSSteen Hegelund if (vcap_find_keyset_keyfield(ri->vctrl, vtype, 848*abc4010dSSteen Hegelund keyset, ckf->ctrl.key)) 849*abc4010dSSteen Hegelund ++found; 850*abc4010dSSteen Hegelund 851*abc4010dSSteen Hegelund /* Save the keyset if all keyfields were found */ 852*abc4010dSSteen Hegelund if (found == keycount) 853*abc4010dSSteen Hegelund if (!vcap_keyset_list_add(matches, keyset)) 854*abc4010dSSteen Hegelund /* bail out when the quota is filled */ 855*abc4010dSSteen Hegelund break; 856*abc4010dSSteen Hegelund } 857*abc4010dSSteen Hegelund 858*abc4010dSSteen Hegelund return matches->cnt > 0; 859*abc4010dSSteen Hegelund } 860*abc4010dSSteen Hegelund 861c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */ 862c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) 863c9da1ac1SSteen Hegelund { 864c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 865*abc4010dSSteen Hegelund struct vcap_keyset_list matches = {}; 8668e10490bSSteen Hegelund enum vcap_keyfield_set keysets[10]; 8678e10490bSSteen Hegelund int ret; 868c9da1ac1SSteen Hegelund 8698e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl); 8708e10490bSSteen Hegelund if (ret) 8718e10490bSSteen Hegelund return ret; 872c9da1ac1SSteen Hegelund if (!ri->admin) { 873c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ADMIN; 874c9da1ac1SSteen Hegelund return -EINVAL; 875c9da1ac1SSteen Hegelund } 876c9da1ac1SSteen Hegelund if (!ri->ndev) { 877c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_NETDEV; 878c9da1ac1SSteen Hegelund return -EINVAL; 879c9da1ac1SSteen Hegelund } 880*abc4010dSSteen Hegelund 881*abc4010dSSteen Hegelund matches.keysets = keysets; 882*abc4010dSSteen Hegelund matches.max = ARRAY_SIZE(keysets); 883c9da1ac1SSteen Hegelund if (ri->data.keyset == VCAP_KFS_NO_VALUE) { 884*abc4010dSSteen Hegelund /* Iterate over rule keyfields and select keysets that fits */ 885*abc4010dSSteen Hegelund if (!vcap_rule_find_keysets(ri, &matches)) { 886c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; 887c9da1ac1SSteen Hegelund return -EINVAL; 888c9da1ac1SSteen Hegelund } 889*abc4010dSSteen Hegelund } else { 8908e10490bSSteen Hegelund /* prepare for keyset validation */ 8918e10490bSSteen Hegelund keysets[0] = ri->data.keyset; 892*abc4010dSSteen Hegelund matches.cnt = 1; 893*abc4010dSSteen Hegelund } 894*abc4010dSSteen Hegelund 8958e10490bSSteen Hegelund /* Pick a keyset that is supported in the port lookups */ 896*abc4010dSSteen Hegelund ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, 897*abc4010dSSteen Hegelund &matches, l3_proto); 8988e10490bSSteen Hegelund if (ret < 0) { 8998e10490bSSteen Hegelund pr_err("%s:%d: keyset validation failed: %d\n", 9008e10490bSSteen Hegelund __func__, __LINE__, ret); 9018e10490bSSteen Hegelund ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH; 9028e10490bSSteen Hegelund return ret; 9038e10490bSSteen Hegelund } 904*abc4010dSSteen Hegelund /* use the keyset that is supported in the port lookups */ 905*abc4010dSSteen Hegelund ret = vcap_set_rule_set_keyset(rule, ret); 906*abc4010dSSteen Hegelund if (ret < 0) { 907*abc4010dSSteen Hegelund pr_err("%s:%d: keyset was not updated: %d\n", 908*abc4010dSSteen Hegelund __func__, __LINE__, ret); 909*abc4010dSSteen Hegelund return ret; 910*abc4010dSSteen Hegelund } 911c9da1ac1SSteen Hegelund if (ri->data.actionset == VCAP_AFS_NO_VALUE) { 912*abc4010dSSteen Hegelund /* Later also actionsets will be matched against actions in 913*abc4010dSSteen Hegelund * the rule, and the type will be set accordingly 914*abc4010dSSteen Hegelund */ 915c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; 916c9da1ac1SSteen Hegelund return -EINVAL; 917c9da1ac1SSteen Hegelund } 9188e10490bSSteen Hegelund vcap_add_type_keyfield(rule); 9198e10490bSSteen Hegelund /* Add default fields to this rule */ 9208e10490bSSteen Hegelund ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule); 9218e10490bSSteen Hegelund 9228e10490bSSteen Hegelund /* Rule size is the maximum of the entry and action subword count */ 9238e10490bSSteen Hegelund ri->size = max(ri->keyset_sw, ri->actionset_sw); 9248e10490bSSteen Hegelund 9258e10490bSSteen Hegelund /* Finally check if there is room for the rule in the VCAP */ 9268e10490bSSteen Hegelund return vcap_rule_space(ri->admin, ri->size); 927c9da1ac1SSteen Hegelund } 928c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule); 929c9da1ac1SSteen Hegelund 9308e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */ 9318e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri) 9328e10490bSSteen Hegelund { 9338e10490bSSteen Hegelund return ((addr - ri->size) / ri->size) * ri->size; 9348e10490bSSteen Hegelund } 9358e10490bSSteen Hegelund 936c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */ 937c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri) 938c9da1ac1SSteen Hegelund { 939c9da1ac1SSteen Hegelund u32 next_id; 940c9da1ac1SSteen Hegelund 941c9da1ac1SSteen Hegelund if (ri->data.id != 0) 942c9da1ac1SSteen Hegelund return ri->data.id; 943c9da1ac1SSteen Hegelund 944c9da1ac1SSteen Hegelund next_id = ri->vctrl->rule_id + 1; 945c9da1ac1SSteen Hegelund 946c9da1ac1SSteen Hegelund for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) { 947c9da1ac1SSteen Hegelund if (!vcap_lookup_rule(ri->vctrl, next_id)) { 948c9da1ac1SSteen Hegelund ri->data.id = next_id; 949c9da1ac1SSteen Hegelund ri->vctrl->rule_id = next_id; 950c9da1ac1SSteen Hegelund break; 951c9da1ac1SSteen Hegelund } 952c9da1ac1SSteen Hegelund } 953c9da1ac1SSteen Hegelund return ri->data.id; 954c9da1ac1SSteen Hegelund } 955c9da1ac1SSteen Hegelund 9568e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri, 9578e10490bSSteen Hegelund struct vcap_rule_move *move) 9588e10490bSSteen Hegelund { 9598e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin; 9608e10490bSSteen Hegelund struct vcap_rule_internal *duprule; 9618e10490bSSteen Hegelund 9628e10490bSSteen Hegelund /* Only support appending rules for now */ 9638e10490bSSteen Hegelund ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri); 9648e10490bSSteen Hegelund admin->last_used_addr = ri->addr; 9658e10490bSSteen Hegelund /* Add a shallow copy of the rule to the VCAP list */ 9668e10490bSSteen Hegelund duprule = vcap_dup_rule(ri); 9678e10490bSSteen Hegelund if (IS_ERR(duprule)) 9688e10490bSSteen Hegelund return PTR_ERR(duprule); 9698e10490bSSteen Hegelund list_add_tail(&duprule->list, &admin->rules); 9708e10490bSSteen Hegelund return 0; 9718e10490bSSteen Hegelund } 9728e10490bSSteen Hegelund 9738e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri, 9748e10490bSSteen Hegelund struct vcap_rule_move *move) 9758e10490bSSteen Hegelund { 9768e10490bSSteen Hegelund ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr, 9778e10490bSSteen Hegelund move->offset, move->count); 9788e10490bSSteen Hegelund } 9798e10490bSSteen Hegelund 980c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */ 981c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule) 982c9da1ac1SSteen Hegelund { 9838e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 9848e10490bSSteen Hegelund struct vcap_rule_move move = {0}; 9858e10490bSSteen Hegelund int ret; 9868e10490bSSteen Hegelund 9878e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl); 9888e10490bSSteen Hegelund if (ret) 9898e10490bSSteen Hegelund return ret; 9908e10490bSSteen Hegelund /* Insert the new rule in the list of vcap rules */ 9918e10490bSSteen Hegelund ret = vcap_insert_rule(ri, &move); 9928e10490bSSteen Hegelund if (ret < 0) { 9938e10490bSSteen Hegelund pr_err("%s:%d: could not insert rule in vcap list: %d\n", 9948e10490bSSteen Hegelund __func__, __LINE__, ret); 9958e10490bSSteen Hegelund goto out; 9968e10490bSSteen Hegelund } 9978e10490bSSteen Hegelund if (move.count > 0) 9988e10490bSSteen Hegelund vcap_move_rules(ri, &move); 9998e10490bSSteen Hegelund ret = vcap_encode_rule(ri); 10008e10490bSSteen Hegelund if (ret) { 10018e10490bSSteen Hegelund pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret); 10028e10490bSSteen Hegelund goto out; 10038e10490bSSteen Hegelund } 10048e10490bSSteen Hegelund 10058e10490bSSteen Hegelund ret = vcap_write_rule(ri); 10068e10490bSSteen Hegelund if (ret) 10078e10490bSSteen Hegelund pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret); 10088e10490bSSteen Hegelund out: 10098e10490bSSteen Hegelund return ret; 1010c9da1ac1SSteen Hegelund } 1011c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule); 1012c9da1ac1SSteen Hegelund 1013c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */ 1014c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, 1015c9da1ac1SSteen Hegelund struct net_device *ndev, int vcap_chain_id, 1016c9da1ac1SSteen Hegelund enum vcap_user user, u16 priority, 1017c9da1ac1SSteen Hegelund u32 id) 1018c9da1ac1SSteen Hegelund { 1019c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 1020c9da1ac1SSteen Hegelund struct vcap_admin *admin; 10218e10490bSSteen Hegelund int maxsize; 1022c9da1ac1SSteen Hegelund 1023c9da1ac1SSteen Hegelund if (!ndev) 1024c9da1ac1SSteen Hegelund return ERR_PTR(-ENODEV); 1025c9da1ac1SSteen Hegelund /* Get the VCAP instance */ 1026c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, vcap_chain_id); 1027c9da1ac1SSteen Hegelund if (!admin) 1028c9da1ac1SSteen Hegelund return ERR_PTR(-ENOENT); 10298e10490bSSteen Hegelund /* Sanity check that this VCAP is supported on this platform */ 10308e10490bSSteen Hegelund if (vctrl->vcaps[admin->vtype].rows == 0) 10318e10490bSSteen Hegelund return ERR_PTR(-EINVAL); 10328e10490bSSteen Hegelund /* Check if a rule with this id already exists */ 10338e10490bSSteen Hegelund if (vcap_lookup_rule(vctrl, id)) 10348e10490bSSteen Hegelund return ERR_PTR(-EEXIST); 10358e10490bSSteen Hegelund /* Check if there is room for the rule in the block(s) of the VCAP */ 10368e10490bSSteen Hegelund maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */ 10378e10490bSSteen Hegelund if (vcap_rule_space(admin, maxsize)) 10388e10490bSSteen Hegelund return ERR_PTR(-ENOSPC); 1039c9da1ac1SSteen Hegelund /* Create a container for the rule and return it */ 1040c9da1ac1SSteen Hegelund ri = kzalloc(sizeof(*ri), GFP_KERNEL); 1041c9da1ac1SSteen Hegelund if (!ri) 1042c9da1ac1SSteen Hegelund return ERR_PTR(-ENOMEM); 1043c9da1ac1SSteen Hegelund ri->data.vcap_chain_id = vcap_chain_id; 1044c9da1ac1SSteen Hegelund ri->data.user = user; 1045c9da1ac1SSteen Hegelund ri->data.priority = priority; 1046c9da1ac1SSteen Hegelund ri->data.id = id; 1047c9da1ac1SSteen Hegelund ri->data.keyset = VCAP_KFS_NO_VALUE; 1048c9da1ac1SSteen Hegelund ri->data.actionset = VCAP_AFS_NO_VALUE; 1049c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->list); 1050c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.keyfields); 1051c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.actionfields); 1052c9da1ac1SSteen Hegelund ri->ndev = ndev; 1053c9da1ac1SSteen Hegelund ri->admin = admin; /* refer to the vcap instance */ 1054c9da1ac1SSteen Hegelund ri->vctrl = vctrl; /* refer to the client */ 1055c9da1ac1SSteen Hegelund if (vcap_set_rule_id(ri) == 0) 1056c9da1ac1SSteen Hegelund goto out_free; 10578e10490bSSteen Hegelund vcap_erase_cache(ri); 1058c9da1ac1SSteen Hegelund return (struct vcap_rule *)ri; 1059c9da1ac1SSteen Hegelund 1060c9da1ac1SSteen Hegelund out_free: 1061c9da1ac1SSteen Hegelund kfree(ri); 1062c9da1ac1SSteen Hegelund return ERR_PTR(-EINVAL); 1063c9da1ac1SSteen Hegelund } 1064c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule); 1065c9da1ac1SSteen Hegelund 1066c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */ 1067c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule) 1068c9da1ac1SSteen Hegelund { 1069c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1070c9da1ac1SSteen Hegelund struct vcap_client_actionfield *caf, *next_caf; 1071c9da1ac1SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf; 1072c9da1ac1SSteen Hegelund 1073c9da1ac1SSteen Hegelund /* Deallocate the list of keys and actions */ 1074c9da1ac1SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) { 1075c9da1ac1SSteen Hegelund list_del(&ckf->ctrl.list); 1076c9da1ac1SSteen Hegelund kfree(ckf); 1077c9da1ac1SSteen Hegelund } 1078c9da1ac1SSteen Hegelund list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) { 1079c9da1ac1SSteen Hegelund list_del(&caf->ctrl.list); 1080c9da1ac1SSteen Hegelund kfree(caf); 1081c9da1ac1SSteen Hegelund } 1082c9da1ac1SSteen Hegelund /* Deallocate the rule */ 1083c9da1ac1SSteen Hegelund kfree(rule); 1084c9da1ac1SSteen Hegelund } 1085c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule); 1086c9da1ac1SSteen Hegelund 1087c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */ 1088c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id) 1089c9da1ac1SSteen Hegelund { 1090c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri, *elem; 1091c9da1ac1SSteen Hegelund struct vcap_admin *admin; 10928e10490bSSteen Hegelund int err; 1093c9da1ac1SSteen Hegelund 1094c9da1ac1SSteen Hegelund /* This will later also handle rule moving */ 1095c9da1ac1SSteen Hegelund if (!ndev) 1096c9da1ac1SSteen Hegelund return -ENODEV; 10978e10490bSSteen Hegelund err = vcap_api_check(vctrl); 10988e10490bSSteen Hegelund if (err) 10998e10490bSSteen Hegelund return err; 1100c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 1101c9da1ac1SSteen Hegelund ri = vcap_lookup_rule(vctrl, id); 1102c9da1ac1SSteen Hegelund if (!ri) 1103c9da1ac1SSteen Hegelund return -EINVAL; 1104c9da1ac1SSteen Hegelund admin = ri->admin; 1105c9da1ac1SSteen Hegelund list_del(&ri->list); 11068e10490bSSteen Hegelund 11078e10490bSSteen Hegelund /* delete the rule in the cache */ 11088e10490bSSteen Hegelund vctrl->ops->init(ndev, admin, ri->addr, ri->size); 1109c9da1ac1SSteen Hegelund if (list_empty(&admin->rules)) { 1110c9da1ac1SSteen Hegelund admin->last_used_addr = admin->last_valid_addr; 1111c9da1ac1SSteen Hegelund } else { 1112c9da1ac1SSteen Hegelund /* update the address range end marker from the last rule in the list */ 1113c9da1ac1SSteen Hegelund elem = list_last_entry(&admin->rules, struct vcap_rule_internal, list); 1114c9da1ac1SSteen Hegelund admin->last_used_addr = elem->addr; 1115c9da1ac1SSteen Hegelund } 1116c9da1ac1SSteen Hegelund kfree(ri); 1117c9da1ac1SSteen Hegelund return 0; 1118c9da1ac1SSteen Hegelund } 1119c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule); 1120c9da1ac1SSteen Hegelund 11218e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */ 11228e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) 11238e10490bSSteen Hegelund { 11248e10490bSSteen Hegelund struct vcap_rule_internal *ri, *next_ri; 11258e10490bSSteen Hegelund int ret = vcap_api_check(vctrl); 11268e10490bSSteen Hegelund 11278e10490bSSteen Hegelund if (ret) 11288e10490bSSteen Hegelund return ret; 11298e10490bSSteen Hegelund list_for_each_entry_safe(ri, next_ri, &admin->rules, list) { 11308e10490bSSteen Hegelund vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size); 11318e10490bSSteen Hegelund list_del(&ri->list); 11328e10490bSSteen Hegelund kfree(ri); 11338e10490bSSteen Hegelund } 11348e10490bSSteen Hegelund admin->last_used_addr = admin->last_valid_addr; 11358e10490bSSteen Hegelund return 0; 11368e10490bSSteen Hegelund } 11378e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules); 11388e10490bSSteen Hegelund 113946be056eSSteen Hegelund /* Find information on a key field in a rule */ 114046be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, 114146be056eSSteen Hegelund enum vcap_key_field key) 114246be056eSSteen Hegelund { 11438e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 114446be056eSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 114546be056eSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 114646be056eSSteen Hegelund const struct vcap_field *fields; 114746be056eSSteen Hegelund 114846be056eSSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE) 114946be056eSSteen Hegelund return NULL; 115046be056eSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 115146be056eSSteen Hegelund if (!fields) 115246be056eSSteen Hegelund return NULL; 115346be056eSSteen Hegelund return &fields[key]; 115446be056eSSteen Hegelund } 115546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield); 115646be056eSSteen Hegelund 1157c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, 1158c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field, 1159c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 1160c9da1ac1SSteen Hegelund { 1161c9da1ac1SSteen Hegelund /* This will be expanded later to handle different vcap memory layouts */ 1162c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 1163c9da1ac1SSteen Hegelund } 1164c9da1ac1SSteen Hegelund 1165c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule, 1166c9da1ac1SSteen Hegelund enum vcap_key_field key, 1167c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 1168c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 1169c9da1ac1SSteen Hegelund { 1170c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field; 1171c9da1ac1SSteen Hegelund 1172c9da1ac1SSteen Hegelund /* More validation will be added here later */ 1173c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 1174c9da1ac1SSteen Hegelund if (!field) 1175c9da1ac1SSteen Hegelund return -ENOMEM; 1176c9da1ac1SSteen Hegelund field->ctrl.key = key; 1177c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 1178c9da1ac1SSteen Hegelund vcap_copy_from_client_keyfield(rule, field, data); 1179c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->keyfields); 1180c9da1ac1SSteen Hegelund return 0; 1181c9da1ac1SSteen Hegelund } 1182c9da1ac1SSteen Hegelund 118346be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val) 118446be056eSSteen Hegelund { 118546be056eSSteen Hegelund switch (val) { 118646be056eSSteen Hegelund case VCAP_BIT_0: 118746be056eSSteen Hegelund u1->value = 0; 118846be056eSSteen Hegelund u1->mask = 1; 118946be056eSSteen Hegelund break; 119046be056eSSteen Hegelund case VCAP_BIT_1: 119146be056eSSteen Hegelund u1->value = 1; 119246be056eSSteen Hegelund u1->mask = 1; 119346be056eSSteen Hegelund break; 119446be056eSSteen Hegelund case VCAP_BIT_ANY: 119546be056eSSteen Hegelund u1->value = 0; 119646be056eSSteen Hegelund u1->mask = 0; 119746be056eSSteen Hegelund break; 119846be056eSSteen Hegelund } 119946be056eSSteen Hegelund } 120046be056eSSteen Hegelund 120146be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */ 120246be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, 120346be056eSSteen Hegelund enum vcap_bit val) 120446be056eSSteen Hegelund { 120546be056eSSteen Hegelund struct vcap_client_keyfield_data data; 120646be056eSSteen Hegelund 120746be056eSSteen Hegelund vcap_rule_set_key_bitsize(&data.u1, val); 120846be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data); 120946be056eSSteen Hegelund } 121046be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit); 121146be056eSSteen Hegelund 121246be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */ 121346be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 121446be056eSSteen Hegelund u32 value, u32 mask) 121546be056eSSteen Hegelund { 121646be056eSSteen Hegelund struct vcap_client_keyfield_data data; 121746be056eSSteen Hegelund 121846be056eSSteen Hegelund data.u32.value = value; 121946be056eSSteen Hegelund data.u32.mask = mask; 122046be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data); 122146be056eSSteen Hegelund } 122246be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32); 122346be056eSSteen Hegelund 1224c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */ 1225c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, 1226c9da1ac1SSteen Hegelund struct vcap_u48_key *fieldval) 1227c9da1ac1SSteen Hegelund { 1228c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data data; 1229c9da1ac1SSteen Hegelund 1230c9da1ac1SSteen Hegelund memcpy(&data.u48, fieldval, sizeof(data.u48)); 1231c9da1ac1SSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data); 1232c9da1ac1SSteen Hegelund } 1233c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48); 1234c9da1ac1SSteen Hegelund 123546be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */ 123646be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, 123746be056eSSteen Hegelund struct vcap_u72_key *fieldval) 123846be056eSSteen Hegelund { 123946be056eSSteen Hegelund struct vcap_client_keyfield_data data; 124046be056eSSteen Hegelund 124146be056eSSteen Hegelund memcpy(&data.u72, fieldval, sizeof(data.u72)); 124246be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data); 124346be056eSSteen Hegelund } 124446be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); 124546be056eSSteen Hegelund 1246d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */ 1247d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key, 1248d6c2964dSSteen Hegelund struct vcap_u128_key *fieldval) 1249d6c2964dSSteen Hegelund { 1250d6c2964dSSteen Hegelund struct vcap_client_keyfield_data data; 1251d6c2964dSSteen Hegelund 1252d6c2964dSSteen Hegelund memcpy(&data.u128, fieldval, sizeof(data.u128)); 1253d6c2964dSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data); 1254d6c2964dSSteen Hegelund } 1255d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128); 1256d6c2964dSSteen Hegelund 1257c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, 1258c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field, 1259c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 1260c9da1ac1SSteen Hegelund { 1261c9da1ac1SSteen Hegelund /* This will be expanded later to handle different vcap memory layouts */ 1262c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 1263c9da1ac1SSteen Hegelund } 1264c9da1ac1SSteen Hegelund 1265c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule, 1266c9da1ac1SSteen Hegelund enum vcap_action_field action, 1267c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 1268c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 1269c9da1ac1SSteen Hegelund { 1270c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field; 1271c9da1ac1SSteen Hegelund 1272c9da1ac1SSteen Hegelund /* More validation will be added here later */ 1273c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 1274c9da1ac1SSteen Hegelund if (!field) 1275c9da1ac1SSteen Hegelund return -ENOMEM; 1276c9da1ac1SSteen Hegelund field->ctrl.action = action; 1277c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 1278c9da1ac1SSteen Hegelund vcap_copy_from_client_actionfield(rule, field, data); 1279c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->actionfields); 1280c9da1ac1SSteen Hegelund return 0; 1281c9da1ac1SSteen Hegelund } 1282c9da1ac1SSteen Hegelund 1283c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1, 1284c9da1ac1SSteen Hegelund enum vcap_bit val) 1285c9da1ac1SSteen Hegelund { 1286c9da1ac1SSteen Hegelund switch (val) { 1287c9da1ac1SSteen Hegelund case VCAP_BIT_0: 1288c9da1ac1SSteen Hegelund u1->value = 0; 1289c9da1ac1SSteen Hegelund break; 1290c9da1ac1SSteen Hegelund case VCAP_BIT_1: 1291c9da1ac1SSteen Hegelund u1->value = 1; 1292c9da1ac1SSteen Hegelund break; 1293c9da1ac1SSteen Hegelund case VCAP_BIT_ANY: 1294c9da1ac1SSteen Hegelund u1->value = 0; 1295c9da1ac1SSteen Hegelund break; 1296c9da1ac1SSteen Hegelund } 1297c9da1ac1SSteen Hegelund } 1298c9da1ac1SSteen Hegelund 1299c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */ 1300c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule, 1301c9da1ac1SSteen Hegelund enum vcap_action_field action, 1302c9da1ac1SSteen Hegelund enum vcap_bit val) 1303c9da1ac1SSteen Hegelund { 1304c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 1305c9da1ac1SSteen Hegelund 1306c9da1ac1SSteen Hegelund vcap_rule_set_action_bitsize(&data.u1, val); 1307c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data); 1308c9da1ac1SSteen Hegelund } 1309c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit); 1310c9da1ac1SSteen Hegelund 1311c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */ 1312c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule, 1313c9da1ac1SSteen Hegelund enum vcap_action_field action, 1314c9da1ac1SSteen Hegelund u32 value) 1315c9da1ac1SSteen Hegelund { 1316c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 1317c9da1ac1SSteen Hegelund 1318c9da1ac1SSteen Hegelund data.u32.value = value; 1319c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data); 1320c9da1ac1SSteen Hegelund } 1321c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); 1322c9da1ac1SSteen Hegelund 1323c9da1ac1SSteen Hegelund /* Copy to host byte order */ 1324c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count) 1325c9da1ac1SSteen Hegelund { 1326c9da1ac1SSteen Hegelund int idx; 1327c9da1ac1SSteen Hegelund 1328c9da1ac1SSteen Hegelund for (idx = 0; idx < count; ++idx, ++dst) 1329c9da1ac1SSteen Hegelund *dst = src[count - idx - 1]; 1330c9da1ac1SSteen Hegelund } 1331c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy); 1332c9da1ac1SSteen Hegelund 1333c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */ 1334c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) 1335c9da1ac1SSteen Hegelund { 1336c9da1ac1SSteen Hegelund switch (vrule->exterr) { 1337c9da1ac1SSteen Hegelund case VCAP_ERR_NONE: 1338c9da1ac1SSteen Hegelund break; 1339c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ADMIN: 1340c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1341c9da1ac1SSteen Hegelund "Missing VCAP instance"); 1342c9da1ac1SSteen Hegelund break; 1343c9da1ac1SSteen Hegelund case VCAP_ERR_NO_NETDEV: 1344c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1345c9da1ac1SSteen Hegelund "Missing network interface"); 1346c9da1ac1SSteen Hegelund break; 1347c9da1ac1SSteen Hegelund case VCAP_ERR_NO_KEYSET_MATCH: 1348c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1349c9da1ac1SSteen Hegelund "No keyset matched the filter keys"); 1350c9da1ac1SSteen Hegelund break; 1351c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ACTIONSET_MATCH: 1352c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1353c9da1ac1SSteen Hegelund "No actionset matched the filter actions"); 1354c9da1ac1SSteen Hegelund break; 1355c9da1ac1SSteen Hegelund case VCAP_ERR_NO_PORT_KEYSET_MATCH: 1356c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1357c9da1ac1SSteen Hegelund "No port keyset matched the filter keys"); 1358c9da1ac1SSteen Hegelund break; 1359c9da1ac1SSteen Hegelund } 1360c9da1ac1SSteen Hegelund } 1361c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); 136267d63751SSteen Hegelund 136367d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST 136467d63751SSteen Hegelund #include "vcap_api_kunit.c" 136567d63751SSteen Hegelund #endif 1366