1  // SPDX-License-Identifier: GPL-2.0
2  /* Copyright (c) 2019 Chelsio Communications, Inc. All rights reserved. */
3  
4  #include "cxgb4.h"
5  
cxgb4_mps_ref_dec_by_mac(struct adapter * adap,const u8 * addr,const u8 * mask)6  static int cxgb4_mps_ref_dec_by_mac(struct adapter *adap,
7  				    const u8 *addr, const u8 *mask)
8  {
9  	u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
10  	struct mps_entries_ref *mps_entry, *tmp;
11  	int ret = -EINVAL;
12  
13  	spin_lock_bh(&adap->mps_ref_lock);
14  	list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
15  		if (ether_addr_equal(mps_entry->addr, addr) &&
16  		    ether_addr_equal(mps_entry->mask, mask ? mask : bitmask)) {
17  			if (!refcount_dec_and_test(&mps_entry->refcnt)) {
18  				spin_unlock_bh(&adap->mps_ref_lock);
19  				return -EBUSY;
20  			}
21  			list_del(&mps_entry->list);
22  			kfree(mps_entry);
23  			ret = 0;
24  			break;
25  		}
26  	}
27  	spin_unlock_bh(&adap->mps_ref_lock);
28  	return ret;
29  }
30  
cxgb4_mps_ref_dec(struct adapter * adap,u16 idx)31  static int cxgb4_mps_ref_dec(struct adapter *adap, u16 idx)
32  {
33  	struct mps_entries_ref *mps_entry, *tmp;
34  	int ret = -EINVAL;
35  
36  	spin_lock(&adap->mps_ref_lock);
37  	list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
38  		if (mps_entry->idx == idx) {
39  			if (!refcount_dec_and_test(&mps_entry->refcnt)) {
40  				spin_unlock(&adap->mps_ref_lock);
41  				return -EBUSY;
42  			}
43  			list_del(&mps_entry->list);
44  			kfree(mps_entry);
45  			ret = 0;
46  			break;
47  		}
48  	}
49  	spin_unlock(&adap->mps_ref_lock);
50  	return ret;
51  }
52  
cxgb4_mps_ref_inc(struct adapter * adap,const u8 * mac_addr,u16 idx,const u8 * mask)53  static int cxgb4_mps_ref_inc(struct adapter *adap, const u8 *mac_addr,
54  			     u16 idx, const u8 *mask)
55  {
56  	u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
57  	struct mps_entries_ref *mps_entry;
58  	int ret = 0;
59  
60  	spin_lock_bh(&adap->mps_ref_lock);
61  	list_for_each_entry(mps_entry, &adap->mps_ref, list) {
62  		if (mps_entry->idx == idx) {
63  			refcount_inc(&mps_entry->refcnt);
64  			goto unlock;
65  		}
66  	}
67  	mps_entry = kzalloc(sizeof(*mps_entry), GFP_ATOMIC);
68  	if (!mps_entry) {
69  		ret = -ENOMEM;
70  		goto unlock;
71  	}
72  	ether_addr_copy(mps_entry->mask, mask ? mask : bitmask);
73  	ether_addr_copy(mps_entry->addr, mac_addr);
74  	mps_entry->idx = idx;
75  	refcount_set(&mps_entry->refcnt, 1);
76  	list_add_tail(&mps_entry->list, &adap->mps_ref);
77  unlock:
78  	spin_unlock_bh(&adap->mps_ref_lock);
79  	return ret;
80  }
81  
cxgb4_free_mac_filt(struct adapter * adap,unsigned int viid,unsigned int naddr,const u8 ** addr,bool sleep_ok)82  int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid,
83  			unsigned int naddr, const u8 **addr, bool sleep_ok)
84  {
85  	int ret, i;
86  
87  	for (i = 0; i < naddr; i++) {
88  		if (!cxgb4_mps_ref_dec_by_mac(adap, addr[i], NULL)) {
89  			ret = t4_free_mac_filt(adap, adap->mbox, viid,
90  					       1, &addr[i], sleep_ok);
91  			if (ret < 0)
92  				return ret;
93  		}
94  	}
95  
96  	/* return number of filters freed */
97  	return naddr;
98  }
99  
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)100  int cxgb4_alloc_mac_filt(struct adapter *adap, unsigned int viid,
101  			 bool free, unsigned int naddr, const u8 **addr,
102  			 u16 *idx, u64 *hash, bool sleep_ok)
103  {
104  	int ret, i;
105  
106  	ret = t4_alloc_mac_filt(adap, adap->mbox, viid, free,
107  				naddr, addr, idx, hash, sleep_ok);
108  	if (ret < 0)
109  		return ret;
110  
111  	for (i = 0; i < naddr; i++) {
112  		if (idx[i] != 0xffff) {
113  			if (cxgb4_mps_ref_inc(adap, addr[i], idx[i], NULL)) {
114  				ret = -ENOMEM;
115  				goto error;
116  			}
117  		}
118  	}
119  
120  	goto out;
121  error:
122  	cxgb4_free_mac_filt(adap, viid, naddr, addr, sleep_ok);
123  
124  out:
125  	/* Returns a negative error number or the number of filters allocated */
126  	return ret;
127  }
128  
cxgb4_update_mac_filt(struct port_info * pi,unsigned int viid,int * tcam_idx,const u8 * addr,bool persistent,u8 * smt_idx)129  int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid,
130  			  int *tcam_idx, const u8 *addr,
131  			  bool persistent, u8 *smt_idx)
132  {
133  	int ret;
134  
135  	ret = cxgb4_change_mac(pi, viid, tcam_idx,
136  			       addr, persistent, smt_idx);
137  	if (ret < 0)
138  		return ret;
139  
140  	cxgb4_mps_ref_inc(pi->adapter, addr, *tcam_idx, NULL);
141  	return ret;
142  }
143  
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)144  int cxgb4_free_raw_mac_filt(struct adapter *adap,
145  			    unsigned int viid,
146  			    const u8 *addr,
147  			    const u8 *mask,
148  			    unsigned int idx,
149  			    u8 lookup_type,
150  			    u8 port_id,
151  			    bool sleep_ok)
152  {
153  	int ret = 0;
154  
155  	if (!cxgb4_mps_ref_dec(adap, idx))
156  		ret = t4_free_raw_mac_filt(adap, viid, addr,
157  					   mask, idx, lookup_type,
158  					   port_id, sleep_ok);
159  
160  	return ret;
161  }
162  
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)163  int cxgb4_alloc_raw_mac_filt(struct adapter *adap,
164  			     unsigned int viid,
165  			     const u8 *addr,
166  			     const u8 *mask,
167  			     unsigned int idx,
168  			     u8 lookup_type,
169  			     u8 port_id,
170  			     bool sleep_ok)
171  {
172  	int ret;
173  
174  	ret = t4_alloc_raw_mac_filt(adap, viid, addr,
175  				    mask, idx, lookup_type,
176  				    port_id, sleep_ok);
177  	if (ret < 0)
178  		return ret;
179  
180  	if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
181  		ret = -ENOMEM;
182  		t4_free_raw_mac_filt(adap, viid, addr,
183  				     mask, idx, lookup_type,
184  				     port_id, sleep_ok);
185  	}
186  
187  	return ret;
188  }
189  
cxgb4_free_encap_mac_filt(struct adapter * adap,unsigned int viid,int idx,bool sleep_ok)190  int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
191  			      int idx, bool sleep_ok)
192  {
193  	int ret = 0;
194  
195  	if (!cxgb4_mps_ref_dec(adap, idx))
196  		ret = t4_free_encap_mac_filt(adap, viid, idx, sleep_ok);
197  
198  	return ret;
199  }
200  
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)201  int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid,
202  			       const u8 *addr, const u8 *mask,
203  			       unsigned int vni, unsigned int vni_mask,
204  			       u8 dip_hit, u8 lookup_type, bool sleep_ok)
205  {
206  	int ret;
207  
208  	ret = t4_alloc_encap_mac_filt(adap, viid, addr, mask, vni, vni_mask,
209  				      dip_hit, lookup_type, sleep_ok);
210  	if (ret < 0)
211  		return ret;
212  
213  	if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
214  		ret = -ENOMEM;
215  		t4_free_encap_mac_filt(adap, viid, ret, sleep_ok);
216  	}
217  	return ret;
218  }
219  
cxgb4_init_mps_ref_entries(struct adapter * adap)220  int cxgb4_init_mps_ref_entries(struct adapter *adap)
221  {
222  	spin_lock_init(&adap->mps_ref_lock);
223  	INIT_LIST_HEAD(&adap->mps_ref);
224  
225  	return 0;
226  }
227  
cxgb4_free_mps_ref_entries(struct adapter * adap)228  void cxgb4_free_mps_ref_entries(struct adapter *adap)
229  {
230  	struct mps_entries_ref *mps_entry, *tmp;
231  
232  	if (list_empty(&adap->mps_ref))
233  		return;
234  
235  	spin_lock(&adap->mps_ref_lock);
236  	list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
237  		list_del(&mps_entry->list);
238  		kfree(mps_entry);
239  	}
240  	spin_unlock(&adap->mps_ref_lock);
241  }
242