mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 17:24:17 +08:00
bna: RX Filter Enhancements
Change Details: - Added bna_rx_ucast_listset() for synchronous ucast listadd operation. - Clear mac->handle before adding it to free_q. - bnad_set_rx_mode() rewritten. bnad_set_rx_mode() adds the MACs in uc_list to UCAM. If it exceeds the max supported, DEFAULT mode is turned on. If MCAM limit is exceeded, ALLMULTI mode is turned on. - Clear CF flags, check for the new mode and reprogram the Rx approach. - Added bnad_set_rx_ucast_fltr() and bnad_set_rx_mcast_fltr(). - Check for IFF_PROMISC to set the correct mode. Signed-off-by: Rasesh Mody <rmody@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
20b298f531
commit
fe1624cfb1
@ -497,11 +497,17 @@ enum bna_cb_status
|
||||
bna_rx_ucast_del(struct bna_rx *rx, u8 *ucmac,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *));
|
||||
enum bna_cb_status
|
||||
bna_rx_ucast_listset(struct bna_rx *rx, int count, u8 *uclist,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *));
|
||||
enum bna_cb_status
|
||||
bna_rx_mcast_add(struct bna_rx *rx, u8 *mcmac,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *));
|
||||
enum bna_cb_status
|
||||
bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mcmac,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *));
|
||||
void
|
||||
bna_rx_mcast_delall(struct bna_rx *rx,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *));
|
||||
enum bna_cb_status
|
||||
bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode rxmode,
|
||||
enum bna_rxmode bitmask,
|
||||
@ -509,6 +515,8 @@ bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode rxmode,
|
||||
void bna_rx_vlan_add(struct bna_rx *rx, int vlan_id);
|
||||
void bna_rx_vlan_del(struct bna_rx *rx, int vlan_id);
|
||||
void bna_rx_vlanfilter_enable(struct bna_rx *rx);
|
||||
void bna_rx_vlan_strip_enable(struct bna_rx *rx);
|
||||
void bna_rx_vlan_strip_disable(struct bna_rx *rx);
|
||||
/* ENET */
|
||||
|
||||
/* API for RX */
|
||||
|
@ -1825,11 +1825,16 @@ static void
|
||||
bna_ucam_mod_uninit(struct bna_ucam_mod *ucam_mod)
|
||||
{
|
||||
struct list_head *qe;
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
list_for_each(qe, &ucam_mod->free_q)
|
||||
i++;
|
||||
|
||||
i = 0;
|
||||
list_for_each(qe, &ucam_mod->del_q)
|
||||
i++;
|
||||
|
||||
ucam_mod->bna = NULL;
|
||||
}
|
||||
|
||||
@ -1877,6 +1882,9 @@ bna_mcam_mod_uninit(struct bna_mcam_mod *mcam_mod)
|
||||
i = 0;
|
||||
list_for_each(qe, &mcam_mod->free_q) i++;
|
||||
|
||||
i = 0;
|
||||
list_for_each(qe, &mcam_mod->del_q) i++;
|
||||
|
||||
i = 0;
|
||||
list_for_each(qe, &mcam_mod->free_handle_q) i++;
|
||||
|
||||
|
@ -915,6 +915,75 @@ bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
|
||||
return BNA_CB_SUCCESS;
|
||||
}
|
||||
|
||||
enum bna_cb_status
|
||||
bna_rx_ucast_listset(struct bna_rx *rx, int count, u8 *uclist,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *))
|
||||
{
|
||||
struct bna_ucam_mod *ucam_mod = &rx->bna->ucam_mod;
|
||||
struct bna_rxf *rxf = &rx->rxf;
|
||||
struct list_head list_head;
|
||||
struct list_head *qe;
|
||||
u8 *mcaddr;
|
||||
struct bna_mac *mac, *del_mac;
|
||||
int i;
|
||||
|
||||
/* Purge the pending_add_q */
|
||||
while (!list_empty(&rxf->ucast_pending_add_q)) {
|
||||
bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
|
||||
bfa_q_qe_init(qe);
|
||||
mac = (struct bna_mac *)qe;
|
||||
bna_cam_mod_mac_put(&ucam_mod->free_q, mac);
|
||||
}
|
||||
|
||||
/* Schedule active_q entries for deletion */
|
||||
while (!list_empty(&rxf->ucast_active_q)) {
|
||||
bfa_q_deq(&rxf->ucast_active_q, &qe);
|
||||
mac = (struct bna_mac *)qe;
|
||||
bfa_q_qe_init(&mac->qe);
|
||||
|
||||
del_mac = bna_cam_mod_mac_get(&ucam_mod->del_q);
|
||||
memcpy(del_mac, mac, sizeof(*del_mac));
|
||||
list_add_tail(&del_mac->qe, &rxf->ucast_pending_del_q);
|
||||
bna_cam_mod_mac_put(&ucam_mod->free_q, mac);
|
||||
}
|
||||
|
||||
/* Allocate nodes */
|
||||
INIT_LIST_HEAD(&list_head);
|
||||
for (i = 0, mcaddr = uclist; i < count; i++) {
|
||||
mac = bna_cam_mod_mac_get(&ucam_mod->free_q);
|
||||
if (mac == NULL)
|
||||
goto err_return;
|
||||
bfa_q_qe_init(&mac->qe);
|
||||
memcpy(mac->addr, mcaddr, ETH_ALEN);
|
||||
list_add_tail(&mac->qe, &list_head);
|
||||
mcaddr += ETH_ALEN;
|
||||
}
|
||||
|
||||
/* Add the new entries */
|
||||
while (!list_empty(&list_head)) {
|
||||
bfa_q_deq(&list_head, &qe);
|
||||
mac = (struct bna_mac *)qe;
|
||||
bfa_q_qe_init(&mac->qe);
|
||||
list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
|
||||
}
|
||||
|
||||
rxf->cam_fltr_cbfn = cbfn;
|
||||
rxf->cam_fltr_cbarg = rx->bna->bnad;
|
||||
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
|
||||
|
||||
return BNA_CB_SUCCESS;
|
||||
|
||||
err_return:
|
||||
while (!list_empty(&list_head)) {
|
||||
bfa_q_deq(&list_head, &qe);
|
||||
mac = (struct bna_mac *)qe;
|
||||
bfa_q_qe_init(&mac->qe);
|
||||
bna_cam_mod_mac_put(&ucam_mod->free_q, mac);
|
||||
}
|
||||
|
||||
return BNA_CB_UCAST_CAM_FULL;
|
||||
}
|
||||
|
||||
enum bna_cb_status
|
||||
bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *))
|
||||
@ -943,7 +1012,7 @@ bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
|
||||
|
||||
del_mac = bna_cam_mod_mac_get(&mcam_mod->del_q);
|
||||
|
||||
memcpy(del_mac, mac, sizeof(*mac));
|
||||
memcpy(del_mac, mac, sizeof(*del_mac));
|
||||
list_add_tail(&del_mac->qe, &rxf->mcast_pending_del_q);
|
||||
mac->handle = NULL;
|
||||
bna_cam_mod_mac_put(&mcam_mod->free_q, mac);
|
||||
@ -987,6 +1056,49 @@ err_return:
|
||||
return BNA_CB_MCAST_LIST_FULL;
|
||||
}
|
||||
|
||||
void
|
||||
bna_rx_mcast_delall(struct bna_rx *rx,
|
||||
void (*cbfn)(struct bnad *, struct bna_rx *))
|
||||
{
|
||||
struct bna_rxf *rxf = &rx->rxf;
|
||||
struct list_head *qe;
|
||||
struct bna_mac *mac, *del_mac;
|
||||
int need_hw_config = 0;
|
||||
|
||||
/* Purge all entries from pending_add_q */
|
||||
while (!list_empty(&rxf->mcast_pending_add_q)) {
|
||||
bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
|
||||
mac = (struct bna_mac *)qe;
|
||||
bfa_q_qe_init(&mac->qe);
|
||||
bna_cam_mod_mac_put(bna_mcam_mod_free_q(rxf->rx->bna), mac);
|
||||
}
|
||||
|
||||
/* Schedule all entries in active_q for deletion */
|
||||
while (!list_empty(&rxf->mcast_active_q)) {
|
||||
bfa_q_deq(&rxf->mcast_active_q, &qe);
|
||||
mac = (struct bna_mac *)qe;
|
||||
bfa_q_qe_init(&mac->qe);
|
||||
|
||||
del_mac = bna_cam_mod_mac_get(bna_mcam_mod_del_q(rxf->rx->bna));
|
||||
|
||||
memcpy(del_mac, mac, sizeof(*del_mac));
|
||||
list_add_tail(&del_mac->qe, &rxf->mcast_pending_del_q);
|
||||
mac->handle = NULL;
|
||||
bna_cam_mod_mac_put(bna_mcam_mod_free_q(rxf->rx->bna), mac);
|
||||
need_hw_config = 1;
|
||||
}
|
||||
|
||||
if (need_hw_config) {
|
||||
rxf->cam_fltr_cbfn = cbfn;
|
||||
rxf->cam_fltr_cbarg = rx->bna->bnad;
|
||||
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cbfn)
|
||||
(*cbfn)(rx->bna->bnad, rx);
|
||||
}
|
||||
|
||||
void
|
||||
bna_rx_vlan_add(struct bna_rx *rx, int vlan_id)
|
||||
{
|
||||
@ -2679,6 +2791,30 @@ bna_rx_cleanup_complete(struct bna_rx *rx)
|
||||
bfa_fsm_send_event(rx, RX_E_CLEANUP_DONE);
|
||||
}
|
||||
|
||||
void
|
||||
bna_rx_vlan_strip_enable(struct bna_rx *rx)
|
||||
{
|
||||
struct bna_rxf *rxf = &rx->rxf;
|
||||
|
||||
if (rxf->vlan_strip_status == BNA_STATUS_T_DISABLED) {
|
||||
rxf->vlan_strip_status = BNA_STATUS_T_ENABLED;
|
||||
rxf->vlan_strip_pending = true;
|
||||
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bna_rx_vlan_strip_disable(struct bna_rx *rx)
|
||||
{
|
||||
struct bna_rxf *rxf = &rx->rxf;
|
||||
|
||||
if (rxf->vlan_strip_status != BNA_STATUS_T_DISABLED) {
|
||||
rxf->vlan_strip_status = BNA_STATUS_T_DISABLED;
|
||||
rxf->vlan_strip_pending = true;
|
||||
bfa_fsm_send_event(rxf, RXF_E_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
enum bna_cb_status
|
||||
bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
|
||||
enum bna_rxmode bitmask,
|
||||
|
@ -2624,9 +2624,6 @@ bnad_stop(struct net_device *netdev)
|
||||
bnad_destroy_tx(bnad, 0);
|
||||
bnad_destroy_rx(bnad, 0);
|
||||
|
||||
/* These config flags are cleared in the hardware */
|
||||
bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI | BNAD_CF_PROMISC);
|
||||
|
||||
/* Synchronize mailbox IRQ */
|
||||
bnad_mbox_irq_sync(bnad);
|
||||
|
||||
@ -2939,73 +2936,133 @@ bnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
|
||||
return stats;
|
||||
}
|
||||
|
||||
static void
|
||||
bnad_set_rx_ucast_fltr(struct bnad *bnad)
|
||||
{
|
||||
struct net_device *netdev = bnad->netdev;
|
||||
int uc_count = netdev_uc_count(netdev);
|
||||
enum bna_cb_status ret;
|
||||
u8 *mac_list;
|
||||
struct netdev_hw_addr *ha;
|
||||
int entry;
|
||||
|
||||
if (netdev_uc_empty(bnad->netdev)) {
|
||||
bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uc_count > bna_attr(&bnad->bna)->num_ucmac)
|
||||
goto mode_default;
|
||||
|
||||
mac_list = kzalloc(uc_count * ETH_ALEN, GFP_ATOMIC);
|
||||
if (mac_list == NULL)
|
||||
goto mode_default;
|
||||
|
||||
entry = 0;
|
||||
netdev_for_each_uc_addr(ha, netdev) {
|
||||
memcpy(&mac_list[entry * ETH_ALEN],
|
||||
&ha->addr[0], ETH_ALEN);
|
||||
entry++;
|
||||
}
|
||||
|
||||
ret = bna_rx_ucast_listset(bnad->rx_info[0].rx, entry,
|
||||
mac_list, NULL);
|
||||
kfree(mac_list);
|
||||
|
||||
if (ret != BNA_CB_SUCCESS)
|
||||
goto mode_default;
|
||||
|
||||
return;
|
||||
|
||||
/* ucast packets not in UCAM are routed to default function */
|
||||
mode_default:
|
||||
bnad->cfg_flags |= BNAD_CF_DEFAULT;
|
||||
bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
bnad_set_rx_mcast_fltr(struct bnad *bnad)
|
||||
{
|
||||
struct net_device *netdev = bnad->netdev;
|
||||
int mc_count = netdev_mc_count(netdev);
|
||||
enum bna_cb_status ret;
|
||||
u8 *mac_list;
|
||||
|
||||
if (netdev->flags & IFF_ALLMULTI)
|
||||
goto mode_allmulti;
|
||||
|
||||
if (netdev_mc_empty(netdev))
|
||||
return;
|
||||
|
||||
if (mc_count > bna_attr(&bnad->bna)->num_mcmac)
|
||||
goto mode_allmulti;
|
||||
|
||||
mac_list = kzalloc((mc_count + 1) * ETH_ALEN, GFP_ATOMIC);
|
||||
|
||||
if (mac_list == NULL)
|
||||
goto mode_allmulti;
|
||||
|
||||
memcpy(&mac_list[0], &bnad_bcast_addr[0], ETH_ALEN);
|
||||
|
||||
/* copy rest of the MCAST addresses */
|
||||
bnad_netdev_mc_list_get(netdev, mac_list);
|
||||
ret = bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1,
|
||||
mac_list, NULL);
|
||||
kfree(mac_list);
|
||||
|
||||
if (ret != BNA_CB_SUCCESS)
|
||||
goto mode_allmulti;
|
||||
|
||||
return;
|
||||
|
||||
mode_allmulti:
|
||||
bnad->cfg_flags |= BNAD_CF_ALLMULTI;
|
||||
bna_rx_mcast_delall(bnad->rx_info[0].rx, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
bnad_set_rx_mode(struct net_device *netdev)
|
||||
{
|
||||
struct bnad *bnad = netdev_priv(netdev);
|
||||
u32 new_mask, valid_mask;
|
||||
enum bna_rxmode new_mode, mode_mask;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bnad->bna_lock, flags);
|
||||
|
||||
new_mask = valid_mask = 0;
|
||||
if (bnad->rx_info[0].rx == NULL) {
|
||||
spin_unlock_irqrestore(&bnad->bna_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear bnad flags to update it with new settings */
|
||||
bnad->cfg_flags &= ~(BNAD_CF_PROMISC | BNAD_CF_DEFAULT |
|
||||
BNAD_CF_ALLMULTI);
|
||||
|
||||
new_mode = 0;
|
||||
if (netdev->flags & IFF_PROMISC) {
|
||||
if (!(bnad->cfg_flags & BNAD_CF_PROMISC)) {
|
||||
new_mask = BNAD_RXMODE_PROMISC_DEFAULT;
|
||||
valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
|
||||
bnad->cfg_flags |= BNAD_CF_PROMISC;
|
||||
}
|
||||
new_mode |= BNAD_RXMODE_PROMISC_DEFAULT;
|
||||
bnad->cfg_flags |= BNAD_CF_PROMISC;
|
||||
} else {
|
||||
if (bnad->cfg_flags & BNAD_CF_PROMISC) {
|
||||
new_mask = ~BNAD_RXMODE_PROMISC_DEFAULT;
|
||||
valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
|
||||
bnad->cfg_flags &= ~BNAD_CF_PROMISC;
|
||||
}
|
||||
bnad_set_rx_mcast_fltr(bnad);
|
||||
|
||||
if (bnad->cfg_flags & BNAD_CF_ALLMULTI)
|
||||
new_mode |= BNA_RXMODE_ALLMULTI;
|
||||
|
||||
bnad_set_rx_ucast_fltr(bnad);
|
||||
|
||||
if (bnad->cfg_flags & BNAD_CF_DEFAULT)
|
||||
new_mode |= BNA_RXMODE_DEFAULT;
|
||||
}
|
||||
|
||||
if (netdev->flags & IFF_ALLMULTI) {
|
||||
if (!(bnad->cfg_flags & BNAD_CF_ALLMULTI)) {
|
||||
new_mask |= BNA_RXMODE_ALLMULTI;
|
||||
valid_mask |= BNA_RXMODE_ALLMULTI;
|
||||
bnad->cfg_flags |= BNAD_CF_ALLMULTI;
|
||||
}
|
||||
} else {
|
||||
if (bnad->cfg_flags & BNAD_CF_ALLMULTI) {
|
||||
new_mask &= ~BNA_RXMODE_ALLMULTI;
|
||||
valid_mask |= BNA_RXMODE_ALLMULTI;
|
||||
bnad->cfg_flags &= ~BNAD_CF_ALLMULTI;
|
||||
}
|
||||
}
|
||||
mode_mask = BNA_RXMODE_PROMISC | BNA_RXMODE_DEFAULT |
|
||||
BNA_RXMODE_ALLMULTI;
|
||||
bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
|
||||
|
||||
if (bnad->rx_info[0].rx == NULL)
|
||||
goto unlock;
|
||||
if (bnad->cfg_flags & BNAD_CF_PROMISC)
|
||||
bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
|
||||
else
|
||||
bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
|
||||
|
||||
bna_rx_mode_set(bnad->rx_info[0].rx, new_mask, valid_mask, NULL);
|
||||
|
||||
if (!netdev_mc_empty(netdev)) {
|
||||
u8 *mcaddr_list;
|
||||
int mc_count = netdev_mc_count(netdev);
|
||||
|
||||
/* Index 0 holds the broadcast address */
|
||||
mcaddr_list =
|
||||
kzalloc((mc_count + 1) * ETH_ALEN,
|
||||
GFP_ATOMIC);
|
||||
if (!mcaddr_list)
|
||||
goto unlock;
|
||||
|
||||
memcpy(&mcaddr_list[0], &bnad_bcast_addr[0], ETH_ALEN);
|
||||
|
||||
/* Copy rest of the MC addresses */
|
||||
bnad_netdev_mc_list_get(netdev, mcaddr_list);
|
||||
|
||||
bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1,
|
||||
mcaddr_list, NULL);
|
||||
|
||||
/* Should we enable BNAD_CF_ALLMULTI for err != 0 ? */
|
||||
kfree(mcaddr_list);
|
||||
}
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&bnad->bna_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -260,7 +260,8 @@ struct bnad_rx_unmap_q {
|
||||
#define BNAD_CF_DIM_ENABLED 0x01 /* DIM */
|
||||
#define BNAD_CF_PROMISC 0x02
|
||||
#define BNAD_CF_ALLMULTI 0x04
|
||||
#define BNAD_CF_MSIX 0x08 /* If in MSIx mode */
|
||||
#define BNAD_CF_DEFAULT 0x08
|
||||
#define BNAD_CF_MSIX 0x10 /* If in MSIx mode */
|
||||
|
||||
/* Defines for run_flags bit-mask */
|
||||
/* Set, tested & cleared using xxx_bit() functions */
|
||||
|
Loading…
Reference in New Issue
Block a user