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 
172*610c32b2SHoratiu Vultur static bool vcap_bitarray_zero(int width, u8 *value)
173*610c32b2SHoratiu Vultur {
174*610c32b2SHoratiu Vultur 	int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
175*610c32b2SHoratiu Vultur 	u8 total = 0, bmask = 0xff;
176*610c32b2SHoratiu Vultur 	int rwidth = width;
177*610c32b2SHoratiu Vultur 	int idx;
178*610c32b2SHoratiu Vultur 
179*610c32b2SHoratiu Vultur 	for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
180*610c32b2SHoratiu Vultur 		if (rwidth && rwidth < BITS_PER_BYTE)
181*610c32b2SHoratiu Vultur 			bmask = (1 << rwidth) - 1;
182*610c32b2SHoratiu Vultur 		total += value[idx] & bmask;
183*610c32b2SHoratiu Vultur 	}
184*610c32b2SHoratiu Vultur 	return total == 0;
185*610c32b2SHoratiu Vultur }
186*610c32b2SHoratiu Vultur 
187*610c32b2SHoratiu Vultur static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
188*610c32b2SHoratiu Vultur {
189*610c32b2SHoratiu Vultur 	u32 mask = BIT(itr->reg_bitpos);
190*610c32b2SHoratiu Vultur 	u32 *p = &stream[itr->reg_idx];
191*610c32b2SHoratiu Vultur 
192*610c32b2SHoratiu Vultur 	return !!(*p & mask);
193*610c32b2SHoratiu Vultur }
194*610c32b2SHoratiu Vultur 
195*610c32b2SHoratiu Vultur static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
196*610c32b2SHoratiu Vultur 			      int width, u8 *value)
197*610c32b2SHoratiu Vultur {
198*610c32b2SHoratiu Vultur 	int idx;
199*610c32b2SHoratiu Vultur 
200*610c32b2SHoratiu Vultur 	/* Loop over the field value bits and get the field bits and
201*610c32b2SHoratiu Vultur 	 * set them in the output value byte array
202*610c32b2SHoratiu Vultur 	 */
203*610c32b2SHoratiu Vultur 	for (idx = 0; idx < width; idx++) {
204*610c32b2SHoratiu Vultur 		u8 bidx = idx & 0x7;
205*610c32b2SHoratiu Vultur 
206*610c32b2SHoratiu Vultur 		/* Decode one field value bit */
207*610c32b2SHoratiu Vultur 		if (vcap_get_bit(stream, itr))
208*610c32b2SHoratiu Vultur 			*value |= 1 << bidx;
209*610c32b2SHoratiu Vultur 		vcap_iter_next(itr);
210*610c32b2SHoratiu Vultur 		if (bidx == 7)
211*610c32b2SHoratiu Vultur 			value++;
212*610c32b2SHoratiu Vultur 	}
213*610c32b2SHoratiu Vultur }
214*610c32b2SHoratiu Vultur 
215*610c32b2SHoratiu Vultur /* Verify that the type id in the stream matches the type id of the keyset */
216*610c32b2SHoratiu Vultur static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
217*610c32b2SHoratiu Vultur 					 enum vcap_type vt,
218*610c32b2SHoratiu Vultur 					 u32 *keystream,
219*610c32b2SHoratiu Vultur 					 u32 *mskstream,
220*610c32b2SHoratiu Vultur 					 enum vcap_keyfield_set keyset)
221*610c32b2SHoratiu Vultur {
222*610c32b2SHoratiu Vultur 	const struct vcap_info *vcap = &vctrl->vcaps[vt];
223*610c32b2SHoratiu Vultur 	const struct vcap_field *typefld;
224*610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
225*610c32b2SHoratiu Vultur 	const struct vcap_field *fields;
226*610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
227*610c32b2SHoratiu Vultur 	const struct vcap_set *info;
228*610c32b2SHoratiu Vultur 	u32 value = 0;
229*610c32b2SHoratiu Vultur 	u32 mask = 0;
230*610c32b2SHoratiu Vultur 
231*610c32b2SHoratiu Vultur 	if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
232*610c32b2SHoratiu Vultur 		return false;
233*610c32b2SHoratiu Vultur 
234*610c32b2SHoratiu Vultur 	info = vcap_keyfieldset(vctrl, vt, keyset);
235*610c32b2SHoratiu Vultur 	/* Check that the keyset is valid */
236*610c32b2SHoratiu Vultur 	if (!info)
237*610c32b2SHoratiu Vultur 		return false;
238*610c32b2SHoratiu Vultur 
239*610c32b2SHoratiu Vultur 	/* a type_id of value -1 means that there is no type field */
240*610c32b2SHoratiu Vultur 	if (info->type_id == (u8)-1)
241*610c32b2SHoratiu Vultur 		return true;
242*610c32b2SHoratiu Vultur 
243*610c32b2SHoratiu Vultur 	/* Get a valid typegroup for the specific keyset */
244*610c32b2SHoratiu Vultur 	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
245*610c32b2SHoratiu Vultur 	if (!tgt)
246*610c32b2SHoratiu Vultur 		return false;
247*610c32b2SHoratiu Vultur 
248*610c32b2SHoratiu Vultur 	fields = vcap_keyfields(vctrl, vt, keyset);
249*610c32b2SHoratiu Vultur 	if (!fields)
250*610c32b2SHoratiu Vultur 		return false;
251*610c32b2SHoratiu Vultur 
252*610c32b2SHoratiu Vultur 	typefld = &fields[VCAP_KF_TYPE];
253*610c32b2SHoratiu Vultur 	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
254*610c32b2SHoratiu Vultur 	vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
255*610c32b2SHoratiu Vultur 	/* no type info if there are no mask bits */
256*610c32b2SHoratiu Vultur 	if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
257*610c32b2SHoratiu Vultur 		return false;
258*610c32b2SHoratiu Vultur 
259*610c32b2SHoratiu Vultur 	/* Get the value of the type field in the stream and compare to the
260*610c32b2SHoratiu Vultur 	 * one define in the vcap keyset
261*610c32b2SHoratiu Vultur 	 */
262*610c32b2SHoratiu Vultur 	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
263*610c32b2SHoratiu Vultur 	vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
264*610c32b2SHoratiu Vultur 
265*610c32b2SHoratiu Vultur 	return (value & mask) == (info->type_id & mask);
266*610c32b2SHoratiu Vultur }
267*610c32b2SHoratiu Vultur 
268*610c32b2SHoratiu Vultur /* Verify that the typegroup bits have the correct values */
269*610c32b2SHoratiu Vultur static int vcap_verify_typegroups(u32 *stream, int sw_width,
270*610c32b2SHoratiu Vultur 				  const struct vcap_typegroup *tgt, bool mask,
271*610c32b2SHoratiu Vultur 				  int sw_max)
272*610c32b2SHoratiu Vultur {
273*610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
274*610c32b2SHoratiu Vultur 	int sw_cnt, idx;
275*610c32b2SHoratiu Vultur 
276*610c32b2SHoratiu Vultur 	vcap_iter_set(&iter, sw_width, tgt, 0);
277*610c32b2SHoratiu Vultur 	sw_cnt = 0;
278*610c32b2SHoratiu Vultur 	while (iter.tg->width) {
279*610c32b2SHoratiu Vultur 		u32 value = 0;
280*610c32b2SHoratiu Vultur 		u32 tg_value = iter.tg->value;
281*610c32b2SHoratiu Vultur 
282*610c32b2SHoratiu Vultur 		if (mask)
283*610c32b2SHoratiu Vultur 			tg_value = (1 << iter.tg->width) - 1;
284*610c32b2SHoratiu Vultur 		/* Set position to current typegroup bit */
285*610c32b2SHoratiu Vultur 		iter.offset = iter.tg->offset;
286*610c32b2SHoratiu Vultur 		vcap_iter_update(&iter);
287*610c32b2SHoratiu Vultur 		for (idx = 0; idx < iter.tg->width; idx++) {
288*610c32b2SHoratiu Vultur 			/* Decode one typegroup bit */
289*610c32b2SHoratiu Vultur 			if (vcap_get_bit(stream, &iter))
290*610c32b2SHoratiu Vultur 				value |= 1 << idx;
291*610c32b2SHoratiu Vultur 			iter.offset++;
292*610c32b2SHoratiu Vultur 			vcap_iter_update(&iter);
293*610c32b2SHoratiu Vultur 		}
294*610c32b2SHoratiu Vultur 		if (value != tg_value)
295*610c32b2SHoratiu Vultur 			return -EINVAL;
296*610c32b2SHoratiu Vultur 		iter.tg++; /* next typegroup */
297*610c32b2SHoratiu Vultur 		sw_cnt++;
298*610c32b2SHoratiu Vultur 		/* Stop checking more typegroups */
299*610c32b2SHoratiu Vultur 		if (sw_max && sw_cnt >= sw_max)
300*610c32b2SHoratiu Vultur 			break;
301*610c32b2SHoratiu Vultur 	}
302*610c32b2SHoratiu Vultur 	return 0;
303*610c32b2SHoratiu Vultur }
304*610c32b2SHoratiu Vultur 
305*610c32b2SHoratiu Vultur /* Find the subword width of the key typegroup that matches the stream data */
306*610c32b2SHoratiu Vultur static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
307*610c32b2SHoratiu Vultur 					    enum vcap_type vt, u32 *stream,
308*610c32b2SHoratiu Vultur 					    bool mask, int sw_max)
309*610c32b2SHoratiu Vultur {
310*610c32b2SHoratiu Vultur 	const struct vcap_typegroup **tgt;
311*610c32b2SHoratiu Vultur 	int sw_idx, res;
312*610c32b2SHoratiu Vultur 
313*610c32b2SHoratiu Vultur 	tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
314*610c32b2SHoratiu Vultur 	/* Try the longest subword match first */
315*610c32b2SHoratiu Vultur 	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
316*610c32b2SHoratiu Vultur 		if (!tgt[sw_idx])
317*610c32b2SHoratiu Vultur 			continue;
318*610c32b2SHoratiu Vultur 
319*610c32b2SHoratiu Vultur 		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
320*610c32b2SHoratiu Vultur 					     tgt[sw_idx], mask, sw_max);
321*610c32b2SHoratiu Vultur 		if (res == 0)
322*610c32b2SHoratiu Vultur 			return sw_idx;
323*610c32b2SHoratiu Vultur 	}
324*610c32b2SHoratiu Vultur 	return -EINVAL;
325*610c32b2SHoratiu Vultur }
326*610c32b2SHoratiu Vultur 
327*610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, keyset and type id
328*610c32b2SHoratiu Vultur  * are in sync and correct, return the list of matchin keysets
329*610c32b2SHoratiu Vultur  */
330*610c32b2SHoratiu Vultur int
331*610c32b2SHoratiu Vultur vcap_find_keystream_keysets(struct vcap_control *vctrl,
332*610c32b2SHoratiu Vultur 			    enum vcap_type vt,
333*610c32b2SHoratiu Vultur 			    u32 *keystream,
334*610c32b2SHoratiu Vultur 			    u32 *mskstream,
335*610c32b2SHoratiu Vultur 			    bool mask, int sw_max,
336*610c32b2SHoratiu Vultur 			    struct vcap_keyset_list *kslist)
337*610c32b2SHoratiu Vultur {
338*610c32b2SHoratiu Vultur 	const struct vcap_set *keyfield_set;
339*610c32b2SHoratiu Vultur 	int sw_count, idx;
340*610c32b2SHoratiu Vultur 
341*610c32b2SHoratiu Vultur 	sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
342*610c32b2SHoratiu Vultur 						    sw_max);
343*610c32b2SHoratiu Vultur 	if (sw_count < 0)
344*610c32b2SHoratiu Vultur 		return sw_count;
345*610c32b2SHoratiu Vultur 
346*610c32b2SHoratiu Vultur 	keyfield_set = vctrl->vcaps[vt].keyfield_set;
347*610c32b2SHoratiu Vultur 	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
348*610c32b2SHoratiu Vultur 		if (keyfield_set[idx].sw_per_item != sw_count)
349*610c32b2SHoratiu Vultur 			continue;
350*610c32b2SHoratiu Vultur 
351*610c32b2SHoratiu Vultur 		if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
352*610c32b2SHoratiu Vultur 						 mskstream, idx))
353*610c32b2SHoratiu Vultur 			vcap_keyset_list_add(kslist, idx);
354*610c32b2SHoratiu Vultur 	}
355*610c32b2SHoratiu Vultur 	if (kslist->cnt > 0)
356*610c32b2SHoratiu Vultur 		return 0;
357*610c32b2SHoratiu Vultur 	return -EINVAL;
358*610c32b2SHoratiu Vultur }
359*610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_find_keystream_keysets);
360*610c32b2SHoratiu Vultur 
361*610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there are any rule keysets
362*610c32b2SHoratiu Vultur  * here
363*610c32b2SHoratiu Vultur  */
364*610c32b2SHoratiu Vultur int vcap_addr_keysets(struct vcap_control *vctrl,
365*610c32b2SHoratiu Vultur 		      struct net_device *ndev,
366*610c32b2SHoratiu Vultur 		      struct vcap_admin *admin,
367*610c32b2SHoratiu Vultur 		      int addr,
368*610c32b2SHoratiu Vultur 		      struct vcap_keyset_list *kslist)
369*610c32b2SHoratiu Vultur {
370*610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
371*610c32b2SHoratiu Vultur 	int keyset_sw_regs, idx;
372*610c32b2SHoratiu Vultur 	u32 key = 0, mask = 0;
373*610c32b2SHoratiu Vultur 
374*610c32b2SHoratiu Vultur 	/* Read the cache at the specified address */
375*610c32b2SHoratiu Vultur 	keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
376*610c32b2SHoratiu Vultur 	vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
377*610c32b2SHoratiu Vultur 	vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
378*610c32b2SHoratiu Vultur 			       keyset_sw_regs);
379*610c32b2SHoratiu Vultur 	/* Skip uninitialized key/mask entries */
380*610c32b2SHoratiu Vultur 	for (idx = 0; idx < keyset_sw_regs; ++idx) {
381*610c32b2SHoratiu Vultur 		key |= ~admin->cache.keystream[idx];
382*610c32b2SHoratiu Vultur 		mask |= admin->cache.maskstream[idx];
383*610c32b2SHoratiu Vultur 	}
384*610c32b2SHoratiu Vultur 	if (key == 0 && mask == 0)
385*610c32b2SHoratiu Vultur 		return -EINVAL;
386*610c32b2SHoratiu Vultur 	/* Decode and locate the keysets */
387*610c32b2SHoratiu Vultur 	return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
388*610c32b2SHoratiu Vultur 					   admin->cache.maskstream, false, 0,
389*610c32b2SHoratiu Vultur 					   kslist);
390*610c32b2SHoratiu Vultur }
391*610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_addr_keysets);
392*610c32b2SHoratiu 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 
511683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
512683e05c0SSteen Hegelund {
513683e05c0SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
514683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
515683e05c0SSteen Hegelund 	const struct vcap_field *kf_table;
516683e05c0SSteen Hegelund 	int keyset_size;
517683e05c0SSteen Hegelund 
518683e05c0SSteen Hegelund 	/* Get a valid set of fields for the specific keyset */
519683e05c0SSteen Hegelund 	kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset);
520683e05c0SSteen Hegelund 	if (!kf_table) {
521683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this keyset: %d\n",
522683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
523683e05c0SSteen Hegelund 		return -EINVAL;
524683e05c0SSteen Hegelund 	}
525683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific keyset */
526683e05c0SSteen Hegelund 	tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype,
527683e05c0SSteen Hegelund 					   ri->data.keyset);
528683e05c0SSteen Hegelund 	if (!tg_table) {
529683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this keyset: %d\n",
530683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
531683e05c0SSteen Hegelund 		return -EINVAL;
532683e05c0SSteen Hegelund 	}
533683e05c0SSteen Hegelund 	/* Get a valid size for the specific keyset */
534683e05c0SSteen Hegelund 	keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype,
535683e05c0SSteen Hegelund 					  ri->data.keyset);
536683e05c0SSteen Hegelund 	if (keyset_size == 0) {
537683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this keyset: %d\n",
538683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
539683e05c0SSteen Hegelund 		return -EINVAL;
540683e05c0SSteen Hegelund 	}
541683e05c0SSteen Hegelund 	/* Iterate over the keyfields (key, mask) in the rule
542683e05c0SSteen Hegelund 	 * and encode these bits
543683e05c0SSteen Hegelund 	 */
544683e05c0SSteen Hegelund 	if (list_empty(&ri->data.keyfields)) {
545683e05c0SSteen Hegelund 		pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__);
546683e05c0SSteen Hegelund 		return -EINVAL;
547683e05c0SSteen Hegelund 	}
548683e05c0SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
549683e05c0SSteen Hegelund 		/* Check that the client entry exists in the keyset */
550683e05c0SSteen Hegelund 		if (ckf->ctrl.key >= keyset_size) {
551683e05c0SSteen Hegelund 			pr_err("%s:%d: key %d is not in vcap\n",
552683e05c0SSteen Hegelund 			       __func__, __LINE__, ckf->ctrl.key);
553683e05c0SSteen Hegelund 			return -EINVAL;
554683e05c0SSteen Hegelund 		}
555683e05c0SSteen Hegelund 		vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table);
556683e05c0SSteen Hegelund 	}
557683e05c0SSteen Hegelund 	/* Add typegroup bits to the key/mask bitstreams */
558683e05c0SSteen Hegelund 	vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table);
559683e05c0SSteen Hegelund 	return 0;
560683e05c0SSteen Hegelund }
561683e05c0SSteen Hegelund 
562683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */
56372d84dd6SSteen Hegelund const struct vcap_field *
564683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl,
565683e05c0SSteen Hegelund 		  enum vcap_type vt, enum vcap_actionfield_set actionset)
566683e05c0SSteen Hegelund {
567683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
568683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
569683e05c0SSteen Hegelund 		return NULL;
570683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map[actionset];
571683e05c0SSteen Hegelund }
572683e05c0SSteen Hegelund 
57372d84dd6SSteen Hegelund const struct vcap_set *
5748e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl,
5758e10490bSSteen Hegelund 		    enum vcap_type vt, enum vcap_actionfield_set actionset)
5768e10490bSSteen Hegelund {
5778e10490bSSteen Hegelund 	const struct vcap_set *aset;
5788e10490bSSteen Hegelund 
5798e10490bSSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
5808e10490bSSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
5818e10490bSSteen Hegelund 		return NULL;
5828e10490bSSteen Hegelund 	aset = &vctrl->vcaps[vt].actionfield_set[actionset];
5838e10490bSSteen Hegelund 	if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count)
5848e10490bSSteen Hegelund 		return NULL;
5858e10490bSSteen Hegelund 	return aset;
5868e10490bSSteen Hegelund }
5878e10490bSSteen Hegelund 
588683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */
58972d84dd6SSteen Hegelund const struct vcap_typegroup *
590683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl,
591683e05c0SSteen Hegelund 			   enum vcap_type vt, enum vcap_actionfield_set actionset)
592683e05c0SSteen Hegelund {
593683e05c0SSteen Hegelund 	const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset);
594683e05c0SSteen Hegelund 
595683e05c0SSteen Hegelund 	/* Check that the actionset is valid */
596683e05c0SSteen Hegelund 	if (!aset)
597683e05c0SSteen Hegelund 		return NULL;
598683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item];
599683e05c0SSteen Hegelund }
600683e05c0SSteen Hegelund 
601683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */
60272d84dd6SSteen Hegelund int vcap_actionfield_count(struct vcap_control *vctrl,
603683e05c0SSteen Hegelund 			   enum vcap_type vt,
604683e05c0SSteen Hegelund 			   enum vcap_actionfield_set actionset)
605683e05c0SSteen Hegelund {
606683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
607683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
608683e05c0SSteen Hegelund 		return 0;
609683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map_size[actionset];
610683e05c0SSteen Hegelund }
611683e05c0SSteen Hegelund 
612683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri,
613683e05c0SSteen Hegelund 				    const struct vcap_client_actionfield *af,
614683e05c0SSteen Hegelund 				    const struct vcap_field *rf,
615683e05c0SSteen Hegelund 				    const struct vcap_typegroup *tgt)
616683e05c0SSteen Hegelund {
617683e05c0SSteen Hegelund 	int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
618683e05c0SSteen Hegelund 
619683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
620683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
621683e05c0SSteen Hegelund 	const u8 *value;
622683e05c0SSteen Hegelund 
623683e05c0SSteen Hegelund 	/* Encode the action field in the stream, respecting the subword width */
624683e05c0SSteen Hegelund 	switch (af->ctrl.type) {
625683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
626683e05c0SSteen Hegelund 		value = &af->data.u1.value;
627683e05c0SSteen Hegelund 		break;
628683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
629683e05c0SSteen Hegelund 		value = (const u8 *)&af->data.u32.value;
630683e05c0SSteen Hegelund 		break;
631683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
632683e05c0SSteen Hegelund 		value = af->data.u48.value;
633683e05c0SSteen Hegelund 		break;
634683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
635683e05c0SSteen Hegelund 		value = af->data.u56.value;
636683e05c0SSteen Hegelund 		break;
637683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
638683e05c0SSteen Hegelund 		value = af->data.u64.value;
639683e05c0SSteen Hegelund 		break;
640683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
641683e05c0SSteen Hegelund 		value = af->data.u72.value;
642683e05c0SSteen Hegelund 		break;
643683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
644683e05c0SSteen Hegelund 		value = af->data.u112.value;
645683e05c0SSteen Hegelund 		break;
646683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
647683e05c0SSteen Hegelund 		value = af->data.u128.value;
648683e05c0SSteen Hegelund 		break;
649683e05c0SSteen Hegelund 	}
650683e05c0SSteen Hegelund 	vcap_iter_init(&iter, act_width, tgt, rf->offset);
651683e05c0SSteen Hegelund 	vcap_encode_field(cache->actionstream, &iter, rf->width, value);
652683e05c0SSteen Hegelund }
653683e05c0SSteen Hegelund 
654683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri,
655683e05c0SSteen Hegelund 					       const struct vcap_typegroup *tgt)
656683e05c0SSteen Hegelund {
657683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
658683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
659683e05c0SSteen Hegelund 
660683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the actionstream respecting the subword
661683e05c0SSteen Hegelund 	 * width.
662683e05c0SSteen Hegelund 	 */
663683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false);
664683e05c0SSteen Hegelund }
665683e05c0SSteen Hegelund 
666683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri)
667683e05c0SSteen Hegelund {
668683e05c0SSteen Hegelund 	const struct vcap_client_actionfield *caf;
669683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
670683e05c0SSteen Hegelund 	const struct vcap_field *af_table;
671683e05c0SSteen Hegelund 	int actionset_size;
672683e05c0SSteen Hegelund 
673683e05c0SSteen Hegelund 	/* Get a valid set of actionset fields for the specific actionset */
674683e05c0SSteen Hegelund 	af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype,
675683e05c0SSteen Hegelund 				     ri->data.actionset);
676683e05c0SSteen Hegelund 	if (!af_table) {
677683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this actionset: %d\n",
678683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
679683e05c0SSteen Hegelund 		return -EINVAL;
680683e05c0SSteen Hegelund 	}
681683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific actionset */
682683e05c0SSteen Hegelund 	tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype,
683683e05c0SSteen Hegelund 					      ri->data.actionset);
684683e05c0SSteen Hegelund 	if (!tg_table) {
685683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this actionset: %d\n",
686683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
687683e05c0SSteen Hegelund 		return -EINVAL;
688683e05c0SSteen Hegelund 	}
689683e05c0SSteen Hegelund 	/* Get a valid actionset size for the specific actionset */
690683e05c0SSteen Hegelund 	actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype,
691683e05c0SSteen Hegelund 						ri->data.actionset);
692683e05c0SSteen Hegelund 	if (actionset_size == 0) {
693683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this actionset: %d\n",
694683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
695683e05c0SSteen Hegelund 		return -EINVAL;
696683e05c0SSteen Hegelund 	}
697683e05c0SSteen Hegelund 	/* Iterate over the actionfields in the rule
698683e05c0SSteen Hegelund 	 * and encode these bits
699683e05c0SSteen Hegelund 	 */
700683e05c0SSteen Hegelund 	if (list_empty(&ri->data.actionfields))
701683e05c0SSteen Hegelund 		pr_warn("%s:%d: no actionfields in the rule\n",
702683e05c0SSteen Hegelund 			__func__, __LINE__);
703683e05c0SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
704683e05c0SSteen Hegelund 		/* Check that the client action exists in the actionset */
705683e05c0SSteen Hegelund 		if (caf->ctrl.action >= actionset_size) {
706683e05c0SSteen Hegelund 			pr_err("%s:%d: action %d is not in vcap\n",
707683e05c0SSteen Hegelund 			       __func__, __LINE__, caf->ctrl.action);
708683e05c0SSteen Hegelund 			return -EINVAL;
709683e05c0SSteen Hegelund 		}
710683e05c0SSteen Hegelund 		vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action],
711683e05c0SSteen Hegelund 					tg_table);
712683e05c0SSteen Hegelund 	}
713683e05c0SSteen Hegelund 	/* Add typegroup bits to the entry bitstreams */
714683e05c0SSteen Hegelund 	vcap_encode_actionfield_typegroups(ri, tg_table);
715683e05c0SSteen Hegelund 	return 0;
716683e05c0SSteen Hegelund }
717683e05c0SSteen Hegelund 
7188e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri)
7198e10490bSSteen Hegelund {
720683e05c0SSteen Hegelund 	int err;
721683e05c0SSteen Hegelund 
722683e05c0SSteen Hegelund 	err = vcap_encode_rule_keyset(ri);
723683e05c0SSteen Hegelund 	if (err)
724683e05c0SSteen Hegelund 		return err;
725683e05c0SSteen Hegelund 	err = vcap_encode_rule_actionset(ri);
726683e05c0SSteen Hegelund 	if (err)
727683e05c0SSteen Hegelund 		return err;
7288e10490bSSteen Hegelund 	return 0;
7298e10490bSSteen Hegelund }
7308e10490bSSteen Hegelund 
731d4134d41SSteen Hegelund int vcap_api_check(struct vcap_control *ctrl)
7328e10490bSSteen Hegelund {
7338e10490bSSteen Hegelund 	if (!ctrl) {
7348e10490bSSteen Hegelund 		pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
7358e10490bSSteen Hegelund 		return -EINVAL;
7368e10490bSSteen Hegelund 	}
7378e10490bSSteen Hegelund 	if (!ctrl->ops || !ctrl->ops->validate_keyset ||
7388e10490bSSteen Hegelund 	    !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
7398e10490bSSteen Hegelund 	    !ctrl->ops->cache_write || !ctrl->ops->cache_read ||
7408e10490bSSteen Hegelund 	    !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
74167456717SSteen Hegelund 	    !ctrl->ops->port_info || !ctrl->ops->enable) {
7428e10490bSSteen Hegelund 		pr_err("%s:%d: client operations are missing\n",
7438e10490bSSteen Hegelund 		       __func__, __LINE__);
7448e10490bSSteen Hegelund 		return -ENOENT;
7458e10490bSSteen Hegelund 	}
7468e10490bSSteen Hegelund 	return 0;
7478e10490bSSteen Hegelund }
7488e10490bSSteen Hegelund 
7493a792156SSteen Hegelund void vcap_erase_cache(struct vcap_rule_internal *ri)
7508e10490bSSteen Hegelund {
7518e10490bSSteen Hegelund 	ri->vctrl->ops->cache_erase(ri->admin);
7528e10490bSSteen Hegelund }
7538e10490bSSteen Hegelund 
754c9da1ac1SSteen Hegelund /* Update the keyset for the rule */
755c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule,
756c9da1ac1SSteen Hegelund 			     enum vcap_keyfield_set keyset)
757c9da1ac1SSteen Hegelund {
7588e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
7598e10490bSSteen Hegelund 	const struct vcap_set *kset;
7608e10490bSSteen Hegelund 	int sw_width;
7618e10490bSSteen Hegelund 
7628e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset);
7638e10490bSSteen Hegelund 	/* Check that the keyset is valid */
7648e10490bSSteen Hegelund 	if (!kset)
7658e10490bSSteen Hegelund 		return -EINVAL;
7668e10490bSSteen Hegelund 	ri->keyset_sw = kset->sw_per_item;
7678e10490bSSteen Hegelund 	sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
7688e10490bSSteen Hegelund 	ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32);
7698e10490bSSteen Hegelund 	ri->data.keyset = keyset;
770c9da1ac1SSteen Hegelund 	return 0;
771c9da1ac1SSteen Hegelund }
772c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset);
773c9da1ac1SSteen Hegelund 
774c9da1ac1SSteen Hegelund /* Update the actionset for the rule */
775c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule,
776c9da1ac1SSteen Hegelund 				enum vcap_actionfield_set actionset)
777c9da1ac1SSteen Hegelund {
7788e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
7798e10490bSSteen Hegelund 	const struct vcap_set *aset;
7808e10490bSSteen Hegelund 	int act_width;
7818e10490bSSteen Hegelund 
7828e10490bSSteen Hegelund 	aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset);
7838e10490bSSteen Hegelund 	/* Check that the actionset is valid */
7848e10490bSSteen Hegelund 	if (!aset)
7858e10490bSSteen Hegelund 		return -EINVAL;
7868e10490bSSteen Hegelund 	ri->actionset_sw = aset->sw_per_item;
7878e10490bSSteen Hegelund 	act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
7888e10490bSSteen Hegelund 	ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32);
7898e10490bSSteen Hegelund 	ri->data.actionset = actionset;
790c9da1ac1SSteen Hegelund 	return 0;
791c9da1ac1SSteen Hegelund }
792c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset);
793c9da1ac1SSteen Hegelund 
794c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */
795c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl,
796c9da1ac1SSteen Hegelund 						   u32 id)
797c9da1ac1SSteen Hegelund {
798c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
799c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
800c9da1ac1SSteen Hegelund 
801c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
802c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
803c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
804c9da1ac1SSteen Hegelund 			if (ri->data.id == id)
805c9da1ac1SSteen Hegelund 				return ri;
806c9da1ac1SSteen Hegelund 	return NULL;
807c9da1ac1SSteen Hegelund }
808c9da1ac1SSteen Hegelund 
809c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */
810c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
811c9da1ac1SSteen Hegelund {
812c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
813c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
814c9da1ac1SSteen Hegelund 
815c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
816c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
817c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
818c9da1ac1SSteen Hegelund 			if (ri->data.cookie == cookie)
819c9da1ac1SSteen Hegelund 				return ri->data.id;
820c9da1ac1SSteen Hegelund 	return -ENOENT;
821c9da1ac1SSteen Hegelund }
822c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
823c9da1ac1SSteen Hegelund 
8248e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */
8253a792156SSteen Hegelund struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
8268e10490bSSteen Hegelund {
8278e10490bSSteen Hegelund 	struct vcap_rule_internal *duprule;
8288e10490bSSteen Hegelund 
8298e10490bSSteen Hegelund 	/* Allocate the client part */
8308e10490bSSteen Hegelund 	duprule = kzalloc(sizeof(*duprule), GFP_KERNEL);
8318e10490bSSteen Hegelund 	if (!duprule)
8328e10490bSSteen Hegelund 		return ERR_PTR(-ENOMEM);
8338e10490bSSteen Hegelund 	*duprule = *ri;
8348e10490bSSteen Hegelund 	/* Not inserted in the VCAP */
8358e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->list);
8368e10490bSSteen Hegelund 	/* No elements in these lists */
8378e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.keyfields);
8388e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.actionfields);
8398e10490bSSteen Hegelund 	return duprule;
8408e10490bSSteen Hegelund }
8418e10490bSSteen Hegelund 
842*610c32b2SHoratiu Vultur static void vcap_apply_width(u8 *dst, int width, int bytes)
843*610c32b2SHoratiu Vultur {
844*610c32b2SHoratiu Vultur 	u8 bmask;
845*610c32b2SHoratiu Vultur 	int idx;
846*610c32b2SHoratiu Vultur 
847*610c32b2SHoratiu Vultur 	for (idx = 0; idx < bytes; idx++) {
848*610c32b2SHoratiu Vultur 		if (width > 0)
849*610c32b2SHoratiu Vultur 			if (width < 8)
850*610c32b2SHoratiu Vultur 				bmask = (1 << width) - 1;
851*610c32b2SHoratiu Vultur 			else
852*610c32b2SHoratiu Vultur 				bmask = ~0;
853*610c32b2SHoratiu Vultur 		else
854*610c32b2SHoratiu Vultur 			bmask = 0;
855*610c32b2SHoratiu Vultur 		dst[idx] &= bmask;
856*610c32b2SHoratiu Vultur 		width -= 8;
857*610c32b2SHoratiu Vultur 	}
858*610c32b2SHoratiu Vultur }
859*610c32b2SHoratiu Vultur 
860*610c32b2SHoratiu Vultur static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width)
861*610c32b2SHoratiu Vultur {
862*610c32b2SHoratiu Vultur 	int idx, ridx, wstart, nidx;
863*610c32b2SHoratiu Vultur 	int tail_bytes = (((size + 4) >> 2) << 2) - size;
864*610c32b2SHoratiu Vultur 
865*610c32b2SHoratiu Vultur 	for (idx = 0, ridx = size - 1; idx < size; ++idx, --ridx) {
866*610c32b2SHoratiu Vultur 		wstart = (idx >> 2) << 2;
867*610c32b2SHoratiu Vultur 		nidx = wstart + 3 - (idx & 0x3);
868*610c32b2SHoratiu Vultur 		if (nidx >= size)
869*610c32b2SHoratiu Vultur 			nidx -= tail_bytes;
870*610c32b2SHoratiu Vultur 		dst[nidx] = src[ridx];
871*610c32b2SHoratiu Vultur 	}
872*610c32b2SHoratiu Vultur 
873*610c32b2SHoratiu Vultur 	vcap_apply_width(dst, width, size);
874*610c32b2SHoratiu Vultur }
875*610c32b2SHoratiu Vultur 
876*610c32b2SHoratiu Vultur static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *value)
877*610c32b2SHoratiu Vultur {
878*610c32b2SHoratiu Vultur 	field->value = (*value) & 0x1;
879*610c32b2SHoratiu Vultur }
880*610c32b2SHoratiu Vultur 
881*610c32b2SHoratiu Vultur static void vcap_copy_limited_actionfield(u8 *dstvalue, u8 *srcvalue,
882*610c32b2SHoratiu Vultur 					  int width, int bytes)
883*610c32b2SHoratiu Vultur {
884*610c32b2SHoratiu Vultur 	memcpy(dstvalue, srcvalue, bytes);
885*610c32b2SHoratiu Vultur 	vcap_apply_width(dstvalue, width, bytes);
886*610c32b2SHoratiu Vultur }
887*610c32b2SHoratiu Vultur 
888*610c32b2SHoratiu Vultur static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri,
889*610c32b2SHoratiu Vultur 					    struct vcap_client_actionfield *field,
890*610c32b2SHoratiu Vultur 					    u8 *value, u16 width)
891*610c32b2SHoratiu Vultur {
892*610c32b2SHoratiu Vultur 	int field_size = actionfield_size_table[field->ctrl.type];
893*610c32b2SHoratiu Vultur 
894*610c32b2SHoratiu Vultur 	if (ri->admin->w32be) {
895*610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
896*610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
897*610c32b2SHoratiu Vultur 			vcap_copy_action_bit_field(&field->data.u1, value);
898*610c32b2SHoratiu Vultur 			break;
899*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
900*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
901*610c32b2SHoratiu Vultur 						      value,
902*610c32b2SHoratiu Vultur 						      width, field_size);
903*610c32b2SHoratiu Vultur 			break;
904*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
905*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.value, value,
906*610c32b2SHoratiu Vultur 					     field_size, width);
907*610c32b2SHoratiu Vultur 			break;
908*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
909*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.value, value,
910*610c32b2SHoratiu Vultur 					     field_size, width);
911*610c32b2SHoratiu Vultur 			break;
912*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
913*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.value, value,
914*610c32b2SHoratiu Vultur 					     field_size, width);
915*610c32b2SHoratiu Vultur 			break;
916*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
917*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.value, value,
918*610c32b2SHoratiu Vultur 					     field_size, width);
919*610c32b2SHoratiu Vultur 			break;
920*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
921*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.value, value,
922*610c32b2SHoratiu Vultur 					     field_size, width);
923*610c32b2SHoratiu Vultur 			break;
924*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
925*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.value, value,
926*610c32b2SHoratiu Vultur 					     field_size, width);
927*610c32b2SHoratiu Vultur 			break;
928*610c32b2SHoratiu Vultur 		};
929*610c32b2SHoratiu Vultur 	} else {
930*610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
931*610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
932*610c32b2SHoratiu Vultur 			vcap_copy_action_bit_field(&field->data.u1, value);
933*610c32b2SHoratiu Vultur 			break;
934*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
935*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
936*610c32b2SHoratiu Vultur 						      value,
937*610c32b2SHoratiu Vultur 						      width, field_size);
938*610c32b2SHoratiu Vultur 			break;
939*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
940*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u48.value,
941*610c32b2SHoratiu Vultur 						      value,
942*610c32b2SHoratiu Vultur 						      width, field_size);
943*610c32b2SHoratiu Vultur 			break;
944*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
945*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u56.value,
946*610c32b2SHoratiu Vultur 						      value,
947*610c32b2SHoratiu Vultur 						      width, field_size);
948*610c32b2SHoratiu Vultur 			break;
949*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
950*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u64.value,
951*610c32b2SHoratiu Vultur 						      value,
952*610c32b2SHoratiu Vultur 						      width, field_size);
953*610c32b2SHoratiu Vultur 			break;
954*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
955*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u72.value,
956*610c32b2SHoratiu Vultur 						      value,
957*610c32b2SHoratiu Vultur 						      width, field_size);
958*610c32b2SHoratiu Vultur 			break;
959*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
960*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u112.value,
961*610c32b2SHoratiu Vultur 						      value,
962*610c32b2SHoratiu Vultur 						      width, field_size);
963*610c32b2SHoratiu Vultur 			break;
964*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
965*610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u128.value,
966*610c32b2SHoratiu Vultur 						      value,
967*610c32b2SHoratiu Vultur 						      width, field_size);
968*610c32b2SHoratiu Vultur 			break;
969*610c32b2SHoratiu Vultur 		};
970*610c32b2SHoratiu Vultur 	}
971*610c32b2SHoratiu Vultur }
972*610c32b2SHoratiu Vultur 
973*610c32b2SHoratiu Vultur static void vcap_copy_key_bit_field(struct vcap_u1_key *field,
974*610c32b2SHoratiu Vultur 				    u8 *value, u8 *mask)
975*610c32b2SHoratiu Vultur {
976*610c32b2SHoratiu Vultur 	field->value = (*value) & 0x1;
977*610c32b2SHoratiu Vultur 	field->mask = (*mask) & 0x1;
978*610c32b2SHoratiu Vultur }
979*610c32b2SHoratiu Vultur 
980*610c32b2SHoratiu Vultur static void vcap_copy_limited_keyfield(u8 *dstvalue, u8 *dstmask,
981*610c32b2SHoratiu Vultur 				       u8 *srcvalue, u8 *srcmask,
982*610c32b2SHoratiu Vultur 				       int width, int bytes)
983*610c32b2SHoratiu Vultur {
984*610c32b2SHoratiu Vultur 	memcpy(dstvalue, srcvalue, bytes);
985*610c32b2SHoratiu Vultur 	vcap_apply_width(dstvalue, width, bytes);
986*610c32b2SHoratiu Vultur 	memcpy(dstmask, srcmask, bytes);
987*610c32b2SHoratiu Vultur 	vcap_apply_width(dstmask, width, bytes);
988*610c32b2SHoratiu Vultur }
989*610c32b2SHoratiu Vultur 
990*610c32b2SHoratiu Vultur static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri,
991*610c32b2SHoratiu Vultur 					 struct vcap_client_keyfield *field,
992*610c32b2SHoratiu Vultur 					 u8 *value, u8 *mask, u16 width)
993*610c32b2SHoratiu Vultur {
994*610c32b2SHoratiu Vultur 	int field_size = keyfield_size_table[field->ctrl.type] / 2;
995*610c32b2SHoratiu Vultur 
996*610c32b2SHoratiu Vultur 	if (ri->admin->w32be) {
997*610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
998*610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
999*610c32b2SHoratiu Vultur 			vcap_copy_key_bit_field(&field->data.u1, value, mask);
1000*610c32b2SHoratiu Vultur 			break;
1001*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1002*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1003*610c32b2SHoratiu Vultur 						   (u8 *)&field->data.u32.mask,
1004*610c32b2SHoratiu Vultur 						   value, mask,
1005*610c32b2SHoratiu Vultur 						   width, field_size);
1006*610c32b2SHoratiu Vultur 			break;
1007*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1008*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.value, value,
1009*610c32b2SHoratiu Vultur 					     field_size, width);
1010*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.mask,  mask,
1011*610c32b2SHoratiu Vultur 					     field_size, width);
1012*610c32b2SHoratiu Vultur 			break;
1013*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1014*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.value, value,
1015*610c32b2SHoratiu Vultur 					     field_size, width);
1016*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.mask,  mask,
1017*610c32b2SHoratiu Vultur 					     field_size, width);
1018*610c32b2SHoratiu Vultur 			break;
1019*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1020*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.value, value,
1021*610c32b2SHoratiu Vultur 					     field_size, width);
1022*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.mask,  mask,
1023*610c32b2SHoratiu Vultur 					     field_size, width);
1024*610c32b2SHoratiu Vultur 			break;
1025*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1026*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.value, value,
1027*610c32b2SHoratiu Vultur 					     field_size, width);
1028*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.mask,  mask,
1029*610c32b2SHoratiu Vultur 					     field_size, width);
1030*610c32b2SHoratiu Vultur 			break;
1031*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1032*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.value, value,
1033*610c32b2SHoratiu Vultur 					     field_size, width);
1034*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.mask,  mask,
1035*610c32b2SHoratiu Vultur 					     field_size, width);
1036*610c32b2SHoratiu Vultur 			break;
1037*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1038*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.value, value,
1039*610c32b2SHoratiu Vultur 					     field_size, width);
1040*610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.mask,  mask,
1041*610c32b2SHoratiu Vultur 					     field_size, width);
1042*610c32b2SHoratiu Vultur 			break;
1043*610c32b2SHoratiu Vultur 		};
1044*610c32b2SHoratiu Vultur 	} else {
1045*610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1046*610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1047*610c32b2SHoratiu Vultur 			vcap_copy_key_bit_field(&field->data.u1, value, mask);
1048*610c32b2SHoratiu Vultur 			break;
1049*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1050*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1051*610c32b2SHoratiu Vultur 						   (u8 *)&field->data.u32.mask,
1052*610c32b2SHoratiu Vultur 						   value, mask,
1053*610c32b2SHoratiu Vultur 						   width, field_size);
1054*610c32b2SHoratiu Vultur 			break;
1055*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1056*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u48.value,
1057*610c32b2SHoratiu Vultur 						   field->data.u48.mask,
1058*610c32b2SHoratiu Vultur 						   value, mask,
1059*610c32b2SHoratiu Vultur 						   width, field_size);
1060*610c32b2SHoratiu Vultur 			break;
1061*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1062*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u56.value,
1063*610c32b2SHoratiu Vultur 						   field->data.u56.mask,
1064*610c32b2SHoratiu Vultur 						   value, mask,
1065*610c32b2SHoratiu Vultur 						   width, field_size);
1066*610c32b2SHoratiu Vultur 			break;
1067*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1068*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u64.value,
1069*610c32b2SHoratiu Vultur 						   field->data.u64.mask,
1070*610c32b2SHoratiu Vultur 						   value, mask,
1071*610c32b2SHoratiu Vultur 						   width, field_size);
1072*610c32b2SHoratiu Vultur 			break;
1073*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1074*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u72.value,
1075*610c32b2SHoratiu Vultur 						   field->data.u72.mask,
1076*610c32b2SHoratiu Vultur 						   value, mask,
1077*610c32b2SHoratiu Vultur 						   width, field_size);
1078*610c32b2SHoratiu Vultur 			break;
1079*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1080*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u112.value,
1081*610c32b2SHoratiu Vultur 						   field->data.u112.mask,
1082*610c32b2SHoratiu Vultur 						   value, mask,
1083*610c32b2SHoratiu Vultur 						   width, field_size);
1084*610c32b2SHoratiu Vultur 			break;
1085*610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1086*610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u128.value,
1087*610c32b2SHoratiu Vultur 						   field->data.u128.mask,
1088*610c32b2SHoratiu Vultur 						   value, mask,
1089*610c32b2SHoratiu Vultur 						   width, field_size);
1090*610c32b2SHoratiu Vultur 			break;
1091*610c32b2SHoratiu Vultur 		};
1092*610c32b2SHoratiu Vultur 	}
1093*610c32b2SHoratiu Vultur }
1094*610c32b2SHoratiu Vultur 
1095*610c32b2SHoratiu Vultur static void vcap_rule_alloc_keyfield(struct vcap_rule_internal *ri,
1096*610c32b2SHoratiu Vultur 				     const struct vcap_field *keyfield,
1097*610c32b2SHoratiu Vultur 				     enum vcap_key_field key,
1098*610c32b2SHoratiu Vultur 				     u8 *value, u8 *mask)
1099*610c32b2SHoratiu Vultur {
1100*610c32b2SHoratiu Vultur 	struct vcap_client_keyfield *field;
1101*610c32b2SHoratiu Vultur 
1102*610c32b2SHoratiu Vultur 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1103*610c32b2SHoratiu Vultur 	if (!field)
1104*610c32b2SHoratiu Vultur 		return;
1105*610c32b2SHoratiu Vultur 	INIT_LIST_HEAD(&field->ctrl.list);
1106*610c32b2SHoratiu Vultur 	field->ctrl.key = key;
1107*610c32b2SHoratiu Vultur 	field->ctrl.type = keyfield->type;
1108*610c32b2SHoratiu Vultur 	vcap_copy_to_client_keyfield(ri, field, value, mask, keyfield->width);
1109*610c32b2SHoratiu Vultur 	list_add_tail(&field->ctrl.list, &ri->data.keyfields);
1110*610c32b2SHoratiu Vultur }
1111*610c32b2SHoratiu Vultur 
1112*610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there is a rule keyset
1113*610c32b2SHoratiu Vultur  * here
1114*610c32b2SHoratiu Vultur  */
1115*610c32b2SHoratiu Vultur static bool
1116*610c32b2SHoratiu Vultur vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
1117*610c32b2SHoratiu Vultur 				   enum vcap_type vt,
1118*610c32b2SHoratiu Vultur 				   u32 *actionstream,
1119*610c32b2SHoratiu Vultur 				   enum vcap_actionfield_set actionset)
1120*610c32b2SHoratiu Vultur {
1121*610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1122*610c32b2SHoratiu Vultur 	const struct vcap_field *fields;
1123*610c32b2SHoratiu Vultur 	const struct vcap_set *info;
1124*610c32b2SHoratiu Vultur 
1125*610c32b2SHoratiu Vultur 	if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
1126*610c32b2SHoratiu Vultur 		return false;
1127*610c32b2SHoratiu Vultur 
1128*610c32b2SHoratiu Vultur 	info = vcap_actionfieldset(vctrl, vt, actionset);
1129*610c32b2SHoratiu Vultur 	/* Check that the actionset is valid */
1130*610c32b2SHoratiu Vultur 	if (!info)
1131*610c32b2SHoratiu Vultur 		return false;
1132*610c32b2SHoratiu Vultur 
1133*610c32b2SHoratiu Vultur 	/* a type_id of value -1 means that there is no type field */
1134*610c32b2SHoratiu Vultur 	if (info->type_id == (u8)-1)
1135*610c32b2SHoratiu Vultur 		return true;
1136*610c32b2SHoratiu Vultur 
1137*610c32b2SHoratiu Vultur 	/* Get a valid typegroup for the specific actionset */
1138*610c32b2SHoratiu Vultur 	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1139*610c32b2SHoratiu Vultur 	if (!tgt)
1140*610c32b2SHoratiu Vultur 		return false;
1141*610c32b2SHoratiu Vultur 
1142*610c32b2SHoratiu Vultur 	fields = vcap_actionfields(vctrl, vt, actionset);
1143*610c32b2SHoratiu Vultur 	if (!fields)
1144*610c32b2SHoratiu Vultur 		return false;
1145*610c32b2SHoratiu Vultur 
1146*610c32b2SHoratiu Vultur 	/* Later this will be expanded with a check of the type id */
1147*610c32b2SHoratiu Vultur 	return true;
1148*610c32b2SHoratiu Vultur }
1149*610c32b2SHoratiu Vultur 
1150*610c32b2SHoratiu Vultur /* Find the subword width of the action typegroup that matches the stream data
1151*610c32b2SHoratiu Vultur  */
1152*610c32b2SHoratiu Vultur static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
1153*610c32b2SHoratiu Vultur 					       enum vcap_type vt, u32 *stream,
1154*610c32b2SHoratiu Vultur 					       int sw_max)
1155*610c32b2SHoratiu Vultur {
1156*610c32b2SHoratiu Vultur 	const struct vcap_typegroup **tgt;
1157*610c32b2SHoratiu Vultur 	int sw_idx, res;
1158*610c32b2SHoratiu Vultur 
1159*610c32b2SHoratiu Vultur 	tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
1160*610c32b2SHoratiu Vultur 	/* Try the longest subword match first */
1161*610c32b2SHoratiu Vultur 	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
1162*610c32b2SHoratiu Vultur 		if (!tgt[sw_idx])
1163*610c32b2SHoratiu Vultur 			continue;
1164*610c32b2SHoratiu Vultur 		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
1165*610c32b2SHoratiu Vultur 					     tgt[sw_idx], false, sw_max);
1166*610c32b2SHoratiu Vultur 		if (res == 0)
1167*610c32b2SHoratiu Vultur 			return sw_idx;
1168*610c32b2SHoratiu Vultur 	}
1169*610c32b2SHoratiu Vultur 	return -EINVAL;
1170*610c32b2SHoratiu Vultur }
1171*610c32b2SHoratiu Vultur 
1172*610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, actionset and type id
1173*610c32b2SHoratiu Vultur  * are in sync and correct, return the actionset
1174*610c32b2SHoratiu Vultur  */
1175*610c32b2SHoratiu Vultur static enum vcap_actionfield_set
1176*610c32b2SHoratiu Vultur vcap_find_actionstream_actionset(struct vcap_control *vctrl,
1177*610c32b2SHoratiu Vultur 				 enum vcap_type vt,
1178*610c32b2SHoratiu Vultur 				 u32 *stream,
1179*610c32b2SHoratiu Vultur 				 int sw_max)
1180*610c32b2SHoratiu Vultur {
1181*610c32b2SHoratiu Vultur 	const struct vcap_set *actionfield_set;
1182*610c32b2SHoratiu Vultur 	int sw_count, idx;
1183*610c32b2SHoratiu Vultur 	bool res;
1184*610c32b2SHoratiu Vultur 
1185*610c32b2SHoratiu Vultur 	sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
1186*610c32b2SHoratiu Vultur 						       sw_max);
1187*610c32b2SHoratiu Vultur 	if (sw_count < 0)
1188*610c32b2SHoratiu Vultur 		return sw_count;
1189*610c32b2SHoratiu Vultur 
1190*610c32b2SHoratiu Vultur 	actionfield_set = vctrl->vcaps[vt].actionfield_set;
1191*610c32b2SHoratiu Vultur 	for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
1192*610c32b2SHoratiu Vultur 		if (actionfield_set[idx].sw_per_item != sw_count)
1193*610c32b2SHoratiu Vultur 			continue;
1194*610c32b2SHoratiu Vultur 
1195*610c32b2SHoratiu Vultur 		res = vcap_verify_actionstream_actionset(vctrl, vt,
1196*610c32b2SHoratiu Vultur 							 stream, idx);
1197*610c32b2SHoratiu Vultur 		if (res)
1198*610c32b2SHoratiu Vultur 			return idx;
1199*610c32b2SHoratiu Vultur 	}
1200*610c32b2SHoratiu Vultur 	return -EINVAL;
1201*610c32b2SHoratiu Vultur }
1202*610c32b2SHoratiu Vultur 
1203*610c32b2SHoratiu Vultur /* Store action value in an element in a list for the client */
1204*610c32b2SHoratiu Vultur static void vcap_rule_alloc_actionfield(struct vcap_rule_internal *ri,
1205*610c32b2SHoratiu Vultur 					const struct vcap_field *actionfield,
1206*610c32b2SHoratiu Vultur 					enum vcap_action_field action,
1207*610c32b2SHoratiu Vultur 					u8 *value)
1208*610c32b2SHoratiu Vultur {
1209*610c32b2SHoratiu Vultur 	struct vcap_client_actionfield *field;
1210*610c32b2SHoratiu Vultur 
1211*610c32b2SHoratiu Vultur 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1212*610c32b2SHoratiu Vultur 	if (!field)
1213*610c32b2SHoratiu Vultur 		return;
1214*610c32b2SHoratiu Vultur 	INIT_LIST_HEAD(&field->ctrl.list);
1215*610c32b2SHoratiu Vultur 	field->ctrl.action = action;
1216*610c32b2SHoratiu Vultur 	field->ctrl.type = actionfield->type;
1217*610c32b2SHoratiu Vultur 	vcap_copy_to_client_actionfield(ri, field, value, actionfield->width);
1218*610c32b2SHoratiu Vultur 	list_add_tail(&field->ctrl.list, &ri->data.actionfields);
1219*610c32b2SHoratiu Vultur }
1220*610c32b2SHoratiu Vultur 
1221*610c32b2SHoratiu Vultur static int vcap_decode_actionset(struct vcap_rule_internal *ri)
1222*610c32b2SHoratiu Vultur {
1223*610c32b2SHoratiu Vultur 	struct vcap_control *vctrl = ri->vctrl;
1224*610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1225*610c32b2SHoratiu Vultur 	const struct vcap_field *actionfield;
1226*610c32b2SHoratiu Vultur 	enum vcap_actionfield_set actionset;
1227*610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
1228*610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1229*610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
1230*610c32b2SHoratiu Vultur 	int idx, res, actfield_count;
1231*610c32b2SHoratiu Vultur 	u32 *actstream;
1232*610c32b2SHoratiu Vultur 	u8 value[16];
1233*610c32b2SHoratiu Vultur 
1234*610c32b2SHoratiu Vultur 	actstream = admin->cache.actionstream;
1235*610c32b2SHoratiu Vultur 	res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
1236*610c32b2SHoratiu Vultur 	if (res < 0) {
1237*610c32b2SHoratiu Vultur 		pr_err("%s:%d: could not find valid actionset: %d\n",
1238*610c32b2SHoratiu Vultur 		       __func__, __LINE__, res);
1239*610c32b2SHoratiu Vultur 		return -EINVAL;
1240*610c32b2SHoratiu Vultur 	}
1241*610c32b2SHoratiu Vultur 	actionset = res;
1242*610c32b2SHoratiu Vultur 	actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
1243*610c32b2SHoratiu Vultur 	actionfield = vcap_actionfields(vctrl, vt, actionset);
1244*610c32b2SHoratiu Vultur 	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1245*610c32b2SHoratiu Vultur 	/* Start decoding the stream */
1246*610c32b2SHoratiu Vultur 	for (idx = 0; idx < actfield_count; ++idx) {
1247*610c32b2SHoratiu Vultur 		if (actionfield[idx].width <= 0)
1248*610c32b2SHoratiu Vultur 			continue;
1249*610c32b2SHoratiu Vultur 		/* Get the action */
1250*610c32b2SHoratiu Vultur 		memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
1251*610c32b2SHoratiu Vultur 		vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
1252*610c32b2SHoratiu Vultur 			       actionfield[idx].offset);
1253*610c32b2SHoratiu Vultur 		vcap_decode_field(actstream, &iter, actionfield[idx].width,
1254*610c32b2SHoratiu Vultur 				  value);
1255*610c32b2SHoratiu Vultur 		/* Skip if no bits are set */
1256*610c32b2SHoratiu Vultur 		if (vcap_bitarray_zero(actionfield[idx].width, value))
1257*610c32b2SHoratiu Vultur 			continue;
1258*610c32b2SHoratiu Vultur 		vcap_rule_alloc_actionfield(ri, &actionfield[idx], idx, value);
1259*610c32b2SHoratiu Vultur 		/* Later the action id will also be checked */
1260*610c32b2SHoratiu Vultur 	}
1261*610c32b2SHoratiu Vultur 	return vcap_set_rule_set_actionset((struct vcap_rule *)ri, actionset);
1262*610c32b2SHoratiu Vultur }
1263*610c32b2SHoratiu Vultur 
1264*610c32b2SHoratiu Vultur static int vcap_decode_keyset(struct vcap_rule_internal *ri)
1265*610c32b2SHoratiu Vultur {
1266*610c32b2SHoratiu Vultur 	struct vcap_control *vctrl = ri->vctrl;
1267*610c32b2SHoratiu Vultur 	struct vcap_stream_iter kiter, miter;
1268*610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1269*610c32b2SHoratiu Vultur 	enum vcap_keyfield_set keysets[10];
1270*610c32b2SHoratiu Vultur 	const struct vcap_field *keyfield;
1271*610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
1272*610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1273*610c32b2SHoratiu Vultur 	struct vcap_keyset_list matches;
1274*610c32b2SHoratiu Vultur 	enum vcap_keyfield_set keyset;
1275*610c32b2SHoratiu Vultur 	int idx, res, keyfield_count;
1276*610c32b2SHoratiu Vultur 	u32 *maskstream;
1277*610c32b2SHoratiu Vultur 	u32 *keystream;
1278*610c32b2SHoratiu Vultur 	u8 value[16];
1279*610c32b2SHoratiu Vultur 	u8 mask[16];
1280*610c32b2SHoratiu Vultur 
1281*610c32b2SHoratiu Vultur 	keystream = admin->cache.keystream;
1282*610c32b2SHoratiu Vultur 	maskstream = admin->cache.maskstream;
1283*610c32b2SHoratiu Vultur 	matches.keysets = keysets;
1284*610c32b2SHoratiu Vultur 	matches.cnt = 0;
1285*610c32b2SHoratiu Vultur 	matches.max = ARRAY_SIZE(keysets);
1286*610c32b2SHoratiu Vultur 	res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream,
1287*610c32b2SHoratiu Vultur 					  false, 0, &matches);
1288*610c32b2SHoratiu Vultur 	if (res < 0) {
1289*610c32b2SHoratiu Vultur 		pr_err("%s:%d: could not find valid keysets: %d\n",
1290*610c32b2SHoratiu Vultur 		       __func__, __LINE__, res);
1291*610c32b2SHoratiu Vultur 		return -EINVAL;
1292*610c32b2SHoratiu Vultur 	}
1293*610c32b2SHoratiu Vultur 	keyset = matches.keysets[0];
1294*610c32b2SHoratiu Vultur 	keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
1295*610c32b2SHoratiu Vultur 	keyfield = vcap_keyfields(vctrl, vt, keyset);
1296*610c32b2SHoratiu Vultur 	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
1297*610c32b2SHoratiu Vultur 	/* Start decoding the streams */
1298*610c32b2SHoratiu Vultur 	for (idx = 0; idx < keyfield_count; ++idx) {
1299*610c32b2SHoratiu Vultur 		if (keyfield[idx].width <= 0)
1300*610c32b2SHoratiu Vultur 			continue;
1301*610c32b2SHoratiu Vultur 		/* First get the mask */
1302*610c32b2SHoratiu Vultur 		memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1303*610c32b2SHoratiu Vultur 		vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
1304*610c32b2SHoratiu Vultur 			       keyfield[idx].offset);
1305*610c32b2SHoratiu Vultur 		vcap_decode_field(maskstream, &miter, keyfield[idx].width,
1306*610c32b2SHoratiu Vultur 				  mask);
1307*610c32b2SHoratiu Vultur 		/* Skip if no mask bits are set */
1308*610c32b2SHoratiu Vultur 		if (vcap_bitarray_zero(keyfield[idx].width, mask))
1309*610c32b2SHoratiu Vultur 			continue;
1310*610c32b2SHoratiu Vultur 		/* Get the key */
1311*610c32b2SHoratiu Vultur 		memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1312*610c32b2SHoratiu Vultur 		vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
1313*610c32b2SHoratiu Vultur 			       keyfield[idx].offset);
1314*610c32b2SHoratiu Vultur 		vcap_decode_field(keystream, &kiter, keyfield[idx].width,
1315*610c32b2SHoratiu Vultur 				  value);
1316*610c32b2SHoratiu Vultur 		vcap_rule_alloc_keyfield(ri, &keyfield[idx], idx, value, mask);
1317*610c32b2SHoratiu Vultur 	}
1318*610c32b2SHoratiu Vultur 	return vcap_set_rule_set_keyset((struct vcap_rule *)ri, keyset);
1319*610c32b2SHoratiu Vultur }
1320*610c32b2SHoratiu Vultur 
1321*610c32b2SHoratiu Vultur /* Read VCAP content into the VCAP cache */
1322*610c32b2SHoratiu Vultur static int vcap_read_rule(struct vcap_rule_internal *ri)
1323*610c32b2SHoratiu Vultur {
1324*610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1325*610c32b2SHoratiu Vultur 	int sw_idx, ent_idx = 0, act_idx = 0;
1326*610c32b2SHoratiu Vultur 	u32 addr = ri->addr;
1327*610c32b2SHoratiu Vultur 
1328*610c32b2SHoratiu Vultur 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
1329*610c32b2SHoratiu Vultur 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
1330*610c32b2SHoratiu Vultur 		return -EINVAL;
1331*610c32b2SHoratiu Vultur 	}
1332*610c32b2SHoratiu Vultur 	vcap_erase_cache(ri);
1333*610c32b2SHoratiu Vultur 	/* Use the values in the streams to read the VCAP cache */
1334*610c32b2SHoratiu Vultur 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
1335*610c32b2SHoratiu Vultur 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
1336*610c32b2SHoratiu Vultur 				       VCAP_SEL_ALL, addr);
1337*610c32b2SHoratiu Vultur 		ri->vctrl->ops->cache_read(ri->ndev, admin,
1338*610c32b2SHoratiu Vultur 					   VCAP_SEL_ENTRY, ent_idx,
1339*610c32b2SHoratiu Vultur 					   ri->keyset_sw_regs);
1340*610c32b2SHoratiu Vultur 		ri->vctrl->ops->cache_read(ri->ndev, admin,
1341*610c32b2SHoratiu Vultur 					   VCAP_SEL_ACTION, act_idx,
1342*610c32b2SHoratiu Vultur 					   ri->actionset_sw_regs);
1343*610c32b2SHoratiu Vultur 		if (sw_idx == 0)
1344*610c32b2SHoratiu Vultur 			ri->vctrl->ops->cache_read(ri->ndev, admin,
1345*610c32b2SHoratiu Vultur 						   VCAP_SEL_COUNTER,
1346*610c32b2SHoratiu Vultur 						   ri->counter_id, 0);
1347*610c32b2SHoratiu Vultur 		ent_idx += ri->keyset_sw_regs;
1348*610c32b2SHoratiu Vultur 		act_idx += ri->actionset_sw_regs;
1349*610c32b2SHoratiu Vultur 	}
1350*610c32b2SHoratiu Vultur 	return 0;
1351*610c32b2SHoratiu Vultur }
1352*610c32b2SHoratiu Vultur 
13538e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */
13548e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri)
13558e10490bSSteen Hegelund {
13568e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
13578e10490bSSteen Hegelund 	int sw_idx, ent_idx = 0, act_idx = 0;
13588e10490bSSteen Hegelund 	u32 addr = ri->addr;
13598e10490bSSteen Hegelund 
13608e10490bSSteen Hegelund 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
13618e10490bSSteen Hegelund 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
13628e10490bSSteen Hegelund 		return -EINVAL;
13638e10490bSSteen Hegelund 	}
13648e10490bSSteen Hegelund 	/* Use the values in the streams to write the VCAP cache */
13658e10490bSSteen Hegelund 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
13668e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
13678e10490bSSteen Hegelund 					    VCAP_SEL_ENTRY, ent_idx,
13688e10490bSSteen Hegelund 					    ri->keyset_sw_regs);
13698e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
13708e10490bSSteen Hegelund 					    VCAP_SEL_ACTION, act_idx,
13718e10490bSSteen Hegelund 					    ri->actionset_sw_regs);
13728e10490bSSteen Hegelund 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
13738e10490bSSteen Hegelund 				       VCAP_SEL_ALL, addr);
13748e10490bSSteen Hegelund 		ent_idx += ri->keyset_sw_regs;
13758e10490bSSteen Hegelund 		act_idx += ri->actionset_sw_regs;
13768e10490bSSteen Hegelund 	}
13778e10490bSSteen Hegelund 	return 0;
13788e10490bSSteen Hegelund }
13798e10490bSSteen Hegelund 
1380f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri,
1381f13230a4SSteen Hegelund 			      struct vcap_counter *ctr)
1382f13230a4SSteen Hegelund {
1383f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1384f13230a4SSteen Hegelund 
1385f13230a4SSteen Hegelund 	admin->cache.counter = ctr->value;
1386f13230a4SSteen Hegelund 	admin->cache.sticky = ctr->sticky;
1387f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
1388f13230a4SSteen Hegelund 				    ri->counter_id, 0);
1389f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
1390f13230a4SSteen Hegelund 			       VCAP_SEL_COUNTER, ri->addr);
1391f13230a4SSteen Hegelund 	return 0;
1392f13230a4SSteen Hegelund }
1393f13230a4SSteen Hegelund 
13947de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */
13957de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
13967de1dcadSSteen Hegelund {
13977de1dcadSSteen Hegelund 	int lookup_first = admin->vinst * admin->lookups_per_instance;
13987de1dcadSSteen Hegelund 	int lookup_last = lookup_first + admin->lookups_per_instance;
13997de1dcadSSteen Hegelund 	int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE;
14007de1dcadSSteen Hegelund 	int cid = admin->first_cid;
14017de1dcadSSteen Hegelund 	int lookup;
14027de1dcadSSteen Hegelund 
14037de1dcadSSteen Hegelund 	for (lookup = lookup_first; lookup < lookup_last; ++lookup,
14047de1dcadSSteen Hegelund 	     cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE)
14057de1dcadSSteen Hegelund 		if (cur_cid >= cid && cur_cid < cid_next)
14067de1dcadSSteen Hegelund 			return lookup;
14077de1dcadSSteen Hegelund 	return 0;
14087de1dcadSSteen Hegelund }
14097de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup);
14107de1dcadSSteen Hegelund 
1411c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */
1412c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
1413c9da1ac1SSteen Hegelund {
1414c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1415c9da1ac1SSteen Hegelund 
14168e10490bSSteen Hegelund 	if (vcap_api_check(vctrl))
14178e10490bSSteen Hegelund 		return NULL;
14188e10490bSSteen Hegelund 
1419c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
1420c9da1ac1SSteen Hegelund 		if (cid >= admin->first_cid && cid <= admin->last_cid)
1421c9da1ac1SSteen Hegelund 			return admin;
1422c9da1ac1SSteen Hegelund 	}
1423c9da1ac1SSteen Hegelund 	return NULL;
1424c9da1ac1SSteen Hegelund }
1425c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin);
1426c9da1ac1SSteen Hegelund 
1427392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */
1428392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid)
1429392d0ab0SSteen Hegelund {
1430392d0ab0SSteen Hegelund 	struct vcap_admin *admin, *next_admin;
1431392d0ab0SSteen Hegelund 	int lookup, next_lookup;
1432392d0ab0SSteen Hegelund 
1433392d0ab0SSteen Hegelund 	/* The offset must be at least one lookup */
1434392d0ab0SSteen Hegelund 	if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
1435392d0ab0SSteen Hegelund 		return false;
1436392d0ab0SSteen Hegelund 
1437392d0ab0SSteen Hegelund 	if (vcap_api_check(vctrl))
1438392d0ab0SSteen Hegelund 		return false;
1439392d0ab0SSteen Hegelund 
1440392d0ab0SSteen Hegelund 	admin = vcap_find_admin(vctrl, cur_cid);
1441392d0ab0SSteen Hegelund 	if (!admin)
1442392d0ab0SSteen Hegelund 		return false;
1443392d0ab0SSteen Hegelund 
1444392d0ab0SSteen Hegelund 	/* If no VCAP contains the next chain, the next chain must be beyond
1445392d0ab0SSteen Hegelund 	 * the last chain in the current VCAP
1446392d0ab0SSteen Hegelund 	 */
1447392d0ab0SSteen Hegelund 	next_admin = vcap_find_admin(vctrl, next_cid);
1448392d0ab0SSteen Hegelund 	if (!next_admin)
1449392d0ab0SSteen Hegelund 		return next_cid > admin->last_cid;
1450392d0ab0SSteen Hegelund 
1451392d0ab0SSteen Hegelund 	lookup = vcap_chain_id_to_lookup(admin, cur_cid);
1452392d0ab0SSteen Hegelund 	next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid);
1453392d0ab0SSteen Hegelund 
1454392d0ab0SSteen Hegelund 	/* Next lookup must be the following lookup */
1455392d0ab0SSteen Hegelund 	if (admin == next_admin || admin->vtype == next_admin->vtype)
1456392d0ab0SSteen Hegelund 		return next_lookup == lookup + 1;
1457392d0ab0SSteen Hegelund 
1458392d0ab0SSteen Hegelund 	/* Must be the first lookup in the next VCAP instance */
1459392d0ab0SSteen Hegelund 	return next_lookup == 0;
1460392d0ab0SSteen Hegelund }
1461392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
1462392d0ab0SSteen Hegelund 
14638e10490bSSteen Hegelund /* Check if there is room for a new rule */
14648e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size)
14658e10490bSSteen Hegelund {
14668e10490bSSteen Hegelund 	if (admin->last_used_addr - size < admin->first_valid_addr) {
14678e10490bSSteen Hegelund 		pr_err("%s:%d: No room for rule size: %u, %u\n",
14688e10490bSSteen Hegelund 		       __func__, __LINE__, size, admin->first_valid_addr);
14698e10490bSSteen Hegelund 		return -ENOSPC;
14708e10490bSSteen Hegelund 	}
14718e10490bSSteen Hegelund 	return 0;
14728e10490bSSteen Hegelund }
14738e10490bSSteen Hegelund 
14748e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */
14758e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule)
14768e10490bSSteen Hegelund {
14778e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
14788e10490bSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
14798e10490bSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
14808e10490bSSteen Hegelund 	const struct vcap_field *fields;
14818e10490bSSteen Hegelund 	const struct vcap_set *kset;
14828e10490bSSteen Hegelund 	int ret = -EINVAL;
14838e10490bSSteen Hegelund 
14848e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, vt, keyset);
14858e10490bSSteen Hegelund 	if (!kset)
14868e10490bSSteen Hegelund 		return ret;
14878e10490bSSteen Hegelund 	if (kset->type_id == (u8)-1)  /* No type field is needed */
14888e10490bSSteen Hegelund 		return 0;
14898e10490bSSteen Hegelund 
14908e10490bSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
14918e10490bSSteen Hegelund 	if (!fields)
14928e10490bSSteen Hegelund 		return -EINVAL;
14938e10490bSSteen Hegelund 	if (fields[VCAP_KF_TYPE].width > 1) {
14948e10490bSSteen Hegelund 		ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE,
14958e10490bSSteen Hegelund 					    kset->type_id, 0xff);
14968e10490bSSteen Hegelund 	} else {
14978e10490bSSteen Hegelund 		if (kset->type_id)
14988e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
14998e10490bSSteen Hegelund 						    VCAP_BIT_1);
15008e10490bSSteen Hegelund 		else
15018e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
15028e10490bSSteen Hegelund 						    VCAP_BIT_0);
15038e10490bSSteen Hegelund 	}
15048e10490bSSteen Hegelund 	return 0;
15058e10490bSSteen Hegelund }
15068e10490bSSteen Hegelund 
1507abc4010dSSteen Hegelund /* Add a keyset to a keyset list */
1508abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
1509abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset)
1510abc4010dSSteen Hegelund {
1511abc4010dSSteen Hegelund 	int idx;
1512abc4010dSSteen Hegelund 
1513abc4010dSSteen Hegelund 	if (keysetlist->cnt < keysetlist->max) {
1514abc4010dSSteen Hegelund 		/* Avoid duplicates */
1515abc4010dSSteen Hegelund 		for (idx = 0; idx < keysetlist->cnt; ++idx)
1516abc4010dSSteen Hegelund 			if (keysetlist->keysets[idx] == keyset)
1517abc4010dSSteen Hegelund 				return keysetlist->cnt < keysetlist->max;
1518abc4010dSSteen Hegelund 		keysetlist->keysets[keysetlist->cnt++] = keyset;
1519abc4010dSSteen Hegelund 	}
1520abc4010dSSteen Hegelund 	return keysetlist->cnt < keysetlist->max;
1521abc4010dSSteen Hegelund }
1522abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add);
1523abc4010dSSteen Hegelund 
1524abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */
1525abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl,
1526abc4010dSSteen Hegelund 			     enum vcap_keyfield_set keyset)
1527abc4010dSSteen Hegelund {
1528abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_set_names[keyset];
1529abc4010dSSteen Hegelund }
1530abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name);
1531abc4010dSSteen Hegelund 
1532abc4010dSSteen Hegelund /* map key field id to a string with the key name */
1533abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl,
1534abc4010dSSteen Hegelund 			       enum vcap_key_field key)
1535abc4010dSSteen Hegelund {
1536abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_names[key];
1537abc4010dSSteen Hegelund }
1538abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name);
1539abc4010dSSteen Hegelund 
15403a792156SSteen Hegelund /* map actionset id to a string with the actionset name */
15413a792156SSteen Hegelund const char *vcap_actionset_name(struct vcap_control *vctrl,
15423a792156SSteen Hegelund 				enum vcap_actionfield_set actionset)
15433a792156SSteen Hegelund {
15443a792156SSteen Hegelund 	return vctrl->stats->actionfield_set_names[actionset];
15453a792156SSteen Hegelund }
15463a792156SSteen Hegelund 
1547242df4f7SSteen Hegelund /* map action field id to a string with the action name */
15483a792156SSteen Hegelund const char *vcap_actionfield_name(struct vcap_control *vctrl,
1549242df4f7SSteen Hegelund 				  enum vcap_action_field action)
1550242df4f7SSteen Hegelund {
1551242df4f7SSteen Hegelund 	return vctrl->stats->actionfield_names[action];
1552242df4f7SSteen Hegelund }
1553242df4f7SSteen Hegelund 
1554abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */
1555abc4010dSSteen Hegelund static const struct vcap_field *
1556abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl,
1557abc4010dSSteen Hegelund 			  enum vcap_type vtype,
1558abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset,
1559abc4010dSSteen Hegelund 			  enum vcap_key_field key)
1560abc4010dSSteen Hegelund {
1561abc4010dSSteen Hegelund 	const struct vcap_field *fields;
1562abc4010dSSteen Hegelund 	int idx, count;
1563abc4010dSSteen Hegelund 
1564abc4010dSSteen Hegelund 	fields = vcap_keyfields(vctrl, vtype, keyset);
1565abc4010dSSteen Hegelund 	if (!fields)
1566abc4010dSSteen Hegelund 		return NULL;
1567abc4010dSSteen Hegelund 
1568abc4010dSSteen Hegelund 	/* Iterate the keyfields of the keyset */
1569abc4010dSSteen Hegelund 	count = vcap_keyfield_count(vctrl, vtype, keyset);
1570abc4010dSSteen Hegelund 	for (idx = 0; idx < count; ++idx) {
1571abc4010dSSteen Hegelund 		if (fields[idx].width == 0)
1572abc4010dSSteen Hegelund 			continue;
1573abc4010dSSteen Hegelund 
1574abc4010dSSteen Hegelund 		if (key == idx)
1575abc4010dSSteen Hegelund 			return &fields[idx];
1576abc4010dSSteen Hegelund 	}
1577abc4010dSSteen Hegelund 
1578abc4010dSSteen Hegelund 	return NULL;
1579abc4010dSSteen Hegelund }
1580abc4010dSSteen Hegelund 
1581abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
1582465a38a2SSteen Hegelund static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri,
1583abc4010dSSteen Hegelund 				    struct vcap_keyset_list *matches)
1584abc4010dSSteen Hegelund {
1585abc4010dSSteen Hegelund 	const struct vcap_client_keyfield *ckf;
1586abc4010dSSteen Hegelund 	int keyset, found, keycount, map_size;
1587abc4010dSSteen Hegelund 	const struct vcap_field **map;
1588abc4010dSSteen Hegelund 	enum vcap_type vtype;
1589abc4010dSSteen Hegelund 
1590abc4010dSSteen Hegelund 	vtype = ri->admin->vtype;
1591abc4010dSSteen Hegelund 	map = ri->vctrl->vcaps[vtype].keyfield_set_map;
1592abc4010dSSteen Hegelund 	map_size = ri->vctrl->vcaps[vtype].keyfield_set_size;
1593abc4010dSSteen Hegelund 
1594abc4010dSSteen Hegelund 	/* Get a count of the keyfields we want to match */
1595abc4010dSSteen Hegelund 	keycount = 0;
1596abc4010dSSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1597abc4010dSSteen Hegelund 		++keycount;
1598abc4010dSSteen Hegelund 
1599abc4010dSSteen Hegelund 	matches->cnt = 0;
1600abc4010dSSteen Hegelund 	/* Iterate the keysets of the VCAP */
1601abc4010dSSteen Hegelund 	for (keyset = 0; keyset < map_size; ++keyset) {
1602abc4010dSSteen Hegelund 		if (!map[keyset])
1603abc4010dSSteen Hegelund 			continue;
1604abc4010dSSteen Hegelund 
1605abc4010dSSteen Hegelund 		/* Iterate the keys in the rule */
1606abc4010dSSteen Hegelund 		found = 0;
1607abc4010dSSteen Hegelund 		list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1608abc4010dSSteen Hegelund 			if (vcap_find_keyset_keyfield(ri->vctrl, vtype,
1609abc4010dSSteen Hegelund 						      keyset, ckf->ctrl.key))
1610abc4010dSSteen Hegelund 				++found;
1611abc4010dSSteen Hegelund 
1612abc4010dSSteen Hegelund 		/* Save the keyset if all keyfields were found */
1613abc4010dSSteen Hegelund 		if (found == keycount)
1614abc4010dSSteen Hegelund 			if (!vcap_keyset_list_add(matches, keyset))
1615abc4010dSSteen Hegelund 				/* bail out when the quota is filled */
1616abc4010dSSteen Hegelund 				break;
1617abc4010dSSteen Hegelund 	}
1618abc4010dSSteen Hegelund 
1619abc4010dSSteen Hegelund 	return matches->cnt > 0;
1620abc4010dSSteen Hegelund }
1621abc4010dSSteen Hegelund 
1622465a38a2SSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
1623465a38a2SSteen Hegelund bool vcap_rule_find_keysets(struct vcap_rule *rule,
1624465a38a2SSteen Hegelund 			    struct vcap_keyset_list *matches)
1625465a38a2SSteen Hegelund {
1626465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1627465a38a2SSteen Hegelund 
1628465a38a2SSteen Hegelund 	return _vcap_rule_find_keysets(ri, matches);
1629465a38a2SSteen Hegelund }
1630465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_find_keysets);
1631465a38a2SSteen Hegelund 
1632c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
1633c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
1634c9da1ac1SSteen Hegelund {
1635c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1636abc4010dSSteen Hegelund 	struct vcap_keyset_list matches = {};
16378e10490bSSteen Hegelund 	enum vcap_keyfield_set keysets[10];
16388e10490bSSteen Hegelund 	int ret;
1639c9da1ac1SSteen Hegelund 
16408e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
16418e10490bSSteen Hegelund 	if (ret)
16428e10490bSSteen Hegelund 		return ret;
1643c9da1ac1SSteen Hegelund 	if (!ri->admin) {
1644c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ADMIN;
1645c9da1ac1SSteen Hegelund 		return -EINVAL;
1646c9da1ac1SSteen Hegelund 	}
1647c9da1ac1SSteen Hegelund 	if (!ri->ndev) {
1648c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_NETDEV;
1649c9da1ac1SSteen Hegelund 		return -EINVAL;
1650c9da1ac1SSteen Hegelund 	}
1651abc4010dSSteen Hegelund 
1652abc4010dSSteen Hegelund 	matches.keysets = keysets;
1653abc4010dSSteen Hegelund 	matches.max = ARRAY_SIZE(keysets);
1654c9da1ac1SSteen Hegelund 	if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
1655abc4010dSSteen Hegelund 		/* Iterate over rule keyfields and select keysets that fits */
1656465a38a2SSteen Hegelund 		if (!_vcap_rule_find_keysets(ri, &matches)) {
1657c9da1ac1SSteen Hegelund 			ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
1658c9da1ac1SSteen Hegelund 			return -EINVAL;
1659c9da1ac1SSteen Hegelund 		}
1660abc4010dSSteen Hegelund 	} else {
16618e10490bSSteen Hegelund 		/* prepare for keyset validation */
16628e10490bSSteen Hegelund 		keysets[0] = ri->data.keyset;
1663abc4010dSSteen Hegelund 		matches.cnt = 1;
1664abc4010dSSteen Hegelund 	}
1665abc4010dSSteen Hegelund 
16668e10490bSSteen Hegelund 	/* Pick a keyset that is supported in the port lookups */
1667abc4010dSSteen Hegelund 	ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule,
1668abc4010dSSteen Hegelund 					      &matches, l3_proto);
16698e10490bSSteen Hegelund 	if (ret < 0) {
16708e10490bSSteen Hegelund 		pr_err("%s:%d: keyset validation failed: %d\n",
16718e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
16728e10490bSSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
16738e10490bSSteen Hegelund 		return ret;
16748e10490bSSteen Hegelund 	}
1675abc4010dSSteen Hegelund 	/* use the keyset that is supported in the port lookups */
1676abc4010dSSteen Hegelund 	ret = vcap_set_rule_set_keyset(rule, ret);
1677abc4010dSSteen Hegelund 	if (ret < 0) {
1678abc4010dSSteen Hegelund 		pr_err("%s:%d: keyset was not updated: %d\n",
1679abc4010dSSteen Hegelund 		       __func__, __LINE__, ret);
1680abc4010dSSteen Hegelund 		return ret;
1681abc4010dSSteen Hegelund 	}
1682c9da1ac1SSteen Hegelund 	if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
1683abc4010dSSteen Hegelund 		/* Later also actionsets will be matched against actions in
1684abc4010dSSteen Hegelund 		 * the rule, and the type will be set accordingly
1685abc4010dSSteen Hegelund 		 */
1686c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
1687c9da1ac1SSteen Hegelund 		return -EINVAL;
1688c9da1ac1SSteen Hegelund 	}
16898e10490bSSteen Hegelund 	vcap_add_type_keyfield(rule);
16908e10490bSSteen Hegelund 	/* Add default fields to this rule */
16918e10490bSSteen Hegelund 	ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
16928e10490bSSteen Hegelund 
16938e10490bSSteen Hegelund 	/* Rule size is the maximum of the entry and action subword count */
16948e10490bSSteen Hegelund 	ri->size = max(ri->keyset_sw, ri->actionset_sw);
16958e10490bSSteen Hegelund 
16968e10490bSSteen Hegelund 	/* Finally check if there is room for the rule in the VCAP */
16978e10490bSSteen Hegelund 	return vcap_rule_space(ri->admin, ri->size);
1698c9da1ac1SSteen Hegelund }
1699c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
1700c9da1ac1SSteen Hegelund 
1701990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key.
1702990e4839SSteen Hegelund  * I.e. Lowest numerical sort_key is first in list.
1703990e4839SSteen Hegelund  * In order to locate largest keys first in list we negate the key size with
1704990e4839SSteen Hegelund  * (max_size - size).
1705990e4839SSteen Hegelund  */
1706990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
1707990e4839SSteen Hegelund {
1708990e4839SSteen Hegelund 	return ((max_size - size) << 24) | (user << 16) | prio;
1709990e4839SSteen Hegelund }
1710990e4839SSteen Hegelund 
17118e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
17128e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
17138e10490bSSteen Hegelund {
17148e10490bSSteen Hegelund 	return ((addr - ri->size) /  ri->size) * ri->size;
17158e10490bSSteen Hegelund }
17168e10490bSSteen Hegelund 
1717c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
1718c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
1719c9da1ac1SSteen Hegelund {
1720c9da1ac1SSteen Hegelund 	if (ri->data.id != 0)
1721c9da1ac1SSteen Hegelund 		return ri->data.id;
1722c9da1ac1SSteen Hegelund 
1723c1d8e3fbSHoratiu Vultur 	for (u32 next_id = 1; next_id < ~0; ++next_id) {
1724c9da1ac1SSteen Hegelund 		if (!vcap_lookup_rule(ri->vctrl, next_id)) {
1725c9da1ac1SSteen Hegelund 			ri->data.id = next_id;
1726c9da1ac1SSteen Hegelund 			break;
1727c9da1ac1SSteen Hegelund 		}
1728c9da1ac1SSteen Hegelund 	}
1729c9da1ac1SSteen Hegelund 	return ri->data.id;
1730c9da1ac1SSteen Hegelund }
1731c9da1ac1SSteen Hegelund 
17328e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
17338e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
17348e10490bSSteen Hegelund {
1735990e4839SSteen Hegelund 	int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
1736990e4839SSteen Hegelund 	struct vcap_rule_internal *duprule, *iter, *elem = NULL;
17378e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1738990e4839SSteen Hegelund 	u32 addr;
17398e10490bSSteen Hegelund 
1740990e4839SSteen Hegelund 	ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
1741990e4839SSteen Hegelund 				     ri->data.priority);
1742990e4839SSteen Hegelund 
1743990e4839SSteen Hegelund 	/* Insert the new rule in the list of rule based on the sort key
1744990e4839SSteen Hegelund 	 * If the rule needs to be  inserted between existing rules then move
1745990e4839SSteen Hegelund 	 * these rules to make room for the new rule and update their start
1746990e4839SSteen Hegelund 	 * address.
1747990e4839SSteen Hegelund 	 */
1748990e4839SSteen Hegelund 	list_for_each_entry(iter, &admin->rules, list) {
1749990e4839SSteen Hegelund 		if (ri->sort_key < iter->sort_key) {
1750990e4839SSteen Hegelund 			elem = iter;
1751990e4839SSteen Hegelund 			break;
1752990e4839SSteen Hegelund 		}
1753990e4839SSteen Hegelund 	}
1754990e4839SSteen Hegelund 
1755990e4839SSteen Hegelund 	if (!elem) {
17568e10490bSSteen Hegelund 		ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
17578e10490bSSteen Hegelund 		admin->last_used_addr = ri->addr;
1758990e4839SSteen Hegelund 
17598e10490bSSteen Hegelund 		/* Add a shallow copy of the rule to the VCAP list */
17608e10490bSSteen Hegelund 		duprule = vcap_dup_rule(ri);
17618e10490bSSteen Hegelund 		if (IS_ERR(duprule))
17628e10490bSSteen Hegelund 			return PTR_ERR(duprule);
1763990e4839SSteen Hegelund 
17648e10490bSSteen Hegelund 		list_add_tail(&duprule->list, &admin->rules);
17658e10490bSSteen Hegelund 		return 0;
17668e10490bSSteen Hegelund 	}
17678e10490bSSteen Hegelund 
1768990e4839SSteen Hegelund 	/* Reuse the space of the current rule */
1769990e4839SSteen Hegelund 	addr = elem->addr + elem->size;
1770990e4839SSteen Hegelund 	ri->addr = vcap_next_rule_addr(addr, ri);
1771990e4839SSteen Hegelund 	addr = ri->addr;
1772990e4839SSteen Hegelund 
1773990e4839SSteen Hegelund 	/* Add a shallow copy of the rule to the VCAP list */
1774990e4839SSteen Hegelund 	duprule = vcap_dup_rule(ri);
1775990e4839SSteen Hegelund 	if (IS_ERR(duprule))
1776990e4839SSteen Hegelund 		return PTR_ERR(duprule);
1777990e4839SSteen Hegelund 
1778990e4839SSteen Hegelund 	/* Add before the current entry */
1779990e4839SSteen Hegelund 	list_add_tail(&duprule->list, &elem->list);
1780990e4839SSteen Hegelund 
1781990e4839SSteen Hegelund 	/* Update the current rule */
1782990e4839SSteen Hegelund 	elem->addr = vcap_next_rule_addr(addr, elem);
1783990e4839SSteen Hegelund 	addr = elem->addr;
1784990e4839SSteen Hegelund 
1785990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1786990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list) {
1787990e4839SSteen Hegelund 		elem->addr = vcap_next_rule_addr(addr, elem);
1788990e4839SSteen Hegelund 		addr = elem->addr;
1789990e4839SSteen Hegelund 	}
1790990e4839SSteen Hegelund 
1791990e4839SSteen Hegelund 	/* Update the move info */
1792990e4839SSteen Hegelund 	move->addr = admin->last_used_addr;
1793990e4839SSteen Hegelund 	move->count = ri->addr - addr;
1794990e4839SSteen Hegelund 	move->offset = admin->last_used_addr - addr;
1795990e4839SSteen Hegelund 	admin->last_used_addr = addr;
1796990e4839SSteen Hegelund 	return 0;
1797990e4839SSteen Hegelund }
1798990e4839SSteen Hegelund 
17998e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
18008e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
18018e10490bSSteen Hegelund {
18028e10490bSSteen Hegelund 	ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
18038e10490bSSteen Hegelund 			 move->offset, move->count);
18048e10490bSSteen Hegelund }
18058e10490bSSteen Hegelund 
1806c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
1807c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
1808c9da1ac1SSteen Hegelund {
18098e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
18108e10490bSSteen Hegelund 	struct vcap_rule_move move = {0};
18118e10490bSSteen Hegelund 	int ret;
18128e10490bSSteen Hegelund 
18138e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
18148e10490bSSteen Hegelund 	if (ret)
18158e10490bSSteen Hegelund 		return ret;
18168e10490bSSteen Hegelund 	/* Insert the new rule in the list of vcap rules */
181771c9de99SSteen Hegelund 	mutex_lock(&ri->admin->lock);
18188e10490bSSteen Hegelund 	ret = vcap_insert_rule(ri, &move);
18198e10490bSSteen Hegelund 	if (ret < 0) {
18208e10490bSSteen Hegelund 		pr_err("%s:%d: could not insert rule in vcap list: %d\n",
18218e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
18228e10490bSSteen Hegelund 		goto out;
18238e10490bSSteen Hegelund 	}
18248e10490bSSteen Hegelund 	if (move.count > 0)
18258e10490bSSteen Hegelund 		vcap_move_rules(ri, &move);
18268e10490bSSteen Hegelund 	ret = vcap_encode_rule(ri);
18278e10490bSSteen Hegelund 	if (ret) {
18288e10490bSSteen Hegelund 		pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
18298e10490bSSteen Hegelund 		goto out;
18308e10490bSSteen Hegelund 	}
18318e10490bSSteen Hegelund 
18328e10490bSSteen Hegelund 	ret = vcap_write_rule(ri);
18338e10490bSSteen Hegelund 	if (ret)
18348e10490bSSteen Hegelund 		pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
18358e10490bSSteen Hegelund out:
183671c9de99SSteen Hegelund 	mutex_unlock(&ri->admin->lock);
18378e10490bSSteen Hegelund 	return ret;
1838c9da1ac1SSteen Hegelund }
1839c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
1840c9da1ac1SSteen Hegelund 
1841c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
1842c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
1843c9da1ac1SSteen Hegelund 				  struct net_device *ndev, int vcap_chain_id,
1844c9da1ac1SSteen Hegelund 				  enum vcap_user user, u16 priority,
1845c9da1ac1SSteen Hegelund 				  u32 id)
1846c9da1ac1SSteen Hegelund {
1847c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
1848c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1849990e4839SSteen Hegelund 	int err, maxsize;
1850c9da1ac1SSteen Hegelund 
1851990e4839SSteen Hegelund 	err = vcap_api_check(vctrl);
1852990e4839SSteen Hegelund 	if (err)
1853990e4839SSteen Hegelund 		return ERR_PTR(err);
1854c9da1ac1SSteen Hegelund 	if (!ndev)
1855c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENODEV);
1856c9da1ac1SSteen Hegelund 	/* Get the VCAP instance */
1857c9da1ac1SSteen Hegelund 	admin = vcap_find_admin(vctrl, vcap_chain_id);
1858c9da1ac1SSteen Hegelund 	if (!admin)
1859c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOENT);
18608e10490bSSteen Hegelund 	/* Sanity check that this VCAP is supported on this platform */
18618e10490bSSteen Hegelund 	if (vctrl->vcaps[admin->vtype].rows == 0)
18628e10490bSSteen Hegelund 		return ERR_PTR(-EINVAL);
18638e10490bSSteen Hegelund 	/* Check if a rule with this id already exists */
18648e10490bSSteen Hegelund 	if (vcap_lookup_rule(vctrl, id))
18658e10490bSSteen Hegelund 		return ERR_PTR(-EEXIST);
18668e10490bSSteen Hegelund 	/* Check if there is room for the rule in the block(s) of the VCAP */
18678e10490bSSteen Hegelund 	maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
18688e10490bSSteen Hegelund 	if (vcap_rule_space(admin, maxsize))
18698e10490bSSteen Hegelund 		return ERR_PTR(-ENOSPC);
1870c9da1ac1SSteen Hegelund 	/* Create a container for the rule and return it */
1871c9da1ac1SSteen Hegelund 	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
1872c9da1ac1SSteen Hegelund 	if (!ri)
1873c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOMEM);
1874c9da1ac1SSteen Hegelund 	ri->data.vcap_chain_id = vcap_chain_id;
1875c9da1ac1SSteen Hegelund 	ri->data.user = user;
1876c9da1ac1SSteen Hegelund 	ri->data.priority = priority;
1877c9da1ac1SSteen Hegelund 	ri->data.id = id;
1878c9da1ac1SSteen Hegelund 	ri->data.keyset = VCAP_KFS_NO_VALUE;
1879c9da1ac1SSteen Hegelund 	ri->data.actionset = VCAP_AFS_NO_VALUE;
1880c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->list);
1881c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.keyfields);
1882c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.actionfields);
1883c9da1ac1SSteen Hegelund 	ri->ndev = ndev;
1884c9da1ac1SSteen Hegelund 	ri->admin = admin; /* refer to the vcap instance */
1885c9da1ac1SSteen Hegelund 	ri->vctrl = vctrl; /* refer to the client */
1886c9da1ac1SSteen Hegelund 	if (vcap_set_rule_id(ri) == 0)
1887c9da1ac1SSteen Hegelund 		goto out_free;
18888e10490bSSteen Hegelund 	vcap_erase_cache(ri);
1889c9da1ac1SSteen Hegelund 	return (struct vcap_rule *)ri;
1890c9da1ac1SSteen Hegelund 
1891c9da1ac1SSteen Hegelund out_free:
1892c9da1ac1SSteen Hegelund 	kfree(ri);
1893c9da1ac1SSteen Hegelund 	return ERR_PTR(-EINVAL);
1894c9da1ac1SSteen Hegelund }
1895c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
1896c9da1ac1SSteen Hegelund 
1897c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
1898c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
1899c9da1ac1SSteen Hegelund {
1900c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1901c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *caf, *next_caf;
1902c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
1903c9da1ac1SSteen Hegelund 
1904c9da1ac1SSteen Hegelund 	/* Deallocate the list of keys and actions */
1905c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
1906c9da1ac1SSteen Hegelund 		list_del(&ckf->ctrl.list);
1907c9da1ac1SSteen Hegelund 		kfree(ckf);
1908c9da1ac1SSteen Hegelund 	}
1909c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
1910c9da1ac1SSteen Hegelund 		list_del(&caf->ctrl.list);
1911c9da1ac1SSteen Hegelund 		kfree(caf);
1912c9da1ac1SSteen Hegelund 	}
1913c9da1ac1SSteen Hegelund 	/* Deallocate the rule */
1914c9da1ac1SSteen Hegelund 	kfree(rule);
1915c9da1ac1SSteen Hegelund }
1916c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
1917c9da1ac1SSteen Hegelund 
1918*610c32b2SHoratiu Vultur struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
1919*610c32b2SHoratiu Vultur {
1920*610c32b2SHoratiu Vultur 	struct vcap_rule_internal *elem;
1921*610c32b2SHoratiu Vultur 	struct vcap_rule_internal *ri;
1922*610c32b2SHoratiu Vultur 	int err;
1923*610c32b2SHoratiu Vultur 
1924*610c32b2SHoratiu Vultur 	ri = NULL;
1925*610c32b2SHoratiu Vultur 
1926*610c32b2SHoratiu Vultur 	err = vcap_api_check(vctrl);
1927*610c32b2SHoratiu Vultur 	if (err)
1928*610c32b2SHoratiu Vultur 		return ERR_PTR(err);
1929*610c32b2SHoratiu Vultur 	elem = vcap_lookup_rule(vctrl, id);
1930*610c32b2SHoratiu Vultur 	if (!elem)
1931*610c32b2SHoratiu Vultur 		return NULL;
1932*610c32b2SHoratiu Vultur 	mutex_lock(&elem->admin->lock);
1933*610c32b2SHoratiu Vultur 	ri = vcap_dup_rule(elem);
1934*610c32b2SHoratiu Vultur 	if (IS_ERR(ri))
1935*610c32b2SHoratiu Vultur 		goto unlock;
1936*610c32b2SHoratiu Vultur 	err = vcap_read_rule(ri);
1937*610c32b2SHoratiu Vultur 	if (err) {
1938*610c32b2SHoratiu Vultur 		ri = ERR_PTR(err);
1939*610c32b2SHoratiu Vultur 		goto unlock;
1940*610c32b2SHoratiu Vultur 	}
1941*610c32b2SHoratiu Vultur 	err = vcap_decode_keyset(ri);
1942*610c32b2SHoratiu Vultur 	if (err) {
1943*610c32b2SHoratiu Vultur 		ri = ERR_PTR(err);
1944*610c32b2SHoratiu Vultur 		goto unlock;
1945*610c32b2SHoratiu Vultur 	}
1946*610c32b2SHoratiu Vultur 	err = vcap_decode_actionset(ri);
1947*610c32b2SHoratiu Vultur 	if (err) {
1948*610c32b2SHoratiu Vultur 		ri = ERR_PTR(err);
1949*610c32b2SHoratiu Vultur 		goto unlock;
1950*610c32b2SHoratiu Vultur 	}
1951*610c32b2SHoratiu Vultur 
1952*610c32b2SHoratiu Vultur unlock:
1953*610c32b2SHoratiu Vultur 	mutex_unlock(&elem->admin->lock);
1954*610c32b2SHoratiu Vultur 	return (struct vcap_rule *)ri;
1955*610c32b2SHoratiu Vultur }
1956*610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_get_rule);
1957*610c32b2SHoratiu Vultur 
1958990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */
1959990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
1960990e4839SSteen Hegelund {
1961990e4839SSteen Hegelund 	return (el->addr + offset) % el->size;
1962990e4839SSteen Hegelund }
1963990e4839SSteen Hegelund 
1964990e4839SSteen Hegelund /* Update the rule address with an offset */
1965990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
1966990e4839SSteen Hegelund {
1967990e4839SSteen Hegelund 	el->addr += offset;
1968990e4839SSteen Hegelund }
1969990e4839SSteen Hegelund 
1970990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */
1971990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
1972990e4839SSteen Hegelund {
1973990e4839SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1974990e4839SSteen Hegelund 	struct vcap_rule_internal *elem;
1975990e4839SSteen Hegelund 	struct vcap_rule_move move;
1976990e4839SSteen Hegelund 	int gap = 0, offset = 0;
1977990e4839SSteen Hegelund 
1978990e4839SSteen Hegelund 	/* If the first rule is deleted: Move other rules to the top */
1979990e4839SSteen Hegelund 	if (list_is_first(&ri->list, &admin->rules))
1980990e4839SSteen Hegelund 		offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
1981990e4839SSteen Hegelund 
1982990e4839SSteen Hegelund 	/* Locate gaps between odd size rules and adjust the move */
1983990e4839SSteen Hegelund 	elem = ri;
1984990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
1985990e4839SSteen Hegelund 		gap += vcap_valid_rule_move(elem, ri->size);
1986990e4839SSteen Hegelund 
1987990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1988990e4839SSteen Hegelund 	elem = ri;
1989990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
1990990e4839SSteen Hegelund 		vcap_adjust_rule_addr(elem, ri->size + gap + offset);
1991990e4839SSteen Hegelund 
1992990e4839SSteen Hegelund 	/* Update the move info */
1993990e4839SSteen Hegelund 	move.addr = admin->last_used_addr;
1994990e4839SSteen Hegelund 	move.count = ri->addr - admin->last_used_addr - gap;
1995990e4839SSteen Hegelund 	move.offset = -(ri->size + gap + offset);
1996990e4839SSteen Hegelund 
1997990e4839SSteen Hegelund 	/* Do the actual move operation */
1998990e4839SSteen Hegelund 	vcap_move_rules(ri, &move);
1999990e4839SSteen Hegelund 
2000990e4839SSteen Hegelund 	return gap + offset;
2001990e4839SSteen Hegelund }
2002990e4839SSteen Hegelund 
2003c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
2004c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
2005c9da1ac1SSteen Hegelund {
2006c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri, *elem;
2007c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
2008990e4839SSteen Hegelund 	int gap = 0, err;
2009c9da1ac1SSteen Hegelund 
2010c9da1ac1SSteen Hegelund 	/* This will later also handle rule moving */
2011c9da1ac1SSteen Hegelund 	if (!ndev)
2012c9da1ac1SSteen Hegelund 		return -ENODEV;
20138e10490bSSteen Hegelund 	err = vcap_api_check(vctrl);
20148e10490bSSteen Hegelund 	if (err)
20158e10490bSSteen Hegelund 		return err;
2016c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
2017c9da1ac1SSteen Hegelund 	ri = vcap_lookup_rule(vctrl, id);
2018c9da1ac1SSteen Hegelund 	if (!ri)
2019c9da1ac1SSteen Hegelund 		return -EINVAL;
2020c9da1ac1SSteen Hegelund 	admin = ri->admin;
20218e10490bSSteen Hegelund 
2022990e4839SSteen Hegelund 	if (ri->addr > admin->last_used_addr)
2023990e4839SSteen Hegelund 		gap = vcap_fill_rule_gap(ri);
2024990e4839SSteen Hegelund 
2025990e4839SSteen Hegelund 	/* Delete the rule from the list of rules and the cache */
202671c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
2027990e4839SSteen Hegelund 	list_del(&ri->list);
2028990e4839SSteen Hegelund 	vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
2029990e4839SSteen Hegelund 	kfree(ri);
203071c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
2031990e4839SSteen Hegelund 
2032277e9179SSteen Hegelund 	/* Update the last used address, set to default when no rules */
2033c9da1ac1SSteen Hegelund 	if (list_empty(&admin->rules)) {
2034277e9179SSteen Hegelund 		admin->last_used_addr = admin->last_valid_addr + 1;
2035c9da1ac1SSteen Hegelund 	} else {
2036990e4839SSteen Hegelund 		elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
2037990e4839SSteen Hegelund 				       list);
2038c9da1ac1SSteen Hegelund 		admin->last_used_addr = elem->addr;
2039c9da1ac1SSteen Hegelund 	}
2040c9da1ac1SSteen Hegelund 	return 0;
2041c9da1ac1SSteen Hegelund }
2042c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
2043c9da1ac1SSteen Hegelund 
20448e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
20458e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
20468e10490bSSteen Hegelund {
204767456717SSteen Hegelund 	struct vcap_enabled_port *eport, *next_eport;
20488e10490bSSteen Hegelund 	struct vcap_rule_internal *ri, *next_ri;
20498e10490bSSteen Hegelund 	int ret = vcap_api_check(vctrl);
20508e10490bSSteen Hegelund 
20518e10490bSSteen Hegelund 	if (ret)
20528e10490bSSteen Hegelund 		return ret;
205371c9de99SSteen Hegelund 
205471c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
20558e10490bSSteen Hegelund 	list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
20568e10490bSSteen Hegelund 		vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
20578e10490bSSteen Hegelund 		list_del(&ri->list);
20588e10490bSSteen Hegelund 		kfree(ri);
20598e10490bSSteen Hegelund 	}
20608e10490bSSteen Hegelund 	admin->last_used_addr = admin->last_valid_addr;
206167456717SSteen Hegelund 
206267456717SSteen Hegelund 	/* Remove list of enabled ports */
206367456717SSteen Hegelund 	list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
206467456717SSteen Hegelund 		list_del(&eport->list);
206567456717SSteen Hegelund 		kfree(eport);
206667456717SSteen Hegelund 	}
206771c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
206867456717SSteen Hegelund 
20698e10490bSSteen Hegelund 	return 0;
20708e10490bSSteen Hegelund }
20718e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
20728e10490bSSteen Hegelund 
2073465a38a2SSteen Hegelund /* Find a client key field in a rule */
2074465a38a2SSteen Hegelund static struct vcap_client_keyfield *
2075465a38a2SSteen Hegelund vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key)
2076465a38a2SSteen Hegelund {
2077465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2078465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
2079465a38a2SSteen Hegelund 
2080465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2081465a38a2SSteen Hegelund 		if (ckf->ctrl.key == key)
2082465a38a2SSteen Hegelund 			return ckf;
2083465a38a2SSteen Hegelund 	return NULL;
2084465a38a2SSteen Hegelund }
2085465a38a2SSteen Hegelund 
208646be056eSSteen Hegelund /* Find information on a key field in a rule */
208746be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
208846be056eSSteen Hegelund 					      enum vcap_key_field key)
208946be056eSSteen Hegelund {
20908e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
209146be056eSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
209246be056eSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
209346be056eSSteen Hegelund 	const struct vcap_field *fields;
209446be056eSSteen Hegelund 
209546be056eSSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
209646be056eSSteen Hegelund 		return NULL;
209746be056eSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
209846be056eSSteen Hegelund 	if (!fields)
209946be056eSSteen Hegelund 		return NULL;
210046be056eSSteen Hegelund 	return &fields[key];
210146be056eSSteen Hegelund }
210246be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
210346be056eSSteen Hegelund 
21044f141e36SHoratiu Vultur /* Copy data from src to dst but reverse the data in chunks of 32bits.
21054f141e36SHoratiu Vultur  * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will
21064f141e36SHoratiu Vultur  * have the value 22:33:44:55:00:11.
21074f141e36SHoratiu Vultur  */
21084f141e36SHoratiu Vultur static void vcap_copy_to_w32be(u8 *dst, u8 *src, int size)
21094f141e36SHoratiu Vultur {
21104f141e36SHoratiu Vultur 	for (int idx = 0; idx < size; ++idx) {
21114f141e36SHoratiu Vultur 		int first_byte_index = 0;
21124f141e36SHoratiu Vultur 		int nidx;
21134f141e36SHoratiu Vultur 
21144f141e36SHoratiu Vultur 		first_byte_index = size - (((idx >> 2) + 1) << 2);
21154f141e36SHoratiu Vultur 		if (first_byte_index < 0)
21164f141e36SHoratiu Vultur 			first_byte_index = 0;
21174f141e36SHoratiu Vultur 		nidx = idx + first_byte_index - (idx & ~0x3);
21184f141e36SHoratiu Vultur 		dst[nidx] = src[idx];
21194f141e36SHoratiu Vultur 	}
21204f141e36SHoratiu Vultur }
21214f141e36SHoratiu Vultur 
2122c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule,
2123c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield *field,
2124c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield_data *data)
2125c9da1ac1SSteen Hegelund {
21264f141e36SHoratiu Vultur 	struct vcap_rule_internal *ri = to_intrule(rule);
21274f141e36SHoratiu Vultur 	int size;
21284f141e36SHoratiu Vultur 
21294f141e36SHoratiu Vultur 	if (!ri->admin->w32be) {
2130c9da1ac1SSteen Hegelund 		memcpy(&field->data, data, sizeof(field->data));
21314f141e36SHoratiu Vultur 		return;
21324f141e36SHoratiu Vultur 	}
21334f141e36SHoratiu Vultur 
21344f141e36SHoratiu Vultur 	size = keyfield_size_table[field->ctrl.type] / 2;
21354f141e36SHoratiu Vultur 	switch (field->ctrl.type) {
21364f141e36SHoratiu Vultur 	case VCAP_FIELD_BIT:
21374f141e36SHoratiu Vultur 	case VCAP_FIELD_U32:
21384f141e36SHoratiu Vultur 		memcpy(&field->data, data, sizeof(field->data));
21394f141e36SHoratiu Vultur 		break;
21404f141e36SHoratiu Vultur 	case VCAP_FIELD_U48:
21414f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size);
21424f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u48.mask,  data->u48.mask, size);
21434f141e36SHoratiu Vultur 		break;
21444f141e36SHoratiu Vultur 	case VCAP_FIELD_U56:
21454f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size);
21464f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u56.mask,  data->u56.mask, size);
21474f141e36SHoratiu Vultur 		break;
21484f141e36SHoratiu Vultur 	case VCAP_FIELD_U64:
21494f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size);
21504f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u64.mask,  data->u64.mask, size);
21514f141e36SHoratiu Vultur 		break;
21524f141e36SHoratiu Vultur 	case VCAP_FIELD_U72:
21534f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size);
21544f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u72.mask,  data->u72.mask, size);
21554f141e36SHoratiu Vultur 		break;
21564f141e36SHoratiu Vultur 	case VCAP_FIELD_U112:
21574f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size);
21584f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u112.mask,  data->u112.mask, size);
21594f141e36SHoratiu Vultur 		break;
21604f141e36SHoratiu Vultur 	case VCAP_FIELD_U128:
21614f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size);
21624f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u128.mask,  data->u128.mask, size);
21634f141e36SHoratiu Vultur 		break;
21644f141e36SHoratiu Vultur 	};
2165c9da1ac1SSteen Hegelund }
2166c9da1ac1SSteen Hegelund 
2167242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */
2168242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule,
2169242df4f7SSteen Hegelund 				 enum vcap_key_field key)
2170242df4f7SSteen Hegelund {
2171242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2172242df4f7SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
2173242df4f7SSteen Hegelund 
2174242df4f7SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2175242df4f7SSteen Hegelund 		if (ckf->ctrl.key == key)
2176242df4f7SSteen Hegelund 			return false;
2177242df4f7SSteen Hegelund 	return true;
2178242df4f7SSteen Hegelund }
2179242df4f7SSteen Hegelund 
2180242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */
2181242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule,
2182242df4f7SSteen Hegelund 				       enum vcap_key_field key)
2183242df4f7SSteen Hegelund {
2184242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2185242df4f7SSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
2186242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
2187242df4f7SSteen Hegelund 	const struct vcap_field *fields;
2188242df4f7SSteen Hegelund 
2189242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no keyset yet */
2190242df4f7SSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
2191242df4f7SSteen Hegelund 		return true;
2192242df4f7SSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
2193242df4f7SSteen Hegelund 	if (!fields)
2194242df4f7SSteen Hegelund 		return false;
2195242df4f7SSteen Hegelund 	/* if there is a width there is a way */
2196242df4f7SSteen Hegelund 	return fields[key].width > 0;
2197242df4f7SSteen Hegelund }
2198242df4f7SSteen Hegelund 
2199c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
2200c9da1ac1SSteen Hegelund 			     enum vcap_key_field key,
2201c9da1ac1SSteen Hegelund 			     enum vcap_field_type ftype,
2202c9da1ac1SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
2203c9da1ac1SSteen Hegelund {
2204242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2205c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *field;
2206c9da1ac1SSteen Hegelund 
2207242df4f7SSteen Hegelund 	if (!vcap_keyfield_unique(rule, key)) {
2208242df4f7SSteen Hegelund 		pr_warn("%s:%d: keyfield %s is already in the rule\n",
2209242df4f7SSteen Hegelund 			__func__, __LINE__,
2210242df4f7SSteen Hegelund 			vcap_keyfield_name(ri->vctrl, key));
2211242df4f7SSteen Hegelund 		return -EINVAL;
2212242df4f7SSteen Hegelund 	}
2213242df4f7SSteen Hegelund 
2214242df4f7SSteen Hegelund 	if (!vcap_keyfield_match_keyset(rule, key)) {
2215242df4f7SSteen Hegelund 		pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n",
2216242df4f7SSteen Hegelund 		       __func__, __LINE__,
2217242df4f7SSteen Hegelund 		       vcap_keyfield_name(ri->vctrl, key));
2218242df4f7SSteen Hegelund 		return -EINVAL;
2219242df4f7SSteen Hegelund 	}
2220242df4f7SSteen Hegelund 
2221c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
2222c9da1ac1SSteen Hegelund 	if (!field)
2223c9da1ac1SSteen Hegelund 		return -ENOMEM;
2224c9da1ac1SSteen Hegelund 	field->ctrl.key = key;
2225c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
2226c9da1ac1SSteen Hegelund 	vcap_copy_from_client_keyfield(rule, field, data);
2227c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->keyfields);
2228c9da1ac1SSteen Hegelund 	return 0;
2229c9da1ac1SSteen Hegelund }
2230c9da1ac1SSteen Hegelund 
223146be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
223246be056eSSteen Hegelund {
223346be056eSSteen Hegelund 	switch (val) {
223446be056eSSteen Hegelund 	case VCAP_BIT_0:
223546be056eSSteen Hegelund 		u1->value = 0;
223646be056eSSteen Hegelund 		u1->mask = 1;
223746be056eSSteen Hegelund 		break;
223846be056eSSteen Hegelund 	case VCAP_BIT_1:
223946be056eSSteen Hegelund 		u1->value = 1;
224046be056eSSteen Hegelund 		u1->mask = 1;
224146be056eSSteen Hegelund 		break;
224246be056eSSteen Hegelund 	case VCAP_BIT_ANY:
224346be056eSSteen Hegelund 		u1->value = 0;
224446be056eSSteen Hegelund 		u1->mask = 0;
224546be056eSSteen Hegelund 		break;
224646be056eSSteen Hegelund 	}
224746be056eSSteen Hegelund }
224846be056eSSteen Hegelund 
224946be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
225046be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
225146be056eSSteen Hegelund 			  enum vcap_bit val)
225246be056eSSteen Hegelund {
225346be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
225446be056eSSteen Hegelund 
225546be056eSSteen Hegelund 	vcap_rule_set_key_bitsize(&data.u1, val);
225646be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
225746be056eSSteen Hegelund }
225846be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
225946be056eSSteen Hegelund 
226046be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
226146be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
226246be056eSSteen Hegelund 			  u32 value, u32 mask)
226346be056eSSteen Hegelund {
226446be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
226546be056eSSteen Hegelund 
226646be056eSSteen Hegelund 	data.u32.value = value;
226746be056eSSteen Hegelund 	data.u32.mask = mask;
226846be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
226946be056eSSteen Hegelund }
227046be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
227146be056eSSteen Hegelund 
2272c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
2273c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
2274c9da1ac1SSteen Hegelund 			  struct vcap_u48_key *fieldval)
2275c9da1ac1SSteen Hegelund {
2276c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield_data data;
2277c9da1ac1SSteen Hegelund 
2278c9da1ac1SSteen Hegelund 	memcpy(&data.u48, fieldval, sizeof(data.u48));
2279c9da1ac1SSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
2280c9da1ac1SSteen Hegelund }
2281c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
2282c9da1ac1SSteen Hegelund 
228346be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
228446be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
228546be056eSSteen Hegelund 			  struct vcap_u72_key *fieldval)
228646be056eSSteen Hegelund {
228746be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
228846be056eSSteen Hegelund 
228946be056eSSteen Hegelund 	memcpy(&data.u72, fieldval, sizeof(data.u72));
229046be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
229146be056eSSteen Hegelund }
229246be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
229346be056eSSteen Hegelund 
2294d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
2295d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
2296d6c2964dSSteen Hegelund 			   struct vcap_u128_key *fieldval)
2297d6c2964dSSteen Hegelund {
2298d6c2964dSSteen Hegelund 	struct vcap_client_keyfield_data data;
2299d6c2964dSSteen Hegelund 
2300d6c2964dSSteen Hegelund 	memcpy(&data.u128, fieldval, sizeof(data.u128));
2301d6c2964dSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
2302d6c2964dSSteen Hegelund }
2303d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
2304d6c2964dSSteen Hegelund 
2305465a38a2SSteen Hegelund /* Find a client action field in a rule */
2306465a38a2SSteen Hegelund static struct vcap_client_actionfield *
2307465a38a2SSteen Hegelund vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act)
2308465a38a2SSteen Hegelund {
2309465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule;
2310465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
2311465a38a2SSteen Hegelund 
2312465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2313465a38a2SSteen Hegelund 		if (caf->ctrl.action == act)
2314465a38a2SSteen Hegelund 			return caf;
2315465a38a2SSteen Hegelund 	return NULL;
2316465a38a2SSteen Hegelund }
2317465a38a2SSteen Hegelund 
2318c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule,
2319c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield *field,
2320c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield_data *data)
2321c9da1ac1SSteen Hegelund {
23224f141e36SHoratiu Vultur 	struct vcap_rule_internal *ri = to_intrule(rule);
23234f141e36SHoratiu Vultur 	int size;
23244f141e36SHoratiu Vultur 
23254f141e36SHoratiu Vultur 	if (!ri->admin->w32be) {
2326c9da1ac1SSteen Hegelund 		memcpy(&field->data, data, sizeof(field->data));
23274f141e36SHoratiu Vultur 		return;
23284f141e36SHoratiu Vultur 	}
23294f141e36SHoratiu Vultur 
23304f141e36SHoratiu Vultur 	size = actionfield_size_table[field->ctrl.type];
23314f141e36SHoratiu Vultur 	switch (field->ctrl.type) {
23324f141e36SHoratiu Vultur 	case VCAP_FIELD_BIT:
23334f141e36SHoratiu Vultur 	case VCAP_FIELD_U32:
23344f141e36SHoratiu Vultur 		memcpy(&field->data, data, sizeof(field->data));
23354f141e36SHoratiu Vultur 		break;
23364f141e36SHoratiu Vultur 	case VCAP_FIELD_U48:
23374f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size);
23384f141e36SHoratiu Vultur 		break;
23394f141e36SHoratiu Vultur 	case VCAP_FIELD_U56:
23404f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size);
23414f141e36SHoratiu Vultur 		break;
23424f141e36SHoratiu Vultur 	case VCAP_FIELD_U64:
23434f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size);
23444f141e36SHoratiu Vultur 		break;
23454f141e36SHoratiu Vultur 	case VCAP_FIELD_U72:
23464f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size);
23474f141e36SHoratiu Vultur 		break;
23484f141e36SHoratiu Vultur 	case VCAP_FIELD_U112:
23494f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size);
23504f141e36SHoratiu Vultur 		break;
23514f141e36SHoratiu Vultur 	case VCAP_FIELD_U128:
23524f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size);
23534f141e36SHoratiu Vultur 		break;
23544f141e36SHoratiu Vultur 	};
2355c9da1ac1SSteen Hegelund }
2356c9da1ac1SSteen Hegelund 
2357242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */
2358242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule,
2359242df4f7SSteen Hegelund 				    enum vcap_action_field act)
2360242df4f7SSteen Hegelund {
2361242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2362242df4f7SSteen Hegelund 	const struct vcap_client_actionfield *caf;
2363242df4f7SSteen Hegelund 
2364242df4f7SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2365242df4f7SSteen Hegelund 		if (caf->ctrl.action == act)
2366242df4f7SSteen Hegelund 			return false;
2367242df4f7SSteen Hegelund 	return true;
2368242df4f7SSteen Hegelund }
2369242df4f7SSteen Hegelund 
2370242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */
2371242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule,
2372242df4f7SSteen Hegelund 					     enum vcap_action_field action)
2373242df4f7SSteen Hegelund {
2374242df4f7SSteen Hegelund 	enum vcap_actionfield_set actionset = rule->actionset;
2375242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2376242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
2377242df4f7SSteen Hegelund 	const struct vcap_field *fields;
2378242df4f7SSteen Hegelund 
2379242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no actionset yet */
2380242df4f7SSteen Hegelund 	if (actionset == VCAP_AFS_NO_VALUE)
2381242df4f7SSteen Hegelund 		return true;
2382242df4f7SSteen Hegelund 	fields = vcap_actionfields(ri->vctrl, vt, actionset);
2383242df4f7SSteen Hegelund 	if (!fields)
2384242df4f7SSteen Hegelund 		return false;
2385242df4f7SSteen Hegelund 	/* if there is a width there is a way */
2386242df4f7SSteen Hegelund 	return fields[action].width > 0;
2387242df4f7SSteen Hegelund }
2388242df4f7SSteen Hegelund 
2389c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
2390c9da1ac1SSteen Hegelund 				enum vcap_action_field action,
2391c9da1ac1SSteen Hegelund 				enum vcap_field_type ftype,
2392c9da1ac1SSteen Hegelund 				struct vcap_client_actionfield_data *data)
2393c9da1ac1SSteen Hegelund {
2394242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2395c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *field;
2396c9da1ac1SSteen Hegelund 
2397242df4f7SSteen Hegelund 	if (!vcap_actionfield_unique(rule, action)) {
2398242df4f7SSteen Hegelund 		pr_warn("%s:%d: actionfield %s is already in the rule\n",
2399242df4f7SSteen Hegelund 			__func__, __LINE__,
2400242df4f7SSteen Hegelund 			vcap_actionfield_name(ri->vctrl, action));
2401242df4f7SSteen Hegelund 		return -EINVAL;
2402242df4f7SSteen Hegelund 	}
2403242df4f7SSteen Hegelund 
2404242df4f7SSteen Hegelund 	if (!vcap_actionfield_match_actionset(rule, action)) {
2405242df4f7SSteen Hegelund 		pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n",
2406242df4f7SSteen Hegelund 		       __func__, __LINE__,
2407242df4f7SSteen Hegelund 		       vcap_actionfield_name(ri->vctrl, action));
2408242df4f7SSteen Hegelund 		return -EINVAL;
2409242df4f7SSteen Hegelund 	}
2410242df4f7SSteen Hegelund 
2411c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
2412c9da1ac1SSteen Hegelund 	if (!field)
2413c9da1ac1SSteen Hegelund 		return -ENOMEM;
2414c9da1ac1SSteen Hegelund 	field->ctrl.action = action;
2415c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
2416c9da1ac1SSteen Hegelund 	vcap_copy_from_client_actionfield(rule, field, data);
2417c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->actionfields);
2418c9da1ac1SSteen Hegelund 	return 0;
2419c9da1ac1SSteen Hegelund }
2420c9da1ac1SSteen Hegelund 
2421c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
2422c9da1ac1SSteen Hegelund 					 enum vcap_bit val)
2423c9da1ac1SSteen Hegelund {
2424c9da1ac1SSteen Hegelund 	switch (val) {
2425c9da1ac1SSteen Hegelund 	case VCAP_BIT_0:
2426c9da1ac1SSteen Hegelund 		u1->value = 0;
2427c9da1ac1SSteen Hegelund 		break;
2428c9da1ac1SSteen Hegelund 	case VCAP_BIT_1:
2429c9da1ac1SSteen Hegelund 		u1->value = 1;
2430c9da1ac1SSteen Hegelund 		break;
2431c9da1ac1SSteen Hegelund 	case VCAP_BIT_ANY:
2432c9da1ac1SSteen Hegelund 		u1->value = 0;
2433c9da1ac1SSteen Hegelund 		break;
2434c9da1ac1SSteen Hegelund 	}
2435c9da1ac1SSteen Hegelund }
2436c9da1ac1SSteen Hegelund 
2437c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
2438c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
2439c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
2440c9da1ac1SSteen Hegelund 			     enum vcap_bit val)
2441c9da1ac1SSteen Hegelund {
2442c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
2443c9da1ac1SSteen Hegelund 
2444c9da1ac1SSteen Hegelund 	vcap_rule_set_action_bitsize(&data.u1, val);
2445c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
2446c9da1ac1SSteen Hegelund }
2447c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
2448c9da1ac1SSteen Hegelund 
2449c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
2450c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
2451c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
2452c9da1ac1SSteen Hegelund 			     u32 value)
2453c9da1ac1SSteen Hegelund {
2454c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
2455c9da1ac1SSteen Hegelund 
2456c9da1ac1SSteen Hegelund 	data.u32.value = value;
2457c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
2458c9da1ac1SSteen Hegelund }
2459c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
2460c9da1ac1SSteen Hegelund 
2461f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri,
2462f13230a4SSteen Hegelund 			     struct vcap_counter *ctr)
2463f13230a4SSteen Hegelund {
2464f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
2465f13230a4SSteen Hegelund 
2466f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
2467f13230a4SSteen Hegelund 			       ri->addr);
2468f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
2469f13230a4SSteen Hegelund 				   ri->counter_id, 0);
2470f13230a4SSteen Hegelund 	ctr->value = admin->cache.counter;
2471f13230a4SSteen Hegelund 	ctr->sticky = admin->cache.sticky;
2472f13230a4SSteen Hegelund 	return 0;
2473f13230a4SSteen Hegelund }
2474f13230a4SSteen Hegelund 
2475c9da1ac1SSteen Hegelund /* Copy to host byte order */
2476c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
2477c9da1ac1SSteen Hegelund {
2478c9da1ac1SSteen Hegelund 	int idx;
2479c9da1ac1SSteen Hegelund 
2480c9da1ac1SSteen Hegelund 	for (idx = 0; idx < count; ++idx, ++dst)
2481c9da1ac1SSteen Hegelund 		*dst = src[count - idx - 1];
2482c9da1ac1SSteen Hegelund }
2483c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
2484c9da1ac1SSteen Hegelund 
2485c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */
2486c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
2487c9da1ac1SSteen Hegelund {
2488c9da1ac1SSteen Hegelund 	switch (vrule->exterr) {
2489c9da1ac1SSteen Hegelund 	case VCAP_ERR_NONE:
2490c9da1ac1SSteen Hegelund 		break;
2491c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ADMIN:
2492c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2493c9da1ac1SSteen Hegelund 				   "Missing VCAP instance");
2494c9da1ac1SSteen Hegelund 		break;
2495c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_NETDEV:
2496c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2497c9da1ac1SSteen Hegelund 				   "Missing network interface");
2498c9da1ac1SSteen Hegelund 		break;
2499c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_KEYSET_MATCH:
2500c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2501c9da1ac1SSteen Hegelund 				   "No keyset matched the filter keys");
2502c9da1ac1SSteen Hegelund 		break;
2503c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ACTIONSET_MATCH:
2504c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2505c9da1ac1SSteen Hegelund 				   "No actionset matched the filter actions");
2506c9da1ac1SSteen Hegelund 		break;
2507c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_PORT_KEYSET_MATCH:
2508c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2509c9da1ac1SSteen Hegelund 				   "No port keyset matched the filter keys");
2510c9da1ac1SSteen Hegelund 		break;
2511c9da1ac1SSteen Hegelund 	}
2512c9da1ac1SSteen Hegelund }
2513c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
251467d63751SSteen Hegelund 
251567456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */
251667456717SSteen Hegelund static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev,
251767456717SSteen Hegelund 			    unsigned long cookie)
251867456717SSteen Hegelund {
251967456717SSteen Hegelund 	struct vcap_enabled_port *eport;
252067456717SSteen Hegelund 
252167456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list)
252267456717SSteen Hegelund 		if (eport->cookie == cookie || eport->ndev == ndev)
252367456717SSteen Hegelund 			return true;
252467456717SSteen Hegelund 
252567456717SSteen Hegelund 	return false;
252667456717SSteen Hegelund }
252767456717SSteen Hegelund 
252867456717SSteen Hegelund /* Enable this port for this VCAP instance */
252967456717SSteen Hegelund static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,
253067456717SSteen Hegelund 		       unsigned long cookie)
253167456717SSteen Hegelund {
253267456717SSteen Hegelund 	struct vcap_enabled_port *eport;
253367456717SSteen Hegelund 
253467456717SSteen Hegelund 	eport = kzalloc(sizeof(*eport), GFP_KERNEL);
253567456717SSteen Hegelund 	if (!eport)
253667456717SSteen Hegelund 		return -ENOMEM;
253767456717SSteen Hegelund 
253867456717SSteen Hegelund 	eport->ndev = ndev;
253967456717SSteen Hegelund 	eport->cookie = cookie;
254067456717SSteen Hegelund 	list_add_tail(&eport->list, &admin->enabled);
254167456717SSteen Hegelund 
254267456717SSteen Hegelund 	return 0;
254367456717SSteen Hegelund }
254467456717SSteen Hegelund 
254567456717SSteen Hegelund /* Disable this port for this VCAP instance */
254667456717SSteen Hegelund static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev,
254767456717SSteen Hegelund 			unsigned long cookie)
254867456717SSteen Hegelund {
254967456717SSteen Hegelund 	struct vcap_enabled_port *eport;
255067456717SSteen Hegelund 
255167456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list) {
255267456717SSteen Hegelund 		if (eport->cookie == cookie && eport->ndev == ndev) {
255367456717SSteen Hegelund 			list_del(&eport->list);
255467456717SSteen Hegelund 			kfree(eport);
255567456717SSteen Hegelund 			return 0;
255667456717SSteen Hegelund 		}
255767456717SSteen Hegelund 	}
255867456717SSteen Hegelund 
255967456717SSteen Hegelund 	return -ENOENT;
256067456717SSteen Hegelund }
256167456717SSteen Hegelund 
256267456717SSteen Hegelund /* Find the VCAP instance that enabled the port using a specific filter */
256367456717SSteen Hegelund static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl,
256467456717SSteen Hegelund 						    unsigned long cookie)
256567456717SSteen Hegelund {
256667456717SSteen Hegelund 	struct vcap_enabled_port *eport;
256767456717SSteen Hegelund 	struct vcap_admin *admin;
256867456717SSteen Hegelund 
256967456717SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
257067456717SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list)
257167456717SSteen Hegelund 			if (eport->cookie == cookie)
257267456717SSteen Hegelund 				return admin;
257367456717SSteen Hegelund 
257467456717SSteen Hegelund 	return NULL;
257567456717SSteen Hegelund }
257667456717SSteen Hegelund 
257767456717SSteen Hegelund /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
257867456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
257967456717SSteen Hegelund 			int chain_id, unsigned long cookie, bool enable)
258067456717SSteen Hegelund {
258167456717SSteen Hegelund 	struct vcap_admin *admin;
258267456717SSteen Hegelund 	int err;
258367456717SSteen Hegelund 
258467456717SSteen Hegelund 	err = vcap_api_check(vctrl);
258567456717SSteen Hegelund 	if (err)
258667456717SSteen Hegelund 		return err;
258767456717SSteen Hegelund 
258867456717SSteen Hegelund 	if (!ndev)
258967456717SSteen Hegelund 		return -ENODEV;
259067456717SSteen Hegelund 
259167456717SSteen Hegelund 	if (chain_id)
259267456717SSteen Hegelund 		admin = vcap_find_admin(vctrl, chain_id);
259367456717SSteen Hegelund 	else
259467456717SSteen Hegelund 		admin = vcap_find_admin_by_cookie(vctrl, cookie);
259567456717SSteen Hegelund 	if (!admin)
259667456717SSteen Hegelund 		return -ENOENT;
259767456717SSteen Hegelund 
259867456717SSteen Hegelund 	/* first instance and first chain */
259967456717SSteen Hegelund 	if (admin->vinst || chain_id > admin->first_cid)
260067456717SSteen Hegelund 		return -EFAULT;
260167456717SSteen Hegelund 
260267456717SSteen Hegelund 	err = vctrl->ops->enable(ndev, admin, enable);
260367456717SSteen Hegelund 	if (err)
260467456717SSteen Hegelund 		return err;
260567456717SSteen Hegelund 
260667456717SSteen Hegelund 	if (chain_id) {
260767456717SSteen Hegelund 		if (vcap_is_enabled(admin, ndev, cookie))
260867456717SSteen Hegelund 			return -EADDRINUSE;
260971c9de99SSteen Hegelund 		mutex_lock(&admin->lock);
261067456717SSteen Hegelund 		vcap_enable(admin, ndev, cookie);
261167456717SSteen Hegelund 	} else {
261271c9de99SSteen Hegelund 		mutex_lock(&admin->lock);
261367456717SSteen Hegelund 		vcap_disable(admin, ndev, cookie);
261467456717SSteen Hegelund 	}
261571c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
261667456717SSteen Hegelund 
261767456717SSteen Hegelund 	return 0;
261867456717SSteen Hegelund }
261967456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups);
262067456717SSteen Hegelund 
2621f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */
2622f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
2623f13230a4SSteen Hegelund {
2624f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2625f13230a4SSteen Hegelund 
2626f13230a4SSteen Hegelund 	ri->counter_id = counter_id;
2627f13230a4SSteen Hegelund }
2628f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
2629f13230a4SSteen Hegelund 
263040e7fe18SSteen Hegelund /* Provide all rules via a callback interface */
263140e7fe18SSteen Hegelund int vcap_rule_iter(struct vcap_control *vctrl,
263240e7fe18SSteen Hegelund 		   int (*callback)(void *, struct vcap_rule *), void *arg)
263340e7fe18SSteen Hegelund {
263440e7fe18SSteen Hegelund 	struct vcap_rule_internal *ri;
263540e7fe18SSteen Hegelund 	struct vcap_admin *admin;
263640e7fe18SSteen Hegelund 	int ret;
263740e7fe18SSteen Hegelund 
263840e7fe18SSteen Hegelund 	ret = vcap_api_check(vctrl);
263940e7fe18SSteen Hegelund 	if (ret)
264040e7fe18SSteen Hegelund 		return ret;
264140e7fe18SSteen Hegelund 
264240e7fe18SSteen Hegelund 	/* Iterate all rules in each VCAP instance */
264340e7fe18SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
264440e7fe18SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
264540e7fe18SSteen Hegelund 			ret = callback(arg, &ri->data);
264640e7fe18SSteen Hegelund 			if (ret)
264740e7fe18SSteen Hegelund 				return ret;
264840e7fe18SSteen Hegelund 		}
264940e7fe18SSteen Hegelund 	}
265040e7fe18SSteen Hegelund 
265140e7fe18SSteen Hegelund 	return 0;
265240e7fe18SSteen Hegelund }
265340e7fe18SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_iter);
265440e7fe18SSteen Hegelund 
2655f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
2656f13230a4SSteen Hegelund {
2657f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2658f13230a4SSteen Hegelund 	int err;
2659f13230a4SSteen Hegelund 
2660f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2661f13230a4SSteen Hegelund 	if (err)
2662f13230a4SSteen Hegelund 		return err;
2663f13230a4SSteen Hegelund 	if (!ctr) {
2664f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
2665f13230a4SSteen Hegelund 		return -EINVAL;
2666f13230a4SSteen Hegelund 	}
2667f13230a4SSteen Hegelund 	return vcap_write_counter(ri, ctr);
2668f13230a4SSteen Hegelund }
2669f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
2670f13230a4SSteen Hegelund 
2671f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
2672f13230a4SSteen Hegelund {
2673f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2674f13230a4SSteen Hegelund 	int err;
2675f13230a4SSteen Hegelund 
2676f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2677f13230a4SSteen Hegelund 	if (err)
2678f13230a4SSteen Hegelund 		return err;
2679f13230a4SSteen Hegelund 	if (!ctr) {
2680f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
2681f13230a4SSteen Hegelund 		return -EINVAL;
2682f13230a4SSteen Hegelund 	}
2683f13230a4SSteen Hegelund 	return vcap_read_counter(ri, ctr);
2684f13230a4SSteen Hegelund }
2685f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
2686f13230a4SSteen Hegelund 
2687465a38a2SSteen Hegelund static int vcap_rule_mod_key(struct vcap_rule *rule,
2688465a38a2SSteen Hegelund 			     enum vcap_key_field key,
2689465a38a2SSteen Hegelund 			     enum vcap_field_type ftype,
2690465a38a2SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
2691465a38a2SSteen Hegelund {
2692465a38a2SSteen Hegelund 	struct vcap_client_keyfield *field;
2693465a38a2SSteen Hegelund 
2694465a38a2SSteen Hegelund 	field = vcap_find_keyfield(rule, key);
2695465a38a2SSteen Hegelund 	if (!field)
2696465a38a2SSteen Hegelund 		return vcap_rule_add_key(rule, key, ftype, data);
2697465a38a2SSteen Hegelund 	vcap_copy_from_client_keyfield(rule, field, data);
2698465a38a2SSteen Hegelund 	return 0;
2699465a38a2SSteen Hegelund }
2700465a38a2SSteen Hegelund 
2701465a38a2SSteen Hegelund /* Modify a 32 bit key field with value and mask in the rule */
2702465a38a2SSteen Hegelund int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
2703465a38a2SSteen Hegelund 			  u32 value, u32 mask)
2704465a38a2SSteen Hegelund {
2705465a38a2SSteen Hegelund 	struct vcap_client_keyfield_data data;
2706465a38a2SSteen Hegelund 
2707465a38a2SSteen Hegelund 	data.u32.value = value;
2708465a38a2SSteen Hegelund 	data.u32.mask = mask;
2709465a38a2SSteen Hegelund 	return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data);
2710465a38a2SSteen Hegelund }
2711465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32);
2712465a38a2SSteen Hegelund 
2713465a38a2SSteen Hegelund static int vcap_rule_mod_action(struct vcap_rule *rule,
2714465a38a2SSteen Hegelund 				enum vcap_action_field action,
2715465a38a2SSteen Hegelund 				enum vcap_field_type ftype,
2716465a38a2SSteen Hegelund 				struct vcap_client_actionfield_data *data)
2717465a38a2SSteen Hegelund {
2718465a38a2SSteen Hegelund 	struct vcap_client_actionfield *field;
2719465a38a2SSteen Hegelund 
2720465a38a2SSteen Hegelund 	field = vcap_find_actionfield(rule, action);
2721465a38a2SSteen Hegelund 	if (!field)
2722465a38a2SSteen Hegelund 		return vcap_rule_add_action(rule, action, ftype, data);
2723465a38a2SSteen Hegelund 	vcap_copy_from_client_actionfield(rule, field, data);
2724465a38a2SSteen Hegelund 	return 0;
2725465a38a2SSteen Hegelund }
2726465a38a2SSteen Hegelund 
2727465a38a2SSteen Hegelund /* Modify a 32 bit action field with value in the rule */
2728465a38a2SSteen Hegelund int vcap_rule_mod_action_u32(struct vcap_rule *rule,
2729465a38a2SSteen Hegelund 			     enum vcap_action_field action,
2730465a38a2SSteen Hegelund 			     u32 value)
2731465a38a2SSteen Hegelund {
2732465a38a2SSteen Hegelund 	struct vcap_client_actionfield_data data;
2733465a38a2SSteen Hegelund 
2734465a38a2SSteen Hegelund 	data.u32.value = value;
2735465a38a2SSteen Hegelund 	return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data);
2736465a38a2SSteen Hegelund }
2737465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32);
2738465a38a2SSteen Hegelund 
2739465a38a2SSteen Hegelund /* Drop keys in a keylist and any keys that are not supported by the keyset */
2740465a38a2SSteen Hegelund int vcap_filter_rule_keys(struct vcap_rule *rule,
2741465a38a2SSteen Hegelund 			  enum vcap_key_field keylist[], int length,
2742465a38a2SSteen Hegelund 			  bool drop_unsupported)
2743465a38a2SSteen Hegelund {
2744465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2745465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
2746465a38a2SSteen Hegelund 	const struct vcap_field *fields;
2747465a38a2SSteen Hegelund 	enum vcap_key_field key;
2748465a38a2SSteen Hegelund 	int err = 0;
2749465a38a2SSteen Hegelund 	int idx;
2750465a38a2SSteen Hegelund 
2751465a38a2SSteen Hegelund 	if (length > 0) {
2752465a38a2SSteen Hegelund 		err = -EEXIST;
2753465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
2754465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
2755465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
2756465a38a2SSteen Hegelund 			for (idx = 0; idx < length; ++idx)
2757465a38a2SSteen Hegelund 				if (key == keylist[idx]) {
2758465a38a2SSteen Hegelund 					list_del(&ckf->ctrl.list);
2759465a38a2SSteen Hegelund 					kfree(ckf);
2760465a38a2SSteen Hegelund 					idx++;
2761465a38a2SSteen Hegelund 					err = 0;
2762465a38a2SSteen Hegelund 				}
2763465a38a2SSteen Hegelund 		}
2764465a38a2SSteen Hegelund 	}
2765465a38a2SSteen Hegelund 	if (drop_unsupported) {
2766465a38a2SSteen Hegelund 		err = -EEXIST;
2767465a38a2SSteen Hegelund 		fields = vcap_keyfields(ri->vctrl, ri->admin->vtype,
2768465a38a2SSteen Hegelund 					rule->keyset);
2769465a38a2SSteen Hegelund 		if (!fields)
2770465a38a2SSteen Hegelund 			return err;
2771465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
2772465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
2773465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
2774465a38a2SSteen Hegelund 			if (fields[key].width == 0) {
2775465a38a2SSteen Hegelund 				list_del(&ckf->ctrl.list);
2776465a38a2SSteen Hegelund 				kfree(ckf);
2777465a38a2SSteen Hegelund 				err = 0;
2778465a38a2SSteen Hegelund 			}
2779465a38a2SSteen Hegelund 		}
2780465a38a2SSteen Hegelund 	}
2781465a38a2SSteen Hegelund 	return err;
2782465a38a2SSteen Hegelund }
2783465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_filter_rule_keys);
2784465a38a2SSteen Hegelund 
2785465a38a2SSteen Hegelund /* Make a full copy of an existing rule with a new rule id */
2786465a38a2SSteen Hegelund struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
2787465a38a2SSteen Hegelund {
2788465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(erule);
2789465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
2790465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
2791465a38a2SSteen Hegelund 	struct vcap_rule *rule;
2792465a38a2SSteen Hegelund 	int err;
2793465a38a2SSteen Hegelund 
2794465a38a2SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2795465a38a2SSteen Hegelund 	if (err)
2796465a38a2SSteen Hegelund 		return ERR_PTR(err);
2797465a38a2SSteen Hegelund 
2798465a38a2SSteen Hegelund 	rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id,
2799465a38a2SSteen Hegelund 			       ri->data.user, ri->data.priority, 0);
2800465a38a2SSteen Hegelund 	if (IS_ERR(rule))
2801465a38a2SSteen Hegelund 		return rule;
2802465a38a2SSteen Hegelund 
2803465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
2804465a38a2SSteen Hegelund 		/* Add a key duplicate in the new rule */
2805465a38a2SSteen Hegelund 		err = vcap_rule_add_key(rule,
2806465a38a2SSteen Hegelund 					ckf->ctrl.key,
2807465a38a2SSteen Hegelund 					ckf->ctrl.type,
2808465a38a2SSteen Hegelund 					&ckf->data);
2809465a38a2SSteen Hegelund 		if (err)
2810465a38a2SSteen Hegelund 			goto err;
2811465a38a2SSteen Hegelund 	}
2812465a38a2SSteen Hegelund 
2813465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
2814465a38a2SSteen Hegelund 		/* Add a action duplicate in the new rule */
2815465a38a2SSteen Hegelund 		err = vcap_rule_add_action(rule,
2816465a38a2SSteen Hegelund 					   caf->ctrl.action,
2817465a38a2SSteen Hegelund 					   caf->ctrl.type,
2818465a38a2SSteen Hegelund 					   &caf->data);
2819465a38a2SSteen Hegelund 		if (err)
2820465a38a2SSteen Hegelund 			goto err;
2821465a38a2SSteen Hegelund 	}
2822465a38a2SSteen Hegelund 	return rule;
2823465a38a2SSteen Hegelund err:
2824465a38a2SSteen Hegelund 	vcap_free_rule(rule);
2825465a38a2SSteen Hegelund 	return ERR_PTR(err);
2826465a38a2SSteen Hegelund }
2827465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_copy_rule);
2828465a38a2SSteen Hegelund 
282967d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
283067d63751SSteen Hegelund #include "vcap_api_kunit.c"
283167d63751SSteen Hegelund #endif
2832