net: enetc: add VLAN filtering support for i.MX95 ENETC PF

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.fang@nxp.com>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20250506080735.3444381-14-wei.fang@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Wei Fang
2025-05-06 16:07:34 +08:00
committed by Jakub Kicinski
parent 5d7f6f6836
commit f7d30ef6c1
3 changed files with 34 additions and 7 deletions

View File

@@ -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)

View File

@@ -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 *

View File

@@ -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;