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 
40cfd9e7b7SSteen Hegelund /* Stores the filter cookie and chain id 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 */
45cfd9e7b7SSteen Hegelund 	int src_cid; /* source chain id */
46cfd9e7b7SSteen Hegelund 	int dst_cid; /* destination chain id */
4767456717SSteen Hegelund };
4867456717SSteen Hegelund 
49d4134d41SSteen Hegelund void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
50683e05c0SSteen Hegelund 		   const struct vcap_typegroup *tg, u32 offset)
51683e05c0SSteen Hegelund {
52683e05c0SSteen Hegelund 	memset(itr, 0, sizeof(*itr));
53683e05c0SSteen Hegelund 	itr->offset = offset;
54683e05c0SSteen Hegelund 	itr->sw_width = sw_width;
55683e05c0SSteen Hegelund 	itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32);
56683e05c0SSteen Hegelund 	itr->tg = tg;
57683e05c0SSteen Hegelund }
58683e05c0SSteen Hegelund 
59683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr)
60683e05c0SSteen Hegelund {
61683e05c0SSteen Hegelund 	/* Compensate the field offset for preceding typegroups.
62683e05c0SSteen Hegelund 	 * A typegroup table ends with an all-zero terminator.
63683e05c0SSteen Hegelund 	 */
64683e05c0SSteen Hegelund 	while (itr->tg->width && itr->offset >= itr->tg->offset) {
65683e05c0SSteen Hegelund 		itr->offset += itr->tg->width;
66683e05c0SSteen Hegelund 		itr->tg++; /* next typegroup */
67683e05c0SSteen Hegelund 	}
68683e05c0SSteen Hegelund }
69683e05c0SSteen Hegelund 
70d4134d41SSteen Hegelund void vcap_iter_update(struct vcap_stream_iter *itr)
71683e05c0SSteen Hegelund {
72683e05c0SSteen Hegelund 	int sw_idx, sw_bitpos;
73683e05c0SSteen Hegelund 
74683e05c0SSteen Hegelund 	/* Calculate the subword index and bitposition for current bit */
75683e05c0SSteen Hegelund 	sw_idx = itr->offset / itr->sw_width;
76683e05c0SSteen Hegelund 	sw_bitpos = itr->offset % itr->sw_width;
77683e05c0SSteen Hegelund 	/* Calculate the register index and bitposition for current bit */
78683e05c0SSteen Hegelund 	itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32);
79683e05c0SSteen Hegelund 	itr->reg_bitpos = sw_bitpos % 32;
80683e05c0SSteen Hegelund }
81683e05c0SSteen Hegelund 
82d4134d41SSteen Hegelund void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
83683e05c0SSteen Hegelund 		    const struct vcap_typegroup *tg, u32 offset)
84683e05c0SSteen Hegelund {
85683e05c0SSteen Hegelund 	vcap_iter_set(itr, sw_width, tg, offset);
86683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
87683e05c0SSteen Hegelund 	vcap_iter_update(itr);
88683e05c0SSteen Hegelund }
89683e05c0SSteen Hegelund 
90d4134d41SSteen Hegelund void vcap_iter_next(struct vcap_stream_iter *itr)
91683e05c0SSteen Hegelund {
92683e05c0SSteen Hegelund 	itr->offset++;
93683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
94683e05c0SSteen Hegelund 	vcap_iter_update(itr);
95683e05c0SSteen Hegelund }
96683e05c0SSteen Hegelund 
97683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value)
98683e05c0SSteen Hegelund {
99683e05c0SSteen Hegelund 	u32 mask = BIT(itr->reg_bitpos);
100683e05c0SSteen Hegelund 	u32 *p = &stream[itr->reg_idx];
101683e05c0SSteen Hegelund 
102683e05c0SSteen Hegelund 	if (value)
103683e05c0SSteen Hegelund 		*p |= mask;
104683e05c0SSteen Hegelund 	else
105683e05c0SSteen Hegelund 		*p &= ~mask;
106683e05c0SSteen Hegelund }
107683e05c0SSteen Hegelund 
108683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val)
109683e05c0SSteen Hegelund {
110683e05c0SSteen Hegelund 	/* When intersected by a type group field, stream the type group bits
111683e05c0SSteen Hegelund 	 * before continuing with the value bit
112683e05c0SSteen Hegelund 	 */
113683e05c0SSteen Hegelund 	while (itr->tg->width &&
114683e05c0SSteen Hegelund 	       itr->offset >= itr->tg->offset &&
115683e05c0SSteen Hegelund 	       itr->offset < itr->tg->offset + itr->tg->width) {
116683e05c0SSteen Hegelund 		int tg_bitpos = itr->tg->offset - itr->offset;
117683e05c0SSteen Hegelund 
118683e05c0SSteen Hegelund 		vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1);
119683e05c0SSteen Hegelund 		itr->offset++;
120683e05c0SSteen Hegelund 		vcap_iter_update(itr);
121683e05c0SSteen Hegelund 	}
122683e05c0SSteen Hegelund 	vcap_set_bit(stream, itr, val);
123683e05c0SSteen Hegelund }
124683e05c0SSteen Hegelund 
125683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr,
126683e05c0SSteen Hegelund 			      int width, const u8 *value)
127683e05c0SSteen Hegelund {
128683e05c0SSteen Hegelund 	int idx;
129683e05c0SSteen Hegelund 
130683e05c0SSteen Hegelund 	/* Loop over the field value bits and add the value bits one by one to
131683e05c0SSteen Hegelund 	 * the output stream.
132683e05c0SSteen Hegelund 	 */
133683e05c0SSteen Hegelund 	for (idx = 0; idx < width; idx++) {
134683e05c0SSteen Hegelund 		u8 bidx = idx & GENMASK(2, 0);
135683e05c0SSteen Hegelund 
136683e05c0SSteen Hegelund 		/* Encode one field value bit */
137683e05c0SSteen Hegelund 		vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1);
138683e05c0SSteen Hegelund 		vcap_iter_next(itr);
139683e05c0SSteen Hegelund 	}
140683e05c0SSteen Hegelund }
141683e05c0SSteen Hegelund 
142683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width,
143683e05c0SSteen Hegelund 				   const struct vcap_typegroup *tg,
144683e05c0SSteen Hegelund 				   bool mask)
145683e05c0SSteen Hegelund {
146683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
147683e05c0SSteen Hegelund 	int idx;
148683e05c0SSteen Hegelund 
149683e05c0SSteen Hegelund 	/* Mask bits must be set to zeros (inverted later when writing to the
150683e05c0SSteen Hegelund 	 * mask cache register), so that the mask typegroup bits consist of
151683e05c0SSteen Hegelund 	 * match-1 or match-0, or both
152683e05c0SSteen Hegelund 	 */
153683e05c0SSteen Hegelund 	vcap_iter_set(&iter, sw_width, tg, 0);
154683e05c0SSteen Hegelund 	while (iter.tg->width) {
155683e05c0SSteen Hegelund 		/* Set position to current typegroup bit */
156683e05c0SSteen Hegelund 		iter.offset = iter.tg->offset;
157683e05c0SSteen Hegelund 		vcap_iter_update(&iter);
158683e05c0SSteen Hegelund 		for (idx = 0; idx < iter.tg->width; idx++) {
159683e05c0SSteen Hegelund 			/* Iterate over current typegroup bits. Mask typegroup
160683e05c0SSteen Hegelund 			 * bits are always set
161683e05c0SSteen Hegelund 			 */
162683e05c0SSteen Hegelund 			if (mask)
163683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter, 0x1);
164683e05c0SSteen Hegelund 			else
165683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter,
166683e05c0SSteen Hegelund 					     (iter.tg->value >> idx) & 0x1);
167683e05c0SSteen Hegelund 			iter.offset++;
168683e05c0SSteen Hegelund 			vcap_iter_update(&iter);
169683e05c0SSteen Hegelund 		}
170683e05c0SSteen Hegelund 		iter.tg++; /* next typegroup */
171683e05c0SSteen Hegelund 	}
172683e05c0SSteen Hegelund }
173683e05c0SSteen Hegelund 
174610c32b2SHoratiu Vultur static bool vcap_bitarray_zero(int width, u8 *value)
175610c32b2SHoratiu Vultur {
176610c32b2SHoratiu Vultur 	int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
177610c32b2SHoratiu Vultur 	u8 total = 0, bmask = 0xff;
178610c32b2SHoratiu Vultur 	int rwidth = width;
179610c32b2SHoratiu Vultur 	int idx;
180610c32b2SHoratiu Vultur 
181610c32b2SHoratiu Vultur 	for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
182610c32b2SHoratiu Vultur 		if (rwidth && rwidth < BITS_PER_BYTE)
183610c32b2SHoratiu Vultur 			bmask = (1 << rwidth) - 1;
184610c32b2SHoratiu Vultur 		total += value[idx] & bmask;
185610c32b2SHoratiu Vultur 	}
186610c32b2SHoratiu Vultur 	return total == 0;
187610c32b2SHoratiu Vultur }
188610c32b2SHoratiu Vultur 
189610c32b2SHoratiu Vultur static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
190610c32b2SHoratiu Vultur {
191610c32b2SHoratiu Vultur 	u32 mask = BIT(itr->reg_bitpos);
192610c32b2SHoratiu Vultur 	u32 *p = &stream[itr->reg_idx];
193610c32b2SHoratiu Vultur 
194610c32b2SHoratiu Vultur 	return !!(*p & mask);
195610c32b2SHoratiu Vultur }
196610c32b2SHoratiu Vultur 
197610c32b2SHoratiu Vultur static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
198610c32b2SHoratiu Vultur 			      int width, u8 *value)
199610c32b2SHoratiu Vultur {
200610c32b2SHoratiu Vultur 	int idx;
201610c32b2SHoratiu Vultur 
202610c32b2SHoratiu Vultur 	/* Loop over the field value bits and get the field bits and
203610c32b2SHoratiu Vultur 	 * set them in the output value byte array
204610c32b2SHoratiu Vultur 	 */
205610c32b2SHoratiu Vultur 	for (idx = 0; idx < width; idx++) {
206610c32b2SHoratiu Vultur 		u8 bidx = idx & 0x7;
207610c32b2SHoratiu Vultur 
208610c32b2SHoratiu Vultur 		/* Decode one field value bit */
209610c32b2SHoratiu Vultur 		if (vcap_get_bit(stream, itr))
210610c32b2SHoratiu Vultur 			*value |= 1 << bidx;
211610c32b2SHoratiu Vultur 		vcap_iter_next(itr);
212610c32b2SHoratiu Vultur 		if (bidx == 7)
213610c32b2SHoratiu Vultur 			value++;
214610c32b2SHoratiu Vultur 	}
215610c32b2SHoratiu Vultur }
216610c32b2SHoratiu Vultur 
217610c32b2SHoratiu Vultur /* Verify that the type id in the stream matches the type id of the keyset */
218610c32b2SHoratiu Vultur static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
219610c32b2SHoratiu Vultur 					 enum vcap_type vt,
220610c32b2SHoratiu Vultur 					 u32 *keystream,
221610c32b2SHoratiu Vultur 					 u32 *mskstream,
222610c32b2SHoratiu Vultur 					 enum vcap_keyfield_set keyset)
223610c32b2SHoratiu Vultur {
224610c32b2SHoratiu Vultur 	const struct vcap_info *vcap = &vctrl->vcaps[vt];
225610c32b2SHoratiu Vultur 	const struct vcap_field *typefld;
226610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
227610c32b2SHoratiu Vultur 	const struct vcap_field *fields;
228610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
229610c32b2SHoratiu Vultur 	const struct vcap_set *info;
230610c32b2SHoratiu Vultur 	u32 value = 0;
231610c32b2SHoratiu Vultur 	u32 mask = 0;
232610c32b2SHoratiu Vultur 
233610c32b2SHoratiu Vultur 	if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
234610c32b2SHoratiu Vultur 		return false;
235610c32b2SHoratiu Vultur 
236610c32b2SHoratiu Vultur 	info = vcap_keyfieldset(vctrl, vt, keyset);
237610c32b2SHoratiu Vultur 	/* Check that the keyset is valid */
238610c32b2SHoratiu Vultur 	if (!info)
239610c32b2SHoratiu Vultur 		return false;
240610c32b2SHoratiu Vultur 
241610c32b2SHoratiu Vultur 	/* a type_id of value -1 means that there is no type field */
242610c32b2SHoratiu Vultur 	if (info->type_id == (u8)-1)
243610c32b2SHoratiu Vultur 		return true;
244610c32b2SHoratiu Vultur 
245610c32b2SHoratiu Vultur 	/* Get a valid typegroup for the specific keyset */
246610c32b2SHoratiu Vultur 	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
247610c32b2SHoratiu Vultur 	if (!tgt)
248610c32b2SHoratiu Vultur 		return false;
249610c32b2SHoratiu Vultur 
250610c32b2SHoratiu Vultur 	fields = vcap_keyfields(vctrl, vt, keyset);
251610c32b2SHoratiu Vultur 	if (!fields)
252610c32b2SHoratiu Vultur 		return false;
253610c32b2SHoratiu Vultur 
254610c32b2SHoratiu Vultur 	typefld = &fields[VCAP_KF_TYPE];
255610c32b2SHoratiu Vultur 	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
256610c32b2SHoratiu Vultur 	vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
257610c32b2SHoratiu Vultur 	/* no type info if there are no mask bits */
258610c32b2SHoratiu Vultur 	if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
259610c32b2SHoratiu Vultur 		return false;
260610c32b2SHoratiu Vultur 
261610c32b2SHoratiu Vultur 	/* Get the value of the type field in the stream and compare to the
262610c32b2SHoratiu Vultur 	 * one define in the vcap keyset
263610c32b2SHoratiu Vultur 	 */
264610c32b2SHoratiu Vultur 	vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
265610c32b2SHoratiu Vultur 	vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
266610c32b2SHoratiu Vultur 
267610c32b2SHoratiu Vultur 	return (value & mask) == (info->type_id & mask);
268610c32b2SHoratiu Vultur }
269610c32b2SHoratiu Vultur 
270610c32b2SHoratiu Vultur /* Verify that the typegroup bits have the correct values */
271610c32b2SHoratiu Vultur static int vcap_verify_typegroups(u32 *stream, int sw_width,
272610c32b2SHoratiu Vultur 				  const struct vcap_typegroup *tgt, bool mask,
273610c32b2SHoratiu Vultur 				  int sw_max)
274610c32b2SHoratiu Vultur {
275610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
276610c32b2SHoratiu Vultur 	int sw_cnt, idx;
277610c32b2SHoratiu Vultur 
278610c32b2SHoratiu Vultur 	vcap_iter_set(&iter, sw_width, tgt, 0);
279610c32b2SHoratiu Vultur 	sw_cnt = 0;
280610c32b2SHoratiu Vultur 	while (iter.tg->width) {
281610c32b2SHoratiu Vultur 		u32 value = 0;
282610c32b2SHoratiu Vultur 		u32 tg_value = iter.tg->value;
283610c32b2SHoratiu Vultur 
284610c32b2SHoratiu Vultur 		if (mask)
285610c32b2SHoratiu Vultur 			tg_value = (1 << iter.tg->width) - 1;
286610c32b2SHoratiu Vultur 		/* Set position to current typegroup bit */
287610c32b2SHoratiu Vultur 		iter.offset = iter.tg->offset;
288610c32b2SHoratiu Vultur 		vcap_iter_update(&iter);
289610c32b2SHoratiu Vultur 		for (idx = 0; idx < iter.tg->width; idx++) {
290610c32b2SHoratiu Vultur 			/* Decode one typegroup bit */
291610c32b2SHoratiu Vultur 			if (vcap_get_bit(stream, &iter))
292610c32b2SHoratiu Vultur 				value |= 1 << idx;
293610c32b2SHoratiu Vultur 			iter.offset++;
294610c32b2SHoratiu Vultur 			vcap_iter_update(&iter);
295610c32b2SHoratiu Vultur 		}
296610c32b2SHoratiu Vultur 		if (value != tg_value)
297610c32b2SHoratiu Vultur 			return -EINVAL;
298610c32b2SHoratiu Vultur 		iter.tg++; /* next typegroup */
299610c32b2SHoratiu Vultur 		sw_cnt++;
300610c32b2SHoratiu Vultur 		/* Stop checking more typegroups */
301610c32b2SHoratiu Vultur 		if (sw_max && sw_cnt >= sw_max)
302610c32b2SHoratiu Vultur 			break;
303610c32b2SHoratiu Vultur 	}
304610c32b2SHoratiu Vultur 	return 0;
305610c32b2SHoratiu Vultur }
306610c32b2SHoratiu Vultur 
307610c32b2SHoratiu Vultur /* Find the subword width of the key typegroup that matches the stream data */
308610c32b2SHoratiu Vultur static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
309610c32b2SHoratiu Vultur 					    enum vcap_type vt, u32 *stream,
310610c32b2SHoratiu Vultur 					    bool mask, int sw_max)
311610c32b2SHoratiu Vultur {
312610c32b2SHoratiu Vultur 	const struct vcap_typegroup **tgt;
313610c32b2SHoratiu Vultur 	int sw_idx, res;
314610c32b2SHoratiu Vultur 
315610c32b2SHoratiu Vultur 	tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
316610c32b2SHoratiu Vultur 	/* Try the longest subword match first */
317610c32b2SHoratiu Vultur 	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
318610c32b2SHoratiu Vultur 		if (!tgt[sw_idx])
319610c32b2SHoratiu Vultur 			continue;
320610c32b2SHoratiu Vultur 
321610c32b2SHoratiu Vultur 		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
322610c32b2SHoratiu Vultur 					     tgt[sw_idx], mask, sw_max);
323610c32b2SHoratiu Vultur 		if (res == 0)
324610c32b2SHoratiu Vultur 			return sw_idx;
325610c32b2SHoratiu Vultur 	}
326610c32b2SHoratiu Vultur 	return -EINVAL;
327610c32b2SHoratiu Vultur }
328610c32b2SHoratiu Vultur 
329610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, keyset and type id
330610c32b2SHoratiu Vultur  * are in sync and correct, return the list of matchin keysets
331610c32b2SHoratiu Vultur  */
332610c32b2SHoratiu Vultur int
333610c32b2SHoratiu Vultur vcap_find_keystream_keysets(struct vcap_control *vctrl,
334610c32b2SHoratiu Vultur 			    enum vcap_type vt,
335610c32b2SHoratiu Vultur 			    u32 *keystream,
336610c32b2SHoratiu Vultur 			    u32 *mskstream,
337610c32b2SHoratiu Vultur 			    bool mask, int sw_max,
338610c32b2SHoratiu Vultur 			    struct vcap_keyset_list *kslist)
339610c32b2SHoratiu Vultur {
340610c32b2SHoratiu Vultur 	const struct vcap_set *keyfield_set;
341610c32b2SHoratiu Vultur 	int sw_count, idx;
342610c32b2SHoratiu Vultur 
343610c32b2SHoratiu Vultur 	sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
344610c32b2SHoratiu Vultur 						    sw_max);
345610c32b2SHoratiu Vultur 	if (sw_count < 0)
346610c32b2SHoratiu Vultur 		return sw_count;
347610c32b2SHoratiu Vultur 
348610c32b2SHoratiu Vultur 	keyfield_set = vctrl->vcaps[vt].keyfield_set;
349610c32b2SHoratiu Vultur 	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
350610c32b2SHoratiu Vultur 		if (keyfield_set[idx].sw_per_item != sw_count)
351610c32b2SHoratiu Vultur 			continue;
352610c32b2SHoratiu Vultur 
353610c32b2SHoratiu Vultur 		if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
354610c32b2SHoratiu Vultur 						 mskstream, idx))
355610c32b2SHoratiu Vultur 			vcap_keyset_list_add(kslist, idx);
356610c32b2SHoratiu Vultur 	}
357610c32b2SHoratiu Vultur 	if (kslist->cnt > 0)
358610c32b2SHoratiu Vultur 		return 0;
359610c32b2SHoratiu Vultur 	return -EINVAL;
360610c32b2SHoratiu Vultur }
361610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_find_keystream_keysets);
362610c32b2SHoratiu Vultur 
363610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there are any rule keysets
364610c32b2SHoratiu Vultur  * here
365610c32b2SHoratiu Vultur  */
366610c32b2SHoratiu Vultur int vcap_addr_keysets(struct vcap_control *vctrl,
367610c32b2SHoratiu Vultur 		      struct net_device *ndev,
368610c32b2SHoratiu Vultur 		      struct vcap_admin *admin,
369610c32b2SHoratiu Vultur 		      int addr,
370610c32b2SHoratiu Vultur 		      struct vcap_keyset_list *kslist)
371610c32b2SHoratiu Vultur {
372610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
373610c32b2SHoratiu Vultur 	int keyset_sw_regs, idx;
374610c32b2SHoratiu Vultur 	u32 key = 0, mask = 0;
375610c32b2SHoratiu Vultur 
376610c32b2SHoratiu Vultur 	/* Read the cache at the specified address */
377610c32b2SHoratiu Vultur 	keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
378610c32b2SHoratiu Vultur 	vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
379610c32b2SHoratiu Vultur 	vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
380610c32b2SHoratiu Vultur 			       keyset_sw_regs);
381610c32b2SHoratiu Vultur 	/* Skip uninitialized key/mask entries */
382610c32b2SHoratiu Vultur 	for (idx = 0; idx < keyset_sw_regs; ++idx) {
383610c32b2SHoratiu Vultur 		key |= ~admin->cache.keystream[idx];
384610c32b2SHoratiu Vultur 		mask |= admin->cache.maskstream[idx];
385610c32b2SHoratiu Vultur 	}
386610c32b2SHoratiu Vultur 	if (key == 0 && mask == 0)
387610c32b2SHoratiu Vultur 		return -EINVAL;
388610c32b2SHoratiu Vultur 	/* Decode and locate the keysets */
389610c32b2SHoratiu Vultur 	return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
390610c32b2SHoratiu Vultur 					   admin->cache.maskstream, false, 0,
391610c32b2SHoratiu Vultur 					   kslist);
392610c32b2SHoratiu Vultur }
393610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_addr_keysets);
394610c32b2SHoratiu Vultur 
39546be056eSSteen Hegelund /* Return the list of keyfields for the keyset */
396d4134d41SSteen Hegelund const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
39746be056eSSteen Hegelund 					enum vcap_type vt,
39846be056eSSteen Hegelund 					enum vcap_keyfield_set keyset)
39946be056eSSteen Hegelund {
40046be056eSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
40146be056eSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
40246be056eSSteen Hegelund 		return NULL;
40346be056eSSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map[keyset];
40446be056eSSteen Hegelund }
40546be056eSSteen Hegelund 
4068e10490bSSteen Hegelund /* Return the keyset information for the keyset */
407d4134d41SSteen Hegelund const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
4088e10490bSSteen Hegelund 					enum vcap_type vt,
4098e10490bSSteen Hegelund 					enum vcap_keyfield_set keyset)
4108e10490bSSteen Hegelund {
4118e10490bSSteen Hegelund 	const struct vcap_set *kset;
4128e10490bSSteen Hegelund 
4138e10490bSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
4148e10490bSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
4158e10490bSSteen Hegelund 		return NULL;
4168e10490bSSteen Hegelund 	kset = &vctrl->vcaps[vt].keyfield_set[keyset];
4178e10490bSSteen Hegelund 	if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count)
4188e10490bSSteen Hegelund 		return NULL;
4198e10490bSSteen Hegelund 	return kset;
4208e10490bSSteen Hegelund }
421465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfieldset);
4228e10490bSSteen Hegelund 
423683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */
424d4134d41SSteen Hegelund const struct vcap_typegroup *
425683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl,
426683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
427683e05c0SSteen Hegelund {
428683e05c0SSteen Hegelund 	const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset);
429683e05c0SSteen Hegelund 
430683e05c0SSteen Hegelund 	/* Check that the keyset is valid */
431683e05c0SSteen Hegelund 	if (!kset)
432683e05c0SSteen Hegelund 		return NULL;
433683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item];
434683e05c0SSteen Hegelund }
435683e05c0SSteen Hegelund 
436683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */
437d4134d41SSteen Hegelund int vcap_keyfield_count(struct vcap_control *vctrl,
438683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
439683e05c0SSteen Hegelund {
440683e05c0SSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
441683e05c0SSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
442683e05c0SSteen Hegelund 		return 0;
443683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map_size[keyset];
444683e05c0SSteen Hegelund }
445683e05c0SSteen Hegelund 
446683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri,
447683e05c0SSteen Hegelund 				 const struct vcap_client_keyfield *kf,
448683e05c0SSteen Hegelund 				 const struct vcap_field *rf,
449683e05c0SSteen Hegelund 				 const struct vcap_typegroup *tgt)
450683e05c0SSteen Hegelund {
451683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
452683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
453683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
454683e05c0SSteen Hegelund 	const u8 *value, *mask;
455683e05c0SSteen Hegelund 
456683e05c0SSteen Hegelund 	/* Encode the fields for the key and the mask in their respective
457683e05c0SSteen Hegelund 	 * streams, respecting the subword width.
458683e05c0SSteen Hegelund 	 */
459683e05c0SSteen Hegelund 	switch (kf->ctrl.type) {
460683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
461683e05c0SSteen Hegelund 		value = &kf->data.u1.value;
462683e05c0SSteen Hegelund 		mask = &kf->data.u1.mask;
463683e05c0SSteen Hegelund 		break;
464683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
465683e05c0SSteen Hegelund 		value = (const u8 *)&kf->data.u32.value;
466683e05c0SSteen Hegelund 		mask = (const u8 *)&kf->data.u32.mask;
467683e05c0SSteen Hegelund 		break;
468683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
469683e05c0SSteen Hegelund 		value = kf->data.u48.value;
470683e05c0SSteen Hegelund 		mask = kf->data.u48.mask;
471683e05c0SSteen Hegelund 		break;
472683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
473683e05c0SSteen Hegelund 		value = kf->data.u56.value;
474683e05c0SSteen Hegelund 		mask = kf->data.u56.mask;
475683e05c0SSteen Hegelund 		break;
476683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
477683e05c0SSteen Hegelund 		value = kf->data.u64.value;
478683e05c0SSteen Hegelund 		mask = kf->data.u64.mask;
479683e05c0SSteen Hegelund 		break;
480683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
481683e05c0SSteen Hegelund 		value = kf->data.u72.value;
482683e05c0SSteen Hegelund 		mask = kf->data.u72.mask;
483683e05c0SSteen Hegelund 		break;
484683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
485683e05c0SSteen Hegelund 		value = kf->data.u112.value;
486683e05c0SSteen Hegelund 		mask = kf->data.u112.mask;
487683e05c0SSteen Hegelund 		break;
488683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
489683e05c0SSteen Hegelund 		value = kf->data.u128.value;
490683e05c0SSteen Hegelund 		mask = kf->data.u128.mask;
491683e05c0SSteen Hegelund 		break;
492683e05c0SSteen Hegelund 	}
493683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
494683e05c0SSteen Hegelund 	vcap_encode_field(cache->keystream, &iter, rf->width, value);
495683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
496683e05c0SSteen Hegelund 	vcap_encode_field(cache->maskstream, &iter, rf->width, mask);
497683e05c0SSteen Hegelund }
498683e05c0SSteen Hegelund 
499683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl,
500683e05c0SSteen Hegelund 					    struct vcap_rule_internal *ri,
501683e05c0SSteen Hegelund 					    const struct vcap_typegroup *tgt)
502683e05c0SSteen Hegelund {
503683e05c0SSteen Hegelund 	int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width;
504683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
505683e05c0SSteen Hegelund 
506683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the key and the mask in their streams,
507683e05c0SSteen Hegelund 	 * respecting the subword width.
508683e05c0SSteen Hegelund 	 */
509683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->keystream, sw_width, tgt, false);
510683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true);
511683e05c0SSteen Hegelund }
512683e05c0SSteen Hegelund 
51333e3a273SSteen Hegelund /* Copy data from src to dst but reverse the data in chunks of 32bits.
51433e3a273SSteen Hegelund  * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will
51533e3a273SSteen Hegelund  * have the value 22:33:44:55:00:11.
51633e3a273SSteen Hegelund  */
51733e3a273SSteen Hegelund static void vcap_copy_to_w32be(u8 *dst, const u8 *src, int size)
51833e3a273SSteen Hegelund {
51933e3a273SSteen Hegelund 	for (int idx = 0; idx < size; ++idx) {
52033e3a273SSteen Hegelund 		int first_byte_index = 0;
52133e3a273SSteen Hegelund 		int nidx;
52233e3a273SSteen Hegelund 
52333e3a273SSteen Hegelund 		first_byte_index = size - (((idx >> 2) + 1) << 2);
52433e3a273SSteen Hegelund 		if (first_byte_index < 0)
52533e3a273SSteen Hegelund 			first_byte_index = 0;
52633e3a273SSteen Hegelund 		nidx = idx + first_byte_index - (idx & ~0x3);
52733e3a273SSteen Hegelund 		dst[nidx] = src[idx];
52833e3a273SSteen Hegelund 	}
52933e3a273SSteen Hegelund }
53033e3a273SSteen Hegelund 
53133e3a273SSteen Hegelund static void
53233e3a273SSteen Hegelund vcap_copy_from_client_keyfield(struct vcap_rule *rule,
53333e3a273SSteen Hegelund 			       struct vcap_client_keyfield *dst,
53433e3a273SSteen Hegelund 			       const struct vcap_client_keyfield *src)
53533e3a273SSteen Hegelund {
53633e3a273SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
53733e3a273SSteen Hegelund 	const struct vcap_client_keyfield_data *sdata;
53833e3a273SSteen Hegelund 	struct vcap_client_keyfield_data *ddata;
53933e3a273SSteen Hegelund 	int size;
54033e3a273SSteen Hegelund 
54133e3a273SSteen Hegelund 	dst->ctrl.type = src->ctrl.type;
54233e3a273SSteen Hegelund 	dst->ctrl.key = src->ctrl.key;
54333e3a273SSteen Hegelund 	INIT_LIST_HEAD(&dst->ctrl.list);
54433e3a273SSteen Hegelund 	sdata = &src->data;
54533e3a273SSteen Hegelund 	ddata = &dst->data;
54633e3a273SSteen Hegelund 
54733e3a273SSteen Hegelund 	if (!ri->admin->w32be) {
54833e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
54933e3a273SSteen Hegelund 		return;
55033e3a273SSteen Hegelund 	}
55133e3a273SSteen Hegelund 
55233e3a273SSteen Hegelund 	size = keyfield_size_table[dst->ctrl.type] / 2;
55333e3a273SSteen Hegelund 
55433e3a273SSteen Hegelund 	switch (dst->ctrl.type) {
55533e3a273SSteen Hegelund 	case VCAP_FIELD_BIT:
55633e3a273SSteen Hegelund 	case VCAP_FIELD_U32:
55733e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
55833e3a273SSteen Hegelund 		break;
55933e3a273SSteen Hegelund 	case VCAP_FIELD_U48:
56033e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u48.value, src->data.u48.value, size);
56133e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u48.mask,  src->data.u48.mask, size);
56233e3a273SSteen Hegelund 		break;
56333e3a273SSteen Hegelund 	case VCAP_FIELD_U56:
56433e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size);
56533e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u56.mask,  sdata->u56.mask, size);
56633e3a273SSteen Hegelund 		break;
56733e3a273SSteen Hegelund 	case VCAP_FIELD_U64:
56833e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size);
56933e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u64.mask,  sdata->u64.mask, size);
57033e3a273SSteen Hegelund 		break;
57133e3a273SSteen Hegelund 	case VCAP_FIELD_U72:
57233e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size);
57333e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u72.mask,  sdata->u72.mask, size);
57433e3a273SSteen Hegelund 		break;
57533e3a273SSteen Hegelund 	case VCAP_FIELD_U112:
57633e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size);
57733e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u112.mask,  sdata->u112.mask, size);
57833e3a273SSteen Hegelund 		break;
57933e3a273SSteen Hegelund 	case VCAP_FIELD_U128:
58033e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size);
58133e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u128.mask,  sdata->u128.mask, size);
58233e3a273SSteen Hegelund 		break;
58333e3a273SSteen Hegelund 	}
58433e3a273SSteen Hegelund }
58533e3a273SSteen Hegelund 
58633e3a273SSteen Hegelund static void
58733e3a273SSteen Hegelund vcap_copy_from_client_actionfield(struct vcap_rule *rule,
58833e3a273SSteen Hegelund 				  struct vcap_client_actionfield *dst,
58933e3a273SSteen Hegelund 				  const struct vcap_client_actionfield *src)
59033e3a273SSteen Hegelund {
59133e3a273SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
59233e3a273SSteen Hegelund 	const struct vcap_client_actionfield_data *sdata;
59333e3a273SSteen Hegelund 	struct vcap_client_actionfield_data *ddata;
59433e3a273SSteen Hegelund 	int size;
59533e3a273SSteen Hegelund 
59633e3a273SSteen Hegelund 	dst->ctrl.type = src->ctrl.type;
59733e3a273SSteen Hegelund 	dst->ctrl.action = src->ctrl.action;
59833e3a273SSteen Hegelund 	INIT_LIST_HEAD(&dst->ctrl.list);
59933e3a273SSteen Hegelund 	sdata = &src->data;
60033e3a273SSteen Hegelund 	ddata = &dst->data;
60133e3a273SSteen Hegelund 
60233e3a273SSteen Hegelund 	if (!ri->admin->w32be) {
60333e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
60433e3a273SSteen Hegelund 		return;
60533e3a273SSteen Hegelund 	}
60633e3a273SSteen Hegelund 
60733e3a273SSteen Hegelund 	size = actionfield_size_table[dst->ctrl.type];
60833e3a273SSteen Hegelund 
60933e3a273SSteen Hegelund 	switch (dst->ctrl.type) {
61033e3a273SSteen Hegelund 	case VCAP_FIELD_BIT:
61133e3a273SSteen Hegelund 	case VCAP_FIELD_U32:
61233e3a273SSteen Hegelund 		memcpy(ddata, sdata, sizeof(dst->data));
61333e3a273SSteen Hegelund 		break;
61433e3a273SSteen Hegelund 	case VCAP_FIELD_U48:
61533e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u48.value, sdata->u48.value, size);
61633e3a273SSteen Hegelund 		break;
61733e3a273SSteen Hegelund 	case VCAP_FIELD_U56:
61833e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size);
61933e3a273SSteen Hegelund 		break;
62033e3a273SSteen Hegelund 	case VCAP_FIELD_U64:
62133e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size);
62233e3a273SSteen Hegelund 		break;
62333e3a273SSteen Hegelund 	case VCAP_FIELD_U72:
62433e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size);
62533e3a273SSteen Hegelund 		break;
62633e3a273SSteen Hegelund 	case VCAP_FIELD_U112:
62733e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size);
62833e3a273SSteen Hegelund 		break;
62933e3a273SSteen Hegelund 	case VCAP_FIELD_U128:
63033e3a273SSteen Hegelund 		vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size);
63133e3a273SSteen Hegelund 		break;
63233e3a273SSteen Hegelund 	}
63333e3a273SSteen Hegelund }
63433e3a273SSteen Hegelund 
635683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
636683e05c0SSteen Hegelund {
637683e05c0SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
638683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
63933e3a273SSteen Hegelund 	struct vcap_client_keyfield tempkf;
640683e05c0SSteen Hegelund 	const struct vcap_field *kf_table;
641683e05c0SSteen Hegelund 	int keyset_size;
642683e05c0SSteen Hegelund 
643683e05c0SSteen Hegelund 	/* Get a valid set of fields for the specific keyset */
644683e05c0SSteen Hegelund 	kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset);
645683e05c0SSteen Hegelund 	if (!kf_table) {
646683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this keyset: %d\n",
647683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
648683e05c0SSteen Hegelund 		return -EINVAL;
649683e05c0SSteen Hegelund 	}
650683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific keyset */
651683e05c0SSteen Hegelund 	tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype,
652683e05c0SSteen Hegelund 					   ri->data.keyset);
653683e05c0SSteen Hegelund 	if (!tg_table) {
654683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this keyset: %d\n",
655683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
656683e05c0SSteen Hegelund 		return -EINVAL;
657683e05c0SSteen Hegelund 	}
658683e05c0SSteen Hegelund 	/* Get a valid size for the specific keyset */
659683e05c0SSteen Hegelund 	keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype,
660683e05c0SSteen Hegelund 					  ri->data.keyset);
661683e05c0SSteen Hegelund 	if (keyset_size == 0) {
662683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this keyset: %d\n",
663683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
664683e05c0SSteen Hegelund 		return -EINVAL;
665683e05c0SSteen Hegelund 	}
666683e05c0SSteen Hegelund 	/* Iterate over the keyfields (key, mask) in the rule
667683e05c0SSteen Hegelund 	 * and encode these bits
668683e05c0SSteen Hegelund 	 */
669683e05c0SSteen Hegelund 	if (list_empty(&ri->data.keyfields)) {
670683e05c0SSteen Hegelund 		pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__);
671683e05c0SSteen Hegelund 		return -EINVAL;
672683e05c0SSteen Hegelund 	}
673683e05c0SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
674683e05c0SSteen Hegelund 		/* Check that the client entry exists in the keyset */
675683e05c0SSteen Hegelund 		if (ckf->ctrl.key >= keyset_size) {
676683e05c0SSteen Hegelund 			pr_err("%s:%d: key %d is not in vcap\n",
677683e05c0SSteen Hegelund 			       __func__, __LINE__, ckf->ctrl.key);
678683e05c0SSteen Hegelund 			return -EINVAL;
679683e05c0SSteen Hegelund 		}
68033e3a273SSteen Hegelund 		vcap_copy_from_client_keyfield(&ri->data, &tempkf, ckf);
68133e3a273SSteen Hegelund 		vcap_encode_keyfield(ri, &tempkf, &kf_table[ckf->ctrl.key],
68233e3a273SSteen Hegelund 				     tg_table);
683683e05c0SSteen Hegelund 	}
684683e05c0SSteen Hegelund 	/* Add typegroup bits to the key/mask bitstreams */
685683e05c0SSteen Hegelund 	vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table);
686683e05c0SSteen Hegelund 	return 0;
687683e05c0SSteen Hegelund }
688683e05c0SSteen Hegelund 
689683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */
69072d84dd6SSteen Hegelund const struct vcap_field *
691683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl,
692683e05c0SSteen Hegelund 		  enum vcap_type vt, enum vcap_actionfield_set actionset)
693683e05c0SSteen Hegelund {
694683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
695683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
696683e05c0SSteen Hegelund 		return NULL;
697683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map[actionset];
698683e05c0SSteen Hegelund }
699683e05c0SSteen Hegelund 
70072d84dd6SSteen Hegelund const struct vcap_set *
7018e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl,
7028e10490bSSteen Hegelund 		    enum vcap_type vt, enum vcap_actionfield_set actionset)
7038e10490bSSteen Hegelund {
7048e10490bSSteen Hegelund 	const struct vcap_set *aset;
7058e10490bSSteen Hegelund 
7068e10490bSSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
7078e10490bSSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
7088e10490bSSteen Hegelund 		return NULL;
7098e10490bSSteen Hegelund 	aset = &vctrl->vcaps[vt].actionfield_set[actionset];
7108e10490bSSteen Hegelund 	if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count)
7118e10490bSSteen Hegelund 		return NULL;
7128e10490bSSteen Hegelund 	return aset;
7138e10490bSSteen Hegelund }
7148e10490bSSteen Hegelund 
715683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */
71672d84dd6SSteen Hegelund const struct vcap_typegroup *
717683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl,
718683e05c0SSteen Hegelund 			   enum vcap_type vt, enum vcap_actionfield_set actionset)
719683e05c0SSteen Hegelund {
720683e05c0SSteen Hegelund 	const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset);
721683e05c0SSteen Hegelund 
722683e05c0SSteen Hegelund 	/* Check that the actionset is valid */
723683e05c0SSteen Hegelund 	if (!aset)
724683e05c0SSteen Hegelund 		return NULL;
725683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item];
726683e05c0SSteen Hegelund }
727683e05c0SSteen Hegelund 
728683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */
72972d84dd6SSteen Hegelund int vcap_actionfield_count(struct vcap_control *vctrl,
730683e05c0SSteen Hegelund 			   enum vcap_type vt,
731683e05c0SSteen Hegelund 			   enum vcap_actionfield_set actionset)
732683e05c0SSteen Hegelund {
733683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
734683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
735683e05c0SSteen Hegelund 		return 0;
736683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map_size[actionset];
737683e05c0SSteen Hegelund }
738683e05c0SSteen Hegelund 
739683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri,
740683e05c0SSteen Hegelund 				    const struct vcap_client_actionfield *af,
741683e05c0SSteen Hegelund 				    const struct vcap_field *rf,
742683e05c0SSteen Hegelund 				    const struct vcap_typegroup *tgt)
743683e05c0SSteen Hegelund {
744683e05c0SSteen Hegelund 	int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
745683e05c0SSteen Hegelund 
746683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
747683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
748683e05c0SSteen Hegelund 	const u8 *value;
749683e05c0SSteen Hegelund 
750683e05c0SSteen Hegelund 	/* Encode the action field in the stream, respecting the subword width */
751683e05c0SSteen Hegelund 	switch (af->ctrl.type) {
752683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
753683e05c0SSteen Hegelund 		value = &af->data.u1.value;
754683e05c0SSteen Hegelund 		break;
755683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
756683e05c0SSteen Hegelund 		value = (const u8 *)&af->data.u32.value;
757683e05c0SSteen Hegelund 		break;
758683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
759683e05c0SSteen Hegelund 		value = af->data.u48.value;
760683e05c0SSteen Hegelund 		break;
761683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
762683e05c0SSteen Hegelund 		value = af->data.u56.value;
763683e05c0SSteen Hegelund 		break;
764683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
765683e05c0SSteen Hegelund 		value = af->data.u64.value;
766683e05c0SSteen Hegelund 		break;
767683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
768683e05c0SSteen Hegelund 		value = af->data.u72.value;
769683e05c0SSteen Hegelund 		break;
770683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
771683e05c0SSteen Hegelund 		value = af->data.u112.value;
772683e05c0SSteen Hegelund 		break;
773683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
774683e05c0SSteen Hegelund 		value = af->data.u128.value;
775683e05c0SSteen Hegelund 		break;
776683e05c0SSteen Hegelund 	}
777683e05c0SSteen Hegelund 	vcap_iter_init(&iter, act_width, tgt, rf->offset);
778683e05c0SSteen Hegelund 	vcap_encode_field(cache->actionstream, &iter, rf->width, value);
779683e05c0SSteen Hegelund }
780683e05c0SSteen Hegelund 
781683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri,
782683e05c0SSteen Hegelund 					       const struct vcap_typegroup *tgt)
783683e05c0SSteen Hegelund {
784683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
785683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
786683e05c0SSteen Hegelund 
787683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the actionstream respecting the subword
788683e05c0SSteen Hegelund 	 * width.
789683e05c0SSteen Hegelund 	 */
790683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false);
791683e05c0SSteen Hegelund }
792683e05c0SSteen Hegelund 
793683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri)
794683e05c0SSteen Hegelund {
795683e05c0SSteen Hegelund 	const struct vcap_client_actionfield *caf;
796683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
79733e3a273SSteen Hegelund 	struct vcap_client_actionfield tempaf;
798683e05c0SSteen Hegelund 	const struct vcap_field *af_table;
799683e05c0SSteen Hegelund 	int actionset_size;
800683e05c0SSteen Hegelund 
801683e05c0SSteen Hegelund 	/* Get a valid set of actionset fields for the specific actionset */
802683e05c0SSteen Hegelund 	af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype,
803683e05c0SSteen Hegelund 				     ri->data.actionset);
804683e05c0SSteen Hegelund 	if (!af_table) {
805683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this actionset: %d\n",
806683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
807683e05c0SSteen Hegelund 		return -EINVAL;
808683e05c0SSteen Hegelund 	}
809683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific actionset */
810683e05c0SSteen Hegelund 	tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype,
811683e05c0SSteen Hegelund 					      ri->data.actionset);
812683e05c0SSteen Hegelund 	if (!tg_table) {
813683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this actionset: %d\n",
814683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
815683e05c0SSteen Hegelund 		return -EINVAL;
816683e05c0SSteen Hegelund 	}
817683e05c0SSteen Hegelund 	/* Get a valid actionset size for the specific actionset */
818683e05c0SSteen Hegelund 	actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype,
819683e05c0SSteen Hegelund 						ri->data.actionset);
820683e05c0SSteen Hegelund 	if (actionset_size == 0) {
821683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this actionset: %d\n",
822683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
823683e05c0SSteen Hegelund 		return -EINVAL;
824683e05c0SSteen Hegelund 	}
825683e05c0SSteen Hegelund 	/* Iterate over the actionfields in the rule
826683e05c0SSteen Hegelund 	 * and encode these bits
827683e05c0SSteen Hegelund 	 */
828683e05c0SSteen Hegelund 	if (list_empty(&ri->data.actionfields))
829683e05c0SSteen Hegelund 		pr_warn("%s:%d: no actionfields in the rule\n",
830683e05c0SSteen Hegelund 			__func__, __LINE__);
831683e05c0SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
832683e05c0SSteen Hegelund 		/* Check that the client action exists in the actionset */
833683e05c0SSteen Hegelund 		if (caf->ctrl.action >= actionset_size) {
834683e05c0SSteen Hegelund 			pr_err("%s:%d: action %d is not in vcap\n",
835683e05c0SSteen Hegelund 			       __func__, __LINE__, caf->ctrl.action);
836683e05c0SSteen Hegelund 			return -EINVAL;
837683e05c0SSteen Hegelund 		}
83833e3a273SSteen Hegelund 		vcap_copy_from_client_actionfield(&ri->data, &tempaf, caf);
83933e3a273SSteen Hegelund 		vcap_encode_actionfield(ri, &tempaf,
84033e3a273SSteen Hegelund 					&af_table[caf->ctrl.action], tg_table);
841683e05c0SSteen Hegelund 	}
842683e05c0SSteen Hegelund 	/* Add typegroup bits to the entry bitstreams */
843683e05c0SSteen Hegelund 	vcap_encode_actionfield_typegroups(ri, tg_table);
844683e05c0SSteen Hegelund 	return 0;
845683e05c0SSteen Hegelund }
846683e05c0SSteen Hegelund 
8478e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri)
8488e10490bSSteen Hegelund {
849683e05c0SSteen Hegelund 	int err;
850683e05c0SSteen Hegelund 
851683e05c0SSteen Hegelund 	err = vcap_encode_rule_keyset(ri);
852683e05c0SSteen Hegelund 	if (err)
853683e05c0SSteen Hegelund 		return err;
854683e05c0SSteen Hegelund 	err = vcap_encode_rule_actionset(ri);
855683e05c0SSteen Hegelund 	if (err)
856683e05c0SSteen Hegelund 		return err;
8578e10490bSSteen Hegelund 	return 0;
8588e10490bSSteen Hegelund }
8598e10490bSSteen Hegelund 
860d4134d41SSteen Hegelund int vcap_api_check(struct vcap_control *ctrl)
8618e10490bSSteen Hegelund {
8628e10490bSSteen Hegelund 	if (!ctrl) {
8638e10490bSSteen Hegelund 		pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
8648e10490bSSteen Hegelund 		return -EINVAL;
8658e10490bSSteen Hegelund 	}
8668e10490bSSteen Hegelund 	if (!ctrl->ops || !ctrl->ops->validate_keyset ||
8678e10490bSSteen Hegelund 	    !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
8688e10490bSSteen Hegelund 	    !ctrl->ops->cache_write || !ctrl->ops->cache_read ||
8698e10490bSSteen Hegelund 	    !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
87001ef75a2SSteen Hegelund 	    !ctrl->ops->port_info) {
8718e10490bSSteen Hegelund 		pr_err("%s:%d: client operations are missing\n",
8728e10490bSSteen Hegelund 		       __func__, __LINE__);
8738e10490bSSteen Hegelund 		return -ENOENT;
8748e10490bSSteen Hegelund 	}
8758e10490bSSteen Hegelund 	return 0;
8768e10490bSSteen Hegelund }
8778e10490bSSteen Hegelund 
8783a792156SSteen Hegelund void vcap_erase_cache(struct vcap_rule_internal *ri)
8798e10490bSSteen Hegelund {
8808e10490bSSteen Hegelund 	ri->vctrl->ops->cache_erase(ri->admin);
8818e10490bSSteen Hegelund }
8828e10490bSSteen Hegelund 
883c9da1ac1SSteen Hegelund /* Update the keyset for the rule */
884c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule,
885c9da1ac1SSteen Hegelund 			     enum vcap_keyfield_set keyset)
886c9da1ac1SSteen Hegelund {
8878e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
8888e10490bSSteen Hegelund 	const struct vcap_set *kset;
8898e10490bSSteen Hegelund 	int sw_width;
8908e10490bSSteen Hegelund 
8918e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset);
8928e10490bSSteen Hegelund 	/* Check that the keyset is valid */
8938e10490bSSteen Hegelund 	if (!kset)
8948e10490bSSteen Hegelund 		return -EINVAL;
8958e10490bSSteen Hegelund 	ri->keyset_sw = kset->sw_per_item;
8968e10490bSSteen Hegelund 	sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
8978e10490bSSteen Hegelund 	ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32);
8988e10490bSSteen Hegelund 	ri->data.keyset = keyset;
899c9da1ac1SSteen Hegelund 	return 0;
900c9da1ac1SSteen Hegelund }
901c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset);
902c9da1ac1SSteen Hegelund 
903c9da1ac1SSteen Hegelund /* Update the actionset for the rule */
904c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule,
905c9da1ac1SSteen Hegelund 				enum vcap_actionfield_set actionset)
906c9da1ac1SSteen Hegelund {
9078e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
9088e10490bSSteen Hegelund 	const struct vcap_set *aset;
9098e10490bSSteen Hegelund 	int act_width;
9108e10490bSSteen Hegelund 
9118e10490bSSteen Hegelund 	aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset);
9128e10490bSSteen Hegelund 	/* Check that the actionset is valid */
9138e10490bSSteen Hegelund 	if (!aset)
9148e10490bSSteen Hegelund 		return -EINVAL;
9158e10490bSSteen Hegelund 	ri->actionset_sw = aset->sw_per_item;
9168e10490bSSteen Hegelund 	act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
9178e10490bSSteen Hegelund 	ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32);
9188e10490bSSteen Hegelund 	ri->data.actionset = actionset;
919c9da1ac1SSteen Hegelund 	return 0;
920c9da1ac1SSteen Hegelund }
921c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset);
922c9da1ac1SSteen Hegelund 
923975d86acSSteen Hegelund /* Check if a rule with this id exists */
924975d86acSSteen Hegelund static bool vcap_rule_exists(struct vcap_control *vctrl, u32 id)
925975d86acSSteen Hegelund {
926975d86acSSteen Hegelund 	struct vcap_rule_internal *ri;
927975d86acSSteen Hegelund 	struct vcap_admin *admin;
928975d86acSSteen Hegelund 
929975d86acSSteen Hegelund 	/* Look for the rule id in all vcaps */
930975d86acSSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
931975d86acSSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
932975d86acSSteen Hegelund 			if (ri->data.id == id)
933975d86acSSteen Hegelund 				return true;
934975d86acSSteen Hegelund 	return false;
935975d86acSSteen Hegelund }
936975d86acSSteen Hegelund 
9371972b6d9SSteen Hegelund /* Find a rule with a provided rule id return a locked vcap */
9381972b6d9SSteen Hegelund static struct vcap_rule_internal *
9391972b6d9SSteen Hegelund vcap_get_locked_rule(struct vcap_control *vctrl, u32 id)
940c9da1ac1SSteen Hegelund {
941c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
942c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
943c9da1ac1SSteen Hegelund 
944c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
9451972b6d9SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
9461972b6d9SSteen Hegelund 		mutex_lock(&admin->lock);
947c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
948c9da1ac1SSteen Hegelund 			if (ri->data.id == id)
949c9da1ac1SSteen Hegelund 				return ri;
9501972b6d9SSteen Hegelund 		mutex_unlock(&admin->lock);
9511972b6d9SSteen Hegelund 	}
952c9da1ac1SSteen Hegelund 	return NULL;
953c9da1ac1SSteen Hegelund }
954c9da1ac1SSteen Hegelund 
955c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */
956c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
957c9da1ac1SSteen Hegelund {
958c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
959c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
9601972b6d9SSteen Hegelund 	int id = 0;
961c9da1ac1SSteen Hegelund 
962c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
9631972b6d9SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
9641972b6d9SSteen Hegelund 		mutex_lock(&admin->lock);
9651972b6d9SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
9661972b6d9SSteen Hegelund 			if (ri->data.cookie == cookie) {
9671972b6d9SSteen Hegelund 				id = ri->data.id;
9681972b6d9SSteen Hegelund 				break;
9691972b6d9SSteen Hegelund 			}
9701972b6d9SSteen Hegelund 		}
9711972b6d9SSteen Hegelund 		mutex_unlock(&admin->lock);
9721972b6d9SSteen Hegelund 		if (id)
9731972b6d9SSteen Hegelund 			return id;
9741972b6d9SSteen Hegelund 	}
975c9da1ac1SSteen Hegelund 	return -ENOENT;
976c9da1ac1SSteen Hegelund }
977c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
978c9da1ac1SSteen Hegelund 
979814e7693SSteen Hegelund /* Make a copy of the rule, shallow or full */
980814e7693SSteen Hegelund static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri,
981814e7693SSteen Hegelund 						bool full)
9828e10490bSSteen Hegelund {
983814e7693SSteen Hegelund 	struct vcap_client_actionfield *caf, *newcaf;
984814e7693SSteen Hegelund 	struct vcap_client_keyfield *ckf, *newckf;
9858e10490bSSteen Hegelund 	struct vcap_rule_internal *duprule;
9868e10490bSSteen Hegelund 
9878e10490bSSteen Hegelund 	/* Allocate the client part */
9888e10490bSSteen Hegelund 	duprule = kzalloc(sizeof(*duprule), GFP_KERNEL);
9898e10490bSSteen Hegelund 	if (!duprule)
9908e10490bSSteen Hegelund 		return ERR_PTR(-ENOMEM);
9918e10490bSSteen Hegelund 	*duprule = *ri;
9928e10490bSSteen Hegelund 	/* Not inserted in the VCAP */
9938e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->list);
9948e10490bSSteen Hegelund 	/* No elements in these lists */
9958e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.keyfields);
9968e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.actionfields);
997814e7693SSteen Hegelund 
998814e7693SSteen Hegelund 	/* A full rule copy includes keys and actions */
999814e7693SSteen Hegelund 	if (!full)
1000814e7693SSteen Hegelund 		return duprule;
1001814e7693SSteen Hegelund 
1002814e7693SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
10035e64f59aSYang Yingliang 		newckf = kmemdup(ckf, sizeof(*newckf), GFP_KERNEL);
1004814e7693SSteen Hegelund 		if (!newckf)
1005814e7693SSteen Hegelund 			return ERR_PTR(-ENOMEM);
1006814e7693SSteen Hegelund 		list_add_tail(&newckf->ctrl.list, &duprule->data.keyfields);
1007814e7693SSteen Hegelund 	}
1008814e7693SSteen Hegelund 
1009814e7693SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
10105e64f59aSYang Yingliang 		newcaf = kmemdup(caf, sizeof(*newcaf), GFP_KERNEL);
1011814e7693SSteen Hegelund 		if (!newcaf)
1012814e7693SSteen Hegelund 			return ERR_PTR(-ENOMEM);
1013814e7693SSteen Hegelund 		list_add_tail(&newcaf->ctrl.list, &duprule->data.actionfields);
1014814e7693SSteen Hegelund 	}
1015814e7693SSteen Hegelund 
10168e10490bSSteen Hegelund 	return duprule;
10178e10490bSSteen Hegelund }
10188e10490bSSteen Hegelund 
1019610c32b2SHoratiu Vultur static void vcap_apply_width(u8 *dst, int width, int bytes)
1020610c32b2SHoratiu Vultur {
1021610c32b2SHoratiu Vultur 	u8 bmask;
1022610c32b2SHoratiu Vultur 	int idx;
1023610c32b2SHoratiu Vultur 
1024610c32b2SHoratiu Vultur 	for (idx = 0; idx < bytes; idx++) {
1025610c32b2SHoratiu Vultur 		if (width > 0)
1026610c32b2SHoratiu Vultur 			if (width < 8)
1027610c32b2SHoratiu Vultur 				bmask = (1 << width) - 1;
1028610c32b2SHoratiu Vultur 			else
1029610c32b2SHoratiu Vultur 				bmask = ~0;
1030610c32b2SHoratiu Vultur 		else
1031610c32b2SHoratiu Vultur 			bmask = 0;
1032610c32b2SHoratiu Vultur 		dst[idx] &= bmask;
1033610c32b2SHoratiu Vultur 		width -= 8;
1034610c32b2SHoratiu Vultur 	}
1035610c32b2SHoratiu Vultur }
1036610c32b2SHoratiu Vultur 
1037610c32b2SHoratiu Vultur static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width)
1038610c32b2SHoratiu Vultur {
1039610c32b2SHoratiu Vultur 	int idx, ridx, wstart, nidx;
1040610c32b2SHoratiu Vultur 	int tail_bytes = (((size + 4) >> 2) << 2) - size;
1041610c32b2SHoratiu Vultur 
1042610c32b2SHoratiu Vultur 	for (idx = 0, ridx = size - 1; idx < size; ++idx, --ridx) {
1043610c32b2SHoratiu Vultur 		wstart = (idx >> 2) << 2;
1044610c32b2SHoratiu Vultur 		nidx = wstart + 3 - (idx & 0x3);
1045610c32b2SHoratiu Vultur 		if (nidx >= size)
1046610c32b2SHoratiu Vultur 			nidx -= tail_bytes;
1047610c32b2SHoratiu Vultur 		dst[nidx] = src[ridx];
1048610c32b2SHoratiu Vultur 	}
1049610c32b2SHoratiu Vultur 
1050610c32b2SHoratiu Vultur 	vcap_apply_width(dst, width, size);
1051610c32b2SHoratiu Vultur }
1052610c32b2SHoratiu Vultur 
1053610c32b2SHoratiu Vultur static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *value)
1054610c32b2SHoratiu Vultur {
1055610c32b2SHoratiu Vultur 	field->value = (*value) & 0x1;
1056610c32b2SHoratiu Vultur }
1057610c32b2SHoratiu Vultur 
1058610c32b2SHoratiu Vultur static void vcap_copy_limited_actionfield(u8 *dstvalue, u8 *srcvalue,
1059610c32b2SHoratiu Vultur 					  int width, int bytes)
1060610c32b2SHoratiu Vultur {
1061610c32b2SHoratiu Vultur 	memcpy(dstvalue, srcvalue, bytes);
1062610c32b2SHoratiu Vultur 	vcap_apply_width(dstvalue, width, bytes);
1063610c32b2SHoratiu Vultur }
1064610c32b2SHoratiu Vultur 
1065610c32b2SHoratiu Vultur static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri,
1066610c32b2SHoratiu Vultur 					    struct vcap_client_actionfield *field,
1067610c32b2SHoratiu Vultur 					    u8 *value, u16 width)
1068610c32b2SHoratiu Vultur {
1069610c32b2SHoratiu Vultur 	int field_size = actionfield_size_table[field->ctrl.type];
1070610c32b2SHoratiu Vultur 
1071610c32b2SHoratiu Vultur 	if (ri->admin->w32be) {
1072610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1073610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1074610c32b2SHoratiu Vultur 			vcap_copy_action_bit_field(&field->data.u1, value);
1075610c32b2SHoratiu Vultur 			break;
1076610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1077610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
1078610c32b2SHoratiu Vultur 						      value,
1079610c32b2SHoratiu Vultur 						      width, field_size);
1080610c32b2SHoratiu Vultur 			break;
1081610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1082610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.value, value,
1083610c32b2SHoratiu Vultur 					     field_size, width);
1084610c32b2SHoratiu Vultur 			break;
1085610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1086610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.value, value,
1087610c32b2SHoratiu Vultur 					     field_size, width);
1088610c32b2SHoratiu Vultur 			break;
1089610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1090610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.value, value,
1091610c32b2SHoratiu Vultur 					     field_size, width);
1092610c32b2SHoratiu Vultur 			break;
1093610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1094610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.value, value,
1095610c32b2SHoratiu Vultur 					     field_size, width);
1096610c32b2SHoratiu Vultur 			break;
1097610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1098610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.value, value,
1099610c32b2SHoratiu Vultur 					     field_size, width);
1100610c32b2SHoratiu Vultur 			break;
1101610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1102610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.value, value,
1103610c32b2SHoratiu Vultur 					     field_size, width);
1104610c32b2SHoratiu Vultur 			break;
1105610c32b2SHoratiu Vultur 		};
1106610c32b2SHoratiu Vultur 	} else {
1107610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1108610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1109610c32b2SHoratiu Vultur 			vcap_copy_action_bit_field(&field->data.u1, value);
1110610c32b2SHoratiu Vultur 			break;
1111610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1112610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
1113610c32b2SHoratiu Vultur 						      value,
1114610c32b2SHoratiu Vultur 						      width, field_size);
1115610c32b2SHoratiu Vultur 			break;
1116610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1117610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u48.value,
1118610c32b2SHoratiu Vultur 						      value,
1119610c32b2SHoratiu Vultur 						      width, field_size);
1120610c32b2SHoratiu Vultur 			break;
1121610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1122610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u56.value,
1123610c32b2SHoratiu Vultur 						      value,
1124610c32b2SHoratiu Vultur 						      width, field_size);
1125610c32b2SHoratiu Vultur 			break;
1126610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1127610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u64.value,
1128610c32b2SHoratiu Vultur 						      value,
1129610c32b2SHoratiu Vultur 						      width, field_size);
1130610c32b2SHoratiu Vultur 			break;
1131610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1132610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u72.value,
1133610c32b2SHoratiu Vultur 						      value,
1134610c32b2SHoratiu Vultur 						      width, field_size);
1135610c32b2SHoratiu Vultur 			break;
1136610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1137610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u112.value,
1138610c32b2SHoratiu Vultur 						      value,
1139610c32b2SHoratiu Vultur 						      width, field_size);
1140610c32b2SHoratiu Vultur 			break;
1141610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1142610c32b2SHoratiu Vultur 			vcap_copy_limited_actionfield(field->data.u128.value,
1143610c32b2SHoratiu Vultur 						      value,
1144610c32b2SHoratiu Vultur 						      width, field_size);
1145610c32b2SHoratiu Vultur 			break;
1146610c32b2SHoratiu Vultur 		};
1147610c32b2SHoratiu Vultur 	}
1148610c32b2SHoratiu Vultur }
1149610c32b2SHoratiu Vultur 
1150610c32b2SHoratiu Vultur static void vcap_copy_key_bit_field(struct vcap_u1_key *field,
1151610c32b2SHoratiu Vultur 				    u8 *value, u8 *mask)
1152610c32b2SHoratiu Vultur {
1153610c32b2SHoratiu Vultur 	field->value = (*value) & 0x1;
1154610c32b2SHoratiu Vultur 	field->mask = (*mask) & 0x1;
1155610c32b2SHoratiu Vultur }
1156610c32b2SHoratiu Vultur 
1157610c32b2SHoratiu Vultur static void vcap_copy_limited_keyfield(u8 *dstvalue, u8 *dstmask,
1158610c32b2SHoratiu Vultur 				       u8 *srcvalue, u8 *srcmask,
1159610c32b2SHoratiu Vultur 				       int width, int bytes)
1160610c32b2SHoratiu Vultur {
1161610c32b2SHoratiu Vultur 	memcpy(dstvalue, srcvalue, bytes);
1162610c32b2SHoratiu Vultur 	vcap_apply_width(dstvalue, width, bytes);
1163610c32b2SHoratiu Vultur 	memcpy(dstmask, srcmask, bytes);
1164610c32b2SHoratiu Vultur 	vcap_apply_width(dstmask, width, bytes);
1165610c32b2SHoratiu Vultur }
1166610c32b2SHoratiu Vultur 
1167610c32b2SHoratiu Vultur static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri,
1168610c32b2SHoratiu Vultur 					 struct vcap_client_keyfield *field,
1169610c32b2SHoratiu Vultur 					 u8 *value, u8 *mask, u16 width)
1170610c32b2SHoratiu Vultur {
1171610c32b2SHoratiu Vultur 	int field_size = keyfield_size_table[field->ctrl.type] / 2;
1172610c32b2SHoratiu Vultur 
1173610c32b2SHoratiu Vultur 	if (ri->admin->w32be) {
1174610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1175610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1176610c32b2SHoratiu Vultur 			vcap_copy_key_bit_field(&field->data.u1, value, mask);
1177610c32b2SHoratiu Vultur 			break;
1178610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1179610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1180610c32b2SHoratiu Vultur 						   (u8 *)&field->data.u32.mask,
1181610c32b2SHoratiu Vultur 						   value, mask,
1182610c32b2SHoratiu Vultur 						   width, field_size);
1183610c32b2SHoratiu Vultur 			break;
1184610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1185610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.value, value,
1186610c32b2SHoratiu Vultur 					     field_size, width);
1187610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u48.mask,  mask,
1188610c32b2SHoratiu Vultur 					     field_size, width);
1189610c32b2SHoratiu Vultur 			break;
1190610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1191610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.value, value,
1192610c32b2SHoratiu Vultur 					     field_size, width);
1193610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u56.mask,  mask,
1194610c32b2SHoratiu Vultur 					     field_size, width);
1195610c32b2SHoratiu Vultur 			break;
1196610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1197610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.value, value,
1198610c32b2SHoratiu Vultur 					     field_size, width);
1199610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u64.mask,  mask,
1200610c32b2SHoratiu Vultur 					     field_size, width);
1201610c32b2SHoratiu Vultur 			break;
1202610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1203610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.value, value,
1204610c32b2SHoratiu Vultur 					     field_size, width);
1205610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u72.mask,  mask,
1206610c32b2SHoratiu Vultur 					     field_size, width);
1207610c32b2SHoratiu Vultur 			break;
1208610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1209610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.value, value,
1210610c32b2SHoratiu Vultur 					     field_size, width);
1211610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u112.mask,  mask,
1212610c32b2SHoratiu Vultur 					     field_size, width);
1213610c32b2SHoratiu Vultur 			break;
1214610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1215610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.value, value,
1216610c32b2SHoratiu Vultur 					     field_size, width);
1217610c32b2SHoratiu Vultur 			vcap_copy_from_w32be(field->data.u128.mask,  mask,
1218610c32b2SHoratiu Vultur 					     field_size, width);
1219610c32b2SHoratiu Vultur 			break;
1220610c32b2SHoratiu Vultur 		};
1221610c32b2SHoratiu Vultur 	} else {
1222610c32b2SHoratiu Vultur 		switch (field->ctrl.type) {
1223610c32b2SHoratiu Vultur 		case VCAP_FIELD_BIT:
1224610c32b2SHoratiu Vultur 			vcap_copy_key_bit_field(&field->data.u1, value, mask);
1225610c32b2SHoratiu Vultur 			break;
1226610c32b2SHoratiu Vultur 		case VCAP_FIELD_U32:
1227610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1228610c32b2SHoratiu Vultur 						   (u8 *)&field->data.u32.mask,
1229610c32b2SHoratiu Vultur 						   value, mask,
1230610c32b2SHoratiu Vultur 						   width, field_size);
1231610c32b2SHoratiu Vultur 			break;
1232610c32b2SHoratiu Vultur 		case VCAP_FIELD_U48:
1233610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u48.value,
1234610c32b2SHoratiu Vultur 						   field->data.u48.mask,
1235610c32b2SHoratiu Vultur 						   value, mask,
1236610c32b2SHoratiu Vultur 						   width, field_size);
1237610c32b2SHoratiu Vultur 			break;
1238610c32b2SHoratiu Vultur 		case VCAP_FIELD_U56:
1239610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u56.value,
1240610c32b2SHoratiu Vultur 						   field->data.u56.mask,
1241610c32b2SHoratiu Vultur 						   value, mask,
1242610c32b2SHoratiu Vultur 						   width, field_size);
1243610c32b2SHoratiu Vultur 			break;
1244610c32b2SHoratiu Vultur 		case VCAP_FIELD_U64:
1245610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u64.value,
1246610c32b2SHoratiu Vultur 						   field->data.u64.mask,
1247610c32b2SHoratiu Vultur 						   value, mask,
1248610c32b2SHoratiu Vultur 						   width, field_size);
1249610c32b2SHoratiu Vultur 			break;
1250610c32b2SHoratiu Vultur 		case VCAP_FIELD_U72:
1251610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u72.value,
1252610c32b2SHoratiu Vultur 						   field->data.u72.mask,
1253610c32b2SHoratiu Vultur 						   value, mask,
1254610c32b2SHoratiu Vultur 						   width, field_size);
1255610c32b2SHoratiu Vultur 			break;
1256610c32b2SHoratiu Vultur 		case VCAP_FIELD_U112:
1257610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u112.value,
1258610c32b2SHoratiu Vultur 						   field->data.u112.mask,
1259610c32b2SHoratiu Vultur 						   value, mask,
1260610c32b2SHoratiu Vultur 						   width, field_size);
1261610c32b2SHoratiu Vultur 			break;
1262610c32b2SHoratiu Vultur 		case VCAP_FIELD_U128:
1263610c32b2SHoratiu Vultur 			vcap_copy_limited_keyfield(field->data.u128.value,
1264610c32b2SHoratiu Vultur 						   field->data.u128.mask,
1265610c32b2SHoratiu Vultur 						   value, mask,
1266610c32b2SHoratiu Vultur 						   width, field_size);
1267610c32b2SHoratiu Vultur 			break;
1268610c32b2SHoratiu Vultur 		};
1269610c32b2SHoratiu Vultur 	}
1270610c32b2SHoratiu Vultur }
1271610c32b2SHoratiu Vultur 
1272610c32b2SHoratiu Vultur static void vcap_rule_alloc_keyfield(struct vcap_rule_internal *ri,
1273610c32b2SHoratiu Vultur 				     const struct vcap_field *keyfield,
1274610c32b2SHoratiu Vultur 				     enum vcap_key_field key,
1275610c32b2SHoratiu Vultur 				     u8 *value, u8 *mask)
1276610c32b2SHoratiu Vultur {
1277610c32b2SHoratiu Vultur 	struct vcap_client_keyfield *field;
1278610c32b2SHoratiu Vultur 
1279610c32b2SHoratiu Vultur 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1280610c32b2SHoratiu Vultur 	if (!field)
1281610c32b2SHoratiu Vultur 		return;
1282610c32b2SHoratiu Vultur 	INIT_LIST_HEAD(&field->ctrl.list);
1283610c32b2SHoratiu Vultur 	field->ctrl.key = key;
1284610c32b2SHoratiu Vultur 	field->ctrl.type = keyfield->type;
1285610c32b2SHoratiu Vultur 	vcap_copy_to_client_keyfield(ri, field, value, mask, keyfield->width);
1286610c32b2SHoratiu Vultur 	list_add_tail(&field->ctrl.list, &ri->data.keyfields);
1287610c32b2SHoratiu Vultur }
1288610c32b2SHoratiu Vultur 
1289610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there is a rule keyset
1290610c32b2SHoratiu Vultur  * here
1291610c32b2SHoratiu Vultur  */
1292610c32b2SHoratiu Vultur static bool
1293610c32b2SHoratiu Vultur vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
1294610c32b2SHoratiu Vultur 				   enum vcap_type vt,
1295610c32b2SHoratiu Vultur 				   u32 *actionstream,
1296610c32b2SHoratiu Vultur 				   enum vcap_actionfield_set actionset)
1297610c32b2SHoratiu Vultur {
1298610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1299610c32b2SHoratiu Vultur 	const struct vcap_field *fields;
1300610c32b2SHoratiu Vultur 	const struct vcap_set *info;
1301610c32b2SHoratiu Vultur 
1302610c32b2SHoratiu Vultur 	if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
1303610c32b2SHoratiu Vultur 		return false;
1304610c32b2SHoratiu Vultur 
1305610c32b2SHoratiu Vultur 	info = vcap_actionfieldset(vctrl, vt, actionset);
1306610c32b2SHoratiu Vultur 	/* Check that the actionset is valid */
1307610c32b2SHoratiu Vultur 	if (!info)
1308610c32b2SHoratiu Vultur 		return false;
1309610c32b2SHoratiu Vultur 
1310610c32b2SHoratiu Vultur 	/* a type_id of value -1 means that there is no type field */
1311610c32b2SHoratiu Vultur 	if (info->type_id == (u8)-1)
1312610c32b2SHoratiu Vultur 		return true;
1313610c32b2SHoratiu Vultur 
1314610c32b2SHoratiu Vultur 	/* Get a valid typegroup for the specific actionset */
1315610c32b2SHoratiu Vultur 	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1316610c32b2SHoratiu Vultur 	if (!tgt)
1317610c32b2SHoratiu Vultur 		return false;
1318610c32b2SHoratiu Vultur 
1319610c32b2SHoratiu Vultur 	fields = vcap_actionfields(vctrl, vt, actionset);
1320610c32b2SHoratiu Vultur 	if (!fields)
1321610c32b2SHoratiu Vultur 		return false;
1322610c32b2SHoratiu Vultur 
1323610c32b2SHoratiu Vultur 	/* Later this will be expanded with a check of the type id */
1324610c32b2SHoratiu Vultur 	return true;
1325610c32b2SHoratiu Vultur }
1326610c32b2SHoratiu Vultur 
1327610c32b2SHoratiu Vultur /* Find the subword width of the action typegroup that matches the stream data
1328610c32b2SHoratiu Vultur  */
1329610c32b2SHoratiu Vultur static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
1330610c32b2SHoratiu Vultur 					       enum vcap_type vt, u32 *stream,
1331610c32b2SHoratiu Vultur 					       int sw_max)
1332610c32b2SHoratiu Vultur {
1333610c32b2SHoratiu Vultur 	const struct vcap_typegroup **tgt;
1334610c32b2SHoratiu Vultur 	int sw_idx, res;
1335610c32b2SHoratiu Vultur 
1336610c32b2SHoratiu Vultur 	tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
1337610c32b2SHoratiu Vultur 	/* Try the longest subword match first */
1338610c32b2SHoratiu Vultur 	for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
1339610c32b2SHoratiu Vultur 		if (!tgt[sw_idx])
1340610c32b2SHoratiu Vultur 			continue;
1341610c32b2SHoratiu Vultur 		res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
1342610c32b2SHoratiu Vultur 					     tgt[sw_idx], false, sw_max);
1343610c32b2SHoratiu Vultur 		if (res == 0)
1344610c32b2SHoratiu Vultur 			return sw_idx;
1345610c32b2SHoratiu Vultur 	}
1346610c32b2SHoratiu Vultur 	return -EINVAL;
1347610c32b2SHoratiu Vultur }
1348610c32b2SHoratiu Vultur 
1349610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, actionset and type id
1350610c32b2SHoratiu Vultur  * are in sync and correct, return the actionset
1351610c32b2SHoratiu Vultur  */
1352610c32b2SHoratiu Vultur static enum vcap_actionfield_set
1353610c32b2SHoratiu Vultur vcap_find_actionstream_actionset(struct vcap_control *vctrl,
1354610c32b2SHoratiu Vultur 				 enum vcap_type vt,
1355610c32b2SHoratiu Vultur 				 u32 *stream,
1356610c32b2SHoratiu Vultur 				 int sw_max)
1357610c32b2SHoratiu Vultur {
1358610c32b2SHoratiu Vultur 	const struct vcap_set *actionfield_set;
1359610c32b2SHoratiu Vultur 	int sw_count, idx;
1360610c32b2SHoratiu Vultur 	bool res;
1361610c32b2SHoratiu Vultur 
1362610c32b2SHoratiu Vultur 	sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
1363610c32b2SHoratiu Vultur 						       sw_max);
1364610c32b2SHoratiu Vultur 	if (sw_count < 0)
1365610c32b2SHoratiu Vultur 		return sw_count;
1366610c32b2SHoratiu Vultur 
1367610c32b2SHoratiu Vultur 	actionfield_set = vctrl->vcaps[vt].actionfield_set;
1368610c32b2SHoratiu Vultur 	for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
1369610c32b2SHoratiu Vultur 		if (actionfield_set[idx].sw_per_item != sw_count)
1370610c32b2SHoratiu Vultur 			continue;
1371610c32b2SHoratiu Vultur 
1372610c32b2SHoratiu Vultur 		res = vcap_verify_actionstream_actionset(vctrl, vt,
1373610c32b2SHoratiu Vultur 							 stream, idx);
1374610c32b2SHoratiu Vultur 		if (res)
1375610c32b2SHoratiu Vultur 			return idx;
1376610c32b2SHoratiu Vultur 	}
1377610c32b2SHoratiu Vultur 	return -EINVAL;
1378610c32b2SHoratiu Vultur }
1379610c32b2SHoratiu Vultur 
1380610c32b2SHoratiu Vultur /* Store action value in an element in a list for the client */
1381610c32b2SHoratiu Vultur static void vcap_rule_alloc_actionfield(struct vcap_rule_internal *ri,
1382610c32b2SHoratiu Vultur 					const struct vcap_field *actionfield,
1383610c32b2SHoratiu Vultur 					enum vcap_action_field action,
1384610c32b2SHoratiu Vultur 					u8 *value)
1385610c32b2SHoratiu Vultur {
1386610c32b2SHoratiu Vultur 	struct vcap_client_actionfield *field;
1387610c32b2SHoratiu Vultur 
1388610c32b2SHoratiu Vultur 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1389610c32b2SHoratiu Vultur 	if (!field)
1390610c32b2SHoratiu Vultur 		return;
1391610c32b2SHoratiu Vultur 	INIT_LIST_HEAD(&field->ctrl.list);
1392610c32b2SHoratiu Vultur 	field->ctrl.action = action;
1393610c32b2SHoratiu Vultur 	field->ctrl.type = actionfield->type;
1394610c32b2SHoratiu Vultur 	vcap_copy_to_client_actionfield(ri, field, value, actionfield->width);
1395610c32b2SHoratiu Vultur 	list_add_tail(&field->ctrl.list, &ri->data.actionfields);
1396610c32b2SHoratiu Vultur }
1397610c32b2SHoratiu Vultur 
1398610c32b2SHoratiu Vultur static int vcap_decode_actionset(struct vcap_rule_internal *ri)
1399610c32b2SHoratiu Vultur {
1400610c32b2SHoratiu Vultur 	struct vcap_control *vctrl = ri->vctrl;
1401610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1402610c32b2SHoratiu Vultur 	const struct vcap_field *actionfield;
1403610c32b2SHoratiu Vultur 	enum vcap_actionfield_set actionset;
1404610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
1405610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1406610c32b2SHoratiu Vultur 	struct vcap_stream_iter iter;
1407610c32b2SHoratiu Vultur 	int idx, res, actfield_count;
1408610c32b2SHoratiu Vultur 	u32 *actstream;
1409610c32b2SHoratiu Vultur 	u8 value[16];
1410610c32b2SHoratiu Vultur 
1411610c32b2SHoratiu Vultur 	actstream = admin->cache.actionstream;
1412610c32b2SHoratiu Vultur 	res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
1413610c32b2SHoratiu Vultur 	if (res < 0) {
1414610c32b2SHoratiu Vultur 		pr_err("%s:%d: could not find valid actionset: %d\n",
1415610c32b2SHoratiu Vultur 		       __func__, __LINE__, res);
1416610c32b2SHoratiu Vultur 		return -EINVAL;
1417610c32b2SHoratiu Vultur 	}
1418610c32b2SHoratiu Vultur 	actionset = res;
1419610c32b2SHoratiu Vultur 	actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
1420610c32b2SHoratiu Vultur 	actionfield = vcap_actionfields(vctrl, vt, actionset);
1421610c32b2SHoratiu Vultur 	tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1422610c32b2SHoratiu Vultur 	/* Start decoding the stream */
1423610c32b2SHoratiu Vultur 	for (idx = 0; idx < actfield_count; ++idx) {
1424610c32b2SHoratiu Vultur 		if (actionfield[idx].width <= 0)
1425610c32b2SHoratiu Vultur 			continue;
1426610c32b2SHoratiu Vultur 		/* Get the action */
1427610c32b2SHoratiu Vultur 		memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
1428610c32b2SHoratiu Vultur 		vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
1429610c32b2SHoratiu Vultur 			       actionfield[idx].offset);
1430610c32b2SHoratiu Vultur 		vcap_decode_field(actstream, &iter, actionfield[idx].width,
1431610c32b2SHoratiu Vultur 				  value);
1432610c32b2SHoratiu Vultur 		/* Skip if no bits are set */
1433610c32b2SHoratiu Vultur 		if (vcap_bitarray_zero(actionfield[idx].width, value))
1434610c32b2SHoratiu Vultur 			continue;
1435610c32b2SHoratiu Vultur 		vcap_rule_alloc_actionfield(ri, &actionfield[idx], idx, value);
1436610c32b2SHoratiu Vultur 		/* Later the action id will also be checked */
1437610c32b2SHoratiu Vultur 	}
1438610c32b2SHoratiu Vultur 	return vcap_set_rule_set_actionset((struct vcap_rule *)ri, actionset);
1439610c32b2SHoratiu Vultur }
1440610c32b2SHoratiu Vultur 
1441610c32b2SHoratiu Vultur static int vcap_decode_keyset(struct vcap_rule_internal *ri)
1442610c32b2SHoratiu Vultur {
1443610c32b2SHoratiu Vultur 	struct vcap_control *vctrl = ri->vctrl;
1444610c32b2SHoratiu Vultur 	struct vcap_stream_iter kiter, miter;
1445610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1446610c32b2SHoratiu Vultur 	enum vcap_keyfield_set keysets[10];
1447610c32b2SHoratiu Vultur 	const struct vcap_field *keyfield;
1448610c32b2SHoratiu Vultur 	enum vcap_type vt = admin->vtype;
1449610c32b2SHoratiu Vultur 	const struct vcap_typegroup *tgt;
1450610c32b2SHoratiu Vultur 	struct vcap_keyset_list matches;
1451610c32b2SHoratiu Vultur 	enum vcap_keyfield_set keyset;
1452610c32b2SHoratiu Vultur 	int idx, res, keyfield_count;
1453610c32b2SHoratiu Vultur 	u32 *maskstream;
1454610c32b2SHoratiu Vultur 	u32 *keystream;
1455610c32b2SHoratiu Vultur 	u8 value[16];
1456610c32b2SHoratiu Vultur 	u8 mask[16];
1457610c32b2SHoratiu Vultur 
1458610c32b2SHoratiu Vultur 	keystream = admin->cache.keystream;
1459610c32b2SHoratiu Vultur 	maskstream = admin->cache.maskstream;
1460610c32b2SHoratiu Vultur 	matches.keysets = keysets;
1461610c32b2SHoratiu Vultur 	matches.cnt = 0;
1462610c32b2SHoratiu Vultur 	matches.max = ARRAY_SIZE(keysets);
1463610c32b2SHoratiu Vultur 	res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream,
1464610c32b2SHoratiu Vultur 					  false, 0, &matches);
1465610c32b2SHoratiu Vultur 	if (res < 0) {
1466610c32b2SHoratiu Vultur 		pr_err("%s:%d: could not find valid keysets: %d\n",
1467610c32b2SHoratiu Vultur 		       __func__, __LINE__, res);
1468610c32b2SHoratiu Vultur 		return -EINVAL;
1469610c32b2SHoratiu Vultur 	}
1470610c32b2SHoratiu Vultur 	keyset = matches.keysets[0];
1471610c32b2SHoratiu Vultur 	keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
1472610c32b2SHoratiu Vultur 	keyfield = vcap_keyfields(vctrl, vt, keyset);
1473610c32b2SHoratiu Vultur 	tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
1474610c32b2SHoratiu Vultur 	/* Start decoding the streams */
1475610c32b2SHoratiu Vultur 	for (idx = 0; idx < keyfield_count; ++idx) {
1476610c32b2SHoratiu Vultur 		if (keyfield[idx].width <= 0)
1477610c32b2SHoratiu Vultur 			continue;
1478610c32b2SHoratiu Vultur 		/* First get the mask */
1479610c32b2SHoratiu Vultur 		memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1480610c32b2SHoratiu Vultur 		vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
1481610c32b2SHoratiu Vultur 			       keyfield[idx].offset);
1482610c32b2SHoratiu Vultur 		vcap_decode_field(maskstream, &miter, keyfield[idx].width,
1483610c32b2SHoratiu Vultur 				  mask);
1484610c32b2SHoratiu Vultur 		/* Skip if no mask bits are set */
1485610c32b2SHoratiu Vultur 		if (vcap_bitarray_zero(keyfield[idx].width, mask))
1486610c32b2SHoratiu Vultur 			continue;
1487610c32b2SHoratiu Vultur 		/* Get the key */
1488610c32b2SHoratiu Vultur 		memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1489610c32b2SHoratiu Vultur 		vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
1490610c32b2SHoratiu Vultur 			       keyfield[idx].offset);
1491610c32b2SHoratiu Vultur 		vcap_decode_field(keystream, &kiter, keyfield[idx].width,
1492610c32b2SHoratiu Vultur 				  value);
1493610c32b2SHoratiu Vultur 		vcap_rule_alloc_keyfield(ri, &keyfield[idx], idx, value, mask);
1494610c32b2SHoratiu Vultur 	}
1495610c32b2SHoratiu Vultur 	return vcap_set_rule_set_keyset((struct vcap_rule *)ri, keyset);
1496610c32b2SHoratiu Vultur }
1497610c32b2SHoratiu Vultur 
1498610c32b2SHoratiu Vultur /* Read VCAP content into the VCAP cache */
1499610c32b2SHoratiu Vultur static int vcap_read_rule(struct vcap_rule_internal *ri)
1500610c32b2SHoratiu Vultur {
1501610c32b2SHoratiu Vultur 	struct vcap_admin *admin = ri->admin;
1502610c32b2SHoratiu Vultur 	int sw_idx, ent_idx = 0, act_idx = 0;
1503610c32b2SHoratiu Vultur 	u32 addr = ri->addr;
1504610c32b2SHoratiu Vultur 
1505610c32b2SHoratiu Vultur 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
1506610c32b2SHoratiu Vultur 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
1507610c32b2SHoratiu Vultur 		return -EINVAL;
1508610c32b2SHoratiu Vultur 	}
1509610c32b2SHoratiu Vultur 	vcap_erase_cache(ri);
1510610c32b2SHoratiu Vultur 	/* Use the values in the streams to read the VCAP cache */
1511610c32b2SHoratiu Vultur 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
1512610c32b2SHoratiu Vultur 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
1513610c32b2SHoratiu Vultur 				       VCAP_SEL_ALL, addr);
1514610c32b2SHoratiu Vultur 		ri->vctrl->ops->cache_read(ri->ndev, admin,
1515610c32b2SHoratiu Vultur 					   VCAP_SEL_ENTRY, ent_idx,
1516610c32b2SHoratiu Vultur 					   ri->keyset_sw_regs);
1517610c32b2SHoratiu Vultur 		ri->vctrl->ops->cache_read(ri->ndev, admin,
1518610c32b2SHoratiu Vultur 					   VCAP_SEL_ACTION, act_idx,
1519610c32b2SHoratiu Vultur 					   ri->actionset_sw_regs);
1520610c32b2SHoratiu Vultur 		if (sw_idx == 0)
1521610c32b2SHoratiu Vultur 			ri->vctrl->ops->cache_read(ri->ndev, admin,
1522610c32b2SHoratiu Vultur 						   VCAP_SEL_COUNTER,
1523610c32b2SHoratiu Vultur 						   ri->counter_id, 0);
1524610c32b2SHoratiu Vultur 		ent_idx += ri->keyset_sw_regs;
1525610c32b2SHoratiu Vultur 		act_idx += ri->actionset_sw_regs;
1526610c32b2SHoratiu Vultur 	}
1527610c32b2SHoratiu Vultur 	return 0;
1528610c32b2SHoratiu Vultur }
1529610c32b2SHoratiu Vultur 
15308e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */
15318e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri)
15328e10490bSSteen Hegelund {
15338e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
15348e10490bSSteen Hegelund 	int sw_idx, ent_idx = 0, act_idx = 0;
15358e10490bSSteen Hegelund 	u32 addr = ri->addr;
15368e10490bSSteen Hegelund 
15378e10490bSSteen Hegelund 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
15388e10490bSSteen Hegelund 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
15398e10490bSSteen Hegelund 		return -EINVAL;
15408e10490bSSteen Hegelund 	}
15418e10490bSSteen Hegelund 	/* Use the values in the streams to write the VCAP cache */
15428e10490bSSteen Hegelund 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
15438e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
15448e10490bSSteen Hegelund 					    VCAP_SEL_ENTRY, ent_idx,
15458e10490bSSteen Hegelund 					    ri->keyset_sw_regs);
15468e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
15478e10490bSSteen Hegelund 					    VCAP_SEL_ACTION, act_idx,
15488e10490bSSteen Hegelund 					    ri->actionset_sw_regs);
15498e10490bSSteen Hegelund 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
15508e10490bSSteen Hegelund 				       VCAP_SEL_ALL, addr);
15518e10490bSSteen Hegelund 		ent_idx += ri->keyset_sw_regs;
15528e10490bSSteen Hegelund 		act_idx += ri->actionset_sw_regs;
15538e10490bSSteen Hegelund 	}
15548e10490bSSteen Hegelund 	return 0;
15558e10490bSSteen Hegelund }
15568e10490bSSteen Hegelund 
1557f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri,
1558f13230a4SSteen Hegelund 			      struct vcap_counter *ctr)
1559f13230a4SSteen Hegelund {
1560f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1561f13230a4SSteen Hegelund 
1562f13230a4SSteen Hegelund 	admin->cache.counter = ctr->value;
1563f13230a4SSteen Hegelund 	admin->cache.sticky = ctr->sticky;
1564f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
1565f13230a4SSteen Hegelund 				    ri->counter_id, 0);
1566f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
1567f13230a4SSteen Hegelund 			       VCAP_SEL_COUNTER, ri->addr);
1568f13230a4SSteen Hegelund 	return 0;
1569f13230a4SSteen Hegelund }
1570f13230a4SSteen Hegelund 
15717de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */
15727de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
15737de1dcadSSteen Hegelund {
15747de1dcadSSteen Hegelund 	int lookup_first = admin->vinst * admin->lookups_per_instance;
15757de1dcadSSteen Hegelund 	int lookup_last = lookup_first + admin->lookups_per_instance;
15767de1dcadSSteen Hegelund 	int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE;
15777de1dcadSSteen Hegelund 	int cid = admin->first_cid;
15787de1dcadSSteen Hegelund 	int lookup;
15797de1dcadSSteen Hegelund 
15807de1dcadSSteen Hegelund 	for (lookup = lookup_first; lookup < lookup_last; ++lookup,
15817de1dcadSSteen Hegelund 	     cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE)
15827de1dcadSSteen Hegelund 		if (cur_cid >= cid && cur_cid < cid_next)
15837de1dcadSSteen Hegelund 			return lookup;
15847de1dcadSSteen Hegelund 	return 0;
15857de1dcadSSteen Hegelund }
15867de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup);
15877de1dcadSSteen Hegelund 
1588c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */
1589c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
1590c9da1ac1SSteen Hegelund {
1591c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1592c9da1ac1SSteen Hegelund 
15938e10490bSSteen Hegelund 	if (vcap_api_check(vctrl))
15948e10490bSSteen Hegelund 		return NULL;
15958e10490bSSteen Hegelund 
1596c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
1597c9da1ac1SSteen Hegelund 		if (cid >= admin->first_cid && cid <= admin->last_cid)
1598c9da1ac1SSteen Hegelund 			return admin;
1599c9da1ac1SSteen Hegelund 	}
1600c9da1ac1SSteen Hegelund 	return NULL;
1601c9da1ac1SSteen Hegelund }
1602c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin);
1603c9da1ac1SSteen Hegelund 
1604e7e3f514SSteen Hegelund /* Is this the last admin instance ordered by chain id and direction */
160588bd9ea7SSteen Hegelund static bool vcap_admin_is_last(struct vcap_control *vctrl,
1606e7e3f514SSteen Hegelund 			       struct vcap_admin *admin,
1607e7e3f514SSteen Hegelund 			       bool ingress)
160888bd9ea7SSteen Hegelund {
160988bd9ea7SSteen Hegelund 	struct vcap_admin *iter, *last = NULL;
161088bd9ea7SSteen Hegelund 	int max_cid = 0;
161188bd9ea7SSteen Hegelund 
161288bd9ea7SSteen Hegelund 	list_for_each_entry(iter, &vctrl->list, list) {
1613e7e3f514SSteen Hegelund 		if (iter->first_cid > max_cid &&
1614e7e3f514SSteen Hegelund 		    iter->ingress == ingress) {
161588bd9ea7SSteen Hegelund 			last = iter;
161688bd9ea7SSteen Hegelund 			max_cid = iter->first_cid;
161788bd9ea7SSteen Hegelund 		}
161888bd9ea7SSteen Hegelund 	}
161988bd9ea7SSteen Hegelund 	if (!last)
162088bd9ea7SSteen Hegelund 		return false;
162188bd9ea7SSteen Hegelund 
162288bd9ea7SSteen Hegelund 	return admin == last;
162388bd9ea7SSteen Hegelund }
162488bd9ea7SSteen Hegelund 
162588bd9ea7SSteen Hegelund /* Calculate the value used for chaining VCAP rules */
162688bd9ea7SSteen Hegelund int vcap_chain_offset(struct vcap_control *vctrl, int from_cid, int to_cid)
162788bd9ea7SSteen Hegelund {
162888bd9ea7SSteen Hegelund 	int diff = to_cid - from_cid;
162988bd9ea7SSteen Hegelund 
163088bd9ea7SSteen Hegelund 	if (diff < 0) /* Wrong direction */
163188bd9ea7SSteen Hegelund 		return diff;
163288bd9ea7SSteen Hegelund 	to_cid %= VCAP_CID_LOOKUP_SIZE;
163388bd9ea7SSteen Hegelund 	if (to_cid == 0)  /* Destination aligned to a lookup == no chaining */
163488bd9ea7SSteen Hegelund 		return 0;
163588bd9ea7SSteen Hegelund 	diff %= VCAP_CID_LOOKUP_SIZE;  /* Limit to a value within a lookup */
163688bd9ea7SSteen Hegelund 	return diff;
163788bd9ea7SSteen Hegelund }
163888bd9ea7SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_offset);
163988bd9ea7SSteen Hegelund 
1640784c3067SSteen Hegelund /* Is the next chain id in one of the following lookups
1641784c3067SSteen Hegelund  * For now this does not support filters linked to other filters using
1642784c3067SSteen Hegelund  * keys and actions. That will be added later.
1643784c3067SSteen Hegelund  */
1644784c3067SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int src_cid, int dst_cid)
1645392d0ab0SSteen Hegelund {
1646784c3067SSteen Hegelund 	struct vcap_admin *admin;
1647784c3067SSteen Hegelund 	int next_cid;
1648392d0ab0SSteen Hegelund 
1649392d0ab0SSteen Hegelund 	if (vcap_api_check(vctrl))
1650392d0ab0SSteen Hegelund 		return false;
1651392d0ab0SSteen Hegelund 
1652*0518e914SSteen Hegelund 	/* The offset must be at least one lookup so round up one chain */
1653*0518e914SSteen Hegelund 	next_cid = roundup(src_cid + 1, VCAP_CID_LOOKUP_SIZE);
1654784c3067SSteen Hegelund 
1655784c3067SSteen Hegelund 	if (dst_cid < next_cid)
1656784c3067SSteen Hegelund 		return false;
1657784c3067SSteen Hegelund 
1658784c3067SSteen Hegelund 	admin = vcap_find_admin(vctrl, dst_cid);
1659392d0ab0SSteen Hegelund 	if (!admin)
1660392d0ab0SSteen Hegelund 		return false;
1661392d0ab0SSteen Hegelund 
1662784c3067SSteen Hegelund 	return true;
1663392d0ab0SSteen Hegelund }
1664392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
1665392d0ab0SSteen Hegelund 
16668e10490bSSteen Hegelund /* Check if there is room for a new rule */
16678e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size)
16688e10490bSSteen Hegelund {
16698e10490bSSteen Hegelund 	if (admin->last_used_addr - size < admin->first_valid_addr) {
16708e10490bSSteen Hegelund 		pr_err("%s:%d: No room for rule size: %u, %u\n",
16718e10490bSSteen Hegelund 		       __func__, __LINE__, size, admin->first_valid_addr);
16728e10490bSSteen Hegelund 		return -ENOSPC;
16738e10490bSSteen Hegelund 	}
16748e10490bSSteen Hegelund 	return 0;
16758e10490bSSteen Hegelund }
16768e10490bSSteen Hegelund 
16778e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */
16788e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule)
16798e10490bSSteen Hegelund {
16808e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
16818e10490bSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
16828e10490bSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
16838e10490bSSteen Hegelund 	const struct vcap_field *fields;
16848e10490bSSteen Hegelund 	const struct vcap_set *kset;
16858e10490bSSteen Hegelund 	int ret = -EINVAL;
16868e10490bSSteen Hegelund 
16878e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, vt, keyset);
16888e10490bSSteen Hegelund 	if (!kset)
16898e10490bSSteen Hegelund 		return ret;
16908e10490bSSteen Hegelund 	if (kset->type_id == (u8)-1)  /* No type field is needed */
16918e10490bSSteen Hegelund 		return 0;
16928e10490bSSteen Hegelund 
16938e10490bSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
16948e10490bSSteen Hegelund 	if (!fields)
16958e10490bSSteen Hegelund 		return -EINVAL;
16968e10490bSSteen Hegelund 	if (fields[VCAP_KF_TYPE].width > 1) {
16978e10490bSSteen Hegelund 		ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE,
16988e10490bSSteen Hegelund 					    kset->type_id, 0xff);
16998e10490bSSteen Hegelund 	} else {
17008e10490bSSteen Hegelund 		if (kset->type_id)
17018e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
17028e10490bSSteen Hegelund 						    VCAP_BIT_1);
17038e10490bSSteen Hegelund 		else
17048e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
17058e10490bSSteen Hegelund 						    VCAP_BIT_0);
17068e10490bSSteen Hegelund 	}
17078e10490bSSteen Hegelund 	return 0;
17088e10490bSSteen Hegelund }
17098e10490bSSteen Hegelund 
17107306fcd1SSteen Hegelund /* Add the actionset typefield to the list of rule actionfields */
17117306fcd1SSteen Hegelund static int vcap_add_type_actionfield(struct vcap_rule *rule)
17127306fcd1SSteen Hegelund {
17137306fcd1SSteen Hegelund 	enum vcap_actionfield_set actionset = rule->actionset;
17147306fcd1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
17157306fcd1SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
17167306fcd1SSteen Hegelund 	const struct vcap_field *fields;
17177306fcd1SSteen Hegelund 	const struct vcap_set *aset;
17187306fcd1SSteen Hegelund 	int ret = -EINVAL;
17197306fcd1SSteen Hegelund 
17207306fcd1SSteen Hegelund 	aset = vcap_actionfieldset(ri->vctrl, vt, actionset);
17217306fcd1SSteen Hegelund 	if (!aset)
17227306fcd1SSteen Hegelund 		return ret;
17237306fcd1SSteen Hegelund 	if (aset->type_id == (u8)-1)  /* No type field is needed */
17247306fcd1SSteen Hegelund 		return 0;
17257306fcd1SSteen Hegelund 
17267306fcd1SSteen Hegelund 	fields = vcap_actionfields(ri->vctrl, vt, actionset);
17277306fcd1SSteen Hegelund 	if (!fields)
17287306fcd1SSteen Hegelund 		return -EINVAL;
17297306fcd1SSteen Hegelund 	if (fields[VCAP_AF_TYPE].width > 1) {
17307306fcd1SSteen Hegelund 		ret = vcap_rule_add_action_u32(rule, VCAP_AF_TYPE,
17317306fcd1SSteen Hegelund 					       aset->type_id);
17327306fcd1SSteen Hegelund 	} else {
17337306fcd1SSteen Hegelund 		if (aset->type_id)
17347306fcd1SSteen Hegelund 			ret = vcap_rule_add_action_bit(rule, VCAP_AF_TYPE,
17357306fcd1SSteen Hegelund 						       VCAP_BIT_1);
17367306fcd1SSteen Hegelund 		else
17377306fcd1SSteen Hegelund 			ret = vcap_rule_add_action_bit(rule, VCAP_AF_TYPE,
17387306fcd1SSteen Hegelund 						       VCAP_BIT_0);
17397306fcd1SSteen Hegelund 	}
17407306fcd1SSteen Hegelund 	return ret;
17417306fcd1SSteen Hegelund }
17427306fcd1SSteen Hegelund 
1743abc4010dSSteen Hegelund /* Add a keyset to a keyset list */
1744abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
1745abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset)
1746abc4010dSSteen Hegelund {
1747abc4010dSSteen Hegelund 	int idx;
1748abc4010dSSteen Hegelund 
1749abc4010dSSteen Hegelund 	if (keysetlist->cnt < keysetlist->max) {
1750abc4010dSSteen Hegelund 		/* Avoid duplicates */
1751abc4010dSSteen Hegelund 		for (idx = 0; idx < keysetlist->cnt; ++idx)
1752abc4010dSSteen Hegelund 			if (keysetlist->keysets[idx] == keyset)
1753abc4010dSSteen Hegelund 				return keysetlist->cnt < keysetlist->max;
1754abc4010dSSteen Hegelund 		keysetlist->keysets[keysetlist->cnt++] = keyset;
1755abc4010dSSteen Hegelund 	}
1756abc4010dSSteen Hegelund 	return keysetlist->cnt < keysetlist->max;
1757abc4010dSSteen Hegelund }
1758abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add);
1759abc4010dSSteen Hegelund 
176081e164c4SSteen Hegelund /* Add a actionset to a actionset list */
176181e164c4SSteen Hegelund static bool vcap_actionset_list_add(struct vcap_actionset_list *actionsetlist,
176281e164c4SSteen Hegelund 				    enum vcap_actionfield_set actionset)
176381e164c4SSteen Hegelund {
176481e164c4SSteen Hegelund 	int idx;
176581e164c4SSteen Hegelund 
176681e164c4SSteen Hegelund 	if (actionsetlist->cnt < actionsetlist->max) {
176781e164c4SSteen Hegelund 		/* Avoid duplicates */
176881e164c4SSteen Hegelund 		for (idx = 0; idx < actionsetlist->cnt; ++idx)
176981e164c4SSteen Hegelund 			if (actionsetlist->actionsets[idx] == actionset)
177081e164c4SSteen Hegelund 				return actionsetlist->cnt < actionsetlist->max;
177181e164c4SSteen Hegelund 		actionsetlist->actionsets[actionsetlist->cnt++] = actionset;
177281e164c4SSteen Hegelund 	}
177381e164c4SSteen Hegelund 	return actionsetlist->cnt < actionsetlist->max;
177481e164c4SSteen Hegelund }
177581e164c4SSteen Hegelund 
1776abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */
1777abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl,
1778abc4010dSSteen Hegelund 			     enum vcap_keyfield_set keyset)
1779abc4010dSSteen Hegelund {
1780abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_set_names[keyset];
1781abc4010dSSteen Hegelund }
1782abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name);
1783abc4010dSSteen Hegelund 
1784abc4010dSSteen Hegelund /* map key field id to a string with the key name */
1785abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl,
1786abc4010dSSteen Hegelund 			       enum vcap_key_field key)
1787abc4010dSSteen Hegelund {
1788abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_names[key];
1789abc4010dSSteen Hegelund }
1790abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name);
1791abc4010dSSteen Hegelund 
17923a792156SSteen Hegelund /* map actionset id to a string with the actionset name */
17933a792156SSteen Hegelund const char *vcap_actionset_name(struct vcap_control *vctrl,
17943a792156SSteen Hegelund 				enum vcap_actionfield_set actionset)
17953a792156SSteen Hegelund {
17963a792156SSteen Hegelund 	return vctrl->stats->actionfield_set_names[actionset];
17973a792156SSteen Hegelund }
17983a792156SSteen Hegelund 
1799242df4f7SSteen Hegelund /* map action field id to a string with the action name */
18003a792156SSteen Hegelund const char *vcap_actionfield_name(struct vcap_control *vctrl,
1801242df4f7SSteen Hegelund 				  enum vcap_action_field action)
1802242df4f7SSteen Hegelund {
1803242df4f7SSteen Hegelund 	return vctrl->stats->actionfield_names[action];
1804242df4f7SSteen Hegelund }
1805242df4f7SSteen Hegelund 
1806abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */
1807abc4010dSSteen Hegelund static const struct vcap_field *
1808abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl,
1809abc4010dSSteen Hegelund 			  enum vcap_type vtype,
1810abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset,
1811abc4010dSSteen Hegelund 			  enum vcap_key_field key)
1812abc4010dSSteen Hegelund {
1813abc4010dSSteen Hegelund 	const struct vcap_field *fields;
1814abc4010dSSteen Hegelund 	int idx, count;
1815abc4010dSSteen Hegelund 
1816abc4010dSSteen Hegelund 	fields = vcap_keyfields(vctrl, vtype, keyset);
1817abc4010dSSteen Hegelund 	if (!fields)
1818abc4010dSSteen Hegelund 		return NULL;
1819abc4010dSSteen Hegelund 
1820abc4010dSSteen Hegelund 	/* Iterate the keyfields of the keyset */
1821abc4010dSSteen Hegelund 	count = vcap_keyfield_count(vctrl, vtype, keyset);
1822abc4010dSSteen Hegelund 	for (idx = 0; idx < count; ++idx) {
1823abc4010dSSteen Hegelund 		if (fields[idx].width == 0)
1824abc4010dSSteen Hegelund 			continue;
1825abc4010dSSteen Hegelund 
1826abc4010dSSteen Hegelund 		if (key == idx)
1827abc4010dSSteen Hegelund 			return &fields[idx];
1828abc4010dSSteen Hegelund 	}
1829abc4010dSSteen Hegelund 
1830abc4010dSSteen Hegelund 	return NULL;
1831abc4010dSSteen Hegelund }
1832abc4010dSSteen Hegelund 
1833abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
1834465a38a2SSteen Hegelund static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri,
1835abc4010dSSteen Hegelund 				    struct vcap_keyset_list *matches)
1836abc4010dSSteen Hegelund {
1837abc4010dSSteen Hegelund 	const struct vcap_client_keyfield *ckf;
1838abc4010dSSteen Hegelund 	int keyset, found, keycount, map_size;
1839abc4010dSSteen Hegelund 	const struct vcap_field **map;
1840abc4010dSSteen Hegelund 	enum vcap_type vtype;
1841abc4010dSSteen Hegelund 
1842abc4010dSSteen Hegelund 	vtype = ri->admin->vtype;
1843abc4010dSSteen Hegelund 	map = ri->vctrl->vcaps[vtype].keyfield_set_map;
1844abc4010dSSteen Hegelund 	map_size = ri->vctrl->vcaps[vtype].keyfield_set_size;
1845abc4010dSSteen Hegelund 
1846abc4010dSSteen Hegelund 	/* Get a count of the keyfields we want to match */
1847abc4010dSSteen Hegelund 	keycount = 0;
1848abc4010dSSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1849abc4010dSSteen Hegelund 		++keycount;
1850abc4010dSSteen Hegelund 
1851abc4010dSSteen Hegelund 	matches->cnt = 0;
1852abc4010dSSteen Hegelund 	/* Iterate the keysets of the VCAP */
1853abc4010dSSteen Hegelund 	for (keyset = 0; keyset < map_size; ++keyset) {
1854abc4010dSSteen Hegelund 		if (!map[keyset])
1855abc4010dSSteen Hegelund 			continue;
1856abc4010dSSteen Hegelund 
1857abc4010dSSteen Hegelund 		/* Iterate the keys in the rule */
1858abc4010dSSteen Hegelund 		found = 0;
1859abc4010dSSteen Hegelund 		list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1860abc4010dSSteen Hegelund 			if (vcap_find_keyset_keyfield(ri->vctrl, vtype,
1861abc4010dSSteen Hegelund 						      keyset, ckf->ctrl.key))
1862abc4010dSSteen Hegelund 				++found;
1863abc4010dSSteen Hegelund 
1864abc4010dSSteen Hegelund 		/* Save the keyset if all keyfields were found */
1865abc4010dSSteen Hegelund 		if (found == keycount)
1866abc4010dSSteen Hegelund 			if (!vcap_keyset_list_add(matches, keyset))
1867abc4010dSSteen Hegelund 				/* bail out when the quota is filled */
1868abc4010dSSteen Hegelund 				break;
1869abc4010dSSteen Hegelund 	}
1870abc4010dSSteen Hegelund 
1871abc4010dSSteen Hegelund 	return matches->cnt > 0;
1872abc4010dSSteen Hegelund }
1873abc4010dSSteen Hegelund 
1874465a38a2SSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
1875465a38a2SSteen Hegelund bool vcap_rule_find_keysets(struct vcap_rule *rule,
1876465a38a2SSteen Hegelund 			    struct vcap_keyset_list *matches)
1877465a38a2SSteen Hegelund {
1878465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1879465a38a2SSteen Hegelund 
1880465a38a2SSteen Hegelund 	return _vcap_rule_find_keysets(ri, matches);
1881465a38a2SSteen Hegelund }
1882465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_find_keysets);
1883465a38a2SSteen Hegelund 
188481e164c4SSteen Hegelund /* Return the actionfield that matches a action in a actionset */
188581e164c4SSteen Hegelund static const struct vcap_field *
188681e164c4SSteen Hegelund vcap_find_actionset_actionfield(struct vcap_control *vctrl,
188781e164c4SSteen Hegelund 				enum vcap_type vtype,
188881e164c4SSteen Hegelund 				enum vcap_actionfield_set actionset,
188981e164c4SSteen Hegelund 				enum vcap_action_field action)
189081e164c4SSteen Hegelund {
189181e164c4SSteen Hegelund 	const struct vcap_field *fields;
189281e164c4SSteen Hegelund 	int idx, count;
189381e164c4SSteen Hegelund 
189481e164c4SSteen Hegelund 	fields = vcap_actionfields(vctrl, vtype, actionset);
189581e164c4SSteen Hegelund 	if (!fields)
189681e164c4SSteen Hegelund 		return NULL;
189781e164c4SSteen Hegelund 
189881e164c4SSteen Hegelund 	/* Iterate the actionfields of the actionset */
189981e164c4SSteen Hegelund 	count = vcap_actionfield_count(vctrl, vtype, actionset);
190081e164c4SSteen Hegelund 	for (idx = 0; idx < count; ++idx) {
190181e164c4SSteen Hegelund 		if (fields[idx].width == 0)
190281e164c4SSteen Hegelund 			continue;
190381e164c4SSteen Hegelund 
190481e164c4SSteen Hegelund 		if (action == idx)
190581e164c4SSteen Hegelund 			return &fields[idx];
190681e164c4SSteen Hegelund 	}
190781e164c4SSteen Hegelund 
190881e164c4SSteen Hegelund 	return NULL;
190981e164c4SSteen Hegelund }
191081e164c4SSteen Hegelund 
191181e164c4SSteen Hegelund /* Match a list of actions against the actionsets available in a vcap type */
191281e164c4SSteen Hegelund static bool vcap_rule_find_actionsets(struct vcap_rule_internal *ri,
191381e164c4SSteen Hegelund 				      struct vcap_actionset_list *matches)
191481e164c4SSteen Hegelund {
191581e164c4SSteen Hegelund 	int actionset, found, actioncount, map_size;
191681e164c4SSteen Hegelund 	const struct vcap_client_actionfield *ckf;
191781e164c4SSteen Hegelund 	const struct vcap_field **map;
191881e164c4SSteen Hegelund 	enum vcap_type vtype;
191981e164c4SSteen Hegelund 
192081e164c4SSteen Hegelund 	vtype = ri->admin->vtype;
192181e164c4SSteen Hegelund 	map = ri->vctrl->vcaps[vtype].actionfield_set_map;
192281e164c4SSteen Hegelund 	map_size = ri->vctrl->vcaps[vtype].actionfield_set_size;
192381e164c4SSteen Hegelund 
192481e164c4SSteen Hegelund 	/* Get a count of the actionfields we want to match */
192581e164c4SSteen Hegelund 	actioncount = 0;
192681e164c4SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.actionfields, ctrl.list)
192781e164c4SSteen Hegelund 		++actioncount;
192881e164c4SSteen Hegelund 
192981e164c4SSteen Hegelund 	matches->cnt = 0;
193081e164c4SSteen Hegelund 	/* Iterate the actionsets of the VCAP */
193181e164c4SSteen Hegelund 	for (actionset = 0; actionset < map_size; ++actionset) {
193281e164c4SSteen Hegelund 		if (!map[actionset])
193381e164c4SSteen Hegelund 			continue;
193481e164c4SSteen Hegelund 
193581e164c4SSteen Hegelund 		/* Iterate the actions in the rule */
193681e164c4SSteen Hegelund 		found = 0;
193781e164c4SSteen Hegelund 		list_for_each_entry(ckf, &ri->data.actionfields, ctrl.list)
193881e164c4SSteen Hegelund 			if (vcap_find_actionset_actionfield(ri->vctrl, vtype,
193981e164c4SSteen Hegelund 							    actionset,
194081e164c4SSteen Hegelund 							    ckf->ctrl.action))
194181e164c4SSteen Hegelund 				++found;
194281e164c4SSteen Hegelund 
194381e164c4SSteen Hegelund 		/* Save the actionset if all actionfields were found */
194481e164c4SSteen Hegelund 		if (found == actioncount)
194581e164c4SSteen Hegelund 			if (!vcap_actionset_list_add(matches, actionset))
194681e164c4SSteen Hegelund 				/* bail out when the quota is filled */
194781e164c4SSteen Hegelund 				break;
194881e164c4SSteen Hegelund 	}
194981e164c4SSteen Hegelund 
195081e164c4SSteen Hegelund 	return matches->cnt > 0;
195181e164c4SSteen Hegelund }
195281e164c4SSteen Hegelund 
1953c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
1954c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
1955c9da1ac1SSteen Hegelund {
1956c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1957abc4010dSSteen Hegelund 	struct vcap_keyset_list matches = {};
19588e10490bSSteen Hegelund 	enum vcap_keyfield_set keysets[10];
19598e10490bSSteen Hegelund 	int ret;
1960c9da1ac1SSteen Hegelund 
19618e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
19628e10490bSSteen Hegelund 	if (ret)
19638e10490bSSteen Hegelund 		return ret;
1964c9da1ac1SSteen Hegelund 	if (!ri->admin) {
1965c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ADMIN;
1966c9da1ac1SSteen Hegelund 		return -EINVAL;
1967c9da1ac1SSteen Hegelund 	}
1968c9da1ac1SSteen Hegelund 	if (!ri->ndev) {
1969c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_NETDEV;
1970c9da1ac1SSteen Hegelund 		return -EINVAL;
1971c9da1ac1SSteen Hegelund 	}
1972abc4010dSSteen Hegelund 
1973abc4010dSSteen Hegelund 	matches.keysets = keysets;
1974abc4010dSSteen Hegelund 	matches.max = ARRAY_SIZE(keysets);
1975c9da1ac1SSteen Hegelund 	if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
1976abc4010dSSteen Hegelund 		/* Iterate over rule keyfields and select keysets that fits */
1977465a38a2SSteen Hegelund 		if (!_vcap_rule_find_keysets(ri, &matches)) {
1978c9da1ac1SSteen Hegelund 			ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
1979c9da1ac1SSteen Hegelund 			return -EINVAL;
1980c9da1ac1SSteen Hegelund 		}
1981abc4010dSSteen Hegelund 	} else {
19828e10490bSSteen Hegelund 		/* prepare for keyset validation */
19838e10490bSSteen Hegelund 		keysets[0] = ri->data.keyset;
1984abc4010dSSteen Hegelund 		matches.cnt = 1;
1985abc4010dSSteen Hegelund 	}
1986abc4010dSSteen Hegelund 
19878e10490bSSteen Hegelund 	/* Pick a keyset that is supported in the port lookups */
1988abc4010dSSteen Hegelund 	ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule,
1989abc4010dSSteen Hegelund 					      &matches, l3_proto);
19908e10490bSSteen Hegelund 	if (ret < 0) {
19918e10490bSSteen Hegelund 		pr_err("%s:%d: keyset validation failed: %d\n",
19928e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
19938e10490bSSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
19948e10490bSSteen Hegelund 		return ret;
19958e10490bSSteen Hegelund 	}
1996abc4010dSSteen Hegelund 	/* use the keyset that is supported in the port lookups */
1997abc4010dSSteen Hegelund 	ret = vcap_set_rule_set_keyset(rule, ret);
1998abc4010dSSteen Hegelund 	if (ret < 0) {
1999abc4010dSSteen Hegelund 		pr_err("%s:%d: keyset was not updated: %d\n",
2000abc4010dSSteen Hegelund 		       __func__, __LINE__, ret);
2001abc4010dSSteen Hegelund 		return ret;
2002abc4010dSSteen Hegelund 	}
2003c9da1ac1SSteen Hegelund 	if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
200481e164c4SSteen Hegelund 		struct vcap_actionset_list matches = {};
200581e164c4SSteen Hegelund 		enum vcap_actionfield_set actionsets[10];
200681e164c4SSteen Hegelund 
200781e164c4SSteen Hegelund 		matches.actionsets = actionsets;
200881e164c4SSteen Hegelund 		matches.max = ARRAY_SIZE(actionsets);
200981e164c4SSteen Hegelund 
201081e164c4SSteen Hegelund 		/* Find an actionset that fits the rule actions */
201181e164c4SSteen Hegelund 		if (!vcap_rule_find_actionsets(ri, &matches)) {
2012c9da1ac1SSteen Hegelund 			ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
2013c9da1ac1SSteen Hegelund 			return -EINVAL;
2014c9da1ac1SSteen Hegelund 		}
201581e164c4SSteen Hegelund 		ret = vcap_set_rule_set_actionset(rule, actionsets[0]);
201681e164c4SSteen Hegelund 		if (ret < 0) {
201781e164c4SSteen Hegelund 			pr_err("%s:%d: actionset was not updated: %d\n",
201881e164c4SSteen Hegelund 			       __func__, __LINE__, ret);
201981e164c4SSteen Hegelund 			return ret;
202081e164c4SSteen Hegelund 		}
202181e164c4SSteen Hegelund 	}
20228e10490bSSteen Hegelund 	vcap_add_type_keyfield(rule);
20237306fcd1SSteen Hegelund 	vcap_add_type_actionfield(rule);
20248e10490bSSteen Hegelund 	/* Add default fields to this rule */
20258e10490bSSteen Hegelund 	ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
20268e10490bSSteen Hegelund 
20278e10490bSSteen Hegelund 	/* Rule size is the maximum of the entry and action subword count */
20288e10490bSSteen Hegelund 	ri->size = max(ri->keyset_sw, ri->actionset_sw);
20298e10490bSSteen Hegelund 
20308e10490bSSteen Hegelund 	/* Finally check if there is room for the rule in the VCAP */
20318e10490bSSteen Hegelund 	return vcap_rule_space(ri->admin, ri->size);
2032c9da1ac1SSteen Hegelund }
2033c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
2034c9da1ac1SSteen Hegelund 
2035990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key.
2036990e4839SSteen Hegelund  * I.e. Lowest numerical sort_key is first in list.
2037990e4839SSteen Hegelund  * In order to locate largest keys first in list we negate the key size with
2038990e4839SSteen Hegelund  * (max_size - size).
2039990e4839SSteen Hegelund  */
2040990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
2041990e4839SSteen Hegelund {
2042990e4839SSteen Hegelund 	return ((max_size - size) << 24) | (user << 16) | prio;
2043990e4839SSteen Hegelund }
2044990e4839SSteen Hegelund 
20458e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
20468e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
20478e10490bSSteen Hegelund {
20488e10490bSSteen Hegelund 	return ((addr - ri->size) /  ri->size) * ri->size;
20498e10490bSSteen Hegelund }
20508e10490bSSteen Hegelund 
2051c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
2052c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
2053c9da1ac1SSteen Hegelund {
2054c9da1ac1SSteen Hegelund 	if (ri->data.id != 0)
2055c9da1ac1SSteen Hegelund 		return ri->data.id;
2056c9da1ac1SSteen Hegelund 
2057c1d8e3fbSHoratiu Vultur 	for (u32 next_id = 1; next_id < ~0; ++next_id) {
2058975d86acSSteen Hegelund 		if (!vcap_rule_exists(ri->vctrl, next_id)) {
2059c9da1ac1SSteen Hegelund 			ri->data.id = next_id;
2060c9da1ac1SSteen Hegelund 			break;
2061c9da1ac1SSteen Hegelund 		}
2062c9da1ac1SSteen Hegelund 	}
2063c9da1ac1SSteen Hegelund 	return ri->data.id;
2064c9da1ac1SSteen Hegelund }
2065c9da1ac1SSteen Hegelund 
20668e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
20678e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
20688e10490bSSteen Hegelund {
2069990e4839SSteen Hegelund 	int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
2070990e4839SSteen Hegelund 	struct vcap_rule_internal *duprule, *iter, *elem = NULL;
20718e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
2072990e4839SSteen Hegelund 	u32 addr;
20738e10490bSSteen Hegelund 
2074990e4839SSteen Hegelund 	ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
2075990e4839SSteen Hegelund 				     ri->data.priority);
2076990e4839SSteen Hegelund 
2077990e4839SSteen Hegelund 	/* Insert the new rule in the list of rule based on the sort key
2078990e4839SSteen Hegelund 	 * If the rule needs to be  inserted between existing rules then move
2079990e4839SSteen Hegelund 	 * these rules to make room for the new rule and update their start
2080990e4839SSteen Hegelund 	 * address.
2081990e4839SSteen Hegelund 	 */
2082990e4839SSteen Hegelund 	list_for_each_entry(iter, &admin->rules, list) {
2083990e4839SSteen Hegelund 		if (ri->sort_key < iter->sort_key) {
2084990e4839SSteen Hegelund 			elem = iter;
2085990e4839SSteen Hegelund 			break;
2086990e4839SSteen Hegelund 		}
2087990e4839SSteen Hegelund 	}
2088990e4839SSteen Hegelund 
2089990e4839SSteen Hegelund 	if (!elem) {
20908e10490bSSteen Hegelund 		ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
20918e10490bSSteen Hegelund 		admin->last_used_addr = ri->addr;
2092990e4839SSteen Hegelund 
2093814e7693SSteen Hegelund 		/* Add a copy of the rule to the VCAP list */
2094814e7693SSteen Hegelund 		duprule = vcap_dup_rule(ri, ri->state == VCAP_RS_DISABLED);
20958e10490bSSteen Hegelund 		if (IS_ERR(duprule))
20968e10490bSSteen Hegelund 			return PTR_ERR(duprule);
2097990e4839SSteen Hegelund 
20988e10490bSSteen Hegelund 		list_add_tail(&duprule->list, &admin->rules);
20998e10490bSSteen Hegelund 		return 0;
21008e10490bSSteen Hegelund 	}
21018e10490bSSteen Hegelund 
2102990e4839SSteen Hegelund 	/* Reuse the space of the current rule */
2103990e4839SSteen Hegelund 	addr = elem->addr + elem->size;
2104990e4839SSteen Hegelund 	ri->addr = vcap_next_rule_addr(addr, ri);
2105990e4839SSteen Hegelund 	addr = ri->addr;
2106990e4839SSteen Hegelund 
2107814e7693SSteen Hegelund 	/* Add a copy of the rule to the VCAP list */
2108814e7693SSteen Hegelund 	duprule = vcap_dup_rule(ri, ri->state == VCAP_RS_DISABLED);
2109990e4839SSteen Hegelund 	if (IS_ERR(duprule))
2110990e4839SSteen Hegelund 		return PTR_ERR(duprule);
2111990e4839SSteen Hegelund 
2112990e4839SSteen Hegelund 	/* Add before the current entry */
2113990e4839SSteen Hegelund 	list_add_tail(&duprule->list, &elem->list);
2114990e4839SSteen Hegelund 
2115990e4839SSteen Hegelund 	/* Update the current rule */
2116990e4839SSteen Hegelund 	elem->addr = vcap_next_rule_addr(addr, elem);
2117990e4839SSteen Hegelund 	addr = elem->addr;
2118990e4839SSteen Hegelund 
2119990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
2120990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list) {
2121990e4839SSteen Hegelund 		elem->addr = vcap_next_rule_addr(addr, elem);
2122990e4839SSteen Hegelund 		addr = elem->addr;
2123990e4839SSteen Hegelund 	}
2124990e4839SSteen Hegelund 
2125990e4839SSteen Hegelund 	/* Update the move info */
2126990e4839SSteen Hegelund 	move->addr = admin->last_used_addr;
2127990e4839SSteen Hegelund 	move->count = ri->addr - addr;
2128990e4839SSteen Hegelund 	move->offset = admin->last_used_addr - addr;
2129990e4839SSteen Hegelund 	admin->last_used_addr = addr;
2130990e4839SSteen Hegelund 	return 0;
2131990e4839SSteen Hegelund }
2132990e4839SSteen Hegelund 
21338e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
21348e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
21358e10490bSSteen Hegelund {
21368e10490bSSteen Hegelund 	ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
21378e10490bSSteen Hegelund 			 move->offset, move->count);
21388e10490bSSteen Hegelund }
21398e10490bSSteen Hegelund 
2140cfd9e7b7SSteen Hegelund /* Check if the chain is already used to enable a VCAP lookup for this port */
2141cfd9e7b7SSteen Hegelund static bool vcap_is_chain_used(struct vcap_control *vctrl,
2142cfd9e7b7SSteen Hegelund 			       struct net_device *ndev, int src_cid)
2143cfd9e7b7SSteen Hegelund {
2144cfd9e7b7SSteen Hegelund 	struct vcap_enabled_port *eport;
2145cfd9e7b7SSteen Hegelund 	struct vcap_admin *admin;
2146cfd9e7b7SSteen Hegelund 
2147cfd9e7b7SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
2148cfd9e7b7SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list)
2149cfd9e7b7SSteen Hegelund 			if (eport->src_cid == src_cid && eport->ndev == ndev)
2150cfd9e7b7SSteen Hegelund 				return true;
2151cfd9e7b7SSteen Hegelund 
2152cfd9e7b7SSteen Hegelund 	return false;
2153cfd9e7b7SSteen Hegelund }
2154cfd9e7b7SSteen Hegelund 
2155814e7693SSteen Hegelund /* Fetch the next chain in the enabled list for the port */
2156814e7693SSteen Hegelund static int vcap_get_next_chain(struct vcap_control *vctrl,
2157814e7693SSteen Hegelund 			       struct net_device *ndev,
2158814e7693SSteen Hegelund 			       int dst_cid)
2159814e7693SSteen Hegelund {
2160814e7693SSteen Hegelund 	struct vcap_enabled_port *eport;
2161814e7693SSteen Hegelund 	struct vcap_admin *admin;
2162814e7693SSteen Hegelund 
2163814e7693SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
2164814e7693SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list) {
2165814e7693SSteen Hegelund 			if (eport->ndev != ndev)
2166814e7693SSteen Hegelund 				continue;
2167814e7693SSteen Hegelund 			if (eport->src_cid == dst_cid)
2168814e7693SSteen Hegelund 				return eport->dst_cid;
2169814e7693SSteen Hegelund 		}
2170814e7693SSteen Hegelund 	}
2171814e7693SSteen Hegelund 
2172814e7693SSteen Hegelund 	return 0;
2173814e7693SSteen Hegelund }
2174814e7693SSteen Hegelund 
2175814e7693SSteen Hegelund static bool vcap_path_exist(struct vcap_control *vctrl, struct net_device *ndev,
2176814e7693SSteen Hegelund 			    int dst_cid)
2177814e7693SSteen Hegelund {
2178*0518e914SSteen Hegelund 	int cid = rounddown(dst_cid, VCAP_CID_LOOKUP_SIZE);
21793bee9b57SDan Carpenter 	struct vcap_enabled_port *eport = NULL;
21803bee9b57SDan Carpenter 	struct vcap_enabled_port *elem;
2181814e7693SSteen Hegelund 	struct vcap_admin *admin;
2182814e7693SSteen Hegelund 	int tmp;
2183814e7693SSteen Hegelund 
2184*0518e914SSteen Hegelund 	if (cid == 0) /* Chain zero is always available */
218518a15c76SSteen Hegelund 		return true;
218618a15c76SSteen Hegelund 
2187814e7693SSteen Hegelund 	/* Find first entry that starts from chain 0*/
2188814e7693SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
2189814e7693SSteen Hegelund 		list_for_each_entry(elem, &admin->enabled, list) {
2190814e7693SSteen Hegelund 			if (elem->src_cid == 0 && elem->ndev == ndev) {
2191814e7693SSteen Hegelund 				eport = elem;
2192814e7693SSteen Hegelund 				break;
2193814e7693SSteen Hegelund 			}
2194814e7693SSteen Hegelund 		}
2195814e7693SSteen Hegelund 		if (eport)
2196814e7693SSteen Hegelund 			break;
2197814e7693SSteen Hegelund 	}
2198814e7693SSteen Hegelund 
2199814e7693SSteen Hegelund 	if (!eport)
2200814e7693SSteen Hegelund 		return false;
2201814e7693SSteen Hegelund 
2202814e7693SSteen Hegelund 	tmp = eport->dst_cid;
2203*0518e914SSteen Hegelund 	while (tmp != cid && tmp != 0)
2204814e7693SSteen Hegelund 		tmp = vcap_get_next_chain(vctrl, ndev, tmp);
2205814e7693SSteen Hegelund 
2206814e7693SSteen Hegelund 	return !!tmp;
2207814e7693SSteen Hegelund }
2208814e7693SSteen Hegelund 
2209814e7693SSteen Hegelund /* Internal clients can always store their rules in HW
2210814e7693SSteen Hegelund  * External clients can store their rules if the chain is enabled all
2211814e7693SSteen Hegelund  * the way from chain 0, otherwise the rule will be cached until
2212814e7693SSteen Hegelund  * the chain is enabled.
2213814e7693SSteen Hegelund  */
2214814e7693SSteen Hegelund static void vcap_rule_set_state(struct vcap_rule_internal *ri)
2215814e7693SSteen Hegelund {
2216814e7693SSteen Hegelund 	if (ri->data.user <= VCAP_USER_QOS)
2217814e7693SSteen Hegelund 		ri->state = VCAP_RS_PERMANENT;
2218814e7693SSteen Hegelund 	else if (vcap_path_exist(ri->vctrl, ri->ndev, ri->data.vcap_chain_id))
2219814e7693SSteen Hegelund 		ri->state = VCAP_RS_ENABLED;
2220814e7693SSteen Hegelund 	else
2221814e7693SSteen Hegelund 		ri->state = VCAP_RS_DISABLED;
2222814e7693SSteen Hegelund }
2223814e7693SSteen Hegelund 
2224c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
2225c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
2226c9da1ac1SSteen Hegelund {
22278e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
22288e10490bSSteen Hegelund 	struct vcap_rule_move move = {0};
222995fa7414SSteen Hegelund 	struct vcap_counter ctr = {0};
22308e10490bSSteen Hegelund 	int ret;
22318e10490bSSteen Hegelund 
22328e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
22338e10490bSSteen Hegelund 	if (ret)
22348e10490bSSteen Hegelund 		return ret;
22358e10490bSSteen Hegelund 	/* Insert the new rule in the list of vcap rules */
223671c9de99SSteen Hegelund 	mutex_lock(&ri->admin->lock);
2237814e7693SSteen Hegelund 
2238814e7693SSteen Hegelund 	vcap_rule_set_state(ri);
22398e10490bSSteen Hegelund 	ret = vcap_insert_rule(ri, &move);
22408e10490bSSteen Hegelund 	if (ret < 0) {
22418e10490bSSteen Hegelund 		pr_err("%s:%d: could not insert rule in vcap list: %d\n",
22428e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
22438e10490bSSteen Hegelund 		goto out;
22448e10490bSSteen Hegelund 	}
22458e10490bSSteen Hegelund 	if (move.count > 0)
22468e10490bSSteen Hegelund 		vcap_move_rules(ri, &move);
2247814e7693SSteen Hegelund 
2248d7953da4SSteen Hegelund 	/* Set the counter to zero */
2249d7953da4SSteen Hegelund 	ret = vcap_write_counter(ri, &ctr);
2250d7953da4SSteen Hegelund 	if (ret)
2251d7953da4SSteen Hegelund 		goto out;
2252d7953da4SSteen Hegelund 
2253814e7693SSteen Hegelund 	if (ri->state == VCAP_RS_DISABLED) {
2254814e7693SSteen Hegelund 		/* Erase the rule area */
2255814e7693SSteen Hegelund 		ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size);
2256814e7693SSteen Hegelund 		goto out;
2257814e7693SSteen Hegelund 	}
2258814e7693SSteen Hegelund 
22596573f71aSSteen Hegelund 	vcap_erase_cache(ri);
22608e10490bSSteen Hegelund 	ret = vcap_encode_rule(ri);
22618e10490bSSteen Hegelund 	if (ret) {
22628e10490bSSteen Hegelund 		pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
22638e10490bSSteen Hegelund 		goto out;
22648e10490bSSteen Hegelund 	}
22658e10490bSSteen Hegelund 
22668e10490bSSteen Hegelund 	ret = vcap_write_rule(ri);
226795fa7414SSteen Hegelund 	if (ret) {
22688e10490bSSteen Hegelund 		pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
226995fa7414SSteen Hegelund 		goto out;
227095fa7414SSteen Hegelund 	}
22718e10490bSSteen Hegelund out:
227271c9de99SSteen Hegelund 	mutex_unlock(&ri->admin->lock);
22738e10490bSSteen Hegelund 	return ret;
2274c9da1ac1SSteen Hegelund }
2275c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
2276c9da1ac1SSteen Hegelund 
2277c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
2278c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
2279c9da1ac1SSteen Hegelund 				  struct net_device *ndev, int vcap_chain_id,
2280c9da1ac1SSteen Hegelund 				  enum vcap_user user, u16 priority,
2281c9da1ac1SSteen Hegelund 				  u32 id)
2282c9da1ac1SSteen Hegelund {
2283c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
2284c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
2285990e4839SSteen Hegelund 	int err, maxsize;
2286c9da1ac1SSteen Hegelund 
2287990e4839SSteen Hegelund 	err = vcap_api_check(vctrl);
2288990e4839SSteen Hegelund 	if (err)
2289990e4839SSteen Hegelund 		return ERR_PTR(err);
2290c9da1ac1SSteen Hegelund 	if (!ndev)
2291c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENODEV);
2292c9da1ac1SSteen Hegelund 	/* Get the VCAP instance */
2293c9da1ac1SSteen Hegelund 	admin = vcap_find_admin(vctrl, vcap_chain_id);
2294c9da1ac1SSteen Hegelund 	if (!admin)
2295c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOENT);
22968e10490bSSteen Hegelund 	/* Sanity check that this VCAP is supported on this platform */
22978e10490bSSteen Hegelund 	if (vctrl->vcaps[admin->vtype].rows == 0)
22988e10490bSSteen Hegelund 		return ERR_PTR(-EINVAL);
22991972b6d9SSteen Hegelund 
23001972b6d9SSteen Hegelund 	mutex_lock(&admin->lock);
23018e10490bSSteen Hegelund 	/* Check if a rule with this id already exists */
23021972b6d9SSteen Hegelund 	if (vcap_rule_exists(vctrl, id)) {
23031972b6d9SSteen Hegelund 		err = -EINVAL;
23041972b6d9SSteen Hegelund 		goto out_unlock;
23051972b6d9SSteen Hegelund 	}
23061972b6d9SSteen Hegelund 
23078e10490bSSteen Hegelund 	/* Check if there is room for the rule in the block(s) of the VCAP */
23088e10490bSSteen Hegelund 	maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
23091972b6d9SSteen Hegelund 	if (vcap_rule_space(admin, maxsize)) {
23101972b6d9SSteen Hegelund 		err = -ENOSPC;
23111972b6d9SSteen Hegelund 		goto out_unlock;
23121972b6d9SSteen Hegelund 	}
23131972b6d9SSteen Hegelund 
2314c9da1ac1SSteen Hegelund 	/* Create a container for the rule and return it */
2315c9da1ac1SSteen Hegelund 	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
23161972b6d9SSteen Hegelund 	if (!ri) {
23171972b6d9SSteen Hegelund 		err = -ENOMEM;
23181972b6d9SSteen Hegelund 		goto out_unlock;
23191972b6d9SSteen Hegelund 	}
23201972b6d9SSteen Hegelund 
2321c9da1ac1SSteen Hegelund 	ri->data.vcap_chain_id = vcap_chain_id;
2322c9da1ac1SSteen Hegelund 	ri->data.user = user;
2323c9da1ac1SSteen Hegelund 	ri->data.priority = priority;
2324c9da1ac1SSteen Hegelund 	ri->data.id = id;
2325c9da1ac1SSteen Hegelund 	ri->data.keyset = VCAP_KFS_NO_VALUE;
2326c9da1ac1SSteen Hegelund 	ri->data.actionset = VCAP_AFS_NO_VALUE;
2327c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->list);
2328c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.keyfields);
2329c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.actionfields);
2330c9da1ac1SSteen Hegelund 	ri->ndev = ndev;
2331c9da1ac1SSteen Hegelund 	ri->admin = admin; /* refer to the vcap instance */
2332c9da1ac1SSteen Hegelund 	ri->vctrl = vctrl; /* refer to the client */
23331972b6d9SSteen Hegelund 
23341972b6d9SSteen Hegelund 	if (vcap_set_rule_id(ri) == 0) {
23351972b6d9SSteen Hegelund 		err = -EINVAL;
2336c9da1ac1SSteen Hegelund 		goto out_free;
23371972b6d9SSteen Hegelund 	}
23381972b6d9SSteen Hegelund 
23391972b6d9SSteen Hegelund 	mutex_unlock(&admin->lock);
2340c9da1ac1SSteen Hegelund 	return (struct vcap_rule *)ri;
2341c9da1ac1SSteen Hegelund 
2342c9da1ac1SSteen Hegelund out_free:
2343c9da1ac1SSteen Hegelund 	kfree(ri);
23441972b6d9SSteen Hegelund out_unlock:
23451972b6d9SSteen Hegelund 	mutex_unlock(&admin->lock);
23461972b6d9SSteen Hegelund 	return ERR_PTR(err);
23471972b6d9SSteen Hegelund 
2348c9da1ac1SSteen Hegelund }
2349c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
2350c9da1ac1SSteen Hegelund 
2351c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
2352c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
2353c9da1ac1SSteen Hegelund {
2354c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2355c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *caf, *next_caf;
2356c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
2357c9da1ac1SSteen Hegelund 
2358c9da1ac1SSteen Hegelund 	/* Deallocate the list of keys and actions */
2359c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
2360c9da1ac1SSteen Hegelund 		list_del(&ckf->ctrl.list);
2361c9da1ac1SSteen Hegelund 		kfree(ckf);
2362c9da1ac1SSteen Hegelund 	}
2363c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
2364c9da1ac1SSteen Hegelund 		list_del(&caf->ctrl.list);
2365c9da1ac1SSteen Hegelund 		kfree(caf);
2366c9da1ac1SSteen Hegelund 	}
2367c9da1ac1SSteen Hegelund 	/* Deallocate the rule */
2368c9da1ac1SSteen Hegelund 	kfree(rule);
2369c9da1ac1SSteen Hegelund }
2370c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
2371c9da1ac1SSteen Hegelund 
23729579e2c2SSteen Hegelund /* Decode a rule from the VCAP cache and return a copy */
23739579e2c2SSteen Hegelund struct vcap_rule *vcap_decode_rule(struct vcap_rule_internal *elem)
2374610c32b2SHoratiu Vultur {
2375610c32b2SHoratiu Vultur 	struct vcap_rule_internal *ri;
2376610c32b2SHoratiu Vultur 	int err;
2377610c32b2SHoratiu Vultur 
23789579e2c2SSteen Hegelund 	ri = vcap_dup_rule(elem, elem->state == VCAP_RS_DISABLED);
23799579e2c2SSteen Hegelund 	if (IS_ERR(ri))
23809579e2c2SSteen Hegelund 		return ERR_PTR(PTR_ERR(ri));
23819579e2c2SSteen Hegelund 
23829579e2c2SSteen Hegelund 	if (ri->state == VCAP_RS_DISABLED)
23839579e2c2SSteen Hegelund 		goto out;
23849579e2c2SSteen Hegelund 
23859579e2c2SSteen Hegelund 	err = vcap_read_rule(ri);
23869579e2c2SSteen Hegelund 	if (err)
23879579e2c2SSteen Hegelund 		return ERR_PTR(err);
23889579e2c2SSteen Hegelund 
23899579e2c2SSteen Hegelund 	err = vcap_decode_keyset(ri);
23909579e2c2SSteen Hegelund 	if (err)
23919579e2c2SSteen Hegelund 		return ERR_PTR(err);
23929579e2c2SSteen Hegelund 
23939579e2c2SSteen Hegelund 	err = vcap_decode_actionset(ri);
23949579e2c2SSteen Hegelund 	if (err)
23959579e2c2SSteen Hegelund 		return ERR_PTR(err);
23969579e2c2SSteen Hegelund 
23979579e2c2SSteen Hegelund out:
23989579e2c2SSteen Hegelund 	return &ri->data;
23999579e2c2SSteen Hegelund }
24009579e2c2SSteen Hegelund 
24019579e2c2SSteen Hegelund struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
24029579e2c2SSteen Hegelund {
24039579e2c2SSteen Hegelund 	struct vcap_rule_internal *elem;
24049579e2c2SSteen Hegelund 	struct vcap_rule *rule;
24059579e2c2SSteen Hegelund 	int err;
2406610c32b2SHoratiu Vultur 
2407610c32b2SHoratiu Vultur 	err = vcap_api_check(vctrl);
2408610c32b2SHoratiu Vultur 	if (err)
2409610c32b2SHoratiu Vultur 		return ERR_PTR(err);
24109579e2c2SSteen Hegelund 
24111972b6d9SSteen Hegelund 	elem = vcap_get_locked_rule(vctrl, id);
2412610c32b2SHoratiu Vultur 	if (!elem)
2413610c32b2SHoratiu Vultur 		return NULL;
24149579e2c2SSteen Hegelund 
24159579e2c2SSteen Hegelund 	rule = vcap_decode_rule(elem);
2416610c32b2SHoratiu Vultur 	mutex_unlock(&elem->admin->lock);
24179579e2c2SSteen Hegelund 	return rule;
2418610c32b2SHoratiu Vultur }
2419610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_get_rule);
2420610c32b2SHoratiu Vultur 
24212662b3f9SHoratiu Vultur /* Update existing rule */
24222662b3f9SHoratiu Vultur int vcap_mod_rule(struct vcap_rule *rule)
24232662b3f9SHoratiu Vultur {
24242662b3f9SHoratiu Vultur 	struct vcap_rule_internal *ri = to_intrule(rule);
24252662b3f9SHoratiu Vultur 	struct vcap_counter ctr;
24262662b3f9SHoratiu Vultur 	int err;
24272662b3f9SHoratiu Vultur 
24282662b3f9SHoratiu Vultur 	err = vcap_api_check(ri->vctrl);
24292662b3f9SHoratiu Vultur 	if (err)
24302662b3f9SHoratiu Vultur 		return err;
24312662b3f9SHoratiu Vultur 
24321972b6d9SSteen Hegelund 	if (!vcap_get_locked_rule(ri->vctrl, ri->data.id))
24332662b3f9SHoratiu Vultur 		return -ENOENT;
24342662b3f9SHoratiu Vultur 
2435814e7693SSteen Hegelund 	vcap_rule_set_state(ri);
2436814e7693SSteen Hegelund 	if (ri->state == VCAP_RS_DISABLED)
2437814e7693SSteen Hegelund 		goto out;
2438814e7693SSteen Hegelund 
24392662b3f9SHoratiu Vultur 	/* Encode the bitstreams to the VCAP cache */
24402662b3f9SHoratiu Vultur 	vcap_erase_cache(ri);
24412662b3f9SHoratiu Vultur 	err = vcap_encode_rule(ri);
24422662b3f9SHoratiu Vultur 	if (err)
24432662b3f9SHoratiu Vultur 		goto out;
24442662b3f9SHoratiu Vultur 
24452662b3f9SHoratiu Vultur 	err = vcap_write_rule(ri);
24462662b3f9SHoratiu Vultur 	if (err)
24472662b3f9SHoratiu Vultur 		goto out;
24482662b3f9SHoratiu Vultur 
24492662b3f9SHoratiu Vultur 	memset(&ctr, 0, sizeof(ctr));
24502662b3f9SHoratiu Vultur 	err =  vcap_write_counter(ri, &ctr);
24512662b3f9SHoratiu Vultur 
24522662b3f9SHoratiu Vultur out:
24532662b3f9SHoratiu Vultur 	mutex_unlock(&ri->admin->lock);
24542662b3f9SHoratiu Vultur 	return err;
24552662b3f9SHoratiu Vultur }
24562662b3f9SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_mod_rule);
24572662b3f9SHoratiu Vultur 
2458990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */
2459990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
2460990e4839SSteen Hegelund {
2461990e4839SSteen Hegelund 	return (el->addr + offset) % el->size;
2462990e4839SSteen Hegelund }
2463990e4839SSteen Hegelund 
2464990e4839SSteen Hegelund /* Update the rule address with an offset */
2465990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
2466990e4839SSteen Hegelund {
2467990e4839SSteen Hegelund 	el->addr += offset;
2468990e4839SSteen Hegelund }
2469990e4839SSteen Hegelund 
2470990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */
2471990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
2472990e4839SSteen Hegelund {
2473990e4839SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
2474990e4839SSteen Hegelund 	struct vcap_rule_internal *elem;
2475990e4839SSteen Hegelund 	struct vcap_rule_move move;
2476990e4839SSteen Hegelund 	int gap = 0, offset = 0;
2477990e4839SSteen Hegelund 
2478990e4839SSteen Hegelund 	/* If the first rule is deleted: Move other rules to the top */
2479990e4839SSteen Hegelund 	if (list_is_first(&ri->list, &admin->rules))
2480990e4839SSteen Hegelund 		offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
2481990e4839SSteen Hegelund 
2482990e4839SSteen Hegelund 	/* Locate gaps between odd size rules and adjust the move */
2483990e4839SSteen Hegelund 	elem = ri;
2484990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
2485990e4839SSteen Hegelund 		gap += vcap_valid_rule_move(elem, ri->size);
2486990e4839SSteen Hegelund 
2487990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
2488990e4839SSteen Hegelund 	elem = ri;
2489990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
2490990e4839SSteen Hegelund 		vcap_adjust_rule_addr(elem, ri->size + gap + offset);
2491990e4839SSteen Hegelund 
2492990e4839SSteen Hegelund 	/* Update the move info */
2493990e4839SSteen Hegelund 	move.addr = admin->last_used_addr;
2494990e4839SSteen Hegelund 	move.count = ri->addr - admin->last_used_addr - gap;
2495990e4839SSteen Hegelund 	move.offset = -(ri->size + gap + offset);
2496990e4839SSteen Hegelund 
2497990e4839SSteen Hegelund 	/* Do the actual move operation */
2498990e4839SSteen Hegelund 	vcap_move_rules(ri, &move);
2499990e4839SSteen Hegelund 
2500990e4839SSteen Hegelund 	return gap + offset;
2501990e4839SSteen Hegelund }
2502990e4839SSteen Hegelund 
2503c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
2504c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
2505c9da1ac1SSteen Hegelund {
2506c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri, *elem;
2507c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
2508990e4839SSteen Hegelund 	int gap = 0, err;
2509c9da1ac1SSteen Hegelund 
2510c9da1ac1SSteen Hegelund 	/* This will later also handle rule moving */
2511c9da1ac1SSteen Hegelund 	if (!ndev)
2512c9da1ac1SSteen Hegelund 		return -ENODEV;
25138e10490bSSteen Hegelund 	err = vcap_api_check(vctrl);
25148e10490bSSteen Hegelund 	if (err)
25158e10490bSSteen Hegelund 		return err;
2516c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
25171972b6d9SSteen Hegelund 	ri = vcap_get_locked_rule(vctrl, id);
2518c9da1ac1SSteen Hegelund 	if (!ri)
25191972b6d9SSteen Hegelund 		return -ENOENT;
25201972b6d9SSteen Hegelund 
2521c9da1ac1SSteen Hegelund 	admin = ri->admin;
25228e10490bSSteen Hegelund 
2523990e4839SSteen Hegelund 	if (ri->addr > admin->last_used_addr)
2524990e4839SSteen Hegelund 		gap = vcap_fill_rule_gap(ri);
2525990e4839SSteen Hegelund 
2526990e4839SSteen Hegelund 	/* Delete the rule from the list of rules and the cache */
2527990e4839SSteen Hegelund 	list_del(&ri->list);
2528990e4839SSteen Hegelund 	vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
2529814e7693SSteen Hegelund 	vcap_free_rule(&ri->data);
2530990e4839SSteen Hegelund 
2531277e9179SSteen Hegelund 	/* Update the last used address, set to default when no rules */
2532c9da1ac1SSteen Hegelund 	if (list_empty(&admin->rules)) {
2533277e9179SSteen Hegelund 		admin->last_used_addr = admin->last_valid_addr + 1;
2534c9da1ac1SSteen Hegelund 	} else {
2535990e4839SSteen Hegelund 		elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
2536990e4839SSteen Hegelund 				       list);
2537c9da1ac1SSteen Hegelund 		admin->last_used_addr = elem->addr;
2538c9da1ac1SSteen Hegelund 	}
25391972b6d9SSteen Hegelund 
25401972b6d9SSteen Hegelund 	mutex_unlock(&admin->lock);
25411972b6d9SSteen Hegelund 	return err;
2542c9da1ac1SSteen Hegelund }
2543c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
2544c9da1ac1SSteen Hegelund 
25458e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
25468e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
25478e10490bSSteen Hegelund {
254867456717SSteen Hegelund 	struct vcap_enabled_port *eport, *next_eport;
25498e10490bSSteen Hegelund 	struct vcap_rule_internal *ri, *next_ri;
25508e10490bSSteen Hegelund 	int ret = vcap_api_check(vctrl);
25518e10490bSSteen Hegelund 
25528e10490bSSteen Hegelund 	if (ret)
25538e10490bSSteen Hegelund 		return ret;
255471c9de99SSteen Hegelund 
255571c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
25568e10490bSSteen Hegelund 	list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
25578e10490bSSteen Hegelund 		vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
25588e10490bSSteen Hegelund 		list_del(&ri->list);
2559814e7693SSteen Hegelund 		vcap_free_rule(&ri->data);
25608e10490bSSteen Hegelund 	}
25618e10490bSSteen Hegelund 	admin->last_used_addr = admin->last_valid_addr;
256267456717SSteen Hegelund 
256367456717SSteen Hegelund 	/* Remove list of enabled ports */
256467456717SSteen Hegelund 	list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
256567456717SSteen Hegelund 		list_del(&eport->list);
256667456717SSteen Hegelund 		kfree(eport);
256767456717SSteen Hegelund 	}
256871c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
256967456717SSteen Hegelund 
25708e10490bSSteen Hegelund 	return 0;
25718e10490bSSteen Hegelund }
25728e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
25738e10490bSSteen Hegelund 
2574465a38a2SSteen Hegelund /* Find a client key field in a rule */
2575465a38a2SSteen Hegelund static struct vcap_client_keyfield *
2576465a38a2SSteen Hegelund vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key)
2577465a38a2SSteen Hegelund {
2578465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2579465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
2580465a38a2SSteen Hegelund 
2581465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2582465a38a2SSteen Hegelund 		if (ckf->ctrl.key == key)
2583465a38a2SSteen Hegelund 			return ckf;
2584465a38a2SSteen Hegelund 	return NULL;
2585465a38a2SSteen Hegelund }
2586465a38a2SSteen Hegelund 
258746be056eSSteen Hegelund /* Find information on a key field in a rule */
258846be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
258946be056eSSteen Hegelund 					      enum vcap_key_field key)
259046be056eSSteen Hegelund {
25918e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
259246be056eSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
259346be056eSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
259446be056eSSteen Hegelund 	const struct vcap_field *fields;
259546be056eSSteen Hegelund 
259646be056eSSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
259746be056eSSteen Hegelund 		return NULL;
259846be056eSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
259946be056eSSteen Hegelund 	if (!fields)
260046be056eSSteen Hegelund 		return NULL;
260146be056eSSteen Hegelund 	return &fields[key];
260246be056eSSteen Hegelund }
260346be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
260446be056eSSteen Hegelund 
2605242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */
2606242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule,
2607242df4f7SSteen Hegelund 				 enum vcap_key_field key)
2608242df4f7SSteen Hegelund {
2609242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2610242df4f7SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
2611242df4f7SSteen Hegelund 
2612242df4f7SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2613242df4f7SSteen Hegelund 		if (ckf->ctrl.key == key)
2614242df4f7SSteen Hegelund 			return false;
2615242df4f7SSteen Hegelund 	return true;
2616242df4f7SSteen Hegelund }
2617242df4f7SSteen Hegelund 
2618242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */
2619242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule,
2620242df4f7SSteen Hegelund 				       enum vcap_key_field key)
2621242df4f7SSteen Hegelund {
2622242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2623242df4f7SSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
2624242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
2625242df4f7SSteen Hegelund 	const struct vcap_field *fields;
2626242df4f7SSteen Hegelund 
2627242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no keyset yet */
2628242df4f7SSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
2629242df4f7SSteen Hegelund 		return true;
2630242df4f7SSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
2631242df4f7SSteen Hegelund 	if (!fields)
2632242df4f7SSteen Hegelund 		return false;
2633242df4f7SSteen Hegelund 	/* if there is a width there is a way */
2634242df4f7SSteen Hegelund 	return fields[key].width > 0;
2635242df4f7SSteen Hegelund }
2636242df4f7SSteen Hegelund 
2637c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
2638c9da1ac1SSteen Hegelund 			     enum vcap_key_field key,
2639c9da1ac1SSteen Hegelund 			     enum vcap_field_type ftype,
2640c9da1ac1SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
2641c9da1ac1SSteen Hegelund {
2642242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2643c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *field;
2644c9da1ac1SSteen Hegelund 
2645242df4f7SSteen Hegelund 	if (!vcap_keyfield_unique(rule, key)) {
2646242df4f7SSteen Hegelund 		pr_warn("%s:%d: keyfield %s is already in the rule\n",
2647242df4f7SSteen Hegelund 			__func__, __LINE__,
2648242df4f7SSteen Hegelund 			vcap_keyfield_name(ri->vctrl, key));
2649242df4f7SSteen Hegelund 		return -EINVAL;
2650242df4f7SSteen Hegelund 	}
2651242df4f7SSteen Hegelund 
2652242df4f7SSteen Hegelund 	if (!vcap_keyfield_match_keyset(rule, key)) {
2653242df4f7SSteen Hegelund 		pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n",
2654242df4f7SSteen Hegelund 		       __func__, __LINE__,
2655242df4f7SSteen Hegelund 		       vcap_keyfield_name(ri->vctrl, key));
2656242df4f7SSteen Hegelund 		return -EINVAL;
2657242df4f7SSteen Hegelund 	}
2658242df4f7SSteen Hegelund 
2659c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
2660c9da1ac1SSteen Hegelund 	if (!field)
2661c9da1ac1SSteen Hegelund 		return -ENOMEM;
266233e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
2663c9da1ac1SSteen Hegelund 	field->ctrl.key = key;
2664c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
2665c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->keyfields);
2666c9da1ac1SSteen Hegelund 	return 0;
2667c9da1ac1SSteen Hegelund }
2668c9da1ac1SSteen Hegelund 
266946be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
267046be056eSSteen Hegelund {
267146be056eSSteen Hegelund 	switch (val) {
267246be056eSSteen Hegelund 	case VCAP_BIT_0:
267346be056eSSteen Hegelund 		u1->value = 0;
267446be056eSSteen Hegelund 		u1->mask = 1;
267546be056eSSteen Hegelund 		break;
267646be056eSSteen Hegelund 	case VCAP_BIT_1:
267746be056eSSteen Hegelund 		u1->value = 1;
267846be056eSSteen Hegelund 		u1->mask = 1;
267946be056eSSteen Hegelund 		break;
268046be056eSSteen Hegelund 	case VCAP_BIT_ANY:
268146be056eSSteen Hegelund 		u1->value = 0;
268246be056eSSteen Hegelund 		u1->mask = 0;
268346be056eSSteen Hegelund 		break;
268446be056eSSteen Hegelund 	}
268546be056eSSteen Hegelund }
268646be056eSSteen Hegelund 
268746be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
268846be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
268946be056eSSteen Hegelund 			  enum vcap_bit val)
269046be056eSSteen Hegelund {
269146be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
269246be056eSSteen Hegelund 
269346be056eSSteen Hegelund 	vcap_rule_set_key_bitsize(&data.u1, val);
269446be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
269546be056eSSteen Hegelund }
269646be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
269746be056eSSteen Hegelund 
269846be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
269946be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
270046be056eSSteen Hegelund 			  u32 value, u32 mask)
270146be056eSSteen Hegelund {
270246be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
270346be056eSSteen Hegelund 
270446be056eSSteen Hegelund 	data.u32.value = value;
270546be056eSSteen Hegelund 	data.u32.mask = mask;
270646be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
270746be056eSSteen Hegelund }
270846be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
270946be056eSSteen Hegelund 
2710c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
2711c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
2712c9da1ac1SSteen Hegelund 			  struct vcap_u48_key *fieldval)
2713c9da1ac1SSteen Hegelund {
2714c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield_data data;
2715c9da1ac1SSteen Hegelund 
2716c9da1ac1SSteen Hegelund 	memcpy(&data.u48, fieldval, sizeof(data.u48));
2717c9da1ac1SSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
2718c9da1ac1SSteen Hegelund }
2719c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
2720c9da1ac1SSteen Hegelund 
272146be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
272246be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
272346be056eSSteen Hegelund 			  struct vcap_u72_key *fieldval)
272446be056eSSteen Hegelund {
272546be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
272646be056eSSteen Hegelund 
272746be056eSSteen Hegelund 	memcpy(&data.u72, fieldval, sizeof(data.u72));
272846be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
272946be056eSSteen Hegelund }
273046be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
273146be056eSSteen Hegelund 
2732d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
2733d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
2734d6c2964dSSteen Hegelund 			   struct vcap_u128_key *fieldval)
2735d6c2964dSSteen Hegelund {
2736d6c2964dSSteen Hegelund 	struct vcap_client_keyfield_data data;
2737d6c2964dSSteen Hegelund 
2738d6c2964dSSteen Hegelund 	memcpy(&data.u128, fieldval, sizeof(data.u128));
2739d6c2964dSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
2740d6c2964dSSteen Hegelund }
2741d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
2742d6c2964dSSteen Hegelund 
27436009b61fSHoratiu Vultur int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
27446009b61fSHoratiu Vultur 			  u32 *value, u32 *mask)
27456009b61fSHoratiu Vultur {
27466009b61fSHoratiu Vultur 	struct vcap_client_keyfield *ckf;
27476009b61fSHoratiu Vultur 
27486009b61fSHoratiu Vultur 	ckf = vcap_find_keyfield(rule, key);
27496009b61fSHoratiu Vultur 	if (!ckf)
27506009b61fSHoratiu Vultur 		return -ENOENT;
27516009b61fSHoratiu Vultur 
27526009b61fSHoratiu Vultur 	*value = ckf->data.u32.value;
27536009b61fSHoratiu Vultur 	*mask = ckf->data.u32.mask;
27546009b61fSHoratiu Vultur 
27556009b61fSHoratiu Vultur 	return 0;
27566009b61fSHoratiu Vultur }
27576009b61fSHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_rule_get_key_u32);
27586009b61fSHoratiu Vultur 
2759465a38a2SSteen Hegelund /* Find a client action field in a rule */
27606ebf182bSDaniel Machon struct vcap_client_actionfield *
2761465a38a2SSteen Hegelund vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act)
2762465a38a2SSteen Hegelund {
2763465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule;
2764465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
2765465a38a2SSteen Hegelund 
2766465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2767465a38a2SSteen Hegelund 		if (caf->ctrl.action == act)
2768465a38a2SSteen Hegelund 			return caf;
2769465a38a2SSteen Hegelund 	return NULL;
2770465a38a2SSteen Hegelund }
27716ebf182bSDaniel Machon EXPORT_SYMBOL_GPL(vcap_find_actionfield);
2772465a38a2SSteen Hegelund 
2773242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */
2774242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule,
2775242df4f7SSteen Hegelund 				    enum vcap_action_field act)
2776242df4f7SSteen Hegelund {
2777242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2778242df4f7SSteen Hegelund 	const struct vcap_client_actionfield *caf;
2779242df4f7SSteen Hegelund 
2780242df4f7SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2781242df4f7SSteen Hegelund 		if (caf->ctrl.action == act)
2782242df4f7SSteen Hegelund 			return false;
2783242df4f7SSteen Hegelund 	return true;
2784242df4f7SSteen Hegelund }
2785242df4f7SSteen Hegelund 
2786242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */
2787242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule,
2788242df4f7SSteen Hegelund 					     enum vcap_action_field action)
2789242df4f7SSteen Hegelund {
2790242df4f7SSteen Hegelund 	enum vcap_actionfield_set actionset = rule->actionset;
2791242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2792242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
2793242df4f7SSteen Hegelund 	const struct vcap_field *fields;
2794242df4f7SSteen Hegelund 
2795242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no actionset yet */
2796242df4f7SSteen Hegelund 	if (actionset == VCAP_AFS_NO_VALUE)
2797242df4f7SSteen Hegelund 		return true;
2798242df4f7SSteen Hegelund 	fields = vcap_actionfields(ri->vctrl, vt, actionset);
2799242df4f7SSteen Hegelund 	if (!fields)
2800242df4f7SSteen Hegelund 		return false;
2801242df4f7SSteen Hegelund 	/* if there is a width there is a way */
2802242df4f7SSteen Hegelund 	return fields[action].width > 0;
2803242df4f7SSteen Hegelund }
2804242df4f7SSteen Hegelund 
2805c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
2806c9da1ac1SSteen Hegelund 				enum vcap_action_field action,
2807c9da1ac1SSteen Hegelund 				enum vcap_field_type ftype,
2808c9da1ac1SSteen Hegelund 				struct vcap_client_actionfield_data *data)
2809c9da1ac1SSteen Hegelund {
2810242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
2811c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *field;
2812c9da1ac1SSteen Hegelund 
2813242df4f7SSteen Hegelund 	if (!vcap_actionfield_unique(rule, action)) {
2814242df4f7SSteen Hegelund 		pr_warn("%s:%d: actionfield %s is already in the rule\n",
2815242df4f7SSteen Hegelund 			__func__, __LINE__,
2816242df4f7SSteen Hegelund 			vcap_actionfield_name(ri->vctrl, action));
2817242df4f7SSteen Hegelund 		return -EINVAL;
2818242df4f7SSteen Hegelund 	}
2819242df4f7SSteen Hegelund 
2820242df4f7SSteen Hegelund 	if (!vcap_actionfield_match_actionset(rule, action)) {
2821242df4f7SSteen Hegelund 		pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n",
2822242df4f7SSteen Hegelund 		       __func__, __LINE__,
2823242df4f7SSteen Hegelund 		       vcap_actionfield_name(ri->vctrl, action));
2824242df4f7SSteen Hegelund 		return -EINVAL;
2825242df4f7SSteen Hegelund 	}
2826242df4f7SSteen Hegelund 
2827c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
2828c9da1ac1SSteen Hegelund 	if (!field)
2829c9da1ac1SSteen Hegelund 		return -ENOMEM;
283033e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
2831c9da1ac1SSteen Hegelund 	field->ctrl.action = action;
2832c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
2833c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->actionfields);
2834c9da1ac1SSteen Hegelund 	return 0;
2835c9da1ac1SSteen Hegelund }
2836c9da1ac1SSteen Hegelund 
2837c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
2838c9da1ac1SSteen Hegelund 					 enum vcap_bit val)
2839c9da1ac1SSteen Hegelund {
2840c9da1ac1SSteen Hegelund 	switch (val) {
2841c9da1ac1SSteen Hegelund 	case VCAP_BIT_0:
2842c9da1ac1SSteen Hegelund 		u1->value = 0;
2843c9da1ac1SSteen Hegelund 		break;
2844c9da1ac1SSteen Hegelund 	case VCAP_BIT_1:
2845c9da1ac1SSteen Hegelund 		u1->value = 1;
2846c9da1ac1SSteen Hegelund 		break;
2847c9da1ac1SSteen Hegelund 	case VCAP_BIT_ANY:
2848c9da1ac1SSteen Hegelund 		u1->value = 0;
2849c9da1ac1SSteen Hegelund 		break;
2850c9da1ac1SSteen Hegelund 	}
2851c9da1ac1SSteen Hegelund }
2852c9da1ac1SSteen Hegelund 
2853c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
2854c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
2855c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
2856c9da1ac1SSteen Hegelund 			     enum vcap_bit val)
2857c9da1ac1SSteen Hegelund {
2858c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
2859c9da1ac1SSteen Hegelund 
2860c9da1ac1SSteen Hegelund 	vcap_rule_set_action_bitsize(&data.u1, val);
2861c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
2862c9da1ac1SSteen Hegelund }
2863c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
2864c9da1ac1SSteen Hegelund 
2865c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
2866c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
2867c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
2868c9da1ac1SSteen Hegelund 			     u32 value)
2869c9da1ac1SSteen Hegelund {
2870c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
2871c9da1ac1SSteen Hegelund 
2872c9da1ac1SSteen Hegelund 	data.u32.value = value;
2873c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
2874c9da1ac1SSteen Hegelund }
2875c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
2876c9da1ac1SSteen Hegelund 
2877f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri,
2878f13230a4SSteen Hegelund 			     struct vcap_counter *ctr)
2879f13230a4SSteen Hegelund {
2880f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
2881f13230a4SSteen Hegelund 
2882f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
2883f13230a4SSteen Hegelund 			       ri->addr);
2884f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
2885f13230a4SSteen Hegelund 				   ri->counter_id, 0);
2886f13230a4SSteen Hegelund 	ctr->value = admin->cache.counter;
2887f13230a4SSteen Hegelund 	ctr->sticky = admin->cache.sticky;
2888f13230a4SSteen Hegelund 	return 0;
2889f13230a4SSteen Hegelund }
2890f13230a4SSteen Hegelund 
2891c9da1ac1SSteen Hegelund /* Copy to host byte order */
2892c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
2893c9da1ac1SSteen Hegelund {
2894c9da1ac1SSteen Hegelund 	int idx;
2895c9da1ac1SSteen Hegelund 
2896c9da1ac1SSteen Hegelund 	for (idx = 0; idx < count; ++idx, ++dst)
2897c9da1ac1SSteen Hegelund 		*dst = src[count - idx - 1];
2898c9da1ac1SSteen Hegelund }
2899c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
2900c9da1ac1SSteen Hegelund 
2901c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */
2902c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
2903c9da1ac1SSteen Hegelund {
2904c9da1ac1SSteen Hegelund 	switch (vrule->exterr) {
2905c9da1ac1SSteen Hegelund 	case VCAP_ERR_NONE:
2906c9da1ac1SSteen Hegelund 		break;
2907c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ADMIN:
2908c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2909c9da1ac1SSteen Hegelund 				   "Missing VCAP instance");
2910c9da1ac1SSteen Hegelund 		break;
2911c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_NETDEV:
2912c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2913c9da1ac1SSteen Hegelund 				   "Missing network interface");
2914c9da1ac1SSteen Hegelund 		break;
2915c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_KEYSET_MATCH:
2916c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2917c9da1ac1SSteen Hegelund 				   "No keyset matched the filter keys");
2918c9da1ac1SSteen Hegelund 		break;
2919c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ACTIONSET_MATCH:
2920c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2921c9da1ac1SSteen Hegelund 				   "No actionset matched the filter actions");
2922c9da1ac1SSteen Hegelund 		break;
2923c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_PORT_KEYSET_MATCH:
2924c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
2925c9da1ac1SSteen Hegelund 				   "No port keyset matched the filter keys");
2926c9da1ac1SSteen Hegelund 		break;
2927c9da1ac1SSteen Hegelund 	}
2928c9da1ac1SSteen Hegelund }
2929c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
293067d63751SSteen Hegelund 
293118a15c76SSteen Hegelund /* Write a rule to VCAP HW to enable it */
293218a15c76SSteen Hegelund static int vcap_enable_rule(struct vcap_rule_internal *ri)
293318a15c76SSteen Hegelund {
293418a15c76SSteen Hegelund 	struct vcap_client_actionfield *af, *naf;
293518a15c76SSteen Hegelund 	struct vcap_client_keyfield *kf, *nkf;
293618a15c76SSteen Hegelund 	int err;
293718a15c76SSteen Hegelund 
293818a15c76SSteen Hegelund 	vcap_erase_cache(ri);
293918a15c76SSteen Hegelund 	err = vcap_encode_rule(ri);
294018a15c76SSteen Hegelund 	if (err)
294118a15c76SSteen Hegelund 		goto out;
294218a15c76SSteen Hegelund 	err = vcap_write_rule(ri);
294318a15c76SSteen Hegelund 	if (err)
294418a15c76SSteen Hegelund 		goto out;
294518a15c76SSteen Hegelund 
294618a15c76SSteen Hegelund 	/* Deallocate the list of keys and actions */
294718a15c76SSteen Hegelund 	list_for_each_entry_safe(kf, nkf, &ri->data.keyfields, ctrl.list) {
294818a15c76SSteen Hegelund 		list_del(&kf->ctrl.list);
294918a15c76SSteen Hegelund 		kfree(kf);
295018a15c76SSteen Hegelund 	}
295118a15c76SSteen Hegelund 	list_for_each_entry_safe(af, naf, &ri->data.actionfields, ctrl.list) {
295218a15c76SSteen Hegelund 		list_del(&af->ctrl.list);
295318a15c76SSteen Hegelund 		kfree(af);
295418a15c76SSteen Hegelund 	}
295518a15c76SSteen Hegelund 	ri->state = VCAP_RS_ENABLED;
295618a15c76SSteen Hegelund out:
295718a15c76SSteen Hegelund 	return err;
295818a15c76SSteen Hegelund }
295918a15c76SSteen Hegelund 
296018a15c76SSteen Hegelund /* Enable all disabled rules for a specific chain/port in the VCAP HW */
296118a15c76SSteen Hegelund static int vcap_enable_rules(struct vcap_control *vctrl,
296218a15c76SSteen Hegelund 			     struct net_device *ndev, int chain)
296318a15c76SSteen Hegelund {
296488bd9ea7SSteen Hegelund 	int next_chain = chain + VCAP_CID_LOOKUP_SIZE;
296518a15c76SSteen Hegelund 	struct vcap_rule_internal *ri;
296618a15c76SSteen Hegelund 	struct vcap_admin *admin;
296718a15c76SSteen Hegelund 	int err = 0;
296818a15c76SSteen Hegelund 
296918a15c76SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
297018a15c76SSteen Hegelund 		if (!(chain >= admin->first_cid && chain <= admin->last_cid))
297118a15c76SSteen Hegelund 			continue;
297218a15c76SSteen Hegelund 
297318a15c76SSteen Hegelund 		/* Found the admin, now find the offloadable rules */
297418a15c76SSteen Hegelund 		mutex_lock(&admin->lock);
297518a15c76SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
297688bd9ea7SSteen Hegelund 			/* Is the rule in the lookup defined by the chain */
297788bd9ea7SSteen Hegelund 			if (!(ri->data.vcap_chain_id >= chain &&
297888bd9ea7SSteen Hegelund 			      ri->data.vcap_chain_id < next_chain)) {
297918a15c76SSteen Hegelund 				continue;
298088bd9ea7SSteen Hegelund 			}
298118a15c76SSteen Hegelund 
298218a15c76SSteen Hegelund 			if (ri->ndev != ndev)
298318a15c76SSteen Hegelund 				continue;
298418a15c76SSteen Hegelund 
298518a15c76SSteen Hegelund 			if (ri->state != VCAP_RS_DISABLED)
298618a15c76SSteen Hegelund 				continue;
298718a15c76SSteen Hegelund 
298818a15c76SSteen Hegelund 			err = vcap_enable_rule(ri);
298918a15c76SSteen Hegelund 			if (err)
299018a15c76SSteen Hegelund 				break;
299118a15c76SSteen Hegelund 		}
299218a15c76SSteen Hegelund 		mutex_unlock(&admin->lock);
299318a15c76SSteen Hegelund 		if (err)
299418a15c76SSteen Hegelund 			break;
299518a15c76SSteen Hegelund 	}
299618a15c76SSteen Hegelund 	return err;
299718a15c76SSteen Hegelund }
299818a15c76SSteen Hegelund 
299918a15c76SSteen Hegelund /* Read and erase a rule from VCAP HW to disable it */
300018a15c76SSteen Hegelund static int vcap_disable_rule(struct vcap_rule_internal *ri)
300118a15c76SSteen Hegelund {
300218a15c76SSteen Hegelund 	int err;
300318a15c76SSteen Hegelund 
300418a15c76SSteen Hegelund 	err = vcap_read_rule(ri);
300518a15c76SSteen Hegelund 	if (err)
300618a15c76SSteen Hegelund 		return err;
300718a15c76SSteen Hegelund 	err = vcap_decode_keyset(ri);
300818a15c76SSteen Hegelund 	if (err)
300918a15c76SSteen Hegelund 		return err;
301018a15c76SSteen Hegelund 	err = vcap_decode_actionset(ri);
301118a15c76SSteen Hegelund 	if (err)
301218a15c76SSteen Hegelund 		return err;
301318a15c76SSteen Hegelund 
301418a15c76SSteen Hegelund 	ri->state = VCAP_RS_DISABLED;
301518a15c76SSteen Hegelund 	ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size);
301618a15c76SSteen Hegelund 	return 0;
301718a15c76SSteen Hegelund }
301818a15c76SSteen Hegelund 
301918a15c76SSteen Hegelund /* Disable all enabled rules for a specific chain/port in the VCAP HW */
302018a15c76SSteen Hegelund static int vcap_disable_rules(struct vcap_control *vctrl,
302118a15c76SSteen Hegelund 			      struct net_device *ndev, int chain)
302218a15c76SSteen Hegelund {
302318a15c76SSteen Hegelund 	struct vcap_rule_internal *ri;
302418a15c76SSteen Hegelund 	struct vcap_admin *admin;
302518a15c76SSteen Hegelund 	int err = 0;
302618a15c76SSteen Hegelund 
302718a15c76SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
302818a15c76SSteen Hegelund 		if (!(chain >= admin->first_cid && chain <= admin->last_cid))
302918a15c76SSteen Hegelund 			continue;
303018a15c76SSteen Hegelund 
303118a15c76SSteen Hegelund 		/* Found the admin, now find the rules on the chain */
303218a15c76SSteen Hegelund 		mutex_lock(&admin->lock);
303318a15c76SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
303418a15c76SSteen Hegelund 			if (ri->data.vcap_chain_id != chain)
303518a15c76SSteen Hegelund 				continue;
303618a15c76SSteen Hegelund 
303718a15c76SSteen Hegelund 			if (ri->ndev != ndev)
303818a15c76SSteen Hegelund 				continue;
303918a15c76SSteen Hegelund 
304018a15c76SSteen Hegelund 			if (ri->state != VCAP_RS_ENABLED)
304118a15c76SSteen Hegelund 				continue;
304218a15c76SSteen Hegelund 
304318a15c76SSteen Hegelund 			err = vcap_disable_rule(ri);
304418a15c76SSteen Hegelund 			if (err)
304518a15c76SSteen Hegelund 				break;
304618a15c76SSteen Hegelund 		}
304718a15c76SSteen Hegelund 		mutex_unlock(&admin->lock);
304818a15c76SSteen Hegelund 		if (err)
304918a15c76SSteen Hegelund 			break;
305018a15c76SSteen Hegelund 	}
305118a15c76SSteen Hegelund 	return err;
305218a15c76SSteen Hegelund }
305318a15c76SSteen Hegelund 
305467456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */
3055cfd9e7b7SSteen Hegelund static bool vcap_is_enabled(struct vcap_control *vctrl, struct net_device *ndev,
3056cfd9e7b7SSteen Hegelund 			    int dst_cid)
305767456717SSteen Hegelund {
305867456717SSteen Hegelund 	struct vcap_enabled_port *eport;
3059cfd9e7b7SSteen Hegelund 	struct vcap_admin *admin;
306067456717SSteen Hegelund 
3061cfd9e7b7SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
306267456717SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list)
3063cfd9e7b7SSteen Hegelund 			if (eport->dst_cid == dst_cid && eport->ndev == ndev)
306467456717SSteen Hegelund 				return true;
306567456717SSteen Hegelund 
306667456717SSteen Hegelund 	return false;
306767456717SSteen Hegelund }
306867456717SSteen Hegelund 
3069cfd9e7b7SSteen Hegelund /* Enable this port and chain id in a VCAP instance */
3070cfd9e7b7SSteen Hegelund static int vcap_enable(struct vcap_control *vctrl, struct net_device *ndev,
3071cfd9e7b7SSteen Hegelund 		       unsigned long cookie, int src_cid, int dst_cid)
307267456717SSteen Hegelund {
307367456717SSteen Hegelund 	struct vcap_enabled_port *eport;
3074cfd9e7b7SSteen Hegelund 	struct vcap_admin *admin;
3075cfd9e7b7SSteen Hegelund 
3076cfd9e7b7SSteen Hegelund 	if (src_cid >= dst_cid)
3077cfd9e7b7SSteen Hegelund 		return -EFAULT;
3078cfd9e7b7SSteen Hegelund 
3079cfd9e7b7SSteen Hegelund 	admin = vcap_find_admin(vctrl, dst_cid);
3080cfd9e7b7SSteen Hegelund 	if (!admin)
3081cfd9e7b7SSteen Hegelund 		return -ENOENT;
308267456717SSteen Hegelund 
308367456717SSteen Hegelund 	eport = kzalloc(sizeof(*eport), GFP_KERNEL);
308467456717SSteen Hegelund 	if (!eport)
308567456717SSteen Hegelund 		return -ENOMEM;
308667456717SSteen Hegelund 
308767456717SSteen Hegelund 	eport->ndev = ndev;
308867456717SSteen Hegelund 	eport->cookie = cookie;
3089cfd9e7b7SSteen Hegelund 	eport->src_cid = src_cid;
3090cfd9e7b7SSteen Hegelund 	eport->dst_cid = dst_cid;
3091cfd9e7b7SSteen Hegelund 	mutex_lock(&admin->lock);
309267456717SSteen Hegelund 	list_add_tail(&eport->list, &admin->enabled);
3093cfd9e7b7SSteen Hegelund 	mutex_unlock(&admin->lock);
309467456717SSteen Hegelund 
309518a15c76SSteen Hegelund 	if (vcap_path_exist(vctrl, ndev, src_cid)) {
309618a15c76SSteen Hegelund 		/* Enable chained lookups */
309718a15c76SSteen Hegelund 		while (dst_cid) {
309818a15c76SSteen Hegelund 			admin = vcap_find_admin(vctrl, dst_cid);
309918a15c76SSteen Hegelund 			if (!admin)
310018a15c76SSteen Hegelund 				return -ENOENT;
310118a15c76SSteen Hegelund 
310218a15c76SSteen Hegelund 			vcap_enable_rules(vctrl, ndev, dst_cid);
310318a15c76SSteen Hegelund 			dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid);
310418a15c76SSteen Hegelund 		}
310518a15c76SSteen Hegelund 	}
310667456717SSteen Hegelund 	return 0;
310767456717SSteen Hegelund }
310867456717SSteen Hegelund 
3109cfd9e7b7SSteen Hegelund /* Disable this port and chain id for a VCAP instance */
3110cfd9e7b7SSteen Hegelund static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev,
311167456717SSteen Hegelund 			unsigned long cookie)
311267456717SSteen Hegelund {
3113cfd9e7b7SSteen Hegelund 	struct vcap_enabled_port *elem, *eport = NULL;
3114cfd9e7b7SSteen Hegelund 	struct vcap_admin *found = NULL, *admin;
311518a15c76SSteen Hegelund 	int dst_cid;
311667456717SSteen Hegelund 
3117cfd9e7b7SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
3118cfd9e7b7SSteen Hegelund 		list_for_each_entry(elem, &admin->enabled, list) {
3119cfd9e7b7SSteen Hegelund 			if (elem->cookie == cookie && elem->ndev == ndev) {
3120cfd9e7b7SSteen Hegelund 				eport = elem;
3121cfd9e7b7SSteen Hegelund 				found = admin;
3122cfd9e7b7SSteen Hegelund 				break;
3123cfd9e7b7SSteen Hegelund 			}
3124cfd9e7b7SSteen Hegelund 		}
3125cfd9e7b7SSteen Hegelund 		if (eport)
3126cfd9e7b7SSteen Hegelund 			break;
3127cfd9e7b7SSteen Hegelund 	}
3128cfd9e7b7SSteen Hegelund 
3129cfd9e7b7SSteen Hegelund 	if (!eport)
3130cfd9e7b7SSteen Hegelund 		return -ENOENT;
3131cfd9e7b7SSteen Hegelund 
313218a15c76SSteen Hegelund 	/* Disable chained lookups */
313318a15c76SSteen Hegelund 	dst_cid = eport->dst_cid;
313418a15c76SSteen Hegelund 	while (dst_cid) {
313518a15c76SSteen Hegelund 		admin = vcap_find_admin(vctrl, dst_cid);
313618a15c76SSteen Hegelund 		if (!admin)
313718a15c76SSteen Hegelund 			return -ENOENT;
313818a15c76SSteen Hegelund 
313918a15c76SSteen Hegelund 		vcap_disable_rules(vctrl, ndev, dst_cid);
314018a15c76SSteen Hegelund 		dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid);
314118a15c76SSteen Hegelund 	}
314218a15c76SSteen Hegelund 
3143cfd9e7b7SSteen Hegelund 	mutex_lock(&found->lock);
314467456717SSteen Hegelund 	list_del(&eport->list);
3145cfd9e7b7SSteen Hegelund 	mutex_unlock(&found->lock);
314667456717SSteen Hegelund 	kfree(eport);
314767456717SSteen Hegelund 	return 0;
314867456717SSteen Hegelund }
314967456717SSteen Hegelund 
3150cfd9e7b7SSteen Hegelund /* Enable/Disable the VCAP instance lookups */
315167456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
3152cfd9e7b7SSteen Hegelund 			int src_cid, int dst_cid, unsigned long cookie,
3153cfd9e7b7SSteen Hegelund 			bool enable)
315467456717SSteen Hegelund {
315567456717SSteen Hegelund 	int err;
315667456717SSteen Hegelund 
315767456717SSteen Hegelund 	err = vcap_api_check(vctrl);
315867456717SSteen Hegelund 	if (err)
315967456717SSteen Hegelund 		return err;
316067456717SSteen Hegelund 
316167456717SSteen Hegelund 	if (!ndev)
316267456717SSteen Hegelund 		return -ENODEV;
316367456717SSteen Hegelund 
3164cfd9e7b7SSteen Hegelund 	/* Source and destination must be the first chain in a lookup */
3165cfd9e7b7SSteen Hegelund 	if (src_cid % VCAP_CID_LOOKUP_SIZE)
3166cfd9e7b7SSteen Hegelund 		return -EFAULT;
3167cfd9e7b7SSteen Hegelund 	if (dst_cid % VCAP_CID_LOOKUP_SIZE)
316867456717SSteen Hegelund 		return -EFAULT;
316967456717SSteen Hegelund 
3170cfd9e7b7SSteen Hegelund 	if (enable) {
3171cfd9e7b7SSteen Hegelund 		if (vcap_is_enabled(vctrl, ndev, dst_cid))
317267456717SSteen Hegelund 			return -EADDRINUSE;
3173cfd9e7b7SSteen Hegelund 		if (vcap_is_chain_used(vctrl, ndev, src_cid))
3174cfd9e7b7SSteen Hegelund 			return -EADDRNOTAVAIL;
3175cfd9e7b7SSteen Hegelund 		err = vcap_enable(vctrl, ndev, cookie, src_cid, dst_cid);
317667456717SSteen Hegelund 	} else {
3177cfd9e7b7SSteen Hegelund 		err = vcap_disable(vctrl, ndev, cookie);
317867456717SSteen Hegelund 	}
317967456717SSteen Hegelund 
3180cfd9e7b7SSteen Hegelund 	return err;
318167456717SSteen Hegelund }
318267456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups);
318367456717SSteen Hegelund 
3184784c3067SSteen Hegelund /* Is this chain id the last lookup of all VCAPs */
3185e7e3f514SSteen Hegelund bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress)
3186784c3067SSteen Hegelund {
3187784c3067SSteen Hegelund 	struct vcap_admin *admin;
3188784c3067SSteen Hegelund 	int lookup;
3189784c3067SSteen Hegelund 
3190784c3067SSteen Hegelund 	if (vcap_api_check(vctrl))
3191784c3067SSteen Hegelund 		return false;
3192784c3067SSteen Hegelund 
3193784c3067SSteen Hegelund 	admin = vcap_find_admin(vctrl, cid);
3194784c3067SSteen Hegelund 	if (!admin)
3195784c3067SSteen Hegelund 		return false;
3196784c3067SSteen Hegelund 
3197e7e3f514SSteen Hegelund 	if (!vcap_admin_is_last(vctrl, admin, ingress))
319888bd9ea7SSteen Hegelund 		return false;
319988bd9ea7SSteen Hegelund 
3200784c3067SSteen Hegelund 	/* This must be the last lookup in this VCAP type */
3201784c3067SSteen Hegelund 	lookup = vcap_chain_id_to_lookup(admin, cid);
3202784c3067SSteen Hegelund 	return lookup == admin->lookups - 1;
3203784c3067SSteen Hegelund }
3204784c3067SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_last_chain);
3205784c3067SSteen Hegelund 
3206f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */
3207f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
3208f13230a4SSteen Hegelund {
3209f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
3210f13230a4SSteen Hegelund 
3211f13230a4SSteen Hegelund 	ri->counter_id = counter_id;
3212f13230a4SSteen Hegelund }
3213f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
3214f13230a4SSteen Hegelund 
3215f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
3216f13230a4SSteen Hegelund {
3217f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
3218f13230a4SSteen Hegelund 	int err;
3219f13230a4SSteen Hegelund 
3220f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
3221f13230a4SSteen Hegelund 	if (err)
3222f13230a4SSteen Hegelund 		return err;
3223f13230a4SSteen Hegelund 	if (!ctr) {
3224f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
3225f13230a4SSteen Hegelund 		return -EINVAL;
3226f13230a4SSteen Hegelund 	}
32271972b6d9SSteen Hegelund 
32281972b6d9SSteen Hegelund 	mutex_lock(&ri->admin->lock);
32291972b6d9SSteen Hegelund 	err = vcap_write_counter(ri, ctr);
32301972b6d9SSteen Hegelund 	mutex_unlock(&ri->admin->lock);
32311972b6d9SSteen Hegelund 
32321972b6d9SSteen Hegelund 	return err;
3233f13230a4SSteen Hegelund }
3234f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
3235f13230a4SSteen Hegelund 
3236f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
3237f13230a4SSteen Hegelund {
3238f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
3239f13230a4SSteen Hegelund 	int err;
3240f13230a4SSteen Hegelund 
3241f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
3242f13230a4SSteen Hegelund 	if (err)
3243f13230a4SSteen Hegelund 		return err;
3244f13230a4SSteen Hegelund 	if (!ctr) {
3245f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
3246f13230a4SSteen Hegelund 		return -EINVAL;
3247f13230a4SSteen Hegelund 	}
32481972b6d9SSteen Hegelund 
32491972b6d9SSteen Hegelund 	mutex_lock(&ri->admin->lock);
32501972b6d9SSteen Hegelund 	err = vcap_read_counter(ri, ctr);
32511972b6d9SSteen Hegelund 	mutex_unlock(&ri->admin->lock);
32521972b6d9SSteen Hegelund 
32531972b6d9SSteen Hegelund 	return err;
3254f13230a4SSteen Hegelund }
3255f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
3256f13230a4SSteen Hegelund 
325718a15c76SSteen Hegelund /* Get a copy of a client key field */
325818a15c76SSteen Hegelund static int vcap_rule_get_key(struct vcap_rule *rule,
325918a15c76SSteen Hegelund 			     enum vcap_key_field key,
326018a15c76SSteen Hegelund 			     struct vcap_client_keyfield *ckf)
326118a15c76SSteen Hegelund {
326218a15c76SSteen Hegelund 	struct vcap_client_keyfield *field;
326318a15c76SSteen Hegelund 
326418a15c76SSteen Hegelund 	field = vcap_find_keyfield(rule, key);
326518a15c76SSteen Hegelund 	if (!field)
326618a15c76SSteen Hegelund 		return -EINVAL;
326718a15c76SSteen Hegelund 	memcpy(ckf, field, sizeof(*ckf));
326818a15c76SSteen Hegelund 	INIT_LIST_HEAD(&ckf->ctrl.list);
326918a15c76SSteen Hegelund 	return 0;
327018a15c76SSteen Hegelund }
327118a15c76SSteen Hegelund 
3272c02b19edSSteen Hegelund /* Find a keyset having the same size as the provided rule, where the keyset
3273c02b19edSSteen Hegelund  * does not have a type id.
3274c02b19edSSteen Hegelund  */
3275c02b19edSSteen Hegelund static int vcap_rule_get_untyped_keyset(struct vcap_rule_internal *ri,
3276c02b19edSSteen Hegelund 					struct vcap_keyset_list *matches)
3277c02b19edSSteen Hegelund {
3278c02b19edSSteen Hegelund 	struct vcap_control *vctrl = ri->vctrl;
3279c02b19edSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
3280c02b19edSSteen Hegelund 	const struct vcap_set *keyfield_set;
3281c02b19edSSteen Hegelund 	int idx;
3282c02b19edSSteen Hegelund 
3283c02b19edSSteen Hegelund 	keyfield_set = vctrl->vcaps[vt].keyfield_set;
3284c02b19edSSteen Hegelund 	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
3285c02b19edSSteen Hegelund 		if (keyfield_set[idx].sw_per_item == ri->keyset_sw &&
3286c02b19edSSteen Hegelund 		    keyfield_set[idx].type_id == (u8)-1) {
3287c02b19edSSteen Hegelund 			vcap_keyset_list_add(matches, idx);
3288c02b19edSSteen Hegelund 			return 0;
3289c02b19edSSteen Hegelund 		}
3290c02b19edSSteen Hegelund 	}
3291c02b19edSSteen Hegelund 	return -EINVAL;
3292c02b19edSSteen Hegelund }
3293c02b19edSSteen Hegelund 
329418a15c76SSteen Hegelund /* Get the keysets that matches the rule key type/mask */
329518a15c76SSteen Hegelund int vcap_rule_get_keysets(struct vcap_rule_internal *ri,
329618a15c76SSteen Hegelund 			  struct vcap_keyset_list *matches)
329718a15c76SSteen Hegelund {
329818a15c76SSteen Hegelund 	struct vcap_control *vctrl = ri->vctrl;
329918a15c76SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
330018a15c76SSteen Hegelund 	const struct vcap_set *keyfield_set;
330118a15c76SSteen Hegelund 	struct vcap_client_keyfield kf = {};
330218a15c76SSteen Hegelund 	u32 value, mask;
330318a15c76SSteen Hegelund 	int err, idx;
330418a15c76SSteen Hegelund 
330518a15c76SSteen Hegelund 	err = vcap_rule_get_key(&ri->data, VCAP_KF_TYPE, &kf);
330618a15c76SSteen Hegelund 	if (err)
3307c02b19edSSteen Hegelund 		return vcap_rule_get_untyped_keyset(ri, matches);
330818a15c76SSteen Hegelund 
330918a15c76SSteen Hegelund 	if (kf.ctrl.type == VCAP_FIELD_BIT) {
331018a15c76SSteen Hegelund 		value = kf.data.u1.value;
331118a15c76SSteen Hegelund 		mask = kf.data.u1.mask;
331218a15c76SSteen Hegelund 	} else if (kf.ctrl.type == VCAP_FIELD_U32) {
331318a15c76SSteen Hegelund 		value = kf.data.u32.value;
331418a15c76SSteen Hegelund 		mask = kf.data.u32.mask;
331518a15c76SSteen Hegelund 	} else {
331618a15c76SSteen Hegelund 		return -EINVAL;
331718a15c76SSteen Hegelund 	}
331818a15c76SSteen Hegelund 
331918a15c76SSteen Hegelund 	keyfield_set = vctrl->vcaps[vt].keyfield_set;
332018a15c76SSteen Hegelund 	for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
332118a15c76SSteen Hegelund 		if (keyfield_set[idx].sw_per_item != ri->keyset_sw)
332218a15c76SSteen Hegelund 			continue;
332318a15c76SSteen Hegelund 
332418a15c76SSteen Hegelund 		if (keyfield_set[idx].type_id == (u8)-1) {
332518a15c76SSteen Hegelund 			vcap_keyset_list_add(matches, idx);
332618a15c76SSteen Hegelund 			continue;
332718a15c76SSteen Hegelund 		}
332818a15c76SSteen Hegelund 
332918a15c76SSteen Hegelund 		if ((keyfield_set[idx].type_id & mask) == value)
333018a15c76SSteen Hegelund 			vcap_keyset_list_add(matches, idx);
333118a15c76SSteen Hegelund 	}
333218a15c76SSteen Hegelund 	if (matches->cnt > 0)
333318a15c76SSteen Hegelund 		return 0;
333418a15c76SSteen Hegelund 
333518a15c76SSteen Hegelund 	return -EINVAL;
333618a15c76SSteen Hegelund }
333718a15c76SSteen Hegelund 
333827d293ccSSteen Hegelund /* Collect packet counts from all rules with the same cookie */
333927d293ccSSteen Hegelund int vcap_get_rule_count_by_cookie(struct vcap_control *vctrl,
334027d293ccSSteen Hegelund 				  struct vcap_counter *ctr, u64 cookie)
334127d293ccSSteen Hegelund {
334227d293ccSSteen Hegelund 	struct vcap_rule_internal *ri;
334327d293ccSSteen Hegelund 	struct vcap_counter temp = {};
334427d293ccSSteen Hegelund 	struct vcap_admin *admin;
334527d293ccSSteen Hegelund 	int err;
334627d293ccSSteen Hegelund 
334727d293ccSSteen Hegelund 	err = vcap_api_check(vctrl);
334827d293ccSSteen Hegelund 	if (err)
334927d293ccSSteen Hegelund 		return err;
335027d293ccSSteen Hegelund 
335127d293ccSSteen Hegelund 	/* Iterate all rules in each VCAP instance */
335227d293ccSSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
335327d293ccSSteen Hegelund 		mutex_lock(&admin->lock);
335427d293ccSSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
335527d293ccSSteen Hegelund 			if (ri->data.cookie != cookie)
335627d293ccSSteen Hegelund 				continue;
335727d293ccSSteen Hegelund 
335827d293ccSSteen Hegelund 			err = vcap_read_counter(ri, &temp);
335927d293ccSSteen Hegelund 			if (err)
336027d293ccSSteen Hegelund 				goto unlock;
336127d293ccSSteen Hegelund 			ctr->value += temp.value;
336227d293ccSSteen Hegelund 
336327d293ccSSteen Hegelund 			/* Reset the rule counter */
336427d293ccSSteen Hegelund 			temp.value = 0;
336527d293ccSSteen Hegelund 			temp.sticky = 0;
336627d293ccSSteen Hegelund 			err = vcap_write_counter(ri, &temp);
336727d293ccSSteen Hegelund 			if (err)
336827d293ccSSteen Hegelund 				goto unlock;
336927d293ccSSteen Hegelund 		}
337027d293ccSSteen Hegelund 		mutex_unlock(&admin->lock);
337127d293ccSSteen Hegelund 	}
337227d293ccSSteen Hegelund 	return err;
337327d293ccSSteen Hegelund 
337427d293ccSSteen Hegelund unlock:
337527d293ccSSteen Hegelund 	mutex_unlock(&admin->lock);
337627d293ccSSteen Hegelund 	return err;
337727d293ccSSteen Hegelund }
337827d293ccSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_get_rule_count_by_cookie);
337927d293ccSSteen Hegelund 
3380465a38a2SSteen Hegelund static int vcap_rule_mod_key(struct vcap_rule *rule,
3381465a38a2SSteen Hegelund 			     enum vcap_key_field key,
3382465a38a2SSteen Hegelund 			     enum vcap_field_type ftype,
3383465a38a2SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
3384465a38a2SSteen Hegelund {
3385465a38a2SSteen Hegelund 	struct vcap_client_keyfield *field;
3386465a38a2SSteen Hegelund 
3387465a38a2SSteen Hegelund 	field = vcap_find_keyfield(rule, key);
3388465a38a2SSteen Hegelund 	if (!field)
3389465a38a2SSteen Hegelund 		return vcap_rule_add_key(rule, key, ftype, data);
339033e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
3391465a38a2SSteen Hegelund 	return 0;
3392465a38a2SSteen Hegelund }
3393465a38a2SSteen Hegelund 
3394465a38a2SSteen Hegelund /* Modify a 32 bit key field with value and mask in the rule */
3395465a38a2SSteen Hegelund int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
3396465a38a2SSteen Hegelund 			  u32 value, u32 mask)
3397465a38a2SSteen Hegelund {
3398465a38a2SSteen Hegelund 	struct vcap_client_keyfield_data data;
3399465a38a2SSteen Hegelund 
3400465a38a2SSteen Hegelund 	data.u32.value = value;
3401465a38a2SSteen Hegelund 	data.u32.mask = mask;
3402465a38a2SSteen Hegelund 	return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data);
3403465a38a2SSteen Hegelund }
3404465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32);
3405465a38a2SSteen Hegelund 
3406465a38a2SSteen Hegelund static int vcap_rule_mod_action(struct vcap_rule *rule,
3407465a38a2SSteen Hegelund 				enum vcap_action_field action,
3408465a38a2SSteen Hegelund 				enum vcap_field_type ftype,
3409465a38a2SSteen Hegelund 				struct vcap_client_actionfield_data *data)
3410465a38a2SSteen Hegelund {
3411465a38a2SSteen Hegelund 	struct vcap_client_actionfield *field;
3412465a38a2SSteen Hegelund 
3413465a38a2SSteen Hegelund 	field = vcap_find_actionfield(rule, action);
3414465a38a2SSteen Hegelund 	if (!field)
3415465a38a2SSteen Hegelund 		return vcap_rule_add_action(rule, action, ftype, data);
341633e3a273SSteen Hegelund 	memcpy(&field->data, data, sizeof(field->data));
3417465a38a2SSteen Hegelund 	return 0;
3418465a38a2SSteen Hegelund }
3419465a38a2SSteen Hegelund 
3420465a38a2SSteen Hegelund /* Modify a 32 bit action field with value in the rule */
3421465a38a2SSteen Hegelund int vcap_rule_mod_action_u32(struct vcap_rule *rule,
3422465a38a2SSteen Hegelund 			     enum vcap_action_field action,
3423465a38a2SSteen Hegelund 			     u32 value)
3424465a38a2SSteen Hegelund {
3425465a38a2SSteen Hegelund 	struct vcap_client_actionfield_data data;
3426465a38a2SSteen Hegelund 
3427465a38a2SSteen Hegelund 	data.u32.value = value;
3428465a38a2SSteen Hegelund 	return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data);
3429465a38a2SSteen Hegelund }
3430465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32);
3431465a38a2SSteen Hegelund 
3432465a38a2SSteen Hegelund /* Drop keys in a keylist and any keys that are not supported by the keyset */
3433465a38a2SSteen Hegelund int vcap_filter_rule_keys(struct vcap_rule *rule,
3434465a38a2SSteen Hegelund 			  enum vcap_key_field keylist[], int length,
3435465a38a2SSteen Hegelund 			  bool drop_unsupported)
3436465a38a2SSteen Hegelund {
3437465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
3438465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
3439465a38a2SSteen Hegelund 	const struct vcap_field *fields;
3440465a38a2SSteen Hegelund 	enum vcap_key_field key;
3441465a38a2SSteen Hegelund 	int err = 0;
3442465a38a2SSteen Hegelund 	int idx;
3443465a38a2SSteen Hegelund 
3444465a38a2SSteen Hegelund 	if (length > 0) {
3445465a38a2SSteen Hegelund 		err = -EEXIST;
3446465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
3447465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
3448465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
3449465a38a2SSteen Hegelund 			for (idx = 0; idx < length; ++idx)
3450465a38a2SSteen Hegelund 				if (key == keylist[idx]) {
3451465a38a2SSteen Hegelund 					list_del(&ckf->ctrl.list);
3452465a38a2SSteen Hegelund 					kfree(ckf);
3453465a38a2SSteen Hegelund 					idx++;
3454465a38a2SSteen Hegelund 					err = 0;
3455465a38a2SSteen Hegelund 				}
3456465a38a2SSteen Hegelund 		}
3457465a38a2SSteen Hegelund 	}
3458465a38a2SSteen Hegelund 	if (drop_unsupported) {
3459465a38a2SSteen Hegelund 		err = -EEXIST;
3460465a38a2SSteen Hegelund 		fields = vcap_keyfields(ri->vctrl, ri->admin->vtype,
3461465a38a2SSteen Hegelund 					rule->keyset);
3462465a38a2SSteen Hegelund 		if (!fields)
3463465a38a2SSteen Hegelund 			return err;
3464465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
3465465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
3466465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
3467465a38a2SSteen Hegelund 			if (fields[key].width == 0) {
3468465a38a2SSteen Hegelund 				list_del(&ckf->ctrl.list);
3469465a38a2SSteen Hegelund 				kfree(ckf);
3470465a38a2SSteen Hegelund 				err = 0;
3471465a38a2SSteen Hegelund 			}
3472465a38a2SSteen Hegelund 		}
3473465a38a2SSteen Hegelund 	}
3474465a38a2SSteen Hegelund 	return err;
3475465a38a2SSteen Hegelund }
3476465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_filter_rule_keys);
3477465a38a2SSteen Hegelund 
3478465a38a2SSteen Hegelund /* Make a full copy of an existing rule with a new rule id */
3479465a38a2SSteen Hegelund struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
3480465a38a2SSteen Hegelund {
3481465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(erule);
3482465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
3483465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
3484465a38a2SSteen Hegelund 	struct vcap_rule *rule;
3485465a38a2SSteen Hegelund 	int err;
3486465a38a2SSteen Hegelund 
3487465a38a2SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
3488465a38a2SSteen Hegelund 	if (err)
3489465a38a2SSteen Hegelund 		return ERR_PTR(err);
3490465a38a2SSteen Hegelund 
3491465a38a2SSteen Hegelund 	rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id,
3492465a38a2SSteen Hegelund 			       ri->data.user, ri->data.priority, 0);
3493465a38a2SSteen Hegelund 	if (IS_ERR(rule))
3494465a38a2SSteen Hegelund 		return rule;
3495465a38a2SSteen Hegelund 
3496465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
3497465a38a2SSteen Hegelund 		/* Add a key duplicate in the new rule */
3498465a38a2SSteen Hegelund 		err = vcap_rule_add_key(rule,
3499465a38a2SSteen Hegelund 					ckf->ctrl.key,
3500465a38a2SSteen Hegelund 					ckf->ctrl.type,
3501465a38a2SSteen Hegelund 					&ckf->data);
3502465a38a2SSteen Hegelund 		if (err)
3503465a38a2SSteen Hegelund 			goto err;
3504465a38a2SSteen Hegelund 	}
3505465a38a2SSteen Hegelund 
3506465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
3507465a38a2SSteen Hegelund 		/* Add a action duplicate in the new rule */
3508465a38a2SSteen Hegelund 		err = vcap_rule_add_action(rule,
3509465a38a2SSteen Hegelund 					   caf->ctrl.action,
3510465a38a2SSteen Hegelund 					   caf->ctrl.type,
3511465a38a2SSteen Hegelund 					   &caf->data);
3512465a38a2SSteen Hegelund 		if (err)
3513465a38a2SSteen Hegelund 			goto err;
3514465a38a2SSteen Hegelund 	}
3515465a38a2SSteen Hegelund 	return rule;
3516465a38a2SSteen Hegelund err:
3517465a38a2SSteen Hegelund 	vcap_free_rule(rule);
3518465a38a2SSteen Hegelund 	return ERR_PTR(err);
3519465a38a2SSteen Hegelund }
3520465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_copy_rule);
3521465a38a2SSteen Hegelund 
352267d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
352367d63751SSteen Hegelund #include "vcap_api_kunit.c"
352467d63751SSteen Hegelund #endif
3525