summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/amd
diff options
context:
space:
mode:
authorLendacky, Thomas <Thomas.Lendacky@amd.com>2014-06-24 16:19:29 -0500
committerDavid S. Miller <davem@davemloft.net>2014-06-26 17:14:04 -0700
commitb85e4d8960f10e4b28613a3e7b76f8889a2089e3 (patch)
tree240e74511042f9bdd930dcb41c030f0eb910c4b1 /drivers/net/ethernet/amd
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')
-rw-r--r--drivers/net/ethernet/amd/Kconfig1
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-common.h10
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c141
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c27
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h4
6 files changed, 116 insertions, 69 deletions
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 8e83e4c8fff0..6e314dbba805 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -183,6 +183,7 @@ config AMD_XGBE
select PHYLIB
select AMD_XGBE_PHY
select BITREVERSE
+ select CRC32
---help---
This driver supports the AMD 10GbE Ethernet device found on an
AMD SoC.
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index 1de9d0fc594a..ccbceba553e5 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -276,13 +276,6 @@
#define MAC_PFR 0x0008
#define MAC_WTR 0x000c
#define MAC_HTR0 0x0010
-#define MAC_HTR1 0x0014
-#define MAC_HTR2 0x0018
-#define MAC_HTR3 0x001c
-#define MAC_HTR4 0x0020
-#define MAC_HTR5 0x0024
-#define MAC_HTR6 0x0028
-#define MAC_HTR7 0x002c
#define MAC_VLANTR 0x0050
#define MAC_VLANHTR 0x0058
#define MAC_VLANIR 0x0060
@@ -315,6 +308,7 @@
#define MAC_QTFCR_INC 4
#define MAC_MACA_INC 4
+#define MAC_HTR_INC 4
/* MAC register entry bit positions and sizes */
#define MAC_HWF0R_ADDMACADRSEL_INDEX 18
@@ -387,6 +381,8 @@
#define MAC_MACA1HR_AE_WIDTH 1
#define MAC_PFR_HMC_INDEX 2
#define MAC_PFR_HMC_WIDTH 1
+#define MAC_PFR_HPF_INDEX 10
+#define MAC_PFR_HPF_WIDTH 1
#define MAC_PFR_HUC_INDEX 1
#define MAC_PFR_HUC_WIDTH 1
#define MAC_PFR_PM_INDEX 4
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 @@
#include <linux/phy.h>
#include <linux/clk.h>
#include <linux/bitrev.h>
+#include <linux/crc32.h>
#include "xgbe.h"
#include "xgbe-common.h"
@@ -548,24 +549,16 @@ static int xgbe_set_all_multicast_mode(struct xgbe_prv_data *pdata,
return 0;
}
-static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata,
- unsigned int am_mode)
+static void xgbe_set_mac_reg(struct xgbe_prv_data *pdata,
+ struct netdev_hw_addr *ha, unsigned int *mac_reg)
{
- struct netdev_hw_addr *ha;
- unsigned int mac_reg;
unsigned int mac_addr_hi, mac_addr_lo;
u8 *mac_addr;
- unsigned int i;
- XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 0);
- XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 0);
-
- i = 0;
- mac_reg = MAC_MACA1HR;
+ mac_addr_lo = 0;
+ mac_addr_hi = 0;
- netdev_for_each_uc_addr(ha, pdata->netdev) {
- mac_addr_lo = 0;
- mac_addr_hi = 0;
+ if (ha) {
mac_addr = (u8 *)&mac_addr_lo;
mac_addr[0] = ha->addr[0];
mac_addr[1] = ha->addr[1];
@@ -575,54 +568,93 @@ static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata,
mac_addr[0] = ha->addr[4];
mac_addr[1] = ha->addr[5];
- DBGPR(" adding unicast address %pM at 0x%04x\n",
- ha->addr, mac_reg);
+ DBGPR(" adding mac address %pM at 0x%04x\n", ha->addr,
+ *mac_reg);
XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1);
+ }
- XGMAC_IOWRITE(pdata, mac_reg, mac_addr_hi);
- mac_reg += MAC_MACA_INC;
- XGMAC_IOWRITE(pdata, mac_reg, mac_addr_lo);
- mac_reg += MAC_MACA_INC;
+ XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_hi);
+ *mac_reg += MAC_MACA_INC;
+ XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_lo);
+ *mac_reg += MAC_MACA_INC;
+}
- i++;
- }
+static void xgbe_set_mac_addn_addrs(struct xgbe_prv_data *pdata)
+{
+ struct net_device *netdev = pdata->netdev;
+ struct netdev_hw_addr *ha;
+ unsigned int mac_reg;
+ unsigned int addn_macs;
+
+ mac_reg = MAC_MACA1HR;
+ addn_macs = pdata->hw_feat.addn_mac;
- if (!am_mode) {
- netdev_for_each_mc_addr(ha, pdata->netdev) {
- mac_addr_lo = 0;
- mac_addr_hi = 0;
- mac_addr = (u8 *)&mac_addr_lo;
- mac_addr[0] = ha->addr[0];
- mac_addr[1] = ha->addr[1];
- mac_addr[2] = ha->addr[2];
- mac_addr[3] = ha->addr[3];
- mac_addr = (u8 *)&mac_addr_hi;
- mac_addr[0] = ha->addr[4];
- mac_addr[1] = ha->addr[5];
-
- DBGPR(" adding multicast address %pM at 0x%04x\n",
- ha->addr, mac_reg);
-
- XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1);
-
- XGMAC_IOWRITE(pdata, mac_reg, mac_addr_hi);
- mac_reg += MAC_MACA_INC;
- XGMAC_IOWRITE(pdata, mac_reg, mac_addr_lo);
- mac_reg += MAC_MACA_INC;
-
- i++;
+ if (netdev_uc_count(netdev) > addn_macs) {
+ xgbe_set_promiscuous_mode(pdata, 1);
+ } else {
+ netdev_for_each_uc_addr(ha, netdev) {
+ xgbe_set_mac_reg(pdata, ha, &mac_reg);
+ addn_macs--;
+ }
+
+ if (netdev_mc_count(netdev) > addn_macs) {
+ xgbe_set_all_multicast_mode(pdata, 1);
+ } else {
+ netdev_for_each_mc_addr(ha, netdev) {
+ xgbe_set_mac_reg(pdata, ha, &mac_reg);
+ addn_macs--;
+ }
}
}
/* Clear remaining additional MAC address entries */
- for (; i < pdata->hw_feat.addn_mac; i++) {
- XGMAC_IOWRITE(pdata, mac_reg, 0);
- mac_reg += MAC_MACA_INC;
- XGMAC_IOWRITE(pdata, mac_reg, 0);
- mac_reg += MAC_MACA_INC;
+ while (addn_macs--)
+ xgbe_set_mac_reg(pdata, NULL, &mac_reg);
+}
+
+static void xgbe_set_mac_hash_table(struct xgbe_prv_data *pdata)
+{
+ struct net_device *netdev = pdata->netdev;
+ struct netdev_hw_addr *ha;
+ unsigned int hash_reg;
+ unsigned int hash_table_shift, hash_table_count;
+ u32 hash_table[XGBE_MAC_HASH_TABLE_SIZE];
+ u32 crc;
+ unsigned int i;
+
+ hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7);
+ hash_table_count = pdata->hw_feat.hash_table_size / 32;
+ memset(hash_table, 0, sizeof(hash_table));
+
+ /* Build the MAC Hash Table register values */
+ netdev_for_each_uc_addr(ha, netdev) {
+ crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN));
+ crc >>= hash_table_shift;
+ hash_table[crc >> 5] |= (1 << (crc & 0x1f));
+ }
+
+ netdev_for_each_mc_addr(ha, netdev) {
+ crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN));
+ crc >>= hash_table_shift;
+ hash_table[crc >> 5] |= (1 << (crc & 0x1f));
}
+ /* Set the MAC Hash Table registers */
+ hash_reg = MAC_HTR0;
+ for (i = 0; i < hash_table_count; i++) {
+ XGMAC_IOWRITE(pdata, hash_reg, hash_table[i]);
+ hash_reg += MAC_HTR_INC;
+ }
+}
+
+static int xgbe_add_mac_addresses(struct xgbe_prv_data *pdata)
+{
+ if (pdata->hw_feat.hash_table_size)
+ xgbe_set_mac_hash_table(pdata);
+ else
+ xgbe_set_mac_addn_addrs(pdata);
+
return 0;
}
@@ -1606,6 +1638,13 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata)
static void xgbe_config_mac_address(struct xgbe_prv_data *pdata)
{
xgbe_set_mac_address(pdata, pdata->netdev->dev_addr);
+
+ /* Filtering is done using perfect filtering and hash filtering */
+ if (pdata->hw_feat.hash_table_size) {
+ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1);
+ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1);
+ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 1);
+ }
}
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)
hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode;
hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode;
- hw_if->set_addn_mac_addrs = xgbe_set_addn_mac_addrs;
+ hw_if->add_mac_addresses = xgbe_add_mac_addresses;
hw_if->set_mac_address = xgbe_set_mac_address;
hw_if->enable_rx_csum = xgbe_enable_rx_csum;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 2acc37c07d9b..72dd61166a1c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -378,6 +378,21 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
hw_feat->pps_out_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, PPSOUTNUM);
hw_feat->aux_snap_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, AUXSNAPNUM);
+ /* Translate the Hash Table size into actual number */
+ switch (hw_feat->hash_table_size) {
+ case 0:
+ break;
+ case 1:
+ hw_feat->hash_table_size = 64;
+ break;
+ case 2:
+ hw_feat->hash_table_size = 128;
+ break;
+ case 3:
+ hw_feat->hash_table_size = 256;
+ break;
+ }
+
/* The Queue and Channel counts are zero based so increment them
* to get the actual number
*/
@@ -912,18 +927,10 @@ static void xgbe_set_rx_mode(struct net_device *netdev)
pr_mode = ((netdev->flags & IFF_PROMISC) != 0);
am_mode = ((netdev->flags & IFF_ALLMULTI) != 0);
- if (netdev_uc_count(netdev) > pdata->hw_feat.addn_mac)
- pr_mode = 1;
- if (netdev_mc_count(netdev) > pdata->hw_feat.addn_mac)
- am_mode = 1;
- if ((netdev_uc_count(netdev) + netdev_mc_count(netdev)) >
- pdata->hw_feat.addn_mac)
- pr_mode = 1;
-
hw_if->set_promiscuous_mode(pdata, pr_mode);
hw_if->set_all_multicast_mode(pdata, am_mode);
- if (!pr_mode)
- hw_if->set_addn_mac_addrs(pdata, am_mode);
+
+ hw_if->add_mac_addresses(pdata);
DBGPR("<--xgbe_set_rx_mode\n");
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index c3a48b7c2aed..b411ac557c47 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -397,6 +397,8 @@ static int xgbe_probe(struct platform_device *pdev)
netdev->features |= netdev->hw_features;
pdata->netdev_features = netdev->features;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
xgbe_init_rx_coalesce(pdata);
xgbe_init_tx_coalesce(pdata);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 3cb911f39b60..a2d5f5f5d8b7 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -191,6 +191,8 @@
/* Flow control queue count */
#define XGMAC_MAX_FLOW_CONTROL_QUEUES 8
+/* Maximum MAC address hash table size (256 bits = 8 bytes) */
+#define XGBE_MAC_HASH_TABLE_SIZE 8
struct xgbe_prv_data;
@@ -387,7 +389,7 @@ struct xgbe_hw_if {
int (*set_promiscuous_mode)(struct xgbe_prv_data *, unsigned int);
int (*set_all_multicast_mode)(struct xgbe_prv_data *, unsigned int);
- int (*set_addn_mac_addrs)(struct xgbe_prv_data *, unsigned int);
+ int (*add_mac_addresses)(struct xgbe_prv_data *);
int (*set_mac_address)(struct xgbe_prv_data *, u8 *addr);
int (*enable_rx_csum)(struct xgbe_prv_data *);