Since the offsets of the VLAN hash filter registers of ENETC v4 are
different from ENETC v1. Therefore, enetc_set_si_vlan_ht_filter() is
added to set the correct VLAN hash filter based on the SI ID and ENETC
revision, so that ENETC v4 PF driver can reuse enetc_vlan_rx_add_vid()
and enetc_vlan_rx_del_vid(). In addition, the VLAN promiscuous mode will
be enabled if VLAN filtering is disabled, which means that PF qualifies
for reception of all VLAN tags.

Signed-off-by: Wei Fang <wei.f...@nxp.com>
---
v5 changes
1. Remove set_si_vlan_hash_filter() hook
2. Refator enetc_set_vlan_ht_filter() and rename it to
enetc_set_si_vlan_ht_filter()
v6: no changes
---
 .../net/ethernet/freescale/enetc/enetc4_hw.h  |  4 +++
 .../net/ethernet/freescale/enetc/enetc4_pf.c  | 12 +++++++++
 .../freescale/enetc/enetc_pf_common.c         | 25 +++++++++++++------
 3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h 
b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index 826359004850..aa25b445d301 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -107,6 +107,10 @@
 #define ENETC4_PSIMMHFR0(a)            ((a) * 0x80 + 0x2058)
 #define ENETC4_PSIMMHFR1(a)            ((a) * 0x80 + 0x205c)
 
+/* Port station interface a VLAN hash filter register 0/1 */
+#define ENETC4_PSIVHFR0(a)             ((a) * 0x80 + 0x2060)
+#define ENETC4_PSIVHFR1(a)             ((a) * 0x80 + 0x2064)
+
 #define ENETC4_PMCAPR                  0x4004
 #define  PMCAPR_HD                     BIT(8)
 #define  PMCAPR_FP                     GENMASK(10, 9)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c 
b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 2d890f7bcc95..1f6500f12bbb 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -526,6 +526,16 @@ static void enetc4_pf_set_rx_mode(struct net_device *ndev)
 static int enetc4_pf_set_features(struct net_device *ndev,
                                  netdev_features_t features)
 {
+       netdev_features_t changed = ndev->features ^ features;
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct enetc_hw *hw = &priv->si->hw;
+
+       if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
+               bool promisc_en = !(features & NETIF_F_HW_VLAN_CTAG_FILTER);
+
+               enetc4_pf_set_si_vlan_promisc(hw, 0, promisc_en);
+       }
+
        enetc_set_features(ndev, features);
 
        return 0;
@@ -539,6 +549,8 @@ static const struct net_device_ops enetc4_ndev_ops = {
        .ndo_set_mac_address    = enetc_pf_set_mac_addr,
        .ndo_set_rx_mode        = enetc4_pf_set_rx_mode,
        .ndo_set_features       = enetc4_pf_set_features,
+       .ndo_vlan_rx_add_vid    = enetc_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = enetc_vlan_rx_del_vid,
 };
 
 static struct phylink_pcs *
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c 
b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index ed8afd174c9e..8c563e552021 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -135,7 +135,7 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct 
net_device *ndev,
 
        /* TODO: currently, i.MX95 ENETC driver does not support advanced 
features */
        if (!is_enetc_rev1(si)) {
-               ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | 
NETIF_F_LOOPBACK);
+               ndev->hw_features &= ~NETIF_F_LOOPBACK;
                goto end;
        }
 
@@ -376,11 +376,22 @@ static void enetc_refresh_vlan_ht_filter(struct enetc_pf 
*pf)
        }
 }
 
-static void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx,
-                                    unsigned long hash)
+static void enetc_set_si_vlan_ht_filter(struct enetc_si *si,
+                                       int si_id, u64 hash)
 {
-       enetc_port_wr(hw, ENETC_PSIVHFR0(si_idx), lower_32_bits(hash));
-       enetc_port_wr(hw, ENETC_PSIVHFR1(si_idx), upper_32_bits(hash));
+       struct enetc_hw *hw = &si->hw;
+       int high_reg_off, low_reg_off;
+
+       if (is_enetc_rev1(si)) {
+               low_reg_off = ENETC_PSIVHFR0(si_id);
+               high_reg_off = ENETC_PSIVHFR1(si_id);
+       } else {
+               low_reg_off = ENETC4_PSIVHFR0(si_id);
+               high_reg_off = ENETC4_PSIVHFR1(si_id);
+       }
+
+       enetc_port_wr(hw, low_reg_off, lower_32_bits(hash));
+       enetc_port_wr(hw, high_reg_off, upper_32_bits(hash));
 }
 
 int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
@@ -393,7 +404,7 @@ int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 
prot, u16 vid)
 
        idx = enetc_vid_hash_idx(vid);
        if (!__test_and_set_bit(idx, pf->vlan_ht_filter))
-               enetc_set_vlan_ht_filter(&pf->si->hw, 0, *pf->vlan_ht_filter);
+               enetc_set_si_vlan_ht_filter(pf->si, 0, *pf->vlan_ht_filter);
 
        return 0;
 }
@@ -406,7 +417,7 @@ int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 
prot, u16 vid)
 
        if (__test_and_clear_bit(vid, pf->active_vlans)) {
                enetc_refresh_vlan_ht_filter(pf);
-               enetc_set_vlan_ht_filter(&pf->si->hw, 0, *pf->vlan_ht_filter);
+               enetc_set_si_vlan_ht_filter(pf->si, 0, *pf->vlan_ht_filter);
        }
 
        return 0;
-- 
2.34.1


Reply via email to