net/bnxt: support 58818 chip family
[dpdk.git] / drivers / net / cxgbe / mps_tcam.c
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 match_entry(struct mps_tcam_entry *entry, const u8 *eth_addr, const u8 *mask)
10 {
11         if (!memcmp(eth_addr, entry->eth_addr, RTE_ETHER_ADDR_LEN) &&
12             !memcmp(mask, entry->mask, RTE_ETHER_ADDR_LEN))
13                 return true;
14         return false;
15 }
16
17 static int cxgbe_update_free_idx(struct mpstcam_table *t)
18 {
19         struct mps_tcam_entry *entry = t->entry;
20         u16 i, next = t->free_idx + 1;
21
22         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         for (i = next; i != t->free_idx; i++) {
28                 if (i == t->size)
29                         /* rollback and search free entry from start */
30                         i = 0;
31
32                 if (entry[i].state == MPS_ENTRY_UNUSED) {
33                         t->free_idx = i;
34                         return 0;
35                 }
36         }
37
38         return -1;      /* table is full */
39 }
40
41 static struct mps_tcam_entry *
42 cxgbe_mpstcam_lookup(struct mpstcam_table *t, const u8 *eth_addr,
43                      const u8 *mask)
44 {
45         struct mps_tcam_entry *entry = t->entry;
46         int i;
47
48         if (!entry)
49                 return NULL;
50
51         for (i = 0; i < t->size; i++) {
52                 if (entry[i].state == MPS_ENTRY_UNUSED)
53                         continue;       /* entry is not being used */
54                 if (match_entry(&entry[i], eth_addr, mask))
55                         return &entry[i];
56         }
57
58         return NULL;
59 }
60
61 int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *eth_addr,
62                         const u8 *mask)
63 {
64         struct adapter *adap = pi->adapter;
65         struct mpstcam_table *mpstcam = adap->mpstcam;
66         struct mps_tcam_entry *entry;
67         int ret;
68
69         if (!adap->mpstcam) {
70                 dev_err(adap, "mpstcam table is not available\n");
71                 return -EOPNOTSUPP;
72         }
73
74         /* If entry already present, return it. */
75         t4_os_write_lock(&mpstcam->lock);
76         entry = cxgbe_mpstcam_lookup(adap->mpstcam, eth_addr, mask);
77         if (entry) {
78                 rte_atomic32_add(&entry->refcnt, 1);
79                 t4_os_write_unlock(&mpstcam->lock);
80                 return entry->idx;
81         }
82
83         if (mpstcam->full) {
84                 t4_os_write_unlock(&mpstcam->lock);
85                 dev_err(adap, "mps-tcam table is full\n");
86                 return -ENOMEM;
87         }
88
89         ret = t4_alloc_raw_mac_filt(adap, pi->viid, eth_addr, mask,
90                                     mpstcam->free_idx, 0, pi->port_id, false);
91         if (ret <= 0) {
92                 t4_os_write_unlock(&mpstcam->lock);
93                 return ret;
94         }
95
96         /* Fill in the new values */
97         entry = &mpstcam->entry[ret];
98         memcpy(entry->eth_addr, eth_addr, RTE_ETHER_ADDR_LEN);
99         memcpy(entry->mask, mask, RTE_ETHER_ADDR_LEN);
100         rte_atomic32_set(&entry->refcnt, 1);
101         entry->state = MPS_ENTRY_USED;
102
103         if (cxgbe_update_free_idx(mpstcam))
104                 mpstcam->full = true;
105
106         t4_os_write_unlock(&mpstcam->lock);
107         return ret;
108 }
109
110 int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr)
111 {
112         struct adapter *adap = pi->adapter;
113         struct mpstcam_table *mpstcam = adap->mpstcam;
114         struct mps_tcam_entry *entry;
115
116         if (!mpstcam)
117                 return -EOPNOTSUPP;
118         t4_os_write_lock(&mpstcam->lock);
119         if (idx != -1 && idx >= mpstcam->size) {
120                 t4_os_write_unlock(&mpstcam->lock);
121                 return -EINVAL;
122         }
123         if (idx >= 0) {
124                 entry = &mpstcam->entry[idx];
125                 /* user wants to modify an existing entry.
126                  * verify if entry exists
127                  */
128                 if (entry->state != MPS_ENTRY_USED) {
129                         t4_os_write_unlock(&mpstcam->lock);
130                         return -EINVAL;
131                 }
132         }
133
134         idx = t4_change_mac(adap, adap->mbox, pi->viid, idx, addr, true, true);
135         if (idx < 0) {
136                 t4_os_write_unlock(&mpstcam->lock);
137                 return idx;
138         }
139
140         /* idx can now be different from what user provided */
141         entry = &mpstcam->entry[idx];
142         memcpy(entry->eth_addr, addr, RTE_ETHER_ADDR_LEN);
143         memset(entry->mask, ~0, RTE_ETHER_ADDR_LEN);
144         /* NOTE: we have considered the case that idx returned by t4_change_mac
145          * will be different from the user provided value only if user
146          * provided value is -1
147          */
148         if (entry->state == MPS_ENTRY_UNUSED) {
149                 rte_atomic32_set(&entry->refcnt, 1);
150                 entry->state = MPS_ENTRY_USED;
151         }
152
153         if (cxgbe_update_free_idx(mpstcam))
154                 mpstcam->full = true;
155
156         t4_os_write_unlock(&mpstcam->lock);
157         return idx;
158 }
159
160 /**
161  * hold appropriate locks while calling this.
162  */
163 static inline void reset_mpstcam_entry(struct mps_tcam_entry *entry)
164 {
165         memset(entry->eth_addr, 0, RTE_ETHER_ADDR_LEN);
166         memset(entry->mask, 0, RTE_ETHER_ADDR_LEN);
167         rte_atomic32_clear(&entry->refcnt);
168         entry->state = MPS_ENTRY_UNUSED;
169 }
170
171 /**
172  * ret < 0: fatal error
173  * ret = 0: entry removed in h/w
174  * ret > 0: updated refcount.
175  */
176 int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx)
177 {
178         struct adapter *adap = pi->adapter;
179         struct mpstcam_table *t = adap->mpstcam;
180         struct mps_tcam_entry *entry;
181         int ret;
182
183         if (!t)
184                 return -EOPNOTSUPP;
185         t4_os_write_lock(&t->lock);
186         entry = &t->entry[idx];
187         if (entry->state == MPS_ENTRY_UNUSED) {
188                 t4_os_write_unlock(&t->lock);
189                 return -EINVAL;
190         }
191
192         if (rte_atomic32_read(&entry->refcnt) == 1)
193                 ret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,
194                                            entry->mask, idx, 1, pi->port_id,
195                                            false);
196         else
197                 ret = rte_atomic32_sub_return(&entry->refcnt, 1);
198
199         if (ret == 0) {
200                 reset_mpstcam_entry(entry);
201                 t->full = false;        /* We have atleast 1 free entry */
202                 cxgbe_update_free_idx(t);
203         }
204
205         t4_os_write_unlock(&t->lock);
206         return ret;
207 }
208
209 struct mpstcam_table *t4_init_mpstcam(struct adapter *adap)
210 {
211         struct mpstcam_table *t;
212         int i;
213         u16 size = adap->params.arch.mps_tcam_size;
214
215         t =  t4_os_alloc(sizeof(*t) + size * sizeof(struct mps_tcam_entry));
216         if (!t)
217                 return NULL;
218
219         t4_os_rwlock_init(&t->lock);
220         t->full = false;
221         t->size = size;
222
223         for (i = 0; i < size; i++) {
224                 reset_mpstcam_entry(&t->entry[i]);
225                 t->entry[i].mpstcam = t;
226                 t->entry[i].idx = i;
227         }
228
229         /* first entry is used by chip. this is overwritten only
230          * in t4_cleanup_mpstcam()
231          */
232         t->entry[0].state = MPS_ENTRY_USED;
233         t->free_idx = 1;
234
235         return t;
236 }
237
238 void t4_cleanup_mpstcam(struct adapter *adap)
239 {
240         if (adap->mpstcam)
241                 t4_os_free(adap->mpstcam);
242 }