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 
9d4134d41SSteen Hegelund #include "vcap_api_private.h"
10c9da1ac1SSteen Hegelund 
114f141e36SHoratiu Vultur static int keyfield_size_table[] = {
124f141e36SHoratiu Vultur 	[VCAP_FIELD_BIT]  = sizeof(struct vcap_u1_key),
134f141e36SHoratiu Vultur 	[VCAP_FIELD_U32]  = sizeof(struct vcap_u32_key),
144f141e36SHoratiu Vultur 	[VCAP_FIELD_U48]  = sizeof(struct vcap_u48_key),
154f141e36SHoratiu Vultur 	[VCAP_FIELD_U56]  = sizeof(struct vcap_u56_key),
164f141e36SHoratiu Vultur 	[VCAP_FIELD_U64]  = sizeof(struct vcap_u64_key),
174f141e36SHoratiu Vultur 	[VCAP_FIELD_U72]  = sizeof(struct vcap_u72_key),
184f141e36SHoratiu Vultur 	[VCAP_FIELD_U112] = sizeof(struct vcap_u112_key),
194f141e36SHoratiu Vultur 	[VCAP_FIELD_U128] = sizeof(struct vcap_u128_key),
204f141e36SHoratiu Vultur };
214f141e36SHoratiu Vultur 
224f141e36SHoratiu Vultur static int actionfield_size_table[] = {
234f141e36SHoratiu Vultur 	[VCAP_FIELD_BIT]  = sizeof(struct vcap_u1_action),
244f141e36SHoratiu Vultur 	[VCAP_FIELD_U32]  = sizeof(struct vcap_u32_action),
254f141e36SHoratiu Vultur 	[VCAP_FIELD_U48]  = sizeof(struct vcap_u48_action),
264f141e36SHoratiu Vultur 	[VCAP_FIELD_U56]  = sizeof(struct vcap_u56_action),
274f141e36SHoratiu Vultur 	[VCAP_FIELD_U64]  = sizeof(struct vcap_u64_action),
284f141e36SHoratiu Vultur 	[VCAP_FIELD_U72]  = sizeof(struct vcap_u72_action),
294f141e36SHoratiu Vultur 	[VCAP_FIELD_U112] = sizeof(struct vcap_u112_action),
304f141e36SHoratiu Vultur 	[VCAP_FIELD_U128] = sizeof(struct vcap_u128_action),
314f141e36SHoratiu Vultur };
324f141e36SHoratiu Vultur 
338e10490bSSteen Hegelund /* Moving a rule in the VCAP address space */
348e10490bSSteen Hegelund struct vcap_rule_move {
358e10490bSSteen Hegelund 	int addr; /* address to move */
368e10490bSSteen Hegelund 	int offset; /* change in address */
378e10490bSSteen Hegelund 	int count; /* blocksize of addresses to move */
388e10490bSSteen Hegelund };
398e10490bSSteen Hegelund 
4067456717SSteen Hegelund /* Stores the filter cookie that enabled the port */
4167456717SSteen Hegelund struct vcap_enabled_port {
4267456717SSteen Hegelund 	struct list_head list; /* for insertion in enabled ports list */
4367456717SSteen Hegelund 	struct net_device *ndev;  /* the enabled port */
4467456717SSteen Hegelund 	unsigned long cookie; /* filter that enabled the port */
4567456717SSteen Hegelund };
4667456717SSteen Hegelund 
47d4134d41SSteen Hegelund void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
48683e05c0SSteen Hegelund 		   const struct vcap_typegroup *tg, u32 offset)
49683e05c0SSteen Hegelund {
50683e05c0SSteen Hegelund 	memset(itr, 0, sizeof(*itr));
51683e05c0SSteen Hegelund 	itr->offset = offset;
52683e05c0SSteen Hegelund 	itr->sw_width = sw_width;
53683e05c0SSteen Hegelund 	itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32);
54683e05c0SSteen Hegelund 	itr->tg = tg;
55683e05c0SSteen Hegelund }
56683e05c0SSteen Hegelund 
57683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr)
58683e05c0SSteen Hegelund {
59683e05c0SSteen Hegelund 	/* Compensate the field offset for preceding typegroups.
60683e05c0SSteen Hegelund 	 * A typegroup table ends with an all-zero terminator.
61683e05c0SSteen Hegelund 	 */
62683e05c0SSteen Hegelund 	while (itr->tg->width && itr->offset >= itr->tg->offset) {
63683e05c0SSteen Hegelund 		itr->offset += itr->tg->width;
64683e05c0SSteen Hegelund 		itr->tg++; /* next typegroup */
65683e05c0SSteen Hegelund 	}
66683e05c0SSteen Hegelund }
67683e05c0SSteen Hegelund 
68d4134d41SSteen Hegelund void vcap_iter_update(struct vcap_stream_iter *itr)
69683e05c0SSteen Hegelund {
70683e05c0SSteen Hegelund 	int sw_idx, sw_bitpos;
71683e05c0SSteen Hegelund 
72683e05c0SSteen Hegelund 	/* Calculate the subword index and bitposition for current bit */
73683e05c0SSteen Hegelund 	sw_idx = itr->offset / itr->sw_width;
74683e05c0SSteen Hegelund 	sw_bitpos = itr->offset % itr->sw_width;
75683e05c0SSteen Hegelund 	/* Calculate the register index and bitposition for current bit */
76683e05c0SSteen Hegelund 	itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32);
77683e05c0SSteen Hegelund 	itr->reg_bitpos = sw_bitpos % 32;
78683e05c0SSteen Hegelund }
79683e05c0SSteen Hegelund 
80d4134d41SSteen Hegelund void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
81683e05c0SSteen Hegelund 		    const struct vcap_typegroup *tg, u32 offset)
82683e05c0SSteen Hegelund {
83683e05c0SSteen Hegelund 	vcap_iter_set(itr, sw_width, tg, offset);
84683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
85683e05c0SSteen Hegelund 	vcap_iter_update(itr);
86683e05c0SSteen Hegelund }
87683e05c0SSteen Hegelund 
88d4134d41SSteen Hegelund void vcap_iter_next(struct vcap_stream_iter *itr)
89683e05c0SSteen Hegelund {
90683e05c0SSteen Hegelund 	itr->offset++;
91683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
92683e05c0SSteen Hegelund 	vcap_iter_update(itr);
93683e05c0SSteen Hegelund }
94683e05c0SSteen Hegelund 
95683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value)
96683e05c0SSteen Hegelund {
97683e05c0SSteen Hegelund 	u32 mask = BIT(itr->reg_bitpos);
98683e05c0SSteen Hegelund 	u32 *p = &stream[itr->reg_idx];
99683e05c0SSteen Hegelund 
100683e05c0SSteen Hegelund 	if (value)
101683e05c0SSteen Hegelund 		*p |= mask;
102683e05c0SSteen Hegelund 	else
103683e05c0SSteen Hegelund 		*p &= ~mask;
104683e05c0SSteen Hegelund }
105683e05c0SSteen Hegelund 
106683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val)
107683e05c0SSteen Hegelund {
108683e05c0SSteen Hegelund 	/* When intersected by a type group field, stream the type group bits
109683e05c0SSteen Hegelund 	 * before continuing with the value bit
110683e05c0SSteen Hegelund 	 */
111683e05c0SSteen Hegelund 	while (itr->tg->width &&
112683e05c0SSteen Hegelund 	       itr->offset >= itr->tg->offset &&
113683e05c0SSteen Hegelund 	       itr->offset < itr->tg->offset + itr->tg->width) {
114683e05c0SSteen Hegelund 		int tg_bitpos = itr->tg->offset - itr->offset;
115683e05c0SSteen Hegelund 
116683e05c0SSteen Hegelund 		vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1);
117683e05c0SSteen Hegelund 		itr->offset++;
118683e05c0SSteen Hegelund 		vcap_iter_update(itr);
119683e05c0SSteen Hegelund 	}
120683e05c0SSteen Hegelund 	vcap_set_bit(stream, itr, val);
121683e05c0SSteen Hegelund }
122683e05c0SSteen Hegelund 
123683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr,
124683e05c0SSteen Hegelund 			      int width, const u8 *value)
125683e05c0SSteen Hegelund {
126683e05c0SSteen Hegelund 	int idx;
127683e05c0SSteen Hegelund 
128683e05c0SSteen Hegelund 	/* Loop over the field value bits and add the value bits one by one to
129683e05c0SSteen Hegelund 	 * the output stream.
130683e05c0SSteen Hegelund 	 */
131683e05c0SSteen Hegelund 	for (idx = 0; idx < width; idx++) {
132683e05c0SSteen Hegelund 		u8 bidx = idx & GENMASK(2, 0);
133683e05c0SSteen Hegelund 
134683e05c0SSteen Hegelund 		/* Encode one field value bit */
135683e05c0SSteen Hegelund 		vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1);
136683e05c0SSteen Hegelund 		vcap_iter_next(itr);
137683e05c0SSteen Hegelund 	}
138683e05c0SSteen Hegelund }
139683e05c0SSteen Hegelund 
140683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width,
141683e05c0SSteen Hegelund 				   const struct vcap_typegroup *tg,
142683e05c0SSteen Hegelund 				   bool mask)
143683e05c0SSteen Hegelund {
144683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
145683e05c0SSteen Hegelund 	int idx;
146683e05c0SSteen Hegelund 
147683e05c0SSteen Hegelund 	/* Mask bits must be set to zeros (inverted later when writing to the
148683e05c0SSteen Hegelund 	 * mask cache register), so that the mask typegroup bits consist of
149683e05c0SSteen Hegelund 	 * match-1 or match-0, or both
150683e05c0SSteen Hegelund 	 */
151683e05c0SSteen Hegelund 	vcap_iter_set(&iter, sw_width, tg, 0);
152683e05c0SSteen Hegelund 	while (iter.tg->width) {
153683e05c0SSteen Hegelund 		/* Set position to current typegroup bit */
154683e05c0SSteen Hegelund 		iter.offset = iter.tg->offset;
155683e05c0SSteen Hegelund 		vcap_iter_update(&iter);
156683e05c0SSteen Hegelund 		for (idx = 0; idx < iter.tg->width; idx++) {
157683e05c0SSteen Hegelund 			/* Iterate over current typegroup bits. Mask typegroup
158683e05c0SSteen Hegelund 			 * bits are always set
159683e05c0SSteen Hegelund 			 */
160683e05c0SSteen Hegelund 			if (mask)
161683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter, 0x1);
162683e05c0SSteen Hegelund 			else
163683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter,
164683e05c0SSteen Hegelund 					     (iter.tg->value >> idx) & 0x1);
165683e05c0SSteen Hegelund 			iter.offset++;
166683e05c0SSteen Hegelund 			vcap_iter_update(&iter);
167683e05c0SSteen Hegelund 		}
168683e05c0SSteen Hegelund 		iter.tg++; /* next typegroup */
169683e05c0SSteen Hegelund 	}
170683e05c0SSteen Hegelund }
171683e05c0SSteen Hegelund 
172610c32b2SHoratiu Vultur static bool vcap_bitarray_zero(int width, u8 *value)
173610c32b2SHoratiu Vultur {
174610c32b2SHoratiu Vultur 	int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
175610c32b2SHoratiu Vultur 	u8 total = 0, bmask = 0xff;
176610c32b2SHoratiu Vultur 	int rwidth = width;
177610c32b2SHoratiu Vultur 	int idx;
178610c32b2SHoratiu Vultur 
179610c32b2SHoratiu Vultur 	for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
180610c32b2SHoratiu Vultur 		if (rwidth && rwidth < BITS_PER_BYTE)
181610c32b2SHoratiu Vultur 			bmask = (1 << rwidth) - 1;
182610c32b2SHoratiu Vultur 		total += value[idx] & bmask;
183610c32b2SHoratiu Vultur 	}
184610c32b2SHoratiu Vultur 	return total == 0;
185610c32b2SHoratiu Vultur }
186610c32b2SHoratiu Vultur 
187610c32b2SHoratiu Vultur static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
188610c32b2SHoratiu Vultur {
189610c32b2SHoratiu Vultur 	u32 mask = BIT(itr->reg_bitpos);
190610c32b2SHoratiu Vultur 	u32 *p = &stream[itr->reg_idx];
191610c32b2SHoratiu Vultur 
192610c32b2SHoratiu Vultur 	return !!(*p & mask);
193610c32b2SHoratiu Vultur }
194610c32b2SHoratiu Vultur 
195610c32b2SHoratiu Vultur static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
196610c32b2SHoratiu Vultur 			      int width, u8 *value)
197610c32b2SHoratiu Vultur {
198610c32b2SHoratiu Vultur 	int idx;
199610c32b2SHoratiu Vultur 
200610c32b2SHoratiu Vultur 	/* Loop over the field value bits and get the field bits and
201610c32b2SHoratiu Vultur 	 * set them in the output value byte array
202610c32b2SHoratiu Vultur 	 */
203610c32b2SHoratiu Vultur 	for (idx = 0; idx < width; idx++) {
204610c32b2SHoratiu Vultur 		u8 bidx = idx & 0x7;
205610c32b2SHoratiu Vultur 
206610c32b2SHoratiu Vultur 		/* Decode one field value bit */
207610c32b2SHoratiu Vultur 		if (vcap_get_bit(stream, itr))
208610c32b2SHoratiu Vultur 			*value |= 1 << bidx;
209610c32b2SHoratiu Vultur 		vcap_iter_next(itr);
210610c32b2SHoratiu Vultur 		if (bidx == 7)
211610c32b2SHoratiu Vultur 			value++;
212610c32b2SHoratiu Vultur 	}
213610c32b2SHoratiu Vultur }
214610c32b2SHoratiu Vultur 
215610c32b2SHoratiu Vultur /* Verify that the type id in the stream matches the type id of the keyset */
216610c32b2SHoratiu Vultur static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
217610c32b2SHoratiu Vultur 					 enum vcap_type vt,
218610c32b2SHoratiu Vultur 					 u32 *keystream,
219610c32b2SHoratiu Vultur 					 u32 *mskstream,
220610c32b2SHoratiu Vultur 					 enum vcap_keyfield_set keyset)
221610c32b2SHoratiu Vultur {
222610c32b2SHoratiu Vultur 	const struct vcap_info *vcap = &vctrl->vcaps[vt];
223610c32b2SHoratiu Vultur 	const struct vcap_field *typefld;
224610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
225610c32b2SHoratiu Vultur 	const struct vcap_field *fields;
226610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
227610c32b2SHoratiu Vultur 	const struct vcap_set *info;
228610c32b2SHoratiu Vultur 	u32 value = 0;
229610c32b2SHoratiu Vultur 	u32 mask = 0;
230610c32b2SHoratiu Vultur 
231610c32b2SHoratiu Vultur 	if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
232610c32b2SHoratiu Vultur 		return false;
233610c32b2SHoratiu Vultur 
234610c32b2SHoratiu Vultur 	info = vcap_keyfieldset(vctrl, vt, keyset);
235610c32b2SHoratiu Vultur 	/* Check that the keyset is valid */
236610c32b2SHoratiu Vultur 	if (!info)
237610c32b2SHoratiu Vultur 		return false;
238610c32b2SHoratiu Vultur 
239610c32b2SHoratiu Vultur 	/* a type_id of value -1 means that there is no type field */
240610c32b2SHoratiu Vultur 	if (info->type_id == (u8)-1)
241610c32b2SHoratiu Vultur 		return true;
242610c32b2SHoratiu Vultur 
243610c32b2SHoratiu Vultur 	/* Get a valid typegroup for the specific keyset */
244610c32b2SHoratiu Vultur 	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
245610c32b2SHoratiu Vultur 	if (!tgt)
246610c32b2SHoratiu Vultur 		return false;
247610c32b2SHoratiu Vultur 
248610c32b2SHoratiu Vultur 	fields = vcap_keyfields(vctrl, vt, keyset);
249610c32b2SHoratiu Vultur 	if (!fields)
250610c32b2SHoratiu Vultur 		return false;
251610c32b2SHoratiu Vultur 
252610c32b2SHoratiu Vultur 	typefld = &fields[VCAP_KF_TYPE];
253610c32b2SHoratiu Vultur 	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
254610c32b2SHoratiu Vultur 	vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
255610c32b2SHoratiu Vultur 	/* no type info if there are no mask bits */
256610c32b2SHoratiu Vultur 	if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
257610c32b2SHoratiu Vultur 		return false;
258610c32b2SHoratiu Vultur 
259610c32b2SHoratiu Vultur 	/* Get the value of the type field in the stream and compare to the
260610c32b2SHoratiu Vultur 	 * one define in the vcap keyset
261610c32b2SHoratiu Vultur 	 */
262610c32b2SHoratiu Vultur 	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
263610c32b2SHoratiu Vultur 	vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
264610c32b2SHoratiu Vultur 
265610c32b2SHoratiu Vultur 	return (value & mask) == (info->type_id & mask);
266610c32b2SHoratiu Vultur }
267610c32b2SHoratiu Vultur 
268610c32b2SHoratiu Vultur /* Verify that the typegroup bits have the correct values */
269610c32b2SHoratiu Vultur static int vcap_verify_typegroups(u32 *stream, int sw_width,
270610c32b2SHoratiu Vultur 				  const struct vcap_typegroup *tgt, bool mask,
271610c32b2SHoratiu Vultur 				  int sw_max)
272610c32b2SHoratiu Vultur {
273610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
274610c32b2SHoratiu Vultur 	int sw_cnt, idx;
275610c32b2SHoratiu Vultur 
276610c32b2SHoratiu Vultur 	vcap_iter_set(&iter, sw_width, tgt, 0);
277610c32b2SHoratiu Vultur 	sw_cnt = 0;
278610c32b2SHoratiu Vultur 	while (iter.tg->width) {
279610c32b2SHoratiu Vultur 		u32 value = 0;
280610c32b2SHoratiu Vultur 		u32 tg_value = iter.tg->value;
281610c32b2SHoratiu Vultur 
282610c32b2SHoratiu Vultur 		if (mask)
283610c32b2SHoratiu Vultur 			tg_value = (1 << iter.tg->width) - 1;
284610c32b2SHoratiu Vultur 		/* Set position to current typegroup bit */
285610c32b2SHoratiu Vultur 		iter.offset = iter.tg->offset;
286610c32b2SHoratiu Vultur 		vcap_iter_update(&iter);
287610c32b2SHoratiu Vultur 		for (idx = 0; idx < iter.tg->width; idx++) {
288610c32b2SHoratiu Vultur 			/* Decode one typegroup bit */
289610c32b2SHoratiu Vultur 			if (vcap_get_bit(stream, &iter))
290610c32b2SHoratiu Vultur 				value |= 1 << idx;
291610c32b2SHoratiu Vultur 			iter.offset++;
292610c32b2SHoratiu Vultur 			vcap_iter_update(&iter);
293610c32b2SHoratiu Vultur 		}
294610c32b2SHoratiu Vultur 		if (value != tg_value)
295610c32b2SHoratiu Vultur 			return -EINVAL;
296610c32b2SHoratiu Vultur 		iter.tg++; /* next typegroup */
297610c32b2SHoratiu Vultur 		sw_cnt++;
298610c32b2SHoratiu Vultur 		/* Stop checking more typegroups */
299610c32b2SHoratiu Vultur 		if (sw_max && sw_cnt >= sw_max)
300610c32b2SHoratiu Vultur 			break;
301610c32b2SHoratiu Vultur 	}
302610c32b2SHoratiu Vultur 	return 0;
303610c32b2SHoratiu Vultur }
304610c32b2SHoratiu Vultur 
305610c32b2SHoratiu Vultur /* Find the subword width of the key typegroup that matches the stream data */
306610c32b2SHoratiu Vultur static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
307610c32b2SHoratiu Vultur 					    enum vcap_type vt, u32 *stream,
308610c32b2SHoratiu Vultur 					    bool mask, int sw_max)
309610c32b2SHoratiu Vultur {
310610c32b2SHoratiu Vultur 	const struct vcap_typegroup **tgt;
311610c32b2SHoratiu Vultur 	int sw_idx, res;
312610c32b2SHoratiu Vultur 
313610c32b2SHoratiu Vultur 	tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
314610c32b2SHoratiu Vultur 	/* Try the longest subword match first */
315610c32b2SHoratiu Vultur 	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
316610c32b2SHoratiu Vultur 		if (!tgt[sw_idx])
317610c32b2SHoratiu Vultur 			continue;
318610c32b2SHoratiu Vultur 
319610c32b2SHoratiu Vultur 		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
320610c32b2SHoratiu Vultur 					     tgt[sw_idx], mask, sw_max);
321610c32b2SHoratiu Vultur 		if (res == 0)
322610c32b2SHoratiu Vultur 			return sw_idx;
323610c32b2SHoratiu Vultur 	}
324610c32b2SHoratiu Vultur 	return -EINVAL;
325610c32b2SHoratiu Vultur }
326610c32b2SHoratiu Vultur 
327610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, keyset and type id
328610c32b2SHoratiu Vultur  * are in sync and correct, return the list of matchin keysets
329610c32b2SHoratiu Vultur  */
330610c32b2SHoratiu Vultur int
331610c32b2SHoratiu Vultur vcap_find_keystream_keysets(struct vcap_control *vctrl,
332610c32b2SHoratiu Vultur 			    enum vcap_type vt,
333610c32b2SHoratiu Vultur 			    u32 *keystream,
334610c32b2SHoratiu Vultur 			    u32 *mskstream,
335610c32b2SHoratiu Vultur 			    bool mask, int sw_max,
336610c32b2SHoratiu Vultur 			    struct vcap_keyset_list *kslist)
337610c32b2SHoratiu Vultur {
338610c32b2SHoratiu Vultur 	const struct vcap_set *keyfield_set;
339610c32b2SHoratiu Vultur 	int sw_count, idx;
340610c32b2SHoratiu Vultur 
341610c32b2SHoratiu Vultur 	sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
342610c32b2SHoratiu Vultur 						    sw_max);
343610c32b2SHoratiu Vultur 	if (sw_count < 0)
344610c32b2SHoratiu Vultur 		return sw_count;
345610c32b2SHoratiu Vultur 
346610c32b2SHoratiu Vultur 	keyfield_set = vctrl->vcaps[vt].keyfield_set;
347610c32b2SHoratiu Vultur 	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
348610c32b2SHoratiu Vultur 		if (keyfield_set[idx].sw_per_item != sw_count)
349610c32b2SHoratiu Vultur 			continue;
350610c32b2SHoratiu Vultur 
351610c32b2SHoratiu Vultur 		if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
352610c32b2SHoratiu Vultur 						 mskstream, idx))
353610c32b2SHoratiu Vultur 			vcap_keyset_list_add(kslist, idx);
354610c32b2SHoratiu Vultur 	}
355610c32b2SHoratiu Vultur 	if (kslist->cnt > 0)
356610c32b2SHoratiu Vultur 		return 0;
357610c32b2SHoratiu Vultur 	return -EINVAL;
358610c32b2SHoratiu Vultur }
359610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_find_keystream_keysets);
360610c32b2SHoratiu Vultur 
361610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there are any rule keysets
362610c32b2SHoratiu Vultur  * here
363610c32b2SHoratiu Vultur  */
364610c32b2SHoratiu Vultur int vcap_addr_keysets(struct vcap_control *vctrl,
365610c32b2SHoratiu Vultur 		      struct net_device *ndev,
366610c32b2SHoratiu Vultur 		      struct vcap_admin *admin,
367610c32b2SHoratiu Vultur 		      int addr,
368610c32b2SHoratiu Vultur 		      struct vcap_keyset_list *kslist)
369610c32b2SHoratiu Vultur {
370610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
371610c32b2SHoratiu Vultur 	int keyset_sw_regs, idx;
372610c32b2SHoratiu Vultur 	u32 key = 0, mask = 0;
373610c32b2SHoratiu Vultur 
374610c32b2SHoratiu Vultur 	/* Read the cache at the specified address */
375610c32b2SHoratiu Vultur 	keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
376610c32b2SHoratiu Vultur 	vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
377610c32b2SHoratiu Vultur 	vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
378610c32b2SHoratiu Vultur 			       keyset_sw_regs);
379610c32b2SHoratiu Vultur 	/* Skip uninitialized key/mask entries */
380610c32b2SHoratiu Vultur 	for (idx = 0; idx < keyset_sw_regs; ++idx) {
381610c32b2SHoratiu Vultur 		key |= ~admin->cache.keystream[idx];
382610c32b2SHoratiu Vultur 		mask |= admin->cache.maskstream[idx];
383610c32b2SHoratiu Vultur 	}
384610c32b2SHoratiu Vultur 	if (key == 0 && mask == 0)
385610c32b2SHoratiu Vultur 		return -EINVAL;
386610c32b2SHoratiu Vultur 	/* Decode and locate the keysets */
387610c32b2SHoratiu Vultur 	return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
388610c32b2SHoratiu Vultur 					   admin->cache.maskstream, false, 0,
389610c32b2SHoratiu Vultur 					   kslist);
390610c32b2SHoratiu Vultur }
391610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_addr_keysets);
392610c32b2SHoratiu Vultur 
39346be056eSSteen Hegelund /* Return the list of keyfields for the keyset */
394d4134d41SSteen Hegelund const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
39546be056eSSteen Hegelund 					enum vcap_type vt,
39646be056eSSteen Hegelund 					enum vcap_keyfield_set keyset)
39746be056eSSteen Hegelund {
39846be056eSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
39946be056eSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
40046be056eSSteen Hegelund 		return NULL;
40146be056eSSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map[keyset];
40246be056eSSteen Hegelund }
40346be056eSSteen Hegelund 
4048e10490bSSteen Hegelund /* Return the keyset information for the keyset */
405d4134d41SSteen Hegelund const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
4068e10490bSSteen Hegelund 					enum vcap_type vt,
4078e10490bSSteen Hegelund 					enum vcap_keyfield_set keyset)
4088e10490bSSteen Hegelund {
4098e10490bSSteen Hegelund 	const struct vcap_set *kset;
4108e10490bSSteen Hegelund 
4118e10490bSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
4128e10490bSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
4138e10490bSSteen Hegelund 		return NULL;
4148e10490bSSteen Hegelund 	kset = &vctrl->vcaps[vt].keyfield_set[keyset];
4158e10490bSSteen Hegelund 	if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count)
4168e10490bSSteen Hegelund 		return NULL;
4178e10490bSSteen Hegelund 	return kset;
4188e10490bSSteen Hegelund }
419465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfieldset);
4208e10490bSSteen Hegelund 
421683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */
422d4134d41SSteen Hegelund const struct vcap_typegroup *
423683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl,
424683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
425683e05c0SSteen Hegelund {
426683e05c0SSteen Hegelund 	const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset);
427683e05c0SSteen Hegelund 
428683e05c0SSteen Hegelund 	/* Check that the keyset is valid */
429683e05c0SSteen Hegelund 	if (!kset)
430683e05c0SSteen Hegelund 		return NULL;
431683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item];
432683e05c0SSteen Hegelund }
433683e05c0SSteen Hegelund 
434683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */
435d4134d41SSteen Hegelund int vcap_keyfield_count(struct vcap_control *vctrl,
436683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
437683e05c0SSteen Hegelund {
438683e05c0SSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
439683e05c0SSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
440683e05c0SSteen Hegelund 		return 0;
441683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map_size[keyset];
442683e05c0SSteen Hegelund }
443683e05c0SSteen Hegelund 
444683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri,
445683e05c0SSteen Hegelund 				 const struct vcap_client_keyfield *kf,
446683e05c0SSteen Hegelund 				 const struct vcap_field *rf,
447683e05c0SSteen Hegelund 				 const struct vcap_typegroup *tgt)
448683e05c0SSteen Hegelund {
449683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
450683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
451683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
452683e05c0SSteen Hegelund 	const u8 *value, *mask;
453683e05c0SSteen Hegelund 
454683e05c0SSteen Hegelund 	/* Encode the fields for the key and the mask in their respective
455683e05c0SSteen Hegelund 	 * streams, respecting the subword width.
456683e05c0SSteen Hegelund 	 */
457683e05c0SSteen Hegelund 	switch (kf->ctrl.type) {
458683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
459683e05c0SSteen Hegelund 		value = &kf->data.u1.value;
460683e05c0SSteen Hegelund 		mask = &kf->data.u1.mask;
461683e05c0SSteen Hegelund 		break;
462683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
463683e05c0SSteen Hegelund 		value = (const u8 *)&kf->data.u32.value;
464683e05c0SSteen Hegelund 		mask = (const u8 *)&kf->data.u32.mask;
465683e05c0SSteen Hegelund 		break;
466683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
467683e05c0SSteen Hegelund 		value = kf->data.u48.value;
468683e05c0SSteen Hegelund 		mask = kf->data.u48.mask;
469683e05c0SSteen Hegelund 		break;
470683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
471683e05c0SSteen Hegelund 		value = kf->data.u56.value;
472683e05c0SSteen Hegelund 		mask = kf->data.u56.mask;
473683e05c0SSteen Hegelund 		break;
474683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
475683e05c0SSteen Hegelund 		value = kf->data.u64.value;
476683e05c0SSteen Hegelund 		mask = kf->data.u64.mask;
477683e05c0SSteen Hegelund 		break;
478683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
479683e05c0SSteen Hegelund 		value = kf->data.u72.value;
480683e05c0SSteen Hegelund 		mask = kf->data.u72.mask;
481683e05c0SSteen Hegelund 		break;
482683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
483683e05c0SSteen Hegelund 		value = kf->data.u112.value;
484683e05c0SSteen Hegelund 		mask = kf->data.u112.mask;
485683e05c0SSteen Hegelund 		break;
486683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
487683e05c0SSteen Hegelund 		value = kf->data.u128.value;
488683e05c0SSteen Hegelund 		mask = kf->data.u128.mask;
489683e05c0SSteen Hegelund 		break;
490683e05c0SSteen Hegelund 	}
491683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
492683e05c0SSteen Hegelund 	vcap_encode_field(cache->keystream, &iter, rf->width, value);
493683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
494683e05c0SSteen Hegelund 	vcap_encode_field(cache->maskstream, &iter, rf->width, mask);
495683e05c0SSteen Hegelund }
496683e05c0SSteen Hegelund 
497683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl,
498683e05c0SSteen Hegelund 					    struct vcap_rule_internal *ri,
499683e05c0SSteen Hegelund 					    const struct vcap_typegroup *tgt)
500683e05c0SSteen Hegelund {
501683e05c0SSteen Hegelund 	int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width;
502683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
503683e05c0SSteen Hegelund 
504683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the key and the mask in their streams,
505683e05c0SSteen Hegelund 	 * respecting the subword width.
506683e05c0SSteen Hegelund 	 */
507683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->keystream, sw_width, tgt, false);
508683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true);
509683e05c0SSteen Hegelund }
510683e05c0SSteen Hegelund 
511*33e3a273SSteen Hegelund /* Copy data from src to dst but reverse the data in chunks of 32bits.
512*33e3a273SSteen Hegelund  * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will
513*33e3a273SSteen Hegelund  * have the value 22:33:44:55:00:11.
514*33e3a273SSteen Hegelund  */
515*33e3a273SSteen Hegelund static void vcap_copy_to_w32be(u8 *dst, const u8 *src, int size)
516*33e3a273SSteen Hegelund {
517*33e3a273SSteen Hegelund 	for (int idx = 0; idx < size; ++idx) {
518*33e3a273SSteen Hegelund 		int first_byte_index = 0;
519*33e3a273SSteen Hegelund 		int nidx;
520*33e3a273SSteen Hegelund 
521*33e3a273SSteen Hegelund 		first_byte_index = size - (((idx >> 2) + 1) << 2);
522*33e3a273SSteen Hegelund 		if (first_byte_index < 0)
523*33e3a273SSteen Hegelund 			first_byte_index = 0;
524*33e3a273SSteen Hegelund 		nidx = idx + first_byte_index - (idx & ~0x3);
525*33e3a273SSteen Hegelund 		dst[nidx] = src[idx];
526*33e3a273SSteen Hegelund 	}
527*33e3a273SSteen Hegelund }
528*33e3a273SSteen Hegelund 
529*33e3a273SSteen Hegelund static void
530*33e3a273SSteen Hegelund vcap_copy_from_client_keyfield(struct vcap_rule *rule,
531*33e3a273SSteen Hegelund 			       struct vcap_client_keyfield *dst,
532*33e3a273SSteen Hegelund 			       const struct vcap_client_keyfield *src)
533*33e3a273SSteen Hegelund {
534*33e3a273SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
535*33e3a273SSteen Hegelund 	const struct vcap_client_keyfield_data *sdata;
536*33e3a273SSteen Hegelund 	struct vcap_client_keyfield_data *ddata;
537*33e3a273SSteen Hegelund 	int size;
538*33e3a273SSteen Hegelund 
539*33e3a273SSteen Hegelund 	dst->ctrl.type = src->ctrl.type;
540*33e3a273SSteen Hegelund 	dst->ctrl.key = src->ctrl.key;
541*33e3a273SSteen Hegelund 	INIT_LIST_HEAD(&dst->ctrl.list);
542*33e3a273SSteen Hegelund 	sdata = &src->data;
543*33e3a273SSteen Hegelund 	ddata = &dst->data;
544*33e3a273SSteen Hegelund 
545*33e3a273SSteen Hegelund 	if (!ri->admin->w32be) {
546*33e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
547*33e3a273SSteen Hegelund 		return;
548*33e3a273SSteen Hegelund 	}
549*33e3a273SSteen Hegelund 
550*33e3a273SSteen Hegelund 	size = keyfield_size_table[dst->ctrl.type] / 2;
551*33e3a273SSteen Hegelund 
552*33e3a273SSteen Hegelund 	switch (dst->ctrl.type) {
553*33e3a273SSteen Hegelund 	case VCAP_FIELD_BIT:
554*33e3a273SSteen Hegelund 	case VCAP_FIELD_U32:
555*33e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
556*33e3a273SSteen Hegelund 		break;
557*33e3a273SSteen Hegelund 	case VCAP_FIELD_U48:
558*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u48.value, src->data.u48.value, size);
559*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u48.mask,  src->data.u48.mask, size);
560*33e3a273SSteen Hegelund 		break;
561*33e3a273SSteen Hegelund 	case VCAP_FIELD_U56:
562*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size);
563*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u56.mask,  sdata->u56.mask, size);
564*33e3a273SSteen Hegelund 		break;
565*33e3a273SSteen Hegelund 	case VCAP_FIELD_U64:
566*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size);
567*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u64.mask,  sdata->u64.mask, size);
568*33e3a273SSteen Hegelund 		break;
569*33e3a273SSteen Hegelund 	case VCAP_FIELD_U72:
570*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size);
571*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u72.mask,  sdata->u72.mask, size);
572*33e3a273SSteen Hegelund 		break;
573*33e3a273SSteen Hegelund 	case VCAP_FIELD_U112:
574*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size);
575*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u112.mask,  sdata->u112.mask, size);
576*33e3a273SSteen Hegelund 		break;
577*33e3a273SSteen Hegelund 	case VCAP_FIELD_U128:
578*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size);
579*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u128.mask,  sdata->u128.mask, size);
580*33e3a273SSteen Hegelund 		break;
581*33e3a273SSteen Hegelund 	}
582*33e3a273SSteen Hegelund }
583*33e3a273SSteen Hegelund 
584*33e3a273SSteen Hegelund static void
585*33e3a273SSteen Hegelund vcap_copy_from_client_actionfield(struct vcap_rule *rule,
586*33e3a273SSteen Hegelund 				  struct vcap_client_actionfield *dst,
587*33e3a273SSteen Hegelund 				  const struct vcap_client_actionfield *src)
588*33e3a273SSteen Hegelund {
589*33e3a273SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
590*33e3a273SSteen Hegelund 	const struct vcap_client_actionfield_data *sdata;
591*33e3a273SSteen Hegelund 	struct vcap_client_actionfield_data *ddata;
592*33e3a273SSteen Hegelund 	int size;
593*33e3a273SSteen Hegelund 
594*33e3a273SSteen Hegelund 	dst->ctrl.type = src->ctrl.type;
595*33e3a273SSteen Hegelund 	dst->ctrl.action = src->ctrl.action;
596*33e3a273SSteen Hegelund 	INIT_LIST_HEAD(&dst->ctrl.list);
597*33e3a273SSteen Hegelund 	sdata = &src->data;
598*33e3a273SSteen Hegelund 	ddata = &dst->data;
599*33e3a273SSteen Hegelund 
600*33e3a273SSteen Hegelund 	if (!ri->admin->w32be) {
601*33e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
602*33e3a273SSteen Hegelund 		return;
603*33e3a273SSteen Hegelund 	}
604*33e3a273SSteen Hegelund 
605*33e3a273SSteen Hegelund 	size = actionfield_size_table[dst->ctrl.type];
606*33e3a273SSteen Hegelund 
607*33e3a273SSteen Hegelund 	switch (dst->ctrl.type) {
608*33e3a273SSteen Hegelund 	case VCAP_FIELD_BIT:
609*33e3a273SSteen Hegelund 	case VCAP_FIELD_U32:
610*33e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
611*33e3a273SSteen Hegelund 		break;
612*33e3a273SSteen Hegelund 	case VCAP_FIELD_U48:
613*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u48.value, sdata->u48.value, size);
614*33e3a273SSteen Hegelund 		break;
615*33e3a273SSteen Hegelund 	case VCAP_FIELD_U56:
616*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size);
617*33e3a273SSteen Hegelund 		break;
618*33e3a273SSteen Hegelund 	case VCAP_FIELD_U64:
619*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size);
620*33e3a273SSteen Hegelund 		break;
621*33e3a273SSteen Hegelund 	case VCAP_FIELD_U72:
622*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size);
623*33e3a273SSteen Hegelund 		break;
624*33e3a273SSteen Hegelund 	case VCAP_FIELD_U112:
625*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size);
626*33e3a273SSteen Hegelund 		break;
627*33e3a273SSteen Hegelund 	case VCAP_FIELD_U128:
628*33e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size);
629*33e3a273SSteen Hegelund 		break;
630*33e3a273SSteen Hegelund 	}
631*33e3a273SSteen Hegelund }
632*33e3a273SSteen Hegelund 
633683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
634683e05c0SSteen Hegelund {
635683e05c0SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
636683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
637*33e3a273SSteen Hegelund 	struct vcap_client_keyfield tempkf;
638683e05c0SSteen Hegelund 	const struct vcap_field *kf_table;
639683e05c0SSteen Hegelund 	int keyset_size;
640683e05c0SSteen Hegelund 
641683e05c0SSteen Hegelund 	/* Get a valid set of fields for the specific keyset */
642683e05c0SSteen Hegelund 	kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset);
643683e05c0SSteen Hegelund 	if (!kf_table) {
644683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this keyset: %d\n",
645683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
646683e05c0SSteen Hegelund 		return -EINVAL;
647683e05c0SSteen Hegelund 	}
648683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific keyset */
649683e05c0SSteen Hegelund 	tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype,
650683e05c0SSteen Hegelund 					   ri->data.keyset);
651683e05c0SSteen Hegelund 	if (!tg_table) {
652683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this keyset: %d\n",
653683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
654683e05c0SSteen Hegelund 		return -EINVAL;
655683e05c0SSteen Hegelund 	}
656683e05c0SSteen Hegelund 	/* Get a valid size for the specific keyset */
657683e05c0SSteen Hegelund 	keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype,
658683e05c0SSteen Hegelund 					  ri->data.keyset);
659683e05c0SSteen Hegelund 	if (keyset_size == 0) {
660683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this keyset: %d\n",
661683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
662683e05c0SSteen Hegelund 		return -EINVAL;
663683e05c0SSteen Hegelund 	}
664683e05c0SSteen Hegelund 	/* Iterate over the keyfields (key, mask) in the rule
665683e05c0SSteen Hegelund 	 * and encode these bits
666683e05c0SSteen Hegelund 	 */
667683e05c0SSteen Hegelund 	if (list_empty(&ri->data.keyfields)) {
668683e05c0SSteen Hegelund 		pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__);
669683e05c0SSteen Hegelund 		return -EINVAL;
670683e05c0SSteen Hegelund 	}
671683e05c0SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
672683e05c0SSteen Hegelund 		/* Check that the client entry exists in the keyset */
673683e05c0SSteen Hegelund 		if (ckf->ctrl.key >= keyset_size) {
674683e05c0SSteen Hegelund 			pr_err("%s:%d: key %d is not in vcap\n",
675683e05c0SSteen Hegelund 			       __func__, __LINE__, ckf->ctrl.key);
676683e05c0SSteen Hegelund 			return -EINVAL;
677683e05c0SSteen Hegelund 		}
678*33e3a273SSteen Hegelund 		vcap_copy_from_client_keyfield(&ri->data, &tempkf, ckf);
679*33e3a273SSteen Hegelund 		vcap_encode_keyfield(ri, &tempkf, &kf_table[ckf->ctrl.key],
680*33e3a273SSteen Hegelund 				     tg_table);
681683e05c0SSteen Hegelund 	}
682683e05c0SSteen Hegelund 	/* Add typegroup bits to the key/mask bitstreams */
683683e05c0SSteen Hegelund 	vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table);
684683e05c0SSteen Hegelund 	return 0;
685683e05c0SSteen Hegelund }
686683e05c0SSteen Hegelund 
687683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */
68872d84dd6SSteen Hegelund const struct vcap_field *
689683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl,
690683e05c0SSteen Hegelund 		  enum vcap_type vt, enum vcap_actionfield_set actionset)
691683e05c0SSteen Hegelund {
692683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
693683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
694683e05c0SSteen Hegelund 		return NULL;
695683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map[actionset];
696683e05c0SSteen Hegelund }
697683e05c0SSteen Hegelund 
69872d84dd6SSteen Hegelund const struct vcap_set *
6998e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl,
7008e10490bSSteen Hegelund 		    enum vcap_type vt, enum vcap_actionfield_set actionset)
7018e10490bSSteen Hegelund {
7028e10490bSSteen Hegelund 	const struct vcap_set *aset;
7038e10490bSSteen Hegelund 
7048e10490bSSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
7058e10490bSSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
7068e10490bSSteen Hegelund 		return NULL;
7078e10490bSSteen Hegelund 	aset = &vctrl->vcaps[vt].actionfield_set[actionset];
7088e10490bSSteen Hegelund 	if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count)
7098e10490bSSteen Hegelund 		return NULL;
7108e10490bSSteen Hegelund 	return aset;
7118e10490bSSteen Hegelund }
7128e10490bSSteen Hegelund 
713683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */
71472d84dd6SSteen Hegelund const struct vcap_typegroup *
715683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl,
716683e05c0SSteen Hegelund 			   enum vcap_type vt, enum vcap_actionfield_set actionset)
717683e05c0SSteen Hegelund {
718683e05c0SSteen Hegelund 	const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset);
719683e05c0SSteen Hegelund 
720683e05c0SSteen Hegelund 	/* Check that the actionset is valid */
721683e05c0SSteen Hegelund 	if (!aset)
722683e05c0SSteen Hegelund 		return NULL;
723683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item];
724683e05c0SSteen Hegelund }
725683e05c0SSteen Hegelund 
726683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */
72772d84dd6SSteen Hegelund int vcap_actionfield_count(struct vcap_control *vctrl,
728683e05c0SSteen Hegelund 			   enum vcap_type vt,
729683e05c0SSteen Hegelund 			   enum vcap_actionfield_set actionset)
730683e05c0SSteen Hegelund {
731683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
732683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
733683e05c0SSteen Hegelund 		return 0;
734683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map_size[actionset];
735683e05c0SSteen Hegelund }
736683e05c0SSteen Hegelund 
737683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri,
738683e05c0SSteen Hegelund 				    const struct vcap_client_actionfield *af,
739683e05c0SSteen Hegelund 				    const struct vcap_field *rf,
740683e05c0SSteen Hegelund 				    const struct vcap_typegroup *tgt)
741683e05c0SSteen Hegelund {
742683e05c0SSteen Hegelund 	int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
743683e05c0SSteen Hegelund 
744683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
745683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
746683e05c0SSteen Hegelund 	const u8 *value;
747683e05c0SSteen Hegelund 
748683e05c0SSteen Hegelund 	/* Encode the action field in the stream, respecting the subword width */
749683e05c0SSteen Hegelund 	switch (af->ctrl.type) {
750683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
751683e05c0SSteen Hegelund 		value = &af->data.u1.value;
752683e05c0SSteen Hegelund 		break;
753683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
754683e05c0SSteen Hegelund 		value = (const u8 *)&af->data.u32.value;
755683e05c0SSteen Hegelund 		break;
756683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
757683e05c0SSteen Hegelund 		value = af->data.u48.value;
758683e05c0SSteen Hegelund 		break;
759683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
760683e05c0SSteen Hegelund 		value = af->data.u56.value;
761683e05c0SSteen Hegelund 		break;
762683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
763683e05c0SSteen Hegelund 		value = af->data.u64.value;
764683e05c0SSteen Hegelund 		break;
765683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
766683e05c0SSteen Hegelund 		value = af->data.u72.value;
767683e05c0SSteen Hegelund 		break;
768683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
769683e05c0SSteen Hegelund 		value = af->data.u112.value;
770683e05c0SSteen Hegelund 		break;
771683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
772683e05c0SSteen Hegelund 		value = af->data.u128.value;
773683e05c0SSteen Hegelund 		break;
774683e05c0SSteen Hegelund 	}
775683e05c0SSteen Hegelund 	vcap_iter_init(&iter, act_width, tgt, rf->offset);
776683e05c0SSteen Hegelund 	vcap_encode_field(cache->actionstream, &iter, rf->width, value);
777683e05c0SSteen Hegelund }
778683e05c0SSteen Hegelund 
779683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri,
780683e05c0SSteen Hegelund 					       const struct vcap_typegroup *tgt)
781683e05c0SSteen Hegelund {
782683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
783683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
784683e05c0SSteen Hegelund 
785683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the actionstream respecting the subword
786683e05c0SSteen Hegelund 	 * width.
787683e05c0SSteen Hegelund 	 */
788683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false);
789683e05c0SSteen Hegelund }
790683e05c0SSteen Hegelund 
791683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri)
792683e05c0SSteen Hegelund {
793683e05c0SSteen Hegelund 	const struct vcap_client_actionfield *caf;
794683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
795*33e3a273SSteen Hegelund 	struct vcap_client_actionfield tempaf;
796683e05c0SSteen Hegelund 	const struct vcap_field *af_table;
797683e05c0SSteen Hegelund 	int actionset_size;
798683e05c0SSteen Hegelund 
799683e05c0SSteen Hegelund 	/* Get a valid set of actionset fields for the specific actionset */
800683e05c0SSteen Hegelund 	af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype,
801683e05c0SSteen Hegelund 				     ri->data.actionset);
802683e05c0SSteen Hegelund 	if (!af_table) {
803683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this actionset: %d\n",
804683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
805683e05c0SSteen Hegelund 		return -EINVAL;
806683e05c0SSteen Hegelund 	}
807683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific actionset */
808683e05c0SSteen Hegelund 	tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype,
809683e05c0SSteen Hegelund 					      ri->data.actionset);
810683e05c0SSteen Hegelund 	if (!tg_table) {
811683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this actionset: %d\n",
812683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
813683e05c0SSteen Hegelund 		return -EINVAL;
814683e05c0SSteen Hegelund 	}
815683e05c0SSteen Hegelund 	/* Get a valid actionset size for the specific actionset */
816683e05c0SSteen Hegelund 	actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype,
817683e05c0SSteen Hegelund 						ri->data.actionset);
818683e05c0SSteen Hegelund 	if (actionset_size == 0) {
819683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this actionset: %d\n",
820683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
821683e05c0SSteen Hegelund 		return -EINVAL;
822683e05c0SSteen Hegelund 	}
823683e05c0SSteen Hegelund 	/* Iterate over the actionfields in the rule
824683e05c0SSteen Hegelund 	 * and encode these bits
825683e05c0SSteen Hegelund 	 */
826683e05c0SSteen Hegelund 	if (list_empty(&ri->data.actionfields))
827683e05c0SSteen Hegelund 		pr_warn("%s:%d: no actionfields in the rule\n",
828683e05c0SSteen Hegelund 			__func__, __LINE__);
829683e05c0SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
830683e05c0SSteen Hegelund 		/* Check that the client action exists in the actionset */
831683e05c0SSteen Hegelund 		if (caf->ctrl.action >= actionset_size) {
832683e05c0SSteen Hegelund 			pr_err("%s:%d: action %d is not in vcap\n",
833683e05c0SSteen Hegelund 			       __func__, __LINE__, caf->ctrl.action);
834683e05c0SSteen Hegelund 			return -EINVAL;
835683e05c0SSteen Hegelund 		}
836*33e3a273SSteen Hegelund 		vcap_copy_from_client_actionfield(&ri->data, &tempaf, caf);
837*33e3a273SSteen Hegelund 		vcap_encode_actionfield(ri, &tempaf,
838*33e3a273SSteen Hegelund 					&af_table[caf->ctrl.action], tg_table);
839683e05c0SSteen Hegelund 	}
840683e05c0SSteen Hegelund 	/* Add typegroup bits to the entry bitstreams */
841683e05c0SSteen Hegelund 	vcap_encode_actionfield_typegroups(ri, tg_table);
842683e05c0SSteen Hegelund 	return 0;
843683e05c0SSteen Hegelund }
844683e05c0SSteen Hegelund 
8458e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri)
8468e10490bSSteen Hegelund {
847683e05c0SSteen Hegelund 	int err;
848683e05c0SSteen Hegelund 
849683e05c0SSteen Hegelund 	err = vcap_encode_rule_keyset(ri);
850683e05c0SSteen Hegelund 	if (err)
851683e05c0SSteen Hegelund 		return err;
852683e05c0SSteen Hegelund 	err = vcap_encode_rule_actionset(ri);
853683e05c0SSteen Hegelund 	if (err)
854683e05c0SSteen Hegelund 		return err;
8558e10490bSSteen Hegelund 	return 0;
8568e10490bSSteen Hegelund }
8578e10490bSSteen Hegelund 
858d4134d41SSteen Hegelund int vcap_api_check(struct vcap_control *ctrl)
8598e10490bSSteen Hegelund {
8608e10490bSSteen Hegelund 	if (!ctrl) {
8618e10490bSSteen Hegelund 		pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
8628e10490bSSteen Hegelund 		return -EINVAL;
8638e10490bSSteen Hegelund 	}
8648e10490bSSteen Hegelund 	if (!ctrl->ops || !ctrl->ops->validate_keyset ||
8658e10490bSSteen Hegelund 	    !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
8668e10490bSSteen Hegelund 	    !ctrl->ops->cache_write || !ctrl->ops->cache_read ||
8678e10490bSSteen Hegelund 	    !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
86801ef75a2SSteen Hegelund 	    !ctrl->ops->port_info) {
8698e10490bSSteen Hegelund 		pr_err("%s:%d: client operations are missing\n",
8708e10490bSSteen Hegelund 		       __func__, __LINE__);
8718e10490bSSteen Hegelund 		return -ENOENT;
8728e10490bSSteen Hegelund 	}
8738e10490bSSteen Hegelund 	return 0;
8748e10490bSSteen Hegelund }
8758e10490bSSteen Hegelund 
8763a792156SSteen Hegelund void vcap_erase_cache(struct vcap_rule_internal *ri)
8778e10490bSSteen Hegelund {
8788e10490bSSteen Hegelund 	ri->vctrl->ops->cache_erase(ri->admin);
8798e10490bSSteen Hegelund }
8808e10490bSSteen Hegelund 
881c9da1ac1SSteen Hegelund /* Update the keyset for the rule */
882c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule,
883c9da1ac1SSteen Hegelund 			     enum vcap_keyfield_set keyset)
884c9da1ac1SSteen Hegelund {
8858e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
8868e10490bSSteen Hegelund 	const struct vcap_set *kset;
8878e10490bSSteen Hegelund 	int sw_width;
8888e10490bSSteen Hegelund 
8898e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset);
8908e10490bSSteen Hegelund 	/* Check that the keyset is valid */
8918e10490bSSteen Hegelund 	if (!kset)
8928e10490bSSteen Hegelund 		return -EINVAL;
8938e10490bSSteen Hegelund 	ri->keyset_sw = kset->sw_per_item;
8948e10490bSSteen Hegelund 	sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
8958e10490bSSteen Hegelund 	ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32);
8968e10490bSSteen Hegelund 	ri->data.keyset = keyset;
897c9da1ac1SSteen Hegelund 	return 0;
898c9da1ac1SSteen Hegelund }
899c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset);
900c9da1ac1SSteen Hegelund 
901c9da1ac1SSteen Hegelund /* Update the actionset for the rule */
902c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule,
903c9da1ac1SSteen Hegelund 				enum vcap_actionfield_set actionset)
904c9da1ac1SSteen Hegelund {
9058e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
9068e10490bSSteen Hegelund 	const struct vcap_set *aset;
9078e10490bSSteen Hegelund 	int act_width;
9088e10490bSSteen Hegelund 
9098e10490bSSteen Hegelund 	aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset);
9108e10490bSSteen Hegelund 	/* Check that the actionset is valid */
9118e10490bSSteen Hegelund 	if (!aset)
9128e10490bSSteen Hegelund 		return -EINVAL;
9138e10490bSSteen Hegelund 	ri->actionset_sw = aset->sw_per_item;
9148e10490bSSteen Hegelund 	act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
9158e10490bSSteen Hegelund 	ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32);
9168e10490bSSteen Hegelund 	ri->data.actionset = actionset;
917c9da1ac1SSteen Hegelund 	return 0;
918c9da1ac1SSteen Hegelund }
919c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset);
920c9da1ac1SSteen Hegelund 
921c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */
922c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl,
923c9da1ac1SSteen Hegelund 						   u32 id)
924c9da1ac1SSteen Hegelund {
925c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
926c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
927c9da1ac1SSteen Hegelund 
928c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
929c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
930c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
931c9da1ac1SSteen Hegelund 			if (ri->data.id == id)
932c9da1ac1SSteen Hegelund 				return ri;
933c9da1ac1SSteen Hegelund 	return NULL;
934c9da1ac1SSteen Hegelund }
935c9da1ac1SSteen Hegelund 
936c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */
937c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
938c9da1ac1SSteen Hegelund {
939c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
940c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
941c9da1ac1SSteen Hegelund 
942c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
943c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
944c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
945c9da1ac1SSteen Hegelund 			if (ri->data.cookie == cookie)
946c9da1ac1SSteen Hegelund 				return ri->data.id;
947c9da1ac1SSteen Hegelund 	return -ENOENT;
948c9da1ac1SSteen Hegelund }
949c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
950c9da1ac1SSteen Hegelund 
9518e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */
9523a792156SSteen Hegelund struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
9538e10490bSSteen Hegelund {
9548e10490bSSteen Hegelund 	struct vcap_rule_internal *duprule;
9558e10490bSSteen Hegelund 
9568e10490bSSteen Hegelund 	/* Allocate the client part */
9578e10490bSSteen Hegelund 	duprule = kzalloc(sizeof(*duprule), GFP_KERNEL);
9588e10490bSSteen Hegelund 	if (!duprule)
9598e10490bSSteen Hegelund 		return ERR_PTR(-ENOMEM);
9608e10490bSSteen Hegelund 	*duprule = *ri;
9618e10490bSSteen Hegelund 	/* Not inserted in the VCAP */
9628e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->list);
9638e10490bSSteen Hegelund 	/* No elements in these lists */
9648e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.keyfields);
9658e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.actionfields);
9668e10490bSSteen Hegelund 	return duprule;
9678e10490bSSteen Hegelund }
9688e10490bSSteen Hegelund 
969610c32b2SHoratiu Vultur static void vcap_apply_width(u8 *dst, int width, int bytes)
970610c32b2SHoratiu Vultur {
971610c32b2SHoratiu Vultur 	u8 bmask;
972610c32b2SHoratiu Vultur 	int idx;
973610c32b2SHoratiu Vultur 
974610c32b2SHoratiu Vultur 	for (idx = 0; idx < bytes; idx++) {
975610c32b2SHoratiu Vultur 		if (width > 0)
976610c32b2SHoratiu Vultur 			if (width < 8)
977610c32b2SHoratiu Vultur 				bmask = (1 << width) - 1;
978610c32b2SHoratiu Vultur 			else
979610c32b2SHoratiu Vultur 				bmask = ~0;
980610c32b2SHoratiu Vultur 		else
981610c32b2SHoratiu Vultur 			bmask = 0;
982610c32b2SHoratiu Vultur 		dst[idx] &= bmask;
983610c32b2SHoratiu Vultur 		width -= 8;
984610c32b2SHoratiu Vultur 	}
985610c32b2SHoratiu Vultur }
986610c32b2SHoratiu Vultur 
987610c32b2SHoratiu Vultur static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width)
988610c32b2SHoratiu Vultur {
989610c32b2SHoratiu Vultur 	int idx, ridx, wstart, nidx;
990610c32b2SHoratiu Vultur 	int tail_bytes = (((size + 4) >> 2) << 2) - size;
991610c32b2SHoratiu Vultur 
992610c32b2SHoratiu Vultur 	for (idx = 0, ridx = size - 1; idx < size; ++idx, --ridx) {
993610c32b2SHoratiu Vultur 		wstart = (idx >> 2) << 2;
994610c32b2SHoratiu Vultur 		nidx = wstart + 3 - (idx & 0x3);
995610c32b2SHoratiu Vultur 		if (nidx >= size)
996610c32b2SHoratiu Vultur 			nidx -= tail_bytes;
997610c32b2SHoratiu Vultur 		dst[nidx] = src[ridx];
998610c32b2SHoratiu Vultur 	}
999610c32b2SHoratiu Vultur 
1000610c32b2SHoratiu Vultur 	vcap_apply_width(dst, width, size);
1001610c32b2SHoratiu Vultur }
1002610c32b2SHoratiu Vultur 
1003610c32b2SHoratiu Vultur static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *value)
1004610c32b2SHoratiu Vultur {
1005610c32b2SHoratiu Vultur 	field->value = (*value) & 0x1;
1006610c32b2SHoratiu Vultur }
1007610c32b2SHoratiu Vultur 
1008610c32b2SHoratiu Vultur static void vcap_copy_limited_actionfield(u8 *dstvalue, u8 *srcvalue,
1009610c32b2SHoratiu Vultur 					  int width, int bytes)
1010610c32b2SHoratiu Vultur {
1011610c32b2SHoratiu Vultur 	memcpy(dstvalue, srcvalue, bytes);
1012610c32b2SHoratiu Vultur 	vcap_apply_width(dstvalue, width, bytes);
1013610c32b2SHoratiu Vultur }
1014610c32b2SHoratiu Vultur 
1015610c32b2SHoratiu Vultur static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri,
1016610c32b2SHoratiu Vultur 					    struct vcap_client_actionfield *field,
1017610c32b2SHoratiu Vultur 					    u8 *value, u16 width)
1018610c32b2SHoratiu Vultur {
1019610c32b2SHoratiu Vultur 	int field_size = actionfield_size_table[field->ctrl.type];
1020610c32b2SHoratiu Vultur 
1021610c32b2SHoratiu Vultur 	if (ri->admin->w32be) {
1022610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1023610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1024610c32b2SHoratiu Vultur 			vcap_copy_action_bit_field(&field->data.u1, value);
1025610c32b2SHoratiu Vultur 			break;
1026610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1027610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
1028610c32b2SHoratiu Vultur 						      value,
1029610c32b2SHoratiu Vultur 						      width, field_size);
1030610c32b2SHoratiu Vultur 			break;
1031610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1032610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.value, value,
1033610c32b2SHoratiu Vultur 					     field_size, width);
1034610c32b2SHoratiu Vultur 			break;
1035610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1036610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.value, value,
1037610c32b2SHoratiu Vultur 					     field_size, width);
1038610c32b2SHoratiu Vultur 			break;
1039610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1040610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.value, value,
1041610c32b2SHoratiu Vultur 					     field_size, width);
1042610c32b2SHoratiu Vultur 			break;
1043610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1044610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.value, value,
1045610c32b2SHoratiu Vultur 					     field_size, width);
1046610c32b2SHoratiu Vultur 			break;
1047610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1048610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.value, value,
1049610c32b2SHoratiu Vultur 					     field_size, width);
1050610c32b2SHoratiu Vultur 			break;
1051610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1052610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.value, value,
1053610c32b2SHoratiu Vultur 					     field_size, width);
1054610c32b2SHoratiu Vultur 			break;
1055610c32b2SHoratiu Vultur 		};
1056610c32b2SHoratiu Vultur 	} else {
1057610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1058610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1059610c32b2SHoratiu Vultur 			vcap_copy_action_bit_field(&field->data.u1, value);
1060610c32b2SHoratiu Vultur 			break;
1061610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1062610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
1063610c32b2SHoratiu Vultur 						      value,
1064610c32b2SHoratiu Vultur 						      width, field_size);
1065610c32b2SHoratiu Vultur 			break;
1066610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1067610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u48.value,
1068610c32b2SHoratiu Vultur 						      value,
1069610c32b2SHoratiu Vultur 						      width, field_size);
1070610c32b2SHoratiu Vultur 			break;
1071610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1072610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u56.value,
1073610c32b2SHoratiu Vultur 						      value,
1074610c32b2SHoratiu Vultur 						      width, field_size);
1075610c32b2SHoratiu Vultur 			break;
1076610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1077610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u64.value,
1078610c32b2SHoratiu Vultur 						      value,
1079610c32b2SHoratiu Vultur 						      width, field_size);
1080610c32b2SHoratiu Vultur 			break;
1081610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1082610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u72.value,
1083610c32b2SHoratiu Vultur 						      value,
1084610c32b2SHoratiu Vultur 						      width, field_size);
1085610c32b2SHoratiu Vultur 			break;
1086610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1087610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u112.value,
1088610c32b2SHoratiu Vultur 						      value,
1089610c32b2SHoratiu Vultur 						      width, field_size);
1090610c32b2SHoratiu Vultur 			break;
1091610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1092610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u128.value,
1093610c32b2SHoratiu Vultur 						      value,
1094610c32b2SHoratiu Vultur 						      width, field_size);
1095610c32b2SHoratiu Vultur 			break;
1096610c32b2SHoratiu Vultur 		};
1097610c32b2SHoratiu Vultur 	}
1098610c32b2SHoratiu Vultur }
1099610c32b2SHoratiu Vultur 
1100610c32b2SHoratiu Vultur static void vcap_copy_key_bit_field(struct vcap_u1_key *field,
1101610c32b2SHoratiu Vultur 				    u8 *value, u8 *mask)
1102610c32b2SHoratiu Vultur {
1103610c32b2SHoratiu Vultur 	field->value = (*value) & 0x1;
1104610c32b2SHoratiu Vultur 	field->mask = (*mask) & 0x1;
1105610c32b2SHoratiu Vultur }
1106610c32b2SHoratiu Vultur 
1107610c32b2SHoratiu Vultur static void vcap_copy_limited_keyfield(u8 *dstvalue, u8 *dstmask,
1108610c32b2SHoratiu Vultur 				       u8 *srcvalue, u8 *srcmask,
1109610c32b2SHoratiu Vultur 				       int width, int bytes)
1110610c32b2SHoratiu Vultur {
1111610c32b2SHoratiu Vultur 	memcpy(dstvalue, srcvalue, bytes);
1112610c32b2SHoratiu Vultur 	vcap_apply_width(dstvalue, width, bytes);
1113610c32b2SHoratiu Vultur 	memcpy(dstmask, srcmask, bytes);
1114610c32b2SHoratiu Vultur 	vcap_apply_width(dstmask, width, bytes);
1115610c32b2SHoratiu Vultur }
1116610c32b2SHoratiu Vultur 
1117610c32b2SHoratiu Vultur static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri,
1118610c32b2SHoratiu Vultur 					 struct vcap_client_keyfield *field,
1119610c32b2SHoratiu Vultur 					 u8 *value, u8 *mask, u16 width)
1120610c32b2SHoratiu Vultur {
1121610c32b2SHoratiu Vultur 	int field_size = keyfield_size_table[field->ctrl.type] / 2;
1122610c32b2SHoratiu Vultur 
1123610c32b2SHoratiu Vultur 	if (ri->admin->w32be) {
1124610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1125610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1126610c32b2SHoratiu Vultur 			vcap_copy_key_bit_field(&field->data.u1, value, mask);
1127610c32b2SHoratiu Vultur 			break;
1128610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1129610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1130610c32b2SHoratiu Vultur 						   (u8 *)&field->data.u32.mask,
1131610c32b2SHoratiu Vultur 						   value, mask,
1132610c32b2SHoratiu Vultur 						   width, field_size);
1133610c32b2SHoratiu Vultur 			break;
1134610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1135610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.value, value,
1136610c32b2SHoratiu Vultur 					     field_size, width);
1137610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.mask,  mask,
1138610c32b2SHoratiu Vultur 					     field_size, width);
1139610c32b2SHoratiu Vultur 			break;
1140610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1141610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.value, value,
1142610c32b2SHoratiu Vultur 					     field_size, width);
1143610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.mask,  mask,
1144610c32b2SHoratiu Vultur 					     field_size, width);
1145610c32b2SHoratiu Vultur 			break;
1146610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1147610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.value, value,
1148610c32b2SHoratiu Vultur 					     field_size, width);
1149610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.mask,  mask,
1150610c32b2SHoratiu Vultur 					     field_size, width);
1151610c32b2SHoratiu Vultur 			break;
1152610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1153610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.value, value,
1154610c32b2SHoratiu Vultur 					     field_size, width);
1155610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.mask,  mask,
1156610c32b2SHoratiu Vultur 					     field_size, width);
1157610c32b2SHoratiu Vultur 			break;
1158610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1159610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.value, value,
1160610c32b2SHoratiu Vultur 					     field_size, width);
1161610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.mask,  mask,
1162610c32b2SHoratiu Vultur 					     field_size, width);
1163610c32b2SHoratiu Vultur 			break;
1164610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1165610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.value, value,
1166610c32b2SHoratiu Vultur 					     field_size, width);
1167610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.mask,  mask,
1168610c32b2SHoratiu Vultur 					     field_size, width);
1169610c32b2SHoratiu Vultur 			break;
1170610c32b2SHoratiu Vultur 		};
1171610c32b2SHoratiu Vultur 	} else {
1172610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1173610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1174610c32b2SHoratiu Vultur 			vcap_copy_key_bit_field(&field->data.u1, value, mask);
1175610c32b2SHoratiu Vultur 			break;
1176610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1177610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1178610c32b2SHoratiu Vultur 						   (u8 *)&field->data.u32.mask,
1179610c32b2SHoratiu Vultur 						   value, mask,
1180610c32b2SHoratiu Vultur 						   width, field_size);
1181610c32b2SHoratiu Vultur 			break;
1182610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1183610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u48.value,
1184610c32b2SHoratiu Vultur 						   field->data.u48.mask,
1185610c32b2SHoratiu Vultur 						   value, mask,
1186610c32b2SHoratiu Vultur 						   width, field_size);
1187610c32b2SHoratiu Vultur 			break;
1188610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1189610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u56.value,
1190610c32b2SHoratiu Vultur 						   field->data.u56.mask,
1191610c32b2SHoratiu Vultur 						   value, mask,
1192610c32b2SHoratiu Vultur 						   width, field_size);
1193610c32b2SHoratiu Vultur 			break;
1194610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1195610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u64.value,
1196610c32b2SHoratiu Vultur 						   field->data.u64.mask,
1197610c32b2SHoratiu Vultur 						   value, mask,
1198610c32b2SHoratiu Vultur 						   width, field_size);
1199610c32b2SHoratiu Vultur 			break;
1200610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1201610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u72.value,
1202610c32b2SHoratiu Vultur 						   field->data.u72.mask,
1203610c32b2SHoratiu Vultur 						   value, mask,
1204610c32b2SHoratiu Vultur 						   width, field_size);
1205610c32b2SHoratiu Vultur 			break;
1206610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1207610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u112.value,
1208610c32b2SHoratiu Vultur 						   field->data.u112.mask,
1209610c32b2SHoratiu Vultur 						   value, mask,
1210610c32b2SHoratiu Vultur 						   width, field_size);
1211610c32b2SHoratiu Vultur 			break;
1212610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1213610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u128.value,
1214610c32b2SHoratiu Vultur 						   field->data.u128.mask,
1215610c32b2SHoratiu Vultur 						   value, mask,
1216610c32b2SHoratiu Vultur 						   width, field_size);
1217610c32b2SHoratiu Vultur 			break;
1218610c32b2SHoratiu Vultur 		};
1219610c32b2SHoratiu Vultur 	}
1220610c32b2SHoratiu Vultur }
1221610c32b2SHoratiu Vultur 
1222610c32b2SHoratiu Vultur static void vcap_rule_alloc_keyfield(struct vcap_rule_internal *ri,
1223610c32b2SHoratiu Vultur 				     const struct vcap_field *keyfield,
1224610c32b2SHoratiu Vultur 				     enum vcap_key_field key,
1225610c32b2SHoratiu Vultur 				     u8 *value, u8 *mask)
1226610c32b2SHoratiu Vultur {
1227610c32b2SHoratiu Vultur 	struct vcap_client_keyfield *field;
1228610c32b2SHoratiu Vultur 
1229610c32b2SHoratiu Vultur 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1230610c32b2SHoratiu Vultur 	if (!field)
1231610c32b2SHoratiu Vultur 		return;
1232610c32b2SHoratiu Vultur 	INIT_LIST_HEAD(&field->ctrl.list);
1233610c32b2SHoratiu Vultur 	field->ctrl.key = key;
1234610c32b2SHoratiu Vultur 	field->ctrl.type = keyfield->type;
1235610c32b2SHoratiu Vultur 	vcap_copy_to_client_keyfield(ri, field, value, mask, keyfield->width);
1236610c32b2SHoratiu Vultur 	list_add_tail(&field->ctrl.list, &ri->data.keyfields);
1237610c32b2SHoratiu Vultur }
1238610c32b2SHoratiu Vultur 
1239610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there is a rule keyset
1240610c32b2SHoratiu Vultur  * here
1241610c32b2SHoratiu Vultur  */
1242610c32b2SHoratiu Vultur static bool
1243610c32b2SHoratiu Vultur vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
1244610c32b2SHoratiu Vultur 				   enum vcap_type vt,
1245610c32b2SHoratiu Vultur 				   u32 *actionstream,
1246610c32b2SHoratiu Vultur 				   enum vcap_actionfield_set actionset)
1247610c32b2SHoratiu Vultur {
1248610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1249610c32b2SHoratiu Vultur 	const struct vcap_field *fields;
1250610c32b2SHoratiu Vultur 	const struct vcap_set *info;
1251610c32b2SHoratiu Vultur 
1252610c32b2SHoratiu Vultur 	if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
1253610c32b2SHoratiu Vultur 		return false;
1254610c32b2SHoratiu Vultur 
1255610c32b2SHoratiu Vultur 	info = vcap_actionfieldset(vctrl, vt, actionset);
1256610c32b2SHoratiu Vultur 	/* Check that the actionset is valid */
1257610c32b2SHoratiu Vultur 	if (!info)
1258610c32b2SHoratiu Vultur 		return false;
1259610c32b2SHoratiu Vultur 
1260610c32b2SHoratiu Vultur 	/* a type_id of value -1 means that there is no type field */
1261610c32b2SHoratiu Vultur 	if (info->type_id == (u8)-1)
1262610c32b2SHoratiu Vultur 		return true;
1263610c32b2SHoratiu Vultur 
1264610c32b2SHoratiu Vultur 	/* Get a valid typegroup for the specific actionset */
1265610c32b2SHoratiu Vultur 	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1266610c32b2SHoratiu Vultur 	if (!tgt)
1267610c32b2SHoratiu Vultur 		return false;
1268610c32b2SHoratiu Vultur 
1269610c32b2SHoratiu Vultur 	fields = vcap_actionfields(vctrl, vt, actionset);
1270610c32b2SHoratiu Vultur 	if (!fields)
1271610c32b2SHoratiu Vultur 		return false;
1272610c32b2SHoratiu Vultur 
1273610c32b2SHoratiu Vultur 	/* Later this will be expanded with a check of the type id */
1274610c32b2SHoratiu Vultur 	return true;
1275610c32b2SHoratiu Vultur }
1276610c32b2SHoratiu Vultur 
1277610c32b2SHoratiu Vultur /* Find the subword width of the action typegroup that matches the stream data
1278610c32b2SHoratiu Vultur  */
1279610c32b2SHoratiu Vultur static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
1280610c32b2SHoratiu Vultur 					       enum vcap_type vt, u32 *stream,
1281610c32b2SHoratiu Vultur 					       int sw_max)
1282610c32b2SHoratiu Vultur {
1283610c32b2SHoratiu Vultur 	const struct vcap_typegroup **tgt;
1284610c32b2SHoratiu Vultur 	int sw_idx, res;
1285610c32b2SHoratiu Vultur 
1286610c32b2SHoratiu Vultur 	tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
1287610c32b2SHoratiu Vultur 	/* Try the longest subword match first */
1288610c32b2SHoratiu Vultur 	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
1289610c32b2SHoratiu Vultur 		if (!tgt[sw_idx])
1290610c32b2SHoratiu Vultur 			continue;
1291610c32b2SHoratiu Vultur 		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
1292610c32b2SHoratiu Vultur 					     tgt[sw_idx], false, sw_max);
1293610c32b2SHoratiu Vultur 		if (res == 0)
1294610c32b2SHoratiu Vultur 			return sw_idx;
1295610c32b2SHoratiu Vultur 	}
1296610c32b2SHoratiu Vultur 	return -EINVAL;
1297610c32b2SHoratiu Vultur }
1298610c32b2SHoratiu Vultur 
1299610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, actionset and type id
1300610c32b2SHoratiu Vultur  * are in sync and correct, return the actionset
1301610c32b2SHoratiu Vultur  */
1302610c32b2SHoratiu Vultur static enum vcap_actionfield_set
1303610c32b2SHoratiu Vultur vcap_find_actionstream_actionset(struct vcap_control *vctrl,
1304610c32b2SHoratiu Vultur 				 enum vcap_type vt,
1305610c32b2SHoratiu Vultur 				 u32 *stream,
1306610c32b2SHoratiu Vultur 				 int sw_max)
1307610c32b2SHoratiu Vultur {
1308610c32b2SHoratiu Vultur 	const struct vcap_set *actionfield_set;
1309610c32b2SHoratiu Vultur 	int sw_count, idx;
1310610c32b2SHoratiu Vultur 	bool res;
1311610c32b2SHoratiu Vultur 
1312610c32b2SHoratiu Vultur 	sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
1313610c32b2SHoratiu Vultur 						       sw_max);
1314610c32b2SHoratiu Vultur 	if (sw_count < 0)
1315610c32b2SHoratiu Vultur 		return sw_count;
1316610c32b2SHoratiu Vultur 
1317610c32b2SHoratiu Vultur 	actionfield_set = vctrl->vcaps[vt].actionfield_set;
1318610c32b2SHoratiu Vultur 	for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
1319610c32b2SHoratiu Vultur 		if (actionfield_set[idx].sw_per_item != sw_count)
1320610c32b2SHoratiu Vultur 			continue;
1321610c32b2SHoratiu Vultur 
1322610c32b2SHoratiu Vultur 		res = vcap_verify_actionstream_actionset(vctrl, vt,
1323610c32b2SHoratiu Vultur 							 stream, idx);
1324610c32b2SHoratiu Vultur 		if (res)
1325610c32b2SHoratiu Vultur 			return idx;
1326610c32b2SHoratiu Vultur 	}
1327610c32b2SHoratiu Vultur 	return -EINVAL;
1328610c32b2SHoratiu Vultur }
1329610c32b2SHoratiu Vultur 
1330610c32b2SHoratiu Vultur /* Store action value in an element in a list for the client */
1331610c32b2SHoratiu Vultur static void vcap_rule_alloc_actionfield(struct vcap_rule_internal *ri,
1332610c32b2SHoratiu Vultur 					const struct vcap_field *actionfield,
1333610c32b2SHoratiu Vultur 					enum vcap_action_field action,
1334610c32b2SHoratiu Vultur 					u8 *value)
1335610c32b2SHoratiu Vultur {
1336610c32b2SHoratiu Vultur 	struct vcap_client_actionfield *field;
1337610c32b2SHoratiu Vultur 
1338610c32b2SHoratiu Vultur 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1339610c32b2SHoratiu Vultur 	if (!field)
1340610c32b2SHoratiu Vultur 		return;
1341610c32b2SHoratiu Vultur 	INIT_LIST_HEAD(&field->ctrl.list);
1342610c32b2SHoratiu Vultur 	field->ctrl.action = action;
1343610c32b2SHoratiu Vultur 	field->ctrl.type = actionfield->type;
1344610c32b2SHoratiu Vultur 	vcap_copy_to_client_actionfield(ri, field, value, actionfield->width);
1345610c32b2SHoratiu Vultur 	list_add_tail(&field->ctrl.list, &ri->data.actionfields);
1346610c32b2SHoratiu Vultur }
1347610c32b2SHoratiu Vultur 
1348610c32b2SHoratiu Vultur static int vcap_decode_actionset(struct vcap_rule_internal *ri)
1349610c32b2SHoratiu Vultur {
1350610c32b2SHoratiu Vultur 	struct vcap_control *vctrl = ri->vctrl;
1351610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1352610c32b2SHoratiu Vultur 	const struct vcap_field *actionfield;
1353610c32b2SHoratiu Vultur 	enum vcap_actionfield_set actionset;
1354610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
1355610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1356610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
1357610c32b2SHoratiu Vultur 	int idx, res, actfield_count;
1358610c32b2SHoratiu Vultur 	u32 *actstream;
1359610c32b2SHoratiu Vultur 	u8 value[16];
1360610c32b2SHoratiu Vultur 
1361610c32b2SHoratiu Vultur 	actstream = admin->cache.actionstream;
1362610c32b2SHoratiu Vultur 	res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
1363610c32b2SHoratiu Vultur 	if (res < 0) {
1364610c32b2SHoratiu Vultur 		pr_err("%s:%d: could not find valid actionset: %d\n",
1365610c32b2SHoratiu Vultur 		       __func__, __LINE__, res);
1366610c32b2SHoratiu Vultur 		return -EINVAL;
1367610c32b2SHoratiu Vultur 	}
1368610c32b2SHoratiu Vultur 	actionset = res;
1369610c32b2SHoratiu Vultur 	actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
1370610c32b2SHoratiu Vultur 	actionfield = vcap_actionfields(vctrl, vt, actionset);
1371610c32b2SHoratiu Vultur 	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1372610c32b2SHoratiu Vultur 	/* Start decoding the stream */
1373610c32b2SHoratiu Vultur 	for (idx = 0; idx < actfield_count; ++idx) {
1374610c32b2SHoratiu Vultur 		if (actionfield[idx].width <= 0)
1375610c32b2SHoratiu Vultur 			continue;
1376610c32b2SHoratiu Vultur 		/* Get the action */
1377610c32b2SHoratiu Vultur 		memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
1378610c32b2SHoratiu Vultur 		vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
1379610c32b2SHoratiu Vultur 			       actionfield[idx].offset);
1380610c32b2SHoratiu Vultur 		vcap_decode_field(actstream, &iter, actionfield[idx].width,
1381610c32b2SHoratiu Vultur 				  value);
1382610c32b2SHoratiu Vultur 		/* Skip if no bits are set */
1383610c32b2SHoratiu Vultur 		if (vcap_bitarray_zero(actionfield[idx].width, value))
1384610c32b2SHoratiu Vultur 			continue;
1385610c32b2SHoratiu Vultur 		vcap_rule_alloc_actionfield(ri, &actionfield[idx], idx, value);
1386610c32b2SHoratiu Vultur 		/* Later the action id will also be checked */
1387610c32b2SHoratiu Vultur 	}
1388610c32b2SHoratiu Vultur 	return vcap_set_rule_set_actionset((struct vcap_rule *)ri, actionset);
1389610c32b2SHoratiu Vultur }
1390610c32b2SHoratiu Vultur 
1391610c32b2SHoratiu Vultur static int vcap_decode_keyset(struct vcap_rule_internal *ri)
1392610c32b2SHoratiu Vultur {
1393610c32b2SHoratiu Vultur 	struct vcap_control *vctrl = ri->vctrl;
1394610c32b2SHoratiu Vultur 	struct vcap_stream_iter kiter, miter;
1395610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1396610c32b2SHoratiu Vultur 	enum vcap_keyfield_set keysets[10];
1397610c32b2SHoratiu Vultur 	const struct vcap_field *keyfield;
1398610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
1399610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1400610c32b2SHoratiu Vultur 	struct vcap_keyset_list matches;
1401610c32b2SHoratiu Vultur 	enum vcap_keyfield_set keyset;
1402610c32b2SHoratiu Vultur 	int idx, res, keyfield_count;
1403610c32b2SHoratiu Vultur 	u32 *maskstream;
1404610c32b2SHoratiu Vultur 	u32 *keystream;
1405610c32b2SHoratiu Vultur 	u8 value[16];
1406610c32b2SHoratiu Vultur 	u8 mask[16];
1407610c32b2SHoratiu Vultur 
1408610c32b2SHoratiu Vultur 	keystream = admin->cache.keystream;
1409610c32b2SHoratiu Vultur 	maskstream = admin->cache.maskstream;
1410610c32b2SHoratiu Vultur 	matches.keysets = keysets;
1411610c32b2SHoratiu Vultur 	matches.cnt = 0;
1412610c32b2SHoratiu Vultur 	matches.max = ARRAY_SIZE(keysets);
1413610c32b2SHoratiu Vultur 	res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream,
1414610c32b2SHoratiu Vultur 					  false, 0, &matches);
1415610c32b2SHoratiu Vultur 	if (res < 0) {
1416610c32b2SHoratiu Vultur 		pr_err("%s:%d: could not find valid keysets: %d\n",
1417610c32b2SHoratiu Vultur 		       __func__, __LINE__, res);
1418610c32b2SHoratiu Vultur 		return -EINVAL;
1419610c32b2SHoratiu Vultur 	}
1420610c32b2SHoratiu Vultur 	keyset = matches.keysets[0];
1421610c32b2SHoratiu Vultur 	keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
1422610c32b2SHoratiu Vultur 	keyfield = vcap_keyfields(vctrl, vt, keyset);
1423610c32b2SHoratiu Vultur 	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
1424610c32b2SHoratiu Vultur 	/* Start decoding the streams */
1425610c32b2SHoratiu Vultur 	for (idx = 0; idx < keyfield_count; ++idx) {
1426610c32b2SHoratiu Vultur 		if (keyfield[idx].width <= 0)
1427610c32b2SHoratiu Vultur 			continue;
1428610c32b2SHoratiu Vultur 		/* First get the mask */
1429610c32b2SHoratiu Vultur 		memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1430610c32b2SHoratiu Vultur 		vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
1431610c32b2SHoratiu Vultur 			       keyfield[idx].offset);
1432610c32b2SHoratiu Vultur 		vcap_decode_field(maskstream, &miter, keyfield[idx].width,
1433610c32b2SHoratiu Vultur 				  mask);
1434610c32b2SHoratiu Vultur 		/* Skip if no mask bits are set */
1435610c32b2SHoratiu Vultur 		if (vcap_bitarray_zero(keyfield[idx].width, mask))
1436610c32b2SHoratiu Vultur 			continue;
1437610c32b2SHoratiu Vultur 		/* Get the key */
1438610c32b2SHoratiu Vultur 		memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1439610c32b2SHoratiu Vultur 		vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
1440610c32b2SHoratiu Vultur 			       keyfield[idx].offset);
1441610c32b2SHoratiu Vultur 		vcap_decode_field(keystream, &kiter, keyfield[idx].width,
1442610c32b2SHoratiu Vultur 				  value);
1443610c32b2SHoratiu Vultur 		vcap_rule_alloc_keyfield(ri, &keyfield[idx], idx, value, mask);
1444610c32b2SHoratiu Vultur 	}
1445610c32b2SHoratiu Vultur 	return vcap_set_rule_set_keyset((struct vcap_rule *)ri, keyset);
1446610c32b2SHoratiu Vultur }
1447610c32b2SHoratiu Vultur 
1448610c32b2SHoratiu Vultur /* Read VCAP content into the VCAP cache */
1449610c32b2SHoratiu Vultur static int vcap_read_rule(struct vcap_rule_internal *ri)
1450610c32b2SHoratiu Vultur {
1451610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1452610c32b2SHoratiu Vultur 	int sw_idx, ent_idx = 0, act_idx = 0;
1453610c32b2SHoratiu Vultur 	u32 addr = ri->addr;
1454610c32b2SHoratiu Vultur 
1455610c32b2SHoratiu Vultur 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
1456610c32b2SHoratiu Vultur 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
1457610c32b2SHoratiu Vultur 		return -EINVAL;
1458610c32b2SHoratiu Vultur 	}
1459610c32b2SHoratiu Vultur 	vcap_erase_cache(ri);
1460610c32b2SHoratiu Vultur 	/* Use the values in the streams to read the VCAP cache */
1461610c32b2SHoratiu Vultur 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
1462610c32b2SHoratiu Vultur 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
1463610c32b2SHoratiu Vultur 				       VCAP_SEL_ALL, addr);
1464610c32b2SHoratiu Vultur 		ri->vctrl->ops->cache_read(ri->ndev, admin,
1465610c32b2SHoratiu Vultur 					   VCAP_SEL_ENTRY, ent_idx,
1466610c32b2SHoratiu Vultur 					   ri->keyset_sw_regs);
1467610c32b2SHoratiu Vultur 		ri->vctrl->ops->cache_read(ri->ndev, admin,
1468610c32b2SHoratiu Vultur 					   VCAP_SEL_ACTION, act_idx,
1469610c32b2SHoratiu Vultur 					   ri->actionset_sw_regs);
1470610c32b2SHoratiu Vultur 		if (sw_idx == 0)
1471610c32b2SHoratiu Vultur 			ri->vctrl->ops->cache_read(ri->ndev, admin,
1472610c32b2SHoratiu Vultur 						   VCAP_SEL_COUNTER,
1473610c32b2SHoratiu Vultur 						   ri->counter_id, 0);
1474610c32b2SHoratiu Vultur 		ent_idx += ri->keyset_sw_regs;
1475610c32b2SHoratiu Vultur 		act_idx += ri->actionset_sw_regs;
1476610c32b2SHoratiu Vultur 	}
1477610c32b2SHoratiu Vultur 	return 0;
1478610c32b2SHoratiu Vultur }
1479610c32b2SHoratiu Vultur 
14808e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */
14818e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri)
14828e10490bSSteen Hegelund {
14838e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
14848e10490bSSteen Hegelund 	int sw_idx, ent_idx = 0, act_idx = 0;
14858e10490bSSteen Hegelund 	u32 addr = ri->addr;
14868e10490bSSteen Hegelund 
14878e10490bSSteen Hegelund 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
14888e10490bSSteen Hegelund 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
14898e10490bSSteen Hegelund 		return -EINVAL;
14908e10490bSSteen Hegelund 	}
14918e10490bSSteen Hegelund 	/* Use the values in the streams to write the VCAP cache */
14928e10490bSSteen Hegelund 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
14938e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
14948e10490bSSteen Hegelund 					    VCAP_SEL_ENTRY, ent_idx,
14958e10490bSSteen Hegelund 					    ri->keyset_sw_regs);
14968e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
14978e10490bSSteen Hegelund 					    VCAP_SEL_ACTION, act_idx,
14988e10490bSSteen Hegelund 					    ri->actionset_sw_regs);
14998e10490bSSteen Hegelund 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
15008e10490bSSteen Hegelund 				       VCAP_SEL_ALL, addr);
15018e10490bSSteen Hegelund 		ent_idx += ri->keyset_sw_regs;
15028e10490bSSteen Hegelund 		act_idx += ri->actionset_sw_regs;
15038e10490bSSteen Hegelund 	}
15048e10490bSSteen Hegelund 	return 0;
15058e10490bSSteen Hegelund }
15068e10490bSSteen Hegelund 
1507f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri,
1508f13230a4SSteen Hegelund 			      struct vcap_counter *ctr)
1509f13230a4SSteen Hegelund {
1510f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1511f13230a4SSteen Hegelund 
1512f13230a4SSteen Hegelund 	admin->cache.counter = ctr->value;
1513f13230a4SSteen Hegelund 	admin->cache.sticky = ctr->sticky;
1514f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
1515f13230a4SSteen Hegelund 				    ri->counter_id, 0);
1516f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
1517f13230a4SSteen Hegelund 			       VCAP_SEL_COUNTER, ri->addr);
1518f13230a4SSteen Hegelund 	return 0;
1519f13230a4SSteen Hegelund }
1520f13230a4SSteen Hegelund 
15217de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */
15227de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
15237de1dcadSSteen Hegelund {
15247de1dcadSSteen Hegelund 	int lookup_first = admin->vinst * admin->lookups_per_instance;
15257de1dcadSSteen Hegelund 	int lookup_last = lookup_first + admin->lookups_per_instance;
15267de1dcadSSteen Hegelund 	int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE;
15277de1dcadSSteen Hegelund 	int cid = admin->first_cid;
15287de1dcadSSteen Hegelund 	int lookup;
15297de1dcadSSteen Hegelund 
15307de1dcadSSteen Hegelund 	for (lookup = lookup_first; lookup < lookup_last; ++lookup,
15317de1dcadSSteen Hegelund 	     cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE)
15327de1dcadSSteen Hegelund 		if (cur_cid >= cid && cur_cid < cid_next)
15337de1dcadSSteen Hegelund 			return lookup;
15347de1dcadSSteen Hegelund 	return 0;
15357de1dcadSSteen Hegelund }
15367de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup);
15377de1dcadSSteen Hegelund 
1538c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */
1539c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
1540c9da1ac1SSteen Hegelund {
1541c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1542c9da1ac1SSteen Hegelund 
15438e10490bSSteen Hegelund 	if (vcap_api_check(vctrl))
15448e10490bSSteen Hegelund 		return NULL;
15458e10490bSSteen Hegelund 
1546c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
1547c9da1ac1SSteen Hegelund 		if (cid >= admin->first_cid && cid <= admin->last_cid)
1548c9da1ac1SSteen Hegelund 			return admin;
1549c9da1ac1SSteen Hegelund 	}
1550c9da1ac1SSteen Hegelund 	return NULL;
1551c9da1ac1SSteen Hegelund }
1552c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin);
1553c9da1ac1SSteen Hegelund 
1554392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */
1555392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid)
1556392d0ab0SSteen Hegelund {
1557392d0ab0SSteen Hegelund 	struct vcap_admin *admin, *next_admin;
1558392d0ab0SSteen Hegelund 	int lookup, next_lookup;
1559392d0ab0SSteen Hegelund 
1560392d0ab0SSteen Hegelund 	/* The offset must be at least one lookup */
1561392d0ab0SSteen Hegelund 	if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
1562392d0ab0SSteen Hegelund 		return false;
1563392d0ab0SSteen Hegelund 
1564392d0ab0SSteen Hegelund 	if (vcap_api_check(vctrl))
1565392d0ab0SSteen Hegelund 		return false;
1566392d0ab0SSteen Hegelund 
1567392d0ab0SSteen Hegelund 	admin = vcap_find_admin(vctrl, cur_cid);
1568392d0ab0SSteen Hegelund 	if (!admin)
1569392d0ab0SSteen Hegelund 		return false;
1570392d0ab0SSteen Hegelund 
1571392d0ab0SSteen Hegelund 	/* If no VCAP contains the next chain, the next chain must be beyond
1572392d0ab0SSteen Hegelund 	 * the last chain in the current VCAP
1573392d0ab0SSteen Hegelund 	 */
1574392d0ab0SSteen Hegelund 	next_admin = vcap_find_admin(vctrl, next_cid);
1575392d0ab0SSteen Hegelund 	if (!next_admin)
1576392d0ab0SSteen Hegelund 		return next_cid > admin->last_cid;
1577392d0ab0SSteen Hegelund 
1578392d0ab0SSteen Hegelund 	lookup = vcap_chain_id_to_lookup(admin, cur_cid);
1579392d0ab0SSteen Hegelund 	next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid);
1580392d0ab0SSteen Hegelund 
1581392d0ab0SSteen Hegelund 	/* Next lookup must be the following lookup */
1582392d0ab0SSteen Hegelund 	if (admin == next_admin || admin->vtype == next_admin->vtype)
1583392d0ab0SSteen Hegelund 		return next_lookup == lookup + 1;
1584392d0ab0SSteen Hegelund 
1585392d0ab0SSteen Hegelund 	/* Must be the first lookup in the next VCAP instance */
1586392d0ab0SSteen Hegelund 	return next_lookup == 0;
1587392d0ab0SSteen Hegelund }
1588392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
1589392d0ab0SSteen Hegelund 
15908e10490bSSteen Hegelund /* Check if there is room for a new rule */
15918e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size)
15928e10490bSSteen Hegelund {
15938e10490bSSteen Hegelund 	if (admin->last_used_addr - size < admin->first_valid_addr) {
15948e10490bSSteen Hegelund 		pr_err("%s:%d: No room for rule size: %u, %u\n",
15958e10490bSSteen Hegelund 		       __func__, __LINE__, size, admin->first_valid_addr);
15968e10490bSSteen Hegelund 		return -ENOSPC;
15978e10490bSSteen Hegelund 	}
15988e10490bSSteen Hegelund 	return 0;
15998e10490bSSteen Hegelund }
16008e10490bSSteen Hegelund 
16018e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */
16028e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule)
16038e10490bSSteen Hegelund {
16048e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
16058e10490bSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
16068e10490bSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
16078e10490bSSteen Hegelund 	const struct vcap_field *fields;
16088e10490bSSteen Hegelund 	const struct vcap_set *kset;
16098e10490bSSteen Hegelund 	int ret = -EINVAL;
16108e10490bSSteen Hegelund 
16118e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, vt, keyset);
16128e10490bSSteen Hegelund 	if (!kset)
16138e10490bSSteen Hegelund 		return ret;
16148e10490bSSteen Hegelund 	if (kset->type_id == (u8)-1)  /* No type field is needed */
16158e10490bSSteen Hegelund 		return 0;
16168e10490bSSteen Hegelund 
16178e10490bSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
16188e10490bSSteen Hegelund 	if (!fields)
16198e10490bSSteen Hegelund 		return -EINVAL;
16208e10490bSSteen Hegelund 	if (fields[VCAP_KF_TYPE].width > 1) {
16218e10490bSSteen Hegelund 		ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE,
16228e10490bSSteen Hegelund 					    kset->type_id, 0xff);
16238e10490bSSteen Hegelund 	} else {
16248e10490bSSteen Hegelund 		if (kset->type_id)
16258e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
16268e10490bSSteen Hegelund 						    VCAP_BIT_1);
16278e10490bSSteen Hegelund 		else
16288e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
16298e10490bSSteen Hegelund 						    VCAP_BIT_0);
16308e10490bSSteen Hegelund 	}
16318e10490bSSteen Hegelund 	return 0;
16328e10490bSSteen Hegelund }
16338e10490bSSteen Hegelund 
1634abc4010dSSteen Hegelund /* Add a keyset to a keyset list */
1635abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
1636abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset)
1637abc4010dSSteen Hegelund {
1638abc4010dSSteen Hegelund 	int idx;
1639abc4010dSSteen Hegelund 
1640abc4010dSSteen Hegelund 	if (keysetlist->cnt < keysetlist->max) {
1641abc4010dSSteen Hegelund 		/* Avoid duplicates */
1642abc4010dSSteen Hegelund 		for (idx = 0; idx < keysetlist->cnt; ++idx)
1643abc4010dSSteen Hegelund 			if (keysetlist->keysets[idx] == keyset)
1644abc4010dSSteen Hegelund 				return keysetlist->cnt < keysetlist->max;
1645abc4010dSSteen Hegelund 		keysetlist->keysets[keysetlist->cnt++] = keyset;
1646abc4010dSSteen Hegelund 	}
1647abc4010dSSteen Hegelund 	return keysetlist->cnt < keysetlist->max;
1648abc4010dSSteen Hegelund }
1649abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add);
1650abc4010dSSteen Hegelund 
1651abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */
1652abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl,
1653abc4010dSSteen Hegelund 			     enum vcap_keyfield_set keyset)
1654abc4010dSSteen Hegelund {
1655abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_set_names[keyset];
1656abc4010dSSteen Hegelund }
1657abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name);
1658abc4010dSSteen Hegelund 
1659abc4010dSSteen Hegelund /* map key field id to a string with the key name */
1660abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl,
1661abc4010dSSteen Hegelund 			       enum vcap_key_field key)
1662abc4010dSSteen Hegelund {
1663abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_names[key];
1664abc4010dSSteen Hegelund }
1665abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name);
1666abc4010dSSteen Hegelund 
16673a792156SSteen Hegelund /* map actionset id to a string with the actionset name */
16683a792156SSteen Hegelund const char *vcap_actionset_name(struct vcap_control *vctrl,
16693a792156SSteen Hegelund 				enum vcap_actionfield_set actionset)
16703a792156SSteen Hegelund {
16713a792156SSteen Hegelund 	return vctrl->stats->actionfield_set_names[actionset];
16723a792156SSteen Hegelund }
16733a792156SSteen Hegelund 
1674242df4f7SSteen Hegelund /* map action field id to a string with the action name */
16753a792156SSteen Hegelund const char *vcap_actionfield_name(struct vcap_control *vctrl,
1676242df4f7SSteen Hegelund 				  enum vcap_action_field action)
1677242df4f7SSteen Hegelund {
1678242df4f7SSteen Hegelund 	return vctrl->stats->actionfield_names[action];
1679242df4f7SSteen Hegelund }
1680242df4f7SSteen Hegelund 
1681abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */
1682abc4010dSSteen Hegelund static const struct vcap_field *
1683abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl,
1684abc4010dSSteen Hegelund 			  enum vcap_type vtype,
1685abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset,
1686abc4010dSSteen Hegelund 			  enum vcap_key_field key)
1687abc4010dSSteen Hegelund {
1688abc4010dSSteen Hegelund 	const struct vcap_field *fields;
1689abc4010dSSteen Hegelund 	int idx, count;
1690abc4010dSSteen Hegelund 
1691abc4010dSSteen Hegelund 	fields = vcap_keyfields(vctrl, vtype, keyset);
1692abc4010dSSteen Hegelund 	if (!fields)
1693abc4010dSSteen Hegelund 		return NULL;
1694abc4010dSSteen Hegelund 
1695abc4010dSSteen Hegelund 	/* Iterate the keyfields of the keyset */
1696abc4010dSSteen Hegelund 	count = vcap_keyfield_count(vctrl, vtype, keyset);
1697abc4010dSSteen Hegelund 	for (idx = 0; idx < count; ++idx) {
1698abc4010dSSteen Hegelund 		if (fields[idx].width == 0)
1699abc4010dSSteen Hegelund 			continue;
1700abc4010dSSteen Hegelund 
1701abc4010dSSteen Hegelund 		if (key == idx)
1702abc4010dSSteen Hegelund 			return &fields[idx];
1703abc4010dSSteen Hegelund 	}
1704abc4010dSSteen Hegelund 
1705abc4010dSSteen Hegelund 	return NULL;
1706abc4010dSSteen Hegelund }
1707abc4010dSSteen Hegelund 
1708abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
1709465a38a2SSteen Hegelund static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri,
1710abc4010dSSteen Hegelund 				    struct vcap_keyset_list *matches)
1711abc4010dSSteen Hegelund {
1712abc4010dSSteen Hegelund 	const struct vcap_client_keyfield *ckf;
1713abc4010dSSteen Hegelund 	int keyset, found, keycount, map_size;
1714abc4010dSSteen Hegelund 	const struct vcap_field **map;
1715abc4010dSSteen Hegelund 	enum vcap_type vtype;
1716abc4010dSSteen Hegelund 
1717abc4010dSSteen Hegelund 	vtype = ri->admin->vtype;
1718abc4010dSSteen Hegelund 	map = ri->vctrl->vcaps[vtype].keyfield_set_map;
1719abc4010dSSteen Hegelund 	map_size = ri->vctrl->vcaps[vtype].keyfield_set_size;
1720abc4010dSSteen Hegelund 
1721abc4010dSSteen Hegelund 	/* Get a count of the keyfields we want to match */
1722abc4010dSSteen Hegelund 	keycount = 0;
1723abc4010dSSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1724abc4010dSSteen Hegelund 		++keycount;
1725abc4010dSSteen Hegelund 
1726abc4010dSSteen Hegelund 	matches->cnt = 0;
1727abc4010dSSteen Hegelund 	/* Iterate the keysets of the VCAP */
1728abc4010dSSteen Hegelund 	for (keyset = 0; keyset < map_size; ++keyset) {
1729abc4010dSSteen Hegelund 		if (!map[keyset])
1730abc4010dSSteen Hegelund 			continue;
1731abc4010dSSteen Hegelund 
1732abc4010dSSteen Hegelund 		/* Iterate the keys in the rule */
1733abc4010dSSteen Hegelund 		found = 0;
1734abc4010dSSteen Hegelund 		list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1735abc4010dSSteen Hegelund 			if (vcap_find_keyset_keyfield(ri->vctrl, vtype,
1736abc4010dSSteen Hegelund 						      keyset, ckf->ctrl.key))
1737abc4010dSSteen Hegelund 				++found;
1738abc4010dSSteen Hegelund 
1739abc4010dSSteen Hegelund 		/* Save the keyset if all keyfields were found */
1740abc4010dSSteen Hegelund 		if (found == keycount)
1741abc4010dSSteen Hegelund 			if (!vcap_keyset_list_add(matches, keyset))
1742abc4010dSSteen Hegelund 				/* bail out when the quota is filled */
1743abc4010dSSteen Hegelund 				break;
1744abc4010dSSteen Hegelund 	}
1745abc4010dSSteen Hegelund 
1746abc4010dSSteen Hegelund 	return matches->cnt > 0;
1747abc4010dSSteen Hegelund }
1748abc4010dSSteen Hegelund 
1749465a38a2SSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
1750465a38a2SSteen Hegelund bool vcap_rule_find_keysets(struct vcap_rule *rule,
1751465a38a2SSteen Hegelund 			    struct vcap_keyset_list *matches)
1752465a38a2SSteen Hegelund {
1753465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1754465a38a2SSteen Hegelund 
1755465a38a2SSteen Hegelund 	return _vcap_rule_find_keysets(ri, matches);
1756465a38a2SSteen Hegelund }
1757465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_find_keysets);
1758465a38a2SSteen Hegelund 
1759c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
1760c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
1761c9da1ac1SSteen Hegelund {
1762c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1763abc4010dSSteen Hegelund 	struct vcap_keyset_list matches = {};
17648e10490bSSteen Hegelund 	enum vcap_keyfield_set keysets[10];
17658e10490bSSteen Hegelund 	int ret;
1766c9da1ac1SSteen Hegelund 
17678e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
17688e10490bSSteen Hegelund 	if (ret)
17698e10490bSSteen Hegelund 		return ret;
1770c9da1ac1SSteen Hegelund 	if (!ri->admin) {
1771c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ADMIN;
1772c9da1ac1SSteen Hegelund 		return -EINVAL;
1773c9da1ac1SSteen Hegelund 	}
1774c9da1ac1SSteen Hegelund 	if (!ri->ndev) {
1775c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_NETDEV;
1776c9da1ac1SSteen Hegelund 		return -EINVAL;
1777c9da1ac1SSteen Hegelund 	}
1778abc4010dSSteen Hegelund 
1779abc4010dSSteen Hegelund 	matches.keysets = keysets;
1780abc4010dSSteen Hegelund 	matches.max = ARRAY_SIZE(keysets);
1781c9da1ac1SSteen Hegelund 	if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
1782abc4010dSSteen Hegelund 		/* Iterate over rule keyfields and select keysets that fits */
1783465a38a2SSteen Hegelund 		if (!_vcap_rule_find_keysets(ri, &matches)) {
1784c9da1ac1SSteen Hegelund 			ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
1785c9da1ac1SSteen Hegelund 			return -EINVAL;
1786c9da1ac1SSteen Hegelund 		}
1787abc4010dSSteen Hegelund 	} else {
17888e10490bSSteen Hegelund 		/* prepare for keyset validation */
17898e10490bSSteen Hegelund 		keysets[0] = ri->data.keyset;
1790abc4010dSSteen Hegelund 		matches.cnt = 1;
1791abc4010dSSteen Hegelund 	}
1792abc4010dSSteen Hegelund 
17938e10490bSSteen Hegelund 	/* Pick a keyset that is supported in the port lookups */
1794abc4010dSSteen Hegelund 	ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule,
1795abc4010dSSteen Hegelund 					      &matches, l3_proto);
17968e10490bSSteen Hegelund 	if (ret < 0) {
17978e10490bSSteen Hegelund 		pr_err("%s:%d: keyset validation failed: %d\n",
17988e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
17998e10490bSSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
18008e10490bSSteen Hegelund 		return ret;
18018e10490bSSteen Hegelund 	}
1802abc4010dSSteen Hegelund 	/* use the keyset that is supported in the port lookups */
1803abc4010dSSteen Hegelund 	ret = vcap_set_rule_set_keyset(rule, ret);
1804abc4010dSSteen Hegelund 	if (ret < 0) {
1805abc4010dSSteen Hegelund 		pr_err("%s:%d: keyset was not updated: %d\n",
1806abc4010dSSteen Hegelund 		       __func__, __LINE__, ret);
1807abc4010dSSteen Hegelund 		return ret;
1808abc4010dSSteen Hegelund 	}
1809c9da1ac1SSteen Hegelund 	if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
1810abc4010dSSteen Hegelund 		/* Later also actionsets will be matched against actions in
1811abc4010dSSteen Hegelund 		 * the rule, and the type will be set accordingly
1812abc4010dSSteen Hegelund 		 */
1813c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
1814c9da1ac1SSteen Hegelund 		return -EINVAL;
1815c9da1ac1SSteen Hegelund 	}
18168e10490bSSteen Hegelund 	vcap_add_type_keyfield(rule);
18178e10490bSSteen Hegelund 	/* Add default fields to this rule */
18188e10490bSSteen Hegelund 	ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
18198e10490bSSteen Hegelund 
18208e10490bSSteen Hegelund 	/* Rule size is the maximum of the entry and action subword count */
18218e10490bSSteen Hegelund 	ri->size = max(ri->keyset_sw, ri->actionset_sw);
18228e10490bSSteen Hegelund 
18238e10490bSSteen Hegelund 	/* Finally check if there is room for the rule in the VCAP */
18248e10490bSSteen Hegelund 	return vcap_rule_space(ri->admin, ri->size);
1825c9da1ac1SSteen Hegelund }
1826c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
1827c9da1ac1SSteen Hegelund 
1828990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key.
1829990e4839SSteen Hegelund  * I.e. Lowest numerical sort_key is first in list.
1830990e4839SSteen Hegelund  * In order to locate largest keys first in list we negate the key size with
1831990e4839SSteen Hegelund  * (max_size - size).
1832990e4839SSteen Hegelund  */
1833990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
1834990e4839SSteen Hegelund {
1835990e4839SSteen Hegelund 	return ((max_size - size) << 24) | (user << 16) | prio;
1836990e4839SSteen Hegelund }
1837990e4839SSteen Hegelund 
18388e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
18398e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
18408e10490bSSteen Hegelund {
18418e10490bSSteen Hegelund 	return ((addr - ri->size) /  ri->size) * ri->size;
18428e10490bSSteen Hegelund }
18438e10490bSSteen Hegelund 
1844c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
1845c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
1846c9da1ac1SSteen Hegelund {
1847c9da1ac1SSteen Hegelund 	if (ri->data.id != 0)
1848c9da1ac1SSteen Hegelund 		return ri->data.id;
1849c9da1ac1SSteen Hegelund 
1850c1d8e3fbSHoratiu Vultur 	for (u32 next_id = 1; next_id < ~0; ++next_id) {
1851c9da1ac1SSteen Hegelund 		if (!vcap_lookup_rule(ri->vctrl, next_id)) {
1852c9da1ac1SSteen Hegelund 			ri->data.id = next_id;
1853c9da1ac1SSteen Hegelund 			break;
1854c9da1ac1SSteen Hegelund 		}
1855c9da1ac1SSteen Hegelund 	}
1856c9da1ac1SSteen Hegelund 	return ri->data.id;
1857c9da1ac1SSteen Hegelund }
1858c9da1ac1SSteen Hegelund 
18598e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
18608e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
18618e10490bSSteen Hegelund {
1862990e4839SSteen Hegelund 	int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
1863990e4839SSteen Hegelund 	struct vcap_rule_internal *duprule, *iter, *elem = NULL;
18648e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1865990e4839SSteen Hegelund 	u32 addr;
18668e10490bSSteen Hegelund 
1867990e4839SSteen Hegelund 	ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
1868990e4839SSteen Hegelund 				     ri->data.priority);
1869990e4839SSteen Hegelund 
1870990e4839SSteen Hegelund 	/* Insert the new rule in the list of rule based on the sort key
1871990e4839SSteen Hegelund 	 * If the rule needs to be  inserted between existing rules then move
1872990e4839SSteen Hegelund 	 * these rules to make room for the new rule and update their start
1873990e4839SSteen Hegelund 	 * address.
1874990e4839SSteen Hegelund 	 */
1875990e4839SSteen Hegelund 	list_for_each_entry(iter, &admin->rules, list) {
1876990e4839SSteen Hegelund 		if (ri->sort_key < iter->sort_key) {
1877990e4839SSteen Hegelund 			elem = iter;
1878990e4839SSteen Hegelund 			break;
1879990e4839SSteen Hegelund 		}
1880990e4839SSteen Hegelund 	}
1881990e4839SSteen Hegelund 
1882990e4839SSteen Hegelund 	if (!elem) {
18838e10490bSSteen Hegelund 		ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
18848e10490bSSteen Hegelund 		admin->last_used_addr = ri->addr;
1885990e4839SSteen Hegelund 
18868e10490bSSteen Hegelund 		/* Add a shallow copy of the rule to the VCAP list */
18878e10490bSSteen Hegelund 		duprule = vcap_dup_rule(ri);
18888e10490bSSteen Hegelund 		if (IS_ERR(duprule))
18898e10490bSSteen Hegelund 			return PTR_ERR(duprule);
1890990e4839SSteen Hegelund 
18918e10490bSSteen Hegelund 		list_add_tail(&duprule->list, &admin->rules);
18928e10490bSSteen Hegelund 		return 0;
18938e10490bSSteen Hegelund 	}
18948e10490bSSteen Hegelund 
1895990e4839SSteen Hegelund 	/* Reuse the space of the current rule */
1896990e4839SSteen Hegelund 	addr = elem->addr + elem->size;
1897990e4839SSteen Hegelund 	ri->addr = vcap_next_rule_addr(addr, ri);
1898990e4839SSteen Hegelund 	addr = ri->addr;
1899990e4839SSteen Hegelund 
1900990e4839SSteen Hegelund 	/* Add a shallow copy of the rule to the VCAP list */
1901990e4839SSteen Hegelund 	duprule = vcap_dup_rule(ri);
1902990e4839SSteen Hegelund 	if (IS_ERR(duprule))
1903990e4839SSteen Hegelund 		return PTR_ERR(duprule);
1904990e4839SSteen Hegelund 
1905990e4839SSteen Hegelund 	/* Add before the current entry */
1906990e4839SSteen Hegelund 	list_add_tail(&duprule->list, &elem->list);
1907990e4839SSteen Hegelund 
1908990e4839SSteen Hegelund 	/* Update the current rule */
1909990e4839SSteen Hegelund 	elem->addr = vcap_next_rule_addr(addr, elem);
1910990e4839SSteen Hegelund 	addr = elem->addr;
1911990e4839SSteen Hegelund 
1912990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1913990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list) {
1914990e4839SSteen Hegelund 		elem->addr = vcap_next_rule_addr(addr, elem);
1915990e4839SSteen Hegelund 		addr = elem->addr;
1916990e4839SSteen Hegelund 	}
1917990e4839SSteen Hegelund 
1918990e4839SSteen Hegelund 	/* Update the move info */
1919990e4839SSteen Hegelund 	move->addr = admin->last_used_addr;
1920990e4839SSteen Hegelund 	move->count = ri->addr - addr;
1921990e4839SSteen Hegelund 	move->offset = admin->last_used_addr - addr;
1922990e4839SSteen Hegelund 	admin->last_used_addr = addr;
1923990e4839SSteen Hegelund 	return 0;
1924990e4839SSteen Hegelund }
1925990e4839SSteen Hegelund 
19268e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
19278e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
19288e10490bSSteen Hegelund {
19298e10490bSSteen Hegelund 	ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
19308e10490bSSteen Hegelund 			 move->offset, move->count);
19318e10490bSSteen Hegelund }
19328e10490bSSteen Hegelund 
1933c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
1934c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
1935c9da1ac1SSteen Hegelund {
19368e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
19378e10490bSSteen Hegelund 	struct vcap_rule_move move = {0};
193895fa7414SSteen Hegelund 	struct vcap_counter ctr = {0};
19398e10490bSSteen Hegelund 	int ret;
19408e10490bSSteen Hegelund 
19418e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
19428e10490bSSteen Hegelund 	if (ret)
19438e10490bSSteen Hegelund 		return ret;
19448e10490bSSteen Hegelund 	/* Insert the new rule in the list of vcap rules */
194571c9de99SSteen Hegelund 	mutex_lock(&ri->admin->lock);
19468e10490bSSteen Hegelund 	ret = vcap_insert_rule(ri, &move);
19478e10490bSSteen Hegelund 	if (ret < 0) {
19488e10490bSSteen Hegelund 		pr_err("%s:%d: could not insert rule in vcap list: %d\n",
19498e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
19508e10490bSSteen Hegelund 		goto out;
19518e10490bSSteen Hegelund 	}
19528e10490bSSteen Hegelund 	if (move.count > 0)
19538e10490bSSteen Hegelund 		vcap_move_rules(ri, &move);
19546573f71aSSteen Hegelund 	vcap_erase_cache(ri);
19558e10490bSSteen Hegelund 	ret = vcap_encode_rule(ri);
19568e10490bSSteen Hegelund 	if (ret) {
19578e10490bSSteen Hegelund 		pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
19588e10490bSSteen Hegelund 		goto out;
19598e10490bSSteen Hegelund 	}
19608e10490bSSteen Hegelund 
19618e10490bSSteen Hegelund 	ret = vcap_write_rule(ri);
196295fa7414SSteen Hegelund 	if (ret) {
19638e10490bSSteen Hegelund 		pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
196495fa7414SSteen Hegelund 		goto out;
196595fa7414SSteen Hegelund 	}
196695fa7414SSteen Hegelund 	/* Set the counter to zero */
196795fa7414SSteen Hegelund 	ret = vcap_write_counter(ri, &ctr);
19688e10490bSSteen Hegelund out:
196971c9de99SSteen Hegelund 	mutex_unlock(&ri->admin->lock);
19708e10490bSSteen Hegelund 	return ret;
1971c9da1ac1SSteen Hegelund }
1972c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
1973c9da1ac1SSteen Hegelund 
1974c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
1975c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
1976c9da1ac1SSteen Hegelund 				  struct net_device *ndev, int vcap_chain_id,
1977c9da1ac1SSteen Hegelund 				  enum vcap_user user, u16 priority,
1978c9da1ac1SSteen Hegelund 				  u32 id)
1979c9da1ac1SSteen Hegelund {
1980c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
1981c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1982990e4839SSteen Hegelund 	int err, maxsize;
1983c9da1ac1SSteen Hegelund 
1984990e4839SSteen Hegelund 	err = vcap_api_check(vctrl);
1985990e4839SSteen Hegelund 	if (err)
1986990e4839SSteen Hegelund 		return ERR_PTR(err);
1987c9da1ac1SSteen Hegelund 	if (!ndev)
1988c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENODEV);
1989c9da1ac1SSteen Hegelund 	/* Get the VCAP instance */
1990c9da1ac1SSteen Hegelund 	admin = vcap_find_admin(vctrl, vcap_chain_id);
1991c9da1ac1SSteen Hegelund 	if (!admin)
1992c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOENT);
19938e10490bSSteen Hegelund 	/* Sanity check that this VCAP is supported on this platform */
19948e10490bSSteen Hegelund 	if (vctrl->vcaps[admin->vtype].rows == 0)
19958e10490bSSteen Hegelund 		return ERR_PTR(-EINVAL);
19968e10490bSSteen Hegelund 	/* Check if a rule with this id already exists */
19978e10490bSSteen Hegelund 	if (vcap_lookup_rule(vctrl, id))
19988e10490bSSteen Hegelund 		return ERR_PTR(-EEXIST);
19998e10490bSSteen Hegelund 	/* Check if there is room for the rule in the block(s) of the VCAP */
20008e10490bSSteen Hegelund 	maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
20018e10490bSSteen Hegelund 	if (vcap_rule_space(admin, maxsize))
20028e10490bSSteen Hegelund 		return ERR_PTR(-ENOSPC);
2003c9da1ac1SSteen Hegelund 	/* Create a container for the rule and return it */
2004c9da1ac1SSteen Hegelund 	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
2005c9da1ac1SSteen Hegelund 	if (!ri)
2006c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOMEM);
2007c9da1ac1SSteen Hegelund 	ri->data.vcap_chain_id = vcap_chain_id;
2008c9da1ac1SSteen Hegelund 	ri->data.user = user;
2009c9da1ac1SSteen Hegelund 	ri->data.priority = priority;
2010c9da1ac1SSteen Hegelund 	ri->data.id = id;
2011c9da1ac1SSteen Hegelund 	ri->data.keyset = VCAP_KFS_NO_VALUE;
2012c9da1ac1SSteen Hegelund 	ri->data.actionset = VCAP_AFS_NO_VALUE;
2013c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->list);
2014c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.keyfields);
2015c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.actionfields);
2016c9da1ac1SSteen Hegelund 	ri->ndev = ndev;
2017c9da1ac1SSteen Hegelund 	ri->admin = admin; /* refer to the vcap instance */
2018c9da1ac1SSteen Hegelund 	ri->vctrl = vctrl; /* refer to the client */
2019c9da1ac1SSteen Hegelund 	if (vcap_set_rule_id(ri) == 0)
2020c9da1ac1SSteen Hegelund 		goto out_free;
2021c9da1ac1SSteen Hegelund 	return (struct vcap_rule *)ri;
2022c9da1ac1SSteen Hegelund 
2023c9da1ac1SSteen Hegelund out_free:
2024c9da1ac1SSteen Hegelund 	kfree(ri);
2025c9da1ac1SSteen Hegelund 	return ERR_PTR(-EINVAL);
2026c9da1ac1SSteen Hegelund }
2027c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
2028c9da1ac1SSteen Hegelund 
2029c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
2030c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
2031c9da1ac1SSteen Hegelund {
2032c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2033c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *caf, *next_caf;
2034c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
2035c9da1ac1SSteen Hegelund 
2036c9da1ac1SSteen Hegelund 	/* Deallocate the list of keys and actions */
2037c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
2038c9da1ac1SSteen Hegelund 		list_del(&ckf->ctrl.list);
2039c9da1ac1SSteen Hegelund 		kfree(ckf);
2040c9da1ac1SSteen Hegelund 	}
2041c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
2042c9da1ac1SSteen Hegelund 		list_del(&caf->ctrl.list);
2043c9da1ac1SSteen Hegelund 		kfree(caf);
2044c9da1ac1SSteen Hegelund 	}
2045c9da1ac1SSteen Hegelund 	/* Deallocate the rule */
2046c9da1ac1SSteen Hegelund 	kfree(rule);
2047c9da1ac1SSteen Hegelund }
2048c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
2049c9da1ac1SSteen Hegelund 
2050610c32b2SHoratiu Vultur struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
2051610c32b2SHoratiu Vultur {
2052610c32b2SHoratiu Vultur 	struct vcap_rule_internal *elem;
2053610c32b2SHoratiu Vultur 	struct vcap_rule_internal *ri;
2054610c32b2SHoratiu Vultur 	int err;
2055610c32b2SHoratiu Vultur 
2056610c32b2SHoratiu Vultur 	ri = NULL;
2057610c32b2SHoratiu Vultur 
2058610c32b2SHoratiu Vultur 	err = vcap_api_check(vctrl);
2059610c32b2SHoratiu Vultur 	if (err)
2060610c32b2SHoratiu Vultur 		return ERR_PTR(err);
2061610c32b2SHoratiu Vultur 	elem = vcap_lookup_rule(vctrl, id);
2062610c32b2SHoratiu Vultur 	if (!elem)
2063610c32b2SHoratiu Vultur 		return NULL;
2064610c32b2SHoratiu Vultur 	mutex_lock(&elem->admin->lock);
2065610c32b2SHoratiu Vultur 	ri = vcap_dup_rule(elem);
2066610c32b2SHoratiu Vultur 	if (IS_ERR(ri))
2067610c32b2SHoratiu Vultur 		goto unlock;
2068610c32b2SHoratiu Vultur 	err = vcap_read_rule(ri);
2069610c32b2SHoratiu Vultur 	if (err) {
2070610c32b2SHoratiu Vultur 		ri = ERR_PTR(err);
2071610c32b2SHoratiu Vultur 		goto unlock;
2072610c32b2SHoratiu Vultur 	}
2073610c32b2SHoratiu Vultur 	err = vcap_decode_keyset(ri);
2074610c32b2SHoratiu Vultur 	if (err) {
2075610c32b2SHoratiu Vultur 		ri = ERR_PTR(err);
2076610c32b2SHoratiu Vultur 		goto unlock;
2077610c32b2SHoratiu Vultur 	}
2078610c32b2SHoratiu Vultur 	err = vcap_decode_actionset(ri);
2079610c32b2SHoratiu Vultur 	if (err) {
2080610c32b2SHoratiu Vultur 		ri = ERR_PTR(err);
2081610c32b2SHoratiu Vultur 		goto unlock;
2082610c32b2SHoratiu Vultur 	}
2083610c32b2SHoratiu Vultur 
2084610c32b2SHoratiu Vultur unlock:
2085610c32b2SHoratiu Vultur 	mutex_unlock(&elem->admin->lock);
2086610c32b2SHoratiu Vultur 	return (struct vcap_rule *)ri;
2087610c32b2SHoratiu Vultur }
2088610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_get_rule);
2089610c32b2SHoratiu Vultur 
20902662b3f9SHoratiu Vultur /* Update existing rule */
20912662b3f9SHoratiu Vultur int vcap_mod_rule(struct vcap_rule *rule)
20922662b3f9SHoratiu Vultur {
20932662b3f9SHoratiu Vultur 	struct vcap_rule_internal *ri = to_intrule(rule);
20942662b3f9SHoratiu Vultur 	struct vcap_counter ctr;
20952662b3f9SHoratiu Vultur 	int err;
20962662b3f9SHoratiu Vultur 
20972662b3f9SHoratiu Vultur 	err = vcap_api_check(ri->vctrl);
20982662b3f9SHoratiu Vultur 	if (err)
20992662b3f9SHoratiu Vultur 		return err;
21002662b3f9SHoratiu Vultur 
21012662b3f9SHoratiu Vultur 	if (!vcap_lookup_rule(ri->vctrl, ri->data.id))
21022662b3f9SHoratiu Vultur 		return -ENOENT;
21032662b3f9SHoratiu Vultur 
21042662b3f9SHoratiu Vultur 	mutex_lock(&ri->admin->lock);
21052662b3f9SHoratiu Vultur 	/* Encode the bitstreams to the VCAP cache */
21062662b3f9SHoratiu Vultur 	vcap_erase_cache(ri);
21072662b3f9SHoratiu Vultur 	err = vcap_encode_rule(ri);
21082662b3f9SHoratiu Vultur 	if (err)
21092662b3f9SHoratiu Vultur 		goto out;
21102662b3f9SHoratiu Vultur 
21112662b3f9SHoratiu Vultur 	err = vcap_write_rule(ri);
21122662b3f9SHoratiu Vultur 	if (err)
21132662b3f9SHoratiu Vultur 		goto out;
21142662b3f9SHoratiu Vultur 
21152662b3f9SHoratiu Vultur 	memset(&ctr, 0, sizeof(ctr));
21162662b3f9SHoratiu Vultur 	err =  vcap_write_counter(ri, &ctr);
21172662b3f9SHoratiu Vultur 	if (err)
21182662b3f9SHoratiu Vultur 		goto out;
21192662b3f9SHoratiu Vultur 
21202662b3f9SHoratiu Vultur out:
21212662b3f9SHoratiu Vultur 	mutex_unlock(&ri->admin->lock);
21222662b3f9SHoratiu Vultur 	return err;
21232662b3f9SHoratiu Vultur }
21242662b3f9SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_mod_rule);
21252662b3f9SHoratiu Vultur 
2126990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */
2127990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
2128990e4839SSteen Hegelund {
2129990e4839SSteen Hegelund 	return (el->addr + offset) % el->size;
2130990e4839SSteen Hegelund }
2131990e4839SSteen Hegelund 
2132990e4839SSteen Hegelund /* Update the rule address with an offset */
2133990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
2134990e4839SSteen Hegelund {
2135990e4839SSteen Hegelund 	el->addr += offset;
2136990e4839SSteen Hegelund }
2137990e4839SSteen Hegelund 
2138990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */
2139990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
2140990e4839SSteen Hegelund {
2141990e4839SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
2142990e4839SSteen Hegelund 	struct vcap_rule_internal *elem;
2143990e4839SSteen Hegelund 	struct vcap_rule_move move;
2144990e4839SSteen Hegelund 	int gap = 0, offset = 0;
2145990e4839SSteen Hegelund 
2146990e4839SSteen Hegelund 	/* If the first rule is deleted: Move other rules to the top */
2147990e4839SSteen Hegelund 	if (list_is_first(&ri->list, &admin->rules))
2148990e4839SSteen Hegelund 		offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
2149990e4839SSteen Hegelund 
2150990e4839SSteen Hegelund 	/* Locate gaps between odd size rules and adjust the move */
2151990e4839SSteen Hegelund 	elem = ri;
2152990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
2153990e4839SSteen Hegelund 		gap += vcap_valid_rule_move(elem, ri->size);
2154990e4839SSteen Hegelund 
2155990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
2156990e4839SSteen Hegelund 	elem = ri;
2157990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
2158990e4839SSteen Hegelund 		vcap_adjust_rule_addr(elem, ri->size + gap + offset);
2159990e4839SSteen Hegelund 
2160990e4839SSteen Hegelund 	/* Update the move info */
2161990e4839SSteen Hegelund 	move.addr = admin->last_used_addr;
2162990e4839SSteen Hegelund 	move.count = ri->addr - admin->last_used_addr - gap;
2163990e4839SSteen Hegelund 	move.offset = -(ri->size + gap + offset);
2164990e4839SSteen Hegelund 
2165990e4839SSteen Hegelund 	/* Do the actual move operation */
2166990e4839SSteen Hegelund 	vcap_move_rules(ri, &move);
2167990e4839SSteen Hegelund 
2168990e4839SSteen Hegelund 	return gap + offset;
2169990e4839SSteen Hegelund }
2170990e4839SSteen Hegelund 
2171c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
2172c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
2173c9da1ac1SSteen Hegelund {
2174c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri, *elem;
2175c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
2176990e4839SSteen Hegelund 	int gap = 0, err;
2177c9da1ac1SSteen Hegelund 
2178c9da1ac1SSteen Hegelund 	/* This will later also handle rule moving */
2179c9da1ac1SSteen Hegelund 	if (!ndev)
2180c9da1ac1SSteen Hegelund 		return -ENODEV;
21818e10490bSSteen Hegelund 	err = vcap_api_check(vctrl);
21828e10490bSSteen Hegelund 	if (err)
21838e10490bSSteen Hegelund 		return err;
2184c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
2185c9da1ac1SSteen Hegelund 	ri = vcap_lookup_rule(vctrl, id);
2186c9da1ac1SSteen Hegelund 	if (!ri)
2187c9da1ac1SSteen Hegelund 		return -EINVAL;
2188c9da1ac1SSteen Hegelund 	admin = ri->admin;
21898e10490bSSteen Hegelund 
2190990e4839SSteen Hegelund 	if (ri->addr > admin->last_used_addr)
2191990e4839SSteen Hegelund 		gap = vcap_fill_rule_gap(ri);
2192990e4839SSteen Hegelund 
2193990e4839SSteen Hegelund 	/* Delete the rule from the list of rules and the cache */
219471c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
2195990e4839SSteen Hegelund 	list_del(&ri->list);
2196990e4839SSteen Hegelund 	vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
2197990e4839SSteen Hegelund 	kfree(ri);
219871c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
2199990e4839SSteen Hegelund 
2200277e9179SSteen Hegelund 	/* Update the last used address, set to default when no rules */
2201c9da1ac1SSteen Hegelund 	if (list_empty(&admin->rules)) {
2202277e9179SSteen Hegelund 		admin->last_used_addr = admin->last_valid_addr + 1;
2203c9da1ac1SSteen Hegelund 	} else {
2204990e4839SSteen Hegelund 		elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
2205990e4839SSteen Hegelund 				       list);
2206c9da1ac1SSteen Hegelund 		admin->last_used_addr = elem->addr;
2207c9da1ac1SSteen Hegelund 	}
2208c9da1ac1SSteen Hegelund 	return 0;
2209c9da1ac1SSteen Hegelund }
2210c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
2211c9da1ac1SSteen Hegelund 
22128e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
22138e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
22148e10490bSSteen Hegelund {
221567456717SSteen Hegelund 	struct vcap_enabled_port *eport, *next_eport;
22168e10490bSSteen Hegelund 	struct vcap_rule_internal *ri, *next_ri;
22178e10490bSSteen Hegelund 	int ret = vcap_api_check(vctrl);
22188e10490bSSteen Hegelund 
22198e10490bSSteen Hegelund 	if (ret)
22208e10490bSSteen Hegelund 		return ret;
222171c9de99SSteen Hegelund 
222271c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
22238e10490bSSteen Hegelund 	list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
22248e10490bSSteen Hegelund 		vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
22258e10490bSSteen Hegelund 		list_del(&ri->list);
22268e10490bSSteen Hegelund 		kfree(ri);
22278e10490bSSteen Hegelund 	}
22288e10490bSSteen Hegelund 	admin->last_used_addr = admin->last_valid_addr;
222967456717SSteen Hegelund 
223067456717SSteen Hegelund 	/* Remove list of enabled ports */
223167456717SSteen Hegelund 	list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
223267456717SSteen Hegelund 		list_del(&eport->list);
223367456717SSteen Hegelund 		kfree(eport);
223467456717SSteen Hegelund 	}
223571c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
223667456717SSteen Hegelund 
22378e10490bSSteen Hegelund 	return 0;
22388e10490bSSteen Hegelund }
22398e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
22408e10490bSSteen Hegelund 
2241465a38a2SSteen Hegelund /* Find a client key field in a rule */
2242465a38a2SSteen Hegelund static struct vcap_client_keyfield *
2243465a38a2SSteen Hegelund vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key)
2244465a38a2SSteen Hegelund {
2245465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2246465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
2247465a38a2SSteen Hegelund 
2248465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2249465a38a2SSteen Hegelund 		if (ckf->ctrl.key == key)
2250465a38a2SSteen Hegelund 			return ckf;
2251465a38a2SSteen Hegelund 	return NULL;
2252465a38a2SSteen Hegelund }
2253465a38a2SSteen Hegelund 
225446be056eSSteen Hegelund /* Find information on a key field in a rule */
225546be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
225646be056eSSteen Hegelund 					      enum vcap_key_field key)
225746be056eSSteen Hegelund {
22588e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
225946be056eSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
226046be056eSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
226146be056eSSteen Hegelund 	const struct vcap_field *fields;
226246be056eSSteen Hegelund 
226346be056eSSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
226446be056eSSteen Hegelund 		return NULL;
226546be056eSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
226646be056eSSteen Hegelund 	if (!fields)
226746be056eSSteen Hegelund 		return NULL;
226846be056eSSteen Hegelund 	return &fields[key];
226946be056eSSteen Hegelund }
227046be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
227146be056eSSteen Hegelund 
2272242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */
2273242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule,
2274242df4f7SSteen Hegelund 				 enum vcap_key_field key)
2275242df4f7SSteen Hegelund {
2276242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2277242df4f7SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
2278242df4f7SSteen Hegelund 
2279242df4f7SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2280242df4f7SSteen Hegelund 		if (ckf->ctrl.key == key)
2281242df4f7SSteen Hegelund 			return false;
2282242df4f7SSteen Hegelund 	return true;
2283242df4f7SSteen Hegelund }
2284242df4f7SSteen Hegelund 
2285242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */
2286242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule,
2287242df4f7SSteen Hegelund 				       enum vcap_key_field key)
2288242df4f7SSteen Hegelund {
2289242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2290242df4f7SSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
2291242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
2292242df4f7SSteen Hegelund 	const struct vcap_field *fields;
2293242df4f7SSteen Hegelund 
2294242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no keyset yet */
2295242df4f7SSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
2296242df4f7SSteen Hegelund 		return true;
2297242df4f7SSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
2298242df4f7SSteen Hegelund 	if (!fields)
2299242df4f7SSteen Hegelund 		return false;
2300242df4f7SSteen Hegelund 	/* if there is a width there is a way */
2301242df4f7SSteen Hegelund 	return fields[key].width > 0;
2302242df4f7SSteen Hegelund }
2303242df4f7SSteen Hegelund 
2304c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
2305c9da1ac1SSteen Hegelund 			     enum vcap_key_field key,
2306c9da1ac1SSteen Hegelund 			     enum vcap_field_type ftype,
2307c9da1ac1SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
2308c9da1ac1SSteen Hegelund {
2309242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2310c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *field;
2311c9da1ac1SSteen Hegelund 
2312242df4f7SSteen Hegelund 	if (!vcap_keyfield_unique(rule, key)) {
2313242df4f7SSteen Hegelund 		pr_warn("%s:%d: keyfield %s is already in the rule\n",
2314242df4f7SSteen Hegelund 			__func__, __LINE__,
2315242df4f7SSteen Hegelund 			vcap_keyfield_name(ri->vctrl, key));
2316242df4f7SSteen Hegelund 		return -EINVAL;
2317242df4f7SSteen Hegelund 	}
2318242df4f7SSteen Hegelund 
2319242df4f7SSteen Hegelund 	if (!vcap_keyfield_match_keyset(rule, key)) {
2320242df4f7SSteen Hegelund 		pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n",
2321242df4f7SSteen Hegelund 		       __func__, __LINE__,
2322242df4f7SSteen Hegelund 		       vcap_keyfield_name(ri->vctrl, key));
2323242df4f7SSteen Hegelund 		return -EINVAL;
2324242df4f7SSteen Hegelund 	}
2325242df4f7SSteen Hegelund 
2326c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
2327c9da1ac1SSteen Hegelund 	if (!field)
2328c9da1ac1SSteen Hegelund 		return -ENOMEM;
2329*33e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
2330c9da1ac1SSteen Hegelund 	field->ctrl.key = key;
2331c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
2332c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->keyfields);
2333c9da1ac1SSteen Hegelund 	return 0;
2334c9da1ac1SSteen Hegelund }
2335c9da1ac1SSteen Hegelund 
233646be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
233746be056eSSteen Hegelund {
233846be056eSSteen Hegelund 	switch (val) {
233946be056eSSteen Hegelund 	case VCAP_BIT_0:
234046be056eSSteen Hegelund 		u1->value = 0;
234146be056eSSteen Hegelund 		u1->mask = 1;
234246be056eSSteen Hegelund 		break;
234346be056eSSteen Hegelund 	case VCAP_BIT_1:
234446be056eSSteen Hegelund 		u1->value = 1;
234546be056eSSteen Hegelund 		u1->mask = 1;
234646be056eSSteen Hegelund 		break;
234746be056eSSteen Hegelund 	case VCAP_BIT_ANY:
234846be056eSSteen Hegelund 		u1->value = 0;
234946be056eSSteen Hegelund 		u1->mask = 0;
235046be056eSSteen Hegelund 		break;
235146be056eSSteen Hegelund 	}
235246be056eSSteen Hegelund }
235346be056eSSteen Hegelund 
235446be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
235546be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
235646be056eSSteen Hegelund 			  enum vcap_bit val)
235746be056eSSteen Hegelund {
235846be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
235946be056eSSteen Hegelund 
236046be056eSSteen Hegelund 	vcap_rule_set_key_bitsize(&data.u1, val);
236146be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
236246be056eSSteen Hegelund }
236346be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
236446be056eSSteen Hegelund 
236546be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
236646be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
236746be056eSSteen Hegelund 			  u32 value, u32 mask)
236846be056eSSteen Hegelund {
236946be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
237046be056eSSteen Hegelund 
237146be056eSSteen Hegelund 	data.u32.value = value;
237246be056eSSteen Hegelund 	data.u32.mask = mask;
237346be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
237446be056eSSteen Hegelund }
237546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
237646be056eSSteen Hegelund 
2377c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
2378c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
2379c9da1ac1SSteen Hegelund 			  struct vcap_u48_key *fieldval)
2380c9da1ac1SSteen Hegelund {
2381c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield_data data;
2382c9da1ac1SSteen Hegelund 
2383c9da1ac1SSteen Hegelund 	memcpy(&data.u48, fieldval, sizeof(data.u48));
2384c9da1ac1SSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
2385c9da1ac1SSteen Hegelund }
2386c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
2387c9da1ac1SSteen Hegelund 
238846be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
238946be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
239046be056eSSteen Hegelund 			  struct vcap_u72_key *fieldval)
239146be056eSSteen Hegelund {
239246be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
239346be056eSSteen Hegelund 
239446be056eSSteen Hegelund 	memcpy(&data.u72, fieldval, sizeof(data.u72));
239546be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
239646be056eSSteen Hegelund }
239746be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
239846be056eSSteen Hegelund 
2399d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
2400d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
2401d6c2964dSSteen Hegelund 			   struct vcap_u128_key *fieldval)
2402d6c2964dSSteen Hegelund {
2403d6c2964dSSteen Hegelund 	struct vcap_client_keyfield_data data;
2404d6c2964dSSteen Hegelund 
2405d6c2964dSSteen Hegelund 	memcpy(&data.u128, fieldval, sizeof(data.u128));
2406d6c2964dSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
2407d6c2964dSSteen Hegelund }
2408d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
2409d6c2964dSSteen Hegelund 
24106009b61fSHoratiu Vultur int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
24116009b61fSHoratiu Vultur 			  u32 *value, u32 *mask)
24126009b61fSHoratiu Vultur {
24136009b61fSHoratiu Vultur 	struct vcap_client_keyfield *ckf;
24146009b61fSHoratiu Vultur 
24156009b61fSHoratiu Vultur 	ckf = vcap_find_keyfield(rule, key);
24166009b61fSHoratiu Vultur 	if (!ckf)
24176009b61fSHoratiu Vultur 		return -ENOENT;
24186009b61fSHoratiu Vultur 
24196009b61fSHoratiu Vultur 	*value = ckf->data.u32.value;
24206009b61fSHoratiu Vultur 	*mask = ckf->data.u32.mask;
24216009b61fSHoratiu Vultur 
24226009b61fSHoratiu Vultur 	return 0;
24236009b61fSHoratiu Vultur }
24246009b61fSHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_rule_get_key_u32);
24256009b61fSHoratiu Vultur 
2426465a38a2SSteen Hegelund /* Find a client action field in a rule */
2427465a38a2SSteen Hegelund static struct vcap_client_actionfield *
2428465a38a2SSteen Hegelund vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act)
2429465a38a2SSteen Hegelund {
2430465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule;
2431465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
2432465a38a2SSteen Hegelund 
2433465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2434465a38a2SSteen Hegelund 		if (caf->ctrl.action == act)
2435465a38a2SSteen Hegelund 			return caf;
2436465a38a2SSteen Hegelund 	return NULL;
2437465a38a2SSteen Hegelund }
2438465a38a2SSteen Hegelund 
2439242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */
2440242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule,
2441242df4f7SSteen Hegelund 				    enum vcap_action_field act)
2442242df4f7SSteen Hegelund {
2443242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2444242df4f7SSteen Hegelund 	const struct vcap_client_actionfield *caf;
2445242df4f7SSteen Hegelund 
2446242df4f7SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2447242df4f7SSteen Hegelund 		if (caf->ctrl.action == act)
2448242df4f7SSteen Hegelund 			return false;
2449242df4f7SSteen Hegelund 	return true;
2450242df4f7SSteen Hegelund }
2451242df4f7SSteen Hegelund 
2452242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */
2453242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule,
2454242df4f7SSteen Hegelund 					     enum vcap_action_field action)
2455242df4f7SSteen Hegelund {
2456242df4f7SSteen Hegelund 	enum vcap_actionfield_set actionset = rule->actionset;
2457242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2458242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
2459242df4f7SSteen Hegelund 	const struct vcap_field *fields;
2460242df4f7SSteen Hegelund 
2461242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no actionset yet */
2462242df4f7SSteen Hegelund 	if (actionset == VCAP_AFS_NO_VALUE)
2463242df4f7SSteen Hegelund 		return true;
2464242df4f7SSteen Hegelund 	fields = vcap_actionfields(ri->vctrl, vt, actionset);
2465242df4f7SSteen Hegelund 	if (!fields)
2466242df4f7SSteen Hegelund 		return false;
2467242df4f7SSteen Hegelund 	/* if there is a width there is a way */
2468242df4f7SSteen Hegelund 	return fields[action].width > 0;
2469242df4f7SSteen Hegelund }
2470242df4f7SSteen Hegelund 
2471c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
2472c9da1ac1SSteen Hegelund 				enum vcap_action_field action,
2473c9da1ac1SSteen Hegelund 				enum vcap_field_type ftype,
2474c9da1ac1SSteen Hegelund 				struct vcap_client_actionfield_data *data)
2475c9da1ac1SSteen Hegelund {
2476242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2477c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *field;
2478c9da1ac1SSteen Hegelund 
2479242df4f7SSteen Hegelund 	if (!vcap_actionfield_unique(rule, action)) {
2480242df4f7SSteen Hegelund 		pr_warn("%s:%d: actionfield %s is already in the rule\n",
2481242df4f7SSteen Hegelund 			__func__, __LINE__,
2482242df4f7SSteen Hegelund 			vcap_actionfield_name(ri->vctrl, action));
2483242df4f7SSteen Hegelund 		return -EINVAL;
2484242df4f7SSteen Hegelund 	}
2485242df4f7SSteen Hegelund 
2486242df4f7SSteen Hegelund 	if (!vcap_actionfield_match_actionset(rule, action)) {
2487242df4f7SSteen Hegelund 		pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n",
2488242df4f7SSteen Hegelund 		       __func__, __LINE__,
2489242df4f7SSteen Hegelund 		       vcap_actionfield_name(ri->vctrl, action));
2490242df4f7SSteen Hegelund 		return -EINVAL;
2491242df4f7SSteen Hegelund 	}
2492242df4f7SSteen Hegelund 
2493c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
2494c9da1ac1SSteen Hegelund 	if (!field)
2495c9da1ac1SSteen Hegelund 		return -ENOMEM;
2496*33e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
2497c9da1ac1SSteen Hegelund 	field->ctrl.action = action;
2498c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
2499c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->actionfields);
2500c9da1ac1SSteen Hegelund 	return 0;
2501c9da1ac1SSteen Hegelund }
2502c9da1ac1SSteen Hegelund 
2503c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
2504c9da1ac1SSteen Hegelund 					 enum vcap_bit val)
2505c9da1ac1SSteen Hegelund {
2506c9da1ac1SSteen Hegelund 	switch (val) {
2507c9da1ac1SSteen Hegelund 	case VCAP_BIT_0:
2508c9da1ac1SSteen Hegelund 		u1->value = 0;
2509c9da1ac1SSteen Hegelund 		break;
2510c9da1ac1SSteen Hegelund 	case VCAP_BIT_1:
2511c9da1ac1SSteen Hegelund 		u1->value = 1;
2512c9da1ac1SSteen Hegelund 		break;
2513c9da1ac1SSteen Hegelund 	case VCAP_BIT_ANY:
2514c9da1ac1SSteen Hegelund 		u1->value = 0;
2515c9da1ac1SSteen Hegelund 		break;
2516c9da1ac1SSteen Hegelund 	}
2517c9da1ac1SSteen Hegelund }
2518c9da1ac1SSteen Hegelund 
2519c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
2520c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
2521c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
2522c9da1ac1SSteen Hegelund 			     enum vcap_bit val)
2523c9da1ac1SSteen Hegelund {
2524c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
2525c9da1ac1SSteen Hegelund 
2526c9da1ac1SSteen Hegelund 	vcap_rule_set_action_bitsize(&data.u1, val);
2527c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
2528c9da1ac1SSteen Hegelund }
2529c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
2530c9da1ac1SSteen Hegelund 
2531c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
2532c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
2533c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
2534c9da1ac1SSteen Hegelund 			     u32 value)
2535c9da1ac1SSteen Hegelund {
2536c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
2537c9da1ac1SSteen Hegelund 
2538c9da1ac1SSteen Hegelund 	data.u32.value = value;
2539c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
2540c9da1ac1SSteen Hegelund }
2541c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
2542c9da1ac1SSteen Hegelund 
2543f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri,
2544f13230a4SSteen Hegelund 			     struct vcap_counter *ctr)
2545f13230a4SSteen Hegelund {
2546f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
2547f13230a4SSteen Hegelund 
2548f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
2549f13230a4SSteen Hegelund 			       ri->addr);
2550f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
2551f13230a4SSteen Hegelund 				   ri->counter_id, 0);
2552f13230a4SSteen Hegelund 	ctr->value = admin->cache.counter;
2553f13230a4SSteen Hegelund 	ctr->sticky = admin->cache.sticky;
2554f13230a4SSteen Hegelund 	return 0;
2555f13230a4SSteen Hegelund }
2556f13230a4SSteen Hegelund 
2557c9da1ac1SSteen Hegelund /* Copy to host byte order */
2558c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
2559c9da1ac1SSteen Hegelund {
2560c9da1ac1SSteen Hegelund 	int idx;
2561c9da1ac1SSteen Hegelund 
2562c9da1ac1SSteen Hegelund 	for (idx = 0; idx < count; ++idx, ++dst)
2563c9da1ac1SSteen Hegelund 		*dst = src[count - idx - 1];
2564c9da1ac1SSteen Hegelund }
2565c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
2566c9da1ac1SSteen Hegelund 
2567c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */
2568c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
2569c9da1ac1SSteen Hegelund {
2570c9da1ac1SSteen Hegelund 	switch (vrule->exterr) {
2571c9da1ac1SSteen Hegelund 	case VCAP_ERR_NONE:
2572c9da1ac1SSteen Hegelund 		break;
2573c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ADMIN:
2574c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2575c9da1ac1SSteen Hegelund 				   "Missing VCAP instance");
2576c9da1ac1SSteen Hegelund 		break;
2577c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_NETDEV:
2578c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2579c9da1ac1SSteen Hegelund 				   "Missing network interface");
2580c9da1ac1SSteen Hegelund 		break;
2581c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_KEYSET_MATCH:
2582c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2583c9da1ac1SSteen Hegelund 				   "No keyset matched the filter keys");
2584c9da1ac1SSteen Hegelund 		break;
2585c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ACTIONSET_MATCH:
2586c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2587c9da1ac1SSteen Hegelund 				   "No actionset matched the filter actions");
2588c9da1ac1SSteen Hegelund 		break;
2589c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_PORT_KEYSET_MATCH:
2590c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2591c9da1ac1SSteen Hegelund 				   "No port keyset matched the filter keys");
2592c9da1ac1SSteen Hegelund 		break;
2593c9da1ac1SSteen Hegelund 	}
2594c9da1ac1SSteen Hegelund }
2595c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
259667d63751SSteen Hegelund 
259767456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */
259867456717SSteen Hegelund static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev,
259967456717SSteen Hegelund 			    unsigned long cookie)
260067456717SSteen Hegelund {
260167456717SSteen Hegelund 	struct vcap_enabled_port *eport;
260267456717SSteen Hegelund 
260367456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list)
260467456717SSteen Hegelund 		if (eport->cookie == cookie || eport->ndev == ndev)
260567456717SSteen Hegelund 			return true;
260667456717SSteen Hegelund 
260767456717SSteen Hegelund 	return false;
260867456717SSteen Hegelund }
260967456717SSteen Hegelund 
261067456717SSteen Hegelund /* Enable this port for this VCAP instance */
261167456717SSteen Hegelund static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,
261267456717SSteen Hegelund 		       unsigned long cookie)
261367456717SSteen Hegelund {
261467456717SSteen Hegelund 	struct vcap_enabled_port *eport;
261567456717SSteen Hegelund 
261667456717SSteen Hegelund 	eport = kzalloc(sizeof(*eport), GFP_KERNEL);
261767456717SSteen Hegelund 	if (!eport)
261867456717SSteen Hegelund 		return -ENOMEM;
261967456717SSteen Hegelund 
262067456717SSteen Hegelund 	eport->ndev = ndev;
262167456717SSteen Hegelund 	eport->cookie = cookie;
262267456717SSteen Hegelund 	list_add_tail(&eport->list, &admin->enabled);
262367456717SSteen Hegelund 
262467456717SSteen Hegelund 	return 0;
262567456717SSteen Hegelund }
262667456717SSteen Hegelund 
262767456717SSteen Hegelund /* Disable this port for this VCAP instance */
262867456717SSteen Hegelund static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev,
262967456717SSteen Hegelund 			unsigned long cookie)
263067456717SSteen Hegelund {
263167456717SSteen Hegelund 	struct vcap_enabled_port *eport;
263267456717SSteen Hegelund 
263367456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list) {
263467456717SSteen Hegelund 		if (eport->cookie == cookie && eport->ndev == ndev) {
263567456717SSteen Hegelund 			list_del(&eport->list);
263667456717SSteen Hegelund 			kfree(eport);
263767456717SSteen Hegelund 			return 0;
263867456717SSteen Hegelund 		}
263967456717SSteen Hegelund 	}
264067456717SSteen Hegelund 
264167456717SSteen Hegelund 	return -ENOENT;
264267456717SSteen Hegelund }
264367456717SSteen Hegelund 
264467456717SSteen Hegelund /* Find the VCAP instance that enabled the port using a specific filter */
264567456717SSteen Hegelund static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl,
264667456717SSteen Hegelund 						    unsigned long cookie)
264767456717SSteen Hegelund {
264867456717SSteen Hegelund 	struct vcap_enabled_port *eport;
264967456717SSteen Hegelund 	struct vcap_admin *admin;
265067456717SSteen Hegelund 
265167456717SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
265267456717SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list)
265367456717SSteen Hegelund 			if (eport->cookie == cookie)
265467456717SSteen Hegelund 				return admin;
265567456717SSteen Hegelund 
265667456717SSteen Hegelund 	return NULL;
265767456717SSteen Hegelund }
265867456717SSteen Hegelund 
265967456717SSteen Hegelund /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
266067456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
266167456717SSteen Hegelund 			int chain_id, unsigned long cookie, bool enable)
266267456717SSteen Hegelund {
266367456717SSteen Hegelund 	struct vcap_admin *admin;
266467456717SSteen Hegelund 	int err;
266567456717SSteen Hegelund 
266667456717SSteen Hegelund 	err = vcap_api_check(vctrl);
266767456717SSteen Hegelund 	if (err)
266867456717SSteen Hegelund 		return err;
266967456717SSteen Hegelund 
267067456717SSteen Hegelund 	if (!ndev)
267167456717SSteen Hegelund 		return -ENODEV;
267267456717SSteen Hegelund 
267367456717SSteen Hegelund 	if (chain_id)
267467456717SSteen Hegelund 		admin = vcap_find_admin(vctrl, chain_id);
267567456717SSteen Hegelund 	else
267667456717SSteen Hegelund 		admin = vcap_find_admin_by_cookie(vctrl, cookie);
267767456717SSteen Hegelund 	if (!admin)
267867456717SSteen Hegelund 		return -ENOENT;
267967456717SSteen Hegelund 
268067456717SSteen Hegelund 	/* first instance and first chain */
268167456717SSteen Hegelund 	if (admin->vinst || chain_id > admin->first_cid)
268267456717SSteen Hegelund 		return -EFAULT;
268367456717SSteen Hegelund 
268467456717SSteen Hegelund 	if (chain_id) {
268567456717SSteen Hegelund 		if (vcap_is_enabled(admin, ndev, cookie))
268667456717SSteen Hegelund 			return -EADDRINUSE;
268771c9de99SSteen Hegelund 		mutex_lock(&admin->lock);
268867456717SSteen Hegelund 		vcap_enable(admin, ndev, cookie);
268967456717SSteen Hegelund 	} else {
269071c9de99SSteen Hegelund 		mutex_lock(&admin->lock);
269167456717SSteen Hegelund 		vcap_disable(admin, ndev, cookie);
269267456717SSteen Hegelund 	}
269371c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
269467456717SSteen Hegelund 
269567456717SSteen Hegelund 	return 0;
269667456717SSteen Hegelund }
269767456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups);
269867456717SSteen Hegelund 
2699f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */
2700f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
2701f13230a4SSteen Hegelund {
2702f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2703f13230a4SSteen Hegelund 
2704f13230a4SSteen Hegelund 	ri->counter_id = counter_id;
2705f13230a4SSteen Hegelund }
2706f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
2707f13230a4SSteen Hegelund 
270840e7fe18SSteen Hegelund /* Provide all rules via a callback interface */
270940e7fe18SSteen Hegelund int vcap_rule_iter(struct vcap_control *vctrl,
271040e7fe18SSteen Hegelund 		   int (*callback)(void *, struct vcap_rule *), void *arg)
271140e7fe18SSteen Hegelund {
271240e7fe18SSteen Hegelund 	struct vcap_rule_internal *ri;
271340e7fe18SSteen Hegelund 	struct vcap_admin *admin;
271440e7fe18SSteen Hegelund 	int ret;
271540e7fe18SSteen Hegelund 
271640e7fe18SSteen Hegelund 	ret = vcap_api_check(vctrl);
271740e7fe18SSteen Hegelund 	if (ret)
271840e7fe18SSteen Hegelund 		return ret;
271940e7fe18SSteen Hegelund 
272040e7fe18SSteen Hegelund 	/* Iterate all rules in each VCAP instance */
272140e7fe18SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
272240e7fe18SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
272340e7fe18SSteen Hegelund 			ret = callback(arg, &ri->data);
272440e7fe18SSteen Hegelund 			if (ret)
272540e7fe18SSteen Hegelund 				return ret;
272640e7fe18SSteen Hegelund 		}
272740e7fe18SSteen Hegelund 	}
272840e7fe18SSteen Hegelund 
272940e7fe18SSteen Hegelund 	return 0;
273040e7fe18SSteen Hegelund }
273140e7fe18SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_iter);
273240e7fe18SSteen Hegelund 
2733f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
2734f13230a4SSteen Hegelund {
2735f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2736f13230a4SSteen Hegelund 	int err;
2737f13230a4SSteen Hegelund 
2738f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2739f13230a4SSteen Hegelund 	if (err)
2740f13230a4SSteen Hegelund 		return err;
2741f13230a4SSteen Hegelund 	if (!ctr) {
2742f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
2743f13230a4SSteen Hegelund 		return -EINVAL;
2744f13230a4SSteen Hegelund 	}
2745f13230a4SSteen Hegelund 	return vcap_write_counter(ri, ctr);
2746f13230a4SSteen Hegelund }
2747f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
2748f13230a4SSteen Hegelund 
2749f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
2750f13230a4SSteen Hegelund {
2751f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2752f13230a4SSteen Hegelund 	int err;
2753f13230a4SSteen Hegelund 
2754f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2755f13230a4SSteen Hegelund 	if (err)
2756f13230a4SSteen Hegelund 		return err;
2757f13230a4SSteen Hegelund 	if (!ctr) {
2758f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
2759f13230a4SSteen Hegelund 		return -EINVAL;
2760f13230a4SSteen Hegelund 	}
2761f13230a4SSteen Hegelund 	return vcap_read_counter(ri, ctr);
2762f13230a4SSteen Hegelund }
2763f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
2764f13230a4SSteen Hegelund 
2765465a38a2SSteen Hegelund static int vcap_rule_mod_key(struct vcap_rule *rule,
2766465a38a2SSteen Hegelund 			     enum vcap_key_field key,
2767465a38a2SSteen Hegelund 			     enum vcap_field_type ftype,
2768465a38a2SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
2769465a38a2SSteen Hegelund {
2770465a38a2SSteen Hegelund 	struct vcap_client_keyfield *field;
2771465a38a2SSteen Hegelund 
2772465a38a2SSteen Hegelund 	field = vcap_find_keyfield(rule, key);
2773465a38a2SSteen Hegelund 	if (!field)
2774465a38a2SSteen Hegelund 		return vcap_rule_add_key(rule, key, ftype, data);
2775*33e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
2776465a38a2SSteen Hegelund 	return 0;
2777465a38a2SSteen Hegelund }
2778465a38a2SSteen Hegelund 
2779465a38a2SSteen Hegelund /* Modify a 32 bit key field with value and mask in the rule */
2780465a38a2SSteen Hegelund int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
2781465a38a2SSteen Hegelund 			  u32 value, u32 mask)
2782465a38a2SSteen Hegelund {
2783465a38a2SSteen Hegelund 	struct vcap_client_keyfield_data data;
2784465a38a2SSteen Hegelund 
2785465a38a2SSteen Hegelund 	data.u32.value = value;
2786465a38a2SSteen Hegelund 	data.u32.mask = mask;
2787465a38a2SSteen Hegelund 	return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data);
2788465a38a2SSteen Hegelund }
2789465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32);
2790465a38a2SSteen Hegelund 
2791465a38a2SSteen Hegelund static int vcap_rule_mod_action(struct vcap_rule *rule,
2792465a38a2SSteen Hegelund 				enum vcap_action_field action,
2793465a38a2SSteen Hegelund 				enum vcap_field_type ftype,
2794465a38a2SSteen Hegelund 				struct vcap_client_actionfield_data *data)
2795465a38a2SSteen Hegelund {
2796465a38a2SSteen Hegelund 	struct vcap_client_actionfield *field;
2797465a38a2SSteen Hegelund 
2798465a38a2SSteen Hegelund 	field = vcap_find_actionfield(rule, action);
2799465a38a2SSteen Hegelund 	if (!field)
2800465a38a2SSteen Hegelund 		return vcap_rule_add_action(rule, action, ftype, data);
2801*33e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
2802465a38a2SSteen Hegelund 	return 0;
2803465a38a2SSteen Hegelund }
2804465a38a2SSteen Hegelund 
2805465a38a2SSteen Hegelund /* Modify a 32 bit action field with value in the rule */
2806465a38a2SSteen Hegelund int vcap_rule_mod_action_u32(struct vcap_rule *rule,
2807465a38a2SSteen Hegelund 			     enum vcap_action_field action,
2808465a38a2SSteen Hegelund 			     u32 value)
2809465a38a2SSteen Hegelund {
2810465a38a2SSteen Hegelund 	struct vcap_client_actionfield_data data;
2811465a38a2SSteen Hegelund 
2812465a38a2SSteen Hegelund 	data.u32.value = value;
2813465a38a2SSteen Hegelund 	return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data);
2814465a38a2SSteen Hegelund }
2815465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32);
2816465a38a2SSteen Hegelund 
2817465a38a2SSteen Hegelund /* Drop keys in a keylist and any keys that are not supported by the keyset */
2818465a38a2SSteen Hegelund int vcap_filter_rule_keys(struct vcap_rule *rule,
2819465a38a2SSteen Hegelund 			  enum vcap_key_field keylist[], int length,
2820465a38a2SSteen Hegelund 			  bool drop_unsupported)
2821465a38a2SSteen Hegelund {
2822465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2823465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
2824465a38a2SSteen Hegelund 	const struct vcap_field *fields;
2825465a38a2SSteen Hegelund 	enum vcap_key_field key;
2826465a38a2SSteen Hegelund 	int err = 0;
2827465a38a2SSteen Hegelund 	int idx;
2828465a38a2SSteen Hegelund 
2829465a38a2SSteen Hegelund 	if (length > 0) {
2830465a38a2SSteen Hegelund 		err = -EEXIST;
2831465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
2832465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
2833465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
2834465a38a2SSteen Hegelund 			for (idx = 0; idx < length; ++idx)
2835465a38a2SSteen Hegelund 				if (key == keylist[idx]) {
2836465a38a2SSteen Hegelund 					list_del(&ckf->ctrl.list);
2837465a38a2SSteen Hegelund 					kfree(ckf);
2838465a38a2SSteen Hegelund 					idx++;
2839465a38a2SSteen Hegelund 					err = 0;
2840465a38a2SSteen Hegelund 				}
2841465a38a2SSteen Hegelund 		}
2842465a38a2SSteen Hegelund 	}
2843465a38a2SSteen Hegelund 	if (drop_unsupported) {
2844465a38a2SSteen Hegelund 		err = -EEXIST;
2845465a38a2SSteen Hegelund 		fields = vcap_keyfields(ri->vctrl, ri->admin->vtype,
2846465a38a2SSteen Hegelund 					rule->keyset);
2847465a38a2SSteen Hegelund 		if (!fields)
2848465a38a2SSteen Hegelund 			return err;
2849465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
2850465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
2851465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
2852465a38a2SSteen Hegelund 			if (fields[key].width == 0) {
2853465a38a2SSteen Hegelund 				list_del(&ckf->ctrl.list);
2854465a38a2SSteen Hegelund 				kfree(ckf);
2855465a38a2SSteen Hegelund 				err = 0;
2856465a38a2SSteen Hegelund 			}
2857465a38a2SSteen Hegelund 		}
2858465a38a2SSteen Hegelund 	}
2859465a38a2SSteen Hegelund 	return err;
2860465a38a2SSteen Hegelund }
2861465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_filter_rule_keys);
2862465a38a2SSteen Hegelund 
2863465a38a2SSteen Hegelund /* Make a full copy of an existing rule with a new rule id */
2864465a38a2SSteen Hegelund struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
2865465a38a2SSteen Hegelund {
2866465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(erule);
2867465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
2868465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
2869465a38a2SSteen Hegelund 	struct vcap_rule *rule;
2870465a38a2SSteen Hegelund 	int err;
2871465a38a2SSteen Hegelund 
2872465a38a2SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2873465a38a2SSteen Hegelund 	if (err)
2874465a38a2SSteen Hegelund 		return ERR_PTR(err);
2875465a38a2SSteen Hegelund 
2876465a38a2SSteen Hegelund 	rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id,
2877465a38a2SSteen Hegelund 			       ri->data.user, ri->data.priority, 0);
2878465a38a2SSteen Hegelund 	if (IS_ERR(rule))
2879465a38a2SSteen Hegelund 		return rule;
2880465a38a2SSteen Hegelund 
2881465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
2882465a38a2SSteen Hegelund 		/* Add a key duplicate in the new rule */
2883465a38a2SSteen Hegelund 		err = vcap_rule_add_key(rule,
2884465a38a2SSteen Hegelund 					ckf->ctrl.key,
2885465a38a2SSteen Hegelund 					ckf->ctrl.type,
2886465a38a2SSteen Hegelund 					&ckf->data);
2887465a38a2SSteen Hegelund 		if (err)
2888465a38a2SSteen Hegelund 			goto err;
2889465a38a2SSteen Hegelund 	}
2890465a38a2SSteen Hegelund 
2891465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
2892465a38a2SSteen Hegelund 		/* Add a action duplicate in the new rule */
2893465a38a2SSteen Hegelund 		err = vcap_rule_add_action(rule,
2894465a38a2SSteen Hegelund 					   caf->ctrl.action,
2895465a38a2SSteen Hegelund 					   caf->ctrl.type,
2896465a38a2SSteen Hegelund 					   &caf->data);
2897465a38a2SSteen Hegelund 		if (err)
2898465a38a2SSteen Hegelund 			goto err;
2899465a38a2SSteen Hegelund 	}
2900465a38a2SSteen Hegelund 	return rule;
2901465a38a2SSteen Hegelund err:
2902465a38a2SSteen Hegelund 	vcap_free_rule(rule);
2903465a38a2SSteen Hegelund 	return ERR_PTR(err);
2904465a38a2SSteen Hegelund }
2905465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_copy_rule);
2906465a38a2SSteen Hegelund 
290767d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
290867d63751SSteen Hegelund #include "vcap_api_kunit.c"
290967d63751SSteen Hegelund #endif
2910