qlcnic: Do MAC learning for SRIOV PF.
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Fri, 10 Jan 2014 16:48:55 +0000 (11:48 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Jan 2014 23:31:18 +0000 (15:31 -0800)
o MAC learning will be done for SRIOV PF to help program VLAN filters
  onto adapter. This will help VNIC traffic to flow through without
  flooding traffic.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c

index 8d7aa4ceac90f9ac505d2d1df9cd52bbdd5ef438..a68b145b3451dd21de3edbe815294ee658be5ced 100644 (file)
@@ -1079,6 +1079,7 @@ struct qlcnic_adapter {
        u64 dev_rst_time;
        bool drv_mac_learn;
        bool fdb_mac_learn;
+       u8 rx_mac_learn;
        unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
        u8 flash_mfg_id;
        struct qlcnic_npar_info *npars;
index ca221601e4a266b971ec79140e1cb1dba0c080b2..03f70e8940b3ad9c125cfdf364f4f44009da3eff 100644 (file)
@@ -1591,7 +1591,9 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,
                                                 u32 *interface_id)
 {
        if (qlcnic_sriov_pf_check(adapter)) {
+               qlcnic_alloc_lb_filters_mem(adapter);
                qlcnic_pf_set_interface_id_promisc(adapter, interface_id);
+               adapter->rx_mac_learn = 1;
        } else {
                if (!qlcnic_sriov_vf_check(adapter))
                        *interface_id = adapter->recv_ctx->context_id << 16;
index 22ae884728b81eb27aabb8ca9d73c90a2f4e10ae..abe3924c61c5e265964104cfd1267111b9e096d3 100644 (file)
@@ -2214,6 +2214,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        int err = 0;
 
+       adapter->rx_mac_learn = 0;
        ahw->msix_supported = !!qlcnic_use_msi_x;
 
        qlcnic_83xx_init_rings(adapter);
index 474320a5f0c15aeac1956b6d528cbc5c5a2f0566..23c4fd10e505a3f877b77aa105cc488aa7634a6f 100644 (file)
@@ -224,10 +224,14 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
                return -EIO;
        }
 
-       if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY)
+       if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) {
                adapter->flags |= QLCNIC_ESWITCH_ENABLED;
-       else
+               if (adapter->drv_mac_learn)
+                       adapter->rx_mac_learn = 1;
+       } else {
                adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+               adapter->rx_mac_learn = 0;
+       }
 
        ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
        ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
index a9a149b82375835e1132e68094095f2ec605c910..18cc365bc7ea0dd520f2cae056ad68d99bc5385e 100644 (file)
@@ -546,8 +546,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
            !adapter->fdb_mac_learn) {
                qlcnic_alloc_lb_filters_mem(adapter);
                adapter->drv_mac_learn = 1;
+               if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+                       adapter->rx_mac_learn = 1;
        } else {
                adapter->drv_mac_learn = 0;
+               adapter->rx_mac_learn = 0;
        }
 
        qlcnic_nic_set_promisc(adapter, mode);
index 6373f6022486c651e67379e91d9320998f881777..cbe4a30abd7921a1dcde90ec7ed85135b144515f 100644 (file)
@@ -156,9 +156,9 @@ static inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter,
        writel(1, tx_ring->crb_intr_mask);
 }
 
-static inline u8 qlcnic_mac_hash(u64 mac)
+static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan)
 {
-       return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff));
+       return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff));
 }
 
 static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
@@ -221,8 +221,11 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
        u8 hindex, op;
        int ret;
 
+       if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff))
+               vlan_id = 0;
+
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-       hindex = qlcnic_mac_hash(src_addr) &
+       hindex = qlcnic_mac_hash(src_addr, vlan_id) &
                 (adapter->fhash.fbucket_size - 1);
 
        if (loopback_pkt) {
@@ -322,27 +325,43 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
                               struct cmd_desc_type0 *first_desc,
                               struct sk_buff *skb)
 {
+       struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data);
+       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+       struct net_device *netdev = adapter->netdev;
+       u16 protocol = ntohs(skb->protocol);
        struct qlcnic_filter *fil, *tmp_fil;
-       struct hlist_node *n;
        struct hlist_head *head;
-       struct net_device *netdev = adapter->netdev;
-       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+       struct hlist_node *n;
        u64 src_addr = 0;
        u16 vlan_id = 0;
-       u8 hindex;
+       u8 hindex, hval;
 
-       if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
-               return;
+       if (!qlcnic_sriov_pf_check(adapter)) {
+               if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
+                       return;
+       } else {
+               if (protocol == ETH_P_8021Q) {
+                       vh = (struct vlan_ethhdr *)skb->data;
+                       vlan_id = ntohs(vh->h_vlan_TCI);
+               } else if (vlan_tx_tag_present(skb)) {
+                       vlan_id = vlan_tx_tag_get(skb);
+               }
+
+               if (ether_addr_equal(phdr->h_source, adapter->mac_addr) &&
+                   !vlan_id)
+                       return;
+       }
 
        if (adapter->fhash.fnum >= adapter->fhash.fmax) {
                adapter->stats.mac_filter_limit_overrun++;
-               netdev_info(netdev, "Can not add more than %d mac addresses\n",
-                           adapter->fhash.fmax);
+               netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n",
+                           adapter->fhash.fmax, adapter->fhash.fnum);
                return;
        }
 
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-       hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
+       hval = qlcnic_mac_hash(src_addr, vlan_id);
+       hindex = hval & (adapter->fhash.fbucket_size - 1);
        head = &(adapter->fhash.fhead[hindex]);
 
        hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
@@ -1599,7 +1618,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
        struct sk_buff *skb;
        struct qlcnic_host_rds_ring *rds_ring;
        int index, length, cksum, is_lb_pkt;
-       u16 vid = 0xffff, t_vid;
+       u16 vid = 0xffff;
+       int err;
 
        if (unlikely(ring >= adapter->max_rds_rings))
                return NULL;
@@ -1617,19 +1637,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
        if (!skb)
                return buffer;
 
-       if (adapter->drv_mac_learn &&
-           (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               t_vid = 0;
-               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
-               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
-       }
-
        if (length > rds_ring->skb_size)
                skb_put(skb, rds_ring->skb_size);
        else
                skb_put(skb, length);
 
-       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+       err = qlcnic_check_rx_tagging(adapter, skb, &vid);
+
+       if (adapter->rx_mac_learn) {
+               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
+               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid);
+       }
+
+       if (unlikely(err)) {
                adapter->stats.rxdropped++;
                dev_kfree_skb(skb);
                return buffer;
@@ -1664,7 +1684,8 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        int l2_hdr_offset, l4_hdr_offset;
        int index, is_lb_pkt;
        u16 lro_length, length, data_offset, gso_size;
-       u16 vid = 0xffff, t_vid;
+       u16 vid = 0xffff;
+       int err;
 
        if (unlikely(ring > adapter->max_rds_rings))
                return NULL;
@@ -1686,12 +1707,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        if (!skb)
                return buffer;
 
-       if (adapter->drv_mac_learn &&
-           (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               t_vid = 0;
-               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
-               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
-       }
        if (qlcnic_83xx_is_tstamp(sts_data[1]))
                data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
        else
@@ -1700,7 +1715,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        skb_put(skb, lro_length + data_offset);
        skb_pull(skb, l2_hdr_offset);
 
-       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+       err = qlcnic_check_rx_tagging(adapter, skb, &vid);
+
+       if (adapter->rx_mac_learn) {
+               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
+               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid);
+       }
+
+       if (unlikely(err)) {
                adapter->stats.rxdropped++;
                dev_kfree_skb(skb);
                return buffer;