From 7ac6653a085b41405758bc16b2525db56ee0a23f Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Mon, 16 May 2011 00:05:19 -0700 Subject: stmmac: Move the STMicroelectronics driver Move the STMicroelectronics driver into driver/net/ethernet/stmicro/ and make the necessary Kconfig and Makefile changes. CC: Giuseppe Cavallaro Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 85 ++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac.h (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h new file mode 100644 index 000000000000..de1929b2641b --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -0,0 +1,85 @@ +/******************************************************************************* + Copyright (C) 2007-2009 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#define DRV_MODULE_VERSION "July_2011" +#include + +#include "common.h" +#ifdef CONFIG_STMMAC_TIMER +#include "stmmac_timer.h" +#endif + +struct stmmac_priv { + /* Frequently used values are kept adjacent for cache effect */ + struct dma_desc *dma_tx ____cacheline_aligned; + dma_addr_t dma_tx_phy; + struct sk_buff **tx_skbuff; + unsigned int cur_tx; + unsigned int dirty_tx; + unsigned int dma_tx_size; + int tx_coalesce; + + struct dma_desc *dma_rx ; + unsigned int cur_rx; + unsigned int dirty_rx; + struct sk_buff **rx_skbuff; + dma_addr_t *rx_skbuff_dma; + struct sk_buff_head rx_recycle; + + struct net_device *dev; + dma_addr_t dma_rx_phy; + unsigned int dma_rx_size; + unsigned int dma_buf_sz; + struct device *device; + struct mac_device_info *hw; + void __iomem *ioaddr; + + struct stmmac_extra_stats xstats; + struct napi_struct napi; + + int rx_coe; + int no_csum_insertion; + + struct phy_device *phydev; + int oldlink; + int speed; + int oldduplex; + unsigned int flow_ctrl; + unsigned int pause; + struct mii_bus *mii; + int mii_irq[PHY_MAX_ADDR]; + + u32 msg_enable; + spinlock_t lock; + int wolopts; + int wolenabled; +#ifdef CONFIG_STMMAC_TIMER + struct stmmac_timer *tm; +#endif + struct plat_stmmacenet_data *plat; +}; + +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); +extern const struct stmmac_desc_ops enh_desc_ops; +extern const struct stmmac_desc_ops ndesc_ops; -- cgit v1.2.3 From 3172d3afa998ffb8f1971746ca960cbe98d62444 Mon Sep 17 00:00:00 2001 From: Deepak Sikri Date: Thu, 1 Sep 2011 21:51:37 +0000 Subject: stmmac: support wake up irq from external sources (v3) On some platforms e.g. SPEAr the wake up irq differs from the GMAC interrupt source. With this patch an external wake up irq can be passed through the platform code and named as "eth_wake_irq". In case the wake up interrupt is not passed from the platform so the driver will continue to use the mac irq (ndev->irq) Signed-off-by: Deepak Sikri Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 4 ++-- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 +++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index de1929b2641b..619e3af97404 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -72,6 +72,7 @@ struct stmmac_priv { spinlock_t lock; int wolopts; int wolenabled; + int wol_irq; #ifdef CONFIG_STMMAC_TIMER struct stmmac_timer *tm; #endif diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 7ed8fb6c2117..79df79dc6a69 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -321,10 +321,10 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts) { pr_info("stmmac: wakeup enable\n"); device_set_wakeup_enable(priv->device, 1); - enable_irq_wake(dev->irq); + enable_irq_wake(priv->wol_irq); } else { device_set_wakeup_enable(priv->device, 0); - disable_irq_wake(dev->irq); + disable_irq_wake(priv->wol_irq); } spin_lock_irq(&priv->lock); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 579f2673fd2e..5aea21e587dd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1515,7 +1515,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) if (device_can_wakeup(priv->device)) { priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ - enable_irq_wake(dev->irq); + enable_irq_wake(priv->wol_irq); } return 0; @@ -1588,6 +1588,18 @@ static int stmmac_dvr_probe(struct platform_device *pdev) pr_info("\tPMT module supported\n"); device_set_wakeup_capable(&pdev->dev, 1); } + /* + * On some platforms e.g. SPEAr the wake up irq differs from the mac irq + * The external wake up irq can be passed through the platform code + * named as "eth_wake_irq" + * + * In case the wake up interrupt is not passed from the platform + * 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) + priv->wol_irq = ndev->irq; + platform_set_drvdata(pdev, ndev); -- cgit v1.2.3 From 1c901a46d576926287b05fc145bd3fd31a3e65de Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 1 Sep 2011 21:51:38 +0000 Subject: stmmac: add MMC support exported via ethtool (v3) This patch adds the MMC management counters support. MMC module is an extension of the register address space and all the hardware counters can be accessed via ethtoo -S ethX. Note that, the MMC interrupts remain masked and the logic to handle this kind of interrupt will be added later (if actually useful). Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Makefile | 3 +- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 8 - drivers/net/ethernet/stmicro/stmmac/mmc.h | 131 ++++++++++ drivers/net/ethernet/stmicro/stmmac/mmc_core.c | 265 +++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 140 ++++++++++- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 13 + 8 files changed, 540 insertions(+), 22 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/mmc.h create mode 100644 drivers/net/ethernet/stmicro/stmmac/mmc_core.c (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 9691733ddb8e..0f23d95746b7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \ dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ - dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y) + dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ + mmc_core.o $(stmmac-y) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 290b97a19254..e08fee880f14 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -29,6 +29,7 @@ #endif #include "descs.h" +#include "mmc.h" #undef CHIP_DEBUG_PRINT /* Turn-on extra printk debug for MAC core, dma and descriptors */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index 3dbeea619085..a89384c07513 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -118,13 +118,6 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode, writel(csr6, ioaddr + DMA_CONTROL); } -/* Not yet implemented --- no RMON module */ -static void dwmac1000_dma_diagnostic_fr(void *data, - struct stmmac_extra_stats *x, void __iomem *ioaddr) -{ - return; -} - static void dwmac1000_dump_dma_regs(void __iomem *ioaddr) { int i; @@ -143,7 +136,6 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = { .init = dwmac1000_dma_init, .dump_regs = dwmac1000_dump_dma_regs, .dma_mode = dwmac1000_dma_operation_mode, - .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr, .enable_dma_transmission = dwmac_enable_dma_transmission, .enable_dma_irq = dwmac_enable_dma_irq, .disable_dma_irq = dwmac_disable_dma_irq, diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h new file mode 100644 index 000000000000..a38352024cb8 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h @@ -0,0 +1,131 @@ +/******************************************************************************* + MMC Header file + + Copyright (C) 2011 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +/* MMC control register */ +/* When set, all counter are reset */ +#define MMC_CNTRL_COUNTER_RESET 0x1 +/* When set, do not roll over zero + * after reaching the max value*/ +#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2 +#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */ +#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the + * current value.*/ +#define MMC_CNTRL_PRESET 0x10 +#define MMC_CNTRL_FULL_HALF_PRESET 0x20 +struct stmmac_counters { + unsigned int mmc_tx_octetcount_gb; + unsigned int mmc_tx_framecount_gb; + unsigned int mmc_tx_broadcastframe_g; + unsigned int mmc_tx_multicastframe_g; + unsigned int mmc_tx_64_octets_gb; + unsigned int mmc_tx_65_to_127_octets_gb; + unsigned int mmc_tx_128_to_255_octets_gb; + unsigned int mmc_tx_256_to_511_octets_gb; + unsigned int mmc_tx_512_to_1023_octets_gb; + unsigned int mmc_tx_1024_to_max_octets_gb; + unsigned int mmc_tx_unicast_gb; + unsigned int mmc_tx_multicast_gb; + unsigned int mmc_tx_broadcast_gb; + unsigned int mmc_tx_underflow_error; + unsigned int mmc_tx_singlecol_g; + unsigned int mmc_tx_multicol_g; + unsigned int mmc_tx_deferred; + unsigned int mmc_tx_latecol; + unsigned int mmc_tx_exesscol; + unsigned int mmc_tx_carrier_error; + unsigned int mmc_tx_octetcount_g; + unsigned int mmc_tx_framecount_g; + unsigned int mmc_tx_excessdef; + unsigned int mmc_tx_pause_frame; + unsigned int mmc_tx_vlan_frame_g; + + /* MMC RX counter registers */ + unsigned int mmc_rx_framecount_gb; + unsigned int mmc_rx_octetcount_gb; + unsigned int mmc_rx_octetcount_g; + unsigned int mmc_rx_broadcastframe_g; + unsigned int mmc_rx_multicastframe_g; + unsigned int mmc_rx_crc_errror; + unsigned int mmc_rx_align_error; + unsigned int mmc_rx_run_error; + unsigned int mmc_rx_jabber_error; + unsigned int mmc_rx_undersize_g; + unsigned int mmc_rx_oversize_g; + unsigned int mmc_rx_64_octets_gb; + unsigned int mmc_rx_65_to_127_octets_gb; + unsigned int mmc_rx_128_to_255_octets_gb; + unsigned int mmc_rx_256_to_511_octets_gb; + unsigned int mmc_rx_512_to_1023_octets_gb; + unsigned int mmc_rx_1024_to_max_octets_gb; + unsigned int mmc_rx_unicast_g; + unsigned int mmc_rx_length_error; + unsigned int mmc_rx_autofrangetype; + unsigned int mmc_rx_pause_frames; + unsigned int mmc_rx_fifo_overflow; + unsigned int mmc_rx_vlan_frames_gb; + unsigned int mmc_rx_watchdog_error; + /* IPC */ + unsigned int mmc_rx_ipc_intr_mask; + unsigned int mmc_rx_ipc_intr; + /* IPv4 */ + unsigned int mmc_rx_ipv4_gd; + unsigned int mmc_rx_ipv4_hderr; + unsigned int mmc_rx_ipv4_nopay; + unsigned int mmc_rx_ipv4_frag; + unsigned int mmc_rx_ipv4_udsbl; + + unsigned int mmc_rx_ipv4_gd_octets; + unsigned int mmc_rx_ipv4_hderr_octets; + unsigned int mmc_rx_ipv4_nopay_octets; + unsigned int mmc_rx_ipv4_frag_octets; + unsigned int mmc_rx_ipv4_udsbl_octets; + + /* IPV6 */ + unsigned int mmc_rx_ipv6_gd_octets; + unsigned int mmc_rx_ipv6_hderr_octets; + unsigned int mmc_rx_ipv6_nopay_octets; + + unsigned int mmc_rx_ipv6_gd; + unsigned int mmc_rx_ipv6_hderr; + unsigned int mmc_rx_ipv6_nopay; + + /* Protocols */ + unsigned int mmc_rx_udp_gd; + unsigned int mmc_rx_udp_err; + unsigned int mmc_rx_tcp_gd; + unsigned int mmc_rx_tcp_err; + unsigned int mmc_rx_icmp_gd; + unsigned int mmc_rx_icmp_err; + + unsigned int mmc_rx_udp_gd_octets; + unsigned int mmc_rx_udp_err_octets; + unsigned int mmc_rx_tcp_gd_octets; + unsigned int mmc_rx_tcp_err_octets; + unsigned int mmc_rx_icmp_gd_octets; + 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); diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c new file mode 100644 index 000000000000..41e6b33e1b08 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -0,0 +1,265 @@ +/******************************************************************************* + DWMAC Management Counters + + Copyright (C) 2011 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "mmc.h" + +/* MAC Management Counters register offset */ + +#define MMC_CNTRL 0x00000100 /* MMC Control */ +#define MMC_RX_INTR 0x00000104 /* MMC RX Interrupt */ +#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */ +#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */ +#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */ +#define MMC_DEFAUL_MASK 0xffffffff + +/* MMC TX counter registers */ + +/* Note: + * _GB register stands for good and bad frames + * _G is for good only. + */ +#define MMC_TX_OCTETCOUNT_GB 0x00000114 +#define MMC_TX_FRAMECOUNT_GB 0x00000118 +#define MMC_TX_BROADCASTFRAME_G 0x0000011c +#define MMC_TX_MULTICASTFRAME_G 0x00000120 +#define MMC_TX_64_OCTETS_GB 0x00000124 +#define MMC_TX_65_TO_127_OCTETS_GB 0x00000128 +#define MMC_TX_128_TO_255_OCTETS_GB 0x0000012c +#define MMC_TX_256_TO_511_OCTETS_GB 0x00000130 +#define MMC_TX_512_TO_1023_OCTETS_GB 0x00000134 +#define MMC_TX_1024_TO_MAX_OCTETS_GB 0x00000138 +#define MMC_TX_UNICAST_GB 0x0000013c +#define MMC_TX_MULTICAST_GB 0x00000140 +#define MMC_TX_BROADCAST_GB 0x00000144 +#define MMC_TX_UNDERFLOW_ERROR 0x00000148 +#define MMC_TX_SINGLECOL_G 0x0000014c +#define MMC_TX_MULTICOL_G 0x00000150 +#define MMC_TX_DEFERRED 0x00000154 +#define MMC_TX_LATECOL 0x00000158 +#define MMC_TX_EXESSCOL 0x0000015c +#define MMC_TX_CARRIER_ERROR 0x00000160 +#define MMC_TX_OCTETCOUNT_G 0x00000164 +#define MMC_TX_FRAMECOUNT_G 0x00000168 +#define MMC_TX_EXCESSDEF 0x0000016c +#define MMC_TX_PAUSE_FRAME 0x00000170 +#define MMC_TX_VLAN_FRAME_G 0x00000174 + +/* MMC RX counter registers */ +#define MMC_RX_FRAMECOUNT_GB 0x00000180 +#define MMC_RX_OCTETCOUNT_GB 0x00000184 +#define MMC_RX_OCTETCOUNT_G 0x00000188 +#define MMC_RX_BROADCASTFRAME_G 0x0000018c +#define MMC_RX_MULTICASTFRAME_G 0x00000190 +#define MMC_RX_CRC_ERRROR 0x00000194 +#define MMC_RX_ALIGN_ERROR 0x00000198 +#define MMC_RX_RUN_ERROR 0x0000019C +#define MMC_RX_JABBER_ERROR 0x000001A0 +#define MMC_RX_UNDERSIZE_G 0x000001A4 +#define MMC_RX_OVERSIZE_G 0x000001A8 +#define MMC_RX_64_OCTETS_GB 0x000001AC +#define MMC_RX_65_TO_127_OCTETS_GB 0x000001b0 +#define MMC_RX_128_TO_255_OCTETS_GB 0x000001b4 +#define MMC_RX_256_TO_511_OCTETS_GB 0x000001b8 +#define MMC_RX_512_TO_1023_OCTETS_GB 0x000001bc +#define MMC_RX_1024_TO_MAX_OCTETS_GB 0x000001c0 +#define MMC_RX_UNICAST_G 0x000001c4 +#define MMC_RX_LENGTH_ERROR 0x000001c8 +#define MMC_RX_AUTOFRANGETYPE 0x000001cc +#define MMC_RX_PAUSE_FRAMES 0x000001d0 +#define MMC_RX_FIFO_OVERFLOW 0x000001d4 +#define MMC_RX_VLAN_FRAMES_GB 0x000001d8 +#define MMC_RX_WATCHDOG_ERROR 0x000001dc +/* IPC*/ +#define MMC_RX_IPC_INTR_MASK 0x00000200 +#define MMC_RX_IPC_INTR 0x00000208 +/* IPv4*/ +#define MMC_RX_IPV4_GD 0x00000210 +#define MMC_RX_IPV4_HDERR 0x00000214 +#define MMC_RX_IPV4_NOPAY 0x00000218 +#define MMC_RX_IPV4_FRAG 0x0000021C +#define MMC_RX_IPV4_UDSBL 0x00000220 + +#define MMC_RX_IPV4_GD_OCTETS 0x00000250 +#define MMC_RX_IPV4_HDERR_OCTETS 0x00000254 +#define MMC_RX_IPV4_NOPAY_OCTETS 0x00000258 +#define MMC_RX_IPV4_FRAG_OCTETS 0x0000025c +#define MMC_RX_IPV4_UDSBL_OCTETS 0x00000260 + +/* IPV6*/ +#define MMC_RX_IPV6_GD_OCTETS 0x00000264 +#define MMC_RX_IPV6_HDERR_OCTETS 0x00000268 +#define MMC_RX_IPV6_NOPAY_OCTETS 0x0000026c + +#define MMC_RX_IPV6_GD 0x00000224 +#define MMC_RX_IPV6_HDERR 0x00000228 +#define MMC_RX_IPV6_NOPAY 0x0000022c + +/* Protocols*/ +#define MMC_RX_UDP_GD 0x00000230 +#define MMC_RX_UDP_ERR 0x00000234 +#define MMC_RX_TCP_GD 0x00000238 +#define MMC_RX_TCP_ERR 0x0000023c +#define MMC_RX_ICMP_GD 0x00000240 +#define MMC_RX_ICMP_ERR 0x00000244 + +#define MMC_RX_UDP_GD_OCTETS 0x00000270 +#define MMC_RX_UDP_ERR_OCTETS 0x00000274 +#define MMC_RX_TCP_GD_OCTETS 0x00000278 +#define MMC_RX_TCP_ERR_OCTETS 0x0000027c +#define MMC_RX_ICMP_GD_OCTETS 0x00000280 +#define MMC_RX_ICMP_ERR_OCTETS 0x00000284 + +void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode) +{ + u32 value = readl(ioaddr + MMC_CNTRL); + + value |= (mode & 0x3F); + + writel(value, ioaddr + MMC_CNTRL); + + pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n", + MMC_CNTRL, value); +} + +/* To mask all all interrupts.*/ +void dwmac_mmc_intr_all_mask(void __iomem *ioaddr) +{ + writel(MMC_DEFAUL_MASK, ioaddr + MMC_RX_INTR_MASK); + writel(MMC_DEFAUL_MASK, ioaddr + MMC_TX_INTR_MASK); +} + +/* This reads the MAC core counters (if actaully supported). + * by default the MMC core is programmed to reset each + * counter after a read. So all the field of the mmc struct + * have to be incremented. + */ +void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc) +{ + mmc->mmc_tx_octetcount_gb += readl(ioaddr + MMC_TX_OCTETCOUNT_GB); + mmc->mmc_tx_framecount_gb += readl(ioaddr + MMC_TX_FRAMECOUNT_GB); + mmc->mmc_tx_broadcastframe_g += readl(ioaddr + MMC_TX_BROADCASTFRAME_G); + mmc->mmc_tx_multicastframe_g += readl(ioaddr + MMC_TX_MULTICASTFRAME_G); + mmc->mmc_tx_64_octets_gb += readl(ioaddr + MMC_TX_64_OCTETS_GB); + mmc->mmc_tx_65_to_127_octets_gb += + readl(ioaddr + MMC_TX_65_TO_127_OCTETS_GB); + mmc->mmc_tx_128_to_255_octets_gb += + readl(ioaddr + MMC_TX_128_TO_255_OCTETS_GB); + mmc->mmc_tx_256_to_511_octets_gb += + readl(ioaddr + MMC_TX_256_TO_511_OCTETS_GB); + mmc->mmc_tx_512_to_1023_octets_gb += + readl(ioaddr + MMC_TX_512_TO_1023_OCTETS_GB); + mmc->mmc_tx_1024_to_max_octets_gb += + readl(ioaddr + MMC_TX_1024_TO_MAX_OCTETS_GB); + mmc->mmc_tx_unicast_gb += readl(ioaddr + MMC_TX_UNICAST_GB); + mmc->mmc_tx_multicast_gb += readl(ioaddr + MMC_TX_MULTICAST_GB); + mmc->mmc_tx_broadcast_gb += readl(ioaddr + MMC_TX_BROADCAST_GB); + mmc->mmc_tx_underflow_error += readl(ioaddr + MMC_TX_UNDERFLOW_ERROR); + mmc->mmc_tx_singlecol_g += readl(ioaddr + MMC_TX_SINGLECOL_G); + mmc->mmc_tx_multicol_g += readl(ioaddr + MMC_TX_MULTICOL_G); + mmc->mmc_tx_deferred += readl(ioaddr + MMC_TX_DEFERRED); + mmc->mmc_tx_latecol += readl(ioaddr + MMC_TX_LATECOL); + mmc->mmc_tx_exesscol += readl(ioaddr + MMC_TX_EXESSCOL); + mmc->mmc_tx_carrier_error += readl(ioaddr + MMC_TX_CARRIER_ERROR); + mmc->mmc_tx_octetcount_g += readl(ioaddr + MMC_TX_OCTETCOUNT_G); + mmc->mmc_tx_framecount_g += readl(ioaddr + MMC_TX_FRAMECOUNT_G); + mmc->mmc_tx_excessdef += readl(ioaddr + MMC_TX_EXCESSDEF); + mmc->mmc_tx_pause_frame += readl(ioaddr + MMC_TX_PAUSE_FRAME); + mmc->mmc_tx_vlan_frame_g += readl(ioaddr + MMC_TX_VLAN_FRAME_G); + + /* MMC RX counter registers */ + mmc->mmc_rx_framecount_gb += readl(ioaddr + MMC_RX_FRAMECOUNT_GB); + mmc->mmc_rx_octetcount_gb += readl(ioaddr + MMC_RX_OCTETCOUNT_GB); + mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G); + mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G); + mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G); + mmc->mmc_rx_crc_errror += readl(ioaddr + MMC_RX_CRC_ERRROR); + mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR); + mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR); + mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR); + mmc->mmc_rx_undersize_g += readl(ioaddr + MMC_RX_UNDERSIZE_G); + mmc->mmc_rx_oversize_g += readl(ioaddr + MMC_RX_OVERSIZE_G); + mmc->mmc_rx_64_octets_gb += readl(ioaddr + MMC_RX_64_OCTETS_GB); + mmc->mmc_rx_65_to_127_octets_gb += + readl(ioaddr + MMC_RX_65_TO_127_OCTETS_GB); + mmc->mmc_rx_128_to_255_octets_gb += + readl(ioaddr + MMC_RX_128_TO_255_OCTETS_GB); + mmc->mmc_rx_256_to_511_octets_gb += + readl(ioaddr + MMC_RX_256_TO_511_OCTETS_GB); + mmc->mmc_rx_512_to_1023_octets_gb += + readl(ioaddr + MMC_RX_512_TO_1023_OCTETS_GB); + mmc->mmc_rx_1024_to_max_octets_gb += + readl(ioaddr + MMC_RX_1024_TO_MAX_OCTETS_GB); + mmc->mmc_rx_unicast_g += readl(ioaddr + MMC_RX_UNICAST_G); + mmc->mmc_rx_length_error += readl(ioaddr + MMC_RX_LENGTH_ERROR); + mmc->mmc_rx_autofrangetype += readl(ioaddr + MMC_RX_AUTOFRANGETYPE); + mmc->mmc_rx_pause_frames += readl(ioaddr + MMC_RX_PAUSE_FRAMES); + mmc->mmc_rx_fifo_overflow += readl(ioaddr + MMC_RX_FIFO_OVERFLOW); + mmc->mmc_rx_vlan_frames_gb += readl(ioaddr + MMC_RX_VLAN_FRAMES_GB); + mmc->mmc_rx_watchdog_error += readl(ioaddr + MMC_RX_WATCHDOG_ERROR); + /* IPC */ + mmc->mmc_rx_ipc_intr_mask += readl(ioaddr + MMC_RX_IPC_INTR_MASK); + mmc->mmc_rx_ipc_intr += readl(ioaddr + MMC_RX_IPC_INTR); + /* IPv4 */ + mmc->mmc_rx_ipv4_gd += readl(ioaddr + MMC_RX_IPV4_GD); + mmc->mmc_rx_ipv4_hderr += readl(ioaddr + MMC_RX_IPV4_HDERR); + mmc->mmc_rx_ipv4_nopay += readl(ioaddr + MMC_RX_IPV4_NOPAY); + mmc->mmc_rx_ipv4_frag += readl(ioaddr + MMC_RX_IPV4_FRAG); + mmc->mmc_rx_ipv4_udsbl += readl(ioaddr + MMC_RX_IPV4_UDSBL); + + mmc->mmc_rx_ipv4_gd_octets += readl(ioaddr + MMC_RX_IPV4_GD_OCTETS); + mmc->mmc_rx_ipv4_hderr_octets += + readl(ioaddr + MMC_RX_IPV4_HDERR_OCTETS); + mmc->mmc_rx_ipv4_nopay_octets += + readl(ioaddr + MMC_RX_IPV4_NOPAY_OCTETS); + mmc->mmc_rx_ipv4_frag_octets += readl(ioaddr + MMC_RX_IPV4_FRAG_OCTETS); + mmc->mmc_rx_ipv4_udsbl_octets += + readl(ioaddr + MMC_RX_IPV4_UDSBL_OCTETS); + + /* IPV6 */ + mmc->mmc_rx_ipv6_gd_octets += readl(ioaddr + MMC_RX_IPV6_GD_OCTETS); + mmc->mmc_rx_ipv6_hderr_octets += + readl(ioaddr + MMC_RX_IPV6_HDERR_OCTETS); + mmc->mmc_rx_ipv6_nopay_octets += + readl(ioaddr + MMC_RX_IPV6_NOPAY_OCTETS); + + mmc->mmc_rx_ipv6_gd += readl(ioaddr + MMC_RX_IPV6_GD); + mmc->mmc_rx_ipv6_hderr += readl(ioaddr + MMC_RX_IPV6_HDERR); + mmc->mmc_rx_ipv6_nopay += readl(ioaddr + MMC_RX_IPV6_NOPAY); + + /* Protocols */ + mmc->mmc_rx_udp_gd += readl(ioaddr + MMC_RX_UDP_GD); + mmc->mmc_rx_udp_err += readl(ioaddr + MMC_RX_UDP_ERR); + mmc->mmc_rx_tcp_gd += readl(ioaddr + MMC_RX_TCP_GD); + mmc->mmc_rx_tcp_err += readl(ioaddr + MMC_RX_TCP_ERR); + mmc->mmc_rx_icmp_gd += readl(ioaddr + MMC_RX_ICMP_GD); + mmc->mmc_rx_icmp_err += readl(ioaddr + MMC_RX_ICMP_ERR); + + mmc->mmc_rx_udp_gd_octets += readl(ioaddr + MMC_RX_UDP_GD_OCTETS); + mmc->mmc_rx_udp_err_octets += readl(ioaddr + MMC_RX_UDP_ERR_OCTETS); + mmc->mmc_rx_tcp_gd_octets += readl(ioaddr + MMC_RX_TCP_GD_OCTETS); + mmc->mmc_rx_tcp_err_octets += readl(ioaddr + MMC_RX_TCP_ERR_OCTETS); + mmc->mmc_rx_icmp_gd_octets += readl(ioaddr + MMC_RX_ICMP_GD_OCTETS); + mmc->mmc_rx_icmp_err_octets += readl(ioaddr + MMC_RX_ICMP_ERR_OCTETS); +} diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 619e3af97404..ef037965493d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -77,6 +77,7 @@ struct stmmac_priv { struct stmmac_timer *tm; #endif struct plat_stmmacenet_data *plat; + struct stmmac_counters mmc; }; extern int stmmac_mdio_unregister(struct net_device *ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 79df79dc6a69..aedff9a90ebc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -46,7 +46,7 @@ struct stmmac_stats { { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ offsetof(struct stmmac_priv, xstats.m)} -static const struct stmmac_stats stmmac_gstrings_stats[] = { +static const struct stmmac_stats stmmac_gstrings_stats[] = { STMMAC_STAT(tx_underflow), STMMAC_STAT(tx_carrier), STMMAC_STAT(tx_losscarrier), @@ -91,19 +91,106 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { }; #define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) +/* HW MAC Management counters (if supported) */ +#define STMMAC_MMC_STAT(m) \ + { #m, FIELD_SIZEOF(struct stmmac_counters, m), \ + offsetof(struct stmmac_priv, mmc.m)} + +static const struct stmmac_stats stmmac_gstr_mmc[] = { + STMMAC_MMC_STAT(mmc_tx_octetcount_gb), + STMMAC_MMC_STAT(mmc_tx_framecount_gb), + STMMAC_MMC_STAT(mmc_tx_broadcastframe_g), + STMMAC_MMC_STAT(mmc_tx_multicastframe_g), + STMMAC_MMC_STAT(mmc_tx_64_octets_gb), + STMMAC_MMC_STAT(mmc_tx_65_to_127_octets_gb), + STMMAC_MMC_STAT(mmc_tx_128_to_255_octets_gb), + STMMAC_MMC_STAT(mmc_tx_256_to_511_octets_gb), + STMMAC_MMC_STAT(mmc_tx_512_to_1023_octets_gb), + STMMAC_MMC_STAT(mmc_tx_1024_to_max_octets_gb), + STMMAC_MMC_STAT(mmc_tx_unicast_gb), + STMMAC_MMC_STAT(mmc_tx_multicast_gb), + STMMAC_MMC_STAT(mmc_tx_broadcast_gb), + STMMAC_MMC_STAT(mmc_tx_underflow_error), + STMMAC_MMC_STAT(mmc_tx_singlecol_g), + STMMAC_MMC_STAT(mmc_tx_multicol_g), + STMMAC_MMC_STAT(mmc_tx_deferred), + STMMAC_MMC_STAT(mmc_tx_latecol), + STMMAC_MMC_STAT(mmc_tx_exesscol), + STMMAC_MMC_STAT(mmc_tx_carrier_error), + STMMAC_MMC_STAT(mmc_tx_octetcount_g), + STMMAC_MMC_STAT(mmc_tx_framecount_g), + STMMAC_MMC_STAT(mmc_tx_excessdef), + STMMAC_MMC_STAT(mmc_tx_pause_frame), + STMMAC_MMC_STAT(mmc_tx_vlan_frame_g), + STMMAC_MMC_STAT(mmc_rx_framecount_gb), + STMMAC_MMC_STAT(mmc_rx_octetcount_gb), + STMMAC_MMC_STAT(mmc_rx_octetcount_g), + STMMAC_MMC_STAT(mmc_rx_broadcastframe_g), + STMMAC_MMC_STAT(mmc_rx_multicastframe_g), + STMMAC_MMC_STAT(mmc_rx_crc_errror), + STMMAC_MMC_STAT(mmc_rx_align_error), + STMMAC_MMC_STAT(mmc_rx_run_error), + STMMAC_MMC_STAT(mmc_rx_jabber_error), + STMMAC_MMC_STAT(mmc_rx_undersize_g), + STMMAC_MMC_STAT(mmc_rx_oversize_g), + STMMAC_MMC_STAT(mmc_rx_64_octets_gb), + STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb), + STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb), + STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb), + STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb), + STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb), + STMMAC_MMC_STAT(mmc_rx_unicast_g), + STMMAC_MMC_STAT(mmc_rx_length_error), + STMMAC_MMC_STAT(mmc_rx_autofrangetype), + STMMAC_MMC_STAT(mmc_rx_pause_frames), + STMMAC_MMC_STAT(mmc_rx_fifo_overflow), + STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb), + STMMAC_MMC_STAT(mmc_rx_watchdog_error), + STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask), + STMMAC_MMC_STAT(mmc_rx_ipc_intr), + STMMAC_MMC_STAT(mmc_rx_ipv4_gd), + STMMAC_MMC_STAT(mmc_rx_ipv4_hderr), + STMMAC_MMC_STAT(mmc_rx_ipv4_nopay), + STMMAC_MMC_STAT(mmc_rx_ipv4_frag), + STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl), + STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_gd), + STMMAC_MMC_STAT(mmc_rx_ipv6_hderr), + STMMAC_MMC_STAT(mmc_rx_ipv6_nopay), + STMMAC_MMC_STAT(mmc_rx_udp_gd), + STMMAC_MMC_STAT(mmc_rx_udp_err), + STMMAC_MMC_STAT(mmc_rx_tcp_gd), + STMMAC_MMC_STAT(mmc_rx_tcp_err), + STMMAC_MMC_STAT(mmc_rx_icmp_gd), + STMMAC_MMC_STAT(mmc_rx_icmp_err), + STMMAC_MMC_STAT(mmc_rx_udp_gd_octets), + STMMAC_MMC_STAT(mmc_rx_udp_err_octets), + STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets), + STMMAC_MMC_STAT(mmc_rx_tcp_err_octets), + STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets), + STMMAC_MMC_STAT(mmc_rx_icmp_err_octets), +}; +#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_gstr_mmc) + static void stmmac_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->plat->has_gmac) - strcpy(info->driver, MAC100_ETHTOOL_NAME); - else + if (priv->plat->has_gmac) strcpy(info->driver, GMAC_ETHTOOL_NAME); + else + strcpy(info->driver, MAC100_ETHTOOL_NAME); strcpy(info->version, DRV_MODULE_VERSION); info->fw_version[0] = '\0'; - info->n_stats = STMMAC_STATS_LEN; } static int stmmac_ethtool_getsettings(struct net_device *dev, @@ -252,24 +339,44 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 *data) { struct stmmac_priv *priv = netdev_priv(dev); - int i; - - /* Update HW stats if supported */ - priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats, - priv->ioaddr); + int i, j = 0; + /* Update the DMA HW counters for dwmac10/100 */ + if (!priv->plat->has_gmac) + priv->hw->dma->dma_diagnostic_fr(&dev->stats, + (void *) &priv->xstats, + priv->ioaddr); + else { + /* If supported, for new GMAC chips expose the MMC counters */ + dwmac_mmc_read(priv->ioaddr, &priv->mmc); + + for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { + char *p = (char *)priv + stmmac_gstr_mmc[i].stat_offset; + + data[j++] = (stmmac_gstr_mmc[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + } + } for (i = 0; i < STMMAC_STATS_LEN; i++) { char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; - data[i] = (stmmac_gstrings_stats[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + data[j++] = (stmmac_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); } } static int stmmac_get_sset_count(struct net_device *netdev, int sset) { + struct stmmac_priv *priv = netdev_priv(netdev); + int len; + switch (sset) { case ETH_SS_STATS: - return STMMAC_STATS_LEN; + len = STMMAC_STATS_LEN; + + if (priv->plat->has_gmac) + len += STMMAC_MMC_STATS_LEN; + + return len; default: return -EOPNOTSUPP; } @@ -279,9 +386,16 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) { int i; u8 *p = data; + struct stmmac_priv *priv = netdev_priv(dev); switch (stringset) { case ETH_SS_STATS: + if (priv->plat->has_gmac) + for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { + memcpy(p, stmmac_gstr_mmc[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } for (i = 0; i < STMMAC_STATS_LEN; i++) { memcpy(p, stmmac_gstrings_stats[i].stat_string, ETH_GSTRING_LEN); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5aea21e587dd..c28b90d35007 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -748,6 +748,17 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) stmmac_tx_err(priv); } +static void stmmac_mmc_setup(struct stmmac_priv *priv) +{ + unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | + MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; + + /* Do not manage MMC IRQ (FIXME) */ + dwmac_mmc_intr_all_mask(priv->ioaddr); + dwmac_mmc_ctrl(priv->ioaddr, mode); + memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); +} + /** * stmmac_open - open entry point of the driver * @dev : pointer to the device structure. @@ -846,6 +857,8 @@ static int stmmac_open(struct net_device *dev) memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); priv->xstats.threshold = tc; + stmmac_mmc_setup(priv); + /* Start the ball rolling... */ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); priv->hw->dma->start_tx(priv->ioaddr); -- cgit v1.2.3 From e7434821411b5fc24ab23e55cb11ea793248cb6b Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 1 Sep 2011 21:51:41 +0000 Subject: stmmac: add HW DMA feature register (v3) New GMAC chips have an extra register to indicate the presence of the optional features/functions of the DMA core. This patch adds this support and all the HW cap are exported via debugfs. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 3 +- drivers/net/ethernet/stmicro/stmmac/common.h | 33 ++++++ .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 6 + drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 131 +++++++++++++++++++++ 6 files changed, 174 insertions(+), 1 deletion(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index ae7f56312f08..2e35be7ccfae 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -16,7 +16,8 @@ config STMMAC_DEBUG_FS default n depends on STMMAC_ETH && DEBUG_FS -- help - The stmmac entry in /sys reports DMA TX/RX rings. + The stmmac entry in /sys reports DMA TX/RX rings + or (if supported) the HW cap register. config STMMAC_DA bool "STMMAC DMA arbitration scheme" diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 65b1e56a97c9..22c61b2ebfa3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -116,6 +116,37 @@ enum tx_dma_irq_status { handle_tx_rx = 3, }; +/* DMA HW capabilities */ +struct dma_features { + unsigned int mbps_10_100; + unsigned int mbps_1000; + unsigned int half_duplex; + unsigned int hash_filter; + unsigned int multi_addr; + unsigned int pcs; + unsigned int sma_mdio; + unsigned int pmt_remote_wake_up; + unsigned int pmt_magic_frame; + unsigned int rmon; + /* IEEE 1588-2002*/ + unsigned int time_stamp; + /* IEEE 1588-2008*/ + unsigned int atime_stamp; + /* 802.3az - Energy-Efficient Ethernet (EEE) */ + unsigned int eee; + unsigned int av; + /* TX and RX csum */ + unsigned int tx_coe; + unsigned int rx_coe_type1; + unsigned int rx_coe_type2; + unsigned int rxfifo_over_2048; + /* TX and RX number of channels */ + unsigned int number_rx_channel; + unsigned int number_tx_channel; + /* Alternate (enhanced) DESC mode*/ + unsigned int enh_desc; +}; + /* GMAC TX FIFO is 8K, Rx FIFO is 16K */ #define BUF_SIZE_16KiB 16384 #define BUF_SIZE_8KiB 8192 @@ -188,6 +219,8 @@ struct stmmac_dma_ops { void (*stop_rx) (void __iomem *ioaddr); int (*dma_interrupt) (void __iomem *ioaddr, struct stmmac_extra_stats *x); + /* If supported then get the optional core features */ + unsigned int (*get_hw_feature) (void __iomem *ioaddr); }; struct stmmac_ops { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index a89384c07513..da66ac511c4c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -132,6 +132,11 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr) } } +static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr) +{ + return readl(ioaddr + DMA_HW_FEATURE); +} + const struct stmmac_dma_ops dwmac1000_dma_ops = { .init = dwmac1000_dma_init, .dump_regs = dwmac1000_dump_dma_regs, @@ -144,4 +149,5 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = { .start_rx = dwmac_dma_start_rx, .stop_rx = dwmac_dma_stop_rx, .dma_interrupt = dwmac_dma_interrupt, + .get_hw_feature = dwmac1000_get_hw_feature, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index da3f5ccf83d3..437edacd602e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -34,6 +34,7 @@ #define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */ #define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ #define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ +#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */ /* DMA Control register defines */ #define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index ef037965493d..c3a2da71d1e6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -78,6 +78,7 @@ struct stmmac_priv { #endif struct plat_stmmacenet_data *plat; struct stmmac_counters mmc; + struct dma_features dma_cap; }; extern int stmmac_mdio_unregister(struct net_device *ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index eb210ca2497b..d0fbc5477d10 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -780,6 +780,49 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) } return 0; } + +/* New GMAC chips support a new register to indicate the + * presence of the optional feature/functions. + */ +static int stmmac_get_hw_features(struct stmmac_priv *priv) +{ + u32 hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr); + + if (likely(hw_cap)) { + priv->dma_cap.mbps_10_100 = (hw_cap & 0x1); + priv->dma_cap.mbps_1000 = (hw_cap & 0x2) >> 1; + priv->dma_cap.half_duplex = (hw_cap & 0x4) >> 2; + priv->dma_cap.hash_filter = (hw_cap & 0x10) >> 4; + priv->dma_cap.multi_addr = (hw_cap & 0x20) >> 5; + priv->dma_cap.pcs = (hw_cap & 0x40) >> 6; + priv->dma_cap.sma_mdio = (hw_cap & 0x100) >> 8; + priv->dma_cap.pmt_remote_wake_up = (hw_cap & 0x200) >> 9; + priv->dma_cap.pmt_magic_frame = (hw_cap & 0x400) >> 10; + priv->dma_cap.rmon = (hw_cap & 0x800) >> 11; /* MMC */ + /* IEEE 1588-2002*/ + priv->dma_cap.time_stamp = (hw_cap & 0x1000) >> 12; + /* IEEE 1588-2008*/ + priv->dma_cap.atime_stamp = (hw_cap & 0x2000) >> 13; + /* 802.3az - Energy-Efficient Ethernet (EEE) */ + priv->dma_cap.eee = (hw_cap & 0x4000) >> 14; + priv->dma_cap.av = (hw_cap & 0x8000) >> 15; + /* TX and RX csum */ + priv->dma_cap.tx_coe = (hw_cap & 0x10000) >> 16; + priv->dma_cap.rx_coe_type1 = (hw_cap & 0x20000) >> 17; + priv->dma_cap.rx_coe_type2 = (hw_cap & 0x40000) >> 18; + priv->dma_cap.rxfifo_over_2048 = (hw_cap & 0x80000) >> 19; + /* TX and RX number of channels */ + priv->dma_cap.number_rx_channel = (hw_cap & 0x300000) >> 20; + priv->dma_cap.number_tx_channel = (hw_cap & 0xc00000) >> 22; + /* Alternate (enhanced) DESC mode*/ + priv->dma_cap.enh_desc = (hw_cap & 0x1000000) >> 24; + + } else + pr_debug("\tNo HW DMA feature register supported"); + + return hw_cap; +} + /** * stmmac_open - open entry point of the driver * @dev : pointer to the device structure. @@ -854,6 +897,8 @@ static int stmmac_open(struct net_device *dev) stmmac_get_synopsys_id(priv); + stmmac_get_hw_features(priv); + if (priv->rx_coe) pr_info("stmmac: Rx Checksum Offload Engine supported\n"); if (priv->plat->tx_coe) @@ -1450,6 +1495,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) #ifdef CONFIG_STMMAC_DEBUG_FS static struct dentry *stmmac_fs_dir; static struct dentry *stmmac_rings_status; +static struct dentry *stmmac_dma_cap; static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v) { @@ -1503,6 +1549,78 @@ static const struct file_operations stmmac_rings_status_fops = { .release = seq_release, }; +static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v) +{ + struct net_device *dev = seq->private; + struct stmmac_priv *priv = netdev_priv(dev); + + if (!stmmac_get_hw_features(priv)) { + seq_printf(seq, "DMA HW features not supported\n"); + return 0; + } + + seq_printf(seq, "==============================\n"); + seq_printf(seq, "\tDMA HW features\n"); + seq_printf(seq, "==============================\n"); + + seq_printf(seq, "\t10/100 Mbps %s\n", + (priv->dma_cap.mbps_10_100) ? "Y" : "N"); + seq_printf(seq, "\t1000 Mbps %s\n", + (priv->dma_cap.mbps_1000) ? "Y" : "N"); + seq_printf(seq, "\tHalf duple %s\n", + (priv->dma_cap.half_duplex) ? "Y" : "N"); + seq_printf(seq, "\tHash Filter: %s\n", + (priv->dma_cap.hash_filter) ? "Y" : "N"); + seq_printf(seq, "\tMultiple MAC address registers: %s\n", + (priv->dma_cap.multi_addr) ? "Y" : "N"); + seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfatces): %s\n", + (priv->dma_cap.pcs) ? "Y" : "N"); + seq_printf(seq, "\tSMA (MDIO) Interface: %s\n", + (priv->dma_cap.sma_mdio) ? "Y" : "N"); + seq_printf(seq, "\tPMT Remote wake up: %s\n", + (priv->dma_cap.pmt_remote_wake_up) ? "Y" : "N"); + seq_printf(seq, "\tPMT Magic Frame: %s\n", + (priv->dma_cap.pmt_magic_frame) ? "Y" : "N"); + seq_printf(seq, "\tRMON module: %s\n", + (priv->dma_cap.rmon) ? "Y" : "N"); + seq_printf(seq, "\tIEEE 1588-2002 Time Stamp: %s\n", + (priv->dma_cap.time_stamp) ? "Y" : "N"); + seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp:%s\n", + (priv->dma_cap.atime_stamp) ? "Y" : "N"); + seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE) %s\n", + (priv->dma_cap.eee) ? "Y" : "N"); + seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N"); + seq_printf(seq, "\tChecksum Offload in TX: %s\n", + (priv->dma_cap.tx_coe) ? "Y" : "N"); + seq_printf(seq, "\tIP Checksum Offload (type1) in RX: %s\n", + (priv->dma_cap.rx_coe_type1) ? "Y" : "N"); + seq_printf(seq, "\tIP Checksum Offload (type2) in RX: %s\n", + (priv->dma_cap.rx_coe_type2) ? "Y" : "N"); + seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n", + (priv->dma_cap.rxfifo_over_2048) ? "Y" : "N"); + seq_printf(seq, "\tNumber of Additional RX channel: %d\n", + priv->dma_cap.number_rx_channel); + seq_printf(seq, "\tNumber of Additional TX channel: %d\n", + priv->dma_cap.number_tx_channel); + seq_printf(seq, "\tEnhanced descriptors: %s\n", + (priv->dma_cap.enh_desc) ? "Y" : "N"); + + return 0; +} + +static int stmmac_sysfs_dma_cap_open(struct inode *inode, struct file *file) +{ + return single_open(file, stmmac_sysfs_dma_cap_read, inode->i_private); +} + +static const struct file_operations stmmac_dma_cap_fops = { + .owner = THIS_MODULE, + .open = stmmac_sysfs_dma_cap_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static int stmmac_init_fs(struct net_device *dev) { /* Create debugfs entries */ @@ -1527,12 +1645,25 @@ static int stmmac_init_fs(struct net_device *dev) return -ENOMEM; } + /* Entry to report the DMA HW features */ + stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir, + dev, &stmmac_dma_cap_fops); + + if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) { + pr_info("ERROR creating stmmac MMC debugfs file\n"); + debugfs_remove(stmmac_rings_status); + debugfs_remove(stmmac_fs_dir); + + return -ENOMEM; + } + return 0; } static void stmmac_exit_fs(void) { debugfs_remove(stmmac_rings_status); + debugfs_remove(stmmac_dma_cap); debugfs_remove(stmmac_fs_dir); } #endif /* CONFIG_STMMAC_DEBUG_FS */ -- cgit v1.2.3 From 6096ce0b02c1cb5a5df6a726c5727c267b2468e0 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 1 Sep 2011 21:51:43 +0000 Subject: stmmac: update the driver version (Aug_2011) (v3) Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index c3a2da71d1e6..1434bdb390d4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -20,7 +20,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ -#define DRV_MODULE_VERSION "July_2011" +#define DRV_MODULE_VERSION "Aug_2011" #include #include "common.h" -- cgit v1.2.3 From a9097a9666fd7b08fd2a152b2a0b6c8d48639bb2 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Tue, 18 Oct 2011 00:01:19 +0000 Subject: stmmac: protect tx process with lock (V4) This patch fixes a problem raised on Orly ARM SMP platform where, in case of fragmented frames, the descriptors in the TX ring resulted broken. This was due to a missing lock protection in the tx process. Signed-off-by: Giuseppe Cavallaro Tested-by: Srinivas Kandagatla Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 1434bdb390d4..50e95d87857a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -70,6 +70,7 @@ struct stmmac_priv { u32 msg_enable; spinlock_t lock; + spinlock_t tx_lock; int wolopts; int wolenabled; int wol_irq; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index ae5debb1f5cd..f80190d78f90 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -588,6 +588,8 @@ static void stmmac_tx(struct stmmac_priv *priv) { unsigned int txsize = priv->dma_tx_size; + spin_lock(&priv->tx_lock); + while (priv->dirty_tx != priv->cur_tx) { int last; unsigned int entry = priv->dirty_tx % txsize; @@ -651,6 +653,7 @@ static void stmmac_tx(struct stmmac_priv *priv) } netif_tx_unlock(priv->dev); } + spin_unlock(&priv->tx_lock); } static inline void stmmac_enable_irq(struct stmmac_priv *priv) @@ -1078,6 +1081,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } + spin_lock(&priv->tx_lock); + entry = priv->cur_tx % txsize; #ifdef STMMAC_XMIT_DEBUG @@ -1166,6 +1171,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->hw->dma->enable_dma_transmission(priv->ioaddr); + spin_unlock(&priv->tx_lock); + return NETDEV_TX_OK; } @@ -1731,6 +1738,7 @@ static int stmmac_probe(struct net_device *dev) "please, use ifconfig or nwhwconfig!\n"); spin_lock_init(&priv->lock); + spin_lock_init(&priv->tx_lock); ret = register_netdev(dev); if (ret) { -- cgit v1.2.3 From 51e3137b9b6113c7e12cf0a0dc82238854a86712 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Tue, 18 Oct 2011 00:01:20 +0000 Subject: stmmac: update the driver version and doc (V4) Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- Documentation/networking/stmmac.txt | 11 ++++++++++- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index 40ec92ce4c84..8d67980fabe8 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -76,7 +76,16 @@ core. 4.5) DMA descriptors Driver handles both normal and enhanced descriptors. The latter has been only -tested on DWC Ether MAC 10/100/1000 Universal version 3.41a. +tested on DWC Ether MAC 10/100/1000 Universal version 3.41a and later. + +STMMAC supports DMA descriptor to operate both in dual buffer (RING) +and linked-list(CHAINED) mode. In RING each descriptor points to two +data buffer pointers whereas in CHAINED mode they point to only one data +buffer pointer. RING mode is the default. + +In CHAINED mode each descriptor will have pointer to next descriptor in +the list, hence creating the explicit chaining in the descriptor itself, +whereas such explicit chaining is not possible in RING mode. 4.6) Ethtool support Ethtool is supported. Driver statistics and internal errors can be taken using: diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 50e95d87857a..49a4af3ce3a8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -20,7 +20,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ -#define DRV_MODULE_VERSION "Aug_2011" +#define DRV_MODULE_VERSION "Oct_2011" #include #include "common.h" -- cgit v1.2.3 From 286a837217204b1ef105e3a554d0757e4fdfaac1 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Tue, 18 Oct 2011 00:01:24 +0000 Subject: stmmac: add CHAINED descriptor mode support (V4) This patch enhances the STMMAC driver to support CHAINED mode of descriptor. STMMAC supports DMA descriptor to operate both in dual buffer(RING) and linked-list(CHAINED) mode. In RING mode (default) each descriptor points to two data buffer pointers whereas in CHAINED mode they point to only one data buffer pointer. In CHAINED mode each descriptor will have pointer to next descriptor in the list, hence creating the explicit chaining in the descriptor itself, whereas such explicit chaining is not possible in RING mode. First version of this work has been done by Rayagond. Then the patch has been reworked avoiding ifdef inside the C code. A new header file has been added to define all the functions needed for managing enhanced and normal descriptors. In fact, these have to be specialized according to the ring/chain usage. Two new C files have been also added to implement the helper routines needed to manage: jumbo frames, chain and ring setup (i.e. desc3). Signed-off-by: Rayagond Kokatanur Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 18 +++ drivers/net/ethernet/stmicro/stmmac/Makefile | 2 + drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 137 ++++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/common.h | 13 ++ drivers/net/ethernet/stmicro/stmmac/descs_com.h | 126 ++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 22 ++-- drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 20 ++-- drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 126 ++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 130 ++++++++------------ 10 files changed, 491 insertions(+), 105 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/chain_mode.c create mode 100644 drivers/net/ethernet/stmicro/stmmac/descs_com.h create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode.c (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac.h') diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 8cd9ddec05a0..ac6f190743dd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -63,4 +63,22 @@ config STMMAC_RTC_TIMER endchoice +choice + prompt "Select the DMA TX/RX descriptor operating modes" + depends on STMMAC_ETH + ---help--- + This driver supports DMA descriptor to operate both in dual buffer + (RING) and linked-list(CHAINED) mode. In RING mode each descriptor + points to two data buffer pointers whereas in CHAINED mode they + points to only one data buffer pointer. + +config STMMAC_RING + bool "Enable Descriptor Ring Mode" + +config STMMAC_CHAINED + bool "Enable Descriptor Chained Mode" + +endchoice + + endif diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 0f23d95746b7..d7c45164ea79 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -1,5 +1,7 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o +stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o +stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.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 new file mode 100644 index 000000000000..0668659803ed --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c @@ -0,0 +1,137 @@ +/******************************************************************************* + Specialised functions for managing Chained mode + + Copyright(C) 2011 STMicroelectronics Ltd + + It defines all the functions used to handle the normal/enhanced + descriptors in case of the DMA is configured to work in chained or + in ring mode. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "stmmac.h" + +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; + unsigned int nopaged_len = skb_headlen(skb); + unsigned int bmax; + unsigned int i = 1, len; + + if (priv->plat->enh_desc) + bmax = BUF_SIZE_8KiB; + else + bmax = BUF_SIZE_2KiB; + + len = nopaged_len - bmax; + + desc->des2 = dma_map_single(priv->device, skb->data, + bmax, DMA_TO_DEVICE); + priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum); + + while (len != 0) { + entry = (++priv->cur_tx) % txsize; + desc = priv->dma_tx + entry; + + if (len > bmax) { + desc->des2 = dma_map_single(priv->device, + (skb->data + bmax * i), + bmax, DMA_TO_DEVICE); + priv->hw->desc->prepare_tx_desc(desc, 0, bmax, + csum); + priv->hw->desc->set_tx_owner(desc); + priv->tx_skbuff[entry] = NULL; + len -= bmax; + i++; + } else { + desc->des2 = dma_map_single(priv->device, + (skb->data + bmax * i), len, + DMA_TO_DEVICE); + priv->hw->desc->prepare_tx_desc(desc, 0, len, + csum); + priv->hw->desc->set_tx_owner(desc); + priv->tx_skbuff[entry] = NULL; + len = 0; + } + } + return entry; +} + +static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc) +{ + unsigned int ret = 0; + + if ((enh_desc && (len > BUF_SIZE_8KiB)) || + (!enh_desc && (len > BUF_SIZE_2KiB))) { + ret = 1; + } + + return ret; +} + +static void stmmac_refill_desc3(int bfsize, struct dma_desc *p) +{ +} + +static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p) +{ +} + +static void stmmac_clean_desc3(struct dma_desc *p) +{ +} + +static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr, + unsigned int size) +{ + /* + * In chained mode the des3 points to the next element in the ring. + * The latest element has to point to the head. + */ + int i; + struct dma_desc *p = des; + dma_addr_t dma_phy = phy_addr; + + for (i = 0; i < (size - 1); i++) { + dma_phy += sizeof(struct dma_desc); + p->des3 = (unsigned int)dma_phy; + p++; + } + p->des3 = (unsigned int)phy_addr; +} + +static int stmmac_set_16kib_bfsize(int mtu) +{ + /* Not supported */ + return 0; +} + +const struct stmmac_ring_mode_ops ring_mode_ops = { + .is_jumbo_frm = stmmac_is_jumbo_frm, + .jumbo_frm = stmmac_jumbo_frm, + .refill_desc3 = stmmac_refill_desc3, + .init_desc3 = stmmac_init_desc3, + .init_dma_chain = stmmac_init_dma_chain, + .clean_desc3 = stmmac_clean_desc3, + .set_16kib_bfsize = stmmac_set_16kib_bfsize, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index ffba0144fa38..9100c100d295 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -287,10 +287,22 @@ 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) (int bfsize, struct dma_desc *p); + void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p); + void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr, + unsigned int size); + void (*clean_desc3) (struct dma_desc *p); + int (*set_16kib_bfsize) (int mtu); +}; + 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; struct mii_regs mii; /* MII register Addresses */ struct mac_link link; unsigned int synopsys_uid; @@ -304,3 +316,4 @@ extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, unsigned int high, unsigned int low); extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); +extern const struct stmmac_ring_mode_ops ring_mode_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h new file mode 100644 index 000000000000..dd8d6e19dff6 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h @@ -0,0 +1,126 @@ +/******************************************************************************* + Header File to describe Normal/enhanced descriptor functions used for RING + and CHAINED modes. + + Copyright(C) 2011 STMicroelectronics Ltd + + It defines all the functions used to handle the normal/enhanced + descriptors in case of the DMA is configured to work in chained or + in ring mode. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#if defined(CONFIG_STMMAC_RING) +static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end) +{ + p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1; + if (end) + p->des01.erx.end_ring = 1; +} + +static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end) +{ + if (end) + p->des01.etx.end_ring = 1; +} + +static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter) +{ + p->des01.etx.end_ring = ter; +} + +static inline void enh_set_tx_desc_len(struct dma_desc *p, int len) +{ + if (unlikely(len > BUF_SIZE_4KiB)) { + p->des01.etx.buffer1_size = BUF_SIZE_4KiB; + p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB; + } else + p->des01.etx.buffer1_size = len; +} + +static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end) +{ + p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1; + if (end) + p->des01.rx.end_ring = 1; +} + +static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end) +{ + if (end) + p->des01.tx.end_ring = 1; +} + +static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter) +{ + p->des01.tx.end_ring = ter; +} + +static inline void norm_set_tx_desc_len(struct dma_desc *p, int len) +{ + if (unlikely(len > BUF_SIZE_2KiB)) { + p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1; + p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size; + } else + p->des01.tx.buffer1_size = len; +} + +#else + +static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end) +{ + p->des01.erx.second_address_chained = 1; +} + +static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end) +{ + p->des01.etx.second_address_chained = 1; +} + +static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter) +{ + p->des01.etx.second_address_chained = 1; +} + +static inline void enh_set_tx_desc_len(struct dma_desc *p, int len) +{ + p->des01.etx.buffer1_size = len; +} + +static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end) +{ + p->des01.rx.second_address_chained = 1; +} + +static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size) +{ + p->des01.tx.second_address_chained = 1; +} + +static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter) +{ + p->des01.tx.second_address_chained = 1; +} + +static inline void norm_set_tx_desc_len(struct dma_desc *p, int len) +{ + p->des01.tx.buffer1_size = len; +} +#endif diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index e5dfb6a30182..d87976364ec5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -23,6 +23,7 @@ *******************************************************************************/ #include "common.h" +#include "descs_com.h" static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr) @@ -233,10 +234,9 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size, for (i = 0; i < ring_size; i++) { p->des01.erx.own = 1; p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1; - /* To support jumbo frames */ - p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1; - if (i == ring_size - 1) - p->des01.erx.end_ring = 1; + + ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1)); + if (disable_rx_ic) p->des01.erx.disable_ic = 1; p++; @@ -249,8 +249,7 @@ static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size) for (i = 0; i < ring_size; i++) { p->des01.etx.own = 0; - if (i == ring_size - 1) - p->des01.etx.end_ring = 1; + ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1)); p++; } } @@ -285,19 +284,16 @@ static void enh_desc_release_tx_desc(struct dma_desc *p) int ter = p->des01.etx.end_ring; memset(p, 0, offsetof(struct dma_desc, des2)); - p->des01.etx.end_ring = ter; + enh_desc_end_tx_desc(p, ter); } static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, int csum_flag) { p->des01.etx.first_segment = is_fs; - if (unlikely(len > BUF_SIZE_4KiB)) { - p->des01.etx.buffer1_size = BUF_SIZE_4KiB; - p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB; - } else { - p->des01.etx.buffer1_size = len; - } + + enh_set_tx_desc_len(p, len); + if (likely(csum_flag)) p->des01.etx.checksum_insertion = cic_full; } diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c index e13226b80d47..f7e8ba7f501a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c @@ -23,6 +23,7 @@ *******************************************************************************/ #include "common.h" +#include "descs_com.h" static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr) @@ -126,9 +127,9 @@ static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size, for (i = 0; i < ring_size; i++) { p->des01.rx.own = 1; p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1; - p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1; - if (i == ring_size - 1) - p->des01.rx.end_ring = 1; + + ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1)); + if (disable_rx_ic) p->des01.rx.disable_ic = 1; p++; @@ -140,8 +141,7 @@ static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size) int i; for (i = 0; i < ring_size; i++) { p->des01.tx.own = 0; - if (i == ring_size - 1) - p->des01.tx.end_ring = 1; + ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1))); p++; } } @@ -176,20 +176,14 @@ static void ndesc_release_tx_desc(struct dma_desc *p) int ter = p->des01.tx.end_ring; memset(p, 0, offsetof(struct dma_desc, des2)); - /* set termination field */ - p->des01.tx.end_ring = ter; + ndesc_end_tx_desc(p, ter); } static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, int csum_flag) { p->des01.tx.first_segment = is_fs; - - if (unlikely(len > BUF_SIZE_2KiB)) { - p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1; - p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size; - } else - p->des01.tx.buffer1_size = len; + norm_set_tx_desc_len(p, len); } static void ndesc_clear_tx_ic(struct dma_desc *p) diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c new file mode 100644 index 000000000000..fb8377da1687 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c @@ -0,0 +1,126 @@ +/******************************************************************************* + Specialised functions for managing Ring mode + + Copyright(C) 2011 STMicroelectronics Ltd + + It defines all the functions used to handle the normal/enhanced + descriptors in case of the DMA is configured to work in chained or + in ring mode. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include "stmmac.h" + +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; + unsigned int nopaged_len = skb_headlen(skb); + unsigned int bmax, len; + + if (priv->plat->enh_desc) + bmax = BUF_SIZE_8KiB; + else + bmax = BUF_SIZE_2KiB; + + len = nopaged_len - bmax; + + if (nopaged_len > BUF_SIZE_8KiB) { + + desc->des2 = dma_map_single(priv->device, skb->data, + bmax, DMA_TO_DEVICE); + desc->des3 = desc->des2 + BUF_SIZE_4KiB; + priv->hw->desc->prepare_tx_desc(desc, 1, bmax, + csum); + + entry = (++priv->cur_tx) % txsize; + desc = priv->dma_tx + entry; + + desc->des2 = dma_map_single(priv->device, skb->data + bmax, + len, DMA_TO_DEVICE); + desc->des3 = desc->des2 + BUF_SIZE_4KiB; + priv->hw->desc->prepare_tx_desc(desc, 0, len, csum); + 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); + desc->des3 = desc->des2 + BUF_SIZE_4KiB; + priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum); + } + + return entry; +} + +static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc) +{ + unsigned int ret = 0; + + if (len >= BUF_SIZE_4KiB) + ret = 1; + + return ret; +} + +static void stmmac_refill_desc3(int bfsize, struct dma_desc *p) +{ + /* Fill DES3 in case of RING mode */ + if (bfsize >= 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 */ +static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p) +{ + if (unlikely(des3_as_data_buf)) + p->des3 = p->des2 + BUF_SIZE_8KiB; +} + +static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr, + unsigned int size) +{ +} + +static void stmmac_clean_desc3(struct dma_desc *p) +{ + if (unlikely(p->des3)) + p->des3 = 0; +} + +static int stmmac_set_16kib_bfsize(int mtu) +{ + int ret = 0; + if (unlikely(mtu >= BUF_SIZE_8KiB)) + ret = BUF_SIZE_16KiB; + return ret; +} + +const struct stmmac_ring_mode_ops ring_mode_ops = { + .is_jumbo_frm = stmmac_is_jumbo_frm, + .jumbo_frm = stmmac_jumbo_frm, + .refill_desc3 = stmmac_refill_desc3, + .init_desc3 = stmmac_init_desc3, + .init_dma_chain = stmmac_init_dma_chain, + .clean_desc3 = stmmac_clean_desc3, + .set_16kib_bfsize = stmmac_set_16kib_bfsize, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 49a4af3ce3a8..9bafa6cf9e8b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -22,7 +22,7 @@ #define DRV_MODULE_VERSION "Oct_2011" #include - +#include #include "common.h" #ifdef CONFIG_STMMAC_TIMER #include "stmmac_timer.h" diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index bf895cb75785..5eccd996cde0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2,7 +2,7 @@ This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers. ST Ethernet IPs are built around a Synopsys IP Core. - Copyright (C) 2007-2009 STMicroelectronics Ltd + Copyright(C) 2007-2011 STMicroelectronics Ltd This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -41,17 +41,16 @@ #include #include #include -#include #include #include #include #include #include -#include "stmmac.h" #ifdef CONFIG_STMMAC_DEBUG_FS #include #include #endif +#include "stmmac.h" #define STMMAC_RESOURCE_NAME "stmmaceth" @@ -388,11 +387,28 @@ static void display_ring(struct dma_desc *p, int size) } } +static int stmmac_set_bfsize(int mtu, int bufsize) +{ + int ret = bufsize; + + if (mtu >= BUF_SIZE_4KiB) + ret = BUF_SIZE_8KiB; + else if (mtu >= BUF_SIZE_2KiB) + ret = BUF_SIZE_4KiB; + else if (mtu >= DMA_BUFFER_SIZE) + ret = BUF_SIZE_2KiB; + else + ret = DMA_BUFFER_SIZE; + + return ret; +} + /** * init_dma_desc_rings - init the RX/TX descriptor rings * @dev: net device structure * Description: this function initializes the DMA RX/TX descriptors - * and allocates the socket buffers. + * and allocates the socket buffers. It suppors the chained and ring + * modes. */ static void init_dma_desc_rings(struct net_device *dev) { @@ -401,31 +417,24 @@ static void init_dma_desc_rings(struct net_device *dev) struct sk_buff *skb; unsigned int txsize = priv->dma_tx_size; unsigned int rxsize = priv->dma_rx_size; - unsigned int bfsize = priv->dma_buf_sz; - int buff2_needed = 0, dis_ic = 0; + unsigned int bfsize; + int dis_ic = 0; + int des3_as_data_buf = 0; - /* Set the Buffer size according to the MTU; - * indeed, in case of jumbo we need to bump-up the buffer sizes. - */ - if (unlikely(dev->mtu >= BUF_SIZE_8KiB)) - bfsize = BUF_SIZE_16KiB; - else if (unlikely(dev->mtu >= BUF_SIZE_4KiB)) - bfsize = BUF_SIZE_8KiB; - else if (unlikely(dev->mtu >= BUF_SIZE_2KiB)) - bfsize = BUF_SIZE_4KiB; - else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE)) - bfsize = BUF_SIZE_2KiB; + /* Set the max buffer size according to the DESC mode + * and the MTU. Note that RING mode allows 16KiB bsize. */ + bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu); + + if (bfsize == BUF_SIZE_16KiB) + des3_as_data_buf = 1; else - bfsize = DMA_BUFFER_SIZE; + bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz); #ifdef CONFIG_STMMAC_TIMER /* Disable interrupts on completion for the reception if timer is on */ if (likely(priv->tm->enable)) dis_ic = 1; #endif - /* If the MTU exceeds 8k so use the second buffer in the chain */ - if (bfsize >= BUF_SIZE_8KiB) - buff2_needed = 1; DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n", txsize, rxsize, bfsize); @@ -453,7 +462,7 @@ static void init_dma_desc_rings(struct net_device *dev) return; } - DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, " + DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, " "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n", dev->name, priv->dma_rx, priv->dma_tx, (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy); @@ -475,8 +484,9 @@ static void init_dma_desc_rings(struct net_device *dev) bfsize, DMA_FROM_DEVICE); p->des2 = priv->rx_skbuff_dma[i]; - if (unlikely(buff2_needed)) - p->des3 = p->des2 + BUF_SIZE_8KiB; + + priv->hw->ring->init_desc3(des3_as_data_buf, p); + DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]); } @@ -490,6 +500,12 @@ static void init_dma_desc_rings(struct net_device *dev) priv->tx_skbuff[i] = NULL; priv->dma_tx[i].des2 = 0; } + + /* In case of Chained mode this sets the des3 to the next + * element in the chain */ + priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize); + priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize); + priv->dirty_tx = 0; priv->cur_tx = 0; @@ -620,8 +636,7 @@ static void stmmac_tx(struct stmmac_priv *priv) dma_unmap_single(priv->device, p->des2, priv->hw->desc->get_tx_len(p), DMA_TO_DEVICE); - if (unlikely(p->des3)) - p->des3 = 0; + priv->hw->ring->clean_desc3(p); if (likely(skb != NULL)) { /* @@ -728,7 +743,6 @@ static void stmmac_no_timer_stopped(void) */ static void stmmac_tx_err(struct stmmac_priv *priv) { - netif_stop_queue(priv->dev); priv->hw->dma->stop_tx(priv->ioaddr); @@ -1028,47 +1042,6 @@ static int stmmac_release(struct net_device *dev) return 0; } -static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, - struct net_device *dev, - int csum_insertion) -{ - struct stmmac_priv *priv = netdev_priv(dev); - unsigned int nopaged_len = skb_headlen(skb); - unsigned int txsize = priv->dma_tx_size; - unsigned int entry = priv->cur_tx % txsize; - struct dma_desc *desc = priv->dma_tx + entry; - - if (nopaged_len > BUF_SIZE_8KiB) { - - int buf2_size = nopaged_len - BUF_SIZE_8KiB; - - desc->des2 = dma_map_single(priv->device, skb->data, - BUF_SIZE_8KiB, DMA_TO_DEVICE); - desc->des3 = desc->des2 + BUF_SIZE_4KiB; - priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB, - csum_insertion); - - entry = (++priv->cur_tx) % txsize; - desc = priv->dma_tx + entry; - - desc->des2 = dma_map_single(priv->device, - skb->data + BUF_SIZE_8KiB, - buf2_size, DMA_TO_DEVICE); - desc->des3 = desc->des2 + BUF_SIZE_4KiB; - priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size, - csum_insertion); - 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); - desc->des3 = desc->des2 + BUF_SIZE_4KiB; - priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, - csum_insertion); - } - return entry; -} - /** * stmmac_xmit: * @skb : the socket buffer @@ -1083,6 +1056,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) int i, csum_insertion = 0; int nfrags = skb_shinfo(skb)->nr_frags; struct dma_desc *desc, *first; + unsigned int nopaged_len = skb_headlen(skb); if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) { if (!netif_queue_stopped(dev)) { @@ -1103,7 +1077,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) pr_info("stmmac xmit:\n" "\tskb addr %p - len: %d - nopaged_len: %d\n" "\tn_frags: %d - ip_summed: %d - %s gso\n", - skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed, + skb, skb->len, nopaged_len, nfrags, skb->ip_summed, !skb_is_gso(skb) ? "isn't" : "is"); #endif @@ -1116,14 +1090,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n" "\t\tn_frags: %d, ip_summed: %d\n", - skb->len, skb_headlen(skb), nfrags, skb->ip_summed); + skb->len, nopaged_len, nfrags, skb->ip_summed); #endif priv->tx_skbuff[entry] = skb; - if (unlikely(skb->len >= BUF_SIZE_4KiB)) { - entry = stmmac_handle_jumbo_frames(skb, dev, csum_insertion); + + if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) { + entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion); desc = priv->dma_tx + entry; } else { - unsigned int nopaged_len = skb_headlen(skb); desc->des2 = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE); priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, @@ -1214,11 +1188,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv) DMA_FROM_DEVICE); (p + entry)->des2 = priv->rx_skbuff_dma[entry]; - if (unlikely(priv->plat->has_gmac)) { - if (bfsize >= BUF_SIZE_8KiB) - (p + entry)->des3 = - (p + entry)->des2 + BUF_SIZE_8KiB; - } + + if (unlikely(priv->plat->has_gmac)) + priv->hw->ring->refill_desc3(bfsize, p + entry); + RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); } wmb(); @@ -1795,6 +1768,7 @@ static int stmmac_mac_device_setup(struct net_device *dev) device->desc = &ndesc_ops; priv->hw = device; + priv->hw->ring = &ring_mode_ops; if (device_can_wakeup(priv->device)) { priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ -- cgit v1.2.3