aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/stmicro
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/stmicro')
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig34
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h51
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c130
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c330
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c140
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h7
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c69
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h17
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c72
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c97
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c24
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h28
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c838
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c56
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c198
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c5
26 files changed, 1441 insertions, 722 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 43c1f322332..2d09c116cbc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -1,11 +1,11 @@
config STMMAC_ETH
tristate "STMicroelectronics 10/100/1000 Ethernet driver"
depends on HAS_IOMEM && HAS_DMA
- select NET_CORE
select MII
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
@@ -26,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 7788fbe44f0..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>
@@ -38,16 +37,6 @@
#include "descs.h"
#include "mmc.h"
-#undef CHIP_DEBUG_PRINT
-/* Turn-on extra printk debug for MAC core, dma and descriptors */
-/* #define CHIP_DEBUG_PRINT */
-
-#ifdef CHIP_DEBUG_PRINT
-#define CHIP_DBG(fmt, args...) printk(fmt, ## args)
-#else
-#define CHIP_DBG(fmt, args...) do { } while (0)
-#endif
-
/* Synopsys Core versions */
#define DWMAC_CORE_3_40 0x34
#define DWMAC_CORE_3_50 0x35
@@ -297,12 +286,14 @@ struct dma_features {
#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
/* Default LPI timers */
-#define STMMAC_DEFAULT_LIT_LS_TIMER 0x3E8
-#define STMMAC_DEFAULT_TWT_LS_TIMER 0x0
+#define STMMAC_DEFAULT_LIT_LS 0x3E8
+#define STMMAC_DEFAULT_TWT_LS 0x0
#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,
@@ -379,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 */
@@ -428,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);
};
@@ -450,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;
@@ -461,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, &reg_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, &reg_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 7e05e8d0f1c..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 */
@@ -91,8 +96,8 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
unsigned int value = 0;
unsigned int perfect_addr_number;
- CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
- __func__, netdev_mc_count(dev), netdev_uc_count(dev));
+ pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
+ netdev_mc_count(dev), netdev_uc_count(dev));
if (dev->flags & IFF_PROMISC)
value = GMAC_FRAME_FILTER_PR;
@@ -152,7 +157,7 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
#endif
writel(value, ioaddr + GMAC_FRAME_FILTER);
- CHIP_DBG(KERN_INFO "\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n",
+ pr_debug("\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n",
readl(ioaddr + GMAC_FRAME_FILTER),
readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
}
@@ -162,18 +167,18 @@ static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
{
unsigned int flow = 0;
- CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n");
+ pr_debug("GMAC Flow-Control:\n");
if (fc & FLOW_RX) {
- CHIP_DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
+ pr_debug("\tReceive Flow-Control ON\n");
flow |= GMAC_FLOW_CTRL_RFE;
}
if (fc & FLOW_TX) {
- CHIP_DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
+ pr_debug("\tTransmit Flow-Control ON\n");
flow |= GMAC_FLOW_CTRL_TFE;
}
if (duplex) {
- CHIP_DBG(KERN_DEBUG "\tduplex mode: PAUSE %d\n", pause_time);
+ pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
}
@@ -185,11 +190,11 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
unsigned int pmt = 0;
if (mode & WAKE_MAGIC) {
- CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
+ pr_debug("GMAC: WOL Magic frame\n");
pmt |= power_down | magic_pkt_en;
}
if (mode & WAKE_UCAST) {
- CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
+ pr_debug("GMAC: WOL on global unicast\n");
pmt |= global_unicast;
}
@@ -203,23 +208,13 @@ static int dwmac1000_irq_status(void __iomem *ioaddr,
int ret = 0;
/* Not used events (e.g. MMC interrupts) are not handled. */
- if ((intr_status & mmc_tx_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_TX_INTR));
+ if ((intr_status & mmc_tx_irq))
x->mmc_tx_irq_n++;
- }
- if (unlikely(intr_status & mmc_rx_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_RX_INTR));
+ if (unlikely(intr_status & mmc_rx_irq))
x->mmc_rx_irq_n++;
- }
- if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+ if (unlikely(intr_status & mmc_rx_csum_offload_irq))
x->mmc_rx_csum_offload_irq_n++;
- }
if (unlikely(intr_status & pmt_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
/* clear the PMT bits 5 and 6 by reading the PMT status reg */
readl(ioaddr + GMAC_PMT);
x->irq_receive_pmt_irq_n++;
@@ -229,32 +224,22 @@ static int dwmac1000_irq_status(void __iomem *ioaddr,
/* Clean LPI interrupt by reading the Reg 12 */
ret = readl(ioaddr + LPI_CTRL_STATUS);
- if (ret & LPI_CTRL_STATUS_TLPIEN) {
- CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
+ if (ret & LPI_CTRL_STATUS_TLPIEN)
x->irq_tx_path_in_lpi_mode_n++;
- }
- if (ret & LPI_CTRL_STATUS_TLPIEX) {
- CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n");
+ if (ret & LPI_CTRL_STATUS_TLPIEX)
x->irq_tx_path_exit_lpi_mode_n++;
- }
- if (ret & LPI_CTRL_STATUS_RLPIEN) {
- CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n");
+ if (ret & LPI_CTRL_STATUS_RLPIEN)
x->irq_rx_path_in_lpi_mode_n++;
- }
- if (ret & LPI_CTRL_STATUS_RLPIEX) {
- CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n");
+ if (ret & LPI_CTRL_STATUS_RLPIEX)
x->irq_rx_path_exit_lpi_mode_n++;
- }
}
if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
- CHIP_DBG(KERN_INFO "GMAC PCS ANE IRQ\n");
readl(ioaddr + GMAC_AN_STATUS);
x->irq_pcs_ane_n++;
}
if (intr_status & rgmii_irq) {
u32 status = readl(ioaddr + GMAC_S_R_GMII);
- CHIP_DBG(KERN_INFO "GMAC RGMII/SGMII interrupt\n");
x->irq_rgmii_n++;
/* Save and dump the link status. */
@@ -271,11 +256,12 @@ static int dwmac1000_irq_status(void __iomem *ioaddr,
x->pcs_speed = SPEED_10;
x->pcs_link = 1;
- pr_debug("Link is Up - %d/%s\n", (int)x->pcs_speed,
+ pr_debug("%s: Link is Up - %d/%s\n", __func__,
+ (int)x->pcs_speed,
x->pcs_duplex ? "Full" : "Half");
} else {
x->pcs_link = 0;
- pr_debug("Link is Down\n");
+ pr_debug("%s: Link is Down\n", __func__);
}
}
@@ -334,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/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 2c431b61605..0c2058a69fd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -116,7 +116,7 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
u32 csr6 = readl(ioaddr + DMA_CONTROL);
if (txmode == SF_DMA_MODE) {
- CHIP_DBG(KERN_DEBUG "GMAC: enable TX store and forward mode\n");
+ pr_debug("GMAC: enable TX store and forward mode\n");
/* Transmit COE type 2 cannot be done in cut-through mode. */
csr6 |= DMA_CONTROL_TSF;
/* Operating on second frame increase the performance
@@ -124,8 +124,7 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
*/
csr6 |= DMA_CONTROL_OSF;
} else {
- CHIP_DBG(KERN_DEBUG "GMAC: disabling TX SF (threshold %d)\n",
- txmode);
+ pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
csr6 &= ~DMA_CONTROL_TSF;
csr6 &= DMA_CONTROL_TC_TX_MASK;
/* Set the transmit threshold */
@@ -142,11 +141,10 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
}
if (rxmode == SF_DMA_MODE) {
- CHIP_DBG(KERN_DEBUG "GMAC: enable RX store and forward mode\n");
+ pr_debug("GMAC: enable RX store and forward mode\n");
csr6 |= DMA_CONTROL_RSF;
} else {
- CHIP_DBG(KERN_DEBUG "GMAC: disable RX SF mode (threshold %d)\n",
- rxmode);
+ pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
csr6 &= ~DMA_CONTROL_RSF;
csr6 &= DMA_CONTROL_TC_RX_MASK;
if (rxmode <= 32)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index 007bb2be3f1..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);
@@ -135,10 +135,6 @@ static void dwmac100_set_filter(struct net_device *dev, int id)
}
writel(value, ioaddr + MAC_CONTROL);
-
- CHIP_DBG(KERN_INFO "%s: Filter: 0x%08x Hash: HI 0x%08x, LO 0x%08x\n",
- __func__, readl(ioaddr + MAC_CONTROL),
- readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
}
static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index 67551c15413..7d1dce9e7ff 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -90,14 +90,14 @@ static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
{
int i;
- CHIP_DBG(KERN_DEBUG "DWMAC 100 DMA CSR\n");
+ pr_debug("DWMAC 100 DMA CSR\n");
for (i = 0; i < 9; i++)
pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
(DMA_BUS_MODE + i * 4),
readl(ioaddr + DMA_BUS_MODE + i * 4));
- CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
- DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
- CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
+
+ pr_debug("\tCSR20 (0x%x): 0x%08x, CSR21 (0x%x): 0x%08x\n",
+ DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR),
DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
}
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/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 491d7e93060..484e3cf9c41 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -24,13 +24,6 @@
#include "common.h"
#include "dwmac_dma.h"
-#undef DWMAC_DMA_DEBUG
-#ifdef DWMAC_DMA_DEBUG
-#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args)
-#else
-#define DWMAC_LIB_DBG(fmt, args...) do { } while (0)
-#endif
-
#define GMAC_HI_REG_AE 0x80000000
/* CSR1 enables the transmit DMA to check for new descriptor */
@@ -85,24 +78,24 @@ static void show_tx_process_state(unsigned int status)
switch (state) {
case 0:
- pr_info("- TX (Stopped): Reset or Stop command\n");
+ pr_debug("- TX (Stopped): Reset or Stop command\n");
break;
case 1:
- pr_info("- TX (Running):Fetching the Tx desc\n");
+ pr_debug("- TX (Running):Fetching the Tx desc\n");
break;
case 2:
- pr_info("- TX (Running): Waiting for end of tx\n");
+ pr_debug("- TX (Running): Waiting for end of tx\n");
break;
case 3:
- pr_info("- TX (Running): Reading the data "
+ pr_debug("- TX (Running): Reading the data "
"and queuing the data into the Tx buf\n");
break;
case 6:
- pr_info("- TX (Suspended): Tx Buff Underflow "
+ pr_debug("- TX (Suspended): Tx Buff Underflow "
"or an unavailable Transmit descriptor\n");
break;
case 7:
- pr_info("- TX (Running): Closing Tx descriptor\n");
+ pr_debug("- TX (Running): Closing Tx descriptor\n");
break;
default:
break;
@@ -116,29 +109,29 @@ static void show_rx_process_state(unsigned int status)
switch (state) {
case 0:
- pr_info("- RX (Stopped): Reset or Stop command\n");
+ pr_debug("- RX (Stopped): Reset or Stop command\n");
break;
case 1:
- pr_info("- RX (Running): Fetching the Rx desc\n");
+ pr_debug("- RX (Running): Fetching the Rx desc\n");
break;
case 2:
- pr_info("- RX (Running):Checking for end of pkt\n");
+ pr_debug("- RX (Running):Checking for end of pkt\n");
break;
case 3:
- pr_info("- RX (Running): Waiting for Rx pkt\n");
+ pr_debug("- RX (Running): Waiting for Rx pkt\n");
break;
case 4:
- pr_info("- RX (Suspended): Unavailable Rx buf\n");
+ pr_debug("- RX (Suspended): Unavailable Rx buf\n");
break;
case 5:
- pr_info("- RX (Running): Closing Rx descriptor\n");
+ pr_debug("- RX (Running): Closing Rx descriptor\n");
break;
case 6:
- pr_info("- RX(Running): Flushing the current frame"
+ pr_debug("- RX(Running): Flushing the current frame"
" from the Rx buf\n");
break;
case 7:
- pr_info("- RX (Running): Queuing the Rx frame"
+ pr_debug("- RX (Running): Queuing the Rx frame"
" from the Rx buf into memory\n");
break;
default:
@@ -154,51 +147,37 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
/* read the status register (CSR5) */
u32 intr_status = readl(ioaddr + DMA_STATUS);
- DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
#ifdef DWMAC_DMA_DEBUG
- /* It displays the DMA process states (CSR5 register) */
+ /* Enable it to monitor DMA rx/tx status in case of critical problems */
+ pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);
show_tx_process_state(intr_status);
show_rx_process_state(intr_status);
#endif
/* ABNORMAL interrupts */
if (unlikely(intr_status & DMA_STATUS_AIS)) {
- DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: ");
if (unlikely(intr_status & DMA_STATUS_UNF)) {
- DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n");
ret = tx_hard_error_bump_tc;
x->tx_undeflow_irq++;
}
- if (unlikely(intr_status & DMA_STATUS_TJT)) {
- DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n");
+ if (unlikely(intr_status & DMA_STATUS_TJT))
x->tx_jabber_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_OVF)) {
- DWMAC_LIB_DBG(KERN_INFO "recv overflow\n");
+
+ if (unlikely(intr_status & DMA_STATUS_OVF))
x->rx_overflow_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_RU)) {
- DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n");
+
+ if (unlikely(intr_status & DMA_STATUS_RU))
x->rx_buf_unav_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_RPS)) {
- DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n");
+ if (unlikely(intr_status & DMA_STATUS_RPS))
x->rx_process_stopped_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_RWT)) {
- DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n");
+ if (unlikely(intr_status & DMA_STATUS_RWT))
x->rx_watchdog_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_ETI)) {
- DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n");
+ if (unlikely(intr_status & DMA_STATUS_ETI))
x->tx_early_irq++;
- }
if (unlikely(intr_status & DMA_STATUS_TPS)) {
- DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n");
x->tx_process_stopped_irq++;
ret = tx_hard_error;
}
if (unlikely(intr_status & DMA_STATUS_FBI)) {
- DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n");
x->fatal_bus_error_irq++;
ret = tx_hard_error;
}
@@ -224,12 +203,11 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
/* Optional hardware blocks, interrupts should be disabled */
if (unlikely(intr_status &
(DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
- pr_info("%s: unexpected status %08x\n", __func__, intr_status);
+ pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
- DWMAC_LIB_DBG(KERN_INFO "\n\n");
return ret;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 0fbc8fafa70..1e2bcf5f89e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -33,54 +33,40 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(p->des01.etx.error_summary)) {
- CHIP_DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
- if (unlikely(p->des01.etx.jabber_timeout)) {
- CHIP_DBG(KERN_ERR "\tjabber_timeout error\n");
+ if (unlikely(p->des01.etx.jabber_timeout))
x->tx_jabber++;
- }
if (unlikely(p->des01.etx.frame_flushed)) {
- CHIP_DBG(KERN_ERR "\tframe_flushed error\n");
x->tx_frame_flushed++;
dwmac_dma_flush_tx_fifo(ioaddr);
}
if (unlikely(p->des01.etx.loss_carrier)) {
- CHIP_DBG(KERN_ERR "\tloss_carrier error\n");
x->tx_losscarrier++;
stats->tx_carrier_errors++;
}
if (unlikely(p->des01.etx.no_carrier)) {
- CHIP_DBG(KERN_ERR "\tno_carrier error\n");
x->tx_carrier++;
stats->tx_carrier_errors++;
}
- if (unlikely(p->des01.etx.late_collision)) {
- CHIP_DBG(KERN_ERR "\tlate_collision error\n");
+ if (unlikely(p->des01.etx.late_collision))
stats->collisions += p->des01.etx.collision_count;
- }
- if (unlikely(p->des01.etx.excessive_collisions)) {
- CHIP_DBG(KERN_ERR "\texcessive_collisions\n");
+
+ if (unlikely(p->des01.etx.excessive_collisions))
stats->collisions += p->des01.etx.collision_count;
- }
- if (unlikely(p->des01.etx.excessive_deferral)) {
- CHIP_DBG(KERN_INFO "\texcessive tx_deferral\n");
+
+ if (unlikely(p->des01.etx.excessive_deferral))
x->tx_deferred++;
- }
if (unlikely(p->des01.etx.underflow_error)) {
- CHIP_DBG(KERN_ERR "\tunderflow error\n");
dwmac_dma_flush_tx_fifo(ioaddr);
x->tx_underflow++;
}
- if (unlikely(p->des01.etx.ip_header_error)) {
- CHIP_DBG(KERN_ERR "\tTX IP header csum error\n");
+ if (unlikely(p->des01.etx.ip_header_error))
x->tx_ip_header_error++;
- }
if (unlikely(p->des01.etx.payload_error)) {
- CHIP_DBG(KERN_ERR "\tAddr/Payload csum error\n");
x->tx_payload_error++;
dwmac_dma_flush_tx_fifo(ioaddr);
}
@@ -88,15 +74,12 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
ret = -1;
}
- if (unlikely(p->des01.etx.deferred)) {
- CHIP_DBG(KERN_INFO "GMAC TX status: tx deferred\n");
+ if (unlikely(p->des01.etx.deferred))
x->tx_deferred++;
- }
+
#ifdef STMMAC_VLAN_TAG_USED
- if (p->des01.etx.vlan_frame) {
- CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
+ if (p->des01.etx.vlan_frame)
x->tx_vlan++;
- }
#endif
return ret;
@@ -123,30 +106,20 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
* 0 1 1 | COE bypassed.. no IPv4/6 frame
* 0 1 0 | Reserved.
*/
- if (status == 0x0) {
- CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
+ if (status == 0x0)
ret = llc_snap;
- } else if (status == 0x4) {
- CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
+ else if (status == 0x4)
ret = good_frame;
- } else if (status == 0x5) {
- CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
+ else if (status == 0x5)
ret = csum_none;
- } else if (status == 0x6) {
- CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
+ else if (status == 0x6)
ret = csum_none;
- } else if (status == 0x7) {
- CHIP_DBG(KERN_ERR
- "RX Des0 status: IPv4/6 Header and Payload Error.\n");
+ else if (status == 0x7)
ret = csum_none;
- } else if (status == 0x1) {
- CHIP_DBG(KERN_ERR
- "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
+ else if (status == 0x1)
ret = discard_frame;
- } else if (status == 0x3) {
- CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
+ else if (status == 0x3)
ret = discard_frame;
- }
return ret;
}
@@ -172,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++;
@@ -208,36 +181,26 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(p->des01.erx.error_summary)) {
- CHIP_DBG(KERN_ERR "GMAC RX Error Summary 0x%08x\n",
- p->des01.erx);
if (unlikely(p->des01.erx.descriptor_error)) {
- CHIP_DBG(KERN_ERR "\tdescriptor error\n");
x->rx_desc++;
stats->rx_length_errors++;
}
- if (unlikely(p->des01.erx.overflow_error)) {
- CHIP_DBG(KERN_ERR "\toverflow error\n");
+ if (unlikely(p->des01.erx.overflow_error))
x->rx_gmac_overflow++;
- }
if (unlikely(p->des01.erx.ipc_csum_error))
- CHIP_DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
+ pr_err("\tIPC Csum Error/Giant frame\n");
if (unlikely(p->des01.erx.late_collision)) {
- CHIP_DBG(KERN_ERR "\tlate_collision error\n");
- stats->collisions++;
stats->collisions++;
}
- if (unlikely(p->des01.erx.receive_watchdog)) {
- CHIP_DBG(KERN_ERR "\treceive_watchdog error\n");
+ if (unlikely(p->des01.erx.receive_watchdog))
x->rx_watchdog++;
- }
- if (unlikely(p->des01.erx.error_gmii)) {
- CHIP_DBG(KERN_ERR "\tReceive Error\n");
+
+ if (unlikely(p->des01.erx.error_gmii))
x->rx_mii++;
- }
+
if (unlikely(p->des01.erx.crc_error)) {
- CHIP_DBG(KERN_ERR "\tCRC error\n");
x->rx_crc++;
stats->rx_crc_errors++;
}
@@ -251,30 +214,24 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
- if (unlikely(p->des01.erx.dribbling)) {
- CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
+ if (unlikely(p->des01.erx.dribbling))
x->dribbling_bit++;
- }
+
if (unlikely(p->des01.erx.sa_filter_fail)) {
- CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
x->sa_rx_filter_fail++;
ret = discard_frame;
}
if (unlikely(p->des01.erx.da_filter_fail)) {
- CHIP_DBG(KERN_ERR "GMAC RX : Dest Address filter fail\n");
x->da_rx_filter_fail++;
ret = discard_frame;
}
if (unlikely(p->des01.erx.length_error)) {
- CHIP_DBG(KERN_ERR "GMAC RX: length_error error\n");
x->rx_length++;
ret = discard_frame;
}
#ifdef STMMAC_VLAN_TAG_USED
- if (p->des01.erx.vlan_tag) {
- CHIP_DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
+ if (p->des01.erx.vlan_tag)
x->rx_vlan++;
- }
#endif
return ret;
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/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 11775b99afc..35ad4f427ae 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -52,10 +52,8 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
ret = -1;
}
- if (p->des01.etx.vlan_frame) {
- CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
+ if (p->des01.etx.vlan_frame)
x->tx_vlan++;
- }
if (unlikely(p->des01.tx.deferred))
x->tx_deferred++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index c9d942a5c33..650a4be6bce 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -33,10 +33,15 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
struct stmmac_priv *priv = (struct stmmac_priv *)p;
unsigned int txsize = priv->dma_tx_size;
unsigned int entry = priv->cur_tx % txsize;
- struct dma_desc *desc = priv->dma_tx + entry;
+ struct dma_desc *desc;
unsigned int nopaged_len = skb_headlen(skb);
unsigned int bmax, len;
+ if (priv->extend_desc)
+ desc = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ desc = priv->dma_tx + entry;
+
if (priv->plat->enh_desc)
bmax = BUF_SIZE_8KiB;
else
@@ -53,8 +58,13 @@ 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;
- desc = priv->dma_tx + entry;
+
+ if (priv->extend_desc)
+ desc = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ desc = priv->dma_tx + entry;
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
len, DMA_TO_DEVICE);
@@ -64,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);
@@ -91,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 */
@@ -117,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 c922fde929a..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 */
@@ -70,7 +71,6 @@ struct stmmac_priv {
struct net_device *dev;
struct device *device;
struct mac_device_info *hw;
- int no_csum_insertion;
spinlock_t lock;
struct phy_device *phydev ____cacheline_aligned_in_smp;
@@ -92,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;
@@ -106,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);
@@ -131,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_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index def7e75e1d5..76ad214b403 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -45,8 +45,8 @@ static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
data = (1000000000ULL / 50000000);
/* 0.465ns accuracy */
- if (value & PTP_TCR_TSCTRLSSR)
- data = (data * 100) / 465;
+ if (!(value & PTP_TCR_TSCTRLSSR))
+ data = (data * 1000) / 465;
writel(data, ioaddr + PTP_SSIR);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ee919ca8b8a..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,35 +51,9 @@
#include <linux/net_tstamp.h>
#include "stmmac_ptp.h"
#include "stmmac.h"
-
-#undef STMMAC_DEBUG
-/*#define STMMAC_DEBUG*/
-#ifdef STMMAC_DEBUG
-#define DBG(nlevel, klevel, fmt, args...) \
- ((void)(netif_msg_##nlevel(priv) && \
- printk(KERN_##klevel fmt, ## args)))
-#else
-#define DBG(nlevel, klevel, fmt, args...) do { } while (0)
-#endif
-
-#undef STMMAC_RX_DEBUG
-/*#define STMMAC_RX_DEBUG*/
-#ifdef STMMAC_RX_DEBUG
-#define RX_DBG(fmt, args...) printk(fmt, ## args)
-#else
-#define RX_DBG(fmt, args...) do { } while (0)
-#endif
-
-#undef STMMAC_XMIT_DEBUG
-/*#define STMMAC_XMIT_DEBUG*/
-#ifdef STMMAC_XMIT_DEBUG
-#define TX_DBG(fmt, args...) printk(fmt, ## args)
-#else
-#define TX_DBG(fmt, args...) do { } while (0)
-#endif
+#include <linux/reset.h>
#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
-#define JUMBO_LEN 9000
/* Module parameters */
#define TX_TIMEO 5000
@@ -90,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");
@@ -117,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");
@@ -130,7 +105,7 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
module_param(eee_timer, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
-#define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
+#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
/* By default the driver will use the ring mode to manage tx and rx descriptors
* but passing this value so user can force to use the chain instead of the ring
@@ -161,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))
@@ -214,19 +189,17 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
}
}
-#if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
static void print_pkt(unsigned char *buf, int len)
{
int j;
- pr_info("len = %d byte, buf addr: 0x%p", len, buf);
+ pr_debug("len = %d byte, buf addr: 0x%p", len, buf);
for (j = 0; j < len; j++) {
if ((j % 16) == 0)
- pr_info("\n %03x:", j);
- pr_info(" %02x", buf[j]);
+ pr_debug("\n %03x:", j);
+ pr_debug(" %02x", buf[j]);
}
- pr_info("\n");
+ pr_debug("\n");
}
-#endif
/* minimum number of free TX descriptors required to wake up TX process */
#define STMMAC_TX_THRESH(x) (x->dma_tx_size/4)
@@ -288,7 +261,7 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
struct stmmac_priv *priv = (struct stmmac_priv *)arg;
stmmac_enable_eee_mode(priv);
- mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
+ mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
}
/**
@@ -304,24 +277,51 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
{
bool ret = false;
+ /* Using PCS we cannot dial with the phy registers at this stage
+ * so we do not support extra feature like EEE.
+ */
+ if ((priv->pcs == STMMAC_PCS_RGMII) || (priv->pcs == STMMAC_PCS_TBI) ||
+ (priv->pcs == STMMAC_PCS_RTBI))
+ goto out;
+
/* 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);
+ priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
+ priv->eee_ctrl_timer.data = (unsigned long)priv;
+ priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
+ add_timer(&priv->eee_ctrl_timer);
+
+ priv->hw->mac->set_eee_timer(priv->ioaddr,
+ STMMAC_DEFAULT_LIT_LS,
+ tx_lpi_timer);
+ } else
+ /* Set HW EEE according to the speed */
+ priv->hw->mac->set_eee_pls(priv->ioaddr,
+ priv->phydev->link);
- priv->eee_active = 1;
- init_timer(&priv->eee_ctrl_timer);
- priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
- priv->eee_ctrl_timer.data = (unsigned long)priv;
- priv->eee_ctrl_timer.expires = STMMAC_LPI_TIMER(eee_timer);
- add_timer(&priv->eee_ctrl_timer);
-
- priv->hw->mac->set_eee_timer(priv->ioaddr,
- STMMAC_DEFAULT_LIT_LS_TIMER,
- priv->tx_lpi_timer);
-
- pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
+ pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
ret = true;
}
@@ -329,20 +329,6 @@ out:
return ret;
}
-/**
- * stmmac_eee_adjust: adjust HW EEE according to the speed
- * @priv: driver private structure
- * Description:
- * When the EEE has been already initialised we have to
- * modify the PLS bit in the LPI ctrl & status reg according
- * to the PHY link status. For this reason.
- */
-static void stmmac_eee_adjust(struct stmmac_priv *priv)
-{
- if (priv->eee_enabled)
- priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
-}
-
/* stmmac_get_tx_hwtstamp: get HW TX timestamps
* @priv: driver private structure
* @entry : descriptor index to be used.
@@ -362,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)
@@ -465,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) {
@@ -606,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);
@@ -658,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;
@@ -698,9 +676,6 @@ static void stmmac_adjust_link(struct net_device *dev)
if (phydev == NULL)
return;
- DBG(probe, DEBUG, "stmmac_adjust_link: called. address %d link %d\n",
- phydev->addr, phydev->link);
-
spin_lock_irqsave(&priv->lock, flags);
if (phydev->link) {
@@ -769,11 +744,12 @@ static void stmmac_adjust_link(struct net_device *dev)
if (new_state && netif_msg_link(priv))
phy_print_status(phydev);
- stmmac_eee_adjust(priv);
+ /* At this stage, it could be needed to setup the EEE or adjust some
+ * MAC related HW registers.
+ */
+ priv->eee_enabled = stmmac_eee_init(priv);
spin_unlock_irqrestore(&priv->lock, flags);
-
- DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n");
}
/**
@@ -788,13 +764,13 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
int interface = priv->plat->interface;
if (priv->dma_cap.pcs) {
- if ((interface & PHY_INTERFACE_MODE_RGMII) ||
- (interface & PHY_INTERFACE_MODE_RGMII_ID) ||
- (interface & PHY_INTERFACE_MODE_RGMII_RXID) ||
- (interface & PHY_INTERFACE_MODE_RGMII_TXID)) {
+ if ((interface == PHY_INTERFACE_MODE_RGMII) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
pr_debug("STMMAC: PCS RGMII support enable\n");
priv->pcs = STMMAC_PCS_RGMII;
- } else if (interface & PHY_INTERFACE_MODE_SGMII) {
+ } else if (interface == PHY_INTERFACE_MODE_SGMII) {
pr_debug("STMMAC: PCS SGMII support enable\n");
priv->pcs = STMMAC_PCS_SGMII;
}
@@ -816,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;
@@ -840,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);
@@ -923,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;
}
@@ -971,25 +949,40 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
GFP_KERNEL);
- if (unlikely(skb == NULL)) {
+ if (!skb) {
pr_err("%s: Rx init fails; skb is NULL\n", __func__);
- return 1;
+ return -ENOMEM;
}
skb_reserve(skb, NET_IP_ALIGN);
priv->rx_skbuff[i] = skb;
priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
priv->dma_buf_sz,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(priv->device, priv->rx_skbuff_dma[i])) {
+ pr_err("%s: DMA mapping error\n", __func__);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
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;
}
+static void stmmac_free_rx_buffers(struct stmmac_priv *priv, int i)
+{
+ if (priv->rx_skbuff[i]) {
+ dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
+ priv->dma_buf_sz, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx_skbuff[i]);
+ }
+ priv->rx_skbuff[i] = NULL;
+}
+
/**
* init_dma_desc_rings - init the RX/TX descriptor rings
* @dev: net device structure
@@ -997,66 +990,34 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
* and allocates the socket buffers. It suppors the chained and ring
* modes.
*/
-static void init_dma_desc_rings(struct net_device *dev)
+static int init_dma_desc_rings(struct net_device *dev)
{
int i;
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int txsize = priv->dma_tx_size;
unsigned int rxsize = priv->dma_rx_size;
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);
- DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
- txsize, rxsize, bfsize);
+ priv->dma_buf_sz = 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);
- priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
- sizeof(struct
- dma_extended_desc),
- &priv->dma_tx_phy,
- GFP_KERNEL);
- if ((!priv->dma_erx) || (!priv->dma_etx))
- return;
- } else {
- priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
- sizeof(struct dma_desc),
- &priv->dma_rx_phy,
- GFP_KERNEL);
- priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
- sizeof(struct dma_desc),
- &priv->dma_tx_phy,
- GFP_KERNEL);
- if ((!priv->dma_rx) || (!priv->dma_tx))
- return;
- }
+ if (netif_msg_probe(priv))
+ pr_debug("%s: txsize %d, rxsize %d, bfsize %d\n", __func__,
+ txsize, rxsize, bfsize);
- priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
- GFP_KERNEL);
- priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
- GFP_KERNEL);
- priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
- GFP_KERNEL);
- priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
- GFP_KERNEL);
- if (netif_msg_drv(priv))
+ 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);
- /* RX INITIALIZATION */
- DBG(probe, INFO, "stmmac: SKB addresses:\nskb\t\tskb data\tdma data\n");
+ /* RX INITIALIZATION */
+ pr_debug("\tSKB addresses:\nskb\t\tskb data\tdma data\n");
+ }
for (i = 0; i < rxsize; i++) {
struct dma_desc *p;
if (priv->extend_desc)
@@ -1064,29 +1025,31 @@ static void init_dma_desc_rings(struct net_device *dev)
else
p = priv->dma_rx + i;
- if (stmmac_init_rx_buffers(priv, p, i))
- break;
+ ret = stmmac_init_rx_buffers(priv, p, i);
+ if (ret)
+ goto err_init_rx_buffers;
- DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
- priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
+ if (netif_msg_probe(priv))
+ pr_debug("[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
+ priv->rx_skbuff[i]->data,
+ (unsigned int)priv->rx_skbuff_dma[i]);
}
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);
}
}
@@ -1109,20 +1072,20 @@ static void init_dma_desc_rings(struct net_device *dev)
if (netif_msg_hw(priv))
stmmac_display_rings(priv);
+
+ return 0;
+err_init_rx_buffers:
+ while (--i >= 0)
+ stmmac_free_rx_buffers(priv, i);
+ return ret;
}
static void dma_free_rx_skbufs(struct stmmac_priv *priv)
{
int i;
- for (i = 0; i < priv->dma_rx_size; i++) {
- if (priv->rx_skbuff[i]) {
- dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
- priv->dma_buf_sz, DMA_FROM_DEVICE);
- dev_kfree_skb_any(priv->rx_skbuff[i]);
- }
- priv->rx_skbuff[i] = NULL;
- }
+ for (i = 0; i < priv->dma_rx_size; i++)
+ stmmac_free_rx_buffers(priv, i);
}
static void dma_free_tx_skbufs(struct stmmac_priv *priv)
@@ -1130,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 */
@@ -1185,8 +1230,9 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
*/
static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{
- if (likely(priv->plat->force_sf_dma_mode ||
- ((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) {
+ if (priv->plat->force_thresh_dma_mode)
+ priv->hw->dma->dma_mode(priv->ioaddr, tc, tc);
+ else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
/*
* In case of GMAC, SF mode can be enabled
* to perform the TX COE in HW. This depends on:
@@ -1243,8 +1289,9 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
stmmac_get_tx_hwtstamp(priv, entry, skb);
}
- TX_DBG("%s: curr %d, dirty %d\n", __func__,
- priv->cur_tx, priv->dirty_tx);
+ if (netif_msg_tx_done(priv))
+ pr_debug("%s: curr %d, dirty %d\n", __func__,
+ priv->cur_tx, priv->dirty_tx);
if (likely(priv->tx_skbuff_dma[entry])) {
dma_unmap_single(priv->device,
@@ -1253,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;
}
@@ -1269,7 +1316,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
netif_tx_lock(priv->dev);
if (netif_queue_stopped(priv->dev) &&
stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {
- TX_DBG("%s: restart transmit\n", __func__);
+ if (netif_msg_tx_done(priv))
+ pr_debug("%s: restart transmit\n", __func__);
netif_wake_queue(priv->dev);
}
netif_tx_unlock(priv->dev);
@@ -1277,7 +1325,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
stmmac_enable_eee_mode(priv);
- mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
+ mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
}
spin_unlock(&priv->tx_lock);
}
@@ -1488,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);
}
/**
@@ -1555,44 +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 open_error;
- }
+ ret = init_dma_desc_rings(dev);
+ if (ret < 0) {
+ pr_err("%s: DMA descriptors initialization failed\n", __func__);
+ return ret;
}
-
- /* 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);
- init_dma_desc_rings(dev);
-
/* DMA initialization and SW reset */
ret = stmmac_init_dma_engine(priv);
if (ret < 0) {
- pr_err("%s: DMA initialization failed\n", __func__);
- goto open_error;
+ pr_err("%s: DMA engine initialization failed\n", __func__);
+ return ret;
}
/* Copy the MAC addr into the HW */
@@ -1603,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 open_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 open_error_wolirq;
- }
- }
-
- /* 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 open_error_lpiirq;
- }
- }
+ priv->hw->mac->core_init(priv->ioaddr, dev->mtu);
/* Enable the MAC Rx/Tx */
stmmac_set_mac(priv->ioaddr, true);
@@ -1642,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
@@ -1658,7 +1656,7 @@ static int stmmac_open(struct net_device *dev)
pr_warn("%s: failed debugFS registration\n", __func__);
#endif
/* Start the ball rolling... */
- DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
+ pr_debug("%s: DMA RX/TX processes started...\n", dev->name);
priv->hw->dma->start_tx(priv->ioaddr);
priv->hw->dma->start_rx(priv->ioaddr);
@@ -1667,18 +1665,9 @@ static int stmmac_open(struct net_device *dev)
priv->hw->mac->dump_regs(priv->ioaddr);
priv->hw->dma->dump_regs(priv->ioaddr);
}
+ priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
- if (priv->phydev)
- phy_start(priv->phydev);
-
- priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
-
- /* Using PCS we cannot dial with the phy registers at this stage
- * so we do not support extra feature like EEE.
- */
- if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
- priv->pcs != STMMAC_PCS_RTBI)
- priv->eee_enabled = stmmac_eee_init(priv);
+ priv->eee_enabled = stmmac_eee_init(priv);
stmmac_init_tx_coalesce(priv);
@@ -1690,24 +1679,107 @@ 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);
return 0;
-open_error_lpiirq:
+lpiirq_error:
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
-
-open_error_wolirq:
+wolirq_error:
free_irq(dev->irq, dev);
-open_error:
+init_error:
+ free_dma_desc_resources(priv);
+dma_desc_error:
if (priv->phydev)
phy_disconnect(priv->phydev);
- clk_disable_unprepare(priv->stmmac_clk);
-
return ret;
}
@@ -1741,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 */
@@ -1759,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);
@@ -1783,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)) {
@@ -1800,16 +1872,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
entry = priv->cur_tx % txsize;
-#ifdef STMMAC_XMIT_DEBUG
- if ((skb->len > ETH_FRAME_LEN) || nfrags)
- pr_debug("%s: [entry %d]: skb addr %p len: %d nopagedlen: %d\n"
- "\tn_frags: %d - ip_summed: %d - %s gso\n"
- "\ttx_count_frames %d\n", __func__, entry,
- skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
- !skb_is_gso(skb) ? "isn't" : "is",
- priv->tx_count_frames);
-#endif
-
csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
if (priv->extend_desc)
@@ -1819,52 +1881,35 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
first = desc;
-#ifdef STMMAC_XMIT_DEBUG
- if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
- pr_debug("\tskb len: %d, nopaged_len: %d,\n"
- "\t\tn_frags: %d, ip_summed: %d\n",
- skb->len, nopaged_len, nfrags, skb->ip_summed);
-#endif
- 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);
else
desc = priv->dma_tx + entry;
- TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
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();
@@ -1872,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);
@@ -1884,8 +1931,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
if (priv->tx_coal_frames > priv->tx_count_frames) {
priv->hw->desc->clear_tx_ic(desc);
priv->xstats.tx_reset_ic_bit++;
- TX_DBG("\t[entry %d]: tx_count_frames %d\n", entry,
- priv->tx_count_frames);
mod_timer(&priv->txtimer,
STMMAC_COAL_TIMER(priv->tx_coal_timer));
} else
@@ -1897,22 +1942,22 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
priv->cur_tx++;
-#ifdef STMMAC_XMIT_DEBUG
if (netif_msg_pktdata(priv)) {
- pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d",
+ pr_debug("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d",
__func__, (priv->cur_tx % txsize),
(priv->dirty_tx % txsize), entry, first, nfrags);
+
if (priv->extend_desc)
stmmac_display_ring((void *)priv->dma_etx, txsize, 1);
else
stmmac_display_ring((void *)priv->dma_tx, txsize, 0);
- pr_info(">>> frame to be transmitted: ");
+ pr_debug(">>> frame to be transmitted: ");
print_pkt(skb->data, skb->len);
}
-#endif
if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
- TX_DBG("%s: stop transmitted packets\n", __func__);
+ if (netif_msg_hw(priv))
+ pr_debug("%s: stop transmitted packets\n", __func__);
netif_stop_queue(dev);
}
@@ -1935,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
@@ -1970,9 +2032,10 @@ 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);
- RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
+ if (netif_msg_rx_status(priv))
+ pr_debug("\trefill entry #%d\n", entry);
}
wmb();
priv->hw->desc->set_rx_owner(p);
@@ -1995,15 +2058,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
unsigned int count = 0;
int coe = priv->plat->rx_coe;
-#ifdef STMMAC_RX_DEBUG
- if (netif_msg_hw(priv)) {
- pr_debug(">>> stmmac_rx: descriptor ring:\n");
+ if (netif_msg_rx_status(priv)) {
+ pr_debug("%s: descriptor ring:\n", __func__);
if (priv->extend_desc)
stmmac_display_ring((void *)priv->dma_erx, rxsize, 1);
else
stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);
}
-#endif
while (count < limit) {
int status;
struct dma_desc *p;
@@ -2057,15 +2118,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
*/
if (unlikely(status != llc_snap))
frame_len -= ETH_FCS_LEN;
-#ifdef STMMAC_RX_DEBUG
- if (frame_len > ETH_FRAME_LEN)
- pr_debug("\tRX frame size %d, COE status: %d\n",
- frame_len, status);
- if (netif_msg_hw(priv))
+ if (netif_msg_rx_status(priv)) {
pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
p, entry, p->des2);
-#endif
+ if (frame_len > ETH_FRAME_LEN)
+ pr_debug("\tframe size %d, COE: %d\n",
+ frame_len, status);
+ }
skb = priv->rx_skbuff[entry];
if (unlikely(!skb)) {
pr_err("%s: Inconsistent Rx descriptor chain\n",
@@ -2082,12 +2142,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
priv->dma_buf_sz, DMA_FROM_DEVICE);
-#ifdef STMMAC_RX_DEBUG
+
if (netif_msg_pktdata(priv)) {
- pr_info(" frame received (%dbytes)", frame_len);
+ pr_debug("frame received (%dbytes)", frame_len);
print_pkt(skb->data, frame_len);
}
-#endif
+
+ stmmac_rx_vlan(priv->dev, skb);
+
skb->protocol = eth_type_trans(skb, priv->dev);
if (unlikely(!coe))
@@ -2150,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
@@ -2215,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;
@@ -2262,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;
@@ -2530,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
@@ -2566,16 +2612,13 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
/* Get and dump the chip ID */
priv->synopsys_id = stmmac_get_synopsys_id(priv);
- /* To use alternate (extended) or normal descriptor structures */
- stmmac_selec_desc_mode(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;
}
@@ -2603,6 +2646,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
} else
pr_info(" No HW DMA feature register supported");
+ /* To use alternate (extended) or normal descriptor structures */
+ stmmac_selec_desc_mode(priv);
+
ret = priv->hw->mac->rx_ipc(priv->ioaddr);
if (!ret) {
pr_warn(" RX IPC Checksum Offload not configured.\n");
@@ -2666,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;
@@ -2707,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
@@ -2740,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);
}
/**
@@ -2772,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;
@@ -2803,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);
}
@@ -2830,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);
@@ -2854,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 cc15039eaa4..a5b1e1b776f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -27,6 +27,9 @@
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
#include <asm/io.h>
#include "stmmac.h"
@@ -125,16 +128,51 @@ 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;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
+ struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data;
+
+#ifdef CONFIG_OF
+ if (priv->device->of_node) {
+ int reset_gpio, active_low;
+
+ if (data->reset_gpio < 0) {
+ struct device_node *np = priv->device->of_node;
+ if (!np)
+ return 0;
+
+ data->reset_gpio = of_get_named_gpio(np,
+ "snps,reset-gpio", 0);
+ if (data->reset_gpio < 0)
+ return 0;
+
+ data->active_low = of_property_read_bool(np,
+ "snps,reset-active-low");
+ of_property_read_u32_array(np,
+ "snps,reset-delays-us", data->delays, 3);
+ }
+
+ reset_gpio = data->reset_gpio;
+ active_low = data->active_low;
+
+ if (!gpio_request(reset_gpio, "mdio-reset")) {
+ gpio_direction_output(reset_gpio, active_low ? 1 : 0);
+ udelay(data->delays[0]);
+ gpio_set_value(reset_gpio, active_low ? 0 : 1);
+ udelay(data->delays[1]);
+ gpio_set_value(reset_gpio, active_low ? 1 : 0);
+ udelay(data->delays[2]);
+ }
+ }
+#endif
- if (priv->plat->mdio_bus_data->phy_reset) {
+ if (data->phy_reset) {
pr_debug("stmmac_mdio_reset: calling phy_reset\n");
- priv->plat->mdio_bus_data->phy_reset(priv->plat->bsp_priv);
+ data->phy_reset(priv->plat->bsp_priv);
}
/* This is a workaround for problems with the STE101P PHY.
@@ -167,10 +205,18 @@ 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)
+ mdio_bus_data->reset_gpio = -1;
+#endif
new_bus->name = "stmmac";
new_bus->read = &stmmac_mdio_read;
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 1d3780f55ba..ea7a65be1f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -26,24 +26,95 @@
#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,
const char **mac)
{
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;
+
+ /* 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
@@ -52,10 +123,43 @@ 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;
}
+ if (of_device_is_compatible(np, "snps,dwmac-3.610") ||
+ of_device_is_compatible(np, "snps,dwmac-3.710")) {
+ plat->enh_desc = 1;
+ plat->bugged_jumbo = 1;
+ plat->force_sf_dma_mode = 1;
+ }
+
+ if (of_find_property(np, "snps,pbl", NULL)) {
+ dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+ GFP_KERNEL);
+ if (!dma_cfg)
+ return -ENOMEM;
+ plat->dma_cfg = dma_cfg;
+ of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+ dma_cfg->fixed_burst =
+ of_property_read_bool(np, "snps,fixed-burst");
+ dma_cfg->mixed_burst =
+ of_property_read_bool(np, "snps,mixed-burst");
+ }
+ plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
+ if (plat->force_thresh_dma_mode) {
+ plat->force_sf_dma_mode = 0;
+ pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
+ }
+
return 0;
}
#else
@@ -85,15 +189,14 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
const char *mac = NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr))
return PTR_ERR(addr);
+ plat_dat = dev_get_platdata(&pdev->dev);
if (pdev->dev.of_node) {
- plat_dat = devm_kzalloc(&pdev->dev,
+ if (!plat_dat)
+ plat_dat = devm_kzalloc(&pdev->dev,
sizeof(struct plat_stmmacenet_data),
GFP_KERNEL);
if (!plat_dat) {
@@ -106,21 +209,26 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
pr_err("%s: main dt probe failed", __func__);
return ret;
}
- } else {
- plat_dat = pdev->dev.platform_data;
+ }
+
+ /* 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) */
@@ -129,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;
}
/*
@@ -144,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);
@@ -169,9 +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);
- platform_set_drvdata(pdev, NULL);
+ if (priv->plat->free)
+ priv->plat->free(pdev, priv->plat->bsp_priv);
return ret;
}
@@ -179,62 +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.70a"},
- { .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,