Commit f7d30ef6 authored by Wei Fang's avatar Wei Fang Committed by Jakub Kicinski
Browse files

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: default avatarWei Fang <wei.fang@nxp.com>
Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20250506080735.3444381-14-wei.fang@nxp.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5d7f6f68
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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)
+12 −0
Original line number Diff line number Diff line
@@ -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 *
+18 −7
Original line number Diff line number Diff line
@@ -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;