16fda3f0dSShagun Agrawal /* SPDX-License-Identifier: BSD-3-Clause
26fda3f0dSShagun Agrawal * Copyright(c) 2018 Chelsio Communications.
36fda3f0dSShagun Agrawal * All rights reserved.
46fda3f0dSShagun Agrawal */
56fda3f0dSShagun Agrawal
66fda3f0dSShagun Agrawal #include "mps_tcam.h"
76fda3f0dSShagun Agrawal
86fda3f0dSShagun Agrawal static inline bool
match_entry(struct mps_tcam_entry * entry,const u8 * eth_addr,const u8 * mask)96fda3f0dSShagun Agrawal match_entry(struct mps_tcam_entry *entry, const u8 *eth_addr, const u8 *mask)
106fda3f0dSShagun Agrawal {
1135b2d13fSOlivier Matz if (!memcmp(eth_addr, entry->eth_addr, RTE_ETHER_ADDR_LEN) &&
1235b2d13fSOlivier Matz !memcmp(mask, entry->mask, RTE_ETHER_ADDR_LEN))
136fda3f0dSShagun Agrawal return true;
146fda3f0dSShagun Agrawal return false;
156fda3f0dSShagun Agrawal }
166fda3f0dSShagun Agrawal
cxgbe_update_free_idx(struct mpstcam_table * t)176fda3f0dSShagun Agrawal static int cxgbe_update_free_idx(struct mpstcam_table *t)
186fda3f0dSShagun Agrawal {
196fda3f0dSShagun Agrawal struct mps_tcam_entry *entry = t->entry;
206fda3f0dSShagun Agrawal u16 i, next = t->free_idx + 1;
216fda3f0dSShagun Agrawal
226fda3f0dSShagun Agrawal if (entry[t->free_idx].state == MPS_ENTRY_UNUSED)
236fda3f0dSShagun Agrawal /* You are already pointing to a free entry !! */
246fda3f0dSShagun Agrawal return 0;
256fda3f0dSShagun Agrawal
266fda3f0dSShagun Agrawal /* loop, till we don't rollback to same index where we started */
276fda3f0dSShagun Agrawal for (i = next; i != t->free_idx; i++) {
286fda3f0dSShagun Agrawal if (i == t->size)
296fda3f0dSShagun Agrawal /* rollback and search free entry from start */
306fda3f0dSShagun Agrawal i = 0;
316fda3f0dSShagun Agrawal
326fda3f0dSShagun Agrawal if (entry[i].state == MPS_ENTRY_UNUSED) {
336fda3f0dSShagun Agrawal t->free_idx = i;
346fda3f0dSShagun Agrawal return 0;
356fda3f0dSShagun Agrawal }
366fda3f0dSShagun Agrawal }
376fda3f0dSShagun Agrawal
386fda3f0dSShagun Agrawal return -1; /* table is full */
396fda3f0dSShagun Agrawal }
406fda3f0dSShagun Agrawal
416fda3f0dSShagun Agrawal static struct mps_tcam_entry *
cxgbe_mpstcam_lookup(struct mpstcam_table * t,const u8 * eth_addr,const u8 * mask)426fda3f0dSShagun Agrawal cxgbe_mpstcam_lookup(struct mpstcam_table *t, const u8 *eth_addr,
436fda3f0dSShagun Agrawal const u8 *mask)
446fda3f0dSShagun Agrawal {
456fda3f0dSShagun Agrawal struct mps_tcam_entry *entry = t->entry;
466fda3f0dSShagun Agrawal int i;
476fda3f0dSShagun Agrawal
486fda3f0dSShagun Agrawal if (!entry)
496fda3f0dSShagun Agrawal return NULL;
506fda3f0dSShagun Agrawal
516fda3f0dSShagun Agrawal for (i = 0; i < t->size; i++) {
52422d7823SRahul Lakkireddy if (entry[i].state == MPS_ENTRY_UNUSED ||
53422d7823SRahul Lakkireddy entry[i].state == MPS_ENTRY_RAWF)
546fda3f0dSShagun Agrawal continue; /* entry is not being used */
556fda3f0dSShagun Agrawal if (match_entry(&entry[i], eth_addr, mask))
566fda3f0dSShagun Agrawal return &entry[i];
576fda3f0dSShagun Agrawal }
586fda3f0dSShagun Agrawal
596fda3f0dSShagun Agrawal return NULL;
606fda3f0dSShagun Agrawal }
616fda3f0dSShagun Agrawal
cxgbe_mpstcam_alloc(struct port_info * pi,const u8 * eth_addr,const u8 * mask)626fda3f0dSShagun Agrawal int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *eth_addr,
636fda3f0dSShagun Agrawal const u8 *mask)
646fda3f0dSShagun Agrawal {
656fda3f0dSShagun Agrawal struct adapter *adap = pi->adapter;
666fda3f0dSShagun Agrawal struct mpstcam_table *mpstcam = adap->mpstcam;
676fda3f0dSShagun Agrawal struct mps_tcam_entry *entry;
686fda3f0dSShagun Agrawal int ret;
696fda3f0dSShagun Agrawal
706fda3f0dSShagun Agrawal if (!adap->mpstcam) {
716fda3f0dSShagun Agrawal dev_err(adap, "mpstcam table is not available\n");
726fda3f0dSShagun Agrawal return -EOPNOTSUPP;
736fda3f0dSShagun Agrawal }
746fda3f0dSShagun Agrawal
756fda3f0dSShagun Agrawal /* If entry already present, return it. */
766fda3f0dSShagun Agrawal t4_os_write_lock(&mpstcam->lock);
776fda3f0dSShagun Agrawal entry = cxgbe_mpstcam_lookup(adap->mpstcam, eth_addr, mask);
786fda3f0dSShagun Agrawal if (entry) {
79*e12a0166STyler Retzlaff rte_atomic_fetch_add_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
806fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
816fda3f0dSShagun Agrawal return entry->idx;
826fda3f0dSShagun Agrawal }
836fda3f0dSShagun Agrawal
846fda3f0dSShagun Agrawal if (mpstcam->full) {
856fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
866fda3f0dSShagun Agrawal dev_err(adap, "mps-tcam table is full\n");
876fda3f0dSShagun Agrawal return -ENOMEM;
886fda3f0dSShagun Agrawal }
896fda3f0dSShagun Agrawal
906fda3f0dSShagun Agrawal ret = t4_alloc_raw_mac_filt(adap, pi->viid, eth_addr, mask,
916fda3f0dSShagun Agrawal mpstcam->free_idx, 0, pi->port_id, false);
926fda3f0dSShagun Agrawal if (ret <= 0) {
936fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
946fda3f0dSShagun Agrawal return ret;
956fda3f0dSShagun Agrawal }
966fda3f0dSShagun Agrawal
976fda3f0dSShagun Agrawal /* Fill in the new values */
986fda3f0dSShagun Agrawal entry = &mpstcam->entry[ret];
9935b2d13fSOlivier Matz memcpy(entry->eth_addr, eth_addr, RTE_ETHER_ADDR_LEN);
10035b2d13fSOlivier Matz memcpy(entry->mask, mask, RTE_ETHER_ADDR_LEN);
101*e12a0166STyler Retzlaff rte_atomic_store_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
1026fda3f0dSShagun Agrawal entry->state = MPS_ENTRY_USED;
1036fda3f0dSShagun Agrawal
1046fda3f0dSShagun Agrawal if (cxgbe_update_free_idx(mpstcam))
1056fda3f0dSShagun Agrawal mpstcam->full = true;
1066fda3f0dSShagun Agrawal
1076fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
1086fda3f0dSShagun Agrawal return ret;
1096fda3f0dSShagun Agrawal }
1106fda3f0dSShagun Agrawal
cxgbe_mpstcam_modify(struct port_info * pi,int idx,const u8 * addr)1116fda3f0dSShagun Agrawal int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr)
1126fda3f0dSShagun Agrawal {
1136fda3f0dSShagun Agrawal struct adapter *adap = pi->adapter;
1146fda3f0dSShagun Agrawal struct mpstcam_table *mpstcam = adap->mpstcam;
1156fda3f0dSShagun Agrawal struct mps_tcam_entry *entry;
1166fda3f0dSShagun Agrawal
1176fda3f0dSShagun Agrawal if (!mpstcam)
1186fda3f0dSShagun Agrawal return -EOPNOTSUPP;
1196fda3f0dSShagun Agrawal t4_os_write_lock(&mpstcam->lock);
1206fda3f0dSShagun Agrawal if (idx != -1 && idx >= mpstcam->size) {
1216fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
1226fda3f0dSShagun Agrawal return -EINVAL;
1236fda3f0dSShagun Agrawal }
1246fda3f0dSShagun Agrawal if (idx >= 0) {
1256fda3f0dSShagun Agrawal entry = &mpstcam->entry[idx];
1266fda3f0dSShagun Agrawal /* user wants to modify an existing entry.
1276fda3f0dSShagun Agrawal * verify if entry exists
1286fda3f0dSShagun Agrawal */
1296fda3f0dSShagun Agrawal if (entry->state != MPS_ENTRY_USED) {
1306fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
1316fda3f0dSShagun Agrawal return -EINVAL;
1326fda3f0dSShagun Agrawal }
1336fda3f0dSShagun Agrawal }
1346fda3f0dSShagun Agrawal
1356fda3f0dSShagun Agrawal idx = t4_change_mac(adap, adap->mbox, pi->viid, idx, addr, true, true);
1366fda3f0dSShagun Agrawal if (idx < 0) {
1376fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
1386fda3f0dSShagun Agrawal return idx;
1396fda3f0dSShagun Agrawal }
1406fda3f0dSShagun Agrawal
1416fda3f0dSShagun Agrawal /* idx can now be different from what user provided */
1426fda3f0dSShagun Agrawal entry = &mpstcam->entry[idx];
14335b2d13fSOlivier Matz memcpy(entry->eth_addr, addr, RTE_ETHER_ADDR_LEN);
1440dd95bc9SKarra Satwik memset(entry->mask, ~0, RTE_ETHER_ADDR_LEN);
1456fda3f0dSShagun Agrawal /* NOTE: we have considered the case that idx returned by t4_change_mac
1466fda3f0dSShagun Agrawal * will be different from the user provided value only if user
1476fda3f0dSShagun Agrawal * provided value is -1
1486fda3f0dSShagun Agrawal */
1496fda3f0dSShagun Agrawal if (entry->state == MPS_ENTRY_UNUSED) {
150*e12a0166STyler Retzlaff rte_atomic_store_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
1516fda3f0dSShagun Agrawal entry->state = MPS_ENTRY_USED;
1526fda3f0dSShagun Agrawal }
1536fda3f0dSShagun Agrawal
1546fda3f0dSShagun Agrawal if (cxgbe_update_free_idx(mpstcam))
1556fda3f0dSShagun Agrawal mpstcam->full = true;
1566fda3f0dSShagun Agrawal
1576fda3f0dSShagun Agrawal t4_os_write_unlock(&mpstcam->lock);
1586fda3f0dSShagun Agrawal return idx;
1596fda3f0dSShagun Agrawal }
1606fda3f0dSShagun Agrawal
1616fda3f0dSShagun Agrawal /**
1626fda3f0dSShagun Agrawal * hold appropriate locks while calling this.
1636fda3f0dSShagun Agrawal */
reset_mpstcam_entry(struct mps_tcam_entry * entry)1646fda3f0dSShagun Agrawal static inline void reset_mpstcam_entry(struct mps_tcam_entry *entry)
1656fda3f0dSShagun Agrawal {
16635b2d13fSOlivier Matz memset(entry->eth_addr, 0, RTE_ETHER_ADDR_LEN);
16735b2d13fSOlivier Matz memset(entry->mask, 0, RTE_ETHER_ADDR_LEN);
168*e12a0166STyler Retzlaff rte_atomic_store_explicit(&entry->refcnt, 0, rte_memory_order_relaxed);
1696fda3f0dSShagun Agrawal entry->state = MPS_ENTRY_UNUSED;
1706fda3f0dSShagun Agrawal }
1716fda3f0dSShagun Agrawal
1726fda3f0dSShagun Agrawal /**
1736fda3f0dSShagun Agrawal * ret < 0: fatal error
1746fda3f0dSShagun Agrawal * ret = 0: entry removed in h/w
1756fda3f0dSShagun Agrawal * ret > 0: updated refcount.
1766fda3f0dSShagun Agrawal */
cxgbe_mpstcam_remove(struct port_info * pi,u16 idx)1776fda3f0dSShagun Agrawal int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx)
1786fda3f0dSShagun Agrawal {
1796fda3f0dSShagun Agrawal struct adapter *adap = pi->adapter;
1806fda3f0dSShagun Agrawal struct mpstcam_table *t = adap->mpstcam;
1816fda3f0dSShagun Agrawal struct mps_tcam_entry *entry;
1826fda3f0dSShagun Agrawal int ret;
1836fda3f0dSShagun Agrawal
1846fda3f0dSShagun Agrawal if (!t)
1856fda3f0dSShagun Agrawal return -EOPNOTSUPP;
1866fda3f0dSShagun Agrawal t4_os_write_lock(&t->lock);
1876fda3f0dSShagun Agrawal entry = &t->entry[idx];
188422d7823SRahul Lakkireddy if (entry->state != MPS_ENTRY_USED) {
1896fda3f0dSShagun Agrawal t4_os_write_unlock(&t->lock);
1906fda3f0dSShagun Agrawal return -EINVAL;
1916fda3f0dSShagun Agrawal }
1926fda3f0dSShagun Agrawal
193*e12a0166STyler Retzlaff if (rte_atomic_load_explicit(&entry->refcnt, rte_memory_order_relaxed) == 1)
1946fda3f0dSShagun Agrawal ret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,
1956fda3f0dSShagun Agrawal entry->mask, idx, 1, pi->port_id,
1966fda3f0dSShagun Agrawal false);
1976fda3f0dSShagun Agrawal else
198*e12a0166STyler Retzlaff ret = rte_atomic_fetch_sub_explicit(&entry->refcnt, 1,
199*e12a0166STyler Retzlaff rte_memory_order_relaxed) - 1;
2006fda3f0dSShagun Agrawal
2016fda3f0dSShagun Agrawal if (ret == 0) {
2026fda3f0dSShagun Agrawal reset_mpstcam_entry(entry);
2036fda3f0dSShagun Agrawal t->full = false; /* We have atleast 1 free entry */
2046fda3f0dSShagun Agrawal cxgbe_update_free_idx(t);
2056fda3f0dSShagun Agrawal }
2066fda3f0dSShagun Agrawal
2076fda3f0dSShagun Agrawal t4_os_write_unlock(&t->lock);
2086fda3f0dSShagun Agrawal return ret;
2096fda3f0dSShagun Agrawal }
2106fda3f0dSShagun Agrawal
cxgbe_mpstcam_rawf_enable(struct port_info * pi)211422d7823SRahul Lakkireddy int cxgbe_mpstcam_rawf_enable(struct port_info *pi)
212422d7823SRahul Lakkireddy {
213422d7823SRahul Lakkireddy struct adapter *adap = pi->adapter;
214422d7823SRahul Lakkireddy struct mps_tcam_entry *entry;
215422d7823SRahul Lakkireddy struct mpstcam_table *t;
216422d7823SRahul Lakkireddy u16 rawf_idx;
217422d7823SRahul Lakkireddy int ret = 0;
218422d7823SRahul Lakkireddy
219422d7823SRahul Lakkireddy t = adap->mpstcam;
220422d7823SRahul Lakkireddy if (adap->params.rawf_size == 0 || t == NULL)
221422d7823SRahul Lakkireddy return -EOPNOTSUPP;
222422d7823SRahul Lakkireddy
223422d7823SRahul Lakkireddy t4_os_write_lock(&t->lock);
224422d7823SRahul Lakkireddy rawf_idx = adap->params.rawf_start + pi->port_id;
225422d7823SRahul Lakkireddy entry = &t->entry[rawf_idx];
226*e12a0166STyler Retzlaff if (rte_atomic_load_explicit(&entry->refcnt, rte_memory_order_relaxed) == 1)
227422d7823SRahul Lakkireddy goto out_unlock;
228422d7823SRahul Lakkireddy
229422d7823SRahul Lakkireddy ret = t4_alloc_raw_mac_filt(adap, pi->viid, entry->eth_addr,
230422d7823SRahul Lakkireddy entry->mask, rawf_idx, 0, pi->port_id,
231422d7823SRahul Lakkireddy false);
232422d7823SRahul Lakkireddy if (ret < 0)
233422d7823SRahul Lakkireddy goto out_unlock;
234422d7823SRahul Lakkireddy
235*e12a0166STyler Retzlaff rte_atomic_store_explicit(&entry->refcnt, 1, rte_memory_order_relaxed);
236422d7823SRahul Lakkireddy
237422d7823SRahul Lakkireddy out_unlock:
238422d7823SRahul Lakkireddy t4_os_write_unlock(&t->lock);
239422d7823SRahul Lakkireddy return ret;
240422d7823SRahul Lakkireddy }
241422d7823SRahul Lakkireddy
cxgbe_mpstcam_rawf_disable(struct port_info * pi)242422d7823SRahul Lakkireddy int cxgbe_mpstcam_rawf_disable(struct port_info *pi)
243422d7823SRahul Lakkireddy {
244422d7823SRahul Lakkireddy struct adapter *adap = pi->adapter;
245422d7823SRahul Lakkireddy struct mps_tcam_entry *entry;
246422d7823SRahul Lakkireddy struct mpstcam_table *t;
247422d7823SRahul Lakkireddy u16 rawf_idx;
248422d7823SRahul Lakkireddy int ret = 0;
249422d7823SRahul Lakkireddy
250422d7823SRahul Lakkireddy t = adap->mpstcam;
251422d7823SRahul Lakkireddy if (adap->params.rawf_size == 0 || t == NULL)
252422d7823SRahul Lakkireddy return -EOPNOTSUPP;
253422d7823SRahul Lakkireddy
254422d7823SRahul Lakkireddy t4_os_write_lock(&t->lock);
255422d7823SRahul Lakkireddy rawf_idx = adap->params.rawf_start + pi->port_id;
256422d7823SRahul Lakkireddy entry = &t->entry[rawf_idx];
257*e12a0166STyler Retzlaff if (rte_atomic_load_explicit(&entry->refcnt, rte_memory_order_relaxed) != 1)
258422d7823SRahul Lakkireddy goto out_unlock;
259422d7823SRahul Lakkireddy
260422d7823SRahul Lakkireddy ret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,
261422d7823SRahul Lakkireddy entry->mask, rawf_idx, 0, pi->port_id,
262422d7823SRahul Lakkireddy false);
263422d7823SRahul Lakkireddy if (ret < 0)
264422d7823SRahul Lakkireddy goto out_unlock;
265422d7823SRahul Lakkireddy
266*e12a0166STyler Retzlaff rte_atomic_store_explicit(&entry->refcnt, 0, rte_memory_order_relaxed);
267422d7823SRahul Lakkireddy
268422d7823SRahul Lakkireddy out_unlock:
269422d7823SRahul Lakkireddy t4_os_write_unlock(&t->lock);
270422d7823SRahul Lakkireddy return ret;
271422d7823SRahul Lakkireddy }
272422d7823SRahul Lakkireddy
t4_init_mpstcam(struct adapter * adap)2736fda3f0dSShagun Agrawal struct mpstcam_table *t4_init_mpstcam(struct adapter *adap)
2746fda3f0dSShagun Agrawal {
275422d7823SRahul Lakkireddy u16 size = adap->params.arch.mps_tcam_size;
2766fda3f0dSShagun Agrawal struct mpstcam_table *t;
2776fda3f0dSShagun Agrawal int i;
2786fda3f0dSShagun Agrawal
2796fda3f0dSShagun Agrawal t = t4_os_alloc(sizeof(*t) + size * sizeof(struct mps_tcam_entry));
2806fda3f0dSShagun Agrawal if (!t)
2816fda3f0dSShagun Agrawal return NULL;
2826fda3f0dSShagun Agrawal
2836fda3f0dSShagun Agrawal t4_os_rwlock_init(&t->lock);
2846fda3f0dSShagun Agrawal t->full = false;
2856fda3f0dSShagun Agrawal t->size = size;
2866fda3f0dSShagun Agrawal
2876fda3f0dSShagun Agrawal for (i = 0; i < size; i++) {
2886fda3f0dSShagun Agrawal reset_mpstcam_entry(&t->entry[i]);
2896fda3f0dSShagun Agrawal t->entry[i].mpstcam = t;
2906fda3f0dSShagun Agrawal t->entry[i].idx = i;
2916fda3f0dSShagun Agrawal }
2926fda3f0dSShagun Agrawal
293422d7823SRahul Lakkireddy /* RAW MAC entries are reserved for match-all wildcard to
294422d7823SRahul Lakkireddy * match all promiscuous traffic. So, mark them special.
295422d7823SRahul Lakkireddy */
296422d7823SRahul Lakkireddy for (i = 0; i < adap->params.rawf_size; i++)
297422d7823SRahul Lakkireddy t->entry[adap->params.rawf_start + i].state = MPS_ENTRY_RAWF;
298422d7823SRahul Lakkireddy
2996fda3f0dSShagun Agrawal /* first entry is used by chip. this is overwritten only
3006fda3f0dSShagun Agrawal * in t4_cleanup_mpstcam()
3016fda3f0dSShagun Agrawal */
3026fda3f0dSShagun Agrawal t->entry[0].state = MPS_ENTRY_USED;
3036fda3f0dSShagun Agrawal t->free_idx = 1;
3046fda3f0dSShagun Agrawal
3056fda3f0dSShagun Agrawal return t;
3066fda3f0dSShagun Agrawal }
3076fda3f0dSShagun Agrawal
t4_cleanup_mpstcam(struct adapter * adap)3086fda3f0dSShagun Agrawal void t4_cleanup_mpstcam(struct adapter *adap)
3096fda3f0dSShagun Agrawal {
31027e5d900SRahul Lakkireddy if (adap->mpstcam)
3116fda3f0dSShagun Agrawal t4_os_free(adap->mpstcam);
3126fda3f0dSShagun Agrawal }
313