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 
680*392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */
681*392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid)
682*392d0ab0SSteen Hegelund {
683*392d0ab0SSteen Hegelund 	struct vcap_admin *admin, *next_admin;
684*392d0ab0SSteen Hegelund 	int lookup, next_lookup;
685*392d0ab0SSteen Hegelund 
686*392d0ab0SSteen Hegelund 	/* The offset must be at least one lookup */
687*392d0ab0SSteen Hegelund 	if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
688*392d0ab0SSteen Hegelund 		return false;
689*392d0ab0SSteen Hegelund 
690*392d0ab0SSteen Hegelund 	if (vcap_api_check(vctrl))
691*392d0ab0SSteen Hegelund 		return false;
692*392d0ab0SSteen Hegelund 
693*392d0ab0SSteen Hegelund 	admin = vcap_find_admin(vctrl, cur_cid);
694*392d0ab0SSteen Hegelund 	if (!admin)
695*392d0ab0SSteen Hegelund 		return false;
696*392d0ab0SSteen Hegelund 
697*392d0ab0SSteen Hegelund 	/* If no VCAP contains the next chain, the next chain must be beyond
698*392d0ab0SSteen Hegelund 	 * the last chain in the current VCAP
699*392d0ab0SSteen Hegelund 	 */
700*392d0ab0SSteen Hegelund 	next_admin = vcap_find_admin(vctrl, next_cid);
701*392d0ab0SSteen Hegelund 	if (!next_admin)
702*392d0ab0SSteen Hegelund 		return next_cid > admin->last_cid;
703*392d0ab0SSteen Hegelund 
704*392d0ab0SSteen Hegelund 	lookup = vcap_chain_id_to_lookup(admin, cur_cid);
705*392d0ab0SSteen Hegelund 	next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid);
706*392d0ab0SSteen Hegelund 
707*392d0ab0SSteen Hegelund 	/* Next lookup must be the following lookup */
708*392d0ab0SSteen Hegelund 	if (admin == next_admin || admin->vtype == next_admin->vtype)
709*392d0ab0SSteen Hegelund 		return next_lookup == lookup + 1;
710*392d0ab0SSteen Hegelund 
711*392d0ab0SSteen Hegelund 	/* Must be the first lookup in the next VCAP instance */
712*392d0ab0SSteen Hegelund 	return next_lookup == 0;
713*392d0ab0SSteen Hegelund }
714*392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
715*392d0ab0SSteen 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 
760c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
761c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
762c9da1ac1SSteen Hegelund {
763c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
7648e10490bSSteen Hegelund 	enum vcap_keyfield_set keysets[10];
7658e10490bSSteen Hegelund 	struct vcap_keyset_list kslist;
7668e10490bSSteen Hegelund 	int ret;
767c9da1ac1SSteen Hegelund 
768c9da1ac1SSteen Hegelund 	/* This validation will be much expanded later */
7698e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
7708e10490bSSteen Hegelund 	if (ret)
7718e10490bSSteen Hegelund 		return ret;
772c9da1ac1SSteen Hegelund 	if (!ri->admin) {
773c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ADMIN;
774c9da1ac1SSteen Hegelund 		return -EINVAL;
775c9da1ac1SSteen Hegelund 	}
776c9da1ac1SSteen Hegelund 	if (!ri->ndev) {
777c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_NETDEV;
778c9da1ac1SSteen Hegelund 		return -EINVAL;
779c9da1ac1SSteen Hegelund 	}
780c9da1ac1SSteen Hegelund 	if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
781c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
782c9da1ac1SSteen Hegelund 		return -EINVAL;
783c9da1ac1SSteen Hegelund 	}
7848e10490bSSteen Hegelund 	/* prepare for keyset validation */
7858e10490bSSteen Hegelund 	keysets[0] = ri->data.keyset;
7868e10490bSSteen Hegelund 	kslist.keysets = keysets;
7878e10490bSSteen Hegelund 	kslist.cnt = 1;
7888e10490bSSteen Hegelund 	/* Pick a keyset that is supported in the port lookups */
7898e10490bSSteen Hegelund 	ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, &kslist,
7908e10490bSSteen Hegelund 					      l3_proto);
7918e10490bSSteen Hegelund 	if (ret < 0) {
7928e10490bSSteen Hegelund 		pr_err("%s:%d: keyset validation failed: %d\n",
7938e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
7948e10490bSSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
7958e10490bSSteen Hegelund 		return ret;
7968e10490bSSteen Hegelund 	}
797c9da1ac1SSteen Hegelund 	if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
798c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
799c9da1ac1SSteen Hegelund 		return -EINVAL;
800c9da1ac1SSteen Hegelund 	}
8018e10490bSSteen Hegelund 	vcap_add_type_keyfield(rule);
8028e10490bSSteen Hegelund 	/* Add default fields to this rule */
8038e10490bSSteen Hegelund 	ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
8048e10490bSSteen Hegelund 
8058e10490bSSteen Hegelund 	/* Rule size is the maximum of the entry and action subword count */
8068e10490bSSteen Hegelund 	ri->size = max(ri->keyset_sw, ri->actionset_sw);
8078e10490bSSteen Hegelund 
8088e10490bSSteen Hegelund 	/* Finally check if there is room for the rule in the VCAP */
8098e10490bSSteen Hegelund 	return vcap_rule_space(ri->admin, ri->size);
810c9da1ac1SSteen Hegelund }
811c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
812c9da1ac1SSteen Hegelund 
8138e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
8148e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
8158e10490bSSteen Hegelund {
8168e10490bSSteen Hegelund 	return ((addr - ri->size) /  ri->size) * ri->size;
8178e10490bSSteen Hegelund }
8188e10490bSSteen Hegelund 
819c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
820c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
821c9da1ac1SSteen Hegelund {
822c9da1ac1SSteen Hegelund 	u32 next_id;
823c9da1ac1SSteen Hegelund 
824c9da1ac1SSteen Hegelund 	if (ri->data.id != 0)
825c9da1ac1SSteen Hegelund 		return ri->data.id;
826c9da1ac1SSteen Hegelund 
827c9da1ac1SSteen Hegelund 	next_id = ri->vctrl->rule_id + 1;
828c9da1ac1SSteen Hegelund 
829c9da1ac1SSteen Hegelund 	for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) {
830c9da1ac1SSteen Hegelund 		if (!vcap_lookup_rule(ri->vctrl, next_id)) {
831c9da1ac1SSteen Hegelund 			ri->data.id = next_id;
832c9da1ac1SSteen Hegelund 			ri->vctrl->rule_id = next_id;
833c9da1ac1SSteen Hegelund 			break;
834c9da1ac1SSteen Hegelund 		}
835c9da1ac1SSteen Hegelund 	}
836c9da1ac1SSteen Hegelund 	return ri->data.id;
837c9da1ac1SSteen Hegelund }
838c9da1ac1SSteen Hegelund 
8398e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
8408e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
8418e10490bSSteen Hegelund {
8428e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
8438e10490bSSteen Hegelund 	struct vcap_rule_internal *duprule;
8448e10490bSSteen Hegelund 
8458e10490bSSteen Hegelund 	/* Only support appending rules for now */
8468e10490bSSteen Hegelund 	ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
8478e10490bSSteen Hegelund 	admin->last_used_addr = ri->addr;
8488e10490bSSteen Hegelund 	/* Add a shallow copy of the rule to the VCAP list */
8498e10490bSSteen Hegelund 	duprule = vcap_dup_rule(ri);
8508e10490bSSteen Hegelund 	if (IS_ERR(duprule))
8518e10490bSSteen Hegelund 		return PTR_ERR(duprule);
8528e10490bSSteen Hegelund 	list_add_tail(&duprule->list, &admin->rules);
8538e10490bSSteen Hegelund 	return 0;
8548e10490bSSteen Hegelund }
8558e10490bSSteen Hegelund 
8568e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
8578e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
8588e10490bSSteen Hegelund {
8598e10490bSSteen Hegelund 	ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
8608e10490bSSteen Hegelund 			 move->offset, move->count);
8618e10490bSSteen Hegelund }
8628e10490bSSteen Hegelund 
863c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
864c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
865c9da1ac1SSteen Hegelund {
8668e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
8678e10490bSSteen Hegelund 	struct vcap_rule_move move = {0};
8688e10490bSSteen Hegelund 	int ret;
8698e10490bSSteen Hegelund 
8708e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
8718e10490bSSteen Hegelund 	if (ret)
8728e10490bSSteen Hegelund 		return ret;
8738e10490bSSteen Hegelund 	/* Insert the new rule in the list of vcap rules */
8748e10490bSSteen Hegelund 	ret = vcap_insert_rule(ri, &move);
8758e10490bSSteen Hegelund 	if (ret < 0) {
8768e10490bSSteen Hegelund 		pr_err("%s:%d: could not insert rule in vcap list: %d\n",
8778e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
8788e10490bSSteen Hegelund 		goto out;
8798e10490bSSteen Hegelund 	}
8808e10490bSSteen Hegelund 	if (move.count > 0)
8818e10490bSSteen Hegelund 		vcap_move_rules(ri, &move);
8828e10490bSSteen Hegelund 	ret = vcap_encode_rule(ri);
8838e10490bSSteen Hegelund 	if (ret) {
8848e10490bSSteen Hegelund 		pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
8858e10490bSSteen Hegelund 		goto out;
8868e10490bSSteen Hegelund 	}
8878e10490bSSteen Hegelund 
8888e10490bSSteen Hegelund 	ret = vcap_write_rule(ri);
8898e10490bSSteen Hegelund 	if (ret)
8908e10490bSSteen Hegelund 		pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
8918e10490bSSteen Hegelund out:
8928e10490bSSteen Hegelund 	return ret;
893c9da1ac1SSteen Hegelund }
894c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
895c9da1ac1SSteen Hegelund 
896c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
897c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
898c9da1ac1SSteen Hegelund 				  struct net_device *ndev, int vcap_chain_id,
899c9da1ac1SSteen Hegelund 				  enum vcap_user user, u16 priority,
900c9da1ac1SSteen Hegelund 				  u32 id)
901c9da1ac1SSteen Hegelund {
902c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
903c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
9048e10490bSSteen Hegelund 	int maxsize;
905c9da1ac1SSteen Hegelund 
906c9da1ac1SSteen Hegelund 	if (!ndev)
907c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENODEV);
908c9da1ac1SSteen Hegelund 	/* Get the VCAP instance */
909c9da1ac1SSteen Hegelund 	admin = vcap_find_admin(vctrl, vcap_chain_id);
910c9da1ac1SSteen Hegelund 	if (!admin)
911c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOENT);
9128e10490bSSteen Hegelund 	/* Sanity check that this VCAP is supported on this platform */
9138e10490bSSteen Hegelund 	if (vctrl->vcaps[admin->vtype].rows == 0)
9148e10490bSSteen Hegelund 		return ERR_PTR(-EINVAL);
9158e10490bSSteen Hegelund 	/* Check if a rule with this id already exists */
9168e10490bSSteen Hegelund 	if (vcap_lookup_rule(vctrl, id))
9178e10490bSSteen Hegelund 		return ERR_PTR(-EEXIST);
9188e10490bSSteen Hegelund 	/* Check if there is room for the rule in the block(s) of the VCAP */
9198e10490bSSteen Hegelund 	maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
9208e10490bSSteen Hegelund 	if (vcap_rule_space(admin, maxsize))
9218e10490bSSteen Hegelund 		return ERR_PTR(-ENOSPC);
922c9da1ac1SSteen Hegelund 	/* Create a container for the rule and return it */
923c9da1ac1SSteen Hegelund 	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
924c9da1ac1SSteen Hegelund 	if (!ri)
925c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOMEM);
926c9da1ac1SSteen Hegelund 	ri->data.vcap_chain_id = vcap_chain_id;
927c9da1ac1SSteen Hegelund 	ri->data.user = user;
928c9da1ac1SSteen Hegelund 	ri->data.priority = priority;
929c9da1ac1SSteen Hegelund 	ri->data.id = id;
930c9da1ac1SSteen Hegelund 	ri->data.keyset = VCAP_KFS_NO_VALUE;
931c9da1ac1SSteen Hegelund 	ri->data.actionset = VCAP_AFS_NO_VALUE;
932c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->list);
933c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.keyfields);
934c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.actionfields);
935c9da1ac1SSteen Hegelund 	ri->ndev = ndev;
936c9da1ac1SSteen Hegelund 	ri->admin = admin; /* refer to the vcap instance */
937c9da1ac1SSteen Hegelund 	ri->vctrl = vctrl; /* refer to the client */
938c9da1ac1SSteen Hegelund 	if (vcap_set_rule_id(ri) == 0)
939c9da1ac1SSteen Hegelund 		goto out_free;
9408e10490bSSteen Hegelund 	vcap_erase_cache(ri);
941c9da1ac1SSteen Hegelund 	return (struct vcap_rule *)ri;
942c9da1ac1SSteen Hegelund 
943c9da1ac1SSteen Hegelund out_free:
944c9da1ac1SSteen Hegelund 	kfree(ri);
945c9da1ac1SSteen Hegelund 	return ERR_PTR(-EINVAL);
946c9da1ac1SSteen Hegelund }
947c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
948c9da1ac1SSteen Hegelund 
949c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
950c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
951c9da1ac1SSteen Hegelund {
952c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
953c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *caf, *next_caf;
954c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
955c9da1ac1SSteen Hegelund 
956c9da1ac1SSteen Hegelund 	/* Deallocate the list of keys and actions */
957c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
958c9da1ac1SSteen Hegelund 		list_del(&ckf->ctrl.list);
959c9da1ac1SSteen Hegelund 		kfree(ckf);
960c9da1ac1SSteen Hegelund 	}
961c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
962c9da1ac1SSteen Hegelund 		list_del(&caf->ctrl.list);
963c9da1ac1SSteen Hegelund 		kfree(caf);
964c9da1ac1SSteen Hegelund 	}
965c9da1ac1SSteen Hegelund 	/* Deallocate the rule */
966c9da1ac1SSteen Hegelund 	kfree(rule);
967c9da1ac1SSteen Hegelund }
968c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
969c9da1ac1SSteen Hegelund 
970c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
971c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
972c9da1ac1SSteen Hegelund {
973c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri, *elem;
974c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
9758e10490bSSteen Hegelund 	int err;
976c9da1ac1SSteen Hegelund 
977c9da1ac1SSteen Hegelund 	/* This will later also handle rule moving */
978c9da1ac1SSteen Hegelund 	if (!ndev)
979c9da1ac1SSteen Hegelund 		return -ENODEV;
9808e10490bSSteen Hegelund 	err = vcap_api_check(vctrl);
9818e10490bSSteen Hegelund 	if (err)
9828e10490bSSteen Hegelund 		return err;
983c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
984c9da1ac1SSteen Hegelund 	ri = vcap_lookup_rule(vctrl, id);
985c9da1ac1SSteen Hegelund 	if (!ri)
986c9da1ac1SSteen Hegelund 		return -EINVAL;
987c9da1ac1SSteen Hegelund 	admin = ri->admin;
988c9da1ac1SSteen Hegelund 	list_del(&ri->list);
9898e10490bSSteen Hegelund 
9908e10490bSSteen Hegelund 	/* delete the rule in the cache */
9918e10490bSSteen Hegelund 	vctrl->ops->init(ndev, admin, ri->addr, ri->size);
992c9da1ac1SSteen Hegelund 	if (list_empty(&admin->rules)) {
993c9da1ac1SSteen Hegelund 		admin->last_used_addr = admin->last_valid_addr;
994c9da1ac1SSteen Hegelund 	} else {
995c9da1ac1SSteen Hegelund 		/* update the address range end marker from the last rule in the list */
996c9da1ac1SSteen Hegelund 		elem = list_last_entry(&admin->rules, struct vcap_rule_internal, list);
997c9da1ac1SSteen Hegelund 		admin->last_used_addr = elem->addr;
998c9da1ac1SSteen Hegelund 	}
999c9da1ac1SSteen Hegelund 	kfree(ri);
1000c9da1ac1SSteen Hegelund 	return 0;
1001c9da1ac1SSteen Hegelund }
1002c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
1003c9da1ac1SSteen Hegelund 
10048e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
10058e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
10068e10490bSSteen Hegelund {
10078e10490bSSteen Hegelund 	struct vcap_rule_internal *ri, *next_ri;
10088e10490bSSteen Hegelund 	int ret = vcap_api_check(vctrl);
10098e10490bSSteen Hegelund 
10108e10490bSSteen Hegelund 	if (ret)
10118e10490bSSteen Hegelund 		return ret;
10128e10490bSSteen Hegelund 	list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
10138e10490bSSteen Hegelund 		vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
10148e10490bSSteen Hegelund 		list_del(&ri->list);
10158e10490bSSteen Hegelund 		kfree(ri);
10168e10490bSSteen Hegelund 	}
10178e10490bSSteen Hegelund 	admin->last_used_addr = admin->last_valid_addr;
10188e10490bSSteen Hegelund 	return 0;
10198e10490bSSteen Hegelund }
10208e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
10218e10490bSSteen Hegelund 
102246be056eSSteen Hegelund /* Find information on a key field in a rule */
102346be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
102446be056eSSteen Hegelund 					      enum vcap_key_field key)
102546be056eSSteen Hegelund {
10268e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
102746be056eSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
102846be056eSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
102946be056eSSteen Hegelund 	const struct vcap_field *fields;
103046be056eSSteen Hegelund 
103146be056eSSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
103246be056eSSteen Hegelund 		return NULL;
103346be056eSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
103446be056eSSteen Hegelund 	if (!fields)
103546be056eSSteen Hegelund 		return NULL;
103646be056eSSteen Hegelund 	return &fields[key];
103746be056eSSteen Hegelund }
103846be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
103946be056eSSteen Hegelund 
1040c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule,
1041c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield *field,
1042c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield_data *data)
1043c9da1ac1SSteen Hegelund {
1044c9da1ac1SSteen Hegelund 	/* This will be expanded later to handle different vcap memory layouts */
1045c9da1ac1SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
1046c9da1ac1SSteen Hegelund }
1047c9da1ac1SSteen Hegelund 
1048c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
1049c9da1ac1SSteen Hegelund 			     enum vcap_key_field key,
1050c9da1ac1SSteen Hegelund 			     enum vcap_field_type ftype,
1051c9da1ac1SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
1052c9da1ac1SSteen Hegelund {
1053c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *field;
1054c9da1ac1SSteen Hegelund 
1055c9da1ac1SSteen Hegelund 	/* More validation will be added here later */
1056c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1057c9da1ac1SSteen Hegelund 	if (!field)
1058c9da1ac1SSteen Hegelund 		return -ENOMEM;
1059c9da1ac1SSteen Hegelund 	field->ctrl.key = key;
1060c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
1061c9da1ac1SSteen Hegelund 	vcap_copy_from_client_keyfield(rule, field, data);
1062c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->keyfields);
1063c9da1ac1SSteen Hegelund 	return 0;
1064c9da1ac1SSteen Hegelund }
1065c9da1ac1SSteen Hegelund 
106646be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
106746be056eSSteen Hegelund {
106846be056eSSteen Hegelund 	switch (val) {
106946be056eSSteen Hegelund 	case VCAP_BIT_0:
107046be056eSSteen Hegelund 		u1->value = 0;
107146be056eSSteen Hegelund 		u1->mask = 1;
107246be056eSSteen Hegelund 		break;
107346be056eSSteen Hegelund 	case VCAP_BIT_1:
107446be056eSSteen Hegelund 		u1->value = 1;
107546be056eSSteen Hegelund 		u1->mask = 1;
107646be056eSSteen Hegelund 		break;
107746be056eSSteen Hegelund 	case VCAP_BIT_ANY:
107846be056eSSteen Hegelund 		u1->value = 0;
107946be056eSSteen Hegelund 		u1->mask = 0;
108046be056eSSteen Hegelund 		break;
108146be056eSSteen Hegelund 	}
108246be056eSSteen Hegelund }
108346be056eSSteen Hegelund 
108446be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
108546be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
108646be056eSSteen Hegelund 			  enum vcap_bit val)
108746be056eSSteen Hegelund {
108846be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
108946be056eSSteen Hegelund 
109046be056eSSteen Hegelund 	vcap_rule_set_key_bitsize(&data.u1, val);
109146be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
109246be056eSSteen Hegelund }
109346be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
109446be056eSSteen Hegelund 
109546be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
109646be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
109746be056eSSteen Hegelund 			  u32 value, u32 mask)
109846be056eSSteen Hegelund {
109946be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
110046be056eSSteen Hegelund 
110146be056eSSteen Hegelund 	data.u32.value = value;
110246be056eSSteen Hegelund 	data.u32.mask = mask;
110346be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
110446be056eSSteen Hegelund }
110546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
110646be056eSSteen Hegelund 
1107c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
1108c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
1109c9da1ac1SSteen Hegelund 			  struct vcap_u48_key *fieldval)
1110c9da1ac1SSteen Hegelund {
1111c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield_data data;
1112c9da1ac1SSteen Hegelund 
1113c9da1ac1SSteen Hegelund 	memcpy(&data.u48, fieldval, sizeof(data.u48));
1114c9da1ac1SSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
1115c9da1ac1SSteen Hegelund }
1116c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
1117c9da1ac1SSteen Hegelund 
111846be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
111946be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
112046be056eSSteen Hegelund 			  struct vcap_u72_key *fieldval)
112146be056eSSteen Hegelund {
112246be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
112346be056eSSteen Hegelund 
112446be056eSSteen Hegelund 	memcpy(&data.u72, fieldval, sizeof(data.u72));
112546be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
112646be056eSSteen Hegelund }
112746be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
112846be056eSSteen Hegelund 
1129d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
1130d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
1131d6c2964dSSteen Hegelund 			   struct vcap_u128_key *fieldval)
1132d6c2964dSSteen Hegelund {
1133d6c2964dSSteen Hegelund 	struct vcap_client_keyfield_data data;
1134d6c2964dSSteen Hegelund 
1135d6c2964dSSteen Hegelund 	memcpy(&data.u128, fieldval, sizeof(data.u128));
1136d6c2964dSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
1137d6c2964dSSteen Hegelund }
1138d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
1139d6c2964dSSteen Hegelund 
1140c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule,
1141c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield *field,
1142c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield_data *data)
1143c9da1ac1SSteen Hegelund {
1144c9da1ac1SSteen Hegelund 	/* This will be expanded later to handle different vcap memory layouts */
1145c9da1ac1SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
1146c9da1ac1SSteen Hegelund }
1147c9da1ac1SSteen Hegelund 
1148c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
1149c9da1ac1SSteen Hegelund 				enum vcap_action_field action,
1150c9da1ac1SSteen Hegelund 				enum vcap_field_type ftype,
1151c9da1ac1SSteen Hegelund 				struct vcap_client_actionfield_data *data)
1152c9da1ac1SSteen Hegelund {
1153c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *field;
1154c9da1ac1SSteen Hegelund 
1155c9da1ac1SSteen Hegelund 	/* More validation will be added here later */
1156c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1157c9da1ac1SSteen Hegelund 	if (!field)
1158c9da1ac1SSteen Hegelund 		return -ENOMEM;
1159c9da1ac1SSteen Hegelund 	field->ctrl.action = action;
1160c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
1161c9da1ac1SSteen Hegelund 	vcap_copy_from_client_actionfield(rule, field, data);
1162c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->actionfields);
1163c9da1ac1SSteen Hegelund 	return 0;
1164c9da1ac1SSteen Hegelund }
1165c9da1ac1SSteen Hegelund 
1166c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
1167c9da1ac1SSteen Hegelund 					 enum vcap_bit val)
1168c9da1ac1SSteen Hegelund {
1169c9da1ac1SSteen Hegelund 	switch (val) {
1170c9da1ac1SSteen Hegelund 	case VCAP_BIT_0:
1171c9da1ac1SSteen Hegelund 		u1->value = 0;
1172c9da1ac1SSteen Hegelund 		break;
1173c9da1ac1SSteen Hegelund 	case VCAP_BIT_1:
1174c9da1ac1SSteen Hegelund 		u1->value = 1;
1175c9da1ac1SSteen Hegelund 		break;
1176c9da1ac1SSteen Hegelund 	case VCAP_BIT_ANY:
1177c9da1ac1SSteen Hegelund 		u1->value = 0;
1178c9da1ac1SSteen Hegelund 		break;
1179c9da1ac1SSteen Hegelund 	}
1180c9da1ac1SSteen Hegelund }
1181c9da1ac1SSteen Hegelund 
1182c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
1183c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
1184c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
1185c9da1ac1SSteen Hegelund 			     enum vcap_bit val)
1186c9da1ac1SSteen Hegelund {
1187c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
1188c9da1ac1SSteen Hegelund 
1189c9da1ac1SSteen Hegelund 	vcap_rule_set_action_bitsize(&data.u1, val);
1190c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
1191c9da1ac1SSteen Hegelund }
1192c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
1193c9da1ac1SSteen Hegelund 
1194c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
1195c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
1196c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
1197c9da1ac1SSteen Hegelund 			     u32 value)
1198c9da1ac1SSteen Hegelund {
1199c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
1200c9da1ac1SSteen Hegelund 
1201c9da1ac1SSteen Hegelund 	data.u32.value = value;
1202c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
1203c9da1ac1SSteen Hegelund }
1204c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
1205c9da1ac1SSteen Hegelund 
1206c9da1ac1SSteen Hegelund /* Copy to host byte order */
1207c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
1208c9da1ac1SSteen Hegelund {
1209c9da1ac1SSteen Hegelund 	int idx;
1210c9da1ac1SSteen Hegelund 
1211c9da1ac1SSteen Hegelund 	for (idx = 0; idx < count; ++idx, ++dst)
1212c9da1ac1SSteen Hegelund 		*dst = src[count - idx - 1];
1213c9da1ac1SSteen Hegelund }
1214c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
1215c9da1ac1SSteen Hegelund 
1216c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */
1217c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
1218c9da1ac1SSteen Hegelund {
1219c9da1ac1SSteen Hegelund 	switch (vrule->exterr) {
1220c9da1ac1SSteen Hegelund 	case VCAP_ERR_NONE:
1221c9da1ac1SSteen Hegelund 		break;
1222c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ADMIN:
1223c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1224c9da1ac1SSteen Hegelund 				   "Missing VCAP instance");
1225c9da1ac1SSteen Hegelund 		break;
1226c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_NETDEV:
1227c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1228c9da1ac1SSteen Hegelund 				   "Missing network interface");
1229c9da1ac1SSteen Hegelund 		break;
1230c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_KEYSET_MATCH:
1231c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1232c9da1ac1SSteen Hegelund 				   "No keyset matched the filter keys");
1233c9da1ac1SSteen Hegelund 		break;
1234c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ACTIONSET_MATCH:
1235c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1236c9da1ac1SSteen Hegelund 				   "No actionset matched the filter actions");
1237c9da1ac1SSteen Hegelund 		break;
1238c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_PORT_KEYSET_MATCH:
1239c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1240c9da1ac1SSteen Hegelund 				   "No port keyset matched the filter keys");
1241c9da1ac1SSteen Hegelund 		break;
1242c9da1ac1SSteen Hegelund 	}
1243c9da1ac1SSteen Hegelund }
1244c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
124567d63751SSteen Hegelund 
124667d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
124767d63751SSteen Hegelund #include "vcap_api_kunit.c"
124867d63751SSteen Hegelund #endif
1249