Commit 425eabdd authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller
Browse files

net: stmmac: Implement L3/L4 Filters using TC Flower



Implement filters for Layer 3 and Layer 4 using TC Flower API. Add the
corresponding callbacks in XGMAC core.

Signed-off-by: default avatarJose Abreu <joabreu@synopsys.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c104891c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -360,6 +360,7 @@ struct dma_features {
	unsigned int sphen;
	unsigned int vlins;
	unsigned int dvlan;
	unsigned int l3l4fnum;
};

/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
+30 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#define XGMAC_CORE_INIT_RX		0
#define XGMAC_PACKET_FILTER		0x00000008
#define XGMAC_FILTER_RA			BIT(31)
#define XGMAC_FILTER_IPFE		BIT(20)
#define XGMAC_FILTER_VTFE		BIT(16)
#define XGMAC_FILTER_HPF		BIT(10)
#define XGMAC_FILTER_PCF		BIT(7)
@@ -119,6 +120,7 @@
#define XGMAC_HWFEAT_VLHASH		BIT(4)
#define XGMAC_HWFEAT_GMIISEL		BIT(1)
#define XGMAC_HW_FEATURE1		0x00000120
#define XGMAC_HWFEAT_L3L4FNUM		GENMASK(30, 27)
#define XGMAC_HWFEAT_RSSEN		BIT(20)
#define XGMAC_HWFEAT_TSOEN		BIT(18)
#define XGMAC_HWFEAT_SPHEN		BIT(17)
@@ -150,6 +152,34 @@
#define XGMAC_DCS			GENMASK(19, 16)
#define XGMAC_DCS_SHIFT			16
#define XGMAC_ADDRx_LOW(x)		(0x00000304 + (x) * 0x8)
#define XGMAC_L3L4_ADDR_CTRL		0x00000c00
#define XGMAC_IDDR			GENMASK(15, 8)
#define XGMAC_IDDR_SHIFT		8
#define XGMAC_IDDR_FNUM			4
#define XGMAC_TT			BIT(1)
#define XGMAC_XB			BIT(0)
#define XGMAC_L3L4_DATA			0x00000c04
#define XGMAC_L3L4_CTRL			0x0
#define XGMAC_L4DPIM0			BIT(21)
#define XGMAC_L4DPM0			BIT(20)
#define XGMAC_L4SPIM0			BIT(19)
#define XGMAC_L4SPM0			BIT(18)
#define XGMAC_L4PEN0			BIT(16)
#define XGMAC_L3HDBM0			GENMASK(15, 11)
#define XGMAC_L3HSBM0			GENMASK(10, 6)
#define XGMAC_L3DAIM0			BIT(5)
#define XGMAC_L3DAM0			BIT(4)
#define XGMAC_L3SAIM0			BIT(3)
#define XGMAC_L3SAM0			BIT(2)
#define XGMAC_L3PEN0			BIT(0)
#define XGMAC_L4_ADDR			0x1
#define XGMAC_L4DP0			GENMASK(31, 16)
#define XGMAC_L4DP0_SHIFT		16
#define XGMAC_L4SP0			GENMASK(15, 0)
#define XGMAC_L3_ADDR0			0x4
#define XGMAC_L3_ADDR1			0x5
#define XGMAC_L3_ADDR2			0x6
#define XMGAC_L3_ADDR3			0x7
#define XGMAC_ARP_ADDR			0x00000c10
#define XGMAC_RSS_CTRL			0x00000c80
#define XGMAC_UDP4TE			BIT(3)
+177 −0
Original line number Diff line number Diff line
@@ -1163,6 +1163,181 @@ static void dwxgmac2_enable_vlan(struct mac_device_info *hw, u32 type)
	writel(value, ioaddr + XGMAC_VLAN_INCL);
}

static int dwxgmac2_filter_wait(struct mac_device_info *hw)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;

	if (readl_poll_timeout(ioaddr + XGMAC_L3L4_ADDR_CTRL, value,
			       !(value & XGMAC_XB), 100, 10000))
		return -EBUSY;
	return 0;
}

static int dwxgmac2_filter_read(struct mac_device_info *hw, u32 filter_no,
				u8 reg, u32 *data)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;
	int ret;

	ret = dwxgmac2_filter_wait(hw);
	if (ret)
		return ret;

	value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT;
	value |= XGMAC_TT | XGMAC_XB;
	writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL);

	ret = dwxgmac2_filter_wait(hw);
	if (ret)
		return ret;

	*data = readl(ioaddr + XGMAC_L3L4_DATA);
	return 0;
}

static int dwxgmac2_filter_write(struct mac_device_info *hw, u32 filter_no,
				 u8 reg, u32 data)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;
	int ret;

	ret = dwxgmac2_filter_wait(hw);
	if (ret)
		return ret;

	writel(data, ioaddr + XGMAC_L3L4_DATA);

	value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT;
	value |= XGMAC_XB;
	writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL);

	return dwxgmac2_filter_wait(hw);
}

static int dwxgmac2_config_l3_filter(struct mac_device_info *hw, u32 filter_no,
				     bool en, bool ipv6, bool sa, bool inv,
				     u32 match)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;
	int ret;

	value = readl(ioaddr + XGMAC_PACKET_FILTER);
	value |= XGMAC_FILTER_IPFE;
	writel(value, ioaddr + XGMAC_PACKET_FILTER);

	ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L3L4_CTRL, &value);
	if (ret)
		return ret;

	/* For IPv6 not both SA/DA filters can be active */
	if (ipv6) {
		value |= XGMAC_L3PEN0;
		value &= ~(XGMAC_L3SAM0 | XGMAC_L3SAIM0);
		value &= ~(XGMAC_L3DAM0 | XGMAC_L3DAIM0);
		if (sa) {
			value |= XGMAC_L3SAM0;
			if (inv)
				value |= XGMAC_L3SAIM0;
		} else {
			value |= XGMAC_L3DAM0;
			if (inv)
				value |= XGMAC_L3DAIM0;
		}
	} else {
		value &= ~XGMAC_L3PEN0;
		if (sa) {
			value |= XGMAC_L3SAM0;
			if (inv)
				value |= XGMAC_L3SAIM0;
		} else {
			value |= XGMAC_L3DAM0;
			if (inv)
				value |= XGMAC_L3DAIM0;
		}
	}

	ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
	if (ret)
		return ret;

	if (sa) {
		ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3_ADDR0, match);
		if (ret)
			return ret;
	} else {
		ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3_ADDR1, match);
		if (ret)
			return ret;
	}

	if (!en)
		return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);

	return 0;
}

static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
				     bool en, bool udp, bool sa, bool inv,
				     u32 match)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;
	int ret;

	value = readl(ioaddr + XGMAC_PACKET_FILTER);
	value |= XGMAC_FILTER_IPFE;
	writel(value, ioaddr + XGMAC_PACKET_FILTER);

	ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L3L4_CTRL, &value);
	if (ret)
		return ret;

	if (udp) {
		value |= XGMAC_L4PEN0;
	} else {
		value &= ~XGMAC_L4PEN0;
	}

	value &= ~(XGMAC_L4SPM0 | XGMAC_L4SPIM0);
	value &= ~(XGMAC_L4DPM0 | XGMAC_L4DPIM0);
	if (sa) {
		value |= XGMAC_L4SPM0;
		if (inv)
			value |= XGMAC_L4SPIM0;
	} else {
		value |= XGMAC_L4DPM0;
		if (inv)
			value |= XGMAC_L4DPIM0;
	}

	ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
	if (ret)
		return ret;

	if (sa) {
		value = match & XGMAC_L4SP0;

		ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
		if (ret)
			return ret;
	} else {
		value = (match << XGMAC_L4DP0_SHIFT) & XGMAC_L4DP0;

		ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
		if (ret)
			return ret;
	}

	if (!en)
		return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);

	return 0;
}

const struct stmmac_ops dwxgmac210_ops = {
	.core_init = dwxgmac2_core_init,
	.set_mac = dwxgmac2_set_mac,
@@ -1203,6 +1378,8 @@ const struct stmmac_ops dwxgmac210_ops = {
	.flex_pps_config = dwxgmac2_flex_pps_config,
	.sarc_configure = dwxgmac2_sarc_configure,
	.enable_vlan = dwxgmac2_enable_vlan,
	.config_l3_filter = dwxgmac2_config_l3_filter,
	.config_l4_filter = dwxgmac2_config_l4_filter,
};

int dwxgmac2_setup(struct stmmac_priv *priv)
+1 −0
Original line number Diff line number Diff line
@@ -378,6 +378,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,

	/* MAC HW feature 1 */
	hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
	dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27;
	dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
	dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
	dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
+16 −0
Original line number Diff line number Diff line
@@ -363,6 +363,13 @@ struct stmmac_ops {
	int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
	/* Source Address Insertion / Replacement */
	void (*sarc_configure)(void __iomem *ioaddr, int val);
	/* Filtering */
	int (*config_l3_filter)(struct mac_device_info *hw, u32 filter_no,
				bool en, bool ipv6, bool sa, bool inv,
				u32 match);
	int (*config_l4_filter)(struct mac_device_info *hw, u32 filter_no,
				bool en, bool udp, bool sa, bool inv,
				u32 match);
};

#define stmmac_core_init(__priv, __args...) \
@@ -443,6 +450,10 @@ struct stmmac_ops {
	stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
#define stmmac_sarc_configure(__priv, __args...) \
	stmmac_do_void_callback(__priv, mac, sarc_configure, __args)
#define stmmac_config_l3_filter(__priv, __args...) \
	stmmac_do_callback(__priv, mac, config_l3_filter, __args)
#define stmmac_config_l4_filter(__priv, __args...) \
	stmmac_do_callback(__priv, mac, config_l4_filter, __args)

/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
@@ -499,6 +510,7 @@ struct stmmac_mode_ops {
struct stmmac_priv;
struct tc_cls_u32_offload;
struct tc_cbs_qopt_offload;
struct flow_cls_offload;

struct stmmac_tc_ops {
	int (*init)(struct stmmac_priv *priv);
@@ -506,6 +518,8 @@ struct stmmac_tc_ops {
			     struct tc_cls_u32_offload *cls);
	int (*setup_cbs)(struct stmmac_priv *priv,
			 struct tc_cbs_qopt_offload *qopt);
	int (*setup_cls)(struct stmmac_priv *priv,
			 struct flow_cls_offload *cls);
};

#define stmmac_tc_init(__priv, __args...) \
@@ -514,6 +528,8 @@ struct stmmac_tc_ops {
	stmmac_do_callback(__priv, tc, setup_cls_u32, __args)
#define stmmac_tc_setup_cbs(__priv, __args...) \
	stmmac_do_callback(__priv, tc, setup_cbs, __args)
#define stmmac_tc_setup_cls(__priv, __args...) \
	stmmac_do_callback(__priv, tc, setup_cls, __args)

struct stmmac_counters;

Loading