Commit d1e8496e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'stmmac-next'



Jose Abreu says:

====================
net: stmmac: Improvements for -next

Couple of improvements for -next tree. More info in commit logs.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 44c40910 427849e8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -360,6 +360,8 @@ struct dma_features {
	unsigned int sphen;
	unsigned int vlins;
	unsigned int dvlan;
	unsigned int l3l4fnum;
	unsigned int arpoffsel;
};

/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
+32 −1
Original line number Diff line number Diff line
@@ -44,9 +44,11 @@
#define XGMAC_CONFIG_CST		BIT(2)
#define XGMAC_CONFIG_ACS		BIT(1)
#define XGMAC_CONFIG_RE			BIT(0)
#define XGMAC_CORE_INIT_RX		0
#define XGMAC_CORE_INIT_RX		(XGMAC_CONFIG_GPSLCE | XGMAC_CONFIG_WD | \
					 (XGMAC_JUMBO_LEN << XGMAC_CONFIG_GPSL_SHIFT))
#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 +121,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 +153,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)
+194 −11
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@ static void dwxgmac2_core_init(struct mac_device_info *hw,
			       struct net_device *dev)
{
	void __iomem *ioaddr = hw->pcsr;
	int mtu = dev->mtu;
	u32 tx, rx;

	tx = readl(ioaddr + XGMAC_TX_CONFIG);
@@ -24,16 +23,6 @@ static void dwxgmac2_core_init(struct mac_device_info *hw,
	tx |= XGMAC_CORE_INIT_TX;
	rx |= XGMAC_CORE_INIT_RX;

	if (mtu >= 9000) {
		rx |= XGMAC_CONFIG_GPSLCE;
		rx |= XGMAC_JUMBO_LEN << XGMAC_CONFIG_GPSL_SHIFT;
		rx |= XGMAC_CONFIG_WD;
	} else if (mtu > 2000) {
		rx |= XGMAC_CONFIG_JE;
	} else if (mtu > 1500) {
		rx |= XGMAC_CONFIG_S2KP;
	}

	if (hw->ps) {
		tx |= XGMAC_CONFIG_TE;
		tx &= ~hw->link.speed_mask;
@@ -1163,6 +1152,197 @@ 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;
}

static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
				     u32 addr)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value;

	writel(addr, ioaddr + XGMAC_ARP_ADDR);

	value = readl(ioaddr + XGMAC_RX_CONFIG);
	if (en)
		value |= XGMAC_CONFIG_ARPEN;
	else
		value &= ~XGMAC_CONFIG_ARPEN;
	writel(value, ioaddr + XGMAC_RX_CONFIG);
}

const struct stmmac_ops dwxgmac210_ops = {
	.core_init = dwxgmac2_core_init,
	.set_mac = dwxgmac2_set_mac,
@@ -1203,6 +1383,9 @@ 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,
	.set_arp_offload = dwxgmac2_set_arp_offload,
};

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

	/* ABNORMAL interrupts */
	if (unlikely(intr_status & XGMAC_AIS)) {
		if (unlikely(intr_status & XGMAC_RBU)) {
			x->rx_buf_unav_irq++;
			ret |= handle_rx;
		}
		if (unlikely(intr_status & XGMAC_TPS)) {
			x->tx_process_stopped_irq++;
			ret |= tx_hard_error;
@@ -365,7 +369,8 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
	dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13;
	dma_cap->atime_stamp = (hw_cap & XGMAC_HWFEAT_TSSEL) >> 12;
	dma_cap->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11;
	dma_cap->av &= (hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10;
	dma_cap->av &= !(hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10;
	dma_cap->arpoffsel = (hw_cap & XGMAC_HWFEAT_ARPOFFSEL) >> 9;
	dma_cap->rmon = (hw_cap & XGMAC_HWFEAT_MMCSEL) >> 8;
	dma_cap->pmt_magic_frame = (hw_cap & XGMAC_HWFEAT_MGKSEL) >> 7;
	dma_cap->pmt_remote_wake_up = (hw_cap & XGMAC_HWFEAT_RWKSEL) >> 6;
@@ -374,6 +379,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;
+19 −0
Original line number Diff line number Diff line
@@ -363,6 +363,14 @@ 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);
	void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
};

#define stmmac_core_init(__priv, __args...) \
@@ -443,6 +451,12 @@ 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)
#define stmmac_set_arp_offload(__priv, __args...) \
	stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)

/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
@@ -499,6 +513,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 +521,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 +531,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