Skip to content

Commit

Permalink
qlcnic: Secondary unicast MAC address support.
Browse files Browse the repository at this point in the history
Add support for configuring secondary unicast address which
will use existing HW filters to store all the unicast MAC
addresses and prevent device going into promiscuous mode.

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jitendra Kalsaria authored and David S. Miller committed Jun 24, 2013
1 parent b6b4316 commit 52e493d
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 23 deletions.
8 changes: 8 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ struct qlcnic_hardware_context {
u8 nic_mode;
char diag_cnt;

u16 max_uc_count;
u16 port_type;
u16 board_type;
u16 supported_type;
Expand Down Expand Up @@ -1494,6 +1495,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32);
void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
int qlcnic_enable_msix(struct qlcnic_adapter *, u32);

/* eSwitch management functions */
Expand Down Expand Up @@ -1631,6 +1633,7 @@ struct qlcnic_hardware_ops {
int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16);
int (*get_board_info) (struct qlcnic_adapter *);
void (*set_mac_filter_count) (struct qlcnic_adapter *);
void (*free_mac_list) (struct qlcnic_adapter *);
};

Expand Down Expand Up @@ -1846,6 +1849,11 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
return adapter->ahw->hw_ops->free_mac_list(adapter);
}

static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
{
adapter->ahw->hw_ops->set_mac_filter_count(adapter);
}

static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
u32 key)
{
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
.config_promisc_mode = qlcnic_83xx_nic_set_promisc,
.change_l2_filter = qlcnic_83xx_change_l2_filter,
.get_board_info = qlcnic_83xx_get_port_info,
.set_mac_filter_count = qlcnic_83xx_set_mac_filter_count,
.free_mac_list = qlcnic_82xx_free_mac_list,
};

Expand Down Expand Up @@ -609,6 +610,22 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
return status;
}

void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
u16 act_pci_fn = ahw->act_pci_func;
u16 count;

ahw->max_mc_count = QLC_83XX_MAX_MC_COUNT;
if (act_pci_fn <= 2)
count = (QLC_83XX_MAX_UC_COUNT - QLC_83XX_MAX_MC_COUNT) /
act_pci_fn;
else
count = (QLC_83XX_LB_MAX_FILTERS - QLC_83XX_MAX_MC_COUNT) /
act_pci_fn;
ahw->max_uc_count = count;
}

void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
{
u32 val;
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ enum qlcnic_83xx_states {
#define QLC_83XX_LB_MAX_FILTERS 2048
#define QLC_83XX_LB_BUCKET_SIZE 256
#define QLC_83XX_MINIMUM_VECTOR 3
#define QLC_83XX_MAX_MC_COUNT 38
#define QLC_83XX_MAX_UC_COUNT 4096

#define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val) (val & 0x80000000)
#define QLC_83XX_GET_LRO_CAPABILITY(val) (val & 0x20)
Expand Down Expand Up @@ -624,4 +626,5 @@ u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *, u32 *);
void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *);
void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *);
void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *);
#endif
1 change: 1 addition & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ enum {
#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 10

#define QLCNIC_MAX_MC_COUNT 38
#define QLCNIC_MAX_UC_COUNT 512
#define QLCNIC_WATCHDOG_TIMEOUTVALUE 5

#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
Expand Down
34 changes: 20 additions & 14 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_hardware_context *ahw = adapter->ahw;
struct netdev_hw_addr *ha;
static const u8 bcast_addr[ETH_ALEN] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
Expand All @@ -515,25 +516,30 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
mode = VPORT_MISS_MODE_ACCEPT_ALL;
goto send_fw_cmd;
}

if ((netdev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(netdev) > adapter->ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
goto send_fw_cmd;
} else if (netdev->flags & IFF_ALLMULTI) {
if (netdev_mc_count(netdev) > ahw->max_mc_count) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else if (!netdev_mc_empty(netdev) &&
!qlcnic_sriov_vf_check(adapter)) {
netdev_for_each_mc_addr(ha, netdev)
qlcnic_nic_add_mac(adapter, ha->addr,
vlan);
}
if (mode != VPORT_MISS_MODE_ACCEPT_MULTI &&
qlcnic_sriov_vf_check(adapter))
qlcnic_vf_add_mc_list(netdev, vlan);
}

if (!netdev_mc_empty(netdev) && !qlcnic_sriov_vf_check(adapter)) {
netdev_for_each_mc_addr(ha, netdev) {
/* configure unicast MAC address, if there is not sufficient space
* to store all the unicast addresses then enable promiscuous mode
*/
if (netdev_uc_count(netdev) > ahw->max_uc_count) {
mode = VPORT_MISS_MODE_ACCEPT_ALL;
} else if (!netdev_uc_empty(netdev)) {
netdev_for_each_uc_addr(ha, netdev)
qlcnic_nic_add_mac(adapter, ha->addr, vlan);
}
}

if (qlcnic_sriov_vf_check(adapter))
qlcnic_vf_add_mc_list(netdev, vlan);

send_fw_cmd:
if (!qlcnic_sriov_vf_check(adapter)) {
if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
!adapter->fdb_mac_learn) {
Expand Down
43 changes: 34 additions & 9 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,15 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
return ndo_dflt_fdb_del(ndm, tb, netdev, addr);

if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
if (is_unicast_ether_addr(addr))
err = qlcnic_nic_del_mac(adapter, addr);
else if (is_multicast_ether_addr(addr))
if (is_unicast_ether_addr(addr)) {
err = dev_uc_del(netdev, addr);
if (!err)
err = qlcnic_nic_del_mac(adapter, addr);
} else if (is_multicast_ether_addr(addr)) {
err = dev_mc_del(netdev, addr);
else
} else {
err = -EINVAL;
}
}
return err;
}
Expand All @@ -388,12 +391,16 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (ether_addr_equal(addr, adapter->mac_addr))
return err;

if (is_unicast_ether_addr(addr))
err = qlcnic_nic_add_mac(adapter, addr, 0);
else if (is_multicast_ether_addr(addr))
if (is_unicast_ether_addr(addr)) {
if (netdev_uc_count(netdev) < adapter->ahw->max_uc_count)
err = dev_uc_add_excl(netdev, addr);
else
err = -ENOMEM;
} else if (is_multicast_ether_addr(addr)) {
err = dev_mc_add_excl(netdev, addr);
else
} else {
err = -EINVAL;
}

return err;
}
Expand Down Expand Up @@ -505,6 +512,7 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.config_promisc_mode = qlcnic_82xx_nic_set_promisc,
.change_l2_filter = qlcnic_82xx_change_filter,
.get_board_info = qlcnic_82xx_get_board_info,
.set_mac_filter_count = qlcnic_82xx_set_mac_filter_count,
.free_mac_list = qlcnic_82xx_free_mac_list,
};

Expand Down Expand Up @@ -1829,6 +1837,22 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)
return err;
}

void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
u16 act_pci_fn = ahw->act_pci_func;
u16 count;

ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
if (act_pci_fn <= 2)
count = (QLCNIC_MAX_UC_COUNT - QLCNIC_MAX_MC_COUNT) /
act_pci_fn;
else
count = (QLCNIC_LB_MAX_FILTERS - QLCNIC_MAX_MC_COUNT) /
act_pci_fn;
ahw->max_uc_count = count;
}

int
qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
int pci_using_dac)
Expand All @@ -1838,7 +1862,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,

adapter->rx_csum = 1;
adapter->ahw->mc_enabled = 0;
adapter->ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
qlcnic_set_mac_filter_count(adapter);

netdev->netdev_ops = &qlcnic_netdev_ops;
netdev->watchdog_timeo = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ;
Expand Down Expand Up @@ -1876,6 +1900,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
netdev->features |= NETIF_F_LRO;

netdev->hw_features = netdev->features;
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->irq = adapter->msix_entries[0].vector;

err = register_netdev(netdev);
Expand Down

0 comments on commit 52e493d

Please sign in to comment.