From 7ac6653a085b41405758bc16b2525db56ee0a23f Mon Sep 17 00:00:00 2001 From: Jeff Kirsher <jeffrey.t.kirsher@intel.com> 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 <peppe.cavallaro@st.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> --- .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 359 +++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c new file mode 100644 index 000000000000..7ed8fb6c2117 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -0,0 +1,359 @@ +/******************************************************************************* + STMMAC Ethtool support + + 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 <peppe.cavallaro@st.com> +*******************************************************************************/ + +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/interrupt.h> +#include <linux/mii.h> +#include <linux/phy.h> +#include <asm/io.h> + +#include "stmmac.h" +#include "dwmac_dma.h" + +#define REG_SPACE_SIZE 0x1054 +#define MAC100_ETHTOOL_NAME "st_mac100" +#define GMAC_ETHTOOL_NAME "st_gmac" + +struct stmmac_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define STMMAC_STAT(m) \ + { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ + offsetof(struct stmmac_priv, xstats.m)} + +static const struct stmmac_stats stmmac_gstrings_stats[] = { + STMMAC_STAT(tx_underflow), + STMMAC_STAT(tx_carrier), + STMMAC_STAT(tx_losscarrier), + STMMAC_STAT(tx_heartbeat), + STMMAC_STAT(tx_deferred), + STMMAC_STAT(tx_vlan), + STMMAC_STAT(rx_vlan), + STMMAC_STAT(tx_jabber), + STMMAC_STAT(tx_frame_flushed), + STMMAC_STAT(tx_payload_error), + STMMAC_STAT(tx_ip_header_error), + STMMAC_STAT(rx_desc), + STMMAC_STAT(rx_partial), + STMMAC_STAT(rx_runt), + STMMAC_STAT(rx_toolong), + STMMAC_STAT(rx_collision), + STMMAC_STAT(rx_crc), + STMMAC_STAT(rx_length), + STMMAC_STAT(rx_mii), + STMMAC_STAT(rx_multicast), + STMMAC_STAT(rx_gmac_overflow), + STMMAC_STAT(rx_watchdog), + STMMAC_STAT(da_rx_filter_fail), + STMMAC_STAT(sa_rx_filter_fail), + STMMAC_STAT(rx_missed_cntr), + STMMAC_STAT(rx_overflow_cntr), + STMMAC_STAT(tx_undeflow_irq), + STMMAC_STAT(tx_process_stopped_irq), + STMMAC_STAT(tx_jabber_irq), + STMMAC_STAT(rx_overflow_irq), + STMMAC_STAT(rx_buf_unav_irq), + STMMAC_STAT(rx_process_stopped_irq), + STMMAC_STAT(rx_watchdog_irq), + STMMAC_STAT(tx_early_irq), + STMMAC_STAT(fatal_bus_error_irq), + STMMAC_STAT(threshold), + STMMAC_STAT(tx_pkt_n), + STMMAC_STAT(rx_pkt_n), + STMMAC_STAT(poll_n), + STMMAC_STAT(sched_timer_n), + STMMAC_STAT(normal_irq_n), +}; +#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) + +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 + strcpy(info->driver, GMAC_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, + struct ethtool_cmd *cmd) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phy = priv->phydev; + int rc; + if (phy == NULL) { + pr_err("%s: %s: PHY is not registered\n", + __func__, dev->name); + return -ENODEV; + } + if (!netif_running(dev)) { + pr_err("%s: interface is disabled: we cannot track " + "link speed / duplex setting\n", dev->name); + return -EBUSY; + } + cmd->transceiver = XCVR_INTERNAL; + spin_lock_irq(&priv->lock); + rc = phy_ethtool_gset(phy, cmd); + spin_unlock_irq(&priv->lock); + return rc; +} + +static int stmmac_ethtool_setsettings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phy = priv->phydev; + int rc; + + spin_lock(&priv->lock); + rc = phy_ethtool_sset(phy, cmd); + spin_unlock(&priv->lock); + + return rc; +} + +static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + return priv->msg_enable; +} + +static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level) +{ + struct stmmac_priv *priv = netdev_priv(dev); + priv->msg_enable = level; + +} + +static int stmmac_check_if_running(struct net_device *dev) +{ + if (!netif_running(dev)) + return -EBUSY; + return 0; +} + +static int stmmac_ethtool_get_regs_len(struct net_device *dev) +{ + return REG_SPACE_SIZE; +} + +static void stmmac_ethtool_gregs(struct net_device *dev, + struct ethtool_regs *regs, void *space) +{ + int i; + u32 *reg_space = (u32 *) space; + + struct stmmac_priv *priv = netdev_priv(dev); + + memset(reg_space, 0x0, REG_SPACE_SIZE); + + if (!priv->plat->has_gmac) { + /* MAC registers */ + for (i = 0; i < 12; i++) + reg_space[i] = readl(priv->ioaddr + (i * 4)); + /* DMA registers */ + for (i = 0; i < 9; i++) + reg_space[i + 12] = + readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4))); + reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR); + reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR); + } else { + /* MAC registers */ + for (i = 0; i < 55; i++) + reg_space[i] = readl(priv->ioaddr + (i * 4)); + /* DMA registers */ + for (i = 0; i < 22; i++) + reg_space[i + 55] = + readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4))); + } +} + +static void +stmmac_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct stmmac_priv *priv = netdev_priv(netdev); + + spin_lock(&priv->lock); + + pause->rx_pause = 0; + pause->tx_pause = 0; + pause->autoneg = priv->phydev->autoneg; + + if (priv->flow_ctrl & FLOW_RX) + pause->rx_pause = 1; + if (priv->flow_ctrl & FLOW_TX) + pause->tx_pause = 1; + + spin_unlock(&priv->lock); +} + +static int +stmmac_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct stmmac_priv *priv = netdev_priv(netdev); + struct phy_device *phy = priv->phydev; + int new_pause = FLOW_OFF; + int ret = 0; + + spin_lock(&priv->lock); + + if (pause->rx_pause) + new_pause |= FLOW_RX; + if (pause->tx_pause) + new_pause |= FLOW_TX; + + priv->flow_ctrl = new_pause; + phy->autoneg = pause->autoneg; + + if (phy->autoneg) { + if (netif_running(netdev)) + ret = phy_start_aneg(phy); + } else + priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, + priv->flow_ctrl, priv->pause); + spin_unlock(&priv->lock); + return ret; +} + +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); + + 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); + } +} + +static int stmmac_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return STMMAC_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + int i; + u8 *p = data; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < STMMAC_STATS_LEN; i++) { + memcpy(p, stmmac_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + default: + WARN_ON(1); + break; + } +} + +/* Currently only support WOL through Magic packet. */ +static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + spin_lock_irq(&priv->lock); + if (device_can_wakeup(priv->device)) { + wol->supported = WAKE_MAGIC | WAKE_UCAST; + wol->wolopts = priv->wolopts; + } + spin_unlock_irq(&priv->lock); +} + +static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct stmmac_priv *priv = netdev_priv(dev); + u32 support = WAKE_MAGIC | WAKE_UCAST; + + if (!device_can_wakeup(priv->device)) + return -EINVAL; + + if (wol->wolopts & ~support) + return -EINVAL; + + if (wol->wolopts) { + pr_info("stmmac: wakeup enable\n"); + device_set_wakeup_enable(priv->device, 1); + enable_irq_wake(dev->irq); + } else { + device_set_wakeup_enable(priv->device, 0); + disable_irq_wake(dev->irq); + } + + spin_lock_irq(&priv->lock); + priv->wolopts = wol->wolopts; + spin_unlock_irq(&priv->lock); + + return 0; +} + +static struct ethtool_ops stmmac_ethtool_ops = { + .begin = stmmac_check_if_running, + .get_drvinfo = stmmac_ethtool_getdrvinfo, + .get_settings = stmmac_ethtool_getsettings, + .set_settings = stmmac_ethtool_setsettings, + .get_msglevel = stmmac_ethtool_getmsglevel, + .set_msglevel = stmmac_ethtool_setmsglevel, + .get_regs = stmmac_ethtool_gregs, + .get_regs_len = stmmac_ethtool_get_regs_len, + .get_link = ethtool_op_get_link, + .get_pauseparam = stmmac_get_pauseparam, + .set_pauseparam = stmmac_set_pauseparam, + .get_ethtool_stats = stmmac_get_ethtool_stats, + .get_strings = stmmac_get_strings, + .get_wol = stmmac_get_wol, + .set_wol = stmmac_set_wol, + .get_sset_count = stmmac_get_sset_count, +}; + +void stmmac_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops); +} -- cgit v1.2.3 From 3172d3afa998ffb8f1971746ca960cbe98d62444 Mon Sep 17 00:00:00 2001 From: Deepak Sikri <deepak.sikri@st.com> 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 <deepak.sikri@st.com> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- 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_ethtool.c') 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 <peppe.cavallaro@st.com> 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 <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- 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_ethtool.c') 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 <peppe.cavallaro@st.com> +*******************************************************************************/ + +/* 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 <peppe.cavallaro@st.com> +*******************************************************************************/ + +#include <linux/io.h> +#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 38fe7a93fc734357c4811f1c710b1906a87d315c Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO <peppe.cavallaro@st.com> Date: Tue, 18 Oct 2011 00:01:23 +0000 Subject: stmmac: allow mmc usage only if feature actually available (V4) Enable the MMC support if it is actually available from the HW capability register. Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 24 +++++++++++++--------- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index aedff9a90ebc..406404f6e321 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -96,7 +96,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { { #m, FIELD_SIZEOF(struct stmmac_counters, m), \ offsetof(struct stmmac_priv, mmc.m)} -static const struct stmmac_stats stmmac_gstr_mmc[] = { +static const struct stmmac_stats stmmac_mmc[] = { STMMAC_MMC_STAT(mmc_tx_octetcount_gb), STMMAC_MMC_STAT(mmc_tx_framecount_gb), STMMAC_MMC_STAT(mmc_tx_broadcastframe_g), @@ -177,7 +177,7 @@ static const struct stmmac_stats stmmac_gstr_mmc[] = { 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) +#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc) static void stmmac_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -348,13 +348,17 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, priv->ioaddr); else { /* If supported, for new GMAC chips expose the MMC counters */ - dwmac_mmc_read(priv->ioaddr, &priv->mmc); + if (priv->dma_cap.rmon) { + 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; + for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { + char *p; + p = (char *)priv + stmmac_mmc[i].stat_offset; - data[j++] = (stmmac_gstr_mmc[i].sizeof_stat == - sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); + data[j++] = (stmmac_mmc[i].sizeof_stat == + sizeof(u64)) ? (*(u64 *)p) : + (*(u32 *)p); + } } } for (i = 0; i < STMMAC_STATS_LEN; i++) { @@ -373,7 +377,7 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset) case ETH_SS_STATS: len = STMMAC_STATS_LEN; - if (priv->plat->has_gmac) + if (priv->dma_cap.rmon) len += STMMAC_MMC_STATS_LEN; return len; @@ -390,9 +394,9 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: - if (priv->plat->has_gmac) + if (priv->dma_cap.rmon) for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { - memcpy(p, stmmac_gstr_mmc[i].stat_string, + memcpy(p, stmmac_mmc[i].stat_string, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c88dc358f9b0..bf895cb75785 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -946,7 +946,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); + if (priv->dma_cap.rmon) + stmmac_mmc_setup(priv); /* Start the ball rolling... */ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); -- cgit v1.2.3 From 3c20f72f9108b2fcf30ec63d8a4203736c01ccd0 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO <peppe.cavallaro@st.com> Date: Wed, 26 Oct 2011 19:43:09 +0000 Subject: stmmac: update normal descriptor structure (v2) This patch updates the normal descriptor structure to work fine on new GMAC Synopsys chips. Normal descriptors were designed on the old MAC10/100 databook 1.91 where some bits were reserved: for example the tx checksum insertion and rx checksum offload. The patch maintains the back-compatibility with old MAC devices (tested on STx7109 MAC10/100) and adds new fields that actually new GMAC devices can use. For example, STx7109 (MAC10/100) will pass from the platform tx_coe = 0, enh_desc = 0, has_gmac = 0. A platform like Loongson1B (GMAC) will pass: tx_coe = 1, enh_desc = 0, has_gmac = 1. Thanks to Kelvin, he enhanced the normal descriptors for GMAC (on MIPS Loongson1B platform). Signed-off-by: Kelvin Cheung <keguang.zhang@gmail.com> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ethernet/stmicro/stmmac/common.h | 8 ++--- drivers/net/ethernet/stmicro/stmmac/descs.h | 31 ++++++++++-------- drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 38 ++++++++++++---------- .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 8 ++--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++-- 5 files changed, 51 insertions(+), 40 deletions(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c') diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 9100c100d295..2cc119295821 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -49,7 +49,7 @@ struct stmmac_extra_stats { unsigned long tx_underflow ____cacheline_aligned; unsigned long tx_carrier; unsigned long tx_losscarrier; - unsigned long tx_heartbeat; + unsigned long vlan_tag; unsigned long tx_deferred; unsigned long tx_vlan; unsigned long tx_jabber; @@ -58,9 +58,9 @@ struct stmmac_extra_stats { unsigned long tx_ip_header_error; /* Receive errors */ unsigned long rx_desc; - unsigned long rx_partial; - unsigned long rx_runt; - unsigned long rx_toolong; + unsigned long sa_filter_fail; + unsigned long overflow_error; + unsigned long ipc_csum_error; unsigned long rx_collision; unsigned long rx_crc; unsigned long rx_length; diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h index 63a03e264694..9820ec842cc0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/descs.h +++ b/drivers/net/ethernet/stmicro/stmmac/descs.h @@ -25,33 +25,34 @@ struct dma_desc { union { struct { /* RDES0 */ - u32 reserved1:1; + u32 payload_csum_error:1; u32 crc_error:1; u32 dribbling:1; u32 mii_error:1; u32 receive_watchdog:1; u32 frame_type:1; u32 collision:1; - u32 frame_too_long:1; + u32 ipc_csum_error:1; u32 last_descriptor:1; u32 first_descriptor:1; - u32 multicast_frame:1; - u32 run_frame:1; + u32 vlan_tag:1; + u32 overflow_error:1; u32 length_error:1; - u32 partial_frame_error:1; + u32 sa_filter_fail:1; u32 descriptor_error:1; u32 error_summary:1; u32 frame_length:14; - u32 filtering_fail:1; + u32 da_filter_fail:1; u32 own:1; /* RDES1 */ u32 buffer1_size:11; u32 buffer2_size:11; - u32 reserved2:2; + u32 reserved1:2; u32 second_address_chained:1; u32 end_ring:1; - u32 reserved3:5; + u32 reserved2:5; u32 disable_ic:1; + } rx; struct { /* RDES0 */ @@ -91,24 +92,28 @@ struct dma_desc { u32 underflow_error:1; u32 excessive_deferral:1; u32 collision_count:4; - u32 heartbeat_fail:1; + u32 vlan_frame:1; u32 excessive_collisions:1; u32 late_collision:1; u32 no_carrier:1; u32 loss_carrier:1; - u32 reserved1:3; + u32 payload_error:1; + u32 frame_flushed:1; + u32 jabber_timeout:1; u32 error_summary:1; - u32 reserved2:15; + u32 ip_header_error:1; + u32 time_stamp_status:1; + u32 reserved1:13; u32 own:1; /* TDES1 */ u32 buffer1_size:11; u32 buffer2_size:11; - u32 reserved3:1; + u32 time_stamp_enable:1; u32 disable_padding:1; u32 second_address_chained:1; u32 end_ring:1; u32 crc_disable:1; - u32 reserved4:2; + u32 checksum_insertion:2; u32 first_segment:1; u32 last_segment:1; u32 interrupt:1; diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c index f7e8ba7f501a..fda5d2b31d3a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c @@ -50,11 +50,12 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, stats->collisions += p->des01.tx.collision_count; ret = -1; } - if (unlikely(p->des01.tx.heartbeat_fail)) { - x->tx_heartbeat++; - stats->tx_heartbeat_errors++; - ret = -1; + + if (p->des01.etx.vlan_frame) { + CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n"); + x->tx_vlan++; } + if (unlikely(p->des01.tx.deferred)) x->tx_deferred++; @@ -68,12 +69,12 @@ static int ndesc_get_tx_len(struct dma_desc *p) /* This function verifies if each incoming frame has some errors * and, if required, updates the multicast statistics. - * In case of success, it returns csum_none because the device - * is not able to compute the csum in HW. */ + * In case of success, it returns good_frame because the GMAC device + * is supposed to be able to compute the csum in HW. */ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, struct dma_desc *p) { - int ret = csum_none; + int ret = good_frame; struct net_device_stats *stats = (struct net_device_stats *)data; if (unlikely(p->des01.rx.last_descriptor == 0)) { @@ -86,12 +87,12 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, if (unlikely(p->des01.rx.error_summary)) { if (unlikely(p->des01.rx.descriptor_error)) x->rx_desc++; - if (unlikely(p->des01.rx.partial_frame_error)) - x->rx_partial++; - if (unlikely(p->des01.rx.run_frame)) - x->rx_runt++; - if (unlikely(p->des01.rx.frame_too_long)) - x->rx_toolong++; + if (unlikely(p->des01.rx.sa_filter_fail)) + x->sa_filter_fail++; + if (unlikely(p->des01.rx.overflow_error)) + x->overflow_error++; + if (unlikely(p->des01.rx.ipc_csum_error)) + x->ipc_csum_error++; if (unlikely(p->des01.rx.collision)) { x->rx_collision++; stats->collisions++; @@ -113,10 +114,10 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, x->rx_mii++; ret = discard_frame; } - if (p->des01.rx.multicast_frame) { - x->rx_multicast++; - stats->multicast++; - } +#ifdef STMMAC_VLAN_TAG_USED + if (p->des01.rx.vlan_tag) + x->vlan_tag++; +#endif return ret; } @@ -184,6 +185,9 @@ static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, { p->des01.tx.first_segment = is_fs; norm_set_tx_desc_len(p, len); + + if (likely(csum_flag)) + p->des01.tx.checksum_insertion = cic_full; } static void ndesc_clear_tx_ic(struct dma_desc *p) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 406404f6e321..e8eff09bbbd7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -50,7 +50,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { STMMAC_STAT(tx_underflow), STMMAC_STAT(tx_carrier), STMMAC_STAT(tx_losscarrier), - STMMAC_STAT(tx_heartbeat), + STMMAC_STAT(vlan_tag), STMMAC_STAT(tx_deferred), STMMAC_STAT(tx_vlan), STMMAC_STAT(rx_vlan), @@ -59,9 +59,9 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { STMMAC_STAT(tx_payload_error), STMMAC_STAT(tx_ip_header_error), STMMAC_STAT(rx_desc), - STMMAC_STAT(rx_partial), - STMMAC_STAT(rx_runt), - STMMAC_STAT(rx_toolong), + STMMAC_STAT(sa_filter_fail), + STMMAC_STAT(overflow_error), + STMMAC_STAT(ipc_csum_error), STMMAC_STAT(rx_collision), STMMAC_STAT(rx_crc), STMMAC_STAT(rx_length), diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 003ab56f49b6..20546bbbb8db 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -813,6 +813,7 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) static int stmmac_get_hw_features(struct stmmac_priv *priv) { u32 hw_cap = 0; + if (priv->hw->dma->get_hw_feature) { hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr); @@ -938,6 +939,7 @@ static int stmmac_open(struct net_device *dev) stmmac_get_hw_features(priv); + priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); if (priv->rx_coe) pr_info("stmmac: Rx Checksum Offload Engine supported\n"); if (priv->plat->tx_coe) @@ -1275,8 +1277,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) #endif skb->protocol = eth_type_trans(skb, priv->dev); - if (unlikely(status == csum_none)) { - /* always for the old mac 10/100 */ + if (unlikely(!priv->rx_coe)) { + /* No RX COE for old mac10/100 devices */ skb_checksum_none_assert(skb); netif_receive_skb(skb); } else { -- cgit v1.2.3 From 19e30c14371f7afd38d1d35a693b96423a4db144 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO <peppe.cavallaro@st.com> Date: Wed, 16 Nov 2011 21:58:00 +0000 Subject: stmmac: parameters auto-tuning through HW cap reg New GMAC devices (newer than the databook 3.50a) have the HW capability register that provides which features are actually supported by the hardware. On old devices many information have to be passed through the platform, for example: enhanced descriptor structure, TX COE etc. These are mandatory to properly configure the driver. This remains still valid because the driver has to support old Synopsys devices but now it's also able to override them using the values from the HW capability register if supported. Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 6 ++ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 93 +++++++++++++++------- 3 files changed, 72 insertions(+), 29 deletions(-) (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 9bafa6cf9e8b..a140a8fbf051 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -72,7 +72,6 @@ struct stmmac_priv { spinlock_t lock; spinlock_t tx_lock; int wolopts; - int wolenabled; int wol_irq; #ifdef CONFIG_STMMAC_TIMER struct stmmac_timer *tm; @@ -80,6 +79,7 @@ struct stmmac_priv { struct plat_stmmacenet_data *plat; struct stmmac_counters mmc; struct dma_features dma_cap; + int hw_cap_support; }; 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 e8eff09bbbd7..0395f9eba801 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -430,6 +430,12 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct stmmac_priv *priv = netdev_priv(dev); u32 support = WAKE_MAGIC | WAKE_UCAST; + /* By default almost all GMAC devices support the WoL via + * magic frame but we can disable it if the HW capability + * register shows no support for pmt_magic_frame. */ + if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) + wol->wolopts &= ~WAKE_MAGIC; + if (!device_can_wakeup(priv->device)) return -EINVAL; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e079762a796e..7f3ffd3742d8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -805,8 +805,29 @@ 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. +/** + * stmmac_selec_desc_mode + * @dev : device pointer + * Description: select the Enhanced/Alternate or Normal descriptors */ +static void stmmac_selec_desc_mode(struct stmmac_priv *priv) +{ + if (priv->plat->enh_desc) { + pr_info(" Enhanced/Alternate descriptors\n"); + priv->hw->desc = &enh_desc_ops; + } else { + pr_info(" Normal descriptors\n"); + priv->hw->desc = &ndesc_ops; + } +} + +/** + * stmmac_get_hw_features + * @priv : private device pointer + * Description: + * new GMAC chip generations have a new register to indicate the + * presence of the optional feature/functions. + * This can be also used to override the value passed through the + * platform and necessary for old MAC10/100 and GMAC chips. */ static int stmmac_get_hw_features(struct stmmac_priv *priv) { @@ -827,7 +848,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9; priv->dma_cap.pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10; - /*MMC*/ + /* MMC */ priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11; /* IEEE 1588-2002*/ priv->dma_cap.time_stamp = @@ -855,8 +876,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) priv->dma_cap.enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24; - } else - pr_debug("\tNo HW DMA feature register supported"); + } return hw_cap; } @@ -911,6 +931,44 @@ static int stmmac_open(struct net_device *dev) goto open_error; } + stmmac_get_synopsys_id(priv); + + priv->hw_cap_support = stmmac_get_hw_features(priv); + + if (priv->hw_cap_support) { + pr_info(" Support DMA HW capability register"); + + /* We can override some gmac/dma configuration fields: e.g. + * enh_desc, tx_coe (e.g. that are passed through the + * platform) with the values from the HW capability + * register (if supported). + */ + priv->plat->enh_desc = priv->dma_cap.enh_desc; + priv->plat->tx_coe = priv->dma_cap.tx_coe; + priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; + + /* By default disable wol on magic frame if not supported */ + if (!priv->dma_cap.pmt_magic_frame) + priv->wolopts &= ~WAKE_MAGIC; + + } else + pr_info(" No HW DMA feature register supported"); + + /* Select the enhnaced/normal descriptor structures */ + stmmac_selec_desc_mode(priv); + + /* PMT module is not integrated in all the MAC devices. */ + if (priv->plat->pmt) { + pr_info(" Remote wake-up capable\n"); + device_set_wakeup_capable(priv->device, 1); + } + + priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); + if (priv->rx_coe) + pr_info(" Checksum Offload Engine supported\n"); + if (priv->plat->tx_coe) + pr_info(" Checksum insertion supported\n"); + /* Create and initialize the TX/RX descriptors chains. */ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); @@ -933,15 +991,6 @@ static int stmmac_open(struct net_device *dev) /* Initialize the MAC Core */ priv->hw->mac->core_init(priv->ioaddr); - stmmac_get_synopsys_id(priv); - - stmmac_get_hw_features(priv); - - priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); - if (priv->rx_coe) - pr_info("stmmac: Rx Checksum Offload Engine supported\n"); - if (priv->plat->tx_coe) - pr_info("\tTX Checksum insertion supported\n"); netdev_update_features(dev); /* Request the IRQ lines */ @@ -1556,7 +1605,7 @@ 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)) { + if (!priv->hw_cap_support) { seq_printf(seq, "DMA HW features not supported\n"); return 0; } @@ -1764,12 +1813,6 @@ static int stmmac_mac_device_setup(struct net_device *dev) if (!device) return -ENOMEM; - if (priv->plat->enh_desc) { - device->desc = &enh_desc_ops; - pr_info("\tEnhanced descriptor structure\n"); - } else - device->desc = &ndesc_ops; - priv->hw = device; priv->hw->ring = &ring_mode_ops; @@ -1843,11 +1886,6 @@ static int stmmac_dvr_probe(struct platform_device *pdev) priv->ioaddr = addr; - /* PMT module is not integrated in all the MAC devices. */ - if (plat_dat->pmt) { - 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 @@ -1860,7 +1898,6 @@ static int stmmac_dvr_probe(struct platform_device *pdev) if (priv->wol_irq == -ENXIO) priv->wol_irq = ndev->irq; - platform_set_drvdata(pdev, ndev); /* Set the I/O base addr */ @@ -1873,7 +1910,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev) goto out_free_ndev; } - /* MAC HW revice detection */ + /* MAC HW device detection */ ret = stmmac_mac_device_setup(ndev); if (ret < 0) goto out_plat_exit; -- cgit v1.2.3