diff options
6 files changed, 64 insertions, 31 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 8d7aa4ceac90..a68b145b3451 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
| @@ -1079,6 +1079,7 @@ struct qlcnic_adapter { | |||
| 1079 | u64 dev_rst_time; | 1079 | u64 dev_rst_time; |
| 1080 | bool drv_mac_learn; | 1080 | bool drv_mac_learn; |
| 1081 | bool fdb_mac_learn; | 1081 | bool fdb_mac_learn; |
| 1082 | u8 rx_mac_learn; | ||
| 1082 | unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; | 1083 | unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; |
| 1083 | u8 flash_mfg_id; | 1084 | u8 flash_mfg_id; |
| 1084 | struct qlcnic_npar_info *npars; | 1085 | struct qlcnic_npar_info *npars; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index ca221601e4a2..03f70e8940b3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
| @@ -1591,7 +1591,9 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter, | |||
| 1591 | u32 *interface_id) | 1591 | u32 *interface_id) |
| 1592 | { | 1592 | { |
| 1593 | if (qlcnic_sriov_pf_check(adapter)) { | 1593 | if (qlcnic_sriov_pf_check(adapter)) { |
| 1594 | qlcnic_alloc_lb_filters_mem(adapter); | ||
| 1594 | qlcnic_pf_set_interface_id_promisc(adapter, interface_id); | 1595 | qlcnic_pf_set_interface_id_promisc(adapter, interface_id); |
| 1596 | adapter->rx_mac_learn = 1; | ||
| 1595 | } else { | 1597 | } else { |
| 1596 | if (!qlcnic_sriov_vf_check(adapter)) | 1598 | if (!qlcnic_sriov_vf_check(adapter)) |
| 1597 | *interface_id = adapter->recv_ctx->context_id << 16; | 1599 | *interface_id = adapter->recv_ctx->context_id << 16; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 22ae884728b8..abe3924c61c5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | |||
| @@ -2214,6 +2214,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) | |||
| 2214 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 2214 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
| 2215 | int err = 0; | 2215 | int err = 0; |
| 2216 | 2216 | ||
| 2217 | adapter->rx_mac_learn = 0; | ||
| 2217 | ahw->msix_supported = !!qlcnic_use_msi_x; | 2218 | ahw->msix_supported = !!qlcnic_use_msi_x; |
| 2218 | 2219 | ||
| 2219 | qlcnic_83xx_init_rings(adapter); | 2220 | qlcnic_83xx_init_rings(adapter); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c index 474320a5f0c1..23c4fd10e505 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c | |||
| @@ -224,10 +224,14 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter) | |||
| 224 | return -EIO; | 224 | return -EIO; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) | 227 | if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) { |
| 228 | adapter->flags |= QLCNIC_ESWITCH_ENABLED; | 228 | adapter->flags |= QLCNIC_ESWITCH_ENABLED; |
| 229 | else | 229 | if (adapter->drv_mac_learn) |
| 230 | adapter->rx_mac_learn = 1; | ||
| 231 | } else { | ||
| 230 | adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; | 232 | adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; |
| 233 | adapter->rx_mac_learn = 0; | ||
| 234 | } | ||
| 231 | 235 | ||
| 232 | ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER; | 236 | ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER; |
| 233 | ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO; | 237 | ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index a9a149b82375..18cc365bc7ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | |||
| @@ -546,8 +546,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) | |||
| 546 | !adapter->fdb_mac_learn) { | 546 | !adapter->fdb_mac_learn) { |
| 547 | qlcnic_alloc_lb_filters_mem(adapter); | 547 | qlcnic_alloc_lb_filters_mem(adapter); |
| 548 | adapter->drv_mac_learn = 1; | 548 | adapter->drv_mac_learn = 1; |
| 549 | if (adapter->flags & QLCNIC_ESWITCH_ENABLED) | ||
| 550 | adapter->rx_mac_learn = 1; | ||
| 549 | } else { | 551 | } else { |
| 550 | adapter->drv_mac_learn = 0; | 552 | adapter->drv_mac_learn = 0; |
| 553 | adapter->rx_mac_learn = 0; | ||
| 551 | } | 554 | } |
| 552 | 555 | ||
| 553 | qlcnic_nic_set_promisc(adapter, mode); | 556 | qlcnic_nic_set_promisc(adapter, mode); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 6373f6022486..cbe4a30abd79 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | |||
| @@ -156,9 +156,9 @@ static inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, | |||
| 156 | writel(1, tx_ring->crb_intr_mask); | 156 | writel(1, tx_ring->crb_intr_mask); |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | static inline u8 qlcnic_mac_hash(u64 mac) | 159 | static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan) |
| 160 | { | 160 | { |
| 161 | return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff)); | 161 | return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff)); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, | 164 | 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, | |||
| 221 | u8 hindex, op; | 221 | u8 hindex, op; |
| 222 | int ret; | 222 | int ret; |
| 223 | 223 | ||
| 224 | if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff)) | ||
| 225 | vlan_id = 0; | ||
| 226 | |||
| 224 | memcpy(&src_addr, phdr->h_source, ETH_ALEN); | 227 | memcpy(&src_addr, phdr->h_source, ETH_ALEN); |
| 225 | hindex = qlcnic_mac_hash(src_addr) & | 228 | hindex = qlcnic_mac_hash(src_addr, vlan_id) & |
| 226 | (adapter->fhash.fbucket_size - 1); | 229 | (adapter->fhash.fbucket_size - 1); |
| 227 | 230 | ||
| 228 | if (loopback_pkt) { | 231 | if (loopback_pkt) { |
| @@ -322,27 +325,43 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, | |||
| 322 | struct cmd_desc_type0 *first_desc, | 325 | struct cmd_desc_type0 *first_desc, |
| 323 | struct sk_buff *skb) | 326 | struct sk_buff *skb) |
| 324 | { | 327 | { |
| 328 | struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); | ||
| 329 | struct ethhdr *phdr = (struct ethhdr *)(skb->data); | ||
| 330 | struct net_device *netdev = adapter->netdev; | ||
| 331 | u16 protocol = ntohs(skb->protocol); | ||
| 325 | struct qlcnic_filter *fil, *tmp_fil; | 332 | struct qlcnic_filter *fil, *tmp_fil; |
| 326 | struct hlist_node *n; | ||
| 327 | struct hlist_head *head; | 333 | struct hlist_head *head; |
| 328 | struct net_device *netdev = adapter->netdev; | 334 | struct hlist_node *n; |
| 329 | struct ethhdr *phdr = (struct ethhdr *)(skb->data); | ||
| 330 | u64 src_addr = 0; | 335 | u64 src_addr = 0; |
| 331 | u16 vlan_id = 0; | 336 | u16 vlan_id = 0; |
| 332 | u8 hindex; | 337 | u8 hindex, hval; |
| 333 | 338 | ||
| 334 | if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) | 339 | if (!qlcnic_sriov_pf_check(adapter)) { |
| 335 | return; | 340 | if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) |
| 341 | return; | ||
| 342 | } else { | ||
| 343 | if (protocol == ETH_P_8021Q) { | ||
| 344 | vh = (struct vlan_ethhdr *)skb->data; | ||
| 345 | vlan_id = ntohs(vh->h_vlan_TCI); | ||
| 346 | } else if (vlan_tx_tag_present(skb)) { | ||
| 347 | vlan_id = vlan_tx_tag_get(skb); | ||
| 348 | } | ||
| 349 | |||
| 350 | if (ether_addr_equal(phdr->h_source, adapter->mac_addr) && | ||
| 351 | !vlan_id) | ||
| 352 | return; | ||
| 353 | } | ||
| 336 | 354 | ||
| 337 | if (adapter->fhash.fnum >= adapter->fhash.fmax) { | 355 | if (adapter->fhash.fnum >= adapter->fhash.fmax) { |
| 338 | adapter->stats.mac_filter_limit_overrun++; | 356 | adapter->stats.mac_filter_limit_overrun++; |
| 339 | netdev_info(netdev, "Can not add more than %d mac addresses\n", | 357 | netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n", |
| 340 | adapter->fhash.fmax); | 358 | adapter->fhash.fmax, adapter->fhash.fnum); |
| 341 | return; | 359 | return; |
| 342 | } | 360 | } |
| 343 | 361 | ||
| 344 | memcpy(&src_addr, phdr->h_source, ETH_ALEN); | 362 | memcpy(&src_addr, phdr->h_source, ETH_ALEN); |
| 345 | hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1); | 363 | hval = qlcnic_mac_hash(src_addr, vlan_id); |
| 364 | hindex = hval & (adapter->fhash.fbucket_size - 1); | ||
| 346 | head = &(adapter->fhash.fhead[hindex]); | 365 | head = &(adapter->fhash.fhead[hindex]); |
| 347 | 366 | ||
| 348 | hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { | 367 | hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { |
| @@ -1599,7 +1618,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, | |||
| 1599 | struct sk_buff *skb; | 1618 | struct sk_buff *skb; |
| 1600 | struct qlcnic_host_rds_ring *rds_ring; | 1619 | struct qlcnic_host_rds_ring *rds_ring; |
| 1601 | int index, length, cksum, is_lb_pkt; | 1620 | int index, length, cksum, is_lb_pkt; |
| 1602 | u16 vid = 0xffff, t_vid; | 1621 | u16 vid = 0xffff; |
| 1622 | int err; | ||
| 1603 | 1623 | ||
| 1604 | if (unlikely(ring >= adapter->max_rds_rings)) | 1624 | if (unlikely(ring >= adapter->max_rds_rings)) |
| 1605 | return NULL; | 1625 | return NULL; |
| @@ -1617,19 +1637,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, | |||
| 1617 | if (!skb) | 1637 | if (!skb) |
| 1618 | return buffer; | 1638 | return buffer; |
| 1619 | 1639 | ||
| 1620 | if (adapter->drv_mac_learn && | ||
| 1621 | (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { | ||
| 1622 | t_vid = 0; | ||
| 1623 | is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); | ||
| 1624 | qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | if (length > rds_ring->skb_size) | 1640 | if (length > rds_ring->skb_size) |
| 1628 | skb_put(skb, rds_ring->skb_size); | 1641 | skb_put(skb, rds_ring->skb_size); |
| 1629 | else | 1642 | else |
| 1630 | skb_put(skb, length); | 1643 | skb_put(skb, length); |
| 1631 | 1644 | ||
| 1632 | if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { | 1645 | err = qlcnic_check_rx_tagging(adapter, skb, &vid); |
| 1646 | |||
| 1647 | if (adapter->rx_mac_learn) { | ||
| 1648 | is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); | ||
| 1649 | qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | if (unlikely(err)) { | ||
| 1633 | adapter->stats.rxdropped++; | 1653 | adapter->stats.rxdropped++; |
| 1634 | dev_kfree_skb(skb); | 1654 | dev_kfree_skb(skb); |
| 1635 | return buffer; | 1655 | return buffer; |
| @@ -1664,7 +1684,8 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, | |||
| 1664 | int l2_hdr_offset, l4_hdr_offset; | 1684 | int l2_hdr_offset, l4_hdr_offset; |
| 1665 | int index, is_lb_pkt; | 1685 | int index, is_lb_pkt; |
| 1666 | u16 lro_length, length, data_offset, gso_size; | 1686 | u16 lro_length, length, data_offset, gso_size; |
| 1667 | u16 vid = 0xffff, t_vid; | 1687 | u16 vid = 0xffff; |
| 1688 | int err; | ||
| 1668 | 1689 | ||
| 1669 | if (unlikely(ring > adapter->max_rds_rings)) | 1690 | if (unlikely(ring > adapter->max_rds_rings)) |
| 1670 | return NULL; | 1691 | return NULL; |
| @@ -1686,12 +1707,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, | |||
| 1686 | if (!skb) | 1707 | if (!skb) |
| 1687 | return buffer; | 1708 | return buffer; |
| 1688 | 1709 | ||
| 1689 | if (adapter->drv_mac_learn && | ||
| 1690 | (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { | ||
| 1691 | t_vid = 0; | ||
| 1692 | is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); | ||
| 1693 | qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); | ||
| 1694 | } | ||
| 1695 | if (qlcnic_83xx_is_tstamp(sts_data[1])) | 1710 | if (qlcnic_83xx_is_tstamp(sts_data[1])) |
| 1696 | data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; | 1711 | data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; |
| 1697 | else | 1712 | else |
| @@ -1700,7 +1715,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, | |||
| 1700 | skb_put(skb, lro_length + data_offset); | 1715 | skb_put(skb, lro_length + data_offset); |
| 1701 | skb_pull(skb, l2_hdr_offset); | 1716 | skb_pull(skb, l2_hdr_offset); |
| 1702 | 1717 | ||
| 1703 | if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { | 1718 | err = qlcnic_check_rx_tagging(adapter, skb, &vid); |
| 1719 | |||
| 1720 | if (adapter->rx_mac_learn) { | ||
| 1721 | is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); | ||
| 1722 | qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); | ||
| 1723 | } | ||
| 1724 | |||
| 1725 | if (unlikely(err)) { | ||
| 1704 | adapter->stats.rxdropped++; | 1726 | adapter->stats.rxdropped++; |
| 1705 | dev_kfree_skb(skb); | 1727 | dev_kfree_skb(skb); |
| 1706 | return buffer; | 1728 | return buffer; |
