xref: /openbmc/linux/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
128b38705SRaju Rangoju // SPDX-License-Identifier: GPL-2.0
228b38705SRaju Rangoju /* Copyright (c) 2019 Chelsio Communications, Inc. All rights reserved. */
328b38705SRaju Rangoju 
428b38705SRaju Rangoju #include "cxgb4.h"
528b38705SRaju Rangoju 
cxgb4_mps_ref_dec_by_mac(struct adapter * adap,const u8 * addr,const u8 * mask)6f9f329adSRaju Rangoju static int cxgb4_mps_ref_dec_by_mac(struct adapter *adap,
7f9f329adSRaju Rangoju 				    const u8 *addr, const u8 *mask)
8f9f329adSRaju Rangoju {
9f9f329adSRaju Rangoju 	u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
10f9f329adSRaju Rangoju 	struct mps_entries_ref *mps_entry, *tmp;
11f9f329adSRaju Rangoju 	int ret = -EINVAL;
12f9f329adSRaju Rangoju 
13f9f329adSRaju Rangoju 	spin_lock_bh(&adap->mps_ref_lock);
14f9f329adSRaju Rangoju 	list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
15f9f329adSRaju Rangoju 		if (ether_addr_equal(mps_entry->addr, addr) &&
16f9f329adSRaju Rangoju 		    ether_addr_equal(mps_entry->mask, mask ? mask : bitmask)) {
17f9f329adSRaju Rangoju 			if (!refcount_dec_and_test(&mps_entry->refcnt)) {
18f9f329adSRaju Rangoju 				spin_unlock_bh(&adap->mps_ref_lock);
19f9f329adSRaju Rangoju 				return -EBUSY;
20f9f329adSRaju Rangoju 			}
21f9f329adSRaju Rangoju 			list_del(&mps_entry->list);
22f9f329adSRaju Rangoju 			kfree(mps_entry);
23f9f329adSRaju Rangoju 			ret = 0;
24f9f329adSRaju Rangoju 			break;
25f9f329adSRaju Rangoju 		}
26f9f329adSRaju Rangoju 	}
27f9f329adSRaju Rangoju 	spin_unlock_bh(&adap->mps_ref_lock);
28f9f329adSRaju Rangoju 	return ret;
29f9f329adSRaju Rangoju }
30f9f329adSRaju Rangoju 
cxgb4_mps_ref_dec(struct adapter * adap,u16 idx)3128b38705SRaju Rangoju static int cxgb4_mps_ref_dec(struct adapter *adap, u16 idx)
3228b38705SRaju Rangoju {
3328b38705SRaju Rangoju 	struct mps_entries_ref *mps_entry, *tmp;
3428b38705SRaju Rangoju 	int ret = -EINVAL;
3528b38705SRaju Rangoju 
3628b38705SRaju Rangoju 	spin_lock(&adap->mps_ref_lock);
3728b38705SRaju Rangoju 	list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
3828b38705SRaju Rangoju 		if (mps_entry->idx == idx) {
3928b38705SRaju Rangoju 			if (!refcount_dec_and_test(&mps_entry->refcnt)) {
4028b38705SRaju Rangoju 				spin_unlock(&adap->mps_ref_lock);
4128b38705SRaju Rangoju 				return -EBUSY;
4228b38705SRaju Rangoju 			}
4328b38705SRaju Rangoju 			list_del(&mps_entry->list);
4428b38705SRaju Rangoju 			kfree(mps_entry);
4528b38705SRaju Rangoju 			ret = 0;
4628b38705SRaju Rangoju 			break;
4728b38705SRaju Rangoju 		}
4828b38705SRaju Rangoju 	}
4928b38705SRaju Rangoju 	spin_unlock(&adap->mps_ref_lock);
5028b38705SRaju Rangoju 	return ret;
5128b38705SRaju Rangoju }
5228b38705SRaju Rangoju 
cxgb4_mps_ref_inc(struct adapter * adap,const u8 * mac_addr,u16 idx,const u8 * mask)5328b38705SRaju Rangoju static int cxgb4_mps_ref_inc(struct adapter *adap, const u8 *mac_addr,
5428b38705SRaju Rangoju 			     u16 idx, const u8 *mask)
5528b38705SRaju Rangoju {
5628b38705SRaju Rangoju 	u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5728b38705SRaju Rangoju 	struct mps_entries_ref *mps_entry;
5828b38705SRaju Rangoju 	int ret = 0;
5928b38705SRaju Rangoju 
6028b38705SRaju Rangoju 	spin_lock_bh(&adap->mps_ref_lock);
6128b38705SRaju Rangoju 	list_for_each_entry(mps_entry, &adap->mps_ref, list) {
6228b38705SRaju Rangoju 		if (mps_entry->idx == idx) {
6328b38705SRaju Rangoju 			refcount_inc(&mps_entry->refcnt);
6428b38705SRaju Rangoju 			goto unlock;
6528b38705SRaju Rangoju 		}
6628b38705SRaju Rangoju 	}
6728b38705SRaju Rangoju 	mps_entry = kzalloc(sizeof(*mps_entry), GFP_ATOMIC);
6828b38705SRaju Rangoju 	if (!mps_entry) {
6928b38705SRaju Rangoju 		ret = -ENOMEM;
7028b38705SRaju Rangoju 		goto unlock;
7128b38705SRaju Rangoju 	}
7228b38705SRaju Rangoju 	ether_addr_copy(mps_entry->mask, mask ? mask : bitmask);
7328b38705SRaju Rangoju 	ether_addr_copy(mps_entry->addr, mac_addr);
7428b38705SRaju Rangoju 	mps_entry->idx = idx;
7528b38705SRaju Rangoju 	refcount_set(&mps_entry->refcnt, 1);
7628b38705SRaju Rangoju 	list_add_tail(&mps_entry->list, &adap->mps_ref);
7728b38705SRaju Rangoju unlock:
7828b38705SRaju Rangoju 	spin_unlock_bh(&adap->mps_ref_lock);
7928b38705SRaju Rangoju 	return ret;
8028b38705SRaju Rangoju }
8128b38705SRaju Rangoju 
cxgb4_free_mac_filt(struct adapter * adap,unsigned int viid,unsigned int naddr,const u8 ** addr,bool sleep_ok)82f9f329adSRaju Rangoju int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid,
83f9f329adSRaju Rangoju 			unsigned int naddr, const u8 **addr, bool sleep_ok)
84f9f329adSRaju Rangoju {
85f9f329adSRaju Rangoju 	int ret, i;
86f9f329adSRaju Rangoju 
87f9f329adSRaju Rangoju 	for (i = 0; i < naddr; i++) {
88f9f329adSRaju Rangoju 		if (!cxgb4_mps_ref_dec_by_mac(adap, addr[i], NULL)) {
89f9f329adSRaju Rangoju 			ret = t4_free_mac_filt(adap, adap->mbox, viid,
90f9f329adSRaju Rangoju 					       1, &addr[i], sleep_ok);
91f9f329adSRaju Rangoju 			if (ret < 0)
92f9f329adSRaju Rangoju 				return ret;
93f9f329adSRaju Rangoju 		}
94f9f329adSRaju Rangoju 	}
95f9f329adSRaju Rangoju 
96f9f329adSRaju Rangoju 	/* return number of filters freed */
97f9f329adSRaju Rangoju 	return naddr;
98f9f329adSRaju Rangoju }
99f9f329adSRaju Rangoju 
cxgb4_alloc_mac_filt(struct adapter * adap,unsigned int viid,bool free,unsigned int naddr,const u8 ** addr,u16 * idx,u64 * hash,bool sleep_ok)100f9f329adSRaju Rangoju int cxgb4_alloc_mac_filt(struct adapter *adap, unsigned int viid,
101f9f329adSRaju Rangoju 			 bool free, unsigned int naddr, const u8 **addr,
102f9f329adSRaju Rangoju 			 u16 *idx, u64 *hash, bool sleep_ok)
103f9f329adSRaju Rangoju {
104f9f329adSRaju Rangoju 	int ret, i;
105f9f329adSRaju Rangoju 
106f9f329adSRaju Rangoju 	ret = t4_alloc_mac_filt(adap, adap->mbox, viid, free,
107f9f329adSRaju Rangoju 				naddr, addr, idx, hash, sleep_ok);
108f9f329adSRaju Rangoju 	if (ret < 0)
109f9f329adSRaju Rangoju 		return ret;
110f9f329adSRaju Rangoju 
111f9f329adSRaju Rangoju 	for (i = 0; i < naddr; i++) {
112f9f329adSRaju Rangoju 		if (idx[i] != 0xffff) {
113f9f329adSRaju Rangoju 			if (cxgb4_mps_ref_inc(adap, addr[i], idx[i], NULL)) {
114f9f329adSRaju Rangoju 				ret = -ENOMEM;
115f9f329adSRaju Rangoju 				goto error;
116f9f329adSRaju Rangoju 			}
117f9f329adSRaju Rangoju 		}
118f9f329adSRaju Rangoju 	}
119f9f329adSRaju Rangoju 
120f9f329adSRaju Rangoju 	goto out;
121f9f329adSRaju Rangoju error:
122f9f329adSRaju Rangoju 	cxgb4_free_mac_filt(adap, viid, naddr, addr, sleep_ok);
123f9f329adSRaju Rangoju 
124f9f329adSRaju Rangoju out:
125f9f329adSRaju Rangoju 	/* Returns a negative error number or the number of filters allocated */
126f9f329adSRaju Rangoju 	return ret;
127f9f329adSRaju Rangoju }
128f9f329adSRaju Rangoju 
cxgb4_update_mac_filt(struct port_info * pi,unsigned int viid,int * tcam_idx,const u8 * addr,bool persistent,u8 * smt_idx)1292f0b9406SRaju Rangoju int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid,
1302f0b9406SRaju Rangoju 			  int *tcam_idx, const u8 *addr,
1312f0b9406SRaju Rangoju 			  bool persistent, u8 *smt_idx)
1322f0b9406SRaju Rangoju {
1332f0b9406SRaju Rangoju 	int ret;
1342f0b9406SRaju Rangoju 
1352f0b9406SRaju Rangoju 	ret = cxgb4_change_mac(pi, viid, tcam_idx,
1362f0b9406SRaju Rangoju 			       addr, persistent, smt_idx);
1372f0b9406SRaju Rangoju 	if (ret < 0)
1382f0b9406SRaju Rangoju 		return ret;
1392f0b9406SRaju Rangoju 
1402f0b9406SRaju Rangoju 	cxgb4_mps_ref_inc(pi->adapter, addr, *tcam_idx, NULL);
1412f0b9406SRaju Rangoju 	return ret;
1422f0b9406SRaju Rangoju }
1432f0b9406SRaju Rangoju 
cxgb4_free_raw_mac_filt(struct adapter * adap,unsigned int viid,const u8 * addr,const u8 * mask,unsigned int idx,u8 lookup_type,u8 port_id,bool sleep_ok)1445fab5158SRaju Rangoju int cxgb4_free_raw_mac_filt(struct adapter *adap,
1455fab5158SRaju Rangoju 			    unsigned int viid,
1465fab5158SRaju Rangoju 			    const u8 *addr,
1475fab5158SRaju Rangoju 			    const u8 *mask,
1485fab5158SRaju Rangoju 			    unsigned int idx,
1495fab5158SRaju Rangoju 			    u8 lookup_type,
1505fab5158SRaju Rangoju 			    u8 port_id,
1515fab5158SRaju Rangoju 			    bool sleep_ok)
1525fab5158SRaju Rangoju {
1535fab5158SRaju Rangoju 	int ret = 0;
1545fab5158SRaju Rangoju 
1555fab5158SRaju Rangoju 	if (!cxgb4_mps_ref_dec(adap, idx))
1565fab5158SRaju Rangoju 		ret = t4_free_raw_mac_filt(adap, viid, addr,
1575fab5158SRaju Rangoju 					   mask, idx, lookup_type,
1585fab5158SRaju Rangoju 					   port_id, sleep_ok);
1595fab5158SRaju Rangoju 
1605fab5158SRaju Rangoju 	return ret;
1615fab5158SRaju Rangoju }
1625fab5158SRaju Rangoju 
cxgb4_alloc_raw_mac_filt(struct adapter * adap,unsigned int viid,const u8 * addr,const u8 * mask,unsigned int idx,u8 lookup_type,u8 port_id,bool sleep_ok)1635fab5158SRaju Rangoju int cxgb4_alloc_raw_mac_filt(struct adapter *adap,
1645fab5158SRaju Rangoju 			     unsigned int viid,
1655fab5158SRaju Rangoju 			     const u8 *addr,
1665fab5158SRaju Rangoju 			     const u8 *mask,
1675fab5158SRaju Rangoju 			     unsigned int idx,
1685fab5158SRaju Rangoju 			     u8 lookup_type,
1695fab5158SRaju Rangoju 			     u8 port_id,
1705fab5158SRaju Rangoju 			     bool sleep_ok)
1715fab5158SRaju Rangoju {
1725fab5158SRaju Rangoju 	int ret;
1735fab5158SRaju Rangoju 
1745fab5158SRaju Rangoju 	ret = t4_alloc_raw_mac_filt(adap, viid, addr,
1755fab5158SRaju Rangoju 				    mask, idx, lookup_type,
1765fab5158SRaju Rangoju 				    port_id, sleep_ok);
1775fab5158SRaju Rangoju 	if (ret < 0)
1785fab5158SRaju Rangoju 		return ret;
1795fab5158SRaju Rangoju 
1805fab5158SRaju Rangoju 	if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
1815fab5158SRaju Rangoju 		ret = -ENOMEM;
1825fab5158SRaju Rangoju 		t4_free_raw_mac_filt(adap, viid, addr,
1835fab5158SRaju Rangoju 				     mask, idx, lookup_type,
1845fab5158SRaju Rangoju 				     port_id, sleep_ok);
1855fab5158SRaju Rangoju 	}
1865fab5158SRaju Rangoju 
1875fab5158SRaju Rangoju 	return ret;
1885fab5158SRaju Rangoju }
1895fab5158SRaju Rangoju 
cxgb4_free_encap_mac_filt(struct adapter * adap,unsigned int viid,int idx,bool sleep_ok)19028b38705SRaju Rangoju int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
19128b38705SRaju Rangoju 			      int idx, bool sleep_ok)
19228b38705SRaju Rangoju {
19328b38705SRaju Rangoju 	int ret = 0;
19428b38705SRaju Rangoju 
19528b38705SRaju Rangoju 	if (!cxgb4_mps_ref_dec(adap, idx))
19628b38705SRaju Rangoju 		ret = t4_free_encap_mac_filt(adap, viid, idx, sleep_ok);
19728b38705SRaju Rangoju 
19828b38705SRaju Rangoju 	return ret;
19928b38705SRaju Rangoju }
20028b38705SRaju Rangoju 
cxgb4_alloc_encap_mac_filt(struct adapter * adap,unsigned int viid,const u8 * addr,const u8 * mask,unsigned int vni,unsigned int vni_mask,u8 dip_hit,u8 lookup_type,bool sleep_ok)20128b38705SRaju Rangoju int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid,
20228b38705SRaju Rangoju 			       const u8 *addr, const u8 *mask,
20328b38705SRaju Rangoju 			       unsigned int vni, unsigned int vni_mask,
20428b38705SRaju Rangoju 			       u8 dip_hit, u8 lookup_type, bool sleep_ok)
20528b38705SRaju Rangoju {
20628b38705SRaju Rangoju 	int ret;
20728b38705SRaju Rangoju 
20828b38705SRaju Rangoju 	ret = t4_alloc_encap_mac_filt(adap, viid, addr, mask, vni, vni_mask,
20928b38705SRaju Rangoju 				      dip_hit, lookup_type, sleep_ok);
21028b38705SRaju Rangoju 	if (ret < 0)
21128b38705SRaju Rangoju 		return ret;
21228b38705SRaju Rangoju 
21328b38705SRaju Rangoju 	if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
21428b38705SRaju Rangoju 		ret = -ENOMEM;
21528b38705SRaju Rangoju 		t4_free_encap_mac_filt(adap, viid, ret, sleep_ok);
21628b38705SRaju Rangoju 	}
21728b38705SRaju Rangoju 	return ret;
21828b38705SRaju Rangoju }
21928b38705SRaju Rangoju 
cxgb4_init_mps_ref_entries(struct adapter * adap)22028b38705SRaju Rangoju int cxgb4_init_mps_ref_entries(struct adapter *adap)
22128b38705SRaju Rangoju {
22228b38705SRaju Rangoju 	spin_lock_init(&adap->mps_ref_lock);
22328b38705SRaju Rangoju 	INIT_LIST_HEAD(&adap->mps_ref);
22428b38705SRaju Rangoju 
22528b38705SRaju Rangoju 	return 0;
22628b38705SRaju Rangoju }
22728b38705SRaju Rangoju 
cxgb4_free_mps_ref_entries(struct adapter * adap)22828b38705SRaju Rangoju void cxgb4_free_mps_ref_entries(struct adapter *adap)
22928b38705SRaju Rangoju {
23028b38705SRaju Rangoju 	struct mps_entries_ref *mps_entry, *tmp;
23128b38705SRaju Rangoju 
232*f4a26a9bSRaju Rangoju 	if (list_empty(&adap->mps_ref))
23328b38705SRaju Rangoju 		return;
23428b38705SRaju Rangoju 
23528b38705SRaju Rangoju 	spin_lock(&adap->mps_ref_lock);
23628b38705SRaju Rangoju 	list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
23728b38705SRaju Rangoju 		list_del(&mps_entry->list);
23828b38705SRaju Rangoju 		kfree(mps_entry);
23928b38705SRaju Rangoju 	}
24028b38705SRaju Rangoju 	spin_unlock(&adap->mps_ref_lock);
24128b38705SRaju Rangoju }
242