Skip to content

Commit 801c62d

Browse files
tlendackydavem330
authored andcommitted
amd-xgbe: Add support for VLAN filtering
This patch adds support for (imperfect) filtering of VLAN tag ids using a 16-bit filter hash table. When VLANs are added, a 4-bit hash is calculated with the result indicating the bit in the hash table to set. This table is used by the hardware to drop packets with a VLAN id that does not hash to a set bit in the table. Signed-off-by: Tom Lendacky <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c52e9c6 commit 801c62d

File tree

6 files changed

+165
-14
lines changed

6 files changed

+165
-14
lines changed

drivers/net/ethernet/amd/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ config AMD_XGBE
182182
depends on OF_NET
183183
select PHYLIB
184184
select AMD_XGBE_PHY
185+
select BITREVERSE
185186
---help---
186187
This driver supports the AMD 10GbE Ethernet device found on an
187188
AMD SoC.

drivers/net/ethernet/amd/xgbe/xgbe-common.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@
393393
#define MAC_PFR_PM_WIDTH 1
394394
#define MAC_PFR_PR_INDEX 0
395395
#define MAC_PFR_PR_WIDTH 1
396+
#define MAC_PFR_VTFE_INDEX 16
397+
#define MAC_PFR_VTFE_WIDTH 1
396398
#define MAC_PMTCSR_MGKPKTEN_INDEX 1
397399
#define MAC_PMTCSR_MGKPKTEN_WIDTH 1
398400
#define MAC_PMTCSR_PWRDWN_INDEX 0
@@ -427,6 +429,8 @@
427429
#define MAC_TCR_SS_WIDTH 2
428430
#define MAC_TCR_TE_INDEX 0
429431
#define MAC_TCR_TE_WIDTH 1
432+
#define MAC_VLANHTR_VLHT_INDEX 0
433+
#define MAC_VLANHTR_VLHT_WIDTH 16
430434
#define MAC_VLANIR_VLTI_INDEX 20
431435
#define MAC_VLANIR_VLTI_WIDTH 1
432436
#define MAC_VLANIR_CSVL_INDEX 19
@@ -437,10 +441,18 @@
437441
#define MAC_VLANTR_ERSVLM_WIDTH 1
438442
#define MAC_VLANTR_ESVL_INDEX 18
439443
#define MAC_VLANTR_ESVL_WIDTH 1
444+
#define MAC_VLANTR_ETV_INDEX 16
445+
#define MAC_VLANTR_ETV_WIDTH 1
440446
#define MAC_VLANTR_EVLS_INDEX 21
441447
#define MAC_VLANTR_EVLS_WIDTH 2
442448
#define MAC_VLANTR_EVLRXS_INDEX 24
443449
#define MAC_VLANTR_EVLRXS_WIDTH 1
450+
#define MAC_VLANTR_VL_INDEX 0
451+
#define MAC_VLANTR_VL_WIDTH 16
452+
#define MAC_VLANTR_VTHM_INDEX 25
453+
#define MAC_VLANTR_VTHM_WIDTH 1
454+
#define MAC_VLANTR_VTIM_INDEX 17
455+
#define MAC_VLANTR_VTIM_WIDTH 1
444456
#define MAC_VR_DEVID_INDEX 8
445457
#define MAC_VR_DEVID_WIDTH 8
446458
#define MAC_VR_SNPSVER_INDEX 0

drivers/net/ethernet/amd/xgbe/xgbe-dev.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116

117117
#include <linux/phy.h>
118118
#include <linux/clk.h>
119+
#include <linux/bitrev.h>
119120

120121
#include "xgbe.h"
121122
#include "xgbe-common.h"
@@ -738,6 +739,89 @@ static int xgbe_disable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
738739
return 0;
739740
}
740741

742+
static int xgbe_enable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
743+
{
744+
/* Enable VLAN filtering */
745+
XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1);
746+
747+
/* Enable VLAN Hash Table filtering */
748+
XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTHM, 1);
749+
750+
/* Disable VLAN tag inverse matching */
751+
XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTIM, 0);
752+
753+
/* Only filter on the lower 12-bits of the VLAN tag */
754+
XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ETV, 1);
755+
756+
/* In order for the VLAN Hash Table filtering to be effective,
757+
* the VLAN tag identifier in the VLAN Tag Register must not
758+
* be zero. Set the VLAN tag identifier to "1" to enable the
759+
* VLAN Hash Table filtering. This implies that a VLAN tag of
760+
* 1 will always pass filtering.
761+
*/
762+
XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VL, 1);
763+
764+
return 0;
765+
}
766+
767+
static int xgbe_disable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
768+
{
769+
/* Disable VLAN filtering */
770+
XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0);
771+
772+
return 0;
773+
}
774+
775+
#ifndef CRCPOLY_LE
776+
#define CRCPOLY_LE 0xedb88320
777+
#endif
778+
static u32 xgbe_vid_crc32_le(__le16 vid_le)
779+
{
780+
u32 poly = CRCPOLY_LE;
781+
u32 crc = ~0;
782+
u32 temp = 0;
783+
unsigned char *data = (unsigned char *)&vid_le;
784+
unsigned char data_byte = 0;
785+
int i, bits;
786+
787+
bits = get_bitmask_order(VLAN_VID_MASK);
788+
for (i = 0; i < bits; i++) {
789+
if ((i % 8) == 0)
790+
data_byte = data[i / 8];
791+
792+
temp = ((crc & 1) ^ data_byte) & 1;
793+
crc >>= 1;
794+
data_byte >>= 1;
795+
796+
if (temp)
797+
crc ^= poly;
798+
}
799+
800+
return crc;
801+
}
802+
803+
static int xgbe_update_vlan_hash_table(struct xgbe_prv_data *pdata)
804+
{
805+
u32 crc;
806+
u16 vid;
807+
__le16 vid_le;
808+
u16 vlan_hash_table = 0;
809+
810+
/* Generate the VLAN Hash Table value */
811+
for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) {
812+
/* Get the CRC32 value of the VLAN ID */
813+
vid_le = cpu_to_le16(vid);
814+
crc = bitrev32(~xgbe_vid_crc32_le(vid_le)) >> 28;
815+
816+
vlan_hash_table |= (1 << crc);
817+
}
818+
819+
/* Set the VLAN Hash Table filtering register */
820+
XGMAC_IOWRITE_BITS(pdata, MAC_VLANHTR, VLHT, vlan_hash_table);
821+
822+
return 0;
823+
}
824+
741825
static void xgbe_tx_desc_reset(struct xgbe_ring_data *rdata)
742826
{
743827
struct xgbe_ring_desc *rdesc = rdata->rdesc;
@@ -1547,6 +1631,14 @@ static void xgbe_config_vlan_support(struct xgbe_prv_data *pdata)
15471631
XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, CSVL, 0);
15481632
XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, VLTI, 1);
15491633

1634+
/* Set the current VLAN Hash Table register value */
1635+
xgbe_update_vlan_hash_table(pdata);
1636+
1637+
if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
1638+
xgbe_enable_rx_vlan_filtering(pdata);
1639+
else
1640+
xgbe_disable_rx_vlan_filtering(pdata);
1641+
15501642
if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
15511643
xgbe_enable_rx_vlan_stripping(pdata);
15521644
else
@@ -2118,6 +2210,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
21182210

21192211
hw_if->enable_rx_vlan_stripping = xgbe_enable_rx_vlan_stripping;
21202212
hw_if->disable_rx_vlan_stripping = xgbe_disable_rx_vlan_stripping;
2213+
hw_if->enable_rx_vlan_filtering = xgbe_enable_rx_vlan_filtering;
2214+
hw_if->disable_rx_vlan_filtering = xgbe_disable_rx_vlan_filtering;
2215+
hw_if->update_vlan_hash_table = xgbe_update_vlan_hash_table;
21212216

21222217
hw_if->read_mmd_regs = xgbe_read_mmd_regs;
21232218
hw_if->write_mmd_regs = xgbe_write_mmd_regs;

drivers/net/ethernet/amd/xgbe/xgbe-drv.c

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,38 @@ static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev,
10001000
return s;
10011001
}
10021002

1003+
static int xgbe_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
1004+
u16 vid)
1005+
{
1006+
struct xgbe_prv_data *pdata = netdev_priv(netdev);
1007+
struct xgbe_hw_if *hw_if = &pdata->hw_if;
1008+
1009+
DBGPR("-->%s\n", __func__);
1010+
1011+
set_bit(vid, pdata->active_vlans);
1012+
hw_if->update_vlan_hash_table(pdata);
1013+
1014+
DBGPR("<--%s\n", __func__);
1015+
1016+
return 0;
1017+
}
1018+
1019+
static int xgbe_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
1020+
u16 vid)
1021+
{
1022+
struct xgbe_prv_data *pdata = netdev_priv(netdev);
1023+
struct xgbe_hw_if *hw_if = &pdata->hw_if;
1024+
1025+
DBGPR("-->%s\n", __func__);
1026+
1027+
clear_bit(vid, pdata->active_vlans);
1028+
hw_if->update_vlan_hash_table(pdata);
1029+
1030+
DBGPR("<--%s\n", __func__);
1031+
1032+
return 0;
1033+
}
1034+
10031035
#ifdef CONFIG_NET_POLL_CONTROLLER
10041036
static void xgbe_poll_controller(struct net_device *netdev)
10051037
{
@@ -1022,26 +1054,26 @@ static int xgbe_set_features(struct net_device *netdev,
10221054
{
10231055
struct xgbe_prv_data *pdata = netdev_priv(netdev);
10241056
struct xgbe_hw_if *hw_if = &pdata->hw_if;
1025-
unsigned int rxcsum_enabled, rxvlan_enabled;
1057+
unsigned int rxcsum, rxvlan, rxvlan_filter;
10261058

1027-
rxcsum_enabled = !!(pdata->netdev_features & NETIF_F_RXCSUM);
1028-
rxvlan_enabled = !!(pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX);
1059+
rxcsum = pdata->netdev_features & NETIF_F_RXCSUM;
1060+
rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX;
1061+
rxvlan_filter = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER;
10291062

1030-
if ((features & NETIF_F_RXCSUM) && !rxcsum_enabled) {
1063+
if ((features & NETIF_F_RXCSUM) && !rxcsum)
10311064
hw_if->enable_rx_csum(pdata);
1032-
netdev_alert(netdev, "state change - rxcsum enabled\n");
1033-
} else if (!(features & NETIF_F_RXCSUM) && rxcsum_enabled) {
1065+
else if (!(features & NETIF_F_RXCSUM) && rxcsum)
10341066
hw_if->disable_rx_csum(pdata);
1035-
netdev_alert(netdev, "state change - rxcsum disabled\n");
1036-
}
10371067

1038-
if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan_enabled) {
1068+
if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan)
10391069
hw_if->enable_rx_vlan_stripping(pdata);
1040-
netdev_alert(netdev, "state change - rxvlan enabled\n");
1041-
} else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && rxvlan_enabled) {
1070+
else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && rxvlan)
10421071
hw_if->disable_rx_vlan_stripping(pdata);
1043-
netdev_alert(netdev, "state change - rxvlan disabled\n");
1044-
}
1072+
1073+
if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && !rxvlan_filter)
1074+
hw_if->enable_rx_vlan_filtering(pdata);
1075+
else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && rxvlan_filter)
1076+
hw_if->disable_rx_vlan_filtering(pdata);
10451077

10461078
pdata->netdev_features = features;
10471079

@@ -1059,6 +1091,8 @@ static const struct net_device_ops xgbe_netdev_ops = {
10591091
.ndo_validate_addr = eth_validate_addr,
10601092
.ndo_change_mtu = xgbe_change_mtu,
10611093
.ndo_get_stats64 = xgbe_get_stats64,
1094+
.ndo_vlan_rx_add_vid = xgbe_vlan_rx_add_vid,
1095+
.ndo_vlan_rx_kill_vid = xgbe_vlan_rx_kill_vid,
10621096
#ifdef CONFIG_NET_POLL_CONTROLLER
10631097
.ndo_poll_controller = xgbe_poll_controller,
10641098
#endif

drivers/net/ethernet/amd/xgbe/xgbe-main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,8 @@ static int xgbe_probe(struct platform_device *pdev)
385385
NETIF_F_TSO6 |
386386
NETIF_F_GRO |
387387
NETIF_F_HW_VLAN_CTAG_RX |
388-
NETIF_F_HW_VLAN_CTAG_TX;
388+
NETIF_F_HW_VLAN_CTAG_TX |
389+
NETIF_F_HW_VLAN_CTAG_FILTER;
389390

390391
netdev->vlan_features |= NETIF_F_SG |
391392
NETIF_F_IP_CSUM |

drivers/net/ethernet/amd/xgbe/xgbe.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@
121121
#include <linux/netdevice.h>
122122
#include <linux/workqueue.h>
123123
#include <linux/phy.h>
124+
#include <linux/if_vlan.h>
125+
#include <linux/bitops.h>
124126

125127

126128
#define XGBE_DRV_NAME "amd-xgbe"
@@ -393,6 +395,9 @@ struct xgbe_hw_if {
393395

394396
int (*enable_rx_vlan_stripping)(struct xgbe_prv_data *);
395397
int (*disable_rx_vlan_stripping)(struct xgbe_prv_data *);
398+
int (*enable_rx_vlan_filtering)(struct xgbe_prv_data *);
399+
int (*disable_rx_vlan_filtering)(struct xgbe_prv_data *);
400+
int (*update_vlan_hash_table)(struct xgbe_prv_data *);
396401

397402
int (*read_mmd_regs)(struct xgbe_prv_data *, int, int);
398403
void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int);
@@ -588,6 +593,9 @@ struct xgbe_prv_data {
588593
struct napi_struct napi;
589594
struct xgbe_mmc_stats mmc_stats;
590595

596+
/* Filtering support */
597+
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
598+
591599
/* System clock value used for Rx watchdog */
592600
struct clk *sysclock;
593601

0 commit comments

Comments
 (0)