1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2019 Chelsio Communications, Inc. All rights reserved. */ 3 4 #include "cxgb4.h" 5 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 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 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 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 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 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 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 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 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 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 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 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