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 */
28*f13230a4SSteen Hegelund 	u32 counter_id; /* counter id (if a dedicated counter is available) */
29*f13230a4SSteen Hegelund 	struct vcap_counter counter; /* last read counter value */
30c9da1ac1SSteen Hegelund };
31c9da1ac1SSteen Hegelund 
328e10490bSSteen Hegelund /* Moving a rule in the VCAP address space */
338e10490bSSteen Hegelund struct vcap_rule_move {
348e10490bSSteen Hegelund 	int addr; /* address to move */
358e10490bSSteen Hegelund 	int offset; /* change in address */
368e10490bSSteen Hegelund 	int count; /* blocksize of addresses to move */
378e10490bSSteen Hegelund };
388e10490bSSteen Hegelund 
39683e05c0SSteen Hegelund /* Bit iterator for the VCAP cache streams */
40683e05c0SSteen Hegelund struct vcap_stream_iter {
41683e05c0SSteen Hegelund 	u32 offset; /* bit offset from the stream start */
42683e05c0SSteen Hegelund 	u32 sw_width; /* subword width in bits */
43683e05c0SSteen Hegelund 	u32 regs_per_sw; /* registers per subword */
44683e05c0SSteen Hegelund 	u32 reg_idx; /* current register index */
45683e05c0SSteen Hegelund 	u32 reg_bitpos; /* bit offset in current register */
46683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg; /* current typegroup */
47683e05c0SSteen Hegelund };
48683e05c0SSteen Hegelund 
4967456717SSteen Hegelund /* Stores the filter cookie that enabled the port */
5067456717SSteen Hegelund struct vcap_enabled_port {
5167456717SSteen Hegelund 	struct list_head list; /* for insertion in enabled ports list */
5267456717SSteen Hegelund 	struct net_device *ndev;  /* the enabled port */
5367456717SSteen Hegelund 	unsigned long cookie; /* filter that enabled the port */
5467456717SSteen Hegelund };
5567456717SSteen Hegelund 
56683e05c0SSteen Hegelund static void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
57683e05c0SSteen Hegelund 			  const struct vcap_typegroup *tg, u32 offset)
58683e05c0SSteen Hegelund {
59683e05c0SSteen Hegelund 	memset(itr, 0, sizeof(*itr));
60683e05c0SSteen Hegelund 	itr->offset = offset;
61683e05c0SSteen Hegelund 	itr->sw_width = sw_width;
62683e05c0SSteen Hegelund 	itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32);
63683e05c0SSteen Hegelund 	itr->tg = tg;
64683e05c0SSteen Hegelund }
65683e05c0SSteen Hegelund 
66683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr)
67683e05c0SSteen Hegelund {
68683e05c0SSteen Hegelund 	/* Compensate the field offset for preceding typegroups.
69683e05c0SSteen Hegelund 	 * A typegroup table ends with an all-zero terminator.
70683e05c0SSteen Hegelund 	 */
71683e05c0SSteen Hegelund 	while (itr->tg->width && itr->offset >= itr->tg->offset) {
72683e05c0SSteen Hegelund 		itr->offset += itr->tg->width;
73683e05c0SSteen Hegelund 		itr->tg++; /* next typegroup */
74683e05c0SSteen Hegelund 	}
75683e05c0SSteen Hegelund }
76683e05c0SSteen Hegelund 
77683e05c0SSteen Hegelund static void vcap_iter_update(struct vcap_stream_iter *itr)
78683e05c0SSteen Hegelund {
79683e05c0SSteen Hegelund 	int sw_idx, sw_bitpos;
80683e05c0SSteen Hegelund 
81683e05c0SSteen Hegelund 	/* Calculate the subword index and bitposition for current bit */
82683e05c0SSteen Hegelund 	sw_idx = itr->offset / itr->sw_width;
83683e05c0SSteen Hegelund 	sw_bitpos = itr->offset % itr->sw_width;
84683e05c0SSteen Hegelund 	/* Calculate the register index and bitposition for current bit */
85683e05c0SSteen Hegelund 	itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32);
86683e05c0SSteen Hegelund 	itr->reg_bitpos = sw_bitpos % 32;
87683e05c0SSteen Hegelund }
88683e05c0SSteen Hegelund 
89683e05c0SSteen Hegelund static void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
90683e05c0SSteen Hegelund 			   const struct vcap_typegroup *tg, u32 offset)
91683e05c0SSteen Hegelund {
92683e05c0SSteen Hegelund 	vcap_iter_set(itr, sw_width, tg, offset);
93683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
94683e05c0SSteen Hegelund 	vcap_iter_update(itr);
95683e05c0SSteen Hegelund }
96683e05c0SSteen Hegelund 
97683e05c0SSteen Hegelund static void vcap_iter_next(struct vcap_stream_iter *itr)
98683e05c0SSteen Hegelund {
99683e05c0SSteen Hegelund 	itr->offset++;
100683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
101683e05c0SSteen Hegelund 	vcap_iter_update(itr);
102683e05c0SSteen Hegelund }
103683e05c0SSteen Hegelund 
104683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value)
105683e05c0SSteen Hegelund {
106683e05c0SSteen Hegelund 	u32 mask = BIT(itr->reg_bitpos);
107683e05c0SSteen Hegelund 	u32 *p = &stream[itr->reg_idx];
108683e05c0SSteen Hegelund 
109683e05c0SSteen Hegelund 	if (value)
110683e05c0SSteen Hegelund 		*p |= mask;
111683e05c0SSteen Hegelund 	else
112683e05c0SSteen Hegelund 		*p &= ~mask;
113683e05c0SSteen Hegelund }
114683e05c0SSteen Hegelund 
115683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val)
116683e05c0SSteen Hegelund {
117683e05c0SSteen Hegelund 	/* When intersected by a type group field, stream the type group bits
118683e05c0SSteen Hegelund 	 * before continuing with the value bit
119683e05c0SSteen Hegelund 	 */
120683e05c0SSteen Hegelund 	while (itr->tg->width &&
121683e05c0SSteen Hegelund 	       itr->offset >= itr->tg->offset &&
122683e05c0SSteen Hegelund 	       itr->offset < itr->tg->offset + itr->tg->width) {
123683e05c0SSteen Hegelund 		int tg_bitpos = itr->tg->offset - itr->offset;
124683e05c0SSteen Hegelund 
125683e05c0SSteen Hegelund 		vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1);
126683e05c0SSteen Hegelund 		itr->offset++;
127683e05c0SSteen Hegelund 		vcap_iter_update(itr);
128683e05c0SSteen Hegelund 	}
129683e05c0SSteen Hegelund 	vcap_set_bit(stream, itr, val);
130683e05c0SSteen Hegelund }
131683e05c0SSteen Hegelund 
132683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr,
133683e05c0SSteen Hegelund 			      int width, const u8 *value)
134683e05c0SSteen Hegelund {
135683e05c0SSteen Hegelund 	int idx;
136683e05c0SSteen Hegelund 
137683e05c0SSteen Hegelund 	/* Loop over the field value bits and add the value bits one by one to
138683e05c0SSteen Hegelund 	 * the output stream.
139683e05c0SSteen Hegelund 	 */
140683e05c0SSteen Hegelund 	for (idx = 0; idx < width; idx++) {
141683e05c0SSteen Hegelund 		u8 bidx = idx & GENMASK(2, 0);
142683e05c0SSteen Hegelund 
143683e05c0SSteen Hegelund 		/* Encode one field value bit */
144683e05c0SSteen Hegelund 		vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1);
145683e05c0SSteen Hegelund 		vcap_iter_next(itr);
146683e05c0SSteen Hegelund 	}
147683e05c0SSteen Hegelund }
148683e05c0SSteen Hegelund 
149683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width,
150683e05c0SSteen Hegelund 				   const struct vcap_typegroup *tg,
151683e05c0SSteen Hegelund 				   bool mask)
152683e05c0SSteen Hegelund {
153683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
154683e05c0SSteen Hegelund 	int idx;
155683e05c0SSteen Hegelund 
156683e05c0SSteen Hegelund 	/* Mask bits must be set to zeros (inverted later when writing to the
157683e05c0SSteen Hegelund 	 * mask cache register), so that the mask typegroup bits consist of
158683e05c0SSteen Hegelund 	 * match-1 or match-0, or both
159683e05c0SSteen Hegelund 	 */
160683e05c0SSteen Hegelund 	vcap_iter_set(&iter, sw_width, tg, 0);
161683e05c0SSteen Hegelund 	while (iter.tg->width) {
162683e05c0SSteen Hegelund 		/* Set position to current typegroup bit */
163683e05c0SSteen Hegelund 		iter.offset = iter.tg->offset;
164683e05c0SSteen Hegelund 		vcap_iter_update(&iter);
165683e05c0SSteen Hegelund 		for (idx = 0; idx < iter.tg->width; idx++) {
166683e05c0SSteen Hegelund 			/* Iterate over current typegroup bits. Mask typegroup
167683e05c0SSteen Hegelund 			 * bits are always set
168683e05c0SSteen Hegelund 			 */
169683e05c0SSteen Hegelund 			if (mask)
170683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter, 0x1);
171683e05c0SSteen Hegelund 			else
172683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter,
173683e05c0SSteen Hegelund 					     (iter.tg->value >> idx) & 0x1);
174683e05c0SSteen Hegelund 			iter.offset++;
175683e05c0SSteen Hegelund 			vcap_iter_update(&iter);
176683e05c0SSteen Hegelund 		}
177683e05c0SSteen Hegelund 		iter.tg++; /* next typegroup */
178683e05c0SSteen Hegelund 	}
179683e05c0SSteen Hegelund }
180683e05c0SSteen Hegelund 
18146be056eSSteen Hegelund /* Return the list of keyfields for the keyset */
18246be056eSSteen Hegelund static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
18346be056eSSteen Hegelund 					       enum vcap_type vt,
18446be056eSSteen Hegelund 					       enum vcap_keyfield_set keyset)
18546be056eSSteen Hegelund {
18646be056eSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
18746be056eSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
18846be056eSSteen Hegelund 		return NULL;
18946be056eSSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map[keyset];
19046be056eSSteen Hegelund }
19146be056eSSteen Hegelund 
1928e10490bSSteen Hegelund /* Return the keyset information for the keyset */
1938e10490bSSteen Hegelund static const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
1948e10490bSSteen Hegelund 					       enum vcap_type vt,
1958e10490bSSteen Hegelund 					       enum vcap_keyfield_set keyset)
1968e10490bSSteen Hegelund {
1978e10490bSSteen Hegelund 	const struct vcap_set *kset;
1988e10490bSSteen Hegelund 
1998e10490bSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
2008e10490bSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
2018e10490bSSteen Hegelund 		return NULL;
2028e10490bSSteen Hegelund 	kset = &vctrl->vcaps[vt].keyfield_set[keyset];
2038e10490bSSteen Hegelund 	if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count)
2048e10490bSSteen Hegelund 		return NULL;
2058e10490bSSteen Hegelund 	return kset;
2068e10490bSSteen Hegelund }
2078e10490bSSteen Hegelund 
208683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */
209683e05c0SSteen Hegelund static const struct vcap_typegroup *
210683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl,
211683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
212683e05c0SSteen Hegelund {
213683e05c0SSteen Hegelund 	const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset);
214683e05c0SSteen Hegelund 
215683e05c0SSteen Hegelund 	/* Check that the keyset is valid */
216683e05c0SSteen Hegelund 	if (!kset)
217683e05c0SSteen Hegelund 		return NULL;
218683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item];
219683e05c0SSteen Hegelund }
220683e05c0SSteen Hegelund 
221683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */
222683e05c0SSteen Hegelund static int vcap_keyfield_count(struct vcap_control *vctrl,
223683e05c0SSteen Hegelund 			       enum vcap_type vt, enum vcap_keyfield_set keyset)
224683e05c0SSteen Hegelund {
225683e05c0SSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
226683e05c0SSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
227683e05c0SSteen Hegelund 		return 0;
228683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map_size[keyset];
229683e05c0SSteen Hegelund }
230683e05c0SSteen Hegelund 
231683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri,
232683e05c0SSteen Hegelund 				 const struct vcap_client_keyfield *kf,
233683e05c0SSteen Hegelund 				 const struct vcap_field *rf,
234683e05c0SSteen Hegelund 				 const struct vcap_typegroup *tgt)
235683e05c0SSteen Hegelund {
236683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
237683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
238683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
239683e05c0SSteen Hegelund 	const u8 *value, *mask;
240683e05c0SSteen Hegelund 
241683e05c0SSteen Hegelund 	/* Encode the fields for the key and the mask in their respective
242683e05c0SSteen Hegelund 	 * streams, respecting the subword width.
243683e05c0SSteen Hegelund 	 */
244683e05c0SSteen Hegelund 	switch (kf->ctrl.type) {
245683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
246683e05c0SSteen Hegelund 		value = &kf->data.u1.value;
247683e05c0SSteen Hegelund 		mask = &kf->data.u1.mask;
248683e05c0SSteen Hegelund 		break;
249683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
250683e05c0SSteen Hegelund 		value = (const u8 *)&kf->data.u32.value;
251683e05c0SSteen Hegelund 		mask = (const u8 *)&kf->data.u32.mask;
252683e05c0SSteen Hegelund 		break;
253683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
254683e05c0SSteen Hegelund 		value = kf->data.u48.value;
255683e05c0SSteen Hegelund 		mask = kf->data.u48.mask;
256683e05c0SSteen Hegelund 		break;
257683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
258683e05c0SSteen Hegelund 		value = kf->data.u56.value;
259683e05c0SSteen Hegelund 		mask = kf->data.u56.mask;
260683e05c0SSteen Hegelund 		break;
261683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
262683e05c0SSteen Hegelund 		value = kf->data.u64.value;
263683e05c0SSteen Hegelund 		mask = kf->data.u64.mask;
264683e05c0SSteen Hegelund 		break;
265683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
266683e05c0SSteen Hegelund 		value = kf->data.u72.value;
267683e05c0SSteen Hegelund 		mask = kf->data.u72.mask;
268683e05c0SSteen Hegelund 		break;
269683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
270683e05c0SSteen Hegelund 		value = kf->data.u112.value;
271683e05c0SSteen Hegelund 		mask = kf->data.u112.mask;
272683e05c0SSteen Hegelund 		break;
273683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
274683e05c0SSteen Hegelund 		value = kf->data.u128.value;
275683e05c0SSteen Hegelund 		mask = kf->data.u128.mask;
276683e05c0SSteen Hegelund 		break;
277683e05c0SSteen Hegelund 	}
278683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
279683e05c0SSteen Hegelund 	vcap_encode_field(cache->keystream, &iter, rf->width, value);
280683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
281683e05c0SSteen Hegelund 	vcap_encode_field(cache->maskstream, &iter, rf->width, mask);
282683e05c0SSteen Hegelund }
283683e05c0SSteen Hegelund 
284683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl,
285683e05c0SSteen Hegelund 					    struct vcap_rule_internal *ri,
286683e05c0SSteen Hegelund 					    const struct vcap_typegroup *tgt)
287683e05c0SSteen Hegelund {
288683e05c0SSteen Hegelund 	int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width;
289683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
290683e05c0SSteen Hegelund 
291683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the key and the mask in their streams,
292683e05c0SSteen Hegelund 	 * respecting the subword width.
293683e05c0SSteen Hegelund 	 */
294683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->keystream, sw_width, tgt, false);
295683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true);
296683e05c0SSteen Hegelund }
297683e05c0SSteen Hegelund 
298683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
299683e05c0SSteen Hegelund {
300683e05c0SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
301683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
302683e05c0SSteen Hegelund 	const struct vcap_field *kf_table;
303683e05c0SSteen Hegelund 	int keyset_size;
304683e05c0SSteen Hegelund 
305683e05c0SSteen Hegelund 	/* Get a valid set of fields for the specific keyset */
306683e05c0SSteen Hegelund 	kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset);
307683e05c0SSteen Hegelund 	if (!kf_table) {
308683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this keyset: %d\n",
309683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
310683e05c0SSteen Hegelund 		return -EINVAL;
311683e05c0SSteen Hegelund 	}
312683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific keyset */
313683e05c0SSteen Hegelund 	tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype,
314683e05c0SSteen Hegelund 					   ri->data.keyset);
315683e05c0SSteen Hegelund 	if (!tg_table) {
316683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this keyset: %d\n",
317683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
318683e05c0SSteen Hegelund 		return -EINVAL;
319683e05c0SSteen Hegelund 	}
320683e05c0SSteen Hegelund 	/* Get a valid size for the specific keyset */
321683e05c0SSteen Hegelund 	keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype,
322683e05c0SSteen Hegelund 					  ri->data.keyset);
323683e05c0SSteen Hegelund 	if (keyset_size == 0) {
324683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this keyset: %d\n",
325683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
326683e05c0SSteen Hegelund 		return -EINVAL;
327683e05c0SSteen Hegelund 	}
328683e05c0SSteen Hegelund 	/* Iterate over the keyfields (key, mask) in the rule
329683e05c0SSteen Hegelund 	 * and encode these bits
330683e05c0SSteen Hegelund 	 */
331683e05c0SSteen Hegelund 	if (list_empty(&ri->data.keyfields)) {
332683e05c0SSteen Hegelund 		pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__);
333683e05c0SSteen Hegelund 		return -EINVAL;
334683e05c0SSteen Hegelund 	}
335683e05c0SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
336683e05c0SSteen Hegelund 		/* Check that the client entry exists in the keyset */
337683e05c0SSteen Hegelund 		if (ckf->ctrl.key >= keyset_size) {
338683e05c0SSteen Hegelund 			pr_err("%s:%d: key %d is not in vcap\n",
339683e05c0SSteen Hegelund 			       __func__, __LINE__, ckf->ctrl.key);
340683e05c0SSteen Hegelund 			return -EINVAL;
341683e05c0SSteen Hegelund 		}
342683e05c0SSteen Hegelund 		vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table);
343683e05c0SSteen Hegelund 	}
344683e05c0SSteen Hegelund 	/* Add typegroup bits to the key/mask bitstreams */
345683e05c0SSteen Hegelund 	vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table);
346683e05c0SSteen Hegelund 	return 0;
347683e05c0SSteen Hegelund }
348683e05c0SSteen Hegelund 
349683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */
350683e05c0SSteen Hegelund static const struct vcap_field *
351683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl,
352683e05c0SSteen Hegelund 		  enum vcap_type vt, enum vcap_actionfield_set actionset)
353683e05c0SSteen Hegelund {
354683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
355683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
356683e05c0SSteen Hegelund 		return NULL;
357683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map[actionset];
358683e05c0SSteen Hegelund }
359683e05c0SSteen Hegelund 
3608e10490bSSteen Hegelund static const struct vcap_set *
3618e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl,
3628e10490bSSteen Hegelund 		    enum vcap_type vt, enum vcap_actionfield_set actionset)
3638e10490bSSteen Hegelund {
3648e10490bSSteen Hegelund 	const struct vcap_set *aset;
3658e10490bSSteen Hegelund 
3668e10490bSSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
3678e10490bSSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
3688e10490bSSteen Hegelund 		return NULL;
3698e10490bSSteen Hegelund 	aset = &vctrl->vcaps[vt].actionfield_set[actionset];
3708e10490bSSteen Hegelund 	if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count)
3718e10490bSSteen Hegelund 		return NULL;
3728e10490bSSteen Hegelund 	return aset;
3738e10490bSSteen Hegelund }
3748e10490bSSteen Hegelund 
375683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */
376683e05c0SSteen Hegelund static const struct vcap_typegroup *
377683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl,
378683e05c0SSteen Hegelund 			   enum vcap_type vt, enum vcap_actionfield_set actionset)
379683e05c0SSteen Hegelund {
380683e05c0SSteen Hegelund 	const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset);
381683e05c0SSteen Hegelund 
382683e05c0SSteen Hegelund 	/* Check that the actionset is valid */
383683e05c0SSteen Hegelund 	if (!aset)
384683e05c0SSteen Hegelund 		return NULL;
385683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item];
386683e05c0SSteen Hegelund }
387683e05c0SSteen Hegelund 
388683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */
389683e05c0SSteen Hegelund static int vcap_actionfield_count(struct vcap_control *vctrl,
390683e05c0SSteen Hegelund 				  enum vcap_type vt,
391683e05c0SSteen Hegelund 				  enum vcap_actionfield_set actionset)
392683e05c0SSteen Hegelund {
393683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
394683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
395683e05c0SSteen Hegelund 		return 0;
396683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map_size[actionset];
397683e05c0SSteen Hegelund }
398683e05c0SSteen Hegelund 
399683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri,
400683e05c0SSteen Hegelund 				    const struct vcap_client_actionfield *af,
401683e05c0SSteen Hegelund 				    const struct vcap_field *rf,
402683e05c0SSteen Hegelund 				    const struct vcap_typegroup *tgt)
403683e05c0SSteen Hegelund {
404683e05c0SSteen Hegelund 	int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
405683e05c0SSteen Hegelund 
406683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
407683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
408683e05c0SSteen Hegelund 	const u8 *value;
409683e05c0SSteen Hegelund 
410683e05c0SSteen Hegelund 	/* Encode the action field in the stream, respecting the subword width */
411683e05c0SSteen Hegelund 	switch (af->ctrl.type) {
412683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
413683e05c0SSteen Hegelund 		value = &af->data.u1.value;
414683e05c0SSteen Hegelund 		break;
415683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
416683e05c0SSteen Hegelund 		value = (const u8 *)&af->data.u32.value;
417683e05c0SSteen Hegelund 		break;
418683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
419683e05c0SSteen Hegelund 		value = af->data.u48.value;
420683e05c0SSteen Hegelund 		break;
421683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
422683e05c0SSteen Hegelund 		value = af->data.u56.value;
423683e05c0SSteen Hegelund 		break;
424683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
425683e05c0SSteen Hegelund 		value = af->data.u64.value;
426683e05c0SSteen Hegelund 		break;
427683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
428683e05c0SSteen Hegelund 		value = af->data.u72.value;
429683e05c0SSteen Hegelund 		break;
430683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
431683e05c0SSteen Hegelund 		value = af->data.u112.value;
432683e05c0SSteen Hegelund 		break;
433683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
434683e05c0SSteen Hegelund 		value = af->data.u128.value;
435683e05c0SSteen Hegelund 		break;
436683e05c0SSteen Hegelund 	}
437683e05c0SSteen Hegelund 	vcap_iter_init(&iter, act_width, tgt, rf->offset);
438683e05c0SSteen Hegelund 	vcap_encode_field(cache->actionstream, &iter, rf->width, value);
439683e05c0SSteen Hegelund }
440683e05c0SSteen Hegelund 
441683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri,
442683e05c0SSteen Hegelund 					       const struct vcap_typegroup *tgt)
443683e05c0SSteen Hegelund {
444683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
445683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
446683e05c0SSteen Hegelund 
447683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the actionstream respecting the subword
448683e05c0SSteen Hegelund 	 * width.
449683e05c0SSteen Hegelund 	 */
450683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false);
451683e05c0SSteen Hegelund }
452683e05c0SSteen Hegelund 
453683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri)
454683e05c0SSteen Hegelund {
455683e05c0SSteen Hegelund 	const struct vcap_client_actionfield *caf;
456683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
457683e05c0SSteen Hegelund 	const struct vcap_field *af_table;
458683e05c0SSteen Hegelund 	int actionset_size;
459683e05c0SSteen Hegelund 
460683e05c0SSteen Hegelund 	/* Get a valid set of actionset fields for the specific actionset */
461683e05c0SSteen Hegelund 	af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype,
462683e05c0SSteen Hegelund 				     ri->data.actionset);
463683e05c0SSteen Hegelund 	if (!af_table) {
464683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this actionset: %d\n",
465683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
466683e05c0SSteen Hegelund 		return -EINVAL;
467683e05c0SSteen Hegelund 	}
468683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific actionset */
469683e05c0SSteen Hegelund 	tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype,
470683e05c0SSteen Hegelund 					      ri->data.actionset);
471683e05c0SSteen Hegelund 	if (!tg_table) {
472683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this actionset: %d\n",
473683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
474683e05c0SSteen Hegelund 		return -EINVAL;
475683e05c0SSteen Hegelund 	}
476683e05c0SSteen Hegelund 	/* Get a valid actionset size for the specific actionset */
477683e05c0SSteen Hegelund 	actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype,
478683e05c0SSteen Hegelund 						ri->data.actionset);
479683e05c0SSteen Hegelund 	if (actionset_size == 0) {
480683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this actionset: %d\n",
481683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
482683e05c0SSteen Hegelund 		return -EINVAL;
483683e05c0SSteen Hegelund 	}
484683e05c0SSteen Hegelund 	/* Iterate over the actionfields in the rule
485683e05c0SSteen Hegelund 	 * and encode these bits
486683e05c0SSteen Hegelund 	 */
487683e05c0SSteen Hegelund 	if (list_empty(&ri->data.actionfields))
488683e05c0SSteen Hegelund 		pr_warn("%s:%d: no actionfields in the rule\n",
489683e05c0SSteen Hegelund 			__func__, __LINE__);
490683e05c0SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
491683e05c0SSteen Hegelund 		/* Check that the client action exists in the actionset */
492683e05c0SSteen Hegelund 		if (caf->ctrl.action >= actionset_size) {
493683e05c0SSteen Hegelund 			pr_err("%s:%d: action %d is not in vcap\n",
494683e05c0SSteen Hegelund 			       __func__, __LINE__, caf->ctrl.action);
495683e05c0SSteen Hegelund 			return -EINVAL;
496683e05c0SSteen Hegelund 		}
497683e05c0SSteen Hegelund 		vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action],
498683e05c0SSteen Hegelund 					tg_table);
499683e05c0SSteen Hegelund 	}
500683e05c0SSteen Hegelund 	/* Add typegroup bits to the entry bitstreams */
501683e05c0SSteen Hegelund 	vcap_encode_actionfield_typegroups(ri, tg_table);
502683e05c0SSteen Hegelund 	return 0;
503683e05c0SSteen Hegelund }
504683e05c0SSteen Hegelund 
5058e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri)
5068e10490bSSteen Hegelund {
507683e05c0SSteen Hegelund 	int err;
508683e05c0SSteen Hegelund 
509683e05c0SSteen Hegelund 	err = vcap_encode_rule_keyset(ri);
510683e05c0SSteen Hegelund 	if (err)
511683e05c0SSteen Hegelund 		return err;
512683e05c0SSteen Hegelund 	err = vcap_encode_rule_actionset(ri);
513683e05c0SSteen Hegelund 	if (err)
514683e05c0SSteen Hegelund 		return err;
5158e10490bSSteen Hegelund 	return 0;
5168e10490bSSteen Hegelund }
5178e10490bSSteen Hegelund 
5188e10490bSSteen Hegelund static int vcap_api_check(struct vcap_control *ctrl)
5198e10490bSSteen Hegelund {
5208e10490bSSteen Hegelund 	if (!ctrl) {
5218e10490bSSteen Hegelund 		pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
5228e10490bSSteen Hegelund 		return -EINVAL;
5238e10490bSSteen Hegelund 	}
5248e10490bSSteen Hegelund 	if (!ctrl->ops || !ctrl->ops->validate_keyset ||
5258e10490bSSteen Hegelund 	    !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
5268e10490bSSteen Hegelund 	    !ctrl->ops->cache_write || !ctrl->ops->cache_read ||
5278e10490bSSteen Hegelund 	    !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
52867456717SSteen Hegelund 	    !ctrl->ops->port_info || !ctrl->ops->enable) {
5298e10490bSSteen Hegelund 		pr_err("%s:%d: client operations are missing\n",
5308e10490bSSteen Hegelund 		       __func__, __LINE__);
5318e10490bSSteen Hegelund 		return -ENOENT;
5328e10490bSSteen Hegelund 	}
5338e10490bSSteen Hegelund 	return 0;
5348e10490bSSteen Hegelund }
5358e10490bSSteen Hegelund 
5368e10490bSSteen Hegelund static void vcap_erase_cache(struct vcap_rule_internal *ri)
5378e10490bSSteen Hegelund {
5388e10490bSSteen Hegelund 	ri->vctrl->ops->cache_erase(ri->admin);
5398e10490bSSteen Hegelund }
5408e10490bSSteen Hegelund 
541c9da1ac1SSteen Hegelund /* Update the keyset for the rule */
542c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule,
543c9da1ac1SSteen Hegelund 			     enum vcap_keyfield_set keyset)
544c9da1ac1SSteen Hegelund {
5458e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
5468e10490bSSteen Hegelund 	const struct vcap_set *kset;
5478e10490bSSteen Hegelund 	int sw_width;
5488e10490bSSteen Hegelund 
5498e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset);
5508e10490bSSteen Hegelund 	/* Check that the keyset is valid */
5518e10490bSSteen Hegelund 	if (!kset)
5528e10490bSSteen Hegelund 		return -EINVAL;
5538e10490bSSteen Hegelund 	ri->keyset_sw = kset->sw_per_item;
5548e10490bSSteen Hegelund 	sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
5558e10490bSSteen Hegelund 	ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32);
5568e10490bSSteen Hegelund 	ri->data.keyset = keyset;
557c9da1ac1SSteen Hegelund 	return 0;
558c9da1ac1SSteen Hegelund }
559c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset);
560c9da1ac1SSteen Hegelund 
561c9da1ac1SSteen Hegelund /* Update the actionset for the rule */
562c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule,
563c9da1ac1SSteen Hegelund 				enum vcap_actionfield_set actionset)
564c9da1ac1SSteen Hegelund {
5658e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
5668e10490bSSteen Hegelund 	const struct vcap_set *aset;
5678e10490bSSteen Hegelund 	int act_width;
5688e10490bSSteen Hegelund 
5698e10490bSSteen Hegelund 	aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset);
5708e10490bSSteen Hegelund 	/* Check that the actionset is valid */
5718e10490bSSteen Hegelund 	if (!aset)
5728e10490bSSteen Hegelund 		return -EINVAL;
5738e10490bSSteen Hegelund 	ri->actionset_sw = aset->sw_per_item;
5748e10490bSSteen Hegelund 	act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
5758e10490bSSteen Hegelund 	ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32);
5768e10490bSSteen Hegelund 	ri->data.actionset = actionset;
577c9da1ac1SSteen Hegelund 	return 0;
578c9da1ac1SSteen Hegelund }
579c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset);
580c9da1ac1SSteen Hegelund 
581c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */
582c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl,
583c9da1ac1SSteen Hegelund 						   u32 id)
584c9da1ac1SSteen Hegelund {
585c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
586c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
587c9da1ac1SSteen Hegelund 
588c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
589c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
590c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
591c9da1ac1SSteen Hegelund 			if (ri->data.id == id)
592c9da1ac1SSteen Hegelund 				return ri;
593c9da1ac1SSteen Hegelund 	return NULL;
594c9da1ac1SSteen Hegelund }
595c9da1ac1SSteen Hegelund 
596c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */
597c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
598c9da1ac1SSteen Hegelund {
599c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
600c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
601c9da1ac1SSteen Hegelund 
602c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
603c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
604c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
605c9da1ac1SSteen Hegelund 			if (ri->data.cookie == cookie)
606c9da1ac1SSteen Hegelund 				return ri->data.id;
607c9da1ac1SSteen Hegelund 	return -ENOENT;
608c9da1ac1SSteen Hegelund }
609c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
610c9da1ac1SSteen Hegelund 
6118e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */
6128e10490bSSteen Hegelund static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
6138e10490bSSteen Hegelund {
6148e10490bSSteen Hegelund 	struct vcap_rule_internal *duprule;
6158e10490bSSteen Hegelund 
6168e10490bSSteen Hegelund 	/* Allocate the client part */
6178e10490bSSteen Hegelund 	duprule = kzalloc(sizeof(*duprule), GFP_KERNEL);
6188e10490bSSteen Hegelund 	if (!duprule)
6198e10490bSSteen Hegelund 		return ERR_PTR(-ENOMEM);
6208e10490bSSteen Hegelund 	*duprule = *ri;
6218e10490bSSteen Hegelund 	/* Not inserted in the VCAP */
6228e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->list);
6238e10490bSSteen Hegelund 	/* No elements in these lists */
6248e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.keyfields);
6258e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.actionfields);
6268e10490bSSteen Hegelund 	return duprule;
6278e10490bSSteen Hegelund }
6288e10490bSSteen Hegelund 
6298e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */
6308e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri)
6318e10490bSSteen Hegelund {
6328e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
6338e10490bSSteen Hegelund 	int sw_idx, ent_idx = 0, act_idx = 0;
6348e10490bSSteen Hegelund 	u32 addr = ri->addr;
6358e10490bSSteen Hegelund 
6368e10490bSSteen Hegelund 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
6378e10490bSSteen Hegelund 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
6388e10490bSSteen Hegelund 		return -EINVAL;
6398e10490bSSteen Hegelund 	}
6408e10490bSSteen Hegelund 	/* Use the values in the streams to write the VCAP cache */
6418e10490bSSteen Hegelund 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
6428e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
6438e10490bSSteen Hegelund 					    VCAP_SEL_ENTRY, ent_idx,
6448e10490bSSteen Hegelund 					    ri->keyset_sw_regs);
6458e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
6468e10490bSSteen Hegelund 					    VCAP_SEL_ACTION, act_idx,
6478e10490bSSteen Hegelund 					    ri->actionset_sw_regs);
6488e10490bSSteen Hegelund 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
6498e10490bSSteen Hegelund 				       VCAP_SEL_ALL, addr);
6508e10490bSSteen Hegelund 		ent_idx += ri->keyset_sw_regs;
6518e10490bSSteen Hegelund 		act_idx += ri->actionset_sw_regs;
6528e10490bSSteen Hegelund 	}
6538e10490bSSteen Hegelund 	return 0;
6548e10490bSSteen Hegelund }
6558e10490bSSteen Hegelund 
656*f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri,
657*f13230a4SSteen Hegelund 			      struct vcap_counter *ctr)
658*f13230a4SSteen Hegelund {
659*f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
660*f13230a4SSteen Hegelund 
661*f13230a4SSteen Hegelund 	admin->cache.counter = ctr->value;
662*f13230a4SSteen Hegelund 	admin->cache.sticky = ctr->sticky;
663*f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
664*f13230a4SSteen Hegelund 				    ri->counter_id, 0);
665*f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
666*f13230a4SSteen Hegelund 			       VCAP_SEL_COUNTER, ri->addr);
667*f13230a4SSteen Hegelund 	return 0;
668*f13230a4SSteen Hegelund }
669*f13230a4SSteen Hegelund 
6707de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */
6717de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
6727de1dcadSSteen Hegelund {
6737de1dcadSSteen Hegelund 	int lookup_first = admin->vinst * admin->lookups_per_instance;
6747de1dcadSSteen Hegelund 	int lookup_last = lookup_first + admin->lookups_per_instance;
6757de1dcadSSteen Hegelund 	int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE;
6767de1dcadSSteen Hegelund 	int cid = admin->first_cid;
6777de1dcadSSteen Hegelund 	int lookup;
6787de1dcadSSteen Hegelund 
6797de1dcadSSteen Hegelund 	for (lookup = lookup_first; lookup < lookup_last; ++lookup,
6807de1dcadSSteen Hegelund 	     cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE)
6817de1dcadSSteen Hegelund 		if (cur_cid >= cid && cur_cid < cid_next)
6827de1dcadSSteen Hegelund 			return lookup;
6837de1dcadSSteen Hegelund 	return 0;
6847de1dcadSSteen Hegelund }
6857de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup);
6867de1dcadSSteen Hegelund 
687c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */
688c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
689c9da1ac1SSteen Hegelund {
690c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
691c9da1ac1SSteen Hegelund 
6928e10490bSSteen Hegelund 	if (vcap_api_check(vctrl))
6938e10490bSSteen Hegelund 		return NULL;
6948e10490bSSteen Hegelund 
695c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
696c9da1ac1SSteen Hegelund 		if (cid >= admin->first_cid && cid <= admin->last_cid)
697c9da1ac1SSteen Hegelund 			return admin;
698c9da1ac1SSteen Hegelund 	}
699c9da1ac1SSteen Hegelund 	return NULL;
700c9da1ac1SSteen Hegelund }
701c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin);
702c9da1ac1SSteen Hegelund 
703392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */
704392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid)
705392d0ab0SSteen Hegelund {
706392d0ab0SSteen Hegelund 	struct vcap_admin *admin, *next_admin;
707392d0ab0SSteen Hegelund 	int lookup, next_lookup;
708392d0ab0SSteen Hegelund 
709392d0ab0SSteen Hegelund 	/* The offset must be at least one lookup */
710392d0ab0SSteen Hegelund 	if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
711392d0ab0SSteen Hegelund 		return false;
712392d0ab0SSteen Hegelund 
713392d0ab0SSteen Hegelund 	if (vcap_api_check(vctrl))
714392d0ab0SSteen Hegelund 		return false;
715392d0ab0SSteen Hegelund 
716392d0ab0SSteen Hegelund 	admin = vcap_find_admin(vctrl, cur_cid);
717392d0ab0SSteen Hegelund 	if (!admin)
718392d0ab0SSteen Hegelund 		return false;
719392d0ab0SSteen Hegelund 
720392d0ab0SSteen Hegelund 	/* If no VCAP contains the next chain, the next chain must be beyond
721392d0ab0SSteen Hegelund 	 * the last chain in the current VCAP
722392d0ab0SSteen Hegelund 	 */
723392d0ab0SSteen Hegelund 	next_admin = vcap_find_admin(vctrl, next_cid);
724392d0ab0SSteen Hegelund 	if (!next_admin)
725392d0ab0SSteen Hegelund 		return next_cid > admin->last_cid;
726392d0ab0SSteen Hegelund 
727392d0ab0SSteen Hegelund 	lookup = vcap_chain_id_to_lookup(admin, cur_cid);
728392d0ab0SSteen Hegelund 	next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid);
729392d0ab0SSteen Hegelund 
730392d0ab0SSteen Hegelund 	/* Next lookup must be the following lookup */
731392d0ab0SSteen Hegelund 	if (admin == next_admin || admin->vtype == next_admin->vtype)
732392d0ab0SSteen Hegelund 		return next_lookup == lookup + 1;
733392d0ab0SSteen Hegelund 
734392d0ab0SSteen Hegelund 	/* Must be the first lookup in the next VCAP instance */
735392d0ab0SSteen Hegelund 	return next_lookup == 0;
736392d0ab0SSteen Hegelund }
737392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
738392d0ab0SSteen Hegelund 
7398e10490bSSteen Hegelund /* Check if there is room for a new rule */
7408e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size)
7418e10490bSSteen Hegelund {
7428e10490bSSteen Hegelund 	if (admin->last_used_addr - size < admin->first_valid_addr) {
7438e10490bSSteen Hegelund 		pr_err("%s:%d: No room for rule size: %u, %u\n",
7448e10490bSSteen Hegelund 		       __func__, __LINE__, size, admin->first_valid_addr);
7458e10490bSSteen Hegelund 		return -ENOSPC;
7468e10490bSSteen Hegelund 	}
7478e10490bSSteen Hegelund 	return 0;
7488e10490bSSteen Hegelund }
7498e10490bSSteen Hegelund 
7508e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */
7518e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule)
7528e10490bSSteen Hegelund {
7538e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
7548e10490bSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
7558e10490bSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
7568e10490bSSteen Hegelund 	const struct vcap_field *fields;
7578e10490bSSteen Hegelund 	const struct vcap_set *kset;
7588e10490bSSteen Hegelund 	int ret = -EINVAL;
7598e10490bSSteen Hegelund 
7608e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, vt, keyset);
7618e10490bSSteen Hegelund 	if (!kset)
7628e10490bSSteen Hegelund 		return ret;
7638e10490bSSteen Hegelund 	if (kset->type_id == (u8)-1)  /* No type field is needed */
7648e10490bSSteen Hegelund 		return 0;
7658e10490bSSteen Hegelund 
7668e10490bSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
7678e10490bSSteen Hegelund 	if (!fields)
7688e10490bSSteen Hegelund 		return -EINVAL;
7698e10490bSSteen Hegelund 	if (fields[VCAP_KF_TYPE].width > 1) {
7708e10490bSSteen Hegelund 		ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE,
7718e10490bSSteen Hegelund 					    kset->type_id, 0xff);
7728e10490bSSteen Hegelund 	} else {
7738e10490bSSteen Hegelund 		if (kset->type_id)
7748e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
7758e10490bSSteen Hegelund 						    VCAP_BIT_1);
7768e10490bSSteen Hegelund 		else
7778e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
7788e10490bSSteen Hegelund 						    VCAP_BIT_0);
7798e10490bSSteen Hegelund 	}
7808e10490bSSteen Hegelund 	return 0;
7818e10490bSSteen Hegelund }
7828e10490bSSteen Hegelund 
783abc4010dSSteen Hegelund /* Add a keyset to a keyset list */
784abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
785abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset)
786abc4010dSSteen Hegelund {
787abc4010dSSteen Hegelund 	int idx;
788abc4010dSSteen Hegelund 
789abc4010dSSteen Hegelund 	if (keysetlist->cnt < keysetlist->max) {
790abc4010dSSteen Hegelund 		/* Avoid duplicates */
791abc4010dSSteen Hegelund 		for (idx = 0; idx < keysetlist->cnt; ++idx)
792abc4010dSSteen Hegelund 			if (keysetlist->keysets[idx] == keyset)
793abc4010dSSteen Hegelund 				return keysetlist->cnt < keysetlist->max;
794abc4010dSSteen Hegelund 		keysetlist->keysets[keysetlist->cnt++] = keyset;
795abc4010dSSteen Hegelund 	}
796abc4010dSSteen Hegelund 	return keysetlist->cnt < keysetlist->max;
797abc4010dSSteen Hegelund }
798abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add);
799abc4010dSSteen Hegelund 
800abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */
801abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl,
802abc4010dSSteen Hegelund 			     enum vcap_keyfield_set keyset)
803abc4010dSSteen Hegelund {
804abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_set_names[keyset];
805abc4010dSSteen Hegelund }
806abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name);
807abc4010dSSteen Hegelund 
808abc4010dSSteen Hegelund /* map key field id to a string with the key name */
809abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl,
810abc4010dSSteen Hegelund 			       enum vcap_key_field key)
811abc4010dSSteen Hegelund {
812abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_names[key];
813abc4010dSSteen Hegelund }
814abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name);
815abc4010dSSteen Hegelund 
816242df4f7SSteen Hegelund /* map action field id to a string with the action name */
817242df4f7SSteen Hegelund static const char *vcap_actionfield_name(struct vcap_control *vctrl,
818242df4f7SSteen Hegelund 					 enum vcap_action_field action)
819242df4f7SSteen Hegelund {
820242df4f7SSteen Hegelund 	return vctrl->stats->actionfield_names[action];
821242df4f7SSteen Hegelund }
822242df4f7SSteen Hegelund 
823abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */
824abc4010dSSteen Hegelund static const struct vcap_field *
825abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl,
826abc4010dSSteen Hegelund 			  enum vcap_type vtype,
827abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset,
828abc4010dSSteen Hegelund 			  enum vcap_key_field key)
829abc4010dSSteen Hegelund {
830abc4010dSSteen Hegelund 	const struct vcap_field *fields;
831abc4010dSSteen Hegelund 	int idx, count;
832abc4010dSSteen Hegelund 
833abc4010dSSteen Hegelund 	fields = vcap_keyfields(vctrl, vtype, keyset);
834abc4010dSSteen Hegelund 	if (!fields)
835abc4010dSSteen Hegelund 		return NULL;
836abc4010dSSteen Hegelund 
837abc4010dSSteen Hegelund 	/* Iterate the keyfields of the keyset */
838abc4010dSSteen Hegelund 	count = vcap_keyfield_count(vctrl, vtype, keyset);
839abc4010dSSteen Hegelund 	for (idx = 0; idx < count; ++idx) {
840abc4010dSSteen Hegelund 		if (fields[idx].width == 0)
841abc4010dSSteen Hegelund 			continue;
842abc4010dSSteen Hegelund 
843abc4010dSSteen Hegelund 		if (key == idx)
844abc4010dSSteen Hegelund 			return &fields[idx];
845abc4010dSSteen Hegelund 	}
846abc4010dSSteen Hegelund 
847abc4010dSSteen Hegelund 	return NULL;
848abc4010dSSteen Hegelund }
849abc4010dSSteen Hegelund 
850abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
851abc4010dSSteen Hegelund static bool vcap_rule_find_keysets(struct vcap_rule_internal *ri,
852abc4010dSSteen Hegelund 				   struct vcap_keyset_list *matches)
853abc4010dSSteen Hegelund {
854abc4010dSSteen Hegelund 	const struct vcap_client_keyfield *ckf;
855abc4010dSSteen Hegelund 	int keyset, found, keycount, map_size;
856abc4010dSSteen Hegelund 	const struct vcap_field **map;
857abc4010dSSteen Hegelund 	enum vcap_type vtype;
858abc4010dSSteen Hegelund 
859abc4010dSSteen Hegelund 	vtype = ri->admin->vtype;
860abc4010dSSteen Hegelund 	map = ri->vctrl->vcaps[vtype].keyfield_set_map;
861abc4010dSSteen Hegelund 	map_size = ri->vctrl->vcaps[vtype].keyfield_set_size;
862abc4010dSSteen Hegelund 
863abc4010dSSteen Hegelund 	/* Get a count of the keyfields we want to match */
864abc4010dSSteen Hegelund 	keycount = 0;
865abc4010dSSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
866abc4010dSSteen Hegelund 		++keycount;
867abc4010dSSteen Hegelund 
868abc4010dSSteen Hegelund 	matches->cnt = 0;
869abc4010dSSteen Hegelund 	/* Iterate the keysets of the VCAP */
870abc4010dSSteen Hegelund 	for (keyset = 0; keyset < map_size; ++keyset) {
871abc4010dSSteen Hegelund 		if (!map[keyset])
872abc4010dSSteen Hegelund 			continue;
873abc4010dSSteen Hegelund 
874abc4010dSSteen Hegelund 		/* Iterate the keys in the rule */
875abc4010dSSteen Hegelund 		found = 0;
876abc4010dSSteen Hegelund 		list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
877abc4010dSSteen Hegelund 			if (vcap_find_keyset_keyfield(ri->vctrl, vtype,
878abc4010dSSteen Hegelund 						      keyset, ckf->ctrl.key))
879abc4010dSSteen Hegelund 				++found;
880abc4010dSSteen Hegelund 
881abc4010dSSteen Hegelund 		/* Save the keyset if all keyfields were found */
882abc4010dSSteen Hegelund 		if (found == keycount)
883abc4010dSSteen Hegelund 			if (!vcap_keyset_list_add(matches, keyset))
884abc4010dSSteen Hegelund 				/* bail out when the quota is filled */
885abc4010dSSteen Hegelund 				break;
886abc4010dSSteen Hegelund 	}
887abc4010dSSteen Hegelund 
888abc4010dSSteen Hegelund 	return matches->cnt > 0;
889abc4010dSSteen Hegelund }
890abc4010dSSteen Hegelund 
891c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
892c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
893c9da1ac1SSteen Hegelund {
894c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
895abc4010dSSteen Hegelund 	struct vcap_keyset_list matches = {};
8968e10490bSSteen Hegelund 	enum vcap_keyfield_set keysets[10];
8978e10490bSSteen Hegelund 	int ret;
898c9da1ac1SSteen Hegelund 
8998e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
9008e10490bSSteen Hegelund 	if (ret)
9018e10490bSSteen Hegelund 		return ret;
902c9da1ac1SSteen Hegelund 	if (!ri->admin) {
903c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ADMIN;
904c9da1ac1SSteen Hegelund 		return -EINVAL;
905c9da1ac1SSteen Hegelund 	}
906c9da1ac1SSteen Hegelund 	if (!ri->ndev) {
907c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_NETDEV;
908c9da1ac1SSteen Hegelund 		return -EINVAL;
909c9da1ac1SSteen Hegelund 	}
910abc4010dSSteen Hegelund 
911abc4010dSSteen Hegelund 	matches.keysets = keysets;
912abc4010dSSteen Hegelund 	matches.max = ARRAY_SIZE(keysets);
913c9da1ac1SSteen Hegelund 	if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
914abc4010dSSteen Hegelund 		/* Iterate over rule keyfields and select keysets that fits */
915abc4010dSSteen Hegelund 		if (!vcap_rule_find_keysets(ri, &matches)) {
916c9da1ac1SSteen Hegelund 			ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
917c9da1ac1SSteen Hegelund 			return -EINVAL;
918c9da1ac1SSteen Hegelund 		}
919abc4010dSSteen Hegelund 	} else {
9208e10490bSSteen Hegelund 		/* prepare for keyset validation */
9218e10490bSSteen Hegelund 		keysets[0] = ri->data.keyset;
922abc4010dSSteen Hegelund 		matches.cnt = 1;
923abc4010dSSteen Hegelund 	}
924abc4010dSSteen Hegelund 
9258e10490bSSteen Hegelund 	/* Pick a keyset that is supported in the port lookups */
926abc4010dSSteen Hegelund 	ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule,
927abc4010dSSteen Hegelund 					      &matches, l3_proto);
9288e10490bSSteen Hegelund 	if (ret < 0) {
9298e10490bSSteen Hegelund 		pr_err("%s:%d: keyset validation failed: %d\n",
9308e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
9318e10490bSSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
9328e10490bSSteen Hegelund 		return ret;
9338e10490bSSteen Hegelund 	}
934abc4010dSSteen Hegelund 	/* use the keyset that is supported in the port lookups */
935abc4010dSSteen Hegelund 	ret = vcap_set_rule_set_keyset(rule, ret);
936abc4010dSSteen Hegelund 	if (ret < 0) {
937abc4010dSSteen Hegelund 		pr_err("%s:%d: keyset was not updated: %d\n",
938abc4010dSSteen Hegelund 		       __func__, __LINE__, ret);
939abc4010dSSteen Hegelund 		return ret;
940abc4010dSSteen Hegelund 	}
941c9da1ac1SSteen Hegelund 	if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
942abc4010dSSteen Hegelund 		/* Later also actionsets will be matched against actions in
943abc4010dSSteen Hegelund 		 * the rule, and the type will be set accordingly
944abc4010dSSteen Hegelund 		 */
945c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
946c9da1ac1SSteen Hegelund 		return -EINVAL;
947c9da1ac1SSteen Hegelund 	}
9488e10490bSSteen Hegelund 	vcap_add_type_keyfield(rule);
9498e10490bSSteen Hegelund 	/* Add default fields to this rule */
9508e10490bSSteen Hegelund 	ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
9518e10490bSSteen Hegelund 
9528e10490bSSteen Hegelund 	/* Rule size is the maximum of the entry and action subword count */
9538e10490bSSteen Hegelund 	ri->size = max(ri->keyset_sw, ri->actionset_sw);
9548e10490bSSteen Hegelund 
9558e10490bSSteen Hegelund 	/* Finally check if there is room for the rule in the VCAP */
9568e10490bSSteen Hegelund 	return vcap_rule_space(ri->admin, ri->size);
957c9da1ac1SSteen Hegelund }
958c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
959c9da1ac1SSteen Hegelund 
960990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key.
961990e4839SSteen Hegelund  * I.e. Lowest numerical sort_key is first in list.
962990e4839SSteen Hegelund  * In order to locate largest keys first in list we negate the key size with
963990e4839SSteen Hegelund  * (max_size - size).
964990e4839SSteen Hegelund  */
965990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
966990e4839SSteen Hegelund {
967990e4839SSteen Hegelund 	return ((max_size - size) << 24) | (user << 16) | prio;
968990e4839SSteen Hegelund }
969990e4839SSteen Hegelund 
9708e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
9718e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
9728e10490bSSteen Hegelund {
9738e10490bSSteen Hegelund 	return ((addr - ri->size) /  ri->size) * ri->size;
9748e10490bSSteen Hegelund }
9758e10490bSSteen Hegelund 
976c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
977c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
978c9da1ac1SSteen Hegelund {
979c9da1ac1SSteen Hegelund 	u32 next_id;
980c9da1ac1SSteen Hegelund 
981c9da1ac1SSteen Hegelund 	if (ri->data.id != 0)
982c9da1ac1SSteen Hegelund 		return ri->data.id;
983c9da1ac1SSteen Hegelund 
984c9da1ac1SSteen Hegelund 	next_id = ri->vctrl->rule_id + 1;
985c9da1ac1SSteen Hegelund 
986c9da1ac1SSteen Hegelund 	for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) {
987c9da1ac1SSteen Hegelund 		if (!vcap_lookup_rule(ri->vctrl, next_id)) {
988c9da1ac1SSteen Hegelund 			ri->data.id = next_id;
989c9da1ac1SSteen Hegelund 			ri->vctrl->rule_id = next_id;
990c9da1ac1SSteen Hegelund 			break;
991c9da1ac1SSteen Hegelund 		}
992c9da1ac1SSteen Hegelund 	}
993c9da1ac1SSteen Hegelund 	return ri->data.id;
994c9da1ac1SSteen Hegelund }
995c9da1ac1SSteen Hegelund 
9968e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
9978e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
9988e10490bSSteen Hegelund {
999990e4839SSteen Hegelund 	int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
1000990e4839SSteen Hegelund 	struct vcap_rule_internal *duprule, *iter, *elem = NULL;
10018e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1002990e4839SSteen Hegelund 	u32 addr;
10038e10490bSSteen Hegelund 
1004990e4839SSteen Hegelund 	ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
1005990e4839SSteen Hegelund 				     ri->data.priority);
1006990e4839SSteen Hegelund 
1007990e4839SSteen Hegelund 	/* Insert the new rule in the list of rule based on the sort key
1008990e4839SSteen Hegelund 	 * If the rule needs to be  inserted between existing rules then move
1009990e4839SSteen Hegelund 	 * these rules to make room for the new rule and update their start
1010990e4839SSteen Hegelund 	 * address.
1011990e4839SSteen Hegelund 	 */
1012990e4839SSteen Hegelund 	list_for_each_entry(iter, &admin->rules, list) {
1013990e4839SSteen Hegelund 		if (ri->sort_key < iter->sort_key) {
1014990e4839SSteen Hegelund 			elem = iter;
1015990e4839SSteen Hegelund 			break;
1016990e4839SSteen Hegelund 		}
1017990e4839SSteen Hegelund 	}
1018990e4839SSteen Hegelund 
1019990e4839SSteen Hegelund 	if (!elem) {
10208e10490bSSteen Hegelund 		ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
10218e10490bSSteen Hegelund 		admin->last_used_addr = ri->addr;
1022990e4839SSteen Hegelund 
10238e10490bSSteen Hegelund 		/* Add a shallow copy of the rule to the VCAP list */
10248e10490bSSteen Hegelund 		duprule = vcap_dup_rule(ri);
10258e10490bSSteen Hegelund 		if (IS_ERR(duprule))
10268e10490bSSteen Hegelund 			return PTR_ERR(duprule);
1027990e4839SSteen Hegelund 
10288e10490bSSteen Hegelund 		list_add_tail(&duprule->list, &admin->rules);
10298e10490bSSteen Hegelund 		return 0;
10308e10490bSSteen Hegelund 	}
10318e10490bSSteen Hegelund 
1032990e4839SSteen Hegelund 	/* Reuse the space of the current rule */
1033990e4839SSteen Hegelund 	addr = elem->addr + elem->size;
1034990e4839SSteen Hegelund 	ri->addr = vcap_next_rule_addr(addr, ri);
1035990e4839SSteen Hegelund 	addr = ri->addr;
1036990e4839SSteen Hegelund 
1037990e4839SSteen Hegelund 	/* Add a shallow copy of the rule to the VCAP list */
1038990e4839SSteen Hegelund 	duprule = vcap_dup_rule(ri);
1039990e4839SSteen Hegelund 	if (IS_ERR(duprule))
1040990e4839SSteen Hegelund 		return PTR_ERR(duprule);
1041990e4839SSteen Hegelund 
1042990e4839SSteen Hegelund 	/* Add before the current entry */
1043990e4839SSteen Hegelund 	list_add_tail(&duprule->list, &elem->list);
1044990e4839SSteen Hegelund 
1045990e4839SSteen Hegelund 	/* Update the current rule */
1046990e4839SSteen Hegelund 	elem->addr = vcap_next_rule_addr(addr, elem);
1047990e4839SSteen Hegelund 	addr = elem->addr;
1048990e4839SSteen Hegelund 
1049990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1050990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list) {
1051990e4839SSteen Hegelund 		elem->addr = vcap_next_rule_addr(addr, elem);
1052990e4839SSteen Hegelund 		addr = elem->addr;
1053990e4839SSteen Hegelund 	}
1054990e4839SSteen Hegelund 
1055990e4839SSteen Hegelund 	/* Update the move info */
1056990e4839SSteen Hegelund 	move->addr = admin->last_used_addr;
1057990e4839SSteen Hegelund 	move->count = ri->addr - addr;
1058990e4839SSteen Hegelund 	move->offset = admin->last_used_addr - addr;
1059990e4839SSteen Hegelund 	admin->last_used_addr = addr;
1060990e4839SSteen Hegelund 	return 0;
1061990e4839SSteen Hegelund }
1062990e4839SSteen Hegelund 
10638e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
10648e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
10658e10490bSSteen Hegelund {
10668e10490bSSteen Hegelund 	ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
10678e10490bSSteen Hegelund 			 move->offset, move->count);
10688e10490bSSteen Hegelund }
10698e10490bSSteen Hegelund 
1070c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
1071c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
1072c9da1ac1SSteen Hegelund {
10738e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
10748e10490bSSteen Hegelund 	struct vcap_rule_move move = {0};
10758e10490bSSteen Hegelund 	int ret;
10768e10490bSSteen Hegelund 
10778e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
10788e10490bSSteen Hegelund 	if (ret)
10798e10490bSSteen Hegelund 		return ret;
10808e10490bSSteen Hegelund 	/* Insert the new rule in the list of vcap rules */
10818e10490bSSteen Hegelund 	ret = vcap_insert_rule(ri, &move);
10828e10490bSSteen Hegelund 	if (ret < 0) {
10838e10490bSSteen Hegelund 		pr_err("%s:%d: could not insert rule in vcap list: %d\n",
10848e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
10858e10490bSSteen Hegelund 		goto out;
10868e10490bSSteen Hegelund 	}
10878e10490bSSteen Hegelund 	if (move.count > 0)
10888e10490bSSteen Hegelund 		vcap_move_rules(ri, &move);
10898e10490bSSteen Hegelund 	ret = vcap_encode_rule(ri);
10908e10490bSSteen Hegelund 	if (ret) {
10918e10490bSSteen Hegelund 		pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
10928e10490bSSteen Hegelund 		goto out;
10938e10490bSSteen Hegelund 	}
10948e10490bSSteen Hegelund 
10958e10490bSSteen Hegelund 	ret = vcap_write_rule(ri);
10968e10490bSSteen Hegelund 	if (ret)
10978e10490bSSteen Hegelund 		pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
10988e10490bSSteen Hegelund out:
10998e10490bSSteen Hegelund 	return ret;
1100c9da1ac1SSteen Hegelund }
1101c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
1102c9da1ac1SSteen Hegelund 
1103c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
1104c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
1105c9da1ac1SSteen Hegelund 				  struct net_device *ndev, int vcap_chain_id,
1106c9da1ac1SSteen Hegelund 				  enum vcap_user user, u16 priority,
1107c9da1ac1SSteen Hegelund 				  u32 id)
1108c9da1ac1SSteen Hegelund {
1109c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
1110c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1111990e4839SSteen Hegelund 	int err, maxsize;
1112c9da1ac1SSteen Hegelund 
1113990e4839SSteen Hegelund 	err = vcap_api_check(vctrl);
1114990e4839SSteen Hegelund 	if (err)
1115990e4839SSteen Hegelund 		return ERR_PTR(err);
1116c9da1ac1SSteen Hegelund 	if (!ndev)
1117c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENODEV);
1118c9da1ac1SSteen Hegelund 	/* Get the VCAP instance */
1119c9da1ac1SSteen Hegelund 	admin = vcap_find_admin(vctrl, vcap_chain_id);
1120c9da1ac1SSteen Hegelund 	if (!admin)
1121c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOENT);
11228e10490bSSteen Hegelund 	/* Sanity check that this VCAP is supported on this platform */
11238e10490bSSteen Hegelund 	if (vctrl->vcaps[admin->vtype].rows == 0)
11248e10490bSSteen Hegelund 		return ERR_PTR(-EINVAL);
11258e10490bSSteen Hegelund 	/* Check if a rule with this id already exists */
11268e10490bSSteen Hegelund 	if (vcap_lookup_rule(vctrl, id))
11278e10490bSSteen Hegelund 		return ERR_PTR(-EEXIST);
11288e10490bSSteen Hegelund 	/* Check if there is room for the rule in the block(s) of the VCAP */
11298e10490bSSteen Hegelund 	maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
11308e10490bSSteen Hegelund 	if (vcap_rule_space(admin, maxsize))
11318e10490bSSteen Hegelund 		return ERR_PTR(-ENOSPC);
1132c9da1ac1SSteen Hegelund 	/* Create a container for the rule and return it */
1133c9da1ac1SSteen Hegelund 	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
1134c9da1ac1SSteen Hegelund 	if (!ri)
1135c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOMEM);
1136c9da1ac1SSteen Hegelund 	ri->data.vcap_chain_id = vcap_chain_id;
1137c9da1ac1SSteen Hegelund 	ri->data.user = user;
1138c9da1ac1SSteen Hegelund 	ri->data.priority = priority;
1139c9da1ac1SSteen Hegelund 	ri->data.id = id;
1140c9da1ac1SSteen Hegelund 	ri->data.keyset = VCAP_KFS_NO_VALUE;
1141c9da1ac1SSteen Hegelund 	ri->data.actionset = VCAP_AFS_NO_VALUE;
1142c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->list);
1143c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.keyfields);
1144c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.actionfields);
1145c9da1ac1SSteen Hegelund 	ri->ndev = ndev;
1146c9da1ac1SSteen Hegelund 	ri->admin = admin; /* refer to the vcap instance */
1147c9da1ac1SSteen Hegelund 	ri->vctrl = vctrl; /* refer to the client */
1148c9da1ac1SSteen Hegelund 	if (vcap_set_rule_id(ri) == 0)
1149c9da1ac1SSteen Hegelund 		goto out_free;
11508e10490bSSteen Hegelund 	vcap_erase_cache(ri);
1151c9da1ac1SSteen Hegelund 	return (struct vcap_rule *)ri;
1152c9da1ac1SSteen Hegelund 
1153c9da1ac1SSteen Hegelund out_free:
1154c9da1ac1SSteen Hegelund 	kfree(ri);
1155c9da1ac1SSteen Hegelund 	return ERR_PTR(-EINVAL);
1156c9da1ac1SSteen Hegelund }
1157c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
1158c9da1ac1SSteen Hegelund 
1159c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
1160c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
1161c9da1ac1SSteen Hegelund {
1162c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1163c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *caf, *next_caf;
1164c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
1165c9da1ac1SSteen Hegelund 
1166c9da1ac1SSteen Hegelund 	/* Deallocate the list of keys and actions */
1167c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
1168c9da1ac1SSteen Hegelund 		list_del(&ckf->ctrl.list);
1169c9da1ac1SSteen Hegelund 		kfree(ckf);
1170c9da1ac1SSteen Hegelund 	}
1171c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
1172c9da1ac1SSteen Hegelund 		list_del(&caf->ctrl.list);
1173c9da1ac1SSteen Hegelund 		kfree(caf);
1174c9da1ac1SSteen Hegelund 	}
1175c9da1ac1SSteen Hegelund 	/* Deallocate the rule */
1176c9da1ac1SSteen Hegelund 	kfree(rule);
1177c9da1ac1SSteen Hegelund }
1178c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
1179c9da1ac1SSteen Hegelund 
1180990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */
1181990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
1182990e4839SSteen Hegelund {
1183990e4839SSteen Hegelund 	return (el->addr + offset) % el->size;
1184990e4839SSteen Hegelund }
1185990e4839SSteen Hegelund 
1186990e4839SSteen Hegelund /* Update the rule address with an offset */
1187990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
1188990e4839SSteen Hegelund {
1189990e4839SSteen Hegelund 	el->addr += offset;
1190990e4839SSteen Hegelund }
1191990e4839SSteen Hegelund 
1192990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */
1193990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
1194990e4839SSteen Hegelund {
1195990e4839SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1196990e4839SSteen Hegelund 	struct vcap_rule_internal *elem;
1197990e4839SSteen Hegelund 	struct vcap_rule_move move;
1198990e4839SSteen Hegelund 	int gap = 0, offset = 0;
1199990e4839SSteen Hegelund 
1200990e4839SSteen Hegelund 	/* If the first rule is deleted: Move other rules to the top */
1201990e4839SSteen Hegelund 	if (list_is_first(&ri->list, &admin->rules))
1202990e4839SSteen Hegelund 		offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
1203990e4839SSteen Hegelund 
1204990e4839SSteen Hegelund 	/* Locate gaps between odd size rules and adjust the move */
1205990e4839SSteen Hegelund 	elem = ri;
1206990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
1207990e4839SSteen Hegelund 		gap += vcap_valid_rule_move(elem, ri->size);
1208990e4839SSteen Hegelund 
1209990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1210990e4839SSteen Hegelund 	elem = ri;
1211990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
1212990e4839SSteen Hegelund 		vcap_adjust_rule_addr(elem, ri->size + gap + offset);
1213990e4839SSteen Hegelund 
1214990e4839SSteen Hegelund 	/* Update the move info */
1215990e4839SSteen Hegelund 	move.addr = admin->last_used_addr;
1216990e4839SSteen Hegelund 	move.count = ri->addr - admin->last_used_addr - gap;
1217990e4839SSteen Hegelund 	move.offset = -(ri->size + gap + offset);
1218990e4839SSteen Hegelund 
1219990e4839SSteen Hegelund 	/* Do the actual move operation */
1220990e4839SSteen Hegelund 	vcap_move_rules(ri, &move);
1221990e4839SSteen Hegelund 
1222990e4839SSteen Hegelund 	return gap + offset;
1223990e4839SSteen Hegelund }
1224990e4839SSteen Hegelund 
1225c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
1226c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
1227c9da1ac1SSteen Hegelund {
1228c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri, *elem;
1229c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1230990e4839SSteen Hegelund 	int gap = 0, err;
1231c9da1ac1SSteen Hegelund 
1232c9da1ac1SSteen Hegelund 	/* This will later also handle rule moving */
1233c9da1ac1SSteen Hegelund 	if (!ndev)
1234c9da1ac1SSteen Hegelund 		return -ENODEV;
12358e10490bSSteen Hegelund 	err = vcap_api_check(vctrl);
12368e10490bSSteen Hegelund 	if (err)
12378e10490bSSteen Hegelund 		return err;
1238c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
1239c9da1ac1SSteen Hegelund 	ri = vcap_lookup_rule(vctrl, id);
1240c9da1ac1SSteen Hegelund 	if (!ri)
1241c9da1ac1SSteen Hegelund 		return -EINVAL;
1242c9da1ac1SSteen Hegelund 	admin = ri->admin;
12438e10490bSSteen Hegelund 
1244990e4839SSteen Hegelund 	if (ri->addr > admin->last_used_addr)
1245990e4839SSteen Hegelund 		gap = vcap_fill_rule_gap(ri);
1246990e4839SSteen Hegelund 
1247990e4839SSteen Hegelund 	/* Delete the rule from the list of rules and the cache */
1248990e4839SSteen Hegelund 	list_del(&ri->list);
1249990e4839SSteen Hegelund 	vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
1250990e4839SSteen Hegelund 	kfree(ri);
1251990e4839SSteen Hegelund 
1252990e4839SSteen Hegelund 	/* Update the last used address */
1253c9da1ac1SSteen Hegelund 	if (list_empty(&admin->rules)) {
1254c9da1ac1SSteen Hegelund 		admin->last_used_addr = admin->last_valid_addr;
1255c9da1ac1SSteen Hegelund 	} else {
1256990e4839SSteen Hegelund 		elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
1257990e4839SSteen Hegelund 				       list);
1258c9da1ac1SSteen Hegelund 		admin->last_used_addr = elem->addr;
1259c9da1ac1SSteen Hegelund 	}
1260c9da1ac1SSteen Hegelund 	return 0;
1261c9da1ac1SSteen Hegelund }
1262c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
1263c9da1ac1SSteen Hegelund 
12648e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
12658e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
12668e10490bSSteen Hegelund {
126767456717SSteen Hegelund 	struct vcap_enabled_port *eport, *next_eport;
12688e10490bSSteen Hegelund 	struct vcap_rule_internal *ri, *next_ri;
12698e10490bSSteen Hegelund 	int ret = vcap_api_check(vctrl);
12708e10490bSSteen Hegelund 
12718e10490bSSteen Hegelund 	if (ret)
12728e10490bSSteen Hegelund 		return ret;
12738e10490bSSteen Hegelund 	list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
12748e10490bSSteen Hegelund 		vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
12758e10490bSSteen Hegelund 		list_del(&ri->list);
12768e10490bSSteen Hegelund 		kfree(ri);
12778e10490bSSteen Hegelund 	}
12788e10490bSSteen Hegelund 	admin->last_used_addr = admin->last_valid_addr;
127967456717SSteen Hegelund 
128067456717SSteen Hegelund 	/* Remove list of enabled ports */
128167456717SSteen Hegelund 	list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
128267456717SSteen Hegelund 		list_del(&eport->list);
128367456717SSteen Hegelund 		kfree(eport);
128467456717SSteen Hegelund 	}
128567456717SSteen Hegelund 
12868e10490bSSteen Hegelund 	return 0;
12878e10490bSSteen Hegelund }
12888e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
12898e10490bSSteen Hegelund 
129046be056eSSteen Hegelund /* Find information on a key field in a rule */
129146be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
129246be056eSSteen Hegelund 					      enum vcap_key_field key)
129346be056eSSteen Hegelund {
12948e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
129546be056eSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
129646be056eSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
129746be056eSSteen Hegelund 	const struct vcap_field *fields;
129846be056eSSteen Hegelund 
129946be056eSSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
130046be056eSSteen Hegelund 		return NULL;
130146be056eSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
130246be056eSSteen Hegelund 	if (!fields)
130346be056eSSteen Hegelund 		return NULL;
130446be056eSSteen Hegelund 	return &fields[key];
130546be056eSSteen Hegelund }
130646be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
130746be056eSSteen Hegelund 
1308c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule,
1309c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield *field,
1310c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield_data *data)
1311c9da1ac1SSteen Hegelund {
1312c9da1ac1SSteen Hegelund 	/* This will be expanded later to handle different vcap memory layouts */
1313c9da1ac1SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
1314c9da1ac1SSteen Hegelund }
1315c9da1ac1SSteen Hegelund 
1316242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */
1317242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule,
1318242df4f7SSteen Hegelund 				 enum vcap_key_field key)
1319242df4f7SSteen Hegelund {
1320242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1321242df4f7SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
1322242df4f7SSteen Hegelund 
1323242df4f7SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1324242df4f7SSteen Hegelund 		if (ckf->ctrl.key == key)
1325242df4f7SSteen Hegelund 			return false;
1326242df4f7SSteen Hegelund 	return true;
1327242df4f7SSteen Hegelund }
1328242df4f7SSteen Hegelund 
1329242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */
1330242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule,
1331242df4f7SSteen Hegelund 				       enum vcap_key_field key)
1332242df4f7SSteen Hegelund {
1333242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1334242df4f7SSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
1335242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
1336242df4f7SSteen Hegelund 	const struct vcap_field *fields;
1337242df4f7SSteen Hegelund 
1338242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no keyset yet */
1339242df4f7SSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
1340242df4f7SSteen Hegelund 		return true;
1341242df4f7SSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
1342242df4f7SSteen Hegelund 	if (!fields)
1343242df4f7SSteen Hegelund 		return false;
1344242df4f7SSteen Hegelund 	/* if there is a width there is a way */
1345242df4f7SSteen Hegelund 	return fields[key].width > 0;
1346242df4f7SSteen Hegelund }
1347242df4f7SSteen Hegelund 
1348c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
1349c9da1ac1SSteen Hegelund 			     enum vcap_key_field key,
1350c9da1ac1SSteen Hegelund 			     enum vcap_field_type ftype,
1351c9da1ac1SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
1352c9da1ac1SSteen Hegelund {
1353242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1354c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *field;
1355c9da1ac1SSteen Hegelund 
1356242df4f7SSteen Hegelund 	if (!vcap_keyfield_unique(rule, key)) {
1357242df4f7SSteen Hegelund 		pr_warn("%s:%d: keyfield %s is already in the rule\n",
1358242df4f7SSteen Hegelund 			__func__, __LINE__,
1359242df4f7SSteen Hegelund 			vcap_keyfield_name(ri->vctrl, key));
1360242df4f7SSteen Hegelund 		return -EINVAL;
1361242df4f7SSteen Hegelund 	}
1362242df4f7SSteen Hegelund 
1363242df4f7SSteen Hegelund 	if (!vcap_keyfield_match_keyset(rule, key)) {
1364242df4f7SSteen Hegelund 		pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n",
1365242df4f7SSteen Hegelund 		       __func__, __LINE__,
1366242df4f7SSteen Hegelund 		       vcap_keyfield_name(ri->vctrl, key));
1367242df4f7SSteen Hegelund 		return -EINVAL;
1368242df4f7SSteen Hegelund 	}
1369242df4f7SSteen Hegelund 
1370c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1371c9da1ac1SSteen Hegelund 	if (!field)
1372c9da1ac1SSteen Hegelund 		return -ENOMEM;
1373c9da1ac1SSteen Hegelund 	field->ctrl.key = key;
1374c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
1375c9da1ac1SSteen Hegelund 	vcap_copy_from_client_keyfield(rule, field, data);
1376c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->keyfields);
1377c9da1ac1SSteen Hegelund 	return 0;
1378c9da1ac1SSteen Hegelund }
1379c9da1ac1SSteen Hegelund 
138046be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
138146be056eSSteen Hegelund {
138246be056eSSteen Hegelund 	switch (val) {
138346be056eSSteen Hegelund 	case VCAP_BIT_0:
138446be056eSSteen Hegelund 		u1->value = 0;
138546be056eSSteen Hegelund 		u1->mask = 1;
138646be056eSSteen Hegelund 		break;
138746be056eSSteen Hegelund 	case VCAP_BIT_1:
138846be056eSSteen Hegelund 		u1->value = 1;
138946be056eSSteen Hegelund 		u1->mask = 1;
139046be056eSSteen Hegelund 		break;
139146be056eSSteen Hegelund 	case VCAP_BIT_ANY:
139246be056eSSteen Hegelund 		u1->value = 0;
139346be056eSSteen Hegelund 		u1->mask = 0;
139446be056eSSteen Hegelund 		break;
139546be056eSSteen Hegelund 	}
139646be056eSSteen Hegelund }
139746be056eSSteen Hegelund 
139846be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
139946be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
140046be056eSSteen Hegelund 			  enum vcap_bit val)
140146be056eSSteen Hegelund {
140246be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
140346be056eSSteen Hegelund 
140446be056eSSteen Hegelund 	vcap_rule_set_key_bitsize(&data.u1, val);
140546be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
140646be056eSSteen Hegelund }
140746be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
140846be056eSSteen Hegelund 
140946be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
141046be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
141146be056eSSteen Hegelund 			  u32 value, u32 mask)
141246be056eSSteen Hegelund {
141346be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
141446be056eSSteen Hegelund 
141546be056eSSteen Hegelund 	data.u32.value = value;
141646be056eSSteen Hegelund 	data.u32.mask = mask;
141746be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
141846be056eSSteen Hegelund }
141946be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
142046be056eSSteen Hegelund 
1421c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
1422c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
1423c9da1ac1SSteen Hegelund 			  struct vcap_u48_key *fieldval)
1424c9da1ac1SSteen Hegelund {
1425c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield_data data;
1426c9da1ac1SSteen Hegelund 
1427c9da1ac1SSteen Hegelund 	memcpy(&data.u48, fieldval, sizeof(data.u48));
1428c9da1ac1SSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
1429c9da1ac1SSteen Hegelund }
1430c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
1431c9da1ac1SSteen Hegelund 
143246be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
143346be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
143446be056eSSteen Hegelund 			  struct vcap_u72_key *fieldval)
143546be056eSSteen Hegelund {
143646be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
143746be056eSSteen Hegelund 
143846be056eSSteen Hegelund 	memcpy(&data.u72, fieldval, sizeof(data.u72));
143946be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
144046be056eSSteen Hegelund }
144146be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
144246be056eSSteen Hegelund 
1443d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
1444d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
1445d6c2964dSSteen Hegelund 			   struct vcap_u128_key *fieldval)
1446d6c2964dSSteen Hegelund {
1447d6c2964dSSteen Hegelund 	struct vcap_client_keyfield_data data;
1448d6c2964dSSteen Hegelund 
1449d6c2964dSSteen Hegelund 	memcpy(&data.u128, fieldval, sizeof(data.u128));
1450d6c2964dSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
1451d6c2964dSSteen Hegelund }
1452d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
1453d6c2964dSSteen Hegelund 
1454c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule,
1455c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield *field,
1456c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield_data *data)
1457c9da1ac1SSteen Hegelund {
1458c9da1ac1SSteen Hegelund 	/* This will be expanded later to handle different vcap memory layouts */
1459c9da1ac1SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
1460c9da1ac1SSteen Hegelund }
1461c9da1ac1SSteen Hegelund 
1462242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */
1463242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule,
1464242df4f7SSteen Hegelund 				    enum vcap_action_field act)
1465242df4f7SSteen Hegelund {
1466242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1467242df4f7SSteen Hegelund 	const struct vcap_client_actionfield *caf;
1468242df4f7SSteen Hegelund 
1469242df4f7SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
1470242df4f7SSteen Hegelund 		if (caf->ctrl.action == act)
1471242df4f7SSteen Hegelund 			return false;
1472242df4f7SSteen Hegelund 	return true;
1473242df4f7SSteen Hegelund }
1474242df4f7SSteen Hegelund 
1475242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */
1476242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule,
1477242df4f7SSteen Hegelund 					     enum vcap_action_field action)
1478242df4f7SSteen Hegelund {
1479242df4f7SSteen Hegelund 	enum vcap_actionfield_set actionset = rule->actionset;
1480242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1481242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
1482242df4f7SSteen Hegelund 	const struct vcap_field *fields;
1483242df4f7SSteen Hegelund 
1484242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no actionset yet */
1485242df4f7SSteen Hegelund 	if (actionset == VCAP_AFS_NO_VALUE)
1486242df4f7SSteen Hegelund 		return true;
1487242df4f7SSteen Hegelund 	fields = vcap_actionfields(ri->vctrl, vt, actionset);
1488242df4f7SSteen Hegelund 	if (!fields)
1489242df4f7SSteen Hegelund 		return false;
1490242df4f7SSteen Hegelund 	/* if there is a width there is a way */
1491242df4f7SSteen Hegelund 	return fields[action].width > 0;
1492242df4f7SSteen Hegelund }
1493242df4f7SSteen Hegelund 
1494c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
1495c9da1ac1SSteen Hegelund 				enum vcap_action_field action,
1496c9da1ac1SSteen Hegelund 				enum vcap_field_type ftype,
1497c9da1ac1SSteen Hegelund 				struct vcap_client_actionfield_data *data)
1498c9da1ac1SSteen Hegelund {
1499242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1500c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *field;
1501c9da1ac1SSteen Hegelund 
1502242df4f7SSteen Hegelund 	if (!vcap_actionfield_unique(rule, action)) {
1503242df4f7SSteen Hegelund 		pr_warn("%s:%d: actionfield %s is already in the rule\n",
1504242df4f7SSteen Hegelund 			__func__, __LINE__,
1505242df4f7SSteen Hegelund 			vcap_actionfield_name(ri->vctrl, action));
1506242df4f7SSteen Hegelund 		return -EINVAL;
1507242df4f7SSteen Hegelund 	}
1508242df4f7SSteen Hegelund 
1509242df4f7SSteen Hegelund 	if (!vcap_actionfield_match_actionset(rule, action)) {
1510242df4f7SSteen Hegelund 		pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n",
1511242df4f7SSteen Hegelund 		       __func__, __LINE__,
1512242df4f7SSteen Hegelund 		       vcap_actionfield_name(ri->vctrl, action));
1513242df4f7SSteen Hegelund 		return -EINVAL;
1514242df4f7SSteen Hegelund 	}
1515242df4f7SSteen Hegelund 
1516c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1517c9da1ac1SSteen Hegelund 	if (!field)
1518c9da1ac1SSteen Hegelund 		return -ENOMEM;
1519c9da1ac1SSteen Hegelund 	field->ctrl.action = action;
1520c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
1521c9da1ac1SSteen Hegelund 	vcap_copy_from_client_actionfield(rule, field, data);
1522c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->actionfields);
1523c9da1ac1SSteen Hegelund 	return 0;
1524c9da1ac1SSteen Hegelund }
1525c9da1ac1SSteen Hegelund 
1526c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
1527c9da1ac1SSteen Hegelund 					 enum vcap_bit val)
1528c9da1ac1SSteen Hegelund {
1529c9da1ac1SSteen Hegelund 	switch (val) {
1530c9da1ac1SSteen Hegelund 	case VCAP_BIT_0:
1531c9da1ac1SSteen Hegelund 		u1->value = 0;
1532c9da1ac1SSteen Hegelund 		break;
1533c9da1ac1SSteen Hegelund 	case VCAP_BIT_1:
1534c9da1ac1SSteen Hegelund 		u1->value = 1;
1535c9da1ac1SSteen Hegelund 		break;
1536c9da1ac1SSteen Hegelund 	case VCAP_BIT_ANY:
1537c9da1ac1SSteen Hegelund 		u1->value = 0;
1538c9da1ac1SSteen Hegelund 		break;
1539c9da1ac1SSteen Hegelund 	}
1540c9da1ac1SSteen Hegelund }
1541c9da1ac1SSteen Hegelund 
1542c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
1543c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
1544c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
1545c9da1ac1SSteen Hegelund 			     enum vcap_bit val)
1546c9da1ac1SSteen Hegelund {
1547c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
1548c9da1ac1SSteen Hegelund 
1549c9da1ac1SSteen Hegelund 	vcap_rule_set_action_bitsize(&data.u1, val);
1550c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
1551c9da1ac1SSteen Hegelund }
1552c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
1553c9da1ac1SSteen Hegelund 
1554c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
1555c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
1556c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
1557c9da1ac1SSteen Hegelund 			     u32 value)
1558c9da1ac1SSteen Hegelund {
1559c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
1560c9da1ac1SSteen Hegelund 
1561c9da1ac1SSteen Hegelund 	data.u32.value = value;
1562c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
1563c9da1ac1SSteen Hegelund }
1564c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
1565c9da1ac1SSteen Hegelund 
1566*f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri,
1567*f13230a4SSteen Hegelund 			     struct vcap_counter *ctr)
1568*f13230a4SSteen Hegelund {
1569*f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1570*f13230a4SSteen Hegelund 
1571*f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
1572*f13230a4SSteen Hegelund 			       ri->addr);
1573*f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
1574*f13230a4SSteen Hegelund 				   ri->counter_id, 0);
1575*f13230a4SSteen Hegelund 	ctr->value = admin->cache.counter;
1576*f13230a4SSteen Hegelund 	ctr->sticky = admin->cache.sticky;
1577*f13230a4SSteen Hegelund 	return 0;
1578*f13230a4SSteen Hegelund }
1579*f13230a4SSteen Hegelund 
1580c9da1ac1SSteen Hegelund /* Copy to host byte order */
1581c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
1582c9da1ac1SSteen Hegelund {
1583c9da1ac1SSteen Hegelund 	int idx;
1584c9da1ac1SSteen Hegelund 
1585c9da1ac1SSteen Hegelund 	for (idx = 0; idx < count; ++idx, ++dst)
1586c9da1ac1SSteen Hegelund 		*dst = src[count - idx - 1];
1587c9da1ac1SSteen Hegelund }
1588c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
1589c9da1ac1SSteen Hegelund 
1590c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */
1591c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
1592c9da1ac1SSteen Hegelund {
1593c9da1ac1SSteen Hegelund 	switch (vrule->exterr) {
1594c9da1ac1SSteen Hegelund 	case VCAP_ERR_NONE:
1595c9da1ac1SSteen Hegelund 		break;
1596c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ADMIN:
1597c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1598c9da1ac1SSteen Hegelund 				   "Missing VCAP instance");
1599c9da1ac1SSteen Hegelund 		break;
1600c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_NETDEV:
1601c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1602c9da1ac1SSteen Hegelund 				   "Missing network interface");
1603c9da1ac1SSteen Hegelund 		break;
1604c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_KEYSET_MATCH:
1605c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1606c9da1ac1SSteen Hegelund 				   "No keyset matched the filter keys");
1607c9da1ac1SSteen Hegelund 		break;
1608c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ACTIONSET_MATCH:
1609c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1610c9da1ac1SSteen Hegelund 				   "No actionset matched the filter actions");
1611c9da1ac1SSteen Hegelund 		break;
1612c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_PORT_KEYSET_MATCH:
1613c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1614c9da1ac1SSteen Hegelund 				   "No port keyset matched the filter keys");
1615c9da1ac1SSteen Hegelund 		break;
1616c9da1ac1SSteen Hegelund 	}
1617c9da1ac1SSteen Hegelund }
1618c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
161967d63751SSteen Hegelund 
162067456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */
162167456717SSteen Hegelund static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev,
162267456717SSteen Hegelund 			    unsigned long cookie)
162367456717SSteen Hegelund {
162467456717SSteen Hegelund 	struct vcap_enabled_port *eport;
162567456717SSteen Hegelund 
162667456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list)
162767456717SSteen Hegelund 		if (eport->cookie == cookie || eport->ndev == ndev)
162867456717SSteen Hegelund 			return true;
162967456717SSteen Hegelund 
163067456717SSteen Hegelund 	return false;
163167456717SSteen Hegelund }
163267456717SSteen Hegelund 
163367456717SSteen Hegelund /* Enable this port for this VCAP instance */
163467456717SSteen Hegelund static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,
163567456717SSteen Hegelund 		       unsigned long cookie)
163667456717SSteen Hegelund {
163767456717SSteen Hegelund 	struct vcap_enabled_port *eport;
163867456717SSteen Hegelund 
163967456717SSteen Hegelund 	eport = kzalloc(sizeof(*eport), GFP_KERNEL);
164067456717SSteen Hegelund 	if (!eport)
164167456717SSteen Hegelund 		return -ENOMEM;
164267456717SSteen Hegelund 
164367456717SSteen Hegelund 	eport->ndev = ndev;
164467456717SSteen Hegelund 	eport->cookie = cookie;
164567456717SSteen Hegelund 	list_add_tail(&eport->list, &admin->enabled);
164667456717SSteen Hegelund 
164767456717SSteen Hegelund 	return 0;
164867456717SSteen Hegelund }
164967456717SSteen Hegelund 
165067456717SSteen Hegelund /* Disable this port for this VCAP instance */
165167456717SSteen Hegelund static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev,
165267456717SSteen Hegelund 			unsigned long cookie)
165367456717SSteen Hegelund {
165467456717SSteen Hegelund 	struct vcap_enabled_port *eport;
165567456717SSteen Hegelund 
165667456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list) {
165767456717SSteen Hegelund 		if (eport->cookie == cookie && eport->ndev == ndev) {
165867456717SSteen Hegelund 			list_del(&eport->list);
165967456717SSteen Hegelund 			kfree(eport);
166067456717SSteen Hegelund 			return 0;
166167456717SSteen Hegelund 		}
166267456717SSteen Hegelund 	}
166367456717SSteen Hegelund 
166467456717SSteen Hegelund 	return -ENOENT;
166567456717SSteen Hegelund }
166667456717SSteen Hegelund 
166767456717SSteen Hegelund /* Find the VCAP instance that enabled the port using a specific filter */
166867456717SSteen Hegelund static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl,
166967456717SSteen Hegelund 						    unsigned long cookie)
167067456717SSteen Hegelund {
167167456717SSteen Hegelund 	struct vcap_enabled_port *eport;
167267456717SSteen Hegelund 	struct vcap_admin *admin;
167367456717SSteen Hegelund 
167467456717SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
167567456717SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list)
167667456717SSteen Hegelund 			if (eport->cookie == cookie)
167767456717SSteen Hegelund 				return admin;
167867456717SSteen Hegelund 
167967456717SSteen Hegelund 	return NULL;
168067456717SSteen Hegelund }
168167456717SSteen Hegelund 
168267456717SSteen Hegelund /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
168367456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
168467456717SSteen Hegelund 			int chain_id, unsigned long cookie, bool enable)
168567456717SSteen Hegelund {
168667456717SSteen Hegelund 	struct vcap_admin *admin;
168767456717SSteen Hegelund 	int err;
168867456717SSteen Hegelund 
168967456717SSteen Hegelund 	err = vcap_api_check(vctrl);
169067456717SSteen Hegelund 	if (err)
169167456717SSteen Hegelund 		return err;
169267456717SSteen Hegelund 
169367456717SSteen Hegelund 	if (!ndev)
169467456717SSteen Hegelund 		return -ENODEV;
169567456717SSteen Hegelund 
169667456717SSteen Hegelund 	if (chain_id)
169767456717SSteen Hegelund 		admin = vcap_find_admin(vctrl, chain_id);
169867456717SSteen Hegelund 	else
169967456717SSteen Hegelund 		admin = vcap_find_admin_by_cookie(vctrl, cookie);
170067456717SSteen Hegelund 	if (!admin)
170167456717SSteen Hegelund 		return -ENOENT;
170267456717SSteen Hegelund 
170367456717SSteen Hegelund 	/* first instance and first chain */
170467456717SSteen Hegelund 	if (admin->vinst || chain_id > admin->first_cid)
170567456717SSteen Hegelund 		return -EFAULT;
170667456717SSteen Hegelund 
170767456717SSteen Hegelund 	err = vctrl->ops->enable(ndev, admin, enable);
170867456717SSteen Hegelund 	if (err)
170967456717SSteen Hegelund 		return err;
171067456717SSteen Hegelund 
171167456717SSteen Hegelund 	if (chain_id) {
171267456717SSteen Hegelund 		if (vcap_is_enabled(admin, ndev, cookie))
171367456717SSteen Hegelund 			return -EADDRINUSE;
171467456717SSteen Hegelund 		vcap_enable(admin, ndev, cookie);
171567456717SSteen Hegelund 	} else {
171667456717SSteen Hegelund 		vcap_disable(admin, ndev, cookie);
171767456717SSteen Hegelund 	}
171867456717SSteen Hegelund 
171967456717SSteen Hegelund 	return 0;
172067456717SSteen Hegelund }
172167456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups);
172267456717SSteen Hegelund 
1723*f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */
1724*f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
1725*f13230a4SSteen Hegelund {
1726*f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1727*f13230a4SSteen Hegelund 
1728*f13230a4SSteen Hegelund 	ri->counter_id = counter_id;
1729*f13230a4SSteen Hegelund }
1730*f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
1731*f13230a4SSteen Hegelund 
1732*f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
1733*f13230a4SSteen Hegelund {
1734*f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1735*f13230a4SSteen Hegelund 	int err;
1736*f13230a4SSteen Hegelund 
1737*f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
1738*f13230a4SSteen Hegelund 	if (err)
1739*f13230a4SSteen Hegelund 		return err;
1740*f13230a4SSteen Hegelund 	if (!ctr) {
1741*f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
1742*f13230a4SSteen Hegelund 		return -EINVAL;
1743*f13230a4SSteen Hegelund 	}
1744*f13230a4SSteen Hegelund 	return vcap_write_counter(ri, ctr);
1745*f13230a4SSteen Hegelund }
1746*f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
1747*f13230a4SSteen Hegelund 
1748*f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
1749*f13230a4SSteen Hegelund {
1750*f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1751*f13230a4SSteen Hegelund 	int err;
1752*f13230a4SSteen Hegelund 
1753*f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
1754*f13230a4SSteen Hegelund 	if (err)
1755*f13230a4SSteen Hegelund 		return err;
1756*f13230a4SSteen Hegelund 	if (!ctr) {
1757*f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
1758*f13230a4SSteen Hegelund 		return -EINVAL;
1759*f13230a4SSteen Hegelund 	}
1760*f13230a4SSteen Hegelund 	return vcap_read_counter(ri, ctr);
1761*f13230a4SSteen Hegelund }
1762*f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
1763*f13230a4SSteen Hegelund 
176467d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
176567d63751SSteen Hegelund #include "vcap_api_kunit.c"
176667d63751SSteen Hegelund #endif
1767