Commit 0b28182c authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'refactoring-designware-vlan-code'

Boon Khai Ng says:

====================
Refactoring designware VLAN code.

Refactoring designware VLAN code and introducing support for
hardware-accelerated VLAN stripping for dwxgmac2 IP,
the current patch set consists of two key changes:

1) Refactoring VLAN Functions:
The first change involves moving common VLAN-related functions
of the DesignWare Ethernet MAC into a dedicated file, stmmac_vlan.c.
This refactoring aims to improve code organization and maintainability
by centralizing VLAN handling logic.

2) Renaming all the functions, symbols and macro into more
generic name and consolidate the same function pointer into one.

3) Enabling VLAN for 10G Ethernet MAC IP:
The second change enables VLAN support specifically
for the 10G Ethernet MAC IP. This enhancement leverages
the hardware capabilities of the to perform VLAN stripping,

Changes from previous submmited patches.
v5:
a) Divided the refactor patch in to two patches,
first patch is to move the code into the separate file
and second patch to update the symbol name

b) get the dwmac4 vlan function up to date and port to
stmmac_vlan.c

c) remove the inline function in function pointer and
use only static function defeination.

d) Remove the outer parenthese that is not needed
on the 1 line return statement.

v4:
a) Updated the commit message to explain the descriptors
behaviour on different hardware.

b) Updated the perfect_match variable with the correct
byte order.

Link: https://lore.kernel.org/20250421162930.10237-1-boon.khai.ng@altera.com

v3: https://lore.kernel.org/20250408081354.25881-1-boon.khai.ng@altera.com
v2: https://lore.kernel.org/BL3PR11MB5748AC693D9D61FB56DB7313C1F32@BL3PR11MB5748.namprd11.prod.outlook.com
v1: https://lore.kernel.org/DM8PR11MB5751E5388AEFCFB80BCB483FC13FA@DM8PR11MB5751.namprd11.prod.outlook.com
====================

Link: https://patch.msgid.link/20250507063812.34000-1-boon.khai.ng@altera.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 6a63b015 534df0c1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
	      mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o	\
	      dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
	      stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
	      stmmac_xdp.o stmmac_est.o stmmac_fpe.o \
	      stmmac_xdp.o stmmac_est.o stmmac_fpe.o stmmac_vlan.o \
	      $(stmmac-y)

stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
+1 −0
Original line number Diff line number Diff line
@@ -602,6 +602,7 @@ struct mac_device_info {
	const struct stmmac_tc_ops *tc;
	const struct stmmac_mmc_ops *mmc;
	const struct stmmac_est_ops *est;
	const struct stmmac_vlan_ops *vlan;
	struct dw_xpcs *xpcs;
	struct phylink_pcs *phylink_pcs;
	struct mii_regs mii;	/* MII register Addresses */
+0 −40
Original line number Diff line number Diff line
@@ -17,11 +17,7 @@
#define GMAC_EXT_CONFIG			0x00000004
#define GMAC_PACKET_FILTER		0x00000008
#define GMAC_HASH_TAB(x)		(0x10 + (x) * 4)
#define GMAC_VLAN_TAG			0x00000050
#define GMAC_VLAN_TAG_DATA		0x00000054
#define GMAC_VLAN_HASH_TABLE		0x00000058
#define GMAC_RX_FLOW_CTRL		0x00000090
#define GMAC_VLAN_INCL			0x00000060
#define GMAC_QX_TX_FLOW_CTRL(x)		(0x70 + x * 4)
#define GMAC_TXQ_PRTY_MAP0		0x98
#define GMAC_TXQ_PRTY_MAP1		0x9C
@@ -81,42 +77,6 @@

#define GMAC_MAX_PERFECT_ADDRESSES	128

/* MAC VLAN */
#define GMAC_VLAN_EDVLP			BIT(26)
#define GMAC_VLAN_VTHM			BIT(25)
#define GMAC_VLAN_DOVLTC		BIT(20)
#define GMAC_VLAN_ESVL			BIT(18)
#define GMAC_VLAN_ETV			BIT(16)
#define GMAC_VLAN_VID			GENMASK(15, 0)
#define GMAC_VLAN_VLTI			BIT(20)
#define GMAC_VLAN_CSVL			BIT(19)
#define GMAC_VLAN_VLC			GENMASK(17, 16)
#define GMAC_VLAN_VLC_SHIFT		16
#define GMAC_VLAN_VLHT			GENMASK(15, 0)

/* MAC VLAN Tag */
#define GMAC_VLAN_TAG_VID		GENMASK(15, 0)
#define GMAC_VLAN_TAG_ETV		BIT(16)

/* MAC VLAN Tag Control */
#define GMAC_VLAN_TAG_CTRL_OB		BIT(0)
#define GMAC_VLAN_TAG_CTRL_CT		BIT(1)
#define GMAC_VLAN_TAG_CTRL_OFS_MASK	GENMASK(6, 2)
#define GMAC_VLAN_TAG_CTRL_OFS_SHIFT	2
#define GMAC_VLAN_TAG_CTRL_EVLS_MASK	GENMASK(22, 21)
#define GMAC_VLAN_TAG_CTRL_EVLS_SHIFT	21
#define GMAC_VLAN_TAG_CTRL_EVLRXS	BIT(24)

#define GMAC_VLAN_TAG_STRIP_NONE	(0x0 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
#define GMAC_VLAN_TAG_STRIP_PASS	(0x1 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
#define GMAC_VLAN_TAG_STRIP_FAIL	(0x2 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
#define GMAC_VLAN_TAG_STRIP_ALL		(0x3 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)

/* MAC VLAN Tag Data/Filter */
#define GMAC_VLAN_TAG_DATA_VID		GENMASK(15, 0)
#define GMAC_VLAN_TAG_DATA_VEN		BIT(16)
#define GMAC_VLAN_TAG_DATA_ETV		BIT(17)

/* MAC RX Queue Enable */
#define GMAC_RX_QUEUE_CLEAR(queue)	~(GENMASK(1, 0) << ((queue) * 2))
#define GMAC_RX_AV_QUEUE_ENABLE(queue)	BIT((queue) * 2)
+2 −293
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "stmmac.h"
#include "stmmac_fpe.h"
#include "stmmac_pcs.h"
#include "stmmac_vlan.h"
#include "dwmac4.h"
#include "dwmac5.h"

@@ -448,165 +449,6 @@ static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
	writel(value, ioaddr + GMAC4_LPI_TIMER_CTRL);
}

static void dwmac4_write_single_vlan(struct net_device *dev, u16 vid)
{
	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
	u32 val;

	val = readl(ioaddr + GMAC_VLAN_TAG);
	val &= ~GMAC_VLAN_TAG_VID;
	val |= GMAC_VLAN_TAG_ETV | vid;

	writel(val, ioaddr + GMAC_VLAN_TAG);
}

static int dwmac4_write_vlan_filter(struct net_device *dev,
				    struct mac_device_info *hw,
				    u8 index, u32 data)
{
	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
	int ret;
	u32 val;

	if (index >= hw->num_vlan)
		return -EINVAL;

	writel(data, ioaddr + GMAC_VLAN_TAG_DATA);

	val = readl(ioaddr + GMAC_VLAN_TAG);
	val &= ~(GMAC_VLAN_TAG_CTRL_OFS_MASK |
		GMAC_VLAN_TAG_CTRL_CT |
		GMAC_VLAN_TAG_CTRL_OB);
	val |= (index << GMAC_VLAN_TAG_CTRL_OFS_SHIFT) | GMAC_VLAN_TAG_CTRL_OB;

	writel(val, ioaddr + GMAC_VLAN_TAG);

	ret = readl_poll_timeout(ioaddr + GMAC_VLAN_TAG, val,
				 !(val & GMAC_VLAN_TAG_CTRL_OB),
				 1000, 500000);
	if (ret) {
		netdev_err(dev, "Timeout accessing MAC_VLAN_Tag_Filter\n");
		return -EBUSY;
	}

	return 0;
}

static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev,
				      struct mac_device_info *hw,
				      __be16 proto, u16 vid)
{
	int index = -1;
	u32 val = 0;
	int i, ret;

	if (vid > 4095)
		return -EINVAL;

	/* Single Rx VLAN Filter */
	if (hw->num_vlan == 1) {
		/* For single VLAN filter, VID 0 means VLAN promiscuous */
		if (vid == 0) {
			netdev_warn(dev, "Adding VLAN ID 0 is not supported\n");
			return -EPERM;
		}

		if (hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) {
			netdev_err(dev, "Only single VLAN ID supported\n");
			return -EPERM;
		}

		hw->vlan_filter[0] = vid;
		dwmac4_write_single_vlan(dev, vid);

		return 0;
	}

	/* Extended Rx VLAN Filter Enable */
	val |= GMAC_VLAN_TAG_DATA_ETV | GMAC_VLAN_TAG_DATA_VEN | vid;

	for (i = 0; i < hw->num_vlan; i++) {
		if (hw->vlan_filter[i] == val)
			return 0;
		else if (!(hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN))
			index = i;
	}

	if (index == -1) {
		netdev_err(dev, "MAC_VLAN_Tag_Filter full (size: %0u)\n",
			   hw->num_vlan);
		return -EPERM;
	}

	ret = dwmac4_write_vlan_filter(dev, hw, index, val);

	if (!ret)
		hw->vlan_filter[index] = val;

	return ret;
}

static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev,
				      struct mac_device_info *hw,
				      __be16 proto, u16 vid)
{
	int i, ret = 0;

	/* Single Rx VLAN Filter */
	if (hw->num_vlan == 1) {
		if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) {
			hw->vlan_filter[0] = 0;
			dwmac4_write_single_vlan(dev, 0);
		}
		return 0;
	}

	/* Extended Rx VLAN Filter Enable */
	for (i = 0; i < hw->num_vlan; i++) {
		if ((hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VID) == vid) {
			ret = dwmac4_write_vlan_filter(dev, hw, i, 0);

			if (!ret)
				hw->vlan_filter[i] = 0;
			else
				return ret;
		}
	}

	return ret;
}

static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev,
					   struct mac_device_info *hw)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;
	u32 hash;
	u32 val;
	int i;

	/* Single Rx VLAN Filter */
	if (hw->num_vlan == 1) {
		dwmac4_write_single_vlan(dev, hw->vlan_filter[0]);
		return;
	}

	/* Extended Rx VLAN Filter Enable */
	for (i = 0; i < hw->num_vlan; i++) {
		if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) {
			val = hw->vlan_filter[i];
			dwmac4_write_vlan_filter(dev, hw, i, val);
		}
	}

	hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE);
	if (hash & GMAC_VLAN_VLHT) {
		value = readl(ioaddr + GMAC_VLAN_TAG);
		value |= GMAC_VLAN_VTHM;
		writel(value, ioaddr + GMAC_VLAN_TAG);
	}
}

static void dwmac4_set_filter(struct mac_device_info *hw,
			      struct net_device *dev)
{
@@ -965,45 +807,6 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, bool enable)
	writel(value, ioaddr + GMAC_CONFIG);
}

static void dwmac4_update_vlan_hash(struct mac_device_info *hw, u32 hash,
				    u16 perfect_match, bool is_double)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;

	writel(hash, ioaddr + GMAC_VLAN_HASH_TABLE);

	value = readl(ioaddr + GMAC_VLAN_TAG);

	if (hash) {
		value |= GMAC_VLAN_VTHM | GMAC_VLAN_ETV;
		if (is_double) {
			value |= GMAC_VLAN_EDVLP;
			value |= GMAC_VLAN_ESVL;
			value |= GMAC_VLAN_DOVLTC;
		}

		writel(value, ioaddr + GMAC_VLAN_TAG);
	} else if (perfect_match) {
		u32 value = GMAC_VLAN_ETV;

		if (is_double) {
			value |= GMAC_VLAN_EDVLP;
			value |= GMAC_VLAN_ESVL;
			value |= GMAC_VLAN_DOVLTC;
		}

		writel(value | perfect_match, ioaddr + GMAC_VLAN_TAG);
	} else {
		value &= ~(GMAC_VLAN_VTHM | GMAC_VLAN_ETV);
		value &= ~(GMAC_VLAN_EDVLP | GMAC_VLAN_ESVL);
		value &= ~GMAC_VLAN_DOVLTC;
		value &= ~GMAC_VLAN_VID;

		writel(value, ioaddr + GMAC_VLAN_TAG);
	}
}

static void dwmac4_sarc_configure(void __iomem *ioaddr, int val)
{
	u32 value = readl(ioaddr + GMAC_CONFIG);
@@ -1014,19 +817,6 @@ static void dwmac4_sarc_configure(void __iomem *ioaddr, int val)
	writel(value, ioaddr + GMAC_CONFIG);
}

static void dwmac4_enable_vlan(struct mac_device_info *hw, u32 type)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;

	value = readl(ioaddr + GMAC_VLAN_INCL);
	value |= GMAC_VLAN_VLTI;
	value |= GMAC_VLAN_CSVL; /* Only use SVLAN */
	value &= ~GMAC_VLAN_VLC;
	value |= (type << GMAC_VLAN_VLC_SHIFT) & GMAC_VLAN_VLC;
	writel(value, ioaddr + GMAC_VLAN_INCL);
}

static void dwmac4_set_arp_offload(struct mac_device_info *hw, bool en,
				   u32 addr)
{
@@ -1143,35 +933,6 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
	return 0;
}

static void dwmac4_rx_hw_vlan(struct mac_device_info *hw,
			      struct dma_desc *rx_desc, struct sk_buff *skb)
{
	if (hw->desc->get_rx_vlan_valid(rx_desc)) {
		u16 vid = hw->desc->get_rx_vlan_tci(rx_desc);

		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
	}
}

static void dwmac4_set_hw_vlan_mode(struct mac_device_info *hw)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value = readl(ioaddr + GMAC_VLAN_TAG);

	value &= ~GMAC_VLAN_TAG_CTRL_EVLS_MASK;

	if (hw->hw_vlan_en)
		/* Always strip VLAN on Receive */
		value |= GMAC_VLAN_TAG_STRIP_ALL;
	else
		/* Do not strip VLAN on Receive */
		value |= GMAC_VLAN_TAG_STRIP_NONE;

	/* Enable outer VLAN Tag in Rx DMA descriptor */
	value |= GMAC_VLAN_TAG_CTRL_EVLRXS;
	writel(value, ioaddr + GMAC_VLAN_TAG);
}

const struct stmmac_ops dwmac4_ops = {
	.core_init = dwmac4_core_init,
	.update_caps = dwmac4_update_caps,
@@ -1201,17 +962,10 @@ const struct stmmac_ops dwmac4_ops = {
	.debug = dwmac4_debug,
	.set_filter = dwmac4_set_filter,
	.set_mac_loopback = dwmac4_set_mac_loopback,
	.update_vlan_hash = dwmac4_update_vlan_hash,
	.sarc_configure = dwmac4_sarc_configure,
	.enable_vlan = dwmac4_enable_vlan,
	.set_arp_offload = dwmac4_set_arp_offload,
	.config_l3_filter = dwmac4_config_l3_filter,
	.config_l4_filter = dwmac4_config_l4_filter,
	.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
	.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
	.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
	.rx_hw_vlan = dwmac4_rx_hw_vlan,
	.set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
};

const struct stmmac_ops dwmac410_ops = {
@@ -1244,18 +998,11 @@ const struct stmmac_ops dwmac410_ops = {
	.set_filter = dwmac4_set_filter,
	.flex_pps_config = dwmac5_flex_pps_config,
	.set_mac_loopback = dwmac4_set_mac_loopback,
	.update_vlan_hash = dwmac4_update_vlan_hash,
	.sarc_configure = dwmac4_sarc_configure,
	.enable_vlan = dwmac4_enable_vlan,
	.set_arp_offload = dwmac4_set_arp_offload,
	.config_l3_filter = dwmac4_config_l3_filter,
	.config_l4_filter = dwmac4_config_l4_filter,
	.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
	.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
	.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
	.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
	.rx_hw_vlan = dwmac4_rx_hw_vlan,
	.set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
};

const struct stmmac_ops dwmac510_ops = {
@@ -1292,51 +1039,13 @@ const struct stmmac_ops dwmac510_ops = {
	.rxp_config = dwmac5_rxp_config,
	.flex_pps_config = dwmac5_flex_pps_config,
	.set_mac_loopback = dwmac4_set_mac_loopback,
	.update_vlan_hash = dwmac4_update_vlan_hash,
	.sarc_configure = dwmac4_sarc_configure,
	.enable_vlan = dwmac4_enable_vlan,
	.set_arp_offload = dwmac4_set_arp_offload,
	.config_l3_filter = dwmac4_config_l3_filter,
	.config_l4_filter = dwmac4_config_l4_filter,
	.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
	.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
	.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
	.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
	.rx_hw_vlan = dwmac4_rx_hw_vlan,
	.set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
};

static u32 dwmac4_get_num_vlan(void __iomem *ioaddr)
{
	u32 val, num_vlan;

	val = readl(ioaddr + GMAC_HW_FEATURE3);
	switch (val & GMAC_HW_FEAT_NRVF) {
	case 0:
		num_vlan = 1;
		break;
	case 1:
		num_vlan = 4;
		break;
	case 2:
		num_vlan = 8;
		break;
	case 3:
		num_vlan = 16;
		break;
	case 4:
		num_vlan = 24;
		break;
	case 5:
		num_vlan = 32;
		break;
	default:
		num_vlan = 1;
	}

	return num_vlan;
}

int dwmac4_setup(struct stmmac_priv *priv)
{
	struct mac_device_info *mac = priv->hw;
@@ -1368,7 +1077,7 @@ int dwmac4_setup(struct stmmac_priv *priv)
	mac->mii.reg_mask = GENMASK(20, 16);
	mac->mii.clk_csr_shift = 8;
	mac->mii.clk_csr_mask = GENMASK(11, 8);
	mac->num_vlan = dwmac4_get_num_vlan(priv->ioaddr);
	mac->num_vlan = stmmac_get_num_vlan(priv->ioaddr);

	return 0;
}
+12 −13
Original line number Diff line number Diff line
@@ -57,19 +57,6 @@
#define XGMAC_FILTER_PR			BIT(0)
#define XGMAC_HASH_TABLE(x)		(0x00000010 + (x) * 4)
#define XGMAC_MAX_HASH_TABLE		8
#define XGMAC_VLAN_TAG			0x00000050
#define XGMAC_VLAN_EDVLP		BIT(26)
#define XGMAC_VLAN_VTHM			BIT(25)
#define XGMAC_VLAN_DOVLTC		BIT(20)
#define XGMAC_VLAN_ESVL			BIT(18)
#define XGMAC_VLAN_ETV			BIT(16)
#define XGMAC_VLAN_VID			GENMASK(15, 0)
#define XGMAC_VLAN_HASH_TABLE		0x00000058
#define XGMAC_VLAN_INCL			0x00000060
#define XGMAC_VLAN_VLTI			BIT(20)
#define XGMAC_VLAN_CSVL			BIT(19)
#define XGMAC_VLAN_VLC			GENMASK(17, 16)
#define XGMAC_VLAN_VLC_SHIFT		16
#define XGMAC_RXQ_CTRL0			0x000000a0
#define XGMAC_RXQEN(x)			GENMASK((x) * 2 + 1, (x) * 2)
#define XGMAC_RXQEN_SHIFT(x)		((x) * 2)
@@ -477,6 +464,7 @@
#define XGMAC_RDES3_RSV			BIT(26)
#define XGMAC_RDES3_L34T		GENMASK(23, 20)
#define XGMAC_RDES3_L34T_SHIFT		20
#define XGMAC_RDES3_ET_LT		GENMASK(19, 16)
#define XGMAC_L34T_IP4TCP		0x1
#define XGMAC_L34T_IP4UDP		0x2
#define XGMAC_L34T_IP6TCP		0x9
@@ -486,6 +474,17 @@
#define XGMAC_RDES3_TSD			BIT(6)
#define XGMAC_RDES3_TSA			BIT(4)

/* RDES0 (write back format) */
#define XGMAC_RDES0_VLAN_TAG_MASK	GENMASK(15, 0)

/* Error Type or L2 Type(ET/LT) Field Number */
#define XGMAC_ET_LT_VLAN_STAG		8
#define XGMAC_ET_LT_VLAN_CTAG		9
#define XGMAC_ET_LT_DVLAN_CTAG_CTAG	10
#define XGMAC_ET_LT_DVLAN_STAG_STAG	11
#define XGMAC_ET_LT_DVLAN_CTAG_STAG	12
#define XGMAC_ET_LT_DVLAN_STAG_CTAG	13

extern const struct stmmac_ops dwxgmac210_ops;
extern const struct stmmac_ops dwxlgmac2_ops;
extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
Loading