aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
diff options
context:
space:
mode:
authorLendacky, Thomas <Thomas.Lendacky@amd.com>2014-06-24 17:19:29 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-26 20:14:04 -0400
commitb85e4d8960f10e4b28613a3e7b76f8889a2089e3 (patch)
tree240e74511042f9bdd930dcb41c030f0eb910c4b1 /drivers/net/ethernet/amd/xgbe/xgbe-dev.c
parent801c62d945c6121c0262924732e430f0553bfb37 (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.c141
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
551static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata, 552static 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++; 583static 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; 616static 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
651static 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)
1606static void xgbe_config_mac_address(struct xgbe_prv_data *pdata) 1638static 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
1611static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) 1650static 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;