Merge branch 'cxgb4-addr-sync'

Hariprasad Shenai says:

====================
cxgb4: Use __dev_[um]c_[un]sync for MAC address syncing

This patch series adds support to use __dev_uc_sync/__dev_mc_sync to add
MAC address and __dev_uc_unsync/__dev_mc_unsync to delete MAC address.

This patch series has been created against net-next tree and includes
patches on cxgb4 and cxgb4vf driver.

We have included all the maintainers of respective drivers. Kindly review
the change and let us know in case of any review comments.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-02-18 14:16:13 -05:00
commit 37a6351a64
7 changed files with 359 additions and 138 deletions

View File

@ -702,6 +702,11 @@ struct doorbell_stats {
u32 db_full; u32 db_full;
}; };
struct hash_mac_addr {
struct list_head list;
u8 addr[ETH_ALEN];
};
struct adapter { struct adapter {
void __iomem *regs; void __iomem *regs;
void __iomem *bar2; void __iomem *bar2;
@ -740,6 +745,7 @@ struct adapter {
void *uld_handle[CXGB4_ULD_MAX]; void *uld_handle[CXGB4_ULD_MAX];
struct list_head list_node; struct list_head list_node;
struct list_head rcu_node; struct list_head rcu_node;
struct list_head mac_hlist; /* list of MAC addresses in MPS Hash */
struct tid_info tids; struct tid_info tids;
void **tid_release_head; void **tid_release_head;
@ -1207,6 +1213,24 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false); return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false);
} }
/**
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
* Hashes a MAC address according to the hash function used by HW inexact
* (hash) address matching.
*/
static inline int hash_mac_addr(const u8 *addr)
{
u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
a ^= b;
a ^= (a >> 12);
a ^= (a >> 6);
return a & 0x3f;
}
void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
unsigned int data_reg, const u32 *vals, unsigned int data_reg, const u32 *vals,
unsigned int nregs, unsigned int start_idx); unsigned int nregs, unsigned int start_idx);
@ -1389,6 +1413,9 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
unsigned int viid, bool free, unsigned int naddr, unsigned int viid, bool free, unsigned int naddr,
const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok); const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok);
int t4_free_mac_filt(struct adapter *adap, unsigned int mbox,
unsigned int viid, unsigned int naddr,
const u8 **addr, bool sleep_ok);
int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
int idx, const u8 *addr, bool persist, bool add_smt); int idx, const u8 *addr, bool persist, bool add_smt);
int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,

View File

@ -338,56 +338,6 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id)
netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]);
} }
/*
* Configure the exact and hash address filters to handle a port's multicast
* and secondary unicast MAC addresses.
*/
static int set_addr_filters(const struct net_device *dev, bool sleep)
{
u64 mhash = 0;
u64 uhash = 0;
bool free = true;
u16 filt_idx[7];
const u8 *addr[7];
int ret, naddr = 0;
const struct netdev_hw_addr *ha;
int uc_cnt = netdev_uc_count(dev);
int mc_cnt = netdev_mc_count(dev);
const struct port_info *pi = netdev_priv(dev);
unsigned int mb = pi->adapter->pf;
/* first do the secondary unicast addresses */
netdev_for_each_uc_addr(ha, dev) {
addr[naddr++] = ha->addr;
if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
naddr, addr, filt_idx, &uhash, sleep);
if (ret < 0)
return ret;
free = false;
naddr = 0;
}
}
/* next set up the multicast addresses */
netdev_for_each_mc_addr(ha, dev) {
addr[naddr++] = ha->addr;
if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
naddr, addr, filt_idx, &mhash, sleep);
if (ret < 0)
return ret;
free = false;
naddr = 0;
}
}
return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0,
uhash | mhash, sleep);
}
int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */ int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
module_param(dbfifo_int_thresh, int, 0644); module_param(dbfifo_int_thresh, int, 0644);
MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold"); MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
@ -400,22 +350,96 @@ module_param(dbfifo_drain_delay, int, 0644);
MODULE_PARM_DESC(dbfifo_drain_delay, MODULE_PARM_DESC(dbfifo_drain_delay,
"usecs to sleep while draining the dbfifo"); "usecs to sleep while draining the dbfifo");
static inline int cxgb4_set_addr_hash(struct port_info *pi)
{
struct adapter *adap = pi->adapter;
u64 vec = 0;
bool ucast = false;
struct hash_mac_addr *entry;
/* Calculate the hash vector for the updated list and program it */
list_for_each_entry(entry, &adap->mac_hlist, list) {
ucast |= is_unicast_ether_addr(entry->addr);
vec |= (1ULL << hash_mac_addr(entry->addr));
}
return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast,
vec, false);
}
static int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr)
{
struct port_info *pi = netdev_priv(netdev);
struct adapter *adap = pi->adapter;
int ret;
u64 mhash = 0;
u64 uhash = 0;
bool free = false;
bool ucast = is_unicast_ether_addr(mac_addr);
const u8 *maclist[1] = {mac_addr};
struct hash_mac_addr *new_entry;
ret = t4_alloc_mac_filt(adap, adap->mbox, pi->viid, free, 1, maclist,
NULL, ucast ? &uhash : &mhash, false);
if (ret < 0)
goto out;
/* if hash != 0, then add the addr to hash addr list
* so on the end we will calculate the hash for the
* list and program it
*/
if (uhash || mhash) {
new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
if (!new_entry)
return -ENOMEM;
ether_addr_copy(new_entry->addr, mac_addr);
list_add_tail(&new_entry->list, &adap->mac_hlist);
ret = cxgb4_set_addr_hash(pi);
}
out:
return ret < 0 ? ret : 0;
}
static int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
{
struct port_info *pi = netdev_priv(netdev);
struct adapter *adap = pi->adapter;
int ret;
const u8 *maclist[1] = {mac_addr};
struct hash_mac_addr *entry, *tmp;
/* If the MAC address to be removed is in the hash addr
* list, delete it from the list and update hash vector
*/
list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) {
if (ether_addr_equal(entry->addr, mac_addr)) {
list_del(&entry->list);
kfree(entry);
return cxgb4_set_addr_hash(pi);
}
}
ret = t4_free_mac_filt(adap, adap->mbox, pi->viid, 1, maclist, false);
return ret < 0 ? -EINVAL : 0;
}
/* /*
* Set Rx properties of a port, such as promiscruity, address filters, and MTU. * Set Rx properties of a port, such as promiscruity, address filters, and MTU.
* If @mtu is -1 it is left unchanged. * If @mtu is -1 it is left unchanged.
*/ */
static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
{ {
int ret;
struct port_info *pi = netdev_priv(dev); struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
ret = set_addr_filters(dev, sleep_ok); if (!(dev->flags & IFF_PROMISC)) {
if (ret == 0) __dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
ret = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, mtu, if (!(dev->flags & IFF_ALLMULTI))
(dev->flags & IFF_PROMISC) ? 1 : 0, __dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
(dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, }
sleep_ok);
return ret; return t4_set_rxmode(adapter, adapter->mbox, pi->viid, mtu,
(dev->flags & IFF_PROMISC) ? 1 : 0,
(dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
sleep_ok);
} }
/** /**
@ -2677,6 +2701,8 @@ static int cxgb_up(struct adapter *adap)
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
update_clip(adap); update_clip(adap);
#endif #endif
/* Initialize hash mac addr list*/
INIT_LIST_HEAD(&adap->mac_hlist);
out: out:
return err; return err;
irq_err: irq_err:

View File

@ -4432,23 +4432,6 @@ void t4_intr_disable(struct adapter *adapter)
t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0); t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0);
} }
/**
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
* Hashes a MAC address according to the hash function used by HW inexact
* (hash) address matching.
*/
static int hash_mac_addr(const u8 *addr)
{
u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
a ^= b;
a ^= (a >> 12);
a ^= (a >> 6);
return a & 0x3f;
}
/** /**
* t4_config_rss_range - configure a portion of the RSS mapping table * t4_config_rss_range - configure a portion of the RSS mapping table
* @adapter: the adapter * @adapter: the adapter
@ -6737,6 +6720,81 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
return ret; return ret;
} }
/**
* t4_free_mac_filt - frees exact-match filters of given MAC addresses
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @naddr: the number of MAC addresses to allocate filters for (up to 7)
* @addr: the MAC address(es)
* @sleep_ok: call is allowed to sleep
*
* Frees the exact-match filter for each of the supplied addresses
*
* Returns a negative error number or the number of filters freed.
*/
int t4_free_mac_filt(struct adapter *adap, unsigned int mbox,
unsigned int viid, unsigned int naddr,
const u8 **addr, bool sleep_ok)
{
int offset, ret = 0;
struct fw_vi_mac_cmd c;
unsigned int nfilters = 0;
unsigned int max_naddr = is_t4(adap->params.chip) ?
NUM_MPS_CLS_SRAM_L_INSTANCES :
NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
unsigned int rem = naddr;
if (naddr > max_naddr)
return -EINVAL;
for (offset = 0; offset < (int)naddr ; /**/) {
unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact)
? rem
: ARRAY_SIZE(c.u.exact));
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[fw_naddr]), 16);
struct fw_vi_mac_exact *p;
int i;
memset(&c, 0, sizeof(c));
c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F |
FW_CMD_EXEC_V(0) |
FW_VI_MAC_CMD_VIID_V(viid));
c.freemacs_to_len16 =
cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) |
FW_CMD_LEN16_V(len16));
for (i = 0, p = c.u.exact; i < (int)fw_naddr; i++, p++) {
p->valid_to_idx = cpu_to_be16(
FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE));
memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
}
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
if (ret)
break;
for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_G(
be16_to_cpu(p->valid_to_idx));
if (index < max_naddr)
nfilters++;
}
offset += fw_naddr;
rem -= fw_naddr;
}
if (ret == 0)
ret = nfilters;
return ret;
}
/** /**
* t4_change_mac - modifies the exact-match filter for a MAC address * t4_change_mac - modifies the exact-match filter for a MAC address
* @adap: the adapter * @adap: the adapter

View File

@ -348,6 +348,11 @@ struct sge {
#define for_each_ethrxq(sge, iter) \ #define for_each_ethrxq(sge, iter) \
for (iter = 0; iter < (sge)->ethqsets; iter++) for (iter = 0; iter < (sge)->ethqsets; iter++)
struct hash_mac_addr {
struct list_head list;
u8 addr[ETH_ALEN];
};
/* /*
* Per-"adapter" (Virtual Function) information. * Per-"adapter" (Virtual Function) information.
*/ */
@ -381,6 +386,9 @@ struct adapter {
/* various locks */ /* various locks */
spinlock_t stats_lock; spinlock_t stats_lock;
/* list of MAC addresses in MPS Hash */
struct list_head mac_hlist;
}; };
enum { /* adapter flags */ enum { /* adapter flags */

View File

@ -741,6 +741,9 @@ static int adapter_up(struct adapter *adapter)
*/ */
enable_rx(adapter); enable_rx(adapter);
t4vf_sge_start(adapter); t4vf_sge_start(adapter);
/* Initialize hash mac addr list*/
INIT_LIST_HEAD(&adapter->mac_hlist);
return 0; return 0;
} }
@ -905,51 +908,74 @@ static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device
return naddr; return naddr;
} }
/* static inline int cxgb4vf_set_addr_hash(struct port_info *pi)
* Configure the exact and hash address filters to handle a port's multicast
* and secondary unicast MAC addresses.
*/
static int set_addr_filters(const struct net_device *dev, bool sleep)
{ {
struct adapter *adapter = pi->adapter;
u64 vec = 0;
bool ucast = false;
struct hash_mac_addr *entry;
/* Calculate the hash vector for the updated list and program it */
list_for_each_entry(entry, &adapter->mac_hlist, list) {
ucast |= is_unicast_ether_addr(entry->addr);
vec |= (1ULL << hash_mac_addr(entry->addr));
}
return t4vf_set_addr_hash(adapter, pi->viid, ucast, vec, false);
}
static int cxgb4vf_mac_sync(struct net_device *netdev, const u8 *mac_addr)
{
struct port_info *pi = netdev_priv(netdev);
struct adapter *adapter = pi->adapter;
int ret;
u64 mhash = 0; u64 mhash = 0;
u64 uhash = 0; u64 uhash = 0;
bool free = true; bool free = false;
unsigned int offset, naddr; bool ucast = is_unicast_ether_addr(mac_addr);
const u8 *addr[7]; const u8 *maclist[1] = {mac_addr};
struct hash_mac_addr *new_entry;
ret = t4vf_alloc_mac_filt(adapter, pi->viid, free, 1, maclist,
NULL, ucast ? &uhash : &mhash, false);
if (ret < 0)
goto out;
/* if hash != 0, then add the addr to hash addr list
* so on the end we will calculate the hash for the
* list and program it
*/
if (uhash || mhash) {
new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
if (!new_entry)
return -ENOMEM;
ether_addr_copy(new_entry->addr, mac_addr);
list_add_tail(&new_entry->list, &adapter->mac_hlist);
ret = cxgb4vf_set_addr_hash(pi);
}
out:
return ret < 0 ? ret : 0;
}
static int cxgb4vf_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
{
struct port_info *pi = netdev_priv(netdev);
struct adapter *adapter = pi->adapter;
int ret; int ret;
const struct port_info *pi = netdev_priv(dev); const u8 *maclist[1] = {mac_addr};
struct hash_mac_addr *entry, *tmp;
/* first do the secondary unicast addresses */ /* If the MAC address to be removed is in the hash addr
for (offset = 0; ; offset += naddr) { * list, delete it from the list and update hash vector
naddr = collect_netdev_uc_list_addrs(dev, addr, offset, */
ARRAY_SIZE(addr)); list_for_each_entry_safe(entry, tmp, &adapter->mac_hlist, list) {
if (naddr == 0) if (ether_addr_equal(entry->addr, mac_addr)) {
break; list_del(&entry->list);
kfree(entry);
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, return cxgb4vf_set_addr_hash(pi);
naddr, addr, NULL, &uhash, sleep); }
if (ret < 0)
return ret;
free = false;
} }
/* next set up the multicast addresses */ ret = t4vf_free_mac_filt(adapter, pi->viid, 1, maclist, false);
for (offset = 0; ; offset += naddr) { return ret < 0 ? -EINVAL : 0;
naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
ARRAY_SIZE(addr));
if (naddr == 0)
break;
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
naddr, addr, NULL, &mhash, sleep);
if (ret < 0)
return ret;
free = false;
}
return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
uhash | mhash, sleep);
} }
/* /*
@ -958,16 +984,18 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
*/ */
static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
{ {
int ret;
struct port_info *pi = netdev_priv(dev); struct port_info *pi = netdev_priv(dev);
ret = set_addr_filters(dev, sleep_ok); if (!(dev->flags & IFF_PROMISC)) {
if (ret == 0) __dev_uc_sync(dev, cxgb4vf_mac_sync, cxgb4vf_mac_unsync);
ret = t4vf_set_rxmode(pi->adapter, pi->viid, -1, if (!(dev->flags & IFF_ALLMULTI))
(dev->flags & IFF_PROMISC) != 0, __dev_mc_sync(dev, cxgb4vf_mac_sync,
(dev->flags & IFF_ALLMULTI) != 0, cxgb4vf_mac_unsync);
1, -1, sleep_ok); }
return ret; return t4vf_set_rxmode(pi->adapter, pi->viid, -1,
(dev->flags & IFF_PROMISC) != 0,
(dev->flags & IFF_ALLMULTI) != 0,
1, -1, sleep_ok);
} }
/* /*

View File

@ -285,6 +285,24 @@ static inline int is_t4(enum chip_type chip)
return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T4; return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T4;
} }
/**
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
* Hashes a MAC address according to the hash function used by hardware
* inexact (hash) address matching.
*/
static inline int hash_mac_addr(const u8 *addr)
{
u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
a ^= b;
a ^= (a >> 12);
a ^= (a >> 6);
return a & 0x3f;
}
int t4vf_wait_dev_ready(struct adapter *); int t4vf_wait_dev_ready(struct adapter *);
int t4vf_port_init(struct adapter *, int); int t4vf_port_init(struct adapter *, int);
@ -320,6 +338,8 @@ int t4vf_set_rxmode(struct adapter *, unsigned int, int, int, int, int, int,
bool); bool);
int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int, int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int,
const u8 **, u16 *, u64 *, bool); const u8 **, u16 *, u64 *, bool);
int t4vf_free_mac_filt(struct adapter *, unsigned int, unsigned int naddr,
const u8 **, bool);
int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool); int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool);
int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool); int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool);
int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *); int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *);

View File

@ -236,23 +236,6 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/**
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
* Hashes a MAC address according to the hash function used by hardware
* inexact (hash) address matching.
*/
static int hash_mac_addr(const u8 *addr)
{
u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
a ^= b;
a ^= (a >> 12);
a ^= (a >> 6);
return a & 0x3f;
}
#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG) FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG)
@ -1265,6 +1248,77 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
return ret; return ret;
} }
/**
* t4vf_free_mac_filt - frees exact-match filters of given MAC addresses
* @adapter: the adapter
* @viid: the VI id
* @naddr: the number of MAC addresses to allocate filters for (up to 7)
* @addr: the MAC address(es)
* @sleep_ok: call is allowed to sleep
*
* Frees the exact-match filter for each of the supplied addresses
*
* Returns a negative error number or the number of filters freed.
*/
int t4vf_free_mac_filt(struct adapter *adapter, unsigned int viid,
unsigned int naddr, const u8 **addr, bool sleep_ok)
{
int offset, ret = 0;
struct fw_vi_mac_cmd cmd;
unsigned int nfilters = 0;
unsigned int max_naddr = adapter->params.arch.mps_tcam_size;
unsigned int rem = naddr;
if (naddr > max_naddr)
return -EINVAL;
for (offset = 0; offset < (int)naddr ; /**/) {
unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) ?
rem : ARRAY_SIZE(cmd.u.exact));
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[fw_naddr]), 16);
struct fw_vi_mac_exact *p;
int i;
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F |
FW_CMD_EXEC_V(0) |
FW_VI_MAC_CMD_VIID_V(viid));
cmd.freemacs_to_len16 =
cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) |
FW_CMD_LEN16_V(len16));
for (i = 0, p = cmd.u.exact; i < (int)fw_naddr; i++, p++) {
p->valid_to_idx = cpu_to_be16(
FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE));
memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
}
ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &cmd,
sleep_ok);
if (ret)
break;
for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_G(
be16_to_cpu(p->valid_to_idx));
if (index < max_naddr)
nfilters++;
}
offset += fw_naddr;
rem -= fw_naddr;
}
if (ret == 0)
ret = nfilters;
return ret;
}
/** /**
* t4vf_change_mac - modifies the exact-match filter for a MAC address * t4vf_change_mac - modifies the exact-match filter for a MAC address
* @adapter: the adapter * @adapter: the adapter