diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/Kconfig | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 140 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 495 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 135 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 4 |
15 files changed, 547 insertions, 290 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 6e52c0f74cd9..e2f202e3932f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -5,6 +5,7 @@ config STMMAC_ETH select PHYLIB select CRC32 select PTP_1588_CLOCK + select RESET_CONTROLLER ---help--- This is the driver for the Ethernet IPs are built around a Synopsys IP Core and only tested on the STMicroelectronics @@ -25,6 +26,17 @@ config STMMAC_PLATFORM If unsure, say N. +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 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 356a9dd32be7..ecadecea79b2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -1,6 +1,7 @@ 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-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 d234ab540b29..72d282bf33a5 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; } } diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index fc94f202a43e..7834a3993946 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -29,7 +29,6 @@ #include <linux/netdevice.h> #include <linux/phy.h> #include <linux/module.h> -#include <linux/init.h> #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define STMMAC_VLAN_TAG_USED #include <linux/if_vlan.h> @@ -293,6 +292,8 @@ struct dma_features { #define STMMAC_CHAIN_MODE 0x1 #define STMMAC_RING_MODE 0x2 +#define JUMBO_LEN 9000 + struct stmmac_desc_ops { /* DMA RX descriptor ring initialization */ void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode, @@ -369,7 +370,7 @@ struct stmmac_dma_ops { struct stmmac_ops { /* MAC core initialization */ - void (*core_init) (void __iomem *ioaddr); + void (*core_init) (void __iomem *ioaddr, int mtu); /* Enable and verify that the IPC module is supported */ int (*rx_ipc) (void __iomem *ioaddr); /* Dump MAC registers */ 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 000000000000..771cd15fca18 --- /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 c12aabb8cf93..f37d90f114f5 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 cdd926832e27..b3e148ef5683 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 */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 5857d677dac1..2ff767bcfdd0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -32,7 +32,7 @@ #include <asm/io.h> #include "dwmac100.h" -static void dwmac100_core_init(void __iomem *ioaddr) +static void dwmac100_core_init(void __iomem *ioaddr, int mtu) { u32 value = readl(ioaddr + MAC_CONTROL); diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c index 1ef9d8a555aa..a96c7c2f5f3f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c @@ -58,6 +58,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_RING_MODE); wmb(); + priv->tx_skbuff[entry] = NULL; entry = (++priv->cur_tx) % txsize; if (priv->extend_desc) @@ -73,7 +74,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) STMMAC_RING_MODE); wmb(); priv->hw->desc->set_tx_owner(desc); - priv->tx_skbuff[entry] = NULL; } else { desc->des2 = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 22f89ffdfd95..d9af26ed58ee 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -32,6 +32,7 @@ #include <linux/pci.h> #include "common.h" #include <linux/ptp_clock_kernel.h> +#include <linux/reset.h> struct stmmac_priv { /* Frequently used values are kept adjacent for cache effect */ @@ -91,6 +92,7 @@ struct stmmac_priv { int wolopts; int wol_irq; struct clk *stmmac_clk; + struct reset_control *stmmac_rst; int clk_csr; struct timer_list eee_ctrl_timer; int lpi_irq; @@ -105,21 +107,19 @@ struct stmmac_priv { unsigned int default_addend; u32 adv_ts; int use_riwt; + int irq_wake; spinlock_t ptp_lock; }; -extern int phyaddr; - 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; int stmmac_ptp_register(struct stmmac_priv *priv); void stmmac_ptp_unregister(struct stmmac_priv *priv); -int stmmac_freeze(struct net_device *ndev); -int stmmac_restore(struct net_device *ndev); int stmmac_resume(struct net_device *ndev); int stmmac_suspend(struct net_device *ndev); int stmmac_dvr_remove(struct net_device *ndev); @@ -130,6 +130,9 @@ 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 extern struct platform_driver stmmac_pltfr_driver; static inline int stmmac_register_platform(void) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8a7a23a84ac5..a2e7d2c96e36 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -43,6 +43,7 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/prefetch.h> +#include <linux/pinctrl/consumer.h> #ifdef CONFIG_STMMAC_DEBUG_FS #include <linux/debugfs.h> #include <linux/seq_file.h> @@ -50,9 +51,9 @@ #include <linux/net_tstamp.h> #include "stmmac_ptp.h" #include "stmmac.h" +#include <linux/reset.h> #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) -#define JUMBO_LEN 9000 /* Module parameters */ #define TX_TIMEO 5000 @@ -64,7 +65,7 @@ static int debug = -1; module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); -int phyaddr = -1; +static int phyaddr = -1; module_param(phyaddr, int, S_IRUGO); MODULE_PARM_DESC(phyaddr, "Physical device address"); @@ -91,7 +92,7 @@ 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 +#define DMA_BUFFER_SIZE BUF_SIZE_4KiB static int buf_sz = DMA_BUFFER_SIZE; module_param(buf_sz, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(buf_sz, "DMA buffer size"); @@ -332,7 +333,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) @@ -622,17 +623,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; @@ -778,6 +777,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; @@ -802,7 +802,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); @@ -992,70 +993,12 @@ static int init_dma_desc_rings(struct net_device *dev) if (bfsize < BUF_SIZE_16KiB) bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz); + priv->dma_buf_sz = bfsize; + if (netif_msg_probe(priv)) pr_debug("%s: txsize %d, rxsize %d, bfsize %d\n", __func__, txsize, rxsize, bfsize); - if (priv->extend_desc) { - priv->dma_erx = dma_alloc_coherent(priv->device, rxsize * - sizeof(struct - dma_extended_desc), - &priv->dma_rx_phy, - GFP_KERNEL); - if (!priv->dma_erx) - goto err_dma; - - priv->dma_etx = dma_alloc_coherent(priv->device, txsize * - sizeof(struct - dma_extended_desc), - &priv->dma_tx_phy, - GFP_KERNEL); - if (!priv->dma_etx) { - dma_free_coherent(priv->device, priv->dma_rx_size * - sizeof(struct dma_extended_desc), - priv->dma_erx, priv->dma_rx_phy); - goto err_dma; - } - } else { - priv->dma_rx = dma_alloc_coherent(priv->device, rxsize * - sizeof(struct dma_desc), - &priv->dma_rx_phy, - GFP_KERNEL); - if (!priv->dma_rx) - goto err_dma; - - priv->dma_tx = dma_alloc_coherent(priv->device, txsize * - sizeof(struct dma_desc), - &priv->dma_tx_phy, - GFP_KERNEL); - if (!priv->dma_tx) { - dma_free_coherent(priv->device, priv->dma_rx_size * - sizeof(struct dma_desc), - priv->dma_rx, priv->dma_rx_phy); - goto err_dma; - } - } - - priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), - GFP_KERNEL); - if (!priv->rx_skbuff_dma) - goto err_rx_skbuff_dma; - - priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), - GFP_KERNEL); - if (!priv->rx_skbuff) - goto err_rx_skbuff; - - priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t), - GFP_KERNEL); - if (!priv->tx_skbuff_dma) - goto err_tx_skbuff_dma; - - priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), - GFP_KERNEL); - if (!priv->tx_skbuff) - goto err_tx_skbuff; - if (netif_msg_probe(priv)) { pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__, (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy); @@ -1081,7 +1024,6 @@ static int init_dma_desc_rings(struct net_device *dev) } priv->cur_rx = 0; priv->dirty_rx = (unsigned int)(i - rxsize); - priv->dma_buf_sz = bfsize; buf_sz = bfsize; /* Setup the chained descriptor addresses */ @@ -1123,30 +1065,6 @@ static int init_dma_desc_rings(struct net_device *dev) err_init_rx_buffers: while (--i >= 0) stmmac_free_rx_buffers(priv, i); - kfree(priv->tx_skbuff); -err_tx_skbuff: - kfree(priv->tx_skbuff_dma); -err_tx_skbuff_dma: - kfree(priv->rx_skbuff); -err_rx_skbuff: - kfree(priv->rx_skbuff_dma); -err_rx_skbuff_dma: - if (priv->extend_desc) { - dma_free_coherent(priv->device, priv->dma_tx_size * - sizeof(struct dma_extended_desc), - priv->dma_etx, priv->dma_tx_phy); - dma_free_coherent(priv->device, priv->dma_rx_size * - sizeof(struct dma_extended_desc), - priv->dma_erx, priv->dma_rx_phy); - } else { - dma_free_coherent(priv->device, - priv->dma_tx_size * sizeof(struct dma_desc), - priv->dma_tx, priv->dma_tx_phy); - dma_free_coherent(priv->device, - priv->dma_rx_size * sizeof(struct dma_desc), - priv->dma_rx, priv->dma_rx_phy); - } -err_dma: return ret; } @@ -1163,25 +1081,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 */ @@ -1524,9 +1524,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); } /** @@ -1591,6 +1591,86 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv) } /** + * stmmac_hw_setup: setup mac in a usable state. + * @dev : pointer to the device structure. + * Description: + * 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_hw_setup(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int ret; + + ret = init_dma_desc_rings(dev); + if (ret < 0) { + pr_err("%s: DMA descriptors initialization failed\n", __func__); + return ret; + } + /* DMA initialization and SW reset */ + ret = stmmac_init_dma_engine(priv); + if (ret < 0) { + pr_err("%s: DMA engine initialization failed\n", __func__); + return ret; + } + + /* Copy the MAC addr into the HW */ + priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); + + /* If required, perform hw setup of the bus. */ + if (priv->plat->bus_setup) + priv->plat->bus_setup(priv->ioaddr); + + /* Initialize the MAC Core */ + priv->hw->mac->core_init(priv->ioaddr, dev->mtu); + + /* Enable the MAC Rx/Tx */ + stmmac_set_mac(priv->ioaddr, true); + + /* Set the HW DMA mode and the COE */ + stmmac_dma_operation_mode(priv); + + stmmac_mmc_setup(priv); + + ret = stmmac_init_ptp(priv); + if (ret && ret != -EOPNOTSUPP) + pr_warn("%s: failed PTP initialisation\n", __func__); + +#ifdef CONFIG_STMMAC_DEBUG_FS + ret = stmmac_init_fs(dev); + if (ret < 0) + pr_warn("%s: failed debugFS registration\n", __func__); +#endif + /* Start the ball rolling... */ + 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); + + /* Dump DMA/MAC registers */ + if (netif_msg_hw(priv)) { + priv->hw->mac->dump_regs(priv->ioaddr); + priv->hw->dma->dump_regs(priv->ioaddr); + } + priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; + + priv->eee_enabled = stmmac_eee_init(priv); + + stmmac_init_tx_coalesce(priv); + + if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) { + priv->rx_riwt = MAX_DMA_RIWT; + priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT); + } + + 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: @@ -1604,8 +1684,6 @@ static int stmmac_open(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 && @@ -1618,33 +1696,29 @@ static int stmmac_open(struct net_device *dev) } } + /* 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 = init_dma_desc_rings(dev); + alloc_dma_desc_resources(priv); if (ret < 0) { - pr_err("%s: DMA descriptors initialization failed\n", __func__); + pr_err("%s: DMA descriptors allocation failed\n", __func__); goto dma_desc_error; } - /* DMA initialization and SW reset */ - ret = stmmac_init_dma_engine(priv); + ret = stmmac_hw_setup(dev); if (ret < 0) { - pr_err("%s: DMA engine initialization failed\n", __func__); + pr_err("%s: Hw setup failed\n", __func__); goto init_error; } - /* Copy the MAC addr into the HW */ - priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); - - /* If required, perform hw setup of the bus. */ - if (priv->plat->bus_setup) - priv->plat->bus_setup(priv->ioaddr); - - /* Initialize the MAC Core */ - priv->hw->mac->core_init(priv->ioaddr); + if (priv->phydev) + phy_start(priv->phydev); /* Request the IRQ lines */ ret = request_irq(dev->irq, stmmac_interrupt, @@ -1677,55 +1751,6 @@ static int stmmac_open(struct net_device *dev) } } - /* Enable the MAC Rx/Tx */ - stmmac_set_mac(priv->ioaddr, true); - - /* 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) - pr_warn("%s: failed PTP initialisation\n", __func__); - -#ifdef CONFIG_STMMAC_DEBUG_FS - ret = stmmac_init_fs(dev); - if (ret < 0) - pr_warn("%s: failed debugFS registration\n", __func__); -#endif - /* Start the ball rolling... */ - 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); - - /* Dump DMA/MAC registers */ - if (netif_msg_hw(priv)) { - priv->hw->mac->dump_regs(priv->ioaddr); - priv->hw->dma->dump_regs(priv->ioaddr); - } - - if (priv->phydev) - phy_start(priv->phydev); - - priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; - - priv->eee_enabled = stmmac_eee_init(priv); - - stmmac_init_tx_coalesce(priv); - - if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) { - priv->rx_riwt = MAX_DMA_RIWT; - priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT); - } - - if (priv->pcs && priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->ioaddr, 0); - napi_enable(&priv->napi); netif_start_queue(dev); @@ -1796,7 +1821,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); @@ -1846,8 +1870,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) first = desc; - priv->tx_skbuff[entry] = skb; - /* To program the descriptors according to the size of the frame */ if (priv->mode == STMMAC_RING_MODE) { is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len, @@ -1875,6 +1897,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) 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); @@ -1884,7 +1907,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len, DMA_TO_DEVICE); priv->tx_skbuff_dma[entry] = desc->des2; - priv->tx_skbuff[entry] = NULL; priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion, priv->mode); wmb(); @@ -1892,6 +1914,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); @@ -1953,6 +1977,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 @@ -2104,6 +2145,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) print_pkt(skb->data, frame_len); } + stmmac_rx_vlan(priv->dev, skb); + skb->protocol = eth_type_trans(skb, priv->dev); if (unlikely(!coe)) @@ -2231,6 +2274,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; @@ -2278,6 +2324,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; @@ -2682,10 +2731,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; @@ -2723,12 +2794,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 @@ -2756,15 +2821,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); } /** @@ -2788,6 +2853,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; @@ -2819,10 +2887,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); } @@ -2846,18 +2916,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); @@ -2870,22 +2943,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 fe7bc9903867..a468eb107823 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -128,7 +128,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, * @bus: points to the mii_bus structure * Description: reset the MII bus */ -static int stmmac_mdio_reset(struct mii_bus *bus) +int stmmac_mdio_reset(struct mii_bus *bus) { #if defined(CONFIG_STMMAC_PLATFORM) struct net_device *ndev = bus->priv; @@ -166,7 +166,6 @@ static int stmmac_mdio_reset(struct mii_bus *bus) udelay(data->delays[1]); gpio_set_value(reset_gpio, active_low ? 1 : 0); udelay(data->delays[2]); - gpio_free(reset_gpio); } } #endif diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 644d80ece067..291608924849 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; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 51c9069ef405..5884a7d2063b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -26,8 +26,23 @@ #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 + /* SoC specific glue layers should come before generic bindings */ + { .compatible = "st,spear600-gmac"}, + { .compatible = "snps,dwmac-3.610"}, + { .compatible = "snps,dwmac-3.70a"}, + { .compatible = "snps,dwmac-3.710"}, + { .compatible = "snps,dwmac"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, stmmac_dt_ids); + #ifdef CONFIG_OF static int stmmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat, @@ -35,23 +50,63 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct stmmac_dma_cfg *dma_cfg; + const struct of_device_id *device; if (!np) return -ENODEV; + device = of_match_device(stmmac_dt_ids, &pdev->dev); + if (!device) + return -ENODEV; + + if (device->data) { + const struct stmmac_of_data *data = device->data; + plat->has_gmac = data->has_gmac; + plat->enh_desc = data->enh_desc; + plat->tx_coe = data->tx_coe; + plat->rx_coe = data->rx_coe; + plat->bugged_jumbo = data->bugged_jumbo; + plat->pmt = data->pmt; + plat->riwt_off = data->riwt_off; + plat->fix_mac_speed = data->fix_mac_speed; + plat->bus_setup = data->bus_setup; + plat->setup = data->setup; + plat->free = data->free; + plat->init = data->init; + plat->exit = data->exit; + } + *mac = of_get_mac_address(np); plat->interface = of_get_phy_mode(np); + /* Get max speed of operation from device tree */ + if (of_property_read_u32(np, "max-speed", &plat->max_speed)) + plat->max_speed = -1; + plat->bus_id = of_alias_get_id(np, "ethernet"); if (plat->bus_id < 0) plat->bus_id = 0; - of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr); + /* Default to phy auto-detection */ + plat->phy_addr = -1; + + /* "snps,phy-addr" is not a standard property. Mark it as deprecated + * and warn of its use. Remove this when phy node support is added. + */ + if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0) + dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); plat->mdio_bus_data = devm_kzalloc(&pdev->dev, sizeof(struct stmmac_mdio_bus_data), GFP_KERNEL); + plat->force_sf_dma_mode = of_property_read_bool(np, "snps,force_sf_dma_mode"); + + /* Set the maxmtu to a default of JUMBO_LEN in case the + * parameter is not present in the device tree. + */ + plat->maxmtu = JUMBO_LEN; + /* * Currently only the properties needed on SPEAr600 * are provided. All other properties should be added @@ -60,6 +115,14 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, if (of_device_is_compatible(np, "st,spear600-gmac") || of_device_is_compatible(np, "snps,dwmac-3.70a") || of_device_is_compatible(np, "snps,dwmac")) { + /* Note that the max-frame-size parameter as defined in the + * ePAPR v1.1 spec is defined as max-frame-size, it's + * actually used as the IEEE definition of MAC Client + * data, or MTU. The ePAPR specification is confusing as + * the definition is max-frame-size, but usage examples + * are clearly MTUs + */ + of_property_read_u32(np, "max-frame-size", &plat->maxmtu); plat->has_gmac = 1; plat->pmt = 1; } @@ -140,17 +203,24 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) } } + /* Custom setup (if needed) */ + if (plat_dat->setup) { + plat_dat->bsp_priv = plat_dat->setup(pdev); + if (IS_ERR(plat_dat->bsp_priv)) + return PTR_ERR(plat_dat->bsp_priv); + } + /* Custom initialisation (if needed)*/ if (plat_dat->init) { - ret = plat_dat->init(pdev); + ret = plat_dat->init(pdev, plat_dat->bsp_priv); if (unlikely(ret)) return ret; } priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr); - if (!priv) { + if (IS_ERR(priv)) { pr_err("%s: main driver probe failed", __func__); - return -ENODEV; + return PTR_ERR(priv); } /* Get MAC address if available (DT) */ @@ -199,7 +269,10 @@ static int stmmac_pltfr_remove(struct platform_device *pdev) int ret = stmmac_dvr_remove(ndev); if (priv->plat->exit) - priv->plat->exit(pdev); + priv->plat->exit(pdev, priv->plat->bsp_priv); + + if (priv->plat->free) + priv->plat->free(pdev, priv->plat->bsp_priv); return ret; } @@ -207,64 +280,34 @@ static int stmmac_pltfr_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int stmmac_pltfr_suspend(struct device *dev) { - struct net_device *ndev = dev_get_drvdata(dev); - - return stmmac_suspend(ndev); -} - -static int stmmac_pltfr_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - - return stmmac_resume(ndev); -} - -int stmmac_pltfr_freeze(struct device *dev) -{ int ret; - struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev); struct net_device *ndev = dev_get_drvdata(dev); + struct stmmac_priv *priv = netdev_priv(ndev); struct platform_device *pdev = to_platform_device(dev); - ret = stmmac_freeze(ndev); - if (plat_dat->exit) - plat_dat->exit(pdev); + ret = stmmac_suspend(ndev); + if (priv->plat->exit) + priv->plat->exit(pdev, priv->plat->bsp_priv); return ret; } -int stmmac_pltfr_restore(struct device *dev) +static int stmmac_pltfr_resume(struct device *dev) { - struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev); struct net_device *ndev = dev_get_drvdata(dev); + struct stmmac_priv *priv = netdev_priv(ndev); struct platform_device *pdev = to_platform_device(dev); - if (plat_dat->init) - plat_dat->init(pdev); + if (priv->plat->init) + priv->plat->init(pdev, priv->plat->bsp_priv); - return stmmac_restore(ndev); + return stmmac_resume(ndev); } -static const struct dev_pm_ops stmmac_pltfr_pm_ops = { - .suspend = stmmac_pltfr_suspend, - .resume = stmmac_pltfr_resume, - .freeze = stmmac_pltfr_freeze, - .thaw = stmmac_pltfr_restore, - .restore = stmmac_pltfr_restore, -}; -#else -static const struct dev_pm_ops stmmac_pltfr_pm_ops; #endif /* CONFIG_PM */ -static const struct of_device_id stmmac_dt_ids[] = { - { .compatible = "st,spear600-gmac"}, - { .compatible = "snps,dwmac-3.610"}, - { .compatible = "snps,dwmac-3.70a"}, - { .compatible = "snps,dwmac-3.710"}, - { .compatible = "snps,dwmac"}, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, stmmac_dt_ids); +static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, + stmmac_pltfr_suspend, stmmac_pltfr_resume); struct platform_driver stmmac_pltfr_driver = { .probe = stmmac_pltfr_probe, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index b8b0eeed0f92..7680581ebe12 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; } |