diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro')
21 files changed, 1151 insertions, 433 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 6e52c0f74cd..2d09c116cbc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -5,6 +5,7 @@ config STMMAC_ETH  	select PHYLIB  	select CRC32  	select PTP_1588_CLOCK +	select RESET_CONTROLLER  	---help---  	  This is the driver for the Ethernet IPs are built around a  	  Synopsys IP Core and only tested on the STMicroelectronics @@ -25,6 +26,38 @@ config STMMAC_PLATFORM  	  If unsure, say N. +config DWMAC_SOCFPGA +	bool "SOCFPGA dwmac support" +	depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST) +	help +	  Support for ethernet controller on Altera SOCFPGA + +	  This selects the Altera SOCFPGA SoC glue layer support +	  for the stmmac device driver. This driver is used for +	  arria5 and cyclone5 FPGA SoCs. + +config DWMAC_SUNXI +	bool "Allwinner GMAC support" +	depends on STMMAC_PLATFORM && ARCH_SUNXI +	default y +	---help--- +	  Support for Allwinner A20/A31 GMAC ethernet controllers. + +	  This selects Allwinner SoC glue layer support for the +	  stmmac device driver. This driver is used for A20/A31 +	  GMAC 	  ethernet controller. + +config DWMAC_STI +	bool "STi GMAC support" +	depends on STMMAC_PLATFORM && ARCH_STI +	default y +	---help--- +	  Support for ethernet controller on STi SOCs. + +	  This selects STi SoC glue layer support for the stmmac +	  device driver. This driver is used on for the STi series +	  SOCs GMAC ethernet controller. +  config STMMAC_PCI  	bool "STMMAC PCI bus support"  	depends on STMMAC_ETH && PCI diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 356a9dd32be..18695ebef7e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -1,6 +1,9 @@  obj-$(CONFIG_STMMAC_ETH) += stmmac.o  stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o  stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o +stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o +stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o +stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o  stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\  	      chain_mode.o dwmac_lib.o dwmac1000_core.o  dwmac1000_dma.o \  	      dwmac100_core.o dwmac100_dma.o enh_desc.o  norm_desc.o \ diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c index d234ab540b2..c553f6b5a91 100644 --- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c @@ -51,6 +51,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)  	priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);  	while (len != 0) { +		priv->tx_skbuff[entry] = NULL;  		entry = (++priv->cur_tx) % txsize;  		desc = priv->dma_tx + entry; @@ -62,7 +63,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)  			priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,  							STMMAC_CHAIN_MODE);  			priv->hw->desc->set_tx_owner(desc); -			priv->tx_skbuff[entry] = NULL;  			len -= bmax;  			i++;  		} else { @@ -73,7 +73,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)  			priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,  							STMMAC_CHAIN_MODE);  			priv->hw->desc->set_tx_owner(desc); -			priv->tx_skbuff[entry] = NULL;  			len = 0;  		}  	} @@ -152,7 +151,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)  					  sizeof(struct dma_desc)));  } -const struct stmmac_chain_mode_ops chain_mode_ops = { +const struct stmmac_mode_ops chain_mode_ops = {  	.init = stmmac_init_dma_chain,  	.is_jumbo_frm = stmmac_is_jumbo_frm,  	.jumbo_frm = stmmac_jumbo_frm, diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 7eb8babed2c..74610f3aca9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -29,7 +29,6 @@  #include <linux/netdevice.h>  #include <linux/phy.h>  #include <linux/module.h> -#include <linux/init.h>  #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)  #define STMMAC_VLAN_TAG_USED  #include <linux/if_vlan.h> @@ -293,6 +292,8 @@ struct dma_features {  #define STMMAC_CHAIN_MODE	0x1  #define STMMAC_RING_MODE	0x2 +#define JUMBO_LEN		9000 +  struct stmmac_desc_ops {  	/* DMA RX descriptor ring initialization */  	void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode, @@ -369,7 +370,7 @@ struct stmmac_dma_ops {  struct stmmac_ops {  	/* MAC core initialization */ -	void (*core_init) (void __iomem *ioaddr); +	void (*core_init) (void __iomem *ioaddr, int mtu);  	/* Enable and verify that the IPC module is supported */  	int (*rx_ipc) (void __iomem *ioaddr);  	/* Dump MAC registers */ @@ -418,20 +419,13 @@ struct mii_regs {  	unsigned int data;	/* MII Data */  }; -struct stmmac_ring_mode_ops { -	unsigned int (*is_jumbo_frm) (int len, int ehn_desc); -	unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum); -	void (*refill_desc3) (void *priv, struct dma_desc *p); -	void (*init_desc3) (struct dma_desc *p); -	void (*clean_desc3) (void *priv, struct dma_desc *p); -	int (*set_16kib_bfsize) (int mtu); -}; - -struct stmmac_chain_mode_ops { +struct stmmac_mode_ops {  	void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,  		      unsigned int extend_desc);  	unsigned int (*is_jumbo_frm) (int len, int ehn_desc);  	unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum); +	int (*set_16kib_bfsize)(int mtu); +	void (*init_desc3)(struct dma_desc *p);  	void (*refill_desc3) (void *priv, struct dma_desc *p);  	void (*clean_desc3) (void *priv, struct dma_desc *p);  }; @@ -440,8 +434,7 @@ struct mac_device_info {  	const struct stmmac_ops *mac;  	const struct stmmac_desc_ops *desc;  	const struct stmmac_dma_ops *dma; -	const struct stmmac_ring_mode_ops *ring; -	const struct stmmac_chain_mode_ops *chain; +	const struct stmmac_mode_ops *mode;  	const struct stmmac_hwtimestamp *ptp;  	struct mii_regs mii;	/* MII register Addresses */  	struct mac_link link; @@ -451,15 +444,15 @@ struct mac_device_info {  struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);  struct mac_device_info *dwmac100_setup(void __iomem *ioaddr); -extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], -				unsigned int high, unsigned int low); -extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, -				unsigned int high, unsigned int low); +void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], +			 unsigned int high, unsigned int low); +void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, +			 unsigned int high, unsigned int low); -extern void stmmac_set_mac(void __iomem *ioaddr, bool enable); +void stmmac_set_mac(void __iomem *ioaddr, bool enable); -extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); -extern const struct stmmac_ring_mode_ops ring_mode_ops; -extern const struct stmmac_chain_mode_ops chain_mode_ops; +void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); +extern const struct stmmac_mode_ops ring_mode_ops; +extern const struct stmmac_mode_ops chain_mode_ops;  #endif /* __COMMON_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c new file mode 100644 index 00000000000..fd8a217556a --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -0,0 +1,130 @@ +/* Copyright Altera Corporation (C) 2014. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + * + * Adopted from dwmac-sti.c + */ + +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_net.h> +#include <linux/phy.h> +#include <linux/regmap.h> +#include <linux/stmmac.h> + +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 + +struct socfpga_dwmac { +	int	interface; +	u32	reg_offset; +	u32	reg_shift; +	struct	device *dev; +	struct regmap *sys_mgr_base_addr; +}; + +static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) +{ +	struct device_node *np = dev->of_node; +	struct regmap *sys_mgr_base_addr; +	u32 reg_offset, reg_shift; +	int ret; + +	dwmac->interface = of_get_phy_mode(np); + +	sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); +	if (IS_ERR(sys_mgr_base_addr)) { +		dev_info(dev, "No sysmgr-syscon node found\n"); +		return PTR_ERR(sys_mgr_base_addr); +	} + +	ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset); +	if (ret) { +		dev_info(dev, "Could not read reg_offset from sysmgr-syscon!\n"); +		return -EINVAL; +	} + +	ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, ®_shift); +	if (ret) { +		dev_info(dev, "Could not read reg_shift from sysmgr-syscon!\n"); +		return -EINVAL; +	} + +	dwmac->reg_offset = reg_offset; +	dwmac->reg_shift = reg_shift; +	dwmac->sys_mgr_base_addr = sys_mgr_base_addr; +	dwmac->dev = dev; + +	return 0; +} + +static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) +{ +	struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; +	int phymode = dwmac->interface; +	u32 reg_offset = dwmac->reg_offset; +	u32 reg_shift = dwmac->reg_shift; +	u32 ctrl, val; + +	switch (phymode) { +	case PHY_INTERFACE_MODE_RGMII: +		val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; +		break; +	case PHY_INTERFACE_MODE_MII: +	case PHY_INTERFACE_MODE_GMII: +		val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; +		break; +	default: +		dev_err(dwmac->dev, "bad phy mode %d\n", phymode); +		return -EINVAL; +	} + +	regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); +	ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift); +	ctrl |= val << reg_shift; + +	regmap_write(sys_mgr_base_addr, reg_offset, ctrl); +	return 0; +} + +static void *socfpga_dwmac_probe(struct platform_device *pdev) +{ +	struct device		*dev = &pdev->dev; +	int			ret; +	struct socfpga_dwmac	*dwmac; + +	dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); +	if (!dwmac) +		return ERR_PTR(-ENOMEM); + +	ret = socfpga_dwmac_parse_data(dwmac, dev); +	if (ret) { +		dev_err(dev, "Unable to parse OF data\n"); +		return ERR_PTR(ret); +	} + +	ret = socfpga_dwmac_setup(dwmac); +	if (ret) { +		dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); +		return ERR_PTR(ret); +	} + +	return dwmac; +} + +const struct stmmac_of_data socfpga_gmac_data = { +	.setup = socfpga_dwmac_probe, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c new file mode 100644 index 00000000000..552bbc17863 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -0,0 +1,330 @@ +/** + * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer + * + * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited + * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/stmmac.h> +#include <linux/phy.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_net.h> + +/** + *			STi GMAC glue logic. + *			-------------------- + * + *		 _ + *		|  \ + *	--------|0  \ ETH_SEL_INTERNAL_NOTEXT_PHYCLK + * phyclk	|    |___________________________________________ + *		|    |	|			(phyclk-in) + *	--------|1  /	| + * int-clk	|_ /	| + *			|	 _ + *			|	|  \ + *			|_______|1  \ ETH_SEL_TX_RETIME_CLK + *				|    |___________________________ + *				|    |		(tx-retime-clk) + *			 _______|0  / + *			|	|_ / + *		 _	| + *		|  \	| + *	--------|0  \	| + * clk_125	|    |__| + *		|    |	ETH_SEL_TXCLK_NOT_CLK125 + *	--------|1  / + * txclk	|_ / + * + * + * ETH_SEL_INTERNAL_NOTEXT_PHYCLK is valid only for RMII where PHY can + * generate 50MHz clock or MAC can generate it. + * This bit is configured by "st,ext-phyclk" property. + * + * ETH_SEL_TXCLK_NOT_CLK125 is only valid for gigabit modes, where the 125Mhz + * clock either comes from clk-125 pin or txclk pin. This configuration is + * totally driven by the board wiring. This bit is configured by + * "st,tx-retime-src" property. + * + * TXCLK configuration is different for different phy interface modes + * and changes according to link speed in modes like RGMII. + * + * Below table summarizes the clock requirement and clock sources for + * supported phy interface modes with link speeds. + * ________________________________________________ + *|  PHY_MODE	| 1000 Mbit Link | 100 Mbit Link   | + * ------------------------------------------------ + *|	MII	|	n/a	 |	25Mhz	   | + *|		|		 |	txclk	   | + * ------------------------------------------------ + *|	GMII	|     125Mhz	 |	25Mhz	   | + *|		|  clk-125/txclk |	txclk	   | + * ------------------------------------------------ + *|	RGMII	|     125Mhz	 |	25Mhz	   | + *|		|  clk-125/txclk |	clkgen     | + * ------------------------------------------------ + *|	RMII	|	n/a	 |	25Mhz	   | + *|		|		 |clkgen/phyclk-in | + * ------------------------------------------------ + * + * TX lines are always retimed with a clk, which can vary depending + * on the board configuration. Below is the table of these bits + * in eth configuration register depending on source of retime clk. + * + *--------------------------------------------------------------- + * src	 | tx_rt_clk	| int_not_ext_phyclk	| txclk_n_clk125| + *--------------------------------------------------------------- + * txclk |	0	|	n/a		|	1	| + *--------------------------------------------------------------- + * ck_125|	0	|	n/a		|	0	| + *--------------------------------------------------------------- + * phyclk|	1	|	0		|	n/a	| + *--------------------------------------------------------------- + * clkgen|	1	|	1		|	n/a	| + *--------------------------------------------------------------- + */ + + /* Register definition */ + + /* 3 bits [8:6] +  *  [6:6]      ETH_SEL_TXCLK_NOT_CLK125 +  *  [7:7]      ETH_SEL_INTERNAL_NOTEXT_PHYCLK +  *  [8:8]      ETH_SEL_TX_RETIME_CLK +  * +  */ + +#define TX_RETIME_SRC_MASK		GENMASK(8, 6) +#define ETH_SEL_TX_RETIME_CLK		BIT(8) +#define ETH_SEL_INTERNAL_NOTEXT_PHYCLK	BIT(7) +#define ETH_SEL_TXCLK_NOT_CLK125	BIT(6) + +#define ENMII_MASK			GENMASK(5, 5) +#define ENMII				BIT(5) + +/** + * 3 bits [4:2] + *	000-GMII/MII + *	001-RGMII + *	010-SGMII + *	100-RMII +*/ +#define MII_PHY_SEL_MASK		GENMASK(4, 2) +#define ETH_PHY_SEL_RMII		BIT(4) +#define ETH_PHY_SEL_SGMII		BIT(3) +#define ETH_PHY_SEL_RGMII		BIT(2) +#define ETH_PHY_SEL_GMII		0x0 +#define ETH_PHY_SEL_MII			0x0 + +#define IS_PHY_IF_MODE_RGMII(iface)	(iface == PHY_INTERFACE_MODE_RGMII || \ +			iface == PHY_INTERFACE_MODE_RGMII_ID || \ +			iface == PHY_INTERFACE_MODE_RGMII_RXID || \ +			iface == PHY_INTERFACE_MODE_RGMII_TXID) + +#define IS_PHY_IF_MODE_GBIT(iface)	(IS_PHY_IF_MODE_RGMII(iface) || \ +			iface == PHY_INTERFACE_MODE_GMII) + +struct sti_dwmac { +	int interface; +	bool ext_phyclk; +	bool is_tx_retime_src_clk_125; +	struct clk *clk; +	int reg; +	struct device *dev; +	struct regmap *regmap; +}; + +static u32 phy_intf_sels[] = { +	[PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII, +	[PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII, +	[PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII, +	[PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII, +	[PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII, +	[PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII, +}; + +enum { +	TX_RETIME_SRC_NA = 0, +	TX_RETIME_SRC_TXCLK = 1, +	TX_RETIME_SRC_CLK_125, +	TX_RETIME_SRC_PHYCLK, +	TX_RETIME_SRC_CLKGEN, +}; + +static const char *const tx_retime_srcs[] = { +	[TX_RETIME_SRC_NA] = "", +	[TX_RETIME_SRC_TXCLK] = "txclk", +	[TX_RETIME_SRC_CLK_125] = "clk_125", +	[TX_RETIME_SRC_PHYCLK] = "phyclk", +	[TX_RETIME_SRC_CLKGEN] = "clkgen", +}; + +static u32 tx_retime_val[] = { +	[TX_RETIME_SRC_TXCLK] = ETH_SEL_TXCLK_NOT_CLK125, +	[TX_RETIME_SRC_CLK_125] = 0x0, +	[TX_RETIME_SRC_PHYCLK] = ETH_SEL_TX_RETIME_CLK, +	[TX_RETIME_SRC_CLKGEN] = ETH_SEL_TX_RETIME_CLK | +	    ETH_SEL_INTERNAL_NOTEXT_PHYCLK, +}; + +static void setup_retime_src(struct sti_dwmac *dwmac, u32 spd) +{ +	u32 src = 0, freq = 0; + +	if (spd == SPEED_100) { +		if (dwmac->interface == PHY_INTERFACE_MODE_MII || +		    dwmac->interface == PHY_INTERFACE_MODE_GMII) { +			src = TX_RETIME_SRC_TXCLK; +		} else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) { +			if (dwmac->ext_phyclk) { +				src = TX_RETIME_SRC_PHYCLK; +			} else { +				src = TX_RETIME_SRC_CLKGEN; +				freq = 50000000; +			} + +		} else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) { +			src = TX_RETIME_SRC_CLKGEN; +			freq = 25000000; +		} + +		if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk) +			clk_set_rate(dwmac->clk, freq); + +	} else if (spd == SPEED_1000) { +		if (dwmac->is_tx_retime_src_clk_125) +			src = TX_RETIME_SRC_CLK_125; +		else +			src = TX_RETIME_SRC_TXCLK; +	} + +	regmap_update_bits(dwmac->regmap, dwmac->reg, +			   TX_RETIME_SRC_MASK, tx_retime_val[src]); +} + +static void sti_dwmac_exit(struct platform_device *pdev, void *priv) +{ +	struct sti_dwmac *dwmac = priv; + +	if (dwmac->clk) +		clk_disable_unprepare(dwmac->clk); +} + +static void sti_fix_mac_speed(void *priv, unsigned int spd) +{ +	struct sti_dwmac *dwmac = priv; + +	setup_retime_src(dwmac, spd); + +	return; +} + +static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, +				struct platform_device *pdev) +{ +	struct resource *res; +	struct device *dev = &pdev->dev; +	struct device_node *np = dev->of_node; +	struct regmap *regmap; +	int err; + +	if (!np) +		return -EINVAL; + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf"); +	if (!res) +		return -ENODATA; + +	regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon"); +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	dwmac->dev = dev; +	dwmac->interface = of_get_phy_mode(np); +	dwmac->regmap = regmap; +	dwmac->reg = res->start; +	dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk"); +	dwmac->is_tx_retime_src_clk_125 = false; + +	if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { +		const char *rs; + +		err = of_property_read_string(np, "st,tx-retime-src", &rs); +		if (err < 0) { +			dev_err(dev, "st,tx-retime-src not specified\n"); +			return err; +		} + +		if (!strcasecmp(rs, "clk_125")) +			dwmac->is_tx_retime_src_clk_125 = true; +	} + +	dwmac->clk = devm_clk_get(dev, "sti-ethclk"); + +	if (IS_ERR(dwmac->clk)) +		dwmac->clk = NULL; + +	return 0; +} + +static int sti_dwmac_init(struct platform_device *pdev, void *priv) +{ +	struct sti_dwmac *dwmac = priv; +	struct regmap *regmap = dwmac->regmap; +	int iface = dwmac->interface; +	u32 reg = dwmac->reg; +	u32 val, spd; + +	if (dwmac->clk) +		clk_prepare_enable(dwmac->clk); + +	regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]); + +	val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; +	regmap_update_bits(regmap, reg, ENMII_MASK, val); + +	if (IS_PHY_IF_MODE_GBIT(iface)) +		spd = SPEED_1000; +	else +		spd = SPEED_100; + +	setup_retime_src(dwmac, spd); + +	return 0; +} + +static void *sti_dwmac_setup(struct platform_device *pdev) +{ +	struct sti_dwmac *dwmac; +	int ret; + +	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); +	if (!dwmac) +		return ERR_PTR(-ENOMEM); + +	ret = sti_dwmac_parse_data(dwmac, pdev); +	if (ret) { +		dev_err(&pdev->dev, "Unable to parse OF data\n"); +		return ERR_PTR(ret); +	} + +	return dwmac; +} + +const struct stmmac_of_data sti_gmac_data = { +	.fix_mac_speed = sti_fix_mac_speed, +	.setup = sti_dwmac_setup, +	.init = sti_dwmac_init, +	.exit = sti_dwmac_exit, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c new file mode 100644 index 00000000000..771cd15fca1 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -0,0 +1,140 @@ +/** + * dwmac-sunxi.c - Allwinner sunxi DWMAC specific glue layer + * + * Copyright (C) 2013 Chen-Yu Tsai + * + * Chen-Yu Tsai  <wens@csie.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/stmmac.h> +#include <linux/clk.h> +#include <linux/phy.h> +#include <linux/of_net.h> +#include <linux/regulator/consumer.h> + +struct sunxi_priv_data { +	int interface; +	int clk_enabled; +	struct clk *tx_clk; +	struct regulator *regulator; +}; + +static void *sun7i_gmac_setup(struct platform_device *pdev) +{ +	struct sunxi_priv_data *gmac; +	struct device *dev = &pdev->dev; + +	gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); +	if (!gmac) +		return ERR_PTR(-ENOMEM); + +	gmac->interface = of_get_phy_mode(dev->of_node); + +	gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); +	if (IS_ERR(gmac->tx_clk)) { +		dev_err(dev, "could not get tx clock\n"); +		return gmac->tx_clk; +	} + +	/* Optional regulator for PHY */ +	gmac->regulator = devm_regulator_get_optional(dev, "phy"); +	if (IS_ERR(gmac->regulator)) { +		if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) +			return ERR_PTR(-EPROBE_DEFER); +		dev_info(dev, "no regulator found\n"); +		gmac->regulator = NULL; +	} + +	return gmac; +} + +#define SUN7I_GMAC_GMII_RGMII_RATE	125000000 +#define SUN7I_GMAC_MII_RATE		25000000 + +static int sun7i_gmac_init(struct platform_device *pdev, void *priv) +{ +	struct sunxi_priv_data *gmac = priv; +	int ret; + +	if (gmac->regulator) { +		ret = regulator_enable(gmac->regulator); +		if (ret) +			return ret; +	} + +	/* Set GMAC interface port mode +	 * +	 * The GMAC TX clock lines are configured by setting the clock +	 * rate, which then uses the auto-reparenting feature of the +	 * clock driver, and enabling/disabling the clock. +	 */ +	if (gmac->interface == PHY_INTERFACE_MODE_RGMII) { +		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); +		clk_prepare_enable(gmac->tx_clk); +		gmac->clk_enabled = 1; +	} else { +		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE); +		clk_prepare(gmac->tx_clk); +	} + +	return 0; +} + +static void sun7i_gmac_exit(struct platform_device *pdev, void *priv) +{ +	struct sunxi_priv_data *gmac = priv; + +	if (gmac->clk_enabled) { +		clk_disable(gmac->tx_clk); +		gmac->clk_enabled = 0; +	} +	clk_unprepare(gmac->tx_clk); + +	if (gmac->regulator) +		regulator_disable(gmac->regulator); +} + +static void sun7i_fix_speed(void *priv, unsigned int speed) +{ +	struct sunxi_priv_data *gmac = priv; + +	/* only GMII mode requires us to reconfigure the clock lines */ +	if (gmac->interface != PHY_INTERFACE_MODE_GMII) +		return; + +	if (gmac->clk_enabled) { +		clk_disable(gmac->tx_clk); +		gmac->clk_enabled = 0; +	} +	clk_unprepare(gmac->tx_clk); + +	if (speed == 1000) { +		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); +		clk_prepare_enable(gmac->tx_clk); +		gmac->clk_enabled = 1; +	} else { +		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE); +		clk_prepare(gmac->tx_clk); +	} +} + +/* of_data specifying hardware features and callbacks. + * hardware features were copied from Allwinner drivers. */ +const struct stmmac_of_data sun7i_gmac_data = { +	.has_gmac = 1, +	.tx_coe = 1, +	.fix_mac_speed = sun7i_fix_speed, +	.setup = sun7i_gmac_setup, +	.init = sun7i_gmac_init, +	.exit = sun7i_gmac_exit, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index c12aabb8cf9..f37d90f114f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -126,11 +126,8 @@ enum power_event {  #define GMAC_ANE_PSE		(3 << 7)  #define GMAC_ANE_PSE_SHIFT	7 - /* GMAC Configuration defines */ -#define GMAC_CONTROL_TC	0x01000000	/* Transmit Conf. in RGMII/SGMII */ -#define GMAC_CONTROL_WD	0x00800000	/* Disable Watchdog on receive */ -  /* GMAC Configuration defines */ +#define GMAC_CONTROL_2K 0x08000000	/* IEEE 802.3as 2K packets */  #define GMAC_CONTROL_TC	0x01000000	/* Transmit Conf. in RGMII/SGMII */  #define GMAC_CONTROL_WD	0x00800000	/* Disable Watchdog on receive */  #define GMAC_CONTROL_JD	0x00400000	/* Jabber disable */ @@ -156,7 +153,7 @@ enum inter_frame_gap {  #define GMAC_CONTROL_RE		0x00000004	/* Receiver Enable */  #define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \ -			GMAC_CONTROL_JE | GMAC_CONTROL_BE) +			GMAC_CONTROL_BE)  /* GMAC Frame Filter defines */  #define GMAC_FRAME_FILTER_PR	0x00000001	/* Promiscuous Mode */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index cdd926832e2..9d3748361a1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -32,10 +32,15 @@  #include <asm/io.h>  #include "dwmac1000.h" -static void dwmac1000_core_init(void __iomem *ioaddr) +static void dwmac1000_core_init(void __iomem *ioaddr, int mtu)  {  	u32 value = readl(ioaddr + GMAC_CONTROL);  	value |= GMAC_CORE_INIT; +	if (mtu > 1500) +		value |= GMAC_CONTROL_2K; +	if (mtu > 2000) +		value |= GMAC_CONTROL_JE; +  	writel(value, ioaddr + GMAC_CONTROL);  	/* Mask GMAC interrupts */ @@ -315,11 +320,8 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)  static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)  { -	u32 value; - -	value = readl(ioaddr + GMAC_AN_CTRL);  	/* auto negotiation enable and External Loopback enable */ -	value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE; +	u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;  	if (restart)  		value |= GMAC_AN_CTRL_RAN; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 5857d677dac..2ff767bcfdd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -32,7 +32,7 @@  #include <asm/io.h>  #include "dwmac100.h" -static void dwmac100_core_init(void __iomem *ioaddr) +static void dwmac100_core_init(void __iomem *ioaddr, int mtu)  {  	u32 value = readl(ioaddr + MAC_CONTROL); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index 8e5662ce488..def266da55d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -104,14 +104,13 @@  #define DMA_STATUS_TI	0x00000001	/* Transmit Interrupt */  #define DMA_CONTROL_FTF		0x00100000	/* Flush transmit FIFO */ -extern void dwmac_enable_dma_transmission(void __iomem *ioaddr); -extern void dwmac_enable_dma_irq(void __iomem *ioaddr); -extern void dwmac_disable_dma_irq(void __iomem *ioaddr); -extern void dwmac_dma_start_tx(void __iomem *ioaddr); -extern void dwmac_dma_stop_tx(void __iomem *ioaddr); -extern void dwmac_dma_start_rx(void __iomem *ioaddr); -extern void dwmac_dma_stop_rx(void __iomem *ioaddr); -extern int dwmac_dma_interrupt(void __iomem *ioaddr, -			       struct stmmac_extra_stats *x); +void dwmac_enable_dma_transmission(void __iomem *ioaddr); +void dwmac_enable_dma_irq(void __iomem *ioaddr); +void dwmac_disable_dma_irq(void __iomem *ioaddr); +void dwmac_dma_start_tx(void __iomem *ioaddr); +void dwmac_dma_stop_tx(void __iomem *ioaddr); +void dwmac_dma_start_rx(void __iomem *ioaddr); +void dwmac_dma_stop_rx(void __iomem *ioaddr); +int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x);  #endif /* __DWMAC_DMA_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index 7e6628a9151..1e2bcf5f89e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -145,7 +145,7 @@ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,  			x->rx_msg_type_delay_req++;  		else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)  			x->rx_msg_type_delay_resp++; -		else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ) +		else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_REQ)  			x->rx_msg_type_pdelay_req++;  		else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)  			x->rx_msg_type_pdelay_resp++; diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h index 48ec001566b..8607488cbcf 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc.h +++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h @@ -128,8 +128,8 @@ struct stmmac_counters {  	unsigned int mmc_rx_icmp_err_octets;  }; -extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode); -extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr); -extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc); +void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode); +void dwmac_mmc_intr_all_mask(void __iomem *ioaddr); +void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);  #endif /* __MMC_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c index 1ef9d8a555a..650a4be6bce 100644 --- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c @@ -58,6 +58,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)  		priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,  						STMMAC_RING_MODE);  		wmb(); +		priv->tx_skbuff[entry] = NULL;  		entry = (++priv->cur_tx) % txsize;  		if (priv->extend_desc) @@ -73,7 +74,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)  						STMMAC_RING_MODE);  		wmb();  		priv->hw->desc->set_tx_owner(desc); -		priv->tx_skbuff[entry] = NULL;  	} else {  		desc->des2 = dma_map_single(priv->device, skb->data,  					    nopaged_len, DMA_TO_DEVICE); @@ -100,10 +100,9 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)  {  	struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr; -	if (unlikely(priv->plat->has_gmac)) -		/* Fill DES3 in case of RING mode */ -		if (priv->dma_buf_sz >= BUF_SIZE_8KiB) -			p->des3 = p->des2 + BUF_SIZE_8KiB; +	/* Fill DES3 in case of RING mode */ +	if (priv->dma_buf_sz >= BUF_SIZE_8KiB) +		p->des3 = p->des2 + BUF_SIZE_8KiB;  }  /* In ring mode we need to fill the desc3 because it is used as buffer */ @@ -126,7 +125,7 @@ static int stmmac_set_16kib_bfsize(int mtu)  	return ret;  } -const struct stmmac_ring_mode_ops ring_mode_ops = { +const struct stmmac_mode_ops ring_mode_ops = {  	.is_jumbo_frm = stmmac_is_jumbo_frm,  	.jumbo_frm = stmmac_jumbo_frm,  	.refill_desc3 = stmmac_refill_desc3, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index f16a9bdf45b..ca01035634a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -32,6 +32,7 @@  #include <linux/pci.h>  #include "common.h"  #include <linux/ptp_clock_kernel.h> +#include <linux/reset.h>  struct stmmac_priv {  	/* Frequently used values are kept adjacent for cache effect */ @@ -91,6 +92,7 @@ struct stmmac_priv {  	int wolopts;  	int wol_irq;  	struct clk *stmmac_clk; +	struct reset_control *stmmac_rst;  	int clk_csr;  	struct timer_list eee_ctrl_timer;  	int lpi_irq; @@ -105,21 +107,19 @@ struct stmmac_priv {  	unsigned int default_addend;  	u32 adv_ts;  	int use_riwt; +	int irq_wake;  	spinlock_t ptp_lock;  }; -extern int phyaddr; - -extern int stmmac_mdio_unregister(struct net_device *ndev); -extern int stmmac_mdio_register(struct net_device *ndev); -extern void stmmac_set_ethtool_ops(struct net_device *netdev); +int stmmac_mdio_unregister(struct net_device *ndev); +int stmmac_mdio_register(struct net_device *ndev); +int stmmac_mdio_reset(struct mii_bus *mii); +void stmmac_set_ethtool_ops(struct net_device *netdev);  extern const struct stmmac_desc_ops enh_desc_ops;  extern const struct stmmac_desc_ops ndesc_ops;  extern const struct stmmac_hwtimestamp stmmac_ptp; -extern int stmmac_ptp_register(struct stmmac_priv *priv); -extern void stmmac_ptp_unregister(struct stmmac_priv *priv); -int stmmac_freeze(struct net_device *ndev); -int stmmac_restore(struct net_device *ndev); +int stmmac_ptp_register(struct stmmac_priv *priv); +void stmmac_ptp_unregister(struct stmmac_priv *priv);  int stmmac_resume(struct net_device *ndev);  int stmmac_suspend(struct net_device *ndev);  int stmmac_dvr_remove(struct net_device *ndev); @@ -130,6 +130,15 @@ void stmmac_disable_eee_mode(struct stmmac_priv *priv);  bool stmmac_eee_init(struct stmmac_priv *priv);  #ifdef CONFIG_STMMAC_PLATFORM +#ifdef CONFIG_DWMAC_SUNXI +extern const struct stmmac_of_data sun7i_gmac_data; +#endif +#ifdef CONFIG_DWMAC_STI +extern const struct stmmac_of_data sti_gmac_data; +#endif +#ifdef CONFIG_DWMAC_SOCFPGA +extern const struct stmmac_of_data socfpga_gmac_data; +#endif  extern struct platform_driver stmmac_pltfr_driver;  static inline int stmmac_register_platform(void)  { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index c5f9cb85c8e..c62e67f3c2f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -322,9 +322,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,  		return -EBUSY;  	}  	cmd->transceiver = XCVR_INTERNAL; -	spin_lock_irq(&priv->lock);  	rc = phy_ethtool_gset(phy, cmd); -	spin_unlock_irq(&priv->lock);  	return rc;  } @@ -431,8 +429,6 @@ stmmac_get_pauseparam(struct net_device *netdev,  	if (priv->pcs)	/* FIXME */  		return; -	spin_lock(&priv->lock); -  	pause->rx_pause = 0;  	pause->tx_pause = 0;  	pause->autoneg = priv->phydev->autoneg; @@ -442,7 +438,6 @@ stmmac_get_pauseparam(struct net_device *netdev,  	if (priv->flow_ctrl & FLOW_TX)  		pause->tx_pause = 1; -	spin_unlock(&priv->lock);  }  static int @@ -457,8 +452,6 @@ stmmac_set_pauseparam(struct net_device *netdev,  	if (priv->pcs)	/* FIXME */  		return -EOPNOTSUPP; -	spin_lock(&priv->lock); -  	if (pause->rx_pause)  		new_pause |= FLOW_RX;  	if (pause->tx_pause) @@ -473,7 +466,6 @@ stmmac_set_pauseparam(struct net_device *netdev,  	} else  		priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex,  					 priv->flow_ctrl, priv->pause); -	spin_unlock(&priv->lock);  	return ret;  } @@ -784,5 +776,5 @@ static const struct ethtool_ops stmmac_ethtool_ops = {  void stmmac_set_ethtool_ops(struct net_device *netdev)  { -	SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops); +	netdev->ethtool_ops = &stmmac_ethtool_ops;  } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8d4ccd35a01..057a1208e59 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -43,6 +43,7 @@  #include <linux/dma-mapping.h>  #include <linux/slab.h>  #include <linux/prefetch.h> +#include <linux/pinctrl/consumer.h>  #ifdef CONFIG_STMMAC_DEBUG_FS  #include <linux/debugfs.h>  #include <linux/seq_file.h> @@ -50,9 +51,9 @@  #include <linux/net_tstamp.h>  #include "stmmac_ptp.h"  #include "stmmac.h" +#include <linux/reset.h>  #define STMMAC_ALIGN(x)	L1_CACHE_ALIGN(x) -#define JUMBO_LEN	9000  /* Module parameters */  #define TX_TIMEO	5000 @@ -64,7 +65,7 @@ static int debug = -1;  module_param(debug, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); -int phyaddr = -1; +static int phyaddr = -1;  module_param(phyaddr, int, S_IRUGO);  MODULE_PARM_DESC(phyaddr, "Physical device address"); @@ -91,8 +92,8 @@ static int tc = TC_DEFAULT;  module_param(tc, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(tc, "DMA threshold control value"); -#define DMA_BUFFER_SIZE	BUF_SIZE_2KiB -static int buf_sz = DMA_BUFFER_SIZE; +#define	DEFAULT_BUFSIZE	1536 +static int buf_sz = DEFAULT_BUFSIZE;  module_param(buf_sz, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(buf_sz, "DMA buffer size"); @@ -135,8 +136,8 @@ static void stmmac_verify_args(void)  		dma_rxsize = DMA_RX_SIZE;  	if (unlikely(dma_txsize < 0))  		dma_txsize = DMA_TX_SIZE; -	if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB))) -		buf_sz = DMA_BUFFER_SIZE; +	if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB))) +		buf_sz = DEFAULT_BUFSIZE;  	if (unlikely(flow_ctrl > 1))  		flow_ctrl = FLOW_AUTO;  	else if (likely(flow_ctrl < 0)) @@ -285,10 +286,25 @@ bool stmmac_eee_init(struct stmmac_priv *priv)  	/* MAC core supports the EEE feature. */  	if (priv->dma_cap.eee) { +		int tx_lpi_timer = priv->tx_lpi_timer; +  		/* Check if the PHY supports EEE */ -		if (phy_init_eee(priv->phydev, 1)) +		if (phy_init_eee(priv->phydev, 1)) { +			/* To manage at run-time if the EEE cannot be supported +			 * anymore (for example because the lp caps have been +			 * changed). +			 * In that case the driver disable own timers. +			 */ +			if (priv->eee_active) { +				pr_debug("stmmac: disable EEE\n"); +				del_timer_sync(&priv->eee_ctrl_timer); +				priv->hw->mac->set_eee_timer(priv->ioaddr, 0, +							     tx_lpi_timer); +			} +			priv->eee_active = 0;  			goto out; - +		} +		/* Activate the EEE and start timers */  		if (!priv->eee_active) {  			priv->eee_active = 1;  			init_timer(&priv->eee_ctrl_timer); @@ -299,13 +315,13 @@ bool stmmac_eee_init(struct stmmac_priv *priv)  			priv->hw->mac->set_eee_timer(priv->ioaddr,  						     STMMAC_DEFAULT_LIT_LS, -						     priv->tx_lpi_timer); +						     tx_lpi_timer);  		} else  			/* Set HW EEE according to the speed */  			priv->hw->mac->set_eee_pls(priv->ioaddr,  						   priv->phydev->link); -		pr_info("stmmac: Energy-Efficient Ethernet initialized\n"); +		pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");  		ret = true;  	} @@ -332,7 +348,7 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,  		return;  	/* exit if skb doesn't support hw tstamp */ -	if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))) +	if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))  		return;  	if (priv->adv_ts) @@ -435,16 +451,9 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)  	if (config.flags)  		return -EINVAL; -	switch (config.tx_type) { -	case HWTSTAMP_TX_OFF: -		priv->hwts_tx_en = 0; -		break; -	case HWTSTAMP_TX_ON: -		priv->hwts_tx_en = 1; -		break; -	default: +	if (config.tx_type != HWTSTAMP_TX_OFF && +	    config.tx_type != HWTSTAMP_TX_ON)  		return -ERANGE; -	}  	if (priv->adv_ts) {  		switch (config.rx_filter) { @@ -576,6 +585,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)  		}  	}  	priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1); +	priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON;  	if (!priv->hwts_tx_en && !priv->hwts_rx_en)  		priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0); @@ -628,17 +638,15 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)  	if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))  		return -EOPNOTSUPP; -	if (netif_msg_hw(priv)) { -		if (priv->dma_cap.time_stamp) { -			pr_debug("IEEE 1588-2002 Time Stamp supported\n"); -			priv->adv_ts = 0; -		} -		if (priv->dma_cap.atime_stamp && priv->extend_desc) { -			pr_debug -			    ("IEEE 1588-2008 Advanced Time Stamp supported\n"); -			priv->adv_ts = 1; -		} -	} +	priv->adv_ts = 0; +	if (priv->dma_cap.atime_stamp && priv->extend_desc) +		priv->adv_ts = 1; + +	if (netif_msg_hw(priv) && priv->dma_cap.time_stamp) +		pr_debug("IEEE 1588-2002 Time Stamp supported\n"); + +	if (netif_msg_hw(priv) && priv->adv_ts) +		pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");  	priv->hw->ptp = &stmmac_ptp;  	priv->hwts_tx_en = 0; @@ -784,6 +792,7 @@ static int stmmac_init_phy(struct net_device *dev)  	char phy_id_fmt[MII_BUS_ID_SIZE + 3];  	char bus_id[MII_BUS_ID_SIZE];  	int interface = priv->plat->interface; +	int max_speed = priv->plat->max_speed;  	priv->oldlink = 0;  	priv->speed = 0;  	priv->oldduplex = -1; @@ -808,7 +817,8 @@ static int stmmac_init_phy(struct net_device *dev)  	/* Stop Advertising 1000BASE Capability if interface is not GMII */  	if ((interface == PHY_INTERFACE_MODE_MII) || -	    (interface == PHY_INTERFACE_MODE_RMII)) +	    (interface == PHY_INTERFACE_MODE_RMII) || +		(max_speed < 1000 &&  max_speed > 0))  		phydev->advertising &= ~(SUPPORTED_1000baseT_Half |  					 SUPPORTED_1000baseT_Full); @@ -891,10 +901,10 @@ static int stmmac_set_bfsize(int mtu, int bufsize)  		ret = BUF_SIZE_8KiB;  	else if (mtu >= BUF_SIZE_2KiB)  		ret = BUF_SIZE_4KiB; -	else if (mtu >= DMA_BUFFER_SIZE) +	else if (mtu > DEFAULT_BUFSIZE)  		ret = BUF_SIZE_2KiB;  	else -		ret = DMA_BUFFER_SIZE; +		ret = DEFAULT_BUFSIZE;  	return ret;  } @@ -956,9 +966,9 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,  	p->des2 = priv->rx_skbuff_dma[i]; -	if ((priv->mode == STMMAC_RING_MODE) && +	if ((priv->hw->mode->init_desc3) &&  	    (priv->dma_buf_sz == BUF_SIZE_16KiB)) -		priv->hw->ring->init_desc3(p); +		priv->hw->mode->init_desc3(p);  	return 0;  } @@ -989,79 +999,18 @@ static int init_dma_desc_rings(struct net_device *dev)  	unsigned int bfsize = 0;  	int ret = -ENOMEM; -	/* Set the max buffer size according to the DESC mode -	 * and the MTU. Note that RING mode allows 16KiB bsize. -	 */ -	if (priv->mode == STMMAC_RING_MODE) -		bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu); +	if (priv->hw->mode->set_16kib_bfsize) +		bfsize = priv->hw->mode->set_16kib_bfsize(dev->mtu);  	if (bfsize < BUF_SIZE_16KiB)  		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz); +	priv->dma_buf_sz = bfsize; +  	if (netif_msg_probe(priv))  		pr_debug("%s: txsize %d, rxsize %d, bfsize %d\n", __func__,  			 txsize, rxsize, bfsize); -	if (priv->extend_desc) { -		priv->dma_erx = dma_alloc_coherent(priv->device, rxsize * -						   sizeof(struct -							  dma_extended_desc), -						   &priv->dma_rx_phy, -						   GFP_KERNEL); -		if (!priv->dma_erx) -			goto err_dma; - -		priv->dma_etx = dma_alloc_coherent(priv->device, txsize * -						   sizeof(struct -							  dma_extended_desc), -						   &priv->dma_tx_phy, -						   GFP_KERNEL); -		if (!priv->dma_etx) { -			dma_free_coherent(priv->device, priv->dma_rx_size * -					sizeof(struct dma_extended_desc), -					priv->dma_erx, priv->dma_rx_phy); -			goto err_dma; -		} -	} else { -		priv->dma_rx = dma_alloc_coherent(priv->device, rxsize * -						  sizeof(struct dma_desc), -						  &priv->dma_rx_phy, -						  GFP_KERNEL); -		if (!priv->dma_rx) -			goto err_dma; - -		priv->dma_tx = dma_alloc_coherent(priv->device, txsize * -						  sizeof(struct dma_desc), -						  &priv->dma_tx_phy, -						  GFP_KERNEL); -		if (!priv->dma_tx) { -			dma_free_coherent(priv->device, priv->dma_rx_size * -					sizeof(struct dma_desc), -					priv->dma_rx, priv->dma_rx_phy); -			goto err_dma; -		} -	} - -	priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), -					    GFP_KERNEL); -	if (!priv->rx_skbuff_dma) -		goto err_rx_skbuff_dma; - -	priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), -					GFP_KERNEL); -	if (!priv->rx_skbuff) -		goto err_rx_skbuff; - -	priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t), -					    GFP_KERNEL); -	if (!priv->tx_skbuff_dma) -		goto err_tx_skbuff_dma; - -	priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), -					GFP_KERNEL); -	if (!priv->tx_skbuff) -		goto err_tx_skbuff; -  	if (netif_msg_probe(priv)) {  		pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,  			 (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy); @@ -1087,21 +1036,20 @@ static int init_dma_desc_rings(struct net_device *dev)  	}  	priv->cur_rx = 0;  	priv->dirty_rx = (unsigned int)(i - rxsize); -	priv->dma_buf_sz = bfsize;  	buf_sz = bfsize;  	/* Setup the chained descriptor addresses */  	if (priv->mode == STMMAC_CHAIN_MODE) {  		if (priv->extend_desc) { -			priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy, -					      rxsize, 1); -			priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy, -					      txsize, 1); +			priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy, +					     rxsize, 1); +			priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy, +					     txsize, 1);  		} else { -			priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy, -					      rxsize, 0); -			priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy, -					      txsize, 0); +			priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy, +					     rxsize, 0); +			priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy, +					     txsize, 0);  		}  	} @@ -1129,30 +1077,6 @@ static int init_dma_desc_rings(struct net_device *dev)  err_init_rx_buffers:  	while (--i >= 0)  		stmmac_free_rx_buffers(priv, i); -	kfree(priv->tx_skbuff); -err_tx_skbuff: -	kfree(priv->tx_skbuff_dma); -err_tx_skbuff_dma: -	kfree(priv->rx_skbuff); -err_rx_skbuff: -	kfree(priv->rx_skbuff_dma); -err_rx_skbuff_dma: -	if (priv->extend_desc) { -		dma_free_coherent(priv->device, priv->dma_tx_size * -				  sizeof(struct dma_extended_desc), -				  priv->dma_etx, priv->dma_tx_phy); -		dma_free_coherent(priv->device, priv->dma_rx_size * -				  sizeof(struct dma_extended_desc), -				  priv->dma_erx, priv->dma_rx_phy); -	} else { -		dma_free_coherent(priv->device, -				priv->dma_tx_size * sizeof(struct dma_desc), -				priv->dma_tx, priv->dma_tx_phy); -		dma_free_coherent(priv->device, -				priv->dma_rx_size * sizeof(struct dma_desc), -				priv->dma_rx, priv->dma_rx_phy); -	} -err_dma:  	return ret;  } @@ -1169,25 +1093,107 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)  	int i;  	for (i = 0; i < priv->dma_tx_size; i++) { -		if (priv->tx_skbuff[i] != NULL) { -			struct dma_desc *p; -			if (priv->extend_desc) -				p = &((priv->dma_etx + i)->basic); -			else -				p = priv->dma_tx + i; +		struct dma_desc *p; -			if (priv->tx_skbuff_dma[i]) -				dma_unmap_single(priv->device, -						 priv->tx_skbuff_dma[i], -						 priv->hw->desc->get_tx_len(p), -						 DMA_TO_DEVICE); +		if (priv->extend_desc) +			p = &((priv->dma_etx + i)->basic); +		else +			p = priv->dma_tx + i; + +		if (priv->tx_skbuff_dma[i]) { +			dma_unmap_single(priv->device, +					 priv->tx_skbuff_dma[i], +					 priv->hw->desc->get_tx_len(p), +					 DMA_TO_DEVICE); +			priv->tx_skbuff_dma[i] = 0; +		} + +		if (priv->tx_skbuff[i] != NULL) {  			dev_kfree_skb_any(priv->tx_skbuff[i]);  			priv->tx_skbuff[i] = NULL; -			priv->tx_skbuff_dma[i] = 0;  		}  	}  } +static int alloc_dma_desc_resources(struct stmmac_priv *priv) +{ +	unsigned int txsize = priv->dma_tx_size; +	unsigned int rxsize = priv->dma_rx_size; +	int ret = -ENOMEM; + +	priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), +					    GFP_KERNEL); +	if (!priv->rx_skbuff_dma) +		return -ENOMEM; + +	priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), +					GFP_KERNEL); +	if (!priv->rx_skbuff) +		goto err_rx_skbuff; + +	priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t), +					    GFP_KERNEL); +	if (!priv->tx_skbuff_dma) +		goto err_tx_skbuff_dma; + +	priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), +					GFP_KERNEL); +	if (!priv->tx_skbuff) +		goto err_tx_skbuff; + +	if (priv->extend_desc) { +		priv->dma_erx = dma_alloc_coherent(priv->device, rxsize * +						   sizeof(struct +							  dma_extended_desc), +						   &priv->dma_rx_phy, +						   GFP_KERNEL); +		if (!priv->dma_erx) +			goto err_dma; + +		priv->dma_etx = dma_alloc_coherent(priv->device, txsize * +						   sizeof(struct +							  dma_extended_desc), +						   &priv->dma_tx_phy, +						   GFP_KERNEL); +		if (!priv->dma_etx) { +			dma_free_coherent(priv->device, priv->dma_rx_size * +					sizeof(struct dma_extended_desc), +					priv->dma_erx, priv->dma_rx_phy); +			goto err_dma; +		} +	} else { +		priv->dma_rx = dma_alloc_coherent(priv->device, rxsize * +						  sizeof(struct dma_desc), +						  &priv->dma_rx_phy, +						  GFP_KERNEL); +		if (!priv->dma_rx) +			goto err_dma; + +		priv->dma_tx = dma_alloc_coherent(priv->device, txsize * +						  sizeof(struct dma_desc), +						  &priv->dma_tx_phy, +						  GFP_KERNEL); +		if (!priv->dma_tx) { +			dma_free_coherent(priv->device, priv->dma_rx_size * +					sizeof(struct dma_desc), +					priv->dma_rx, priv->dma_rx_phy); +			goto err_dma; +		} +	} + +	return 0; + +err_dma: +	kfree(priv->tx_skbuff); +err_tx_skbuff: +	kfree(priv->tx_skbuff_dma); +err_tx_skbuff_dma: +	kfree(priv->rx_skbuff); +err_rx_skbuff: +	kfree(priv->rx_skbuff_dma); +	return ret; +} +  static void free_dma_desc_resources(struct stmmac_priv *priv)  {  	/* Release the DMA TX/RX socket buffers */ @@ -1294,10 +1300,10 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)  					 DMA_TO_DEVICE);  			priv->tx_skbuff_dma[entry] = 0;  		} -		priv->hw->ring->clean_desc3(priv, p); +		priv->hw->mode->clean_desc3(priv, p);  		if (likely(skb != NULL)) { -			dev_kfree_skb(skb); +			dev_consume_skb_any(skb);  			priv->tx_skbuff[entry] = NULL;  		} @@ -1530,9 +1536,9 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)  					     priv->dev->dev_addr, 0);  		if (!is_valid_ether_addr(priv->dev->dev_addr))  			eth_hw_addr_random(priv->dev); +		pr_info("%s: device MAC address %pM\n", priv->dev->name, +			priv->dev->dev_addr);  	} -	pr_warn("%s: device MAC address %pM\n", priv->dev->name, -		priv->dev->dev_addr);  }  /** @@ -1597,49 +1603,29 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)  }  /** - *  stmmac_open - open entry point of the driver + * stmmac_hw_setup: setup mac in a usable state.   *  @dev : pointer to the device structure.   *  Description: - *  This function is the open entry point of the driver. + *  This function sets up the ip in a usable state.   *  Return value:   *  0 on success and an appropriate (-)ve integer as defined in errno.h   *  file on failure.   */ -static int stmmac_open(struct net_device *dev) +static int stmmac_hw_setup(struct net_device *dev)  {  	struct stmmac_priv *priv = netdev_priv(dev);  	int ret; -	clk_prepare_enable(priv->stmmac_clk); - -	stmmac_check_ether_addr(priv); - -	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && -	    priv->pcs != STMMAC_PCS_RTBI) { -		ret = stmmac_init_phy(dev); -		if (ret) { -			pr_err("%s: Cannot attach to PHY (error: %d)\n", -			       __func__, ret); -			goto phy_error; -		} -	} - -	/* Create and initialize the TX/RX descriptors chains. */ -	priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); -	priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); -	priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); -  	ret = init_dma_desc_rings(dev);  	if (ret < 0) {  		pr_err("%s: DMA descriptors initialization failed\n", __func__); -		goto dma_desc_error; +		return ret;  	} -  	/* DMA initialization and SW reset */  	ret = stmmac_init_dma_engine(priv);  	if (ret < 0) {  		pr_err("%s: DMA engine initialization failed\n", __func__); -		goto init_error; +		return ret;  	}  	/* Copy the MAC addr into the HW  */ @@ -1650,38 +1636,7 @@ static int stmmac_open(struct net_device *dev)  		priv->plat->bus_setup(priv->ioaddr);  	/* Initialize the MAC Core */ -	priv->hw->mac->core_init(priv->ioaddr); - -	/* Request the IRQ lines */ -	ret = request_irq(dev->irq, stmmac_interrupt, -			  IRQF_SHARED, dev->name, dev); -	if (unlikely(ret < 0)) { -		pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", -		       __func__, dev->irq, ret); -		goto init_error; -	} - -	/* Request the Wake IRQ in case of another line is used for WoL */ -	if (priv->wol_irq != dev->irq) { -		ret = request_irq(priv->wol_irq, stmmac_interrupt, -				  IRQF_SHARED, dev->name, dev); -		if (unlikely(ret < 0)) { -			pr_err("%s: ERROR: allocating the WoL IRQ %d (%d)\n", -			       __func__, priv->wol_irq, ret); -			goto wolirq_error; -		} -	} - -	/* Request the IRQ lines */ -	if (priv->lpi_irq != -ENXIO) { -		ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED, -				  dev->name, dev); -		if (unlikely(ret < 0)) { -			pr_err("%s: ERROR: allocating the LPI IRQ %d (%d)\n", -			       __func__, priv->lpi_irq, ret); -			goto lpiirq_error; -		} -	} +	priv->hw->mac->core_init(priv->ioaddr, dev->mtu);  	/* Enable the MAC Rx/Tx */  	stmmac_set_mac(priv->ioaddr, true); @@ -1689,14 +1644,10 @@ static int stmmac_open(struct net_device *dev)  	/* Set the HW DMA mode and the COE */  	stmmac_dma_operation_mode(priv); -	/* Extra statistics */ -	memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); -	priv->xstats.threshold = tc; -  	stmmac_mmc_setup(priv);  	ret = stmmac_init_ptp(priv); -	if (ret) +	if (ret && ret != -EOPNOTSUPP)  		pr_warn("%s: failed PTP initialisation\n", __func__);  #ifdef CONFIG_STMMAC_DEBUG_FS @@ -1714,10 +1665,6 @@ static int stmmac_open(struct net_device *dev)  		priv->hw->mac->dump_regs(priv->ioaddr);  		priv->hw->dma->dump_regs(priv->ioaddr);  	} - -	if (priv->phydev) -		phy_start(priv->phydev); -  	priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;  	priv->eee_enabled = stmmac_eee_init(priv); @@ -1732,6 +1679,90 @@ static int stmmac_open(struct net_device *dev)  	if (priv->pcs && priv->hw->mac->ctrl_ane)  		priv->hw->mac->ctrl_ane(priv->ioaddr, 0); +	return 0; +} + +/** + *  stmmac_open - open entry point of the driver + *  @dev : pointer to the device structure. + *  Description: + *  This function is the open entry point of the driver. + *  Return value: + *  0 on success and an appropriate (-)ve integer as defined in errno.h + *  file on failure. + */ +static int stmmac_open(struct net_device *dev) +{ +	struct stmmac_priv *priv = netdev_priv(dev); +	int ret; + +	stmmac_check_ether_addr(priv); + +	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && +	    priv->pcs != STMMAC_PCS_RTBI) { +		ret = stmmac_init_phy(dev); +		if (ret) { +			pr_err("%s: Cannot attach to PHY (error: %d)\n", +			       __func__, ret); +			return ret; +		} +	} + +	/* Extra statistics */ +	memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); +	priv->xstats.threshold = tc; + +	/* Create and initialize the TX/RX descriptors chains. */ +	priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); +	priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); +	priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); + +	ret = alloc_dma_desc_resources(priv); +	if (ret < 0) { +		pr_err("%s: DMA descriptors allocation failed\n", __func__); +		goto dma_desc_error; +	} + +	ret = stmmac_hw_setup(dev); +	if (ret < 0) { +		pr_err("%s: Hw setup failed\n", __func__); +		goto init_error; +	} + +	if (priv->phydev) +		phy_start(priv->phydev); + +	/* Request the IRQ lines */ +	ret = request_irq(dev->irq, stmmac_interrupt, +			  IRQF_SHARED, dev->name, dev); +	if (unlikely(ret < 0)) { +		pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", +		       __func__, dev->irq, ret); +		goto init_error; +	} + +	/* Request the Wake IRQ in case of another line is used for WoL */ +	if (priv->wol_irq != dev->irq) { +		ret = request_irq(priv->wol_irq, stmmac_interrupt, +				  IRQF_SHARED, dev->name, dev); +		if (unlikely(ret < 0)) { +			pr_err("%s: ERROR: allocating the WoL IRQ %d (%d)\n", +			       __func__, priv->wol_irq, ret); +			goto wolirq_error; +		} +	} + +	/* Request the IRQ lines */ +	if (priv->lpi_irq > 0) { +		ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED, +				  dev->name, dev); +		if (unlikely(ret < 0)) { +			pr_err("%s: ERROR: allocating the LPI IRQ %d (%d)\n", +			       __func__, priv->lpi_irq, ret); +			goto lpiirq_error; +		} +	} +  	napi_enable(&priv->napi);  	netif_start_queue(dev); @@ -1748,8 +1779,6 @@ init_error:  dma_desc_error:  	if (priv->phydev)  		phy_disconnect(priv->phydev); -phy_error: -	clk_disable_unprepare(priv->stmmac_clk);  	return ret;  } @@ -1784,7 +1813,7 @@ static int stmmac_release(struct net_device *dev)  	free_irq(dev->irq, dev);  	if (priv->wol_irq != dev->irq)  		free_irq(priv->wol_irq, dev); -	if (priv->lpi_irq != -ENXIO) +	if (priv->lpi_irq > 0)  		free_irq(priv->lpi_irq, dev);  	/* Stop TX/RX DMA and clear the descriptors */ @@ -1802,7 +1831,6 @@ static int stmmac_release(struct net_device *dev)  #ifdef CONFIG_STMMAC_DEBUG_FS  	stmmac_exit_fs();  #endif -	clk_disable_unprepare(priv->stmmac_clk);  	stmmac_release_ptp(priv); @@ -1826,6 +1854,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  	int nfrags = skb_shinfo(skb)->nr_frags;  	struct dma_desc *desc, *first;  	unsigned int nopaged_len = skb_headlen(skb); +	unsigned int enh_desc = priv->plat->enh_desc;  	if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {  		if (!netif_queue_stopped(dev)) { @@ -1852,35 +1881,26 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  	first = desc; -	priv->tx_skbuff[entry] = skb; -  	/* To program the descriptors according to the size of the frame */ -	if (priv->mode == STMMAC_RING_MODE) { -		is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len, -							priv->plat->enh_desc); -		if (unlikely(is_jumbo)) -			entry = priv->hw->ring->jumbo_frm(priv, skb, -							  csum_insertion); -	} else { -		is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len, -							 priv->plat->enh_desc); -		if (unlikely(is_jumbo)) -			entry = priv->hw->chain->jumbo_frm(priv, skb, -							   csum_insertion); -	} +	if (enh_desc) +		is_jumbo = priv->hw->mode->is_jumbo_frm(skb->len, enh_desc); +  	if (likely(!is_jumbo)) {  		desc->des2 = dma_map_single(priv->device, skb->data,  					    nopaged_len, DMA_TO_DEVICE);  		priv->tx_skbuff_dma[entry] = desc->des2;  		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,  						csum_insertion, priv->mode); -	} else +	} else {  		desc = first; +		entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion); +	}  	for (i = 0; i < nfrags; i++) {  		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];  		int len = skb_frag_size(frag); +		priv->tx_skbuff[entry] = NULL;  		entry = (++priv->cur_tx) % txsize;  		if (priv->extend_desc)  			desc = (struct dma_desc *)(priv->dma_etx + entry); @@ -1890,7 +1910,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  		desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,  					      DMA_TO_DEVICE);  		priv->tx_skbuff_dma[entry] = desc->des2; -		priv->tx_skbuff[entry] = NULL;  		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,  						priv->mode);  		wmb(); @@ -1898,6 +1917,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  		wmb();  	} +	priv->tx_skbuff[entry] = skb; +  	/* Finalize the latest segment. */  	priv->hw->desc->close_tx_desc(desc); @@ -1959,6 +1980,23 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)  	return NETDEV_TX_OK;  } +static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) +{ +	struct ethhdr *ehdr; +	u16 vlanid; + +	if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) == +	    NETIF_F_HW_VLAN_CTAG_RX && +	    !__vlan_get_tag(skb, &vlanid)) { +		/* pop the vlan tag */ +		ehdr = (struct ethhdr *)skb->data; +		memmove(skb->data + VLAN_HLEN, ehdr, ETH_ALEN * 2); +		skb_pull(skb, VLAN_HLEN); +		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid); +	} +} + +  /**   * stmmac_rx_refill: refill used skb preallocated buffers   * @priv: driver private structure @@ -1994,7 +2032,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)  			p->des2 = priv->rx_skbuff_dma[entry]; -			priv->hw->ring->refill_desc3(priv, p); +			priv->hw->mode->refill_desc3(priv, p);  			if (netif_msg_rx_status(priv))  				pr_debug("\trefill entry #%d\n", entry); @@ -2110,6 +2148,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)  				print_pkt(skb->data, frame_len);  			} +			stmmac_rx_vlan(priv->dev, skb); +  			skb->protocol = eth_type_trans(skb, priv->dev);  			if (unlikely(!coe)) @@ -2172,27 +2212,6 @@ static void stmmac_tx_timeout(struct net_device *dev)  	stmmac_tx_err(priv);  } -/* Configuration changes (passed on by ifconfig) */ -static int stmmac_config(struct net_device *dev, struct ifmap *map) -{ -	if (dev->flags & IFF_UP)	/* can't act on a running interface */ -		return -EBUSY; - -	/* Don't allow changing the I/O address */ -	if (map->base_addr != dev->base_addr) { -		pr_warn("%s: can't change I/O address\n", dev->name); -		return -EOPNOTSUPP; -	} - -	/* Don't allow changing the IRQ */ -	if (map->irq != dev->irq) { -		pr_warn("%s: not change IRQ number %d\n", dev->name, dev->irq); -		return -EOPNOTSUPP; -	} - -	return 0; -} -  /**   *  stmmac_set_rx_mode - entry point for multicast addressing   *  @dev : pointer to the device structure @@ -2237,6 +2256,9 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)  	else  		max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); +	if (priv->plat->maxmtu < max_mtu) +		max_mtu = priv->plat->maxmtu; +  	if ((new_mtu < 46) || (new_mtu > max_mtu)) {  		pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);  		return -EINVAL; @@ -2284,6 +2306,9 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)  	struct net_device *dev = (struct net_device *)dev_id;  	struct stmmac_priv *priv = netdev_priv(dev); +	if (priv->irq_wake) +		pm_wakeup_event(priv->device, 0); +  	if (unlikely(!dev)) {  		pr_err("%s: invalid dev pointer\n", __func__);  		return IRQ_NONE; @@ -2552,7 +2577,6 @@ static const struct net_device_ops stmmac_netdev_ops = {  	.ndo_set_rx_mode = stmmac_set_rx_mode,  	.ndo_tx_timeout = stmmac_tx_timeout,  	.ndo_do_ioctl = stmmac_ioctl, -	.ndo_set_config = stmmac_config,  #ifdef CONFIG_NET_POLL_CONTROLLER  	.ndo_poll_controller = stmmac_poll_controller,  #endif @@ -2590,11 +2614,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)  	/* To use the chained or ring mode */  	if (chain_mode) { -		priv->hw->chain = &chain_mode_ops; +		priv->hw->mode = &chain_mode_ops;  		pr_info(" Chain mode enabled\n");  		priv->mode = STMMAC_CHAIN_MODE;  	} else { -		priv->hw->ring = &ring_mode_ops; +		priv->hw->mode = &ring_mode_ops;  		pr_info(" Ring mode enabled\n");  		priv->mode = STMMAC_RING_MODE;  	} @@ -2688,10 +2712,32 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  	if ((phyaddr >= 0) && (phyaddr <= 31))  		priv->plat->phy_addr = phyaddr; +	priv->stmmac_clk = devm_clk_get(priv->device, STMMAC_RESOURCE_NAME); +	if (IS_ERR(priv->stmmac_clk)) { +		dev_warn(priv->device, "%s: warning: cannot get CSR clock\n", +			 __func__); +		ret = PTR_ERR(priv->stmmac_clk); +		goto error_clk_get; +	} +	clk_prepare_enable(priv->stmmac_clk); + +	priv->stmmac_rst = devm_reset_control_get(priv->device, +						  STMMAC_RESOURCE_NAME); +	if (IS_ERR(priv->stmmac_rst)) { +		if (PTR_ERR(priv->stmmac_rst) == -EPROBE_DEFER) { +			ret = -EPROBE_DEFER; +			goto error_hw_init; +		} +		dev_info(priv->device, "no reset control found\n"); +		priv->stmmac_rst = NULL; +	} +	if (priv->stmmac_rst) +		reset_control_deassert(priv->stmmac_rst); +  	/* Init MAC and get the capabilities */  	ret = stmmac_hw_init(priv);  	if (ret) -		goto error_free_netdev; +		goto error_hw_init;  	ndev->netdev_ops = &stmmac_netdev_ops; @@ -2729,12 +2775,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  		goto error_netdev_register;  	} -	priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME); -	if (IS_ERR(priv->stmmac_clk)) { -		pr_warn("%s: warning: cannot get CSR clock\n", __func__); -		goto error_clk_get; -	} -  	/* If a specific clk_csr value is passed from the platform  	 * this means that the CSR Clock Range selection cannot be  	 * changed at run-time and it is fixed. Viceversa the driver'll try to @@ -2762,15 +2802,15 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,  	return priv;  error_mdio_register: -	clk_put(priv->stmmac_clk); -error_clk_get:  	unregister_netdev(ndev);  error_netdev_register:  	netif_napi_del(&priv->napi); -error_free_netdev: +error_hw_init: +	clk_disable_unprepare(priv->stmmac_clk); +error_clk_get:  	free_netdev(ndev); -	return NULL; +	return ERR_PTR(ret);  }  /** @@ -2794,6 +2834,9 @@ int stmmac_dvr_remove(struct net_device *ndev)  		stmmac_mdio_unregister(ndev);  	netif_carrier_off(ndev);  	unregister_netdev(ndev); +	if (priv->stmmac_rst) +		reset_control_assert(priv->stmmac_rst); +	clk_disable_unprepare(priv->stmmac_clk);  	free_netdev(ndev);  	return 0; @@ -2825,10 +2868,12 @@ int stmmac_suspend(struct net_device *ndev)  	stmmac_clear_descriptors(priv);  	/* Enable Power down mode by programming the PMT regs */ -	if (device_may_wakeup(priv->device)) +	if (device_may_wakeup(priv->device)) {  		priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); -	else { +		priv->irq_wake = 1; +	} else {  		stmmac_set_mac(priv->ioaddr, false); +		pinctrl_pm_select_sleep_state(priv->device);  		/* Disable clock in case of PWM is off */  		clk_disable_unprepare(priv->stmmac_clk);  	} @@ -2852,18 +2897,21 @@ int stmmac_resume(struct net_device *ndev)  	 * this bit because it can generate problems while resuming  	 * from another devices (e.g. serial console).  	 */ -	if (device_may_wakeup(priv->device)) +	if (device_may_wakeup(priv->device)) {  		priv->hw->mac->pmt(priv->ioaddr, 0); -	else +		priv->irq_wake = 0; +	} else { +		pinctrl_pm_select_default_state(priv->device);  		/* enable the clk prevously disabled */  		clk_prepare_enable(priv->stmmac_clk); +		/* reset the phy so that it's ready */ +		if (priv->mii) +			stmmac_mdio_reset(priv->mii); +	}  	netif_device_attach(ndev); -	/* Enable the MAC and DMA */ -	stmmac_set_mac(priv->ioaddr, true); -	priv->hw->dma->start_tx(priv->ioaddr); -	priv->hw->dma->start_rx(priv->ioaddr); +	stmmac_hw_setup(ndev);  	napi_enable(&priv->napi); @@ -2876,22 +2924,6 @@ int stmmac_resume(struct net_device *ndev)  	return 0;  } - -int stmmac_freeze(struct net_device *ndev) -{ -	if (!ndev || !netif_running(ndev)) -		return 0; - -	return stmmac_release(ndev); -} - -int stmmac_restore(struct net_device *ndev) -{ -	if (!ndev || !netif_running(ndev)) -		return 0; - -	return stmmac_open(ndev); -}  #endif /* CONFIG_PM */  /* Driver can be configured w/ and w/ both PCI and Platf drivers diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index fe7bc990386..a5b1e1b776f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -128,7 +128,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,   * @bus: points to the mii_bus structure   * Description: reset the MII bus   */ -static int stmmac_mdio_reset(struct mii_bus *bus) +int stmmac_mdio_reset(struct mii_bus *bus)  {  #if defined(CONFIG_STMMAC_PLATFORM)  	struct net_device *ndev = bus->priv; @@ -166,7 +166,6 @@ static int stmmac_mdio_reset(struct mii_bus *bus)  			udelay(data->delays[1]);  			gpio_set_value(reset_gpio, active_low ? 1 : 0);  			udelay(data->delays[2]); -			gpio_free(reset_gpio);  		}  	}  #endif @@ -206,10 +205,13 @@ int stmmac_mdio_register(struct net_device *ndev)  	if (new_bus == NULL)  		return -ENOMEM; -	if (mdio_bus_data->irqs) +	if (mdio_bus_data->irqs) {  		irqlist = mdio_bus_data->irqs; -	else +	} else { +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) +			priv->mii_irq[addr] = PHY_POLL;  		irqlist = priv->mii_irq; +	}  #ifdef CONFIG_OF  	if (priv->device->of_node) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 023b7c29cb2..29160892484 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -26,9 +26,9 @@  #include <linux/pci.h>  #include "stmmac.h" -struct plat_stmmacenet_data plat_dat; -struct stmmac_mdio_bus_data mdio_data; -struct stmmac_dma_cfg dma_cfg; +static struct plat_stmmacenet_data plat_dat; +static struct stmmac_mdio_bus_data mdio_data; +static struct stmmac_dma_cfg dma_cfg;  static void stmmac_default_data(void)  { @@ -100,9 +100,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev,  	stmmac_default_data();  	priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr); -	if (!priv) { +	if (IS_ERR(priv)) {  		pr_err("%s: main driver probe failed", __func__); -		ret = -ENODEV; +		ret = PTR_ERR(priv);  		goto err_out;  	}  	priv->dev->irq = pdev->irq; @@ -138,7 +138,6 @@ static void stmmac_pci_remove(struct pci_dev *pdev)  	stmmac_dvr_remove(ndev); -	pci_set_drvdata(pdev, NULL);  	pci_iounmap(pdev, priv->ioaddr);  	pci_release_regions(pdev);  	pci_disable_device(pdev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 51c9069ef40..ea7a65be1f9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -26,8 +26,31 @@  #include <linux/io.h>  #include <linux/of.h>  #include <linux/of_net.h> +#include <linux/of_device.h>  #include "stmmac.h" +static const struct of_device_id stmmac_dt_ids[] = { +#ifdef CONFIG_DWMAC_SUNXI +	{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, +#endif +#ifdef CONFIG_DWMAC_STI +	{ .compatible = "st,stih415-dwmac", .data = &sti_gmac_data}, +	{ .compatible = "st,stih416-dwmac", .data = &sti_gmac_data}, +	{ .compatible = "st,stid127-dwmac", .data = &sti_gmac_data}, +#endif +#ifdef CONFIG_DWMAC_SOCFPGA +	{ .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data }, +#endif +	/* SoC specific glue layers should come before generic bindings */ +	{ .compatible = "st,spear600-gmac"}, +	{ .compatible = "snps,dwmac-3.610"}, +	{ .compatible = "snps,dwmac-3.70a"}, +	{ .compatible = "snps,dwmac-3.710"}, +	{ .compatible = "snps,dwmac"}, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, stmmac_dt_ids); +  #ifdef CONFIG_OF  static int stmmac_probe_config_dt(struct platform_device *pdev,  				  struct plat_stmmacenet_data *plat, @@ -35,23 +58,63 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,  {  	struct device_node *np = pdev->dev.of_node;  	struct stmmac_dma_cfg *dma_cfg; +	const struct of_device_id *device;  	if (!np)  		return -ENODEV; +	device = of_match_device(stmmac_dt_ids, &pdev->dev); +	if (!device) +		return -ENODEV; + +	if (device->data) { +		const struct stmmac_of_data *data = device->data; +		plat->has_gmac = data->has_gmac; +		plat->enh_desc = data->enh_desc; +		plat->tx_coe = data->tx_coe; +		plat->rx_coe = data->rx_coe; +		plat->bugged_jumbo = data->bugged_jumbo; +		plat->pmt = data->pmt; +		plat->riwt_off = data->riwt_off; +		plat->fix_mac_speed = data->fix_mac_speed; +		plat->bus_setup = data->bus_setup; +		plat->setup = data->setup; +		plat->free = data->free; +		plat->init = data->init; +		plat->exit = data->exit; +	} +  	*mac = of_get_mac_address(np);  	plat->interface = of_get_phy_mode(np); +	/* Get max speed of operation from device tree */ +	if (of_property_read_u32(np, "max-speed", &plat->max_speed)) +		plat->max_speed = -1; +  	plat->bus_id = of_alias_get_id(np, "ethernet");  	if (plat->bus_id < 0)  		plat->bus_id = 0; -	of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr); +	/* Default to phy auto-detection */ +	plat->phy_addr = -1; + +	/* "snps,phy-addr" is not a standard property. Mark it as deprecated +	 * and warn of its use. Remove this when phy node support is added. +	 */ +	if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0) +		dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");  	plat->mdio_bus_data = devm_kzalloc(&pdev->dev,  					   sizeof(struct stmmac_mdio_bus_data),  					   GFP_KERNEL); +	plat->force_sf_dma_mode = of_property_read_bool(np, "snps,force_sf_dma_mode"); + +	/* Set the maxmtu to a default of JUMBO_LEN in case the +	 * parameter is not present in the device tree. +	 */ +	plat->maxmtu = JUMBO_LEN; +  	/*  	 * Currently only the properties needed on SPEAr600  	 * are provided. All other properties should be added @@ -60,6 +123,14 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,  	if (of_device_is_compatible(np, "st,spear600-gmac") ||  		of_device_is_compatible(np, "snps,dwmac-3.70a") ||  		of_device_is_compatible(np, "snps,dwmac")) { +		/* Note that the max-frame-size parameter as defined in the +		 * ePAPR v1.1 spec is defined as max-frame-size, it's +		 * actually used as the IEEE definition of MAC Client +		 * data, or MTU. The ePAPR specification is confusing as +		 * the definition is max-frame-size, but usage examples +		 * are clearly MTUs +		 */ +		of_property_read_u32(np, "max-frame-size", &plat->maxmtu);  		plat->has_gmac = 1;  		plat->pmt = 1;  	} @@ -140,17 +211,24 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)  		}  	} +	/* Custom setup (if needed) */ +	if (plat_dat->setup) { +		plat_dat->bsp_priv = plat_dat->setup(pdev); +		if (IS_ERR(plat_dat->bsp_priv)) +			return PTR_ERR(plat_dat->bsp_priv); +	} +  	/* Custom initialisation (if needed)*/  	if (plat_dat->init) { -		ret = plat_dat->init(pdev); +		ret = plat_dat->init(pdev, plat_dat->bsp_priv);  		if (unlikely(ret))  			return ret;  	}  	priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr); -	if (!priv) { +	if (IS_ERR(priv)) {  		pr_err("%s: main driver probe failed", __func__); -		return -ENODEV; +		return PTR_ERR(priv);  	}  	/* Get MAC address if available (DT) */ @@ -159,10 +237,12 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)  	/* Get the MAC information */  	priv->dev->irq = platform_get_irq_byname(pdev, "macirq"); -	if (priv->dev->irq == -ENXIO) { -		pr_err("%s: ERROR: MAC IRQ configuration " -		       "information not found\n", __func__); -		return -ENXIO; +	if (priv->dev->irq < 0) { +		if (priv->dev->irq != -EPROBE_DEFER) { +			netdev_err(priv->dev, +				   "MAC IRQ configuration information not found\n"); +		} +		return priv->dev->irq;  	}  	/* @@ -174,10 +254,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)  	 * so the driver will continue to use the mac irq (ndev->irq)  	 */  	priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); -	if (priv->wol_irq == -ENXIO) +	if (priv->wol_irq < 0) { +		if (priv->wol_irq == -EPROBE_DEFER) +			return -EPROBE_DEFER;  		priv->wol_irq = priv->dev->irq; +	}  	priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); +	if (priv->lpi_irq == -EPROBE_DEFER) +		return -EPROBE_DEFER;  	platform_set_drvdata(pdev, priv->dev); @@ -199,7 +284,10 @@ static int stmmac_pltfr_remove(struct platform_device *pdev)  	int ret = stmmac_dvr_remove(ndev);  	if (priv->plat->exit) -		priv->plat->exit(pdev); +		priv->plat->exit(pdev, priv->plat->bsp_priv); + +	if (priv->plat->free) +		priv->plat->free(pdev, priv->plat->bsp_priv);  	return ret;  } @@ -207,64 +295,34 @@ static int stmmac_pltfr_remove(struct platform_device *pdev)  #ifdef CONFIG_PM  static int stmmac_pltfr_suspend(struct device *dev)  { -	struct net_device *ndev = dev_get_drvdata(dev); - -	return stmmac_suspend(ndev); -} - -static int stmmac_pltfr_resume(struct device *dev) -{ -	struct net_device *ndev = dev_get_drvdata(dev); - -	return stmmac_resume(ndev); -} - -int stmmac_pltfr_freeze(struct device *dev) -{  	int ret; -	struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev);  	struct net_device *ndev = dev_get_drvdata(dev); +	struct stmmac_priv *priv = netdev_priv(ndev);  	struct platform_device *pdev = to_platform_device(dev); -	ret = stmmac_freeze(ndev); -	if (plat_dat->exit) -		plat_dat->exit(pdev); +	ret = stmmac_suspend(ndev); +	if (priv->plat->exit) +		priv->plat->exit(pdev, priv->plat->bsp_priv);  	return ret;  } -int stmmac_pltfr_restore(struct device *dev) +static int stmmac_pltfr_resume(struct device *dev)  { -	struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev);  	struct net_device *ndev = dev_get_drvdata(dev); +	struct stmmac_priv *priv = netdev_priv(ndev);  	struct platform_device *pdev = to_platform_device(dev); -	if (plat_dat->init) -		plat_dat->init(pdev); +	if (priv->plat->init) +		priv->plat->init(pdev, priv->plat->bsp_priv); -	return stmmac_restore(ndev); +	return stmmac_resume(ndev);  } -static const struct dev_pm_ops stmmac_pltfr_pm_ops = { -	.suspend = stmmac_pltfr_suspend, -	.resume = stmmac_pltfr_resume, -	.freeze = stmmac_pltfr_freeze, -	.thaw = stmmac_pltfr_restore, -	.restore = stmmac_pltfr_restore, -}; -#else -static const struct dev_pm_ops stmmac_pltfr_pm_ops;  #endif /* CONFIG_PM */ -static const struct of_device_id stmmac_dt_ids[] = { -	{ .compatible = "st,spear600-gmac"}, -	{ .compatible = "snps,dwmac-3.610"}, -	{ .compatible = "snps,dwmac-3.70a"}, -	{ .compatible = "snps,dwmac-3.710"}, -	{ .compatible = "snps,dwmac"}, -	{ /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, stmmac_dt_ids); +static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, +			stmmac_pltfr_suspend, stmmac_pltfr_resume);  struct platform_driver stmmac_pltfr_driver = {  	.probe = stmmac_pltfr_probe, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index b8b0eeed0f9..b7ad3565566 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -56,7 +56,7 @@ static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)  	priv->hw->ptp->config_addend(priv->ioaddr, addend); -	spin_unlock_irqrestore(&priv->lock, flags); +	spin_unlock_irqrestore(&priv->ptp_lock, flags);  	return 0;  } @@ -91,7 +91,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)  	priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj); -	spin_unlock_irqrestore(&priv->lock, flags); +	spin_unlock_irqrestore(&priv->ptp_lock, flags);  	return 0;  } @@ -164,6 +164,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {  	.n_alarm = 0,  	.n_ext_ts = 0,  	.n_per_out = 0, +	.n_pins = 0,  	.pps = 0,  	.adjfreq = stmmac_adjust_freq,  	.adjtime = stmmac_adjust_time,  | 
