mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
5.5 KiB
241 lines
5.5 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* Copyright (c) 2019 Chelsio Communications, Inc. All rights reserved. */ |
|
|
|
#include "cxgb4.h" |
|
|
|
static int cxgb4_mps_ref_dec_by_mac(struct adapter *adap, |
|
const u8 *addr, const u8 *mask) |
|
{ |
|
u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
|
struct mps_entries_ref *mps_entry, *tmp; |
|
int ret = -EINVAL; |
|
|
|
spin_lock_bh(&adap->mps_ref_lock); |
|
list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) { |
|
if (ether_addr_equal(mps_entry->addr, addr) && |
|
ether_addr_equal(mps_entry->mask, mask ? mask : bitmask)) { |
|
if (!refcount_dec_and_test(&mps_entry->refcnt)) { |
|
spin_unlock_bh(&adap->mps_ref_lock); |
|
return -EBUSY; |
|
} |
|
list_del(&mps_entry->list); |
|
kfree(mps_entry); |
|
ret = 0; |
|
break; |
|
} |
|
} |
|
spin_unlock_bh(&adap->mps_ref_lock); |
|
return ret; |
|
} |
|
|
|
static int cxgb4_mps_ref_dec(struct adapter *adap, u16 idx) |
|
{ |
|
struct mps_entries_ref *mps_entry, *tmp; |
|
int ret = -EINVAL; |
|
|
|
spin_lock(&adap->mps_ref_lock); |
|
list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) { |
|
if (mps_entry->idx == idx) { |
|
if (!refcount_dec_and_test(&mps_entry->refcnt)) { |
|
spin_unlock(&adap->mps_ref_lock); |
|
return -EBUSY; |
|
} |
|
list_del(&mps_entry->list); |
|
kfree(mps_entry); |
|
ret = 0; |
|
break; |
|
} |
|
} |
|
spin_unlock(&adap->mps_ref_lock); |
|
return ret; |
|
} |
|
|
|
static int cxgb4_mps_ref_inc(struct adapter *adap, const u8 *mac_addr, |
|
u16 idx, const u8 *mask) |
|
{ |
|
u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
|
struct mps_entries_ref *mps_entry; |
|
int ret = 0; |
|
|
|
spin_lock_bh(&adap->mps_ref_lock); |
|
list_for_each_entry(mps_entry, &adap->mps_ref, list) { |
|
if (mps_entry->idx == idx) { |
|
refcount_inc(&mps_entry->refcnt); |
|
goto unlock; |
|
} |
|
} |
|
mps_entry = kzalloc(sizeof(*mps_entry), GFP_ATOMIC); |
|
if (!mps_entry) { |
|
ret = -ENOMEM; |
|
goto unlock; |
|
} |
|
ether_addr_copy(mps_entry->mask, mask ? mask : bitmask); |
|
ether_addr_copy(mps_entry->addr, mac_addr); |
|
mps_entry->idx = idx; |
|
refcount_set(&mps_entry->refcnt, 1); |
|
list_add_tail(&mps_entry->list, &adap->mps_ref); |
|
unlock: |
|
spin_unlock_bh(&adap->mps_ref_lock); |
|
return ret; |
|
} |
|
|
|
int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid, |
|
unsigned int naddr, const u8 **addr, bool sleep_ok) |
|
{ |
|
int ret, i; |
|
|
|
for (i = 0; i < naddr; i++) { |
|
if (!cxgb4_mps_ref_dec_by_mac(adap, addr[i], NULL)) { |
|
ret = t4_free_mac_filt(adap, adap->mbox, viid, |
|
1, &addr[i], sleep_ok); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} |
|
|
|
/* return number of filters freed */ |
|
return naddr; |
|
} |
|
|
|
int 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) |
|
{ |
|
int ret, i; |
|
|
|
ret = t4_alloc_mac_filt(adap, adap->mbox, viid, free, |
|
naddr, addr, idx, hash, sleep_ok); |
|
if (ret < 0) |
|
return ret; |
|
|
|
for (i = 0; i < naddr; i++) { |
|
if (idx[i] != 0xffff) { |
|
if (cxgb4_mps_ref_inc(adap, addr[i], idx[i], NULL)) { |
|
ret = -ENOMEM; |
|
goto error; |
|
} |
|
} |
|
} |
|
|
|
goto out; |
|
error: |
|
cxgb4_free_mac_filt(adap, viid, naddr, addr, sleep_ok); |
|
|
|
out: |
|
/* Returns a negative error number or the number of filters allocated */ |
|
return ret; |
|
} |
|
|
|
int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid, |
|
int *tcam_idx, const u8 *addr, |
|
bool persistent, u8 *smt_idx) |
|
{ |
|
int ret; |
|
|
|
ret = cxgb4_change_mac(pi, viid, tcam_idx, |
|
addr, persistent, smt_idx); |
|
if (ret < 0) |
|
return ret; |
|
|
|
cxgb4_mps_ref_inc(pi->adapter, addr, *tcam_idx, NULL); |
|
return ret; |
|
} |
|
|
|
int 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) |
|
{ |
|
int ret = 0; |
|
|
|
if (!cxgb4_mps_ref_dec(adap, idx)) |
|
ret = t4_free_raw_mac_filt(adap, viid, addr, |
|
mask, idx, lookup_type, |
|
port_id, sleep_ok); |
|
|
|
return ret; |
|
} |
|
|
|
int 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) |
|
{ |
|
int ret; |
|
|
|
ret = t4_alloc_raw_mac_filt(adap, viid, addr, |
|
mask, idx, lookup_type, |
|
port_id, sleep_ok); |
|
if (ret < 0) |
|
return ret; |
|
|
|
if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) { |
|
ret = -ENOMEM; |
|
t4_free_raw_mac_filt(adap, viid, addr, |
|
mask, idx, lookup_type, |
|
port_id, sleep_ok); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid, |
|
int idx, bool sleep_ok) |
|
{ |
|
int ret = 0; |
|
|
|
if (!cxgb4_mps_ref_dec(adap, idx)) |
|
ret = t4_free_encap_mac_filt(adap, viid, idx, sleep_ok); |
|
|
|
return ret; |
|
} |
|
|
|
int 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) |
|
{ |
|
int ret; |
|
|
|
ret = t4_alloc_encap_mac_filt(adap, viid, addr, mask, vni, vni_mask, |
|
dip_hit, lookup_type, sleep_ok); |
|
if (ret < 0) |
|
return ret; |
|
|
|
if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) { |
|
ret = -ENOMEM; |
|
t4_free_encap_mac_filt(adap, viid, ret, sleep_ok); |
|
} |
|
return ret; |
|
} |
|
|
|
int cxgb4_init_mps_ref_entries(struct adapter *adap) |
|
{ |
|
spin_lock_init(&adap->mps_ref_lock); |
|
INIT_LIST_HEAD(&adap->mps_ref); |
|
|
|
return 0; |
|
} |
|
|
|
void cxgb4_free_mps_ref_entries(struct adapter *adap) |
|
{ |
|
struct mps_entries_ref *mps_entry, *tmp; |
|
|
|
if (list_empty(&adap->mps_ref)) |
|
return; |
|
|
|
spin_lock(&adap->mps_ref_lock); |
|
list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) { |
|
list_del(&mps_entry->list); |
|
kfree(mps_entry); |
|
} |
|
spin_unlock(&adap->mps_ref_lock); |
|
}
|
|
|