diff options
author | Lendacky, Thomas <Thomas.Lendacky@amd.com> | 2014-06-24 17:19:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-26 20:14:04 -0400 |
commit | b85e4d8960f10e4b28613a3e7b76f8889a2089e3 (patch) | |
tree | 240e74511042f9bdd930dcb41c030f0eb910c4b1 /drivers/net/ethernet/amd/xgbe/xgbe-dev.c | |
parent | 801c62d945c6121c0262924732e430f0553bfb37 (diff) |
amd-xgbe: Change destination address filtering support
Currently the driver makes use of the additional mac address
registers in the hardware to provide perfect filtering. The
hardware can also have a set of hash table registers that can
be used for imperfect filtering. By using imperfect filtering
the additional mac address registers can be used for layer 2
filtering support. Use the hash table registers if the device
has them.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-dev.c')
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 141 |
1 files changed, 90 insertions, 51 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 2c7d582e0859..a56069c91fc4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c | |||
@@ -117,6 +117,7 @@ | |||
117 | #include <linux/phy.h> | 117 | #include <linux/phy.h> |
118 | #include <linux/clk.h> | 118 | #include <linux/clk.h> |
119 | #include <linux/bitrev.h> | 119 | #include <linux/bitrev.h> |
120 | #include <linux/crc32.h> | ||
120 | 121 | ||
121 | #include "xgbe.h" | 122 | #include "xgbe.h" |
122 | #include "xgbe-common.h" | 123 | #include "xgbe-common.h" |
@@ -548,24 +549,16 @@ static int xgbe_set_all_multicast_mode(struct xgbe_prv_data *pdata, | |||
548 | return 0; | 549 | return 0; |
549 | } | 550 | } |
550 | 551 | ||
551 | static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata, | 552 | static void xgbe_set_mac_reg(struct xgbe_prv_data *pdata, |
552 | unsigned int am_mode) | 553 | struct netdev_hw_addr *ha, unsigned int *mac_reg) |
553 | { | 554 | { |
554 | struct netdev_hw_addr *ha; | ||
555 | unsigned int mac_reg; | ||
556 | unsigned int mac_addr_hi, mac_addr_lo; | 555 | unsigned int mac_addr_hi, mac_addr_lo; |
557 | u8 *mac_addr; | 556 | u8 *mac_addr; |
558 | unsigned int i; | ||
559 | 557 | ||
560 | XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 0); | 558 | mac_addr_lo = 0; |
561 | XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 0); | 559 | mac_addr_hi = 0; |
562 | |||
563 | i = 0; | ||
564 | mac_reg = MAC_MACA1HR; | ||
565 | 560 | ||
566 | netdev_for_each_uc_addr(ha, pdata->netdev) { | 561 | if (ha) { |
567 | mac_addr_lo = 0; | ||
568 | mac_addr_hi = 0; | ||
569 | mac_addr = (u8 *)&mac_addr_lo; | 562 | mac_addr = (u8 *)&mac_addr_lo; |
570 | mac_addr[0] = ha->addr[0]; | 563 | mac_addr[0] = ha->addr[0]; |
571 | mac_addr[1] = ha->addr[1]; | 564 | mac_addr[1] = ha->addr[1]; |
@@ -575,54 +568,93 @@ static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata, | |||
575 | mac_addr[0] = ha->addr[4]; | 568 | mac_addr[0] = ha->addr[4]; |
576 | mac_addr[1] = ha->addr[5]; | 569 | mac_addr[1] = ha->addr[5]; |
577 | 570 | ||
578 | DBGPR(" adding unicast address %pM at 0x%04x\n", | 571 | DBGPR(" adding mac address %pM at 0x%04x\n", ha->addr, |
579 | ha->addr, mac_reg); | 572 | *mac_reg); |
580 | 573 | ||
581 | XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1); | 574 | XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1); |
575 | } | ||
582 | 576 | ||
583 | XGMAC_IOWRITE(pdata, mac_reg, mac_addr_hi); | 577 | XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_hi); |
584 | mac_reg += MAC_MACA_INC; | 578 | *mac_reg += MAC_MACA_INC; |
585 | XGMAC_IOWRITE(pdata, mac_reg, mac_addr_lo); | 579 | XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_lo); |
586 | mac_reg += MAC_MACA_INC; | 580 | *mac_reg += MAC_MACA_INC; |
581 | } | ||
587 | 582 | ||
588 | i++; | 583 | static void xgbe_set_mac_addn_addrs(struct xgbe_prv_data *pdata) |
589 | } | 584 | { |
585 | struct net_device *netdev = pdata->netdev; | ||
586 | struct netdev_hw_addr *ha; | ||
587 | unsigned int mac_reg; | ||
588 | unsigned int addn_macs; | ||
589 | |||
590 | mac_reg = MAC_MACA1HR; | ||
591 | addn_macs = pdata->hw_feat.addn_mac; | ||
590 | 592 | ||
591 | if (!am_mode) { | 593 | if (netdev_uc_count(netdev) > addn_macs) { |
592 | netdev_for_each_mc_addr(ha, pdata->netdev) { | 594 | xgbe_set_promiscuous_mode(pdata, 1); |
593 | mac_addr_lo = 0; | 595 | } else { |
594 | mac_addr_hi = 0; | 596 | netdev_for_each_uc_addr(ha, netdev) { |
595 | mac_addr = (u8 *)&mac_addr_lo; | 597 | xgbe_set_mac_reg(pdata, ha, &mac_reg); |
596 | mac_addr[0] = ha->addr[0]; | 598 | addn_macs--; |
597 | mac_addr[1] = ha->addr[1]; | 599 | } |
598 | mac_addr[2] = ha->addr[2]; | 600 | |
599 | mac_addr[3] = ha->addr[3]; | 601 | if (netdev_mc_count(netdev) > addn_macs) { |
600 | mac_addr = (u8 *)&mac_addr_hi; | 602 | xgbe_set_all_multicast_mode(pdata, 1); |
601 | mac_addr[0] = ha->addr[4]; | 603 | } else { |
602 | mac_addr[1] = ha->addr[5]; | 604 | netdev_for_each_mc_addr(ha, netdev) { |
603 | 605 | xgbe_set_mac_reg(pdata, ha, &mac_reg); | |
604 | DBGPR(" adding multicast address %pM at 0x%04x\n", | 606 | addn_macs--; |
605 | ha->addr, mac_reg); | 607 | } |
606 | |||
607 | XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1); | ||
608 | |||
609 | XGMAC_IOWRITE(pdata, mac_reg, mac_addr_hi); | ||
610 | mac_reg += MAC_MACA_INC; | ||
611 | XGMAC_IOWRITE(pdata, mac_reg, mac_addr_lo); | ||
612 | mac_reg += MAC_MACA_INC; | ||
613 | |||
614 | i++; | ||
615 | } | 608 | } |
616 | } | 609 | } |
617 | 610 | ||
618 | /* Clear remaining additional MAC address entries */ | 611 | /* Clear remaining additional MAC address entries */ |
619 | for (; i < pdata->hw_feat.addn_mac; i++) { | 612 | while (addn_macs--) |
620 | XGMAC_IOWRITE(pdata, mac_reg, 0); | 613 | xgbe_set_mac_reg(pdata, NULL, &mac_reg); |
621 | mac_reg += MAC_MACA_INC; | 614 | } |
622 | XGMAC_IOWRITE(pdata, mac_reg, 0); | 615 | |
623 | mac_reg += MAC_MACA_INC; | 616 | static void xgbe_set_mac_hash_table(struct xgbe_prv_data *pdata) |
617 | { | ||
618 | struct net_device *netdev = pdata->netdev; | ||
619 | struct netdev_hw_addr *ha; | ||
620 | unsigned int hash_reg; | ||
621 | unsigned int hash_table_shift, hash_table_count; | ||
622 | u32 hash_table[XGBE_MAC_HASH_TABLE_SIZE]; | ||
623 | u32 crc; | ||
624 | unsigned int i; | ||
625 | |||
626 | hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7); | ||
627 | hash_table_count = pdata->hw_feat.hash_table_size / 32; | ||
628 | memset(hash_table, 0, sizeof(hash_table)); | ||
629 | |||
630 | /* Build the MAC Hash Table register values */ | ||
631 | netdev_for_each_uc_addr(ha, netdev) { | ||
632 | crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); | ||
633 | crc >>= hash_table_shift; | ||
634 | hash_table[crc >> 5] |= (1 << (crc & 0x1f)); | ||
635 | } | ||
636 | |||
637 | netdev_for_each_mc_addr(ha, netdev) { | ||
638 | crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); | ||
639 | crc >>= hash_table_shift; | ||
640 | hash_table[crc >> 5] |= (1 << (crc & 0x1f)); | ||
624 | } | 641 | } |
625 | 642 | ||
643 | /* Set the MAC Hash Table registers */ | ||
644 | hash_reg = MAC_HTR0; | ||
645 | for (i = 0; i < hash_table_count; i++) { | ||
646 | XGMAC_IOWRITE(pdata, hash_reg, hash_table[i]); | ||
647 | hash_reg += MAC_HTR_INC; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | static int xgbe_add_mac_addresses(struct xgbe_prv_data *pdata) | ||
652 | { | ||
653 | if (pdata->hw_feat.hash_table_size) | ||
654 | xgbe_set_mac_hash_table(pdata); | ||
655 | else | ||
656 | xgbe_set_mac_addn_addrs(pdata); | ||
657 | |||
626 | return 0; | 658 | return 0; |
627 | } | 659 | } |
628 | 660 | ||
@@ -1606,6 +1638,13 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata) | |||
1606 | static void xgbe_config_mac_address(struct xgbe_prv_data *pdata) | 1638 | static void xgbe_config_mac_address(struct xgbe_prv_data *pdata) |
1607 | { | 1639 | { |
1608 | xgbe_set_mac_address(pdata, pdata->netdev->dev_addr); | 1640 | xgbe_set_mac_address(pdata, pdata->netdev->dev_addr); |
1641 | |||
1642 | /* Filtering is done using perfect filtering and hash filtering */ | ||
1643 | if (pdata->hw_feat.hash_table_size) { | ||
1644 | XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1); | ||
1645 | XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1); | ||
1646 | XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 1); | ||
1647 | } | ||
1609 | } | 1648 | } |
1610 | 1649 | ||
1611 | static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) | 1650 | static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) |
@@ -2202,7 +2241,7 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) | |||
2202 | 2241 | ||
2203 | hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode; | 2242 | hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode; |
2204 | hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode; | 2243 | hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode; |
2205 | hw_if->set_addn_mac_addrs = xgbe_set_addn_mac_addrs; | 2244 | hw_if->add_mac_addresses = xgbe_add_mac_addresses; |
2206 | hw_if->set_mac_address = xgbe_set_mac_address; | 2245 | hw_if->set_mac_address = xgbe_set_mac_address; |
2207 | 2246 | ||
2208 | hw_if->enable_rx_csum = xgbe_enable_rx_csum; | 2247 | hw_if->enable_rx_csum = xgbe_enable_rx_csum; |