Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Chelsio Communications.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "mps_tcam.h"
7 : :
8 : : static inline bool
9 : 0 : match_entry(struct mps_tcam_entry *entry, const u8 *eth_addr, const u8 *mask)
10 : : {
11 [ # # ]: 0 : if (!memcmp(eth_addr, entry->eth_addr, RTE_ETHER_ADDR_LEN) &&
12 [ # # ]: 0 : !memcmp(mask, entry->mask, RTE_ETHER_ADDR_LEN))
13 : 0 : return true;
14 : : return false;
15 : : }
16 : :
17 : 0 : static int cxgbe_update_free_idx(struct mpstcam_table *t)
18 : : {
19 : 0 : struct mps_tcam_entry *entry = t->entry;
20 : 0 : u16 i, next = t->free_idx + 1;
21 : :
22 [ # # ]: 0 : if (entry[t->free_idx].state == MPS_ENTRY_UNUSED)
23 : : /* You are already pointing to a free entry !! */
24 : : return 0;
25 : :
26 : : /* loop, till we don't rollback to same index where we started */
27 [ # # ]: 0 : for (i = next; i != t->free_idx; i++) {
28 [ # # ]: 0 : if (i == t->size)
29 : : /* rollback and search free entry from start */
30 : : i = 0;
31 : :
32 [ # # ]: 0 : if (entry[i].state == MPS_ENTRY_UNUSED) {
33 : 0 : t->free_idx = i;
34 : 0 : return 0;
35 : : }
36 : : }
37 : :
38 : : return -1; /* table is full */
39 : : }
40 : :
41 : : static struct mps_tcam_entry *
42 : 0 : cxgbe_mpstcam_lookup(struct mpstcam_table *t, const u8 *eth_addr,
43 : : const u8 *mask)
44 : : {
45 : 0 : struct mps_tcam_entry *entry = t->entry;
46 : : int i;
47 : :
48 : : if (!entry)
49 : : return NULL;
50 : :
51 [ # # ]: 0 : for (i = 0; i < t->size; i++) {
52 [ # # ]: 0 : if (entry[i].state == MPS_ENTRY_UNUSED ||
53 : : entry[i].state == MPS_ENTRY_RAWF)
54 : 0 : continue; /* entry is not being used */
55 [ # # ]: 0 : if (match_entry(&entry[i], eth_addr, mask))
56 : 0 : return &entry[i];
57 : : }
58 : :
59 : : return NULL;
60 : : }
61 : :
62 : 0 : int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *eth_addr,
63 : : const u8 *mask)
64 : : {
65 : 0 : struct adapter *adap = pi->adapter;
66 : 0 : struct mpstcam_table *mpstcam = adap->mpstcam;
67 : : struct mps_tcam_entry *entry;
68 : : int ret;
69 : :
70 [ # # ]: 0 : if (!adap->mpstcam) {
71 : 0 : dev_err(adap, "mpstcam table is not available\n");
72 : 0 : return -EOPNOTSUPP;
73 : : }
74 : :
75 : : /* If entry already present, return it. */
76 : 0 : t4_os_write_lock(&mpstcam->lock);
77 : 0 : entry = cxgbe_mpstcam_lookup(adap->mpstcam, eth_addr, mask);
78 [ # # ]: 0 : if (entry) {
79 : 0 : rte_atomic_fetch_add_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
80 : : t4_os_write_unlock(&mpstcam->lock);
81 : 0 : return entry->idx;
82 : : }
83 : :
84 [ # # ]: 0 : if (mpstcam->full) {
85 : : t4_os_write_unlock(&mpstcam->lock);
86 : 0 : dev_err(adap, "mps-tcam table is full\n");
87 : 0 : return -ENOMEM;
88 : : }
89 : :
90 : 0 : ret = t4_alloc_raw_mac_filt(adap, pi->viid, eth_addr, mask,
91 : 0 : mpstcam->free_idx, 0, pi->port_id, false);
92 [ # # ]: 0 : if (ret <= 0) {
93 : : t4_os_write_unlock(&mpstcam->lock);
94 : 0 : return ret;
95 : : }
96 : :
97 : : /* Fill in the new values */
98 : : entry = &mpstcam->entry[ret];
99 : 0 : memcpy(entry->eth_addr, eth_addr, RTE_ETHER_ADDR_LEN);
100 : 0 : memcpy(entry->mask, mask, RTE_ETHER_ADDR_LEN);
101 : 0 : rte_atomic_store_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
102 : 0 : entry->state = MPS_ENTRY_USED;
103 : :
104 [ # # ]: 0 : if (cxgbe_update_free_idx(mpstcam))
105 : 0 : mpstcam->full = true;
106 : :
107 : : t4_os_write_unlock(&mpstcam->lock);
108 : 0 : return ret;
109 : : }
110 : :
111 : 0 : int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr)
112 : : {
113 : 0 : struct adapter *adap = pi->adapter;
114 : 0 : struct mpstcam_table *mpstcam = adap->mpstcam;
115 : : struct mps_tcam_entry *entry;
116 : :
117 [ # # ]: 0 : if (!mpstcam)
118 : : return -EOPNOTSUPP;
119 : 0 : t4_os_write_lock(&mpstcam->lock);
120 [ # # # # ]: 0 : if (idx != -1 && idx >= mpstcam->size) {
121 : : t4_os_write_unlock(&mpstcam->lock);
122 : 0 : return -EINVAL;
123 : : }
124 [ # # ]: 0 : if (idx >= 0) {
125 : : entry = &mpstcam->entry[idx];
126 : : /* user wants to modify an existing entry.
127 : : * verify if entry exists
128 : : */
129 [ # # ]: 0 : if (entry->state != MPS_ENTRY_USED) {
130 : : t4_os_write_unlock(&mpstcam->lock);
131 : 0 : return -EINVAL;
132 : : }
133 : : }
134 : :
135 : 0 : idx = t4_change_mac(adap, adap->mbox, pi->viid, idx, addr, true, true);
136 [ # # ]: 0 : if (idx < 0) {
137 : : t4_os_write_unlock(&mpstcam->lock);
138 : 0 : return idx;
139 : : }
140 : :
141 : : /* idx can now be different from what user provided */
142 : : entry = &mpstcam->entry[idx];
143 [ # # ]: 0 : memcpy(entry->eth_addr, addr, RTE_ETHER_ADDR_LEN);
144 [ # # ]: 0 : memset(entry->mask, ~0, RTE_ETHER_ADDR_LEN);
145 : : /* NOTE: we have considered the case that idx returned by t4_change_mac
146 : : * will be different from the user provided value only if user
147 : : * provided value is -1
148 : : */
149 [ # # ]: 0 : if (entry->state == MPS_ENTRY_UNUSED) {
150 : 0 : rte_atomic_store_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
151 : 0 : entry->state = MPS_ENTRY_USED;
152 : : }
153 : :
154 [ # # ]: 0 : if (cxgbe_update_free_idx(mpstcam))
155 : 0 : mpstcam->full = true;
156 : :
157 : : t4_os_write_unlock(&mpstcam->lock);
158 : 0 : return idx;
159 : : }
160 : :
161 : : /**
162 : : * hold appropriate locks while calling this.
163 : : */
164 : 0 : static inline void reset_mpstcam_entry(struct mps_tcam_entry *entry)
165 : : {
166 : 0 : memset(entry->eth_addr, 0, RTE_ETHER_ADDR_LEN);
167 : 0 : memset(entry->mask, 0, RTE_ETHER_ADDR_LEN);
168 : 0 : rte_atomic_store_explicit(&entry->refcnt, 0, rte_memory_order_relaxed);
169 : 0 : entry->state = MPS_ENTRY_UNUSED;
170 : 0 : }
171 : :
172 : : /**
173 : : * ret < 0: fatal error
174 : : * ret = 0: entry removed in h/w
175 : : * ret > 0: updated refcount.
176 : : */
177 : 0 : int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx)
178 : : {
179 : 0 : struct adapter *adap = pi->adapter;
180 : 0 : struct mpstcam_table *t = adap->mpstcam;
181 : : struct mps_tcam_entry *entry;
182 : : int ret;
183 : :
184 [ # # ]: 0 : if (!t)
185 : : return -EOPNOTSUPP;
186 : 0 : t4_os_write_lock(&t->lock);
187 : 0 : entry = &t->entry[idx];
188 [ # # ]: 0 : if (entry->state != MPS_ENTRY_USED) {
189 : : t4_os_write_unlock(&t->lock);
190 : 0 : return -EINVAL;
191 : : }
192 : :
193 [ # # ]: 0 : if (rte_atomic_load_explicit(&entry->refcnt, rte_memory_order_relaxed) == 1)
194 : 0 : ret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,
195 : 0 : entry->mask, idx, 1, pi->port_id,
196 : : false);
197 : : else
198 : 0 : ret = rte_atomic_fetch_sub_explicit(&entry->refcnt, 1,
199 : 0 : rte_memory_order_relaxed) - 1;
200 : :
201 [ # # ]: 0 : if (ret == 0) {
202 : 0 : reset_mpstcam_entry(entry);
203 : 0 : t->full = false; /* We have atleast 1 free entry */
204 : 0 : cxgbe_update_free_idx(t);
205 : : }
206 : :
207 : : t4_os_write_unlock(&t->lock);
208 : 0 : return ret;
209 : : }
210 : :
211 : 0 : int cxgbe_mpstcam_rawf_enable(struct port_info *pi)
212 : : {
213 : 0 : struct adapter *adap = pi->adapter;
214 : : struct mps_tcam_entry *entry;
215 : : struct mpstcam_table *t;
216 : : u16 rawf_idx;
217 : : int ret = 0;
218 : :
219 : 0 : t = adap->mpstcam;
220 [ # # # # ]: 0 : if (adap->params.rawf_size == 0 || t == NULL)
221 : : return -EOPNOTSUPP;
222 : :
223 : 0 : t4_os_write_lock(&t->lock);
224 : 0 : rawf_idx = adap->params.rawf_start + pi->port_id;
225 : 0 : entry = &t->entry[rawf_idx];
226 [ # # ]: 0 : if (rte_atomic_load_explicit(&entry->refcnt, rte_memory_order_relaxed) == 1)
227 : 0 : goto out_unlock;
228 : :
229 : 0 : ret = t4_alloc_raw_mac_filt(adap, pi->viid, entry->eth_addr,
230 : 0 : entry->mask, rawf_idx, 0, pi->port_id,
231 : : false);
232 [ # # ]: 0 : if (ret < 0)
233 : 0 : goto out_unlock;
234 : :
235 : 0 : rte_atomic_store_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
236 : :
237 : 0 : out_unlock:
238 : : t4_os_write_unlock(&t->lock);
239 : 0 : return ret;
240 : : }
241 : :
242 : 0 : int cxgbe_mpstcam_rawf_disable(struct port_info *pi)
243 : : {
244 : 0 : struct adapter *adap = pi->adapter;
245 : : struct mps_tcam_entry *entry;
246 : : struct mpstcam_table *t;
247 : : u16 rawf_idx;
248 : : int ret = 0;
249 : :
250 : 0 : t = adap->mpstcam;
251 [ # # # # ]: 0 : if (adap->params.rawf_size == 0 || t == NULL)
252 : : return -EOPNOTSUPP;
253 : :
254 : 0 : t4_os_write_lock(&t->lock);
255 : 0 : rawf_idx = adap->params.rawf_start + pi->port_id;
256 : 0 : entry = &t->entry[rawf_idx];
257 [ # # ]: 0 : if (rte_atomic_load_explicit(&entry->refcnt, rte_memory_order_relaxed) != 1)
258 : 0 : goto out_unlock;
259 : :
260 : 0 : ret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,
261 : 0 : entry->mask, rawf_idx, 0, pi->port_id,
262 : : false);
263 [ # # ]: 0 : if (ret < 0)
264 : 0 : goto out_unlock;
265 : :
266 : 0 : rte_atomic_store_explicit(&entry->refcnt, 0, rte_memory_order_relaxed);
267 : :
268 : 0 : out_unlock:
269 : : t4_os_write_unlock(&t->lock);
270 : 0 : return ret;
271 : : }
272 : :
273 : 0 : struct mpstcam_table *t4_init_mpstcam(struct adapter *adap)
274 : : {
275 : 0 : u16 size = adap->params.arch.mps_tcam_size;
276 : : struct mpstcam_table *t;
277 : : int i;
278 : :
279 : 0 : t = t4_os_alloc(sizeof(*t) + size * sizeof(struct mps_tcam_entry));
280 [ # # ]: 0 : if (!t)
281 : : return NULL;
282 : :
283 : : t4_os_rwlock_init(&t->lock);
284 : 0 : t->full = false;
285 : 0 : t->size = size;
286 : :
287 [ # # ]: 0 : for (i = 0; i < size; i++) {
288 : 0 : reset_mpstcam_entry(&t->entry[i]);
289 : 0 : t->entry[i].mpstcam = t;
290 : 0 : t->entry[i].idx = i;
291 : : }
292 : :
293 : : /* RAW MAC entries are reserved for match-all wildcard to
294 : : * match all promiscuous traffic. So, mark them special.
295 : : */
296 [ # # ]: 0 : for (i = 0; i < adap->params.rawf_size; i++)
297 : 0 : t->entry[adap->params.rawf_start + i].state = MPS_ENTRY_RAWF;
298 : :
299 : : /* first entry is used by chip. this is overwritten only
300 : : * in t4_cleanup_mpstcam()
301 : : */
302 : 0 : t->entry[0].state = MPS_ENTRY_USED;
303 : 0 : t->free_idx = 1;
304 : :
305 : 0 : return t;
306 : : }
307 : :
308 : 0 : void t4_cleanup_mpstcam(struct adapter *adap)
309 : : {
310 [ # # ]: 0 : if (adap->mpstcam)
311 : 0 : t4_os_free(adap->mpstcam);
312 : 0 : }
|