1d8931847SRahul Lakkireddy /*
2d8931847SRahul Lakkireddy  * This file is part of the Chelsio T4 Ethernet driver for Linux.
3d8931847SRahul Lakkireddy  *
4d8931847SRahul Lakkireddy  * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved.
5d8931847SRahul Lakkireddy  *
6d8931847SRahul Lakkireddy  * This software is available to you under a choice of one of two
7d8931847SRahul Lakkireddy  * licenses.  You may choose to be licensed under the terms of the GNU
8d8931847SRahul Lakkireddy  * General Public License (GPL) Version 2, available from the file
9d8931847SRahul Lakkireddy  * COPYING in the main directory of this source tree, or the
10d8931847SRahul Lakkireddy  * OpenIB.org BSD license below:
11d8931847SRahul Lakkireddy  *
12d8931847SRahul Lakkireddy  *     Redistribution and use in source and binary forms, with or
13d8931847SRahul Lakkireddy  *     without modification, are permitted provided that the following
14d8931847SRahul Lakkireddy  *     conditions are met:
15d8931847SRahul Lakkireddy  *
16d8931847SRahul Lakkireddy  *      - Redistributions of source code must retain the above
17d8931847SRahul Lakkireddy  *        copyright notice, this list of conditions and the following
18d8931847SRahul Lakkireddy  *        disclaimer.
19d8931847SRahul Lakkireddy  *
20d8931847SRahul Lakkireddy  *      - Redistributions in binary form must reproduce the above
21d8931847SRahul Lakkireddy  *        copyright notice, this list of conditions and the following
22d8931847SRahul Lakkireddy  *        disclaimer in the documentation and/or other materials
23d8931847SRahul Lakkireddy  *        provided with the distribution.
24d8931847SRahul Lakkireddy  *
25d8931847SRahul Lakkireddy  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26d8931847SRahul Lakkireddy  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27d8931847SRahul Lakkireddy  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28d8931847SRahul Lakkireddy  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29d8931847SRahul Lakkireddy  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30d8931847SRahul Lakkireddy  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31d8931847SRahul Lakkireddy  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32d8931847SRahul Lakkireddy  * SOFTWARE.
33d8931847SRahul Lakkireddy  */
34d8931847SRahul Lakkireddy 
35d8931847SRahul Lakkireddy #include "cxgb4.h"
36d8931847SRahul Lakkireddy #include "cxgb4_tc_u32_parse.h"
37d8931847SRahul Lakkireddy #include "cxgb4_tc_u32.h"
38d8931847SRahul Lakkireddy 
39d8931847SRahul Lakkireddy /* Fill ch_filter_specification with parsed match value/mask pair. */
40d8931847SRahul Lakkireddy static int fill_match_fields(struct adapter *adap,
41d8931847SRahul Lakkireddy 			     struct ch_filter_specification *fs,
42d8931847SRahul Lakkireddy 			     struct tc_cls_u32_offload *cls,
43d8931847SRahul Lakkireddy 			     const struct cxgb4_match_field *entry,
44d8931847SRahul Lakkireddy 			     bool next_header)
45d8931847SRahul Lakkireddy {
46d8931847SRahul Lakkireddy 	unsigned int i, j;
47d8931847SRahul Lakkireddy 	u32 val, mask;
48d8931847SRahul Lakkireddy 	int off, err;
49d8931847SRahul Lakkireddy 	bool found;
50d8931847SRahul Lakkireddy 
51d8931847SRahul Lakkireddy 	for (i = 0; i < cls->knode.sel->nkeys; i++) {
52d8931847SRahul Lakkireddy 		off = cls->knode.sel->keys[i].off;
53d8931847SRahul Lakkireddy 		val = cls->knode.sel->keys[i].val;
54d8931847SRahul Lakkireddy 		mask = cls->knode.sel->keys[i].mask;
55d8931847SRahul Lakkireddy 
56d8931847SRahul Lakkireddy 		if (next_header) {
57d8931847SRahul Lakkireddy 			/* For next headers, parse only keys with offmask */
58d8931847SRahul Lakkireddy 			if (!cls->knode.sel->keys[i].offmask)
59d8931847SRahul Lakkireddy 				continue;
60d8931847SRahul Lakkireddy 		} else {
61d8931847SRahul Lakkireddy 			/* For the remaining, parse only keys without offmask */
62d8931847SRahul Lakkireddy 			if (cls->knode.sel->keys[i].offmask)
63d8931847SRahul Lakkireddy 				continue;
64d8931847SRahul Lakkireddy 		}
65d8931847SRahul Lakkireddy 
66d8931847SRahul Lakkireddy 		found = false;
67d8931847SRahul Lakkireddy 
68d8931847SRahul Lakkireddy 		for (j = 0; entry[j].val; j++) {
69d8931847SRahul Lakkireddy 			if (off == entry[j].off) {
70d8931847SRahul Lakkireddy 				found = true;
71d8931847SRahul Lakkireddy 				err = entry[j].val(fs, val, mask);
72d8931847SRahul Lakkireddy 				if (err)
73d8931847SRahul Lakkireddy 					return err;
74d8931847SRahul Lakkireddy 				break;
75d8931847SRahul Lakkireddy 			}
76d8931847SRahul Lakkireddy 		}
77d8931847SRahul Lakkireddy 
78d8931847SRahul Lakkireddy 		if (!found)
79d8931847SRahul Lakkireddy 			return -EINVAL;
80d8931847SRahul Lakkireddy 	}
81d8931847SRahul Lakkireddy 
82d8931847SRahul Lakkireddy 	return 0;
83d8931847SRahul Lakkireddy }
84d8931847SRahul Lakkireddy 
85d8931847SRahul Lakkireddy int cxgb4_config_knode(struct net_device *dev, __be16 protocol,
86d8931847SRahul Lakkireddy 		       struct tc_cls_u32_offload *cls)
87d8931847SRahul Lakkireddy {
88d8931847SRahul Lakkireddy 	const struct cxgb4_match_field *start, *link_start = NULL;
89d8931847SRahul Lakkireddy 	struct adapter *adapter = netdev2adap(dev);
90d8931847SRahul Lakkireddy 	struct ch_filter_specification fs;
91d8931847SRahul Lakkireddy 	struct cxgb4_tc_u32_table *t;
92d8931847SRahul Lakkireddy 	struct cxgb4_link *link;
93d8931847SRahul Lakkireddy 	unsigned int filter_id;
94d8931847SRahul Lakkireddy 	u32 uhtid, link_uhtid;
95d8931847SRahul Lakkireddy 	bool is_ipv6 = false;
96d8931847SRahul Lakkireddy 	int ret;
97d8931847SRahul Lakkireddy 
98d8931847SRahul Lakkireddy 	if (!can_tc_u32_offload(dev))
99d8931847SRahul Lakkireddy 		return -EOPNOTSUPP;
100d8931847SRahul Lakkireddy 
101d8931847SRahul Lakkireddy 	if (protocol != htons(ETH_P_IP) && protocol != htons(ETH_P_IPV6))
102d8931847SRahul Lakkireddy 		return -EOPNOTSUPP;
103d8931847SRahul Lakkireddy 
104d8931847SRahul Lakkireddy 	/* Fetch the location to insert the filter. */
105d8931847SRahul Lakkireddy 	filter_id = cls->knode.handle & 0xFFFFF;
106d8931847SRahul Lakkireddy 
107d8931847SRahul Lakkireddy 	if (filter_id > adapter->tids.nftids) {
108d8931847SRahul Lakkireddy 		dev_err(adapter->pdev_dev,
109d8931847SRahul Lakkireddy 			"Location %d out of range for insertion. Max: %d\n",
110d8931847SRahul Lakkireddy 			filter_id, adapter->tids.nftids);
111d8931847SRahul Lakkireddy 		return -ERANGE;
112d8931847SRahul Lakkireddy 	}
113d8931847SRahul Lakkireddy 
114d8931847SRahul Lakkireddy 	t = adapter->tc_u32;
115d8931847SRahul Lakkireddy 	uhtid = TC_U32_USERHTID(cls->knode.handle);
116d8931847SRahul Lakkireddy 	link_uhtid = TC_U32_USERHTID(cls->knode.link_handle);
117d8931847SRahul Lakkireddy 
118d8931847SRahul Lakkireddy 	/* Ensure that uhtid is either root u32 (i.e. 0x800)
119d8931847SRahul Lakkireddy 	 * or a a valid linked bucket.
120d8931847SRahul Lakkireddy 	 */
121d8931847SRahul Lakkireddy 	if (uhtid != 0x800 && uhtid >= t->size)
122d8931847SRahul Lakkireddy 		return -EINVAL;
123d8931847SRahul Lakkireddy 
124d8931847SRahul Lakkireddy 	/* Ensure link handle uhtid is sane, if specified. */
125d8931847SRahul Lakkireddy 	if (link_uhtid >= t->size)
126d8931847SRahul Lakkireddy 		return -EINVAL;
127d8931847SRahul Lakkireddy 
128d8931847SRahul Lakkireddy 	memset(&fs, 0, sizeof(fs));
129d8931847SRahul Lakkireddy 
130d8931847SRahul Lakkireddy 	if (protocol == htons(ETH_P_IPV6)) {
131d8931847SRahul Lakkireddy 		start = cxgb4_ipv6_fields;
132d8931847SRahul Lakkireddy 		is_ipv6 = true;
133d8931847SRahul Lakkireddy 	} else {
134d8931847SRahul Lakkireddy 		start = cxgb4_ipv4_fields;
135d8931847SRahul Lakkireddy 		is_ipv6 = false;
136d8931847SRahul Lakkireddy 	}
137d8931847SRahul Lakkireddy 
138d8931847SRahul Lakkireddy 	if (uhtid != 0x800) {
139d8931847SRahul Lakkireddy 		/* Link must exist from root node before insertion. */
140d8931847SRahul Lakkireddy 		if (!t->table[uhtid - 1].link_handle)
141d8931847SRahul Lakkireddy 			return -EINVAL;
142d8931847SRahul Lakkireddy 
143d8931847SRahul Lakkireddy 		/* Link must have a valid supported next header. */
144d8931847SRahul Lakkireddy 		link_start = t->table[uhtid - 1].match_field;
145d8931847SRahul Lakkireddy 		if (!link_start)
146d8931847SRahul Lakkireddy 			return -EINVAL;
147d8931847SRahul Lakkireddy 	}
148d8931847SRahul Lakkireddy 
149d8931847SRahul Lakkireddy 	/* Parse links and record them for subsequent jumps to valid
150d8931847SRahul Lakkireddy 	 * next headers.
151d8931847SRahul Lakkireddy 	 */
152d8931847SRahul Lakkireddy 	if (link_uhtid) {
153d8931847SRahul Lakkireddy 		const struct cxgb4_next_header *next;
154d8931847SRahul Lakkireddy 		bool found = false;
155d8931847SRahul Lakkireddy 		unsigned int i, j;
156d8931847SRahul Lakkireddy 		u32 val, mask;
157d8931847SRahul Lakkireddy 		int off;
158d8931847SRahul Lakkireddy 
159d8931847SRahul Lakkireddy 		if (t->table[link_uhtid - 1].link_handle) {
160d8931847SRahul Lakkireddy 			dev_err(adapter->pdev_dev,
161d8931847SRahul Lakkireddy 				"Link handle exists for: 0x%x\n",
162d8931847SRahul Lakkireddy 				link_uhtid);
163d8931847SRahul Lakkireddy 			return -EINVAL;
164d8931847SRahul Lakkireddy 		}
165d8931847SRahul Lakkireddy 
166d8931847SRahul Lakkireddy 		next = is_ipv6 ? cxgb4_ipv6_jumps : cxgb4_ipv4_jumps;
167d8931847SRahul Lakkireddy 
168d8931847SRahul Lakkireddy 		/* Try to find matches that allow jumps to next header. */
169d8931847SRahul Lakkireddy 		for (i = 0; next[i].jump; i++) {
170d8931847SRahul Lakkireddy 			if (next[i].offoff != cls->knode.sel->offoff ||
171d8931847SRahul Lakkireddy 			    next[i].shift != cls->knode.sel->offshift ||
172d8931847SRahul Lakkireddy 			    next[i].mask != cls->knode.sel->offmask ||
173d8931847SRahul Lakkireddy 			    next[i].offset != cls->knode.sel->off)
174d8931847SRahul Lakkireddy 				continue;
175d8931847SRahul Lakkireddy 
176d8931847SRahul Lakkireddy 			/* Found a possible candidate.  Find a key that
177d8931847SRahul Lakkireddy 			 * matches the corresponding offset, value, and
178d8931847SRahul Lakkireddy 			 * mask to jump to next header.
179d8931847SRahul Lakkireddy 			 */
180d8931847SRahul Lakkireddy 			for (j = 0; j < cls->knode.sel->nkeys; j++) {
181d8931847SRahul Lakkireddy 				off = cls->knode.sel->keys[j].off;
182d8931847SRahul Lakkireddy 				val = cls->knode.sel->keys[j].val;
183d8931847SRahul Lakkireddy 				mask = cls->knode.sel->keys[j].mask;
184d8931847SRahul Lakkireddy 
185d8931847SRahul Lakkireddy 				if (next[i].match_off == off &&
186d8931847SRahul Lakkireddy 				    next[i].match_val == val &&
187d8931847SRahul Lakkireddy 				    next[i].match_mask == mask) {
188d8931847SRahul Lakkireddy 					found = true;
189d8931847SRahul Lakkireddy 					break;
190d8931847SRahul Lakkireddy 				}
191d8931847SRahul Lakkireddy 			}
192d8931847SRahul Lakkireddy 
193d8931847SRahul Lakkireddy 			if (!found)
194d8931847SRahul Lakkireddy 				continue; /* Try next candidate. */
195d8931847SRahul Lakkireddy 
196d8931847SRahul Lakkireddy 			/* Candidate to jump to next header found.
197d8931847SRahul Lakkireddy 			 * Translate all keys to internal specification
198d8931847SRahul Lakkireddy 			 * and store them in jump table. This spec is copied
199d8931847SRahul Lakkireddy 			 * later to set the actual filters.
200d8931847SRahul Lakkireddy 			 */
201d8931847SRahul Lakkireddy 			ret = fill_match_fields(adapter, &fs, cls,
202d8931847SRahul Lakkireddy 						start, false);
203d8931847SRahul Lakkireddy 			if (ret)
204d8931847SRahul Lakkireddy 				goto out;
205d8931847SRahul Lakkireddy 
206d8931847SRahul Lakkireddy 			link = &t->table[link_uhtid - 1];
207d8931847SRahul Lakkireddy 			link->match_field = next[i].jump;
208d8931847SRahul Lakkireddy 			link->link_handle = cls->knode.handle;
209d8931847SRahul Lakkireddy 			memcpy(&link->fs, &fs, sizeof(fs));
210d8931847SRahul Lakkireddy 			break;
211d8931847SRahul Lakkireddy 		}
212d8931847SRahul Lakkireddy 
213d8931847SRahul Lakkireddy 		/* No candidate found to jump to next header. */
214d8931847SRahul Lakkireddy 		if (!found)
215d8931847SRahul Lakkireddy 			return -EINVAL;
216d8931847SRahul Lakkireddy 
217d8931847SRahul Lakkireddy 		return 0;
218d8931847SRahul Lakkireddy 	}
219d8931847SRahul Lakkireddy 
220d8931847SRahul Lakkireddy 	/* Fill ch_filter_specification match fields to be shipped to hardware.
221d8931847SRahul Lakkireddy 	 * Copy the linked spec (if any) first.  And then update the spec as
222d8931847SRahul Lakkireddy 	 * needed.
223d8931847SRahul Lakkireddy 	 */
224d8931847SRahul Lakkireddy 	if (uhtid != 0x800 && t->table[uhtid - 1].link_handle) {
225d8931847SRahul Lakkireddy 		/* Copy linked ch_filter_specification */
226d8931847SRahul Lakkireddy 		memcpy(&fs, &t->table[uhtid - 1].fs, sizeof(fs));
227d8931847SRahul Lakkireddy 		ret = fill_match_fields(adapter, &fs, cls,
228d8931847SRahul Lakkireddy 					link_start, true);
229d8931847SRahul Lakkireddy 		if (ret)
230d8931847SRahul Lakkireddy 			goto out;
231d8931847SRahul Lakkireddy 	}
232d8931847SRahul Lakkireddy 
233d8931847SRahul Lakkireddy 	ret = fill_match_fields(adapter, &fs, cls, start, false);
234d8931847SRahul Lakkireddy 	if (ret)
235d8931847SRahul Lakkireddy 		goto out;
236d8931847SRahul Lakkireddy 
237d8931847SRahul Lakkireddy 	/* The filter spec has been completely built from the info
238d8931847SRahul Lakkireddy 	 * provided from u32.  We now set some default fields in the
239d8931847SRahul Lakkireddy 	 * spec for sanity.
240d8931847SRahul Lakkireddy 	 */
241d8931847SRahul Lakkireddy 
242d8931847SRahul Lakkireddy 	/* Match only packets coming from the ingress port where this
243d8931847SRahul Lakkireddy 	 * filter will be created.
244d8931847SRahul Lakkireddy 	 */
245d8931847SRahul Lakkireddy 	fs.val.iport = netdev2pinfo(dev)->port_id;
246d8931847SRahul Lakkireddy 	fs.mask.iport = ~0;
247d8931847SRahul Lakkireddy 
248d8931847SRahul Lakkireddy 	/* Enable filter hit counts. */
249d8931847SRahul Lakkireddy 	fs.hitcnts = 1;
250d8931847SRahul Lakkireddy 
251d8931847SRahul Lakkireddy 	/* Set type of filter - IPv6 or IPv4 */
252d8931847SRahul Lakkireddy 	fs.type = is_ipv6 ? 1 : 0;
253d8931847SRahul Lakkireddy 
254d8931847SRahul Lakkireddy 	/* Set the filter */
255d8931847SRahul Lakkireddy 	ret = cxgb4_set_filter(dev, filter_id, &fs);
256d8931847SRahul Lakkireddy 	if (ret)
257d8931847SRahul Lakkireddy 		goto out;
258d8931847SRahul Lakkireddy 
259d8931847SRahul Lakkireddy 	/* If this is a linked bucket, then set the corresponding
260d8931847SRahul Lakkireddy 	 * entry in the bitmap to mark it as belonging to this linked
261d8931847SRahul Lakkireddy 	 * bucket.
262d8931847SRahul Lakkireddy 	 */
263d8931847SRahul Lakkireddy 	if (uhtid != 0x800 && t->table[uhtid - 1].link_handle)
264d8931847SRahul Lakkireddy 		set_bit(filter_id, t->table[uhtid - 1].tid_map);
265d8931847SRahul Lakkireddy 
266d8931847SRahul Lakkireddy out:
267d8931847SRahul Lakkireddy 	return ret;
268d8931847SRahul Lakkireddy }
269d8931847SRahul Lakkireddy 
270d8931847SRahul Lakkireddy int cxgb4_delete_knode(struct net_device *dev, __be16 protocol,
271d8931847SRahul Lakkireddy 		       struct tc_cls_u32_offload *cls)
272d8931847SRahul Lakkireddy {
273d8931847SRahul Lakkireddy 	struct adapter *adapter = netdev2adap(dev);
274d8931847SRahul Lakkireddy 	unsigned int filter_id, max_tids, i, j;
275d8931847SRahul Lakkireddy 	struct cxgb4_link *link = NULL;
276d8931847SRahul Lakkireddy 	struct cxgb4_tc_u32_table *t;
277d8931847SRahul Lakkireddy 	u32 handle, uhtid;
278d8931847SRahul Lakkireddy 	int ret;
279d8931847SRahul Lakkireddy 
280d8931847SRahul Lakkireddy 	if (!can_tc_u32_offload(dev))
281d8931847SRahul Lakkireddy 		return -EOPNOTSUPP;
282d8931847SRahul Lakkireddy 
283d8931847SRahul Lakkireddy 	/* Fetch the location to delete the filter. */
284d8931847SRahul Lakkireddy 	filter_id = cls->knode.handle & 0xFFFFF;
285d8931847SRahul Lakkireddy 
286d8931847SRahul Lakkireddy 	if (filter_id > adapter->tids.nftids) {
287d8931847SRahul Lakkireddy 		dev_err(adapter->pdev_dev,
288d8931847SRahul Lakkireddy 			"Location %d out of range for deletion. Max: %d\n",
289d8931847SRahul Lakkireddy 			filter_id, adapter->tids.nftids);
290d8931847SRahul Lakkireddy 		return -ERANGE;
291d8931847SRahul Lakkireddy 	}
292d8931847SRahul Lakkireddy 
293d8931847SRahul Lakkireddy 	t = adapter->tc_u32;
294d8931847SRahul Lakkireddy 	handle = cls->knode.handle;
295d8931847SRahul Lakkireddy 	uhtid = TC_U32_USERHTID(cls->knode.handle);
296d8931847SRahul Lakkireddy 
297d8931847SRahul Lakkireddy 	/* Ensure that uhtid is either root u32 (i.e. 0x800)
298d8931847SRahul Lakkireddy 	 * or a a valid linked bucket.
299d8931847SRahul Lakkireddy 	 */
300d8931847SRahul Lakkireddy 	if (uhtid != 0x800 && uhtid >= t->size)
301d8931847SRahul Lakkireddy 		return -EINVAL;
302d8931847SRahul Lakkireddy 
303d8931847SRahul Lakkireddy 	/* Delete the specified filter */
304d8931847SRahul Lakkireddy 	if (uhtid != 0x800) {
305d8931847SRahul Lakkireddy 		link = &t->table[uhtid - 1];
306d8931847SRahul Lakkireddy 		if (!link->link_handle)
307d8931847SRahul Lakkireddy 			return -EINVAL;
308d8931847SRahul Lakkireddy 
309d8931847SRahul Lakkireddy 		if (!test_bit(filter_id, link->tid_map))
310d8931847SRahul Lakkireddy 			return -EINVAL;
311d8931847SRahul Lakkireddy 	}
312d8931847SRahul Lakkireddy 
313d8931847SRahul Lakkireddy 	ret = cxgb4_del_filter(dev, filter_id);
314d8931847SRahul Lakkireddy 	if (ret)
315d8931847SRahul Lakkireddy 		goto out;
316d8931847SRahul Lakkireddy 
317d8931847SRahul Lakkireddy 	if (link)
318d8931847SRahul Lakkireddy 		clear_bit(filter_id, link->tid_map);
319d8931847SRahul Lakkireddy 
320d8931847SRahul Lakkireddy 	/* If a link is being deleted, then delete all filters
321d8931847SRahul Lakkireddy 	 * associated with the link.
322d8931847SRahul Lakkireddy 	 */
323d8931847SRahul Lakkireddy 	max_tids = adapter->tids.nftids;
324d8931847SRahul Lakkireddy 	for (i = 0; i < t->size; i++) {
325d8931847SRahul Lakkireddy 		link = &t->table[i];
326d8931847SRahul Lakkireddy 
327d8931847SRahul Lakkireddy 		if (link->link_handle == handle) {
328d8931847SRahul Lakkireddy 			for (j = 0; j < max_tids; j++) {
329d8931847SRahul Lakkireddy 				if (!test_bit(j, link->tid_map))
330d8931847SRahul Lakkireddy 					continue;
331d8931847SRahul Lakkireddy 
332d8931847SRahul Lakkireddy 				ret = __cxgb4_del_filter(dev, j, NULL);
333d8931847SRahul Lakkireddy 				if (ret)
334d8931847SRahul Lakkireddy 					goto out;
335d8931847SRahul Lakkireddy 
336d8931847SRahul Lakkireddy 				clear_bit(j, link->tid_map);
337d8931847SRahul Lakkireddy 			}
338d8931847SRahul Lakkireddy 
339d8931847SRahul Lakkireddy 			/* Clear the link state */
340d8931847SRahul Lakkireddy 			link->match_field = NULL;
341d8931847SRahul Lakkireddy 			link->link_handle = 0;
342d8931847SRahul Lakkireddy 			memset(&link->fs, 0, sizeof(link->fs));
343d8931847SRahul Lakkireddy 			break;
344d8931847SRahul Lakkireddy 		}
345d8931847SRahul Lakkireddy 	}
346d8931847SRahul Lakkireddy 
347d8931847SRahul Lakkireddy out:
348d8931847SRahul Lakkireddy 	return ret;
349d8931847SRahul Lakkireddy }
350d8931847SRahul Lakkireddy 
351d8931847SRahul Lakkireddy void cxgb4_cleanup_tc_u32(struct adapter *adap)
352d8931847SRahul Lakkireddy {
353d8931847SRahul Lakkireddy 	struct cxgb4_tc_u32_table *t;
354d8931847SRahul Lakkireddy 	unsigned int i;
355d8931847SRahul Lakkireddy 
356d8931847SRahul Lakkireddy 	if (!adap->tc_u32)
357d8931847SRahul Lakkireddy 		return;
358d8931847SRahul Lakkireddy 
359d8931847SRahul Lakkireddy 	/* Free up all allocated memory. */
360d8931847SRahul Lakkireddy 	t = adap->tc_u32;
361d8931847SRahul Lakkireddy 	for (i = 0; i < t->size; i++) {
362d8931847SRahul Lakkireddy 		struct cxgb4_link *link = &t->table[i];
363d8931847SRahul Lakkireddy 
364d8931847SRahul Lakkireddy 		t4_free_mem(link->tid_map);
365d8931847SRahul Lakkireddy 	}
366d8931847SRahul Lakkireddy 	t4_free_mem(adap->tc_u32);
367d8931847SRahul Lakkireddy }
368d8931847SRahul Lakkireddy 
369d8931847SRahul Lakkireddy struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap,
370d8931847SRahul Lakkireddy 					     unsigned int size)
371d8931847SRahul Lakkireddy {
372d8931847SRahul Lakkireddy 	struct cxgb4_tc_u32_table *t;
373d8931847SRahul Lakkireddy 	unsigned int i;
374d8931847SRahul Lakkireddy 
375d8931847SRahul Lakkireddy 	if (!size)
376d8931847SRahul Lakkireddy 		return NULL;
377d8931847SRahul Lakkireddy 
378d8931847SRahul Lakkireddy 	t = t4_alloc_mem(sizeof(*t) +
379d8931847SRahul Lakkireddy 			 (size * sizeof(struct cxgb4_link)));
380d8931847SRahul Lakkireddy 	if (!t)
381d8931847SRahul Lakkireddy 		return NULL;
382d8931847SRahul Lakkireddy 
383d8931847SRahul Lakkireddy 	t->size = size;
384d8931847SRahul Lakkireddy 
385d8931847SRahul Lakkireddy 	for (i = 0; i < t->size; i++) {
386d8931847SRahul Lakkireddy 		struct cxgb4_link *link = &t->table[i];
387d8931847SRahul Lakkireddy 		unsigned int bmap_size;
388d8931847SRahul Lakkireddy 		unsigned int max_tids;
389d8931847SRahul Lakkireddy 
390d8931847SRahul Lakkireddy 		max_tids = adap->tids.nftids;
391d8931847SRahul Lakkireddy 		bmap_size = BITS_TO_LONGS(max_tids);
392d8931847SRahul Lakkireddy 		link->tid_map = t4_alloc_mem(sizeof(unsigned long) * bmap_size);
393d8931847SRahul Lakkireddy 		if (!link->tid_map)
394d8931847SRahul Lakkireddy 			goto out_no_mem;
395d8931847SRahul Lakkireddy 		bitmap_zero(link->tid_map, max_tids);
396d8931847SRahul Lakkireddy 	}
397d8931847SRahul Lakkireddy 
398d8931847SRahul Lakkireddy 	return t;
399d8931847SRahul Lakkireddy 
400d8931847SRahul Lakkireddy out_no_mem:
401d8931847SRahul Lakkireddy 	for (i = 0; i < t->size; i++) {
402d8931847SRahul Lakkireddy 		struct cxgb4_link *link = &t->table[i];
403d8931847SRahul Lakkireddy 
404d8931847SRahul Lakkireddy 		if (link->tid_map)
405d8931847SRahul Lakkireddy 			t4_free_mem(link->tid_map);
406d8931847SRahul Lakkireddy 	}
407d8931847SRahul Lakkireddy 
408d8931847SRahul Lakkireddy 	if (t)
409d8931847SRahul Lakkireddy 		t4_free_mem(t);
410d8931847SRahul Lakkireddy 
411d8931847SRahul Lakkireddy 	return NULL;
412d8931847SRahul Lakkireddy }
413