From patchwork Sat Dec 21 03:42:56 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iyappan Subramanian X-Patchwork-Id: 3393081 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 286A1C0D4A for ; Sat, 21 Dec 2013 03:46:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D378220719 for ; Sat, 21 Dec 2013 03:46:16 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 33A8220718 for ; Sat, 21 Dec 2013 03:46:15 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VuDUj-0005sg-4N; Sat, 21 Dec 2013 03:44:53 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VuDUN-0005dD-Cg; Sat, 21 Dec 2013 03:44:31 +0000 Received: from exprod5og113.obsmtp.com ([64.18.0.26]) by merlin.infradead.org with smtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VuDTa-0005Zm-TX for linux-arm-kernel@lists.infradead.org; Sat, 21 Dec 2013 03:44:04 +0000 Received: from mail-pa0-f42.google.com ([209.85.220.42]) (using TLSv1) by exprod5ob113.postini.com ([64.18.4.12]) with SMTP ID DSNKUrUOWbW/QeQn/nKvWc7yxwr18lW1I1vw@postini.com; Fri, 20 Dec 2013 19:43:42 PST Received: by mail-pa0-f42.google.com with SMTP id lj1so3423431pab.29 for ; Fri, 20 Dec 2013 19:43:21 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uG/caoZPl4Ss08EEBO01h3OnI3oI8jLYGbZzSOuGy+s=; b=b426P7xk7XLIuU8wqZH+2AMxxIhQ8B9YYmCEm3wZ0fn3H3LkOzfEVNrB6ksYGQTh7+ IAso3qnTaBOakhLiG8boRFo/lPKXTVWivnU1ZHwIaf4uNPGz9Ca8NZgJ0O2ioz7+Ic5P o/mvp6cX++EHw1hKLPXYrQJAlDjZWNoCtV2FkJkKC/Lxs09+rGiM9uEdKyIMd9weDlw4 vCjlKNqv8zN+Xvf/hUwNdVlQ0sLxHxNLXBv42UXbbwwAgoxRe4bJ/fVaFiTTriRJUgZ0 X5MC4Etviz++d07/FS4VNPSQSWj6GEv9uFmfz8+Tqh4bn9OFD1jdLNt/vIBuJ75RoT3L c3RA== X-Gm-Message-State: ALoCoQkUqsdr5DF1E/fq5g+9z2j/Ocgym5Cs4gnNd9Y80KW9+/ERRK+5E0Hq7magavBz/rXoUHUt4a97KdAyeYUGyz/f6rqv4yalHIusY2o0mNYqLPvHe1L3RIEYGCvno4OewpRVlM5JLsl1YqHT+gd97mrBOhU+a2N81AFeMl2r0+dLQz8rFNeBrPJfB/CDqvMuPyftAZj4 X-Received: by 10.68.111.33 with SMTP id if1mr12754366pbb.31.1387597401378; Fri, 20 Dec 2013 19:43:21 -0800 (PST) X-Received: by 10.68.111.33 with SMTP id if1mr12754354pbb.31.1387597401296; Fri, 20 Dec 2013 19:43:21 -0800 (PST) Received: from amcclab-Precision-WorkStation-T3400.amcc.com (63-147-59-2.dia.static.qwest.net. [63.147.59.2]) by mx.google.com with ESMTPSA id oj6sm23327817pab.9.2013.12.20.19.43.19 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 20 Dec 2013 19:43:20 -0800 (PST) From: Iyappan Subramanian To: davem@davemloft.net Subject: [PATCH 5/5] drivers: net: APM X-Gene SoC Ethernet driver ethtool support Date: Fri, 20 Dec 2013 19:42:56 -0800 Message-Id: <1387597376-29303-6-git-send-email-isubramanian@apm.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1387597376-29303-1-git-send-email-isubramanian@apm.com> References: <1387597376-29303-1-git-send-email-isubramanian@apm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131220_224343_408556_6EB3FEA9 X-CRM114-Status: GOOD ( 21.77 ) X-Spam-Score: -4.2 (----) Cc: devicetree@vger.kernel.org, gregkh@linuxfoundation.org, Iyappan Subramanian , patches@apm.com, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, jcm@redhat.com, Keyur Chudgar , linux-arm-kernel@lists.infradead.org, Ravi Patel X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Ethtool support for APM X-Gene SoC ethernet driver. Signed-off-by: Iyappan Subramanian Signed-off-by: Ravi Patel Signed-off-by: Keyur Chudgar --- drivers/net/ethernet/apm/xgene/Makefile | 3 +- drivers/net/ethernet/apm/xgene/xgene_enet_csr.h | 4 + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_tools.c | 296 +++++++++++++++++++++ 5 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_tools.c diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile index 091547e..472710d 100644 --- a/drivers/net/ethernet/apm/xgene/Makefile +++ b/drivers/net/ethernet/apm/xgene/Makefile @@ -6,6 +6,7 @@ xgene-enet-objs := \ xgene_enet_common.o \ xgene_enet_mac.o \ xgene_enet_main.o \ - xgene_enet_err.o + xgene_enet_err.o \ + xgene_enet_tools.o obj-$(CONFIG_NET_XGENE) += xgene-enet.o diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_csr.h b/drivers/net/ethernet/apm/xgene/xgene_enet_csr.h index 858d155..5ca0d81 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_csr.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_csr.h @@ -357,6 +357,10 @@ #define INTERFACE_CONTROL_ADDR 0x00000038 #define STATION_ADDR0_ADDR 0x00000040 #define STATION_ADDR1_ADDR 0x00000044 +#define RX_FLOW_EN1_MASK 0x00000020 +#define TX_FLOW_EN1_MASK 0x00000010 +#define RX_FLOW_EN1_RD(src) (((src) & 0x00000020)>>5) +#define TX_FLOW_EN1_RD(src) (((src) & 0x00000010)>>4) #define SCAN_CYCLE_MASK 0x00000002 #define SOFT_RESET1_MASK 0x80000000 #define MAX_FRAME_LEN_SET(dst, src) \ diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 90f53b8..77d3fd8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -1416,6 +1416,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdev *pdev) /* Ethtool checks the capabilities/features in hw_features flag */ ndev->hw_features = ndev->features; + SET_ETHTOOL_OPS(ndev, &xgene_ethtool_ops); rc = register_netdev(ndev); if (rc) { diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index b25bb37..b95f129 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -173,4 +173,5 @@ void xgene_enet_init_priv(struct xgene_enet_priv *priv); int xgene_enet_parse_error(u8 LErr, int qid); void xgene_enet_register_err_irqs(struct net_device *ndev); +extern const struct ethtool_ops xgene_ethtool_ops; #endif /* __XGENE_ENET_MAIN_H__ */ diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_tools.c b/drivers/net/ethernet/apm/xgene/xgene_enet_tools.c new file mode 100644 index 0000000..d99f42b --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_tools.c @@ -0,0 +1,296 @@ +/* AppliedMicro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Authors: Hrishikesh Karanjikar + * Ravi Patel + * Iyappan Subramanian + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "xgene_enet_csr.h" +#include "xgene_enet_main.h" + +struct xgene_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +static const struct xgene_stats xgene_gstrings_stats[] = { + { "rx_bytes", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_byte_count), + offsetof(struct xgene_enet_pdev, stats.rx_stats.rx_byte_count) + }, + { "rx_packets", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_packet_count), + offsetof(struct xgene_enet_pdev, stats.rx_stats.rx_packet_count) + }, + { "rx_fcs_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_fcs_err_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_fcs_err_count) + }, + { "rx_alignment_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_alignment_err_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_alignment_err_pkt_count) + }, + { "rx_frm_len_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_frm_len_err_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_frm_len_err_pkt_count) + }, + { "rx_undersize", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_undersize_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_undersize_pkt_count) + }, + { "rx_oversize", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_oversize_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_oversize_pkt_count) + }, + { "rx_drop", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.rx_stats.rx_drop_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.rx_stats.rx_drop_pkt_count) + }, + { "tx_bytes", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_byte_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_byte_count) + }, + { "tx_packets", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_pkt_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_pkt_count) + }, + { "tx_drop", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_drop_frm_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_drop_frm_count) + }, + { "tx_fcs_err", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_fcs_err_frm_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_fcs_err_frm_count) + }, + { "tx_undersize", + FIELD_SIZEOF(struct xgene_enet_pdev, + stats.tx_stats.tx_undersize_frm_count), + offsetof(struct xgene_enet_pdev, + stats.tx_stats.tx_undersize_frm_count) + }, +}; + +#define XGENE_GLOBAL_STATS_LEN ARRAY_SIZE(xgene_gstrings_stats) + +/* Ethtool APIs */ +static int xgene_ethtool_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct phy_device *phydev = pdev->phy_dev; + struct xgene_enet_priv *priv = &pdev->priv; + + if (priv->phy_mode == PHY_MODE_RGMII) { + if (!phydev) + return -ENODEV; + return phy_ethtool_gset(phydev, cmd); + } + return 0; +} + +static int xgene_ethtool_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct phy_device *phydev = pdev->phy_dev; + struct xgene_enet_priv *priv = &pdev->priv; + + if (priv->phy_mode == PHY_MODE_RGMII) { + if (!phydev) + return -ENODEV; + return phy_ethtool_sset(phydev, cmd); + } + return 0; +} + +static int xgene_ethtool_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + u32 data; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + + /* Modify value to set or reset rx flow control */ + if (pp->rx_pause) + data |= RX_FLOW_EN1_MASK; + else + data &= ~RX_FLOW_EN1_MASK; + + /* Modify value to set or reset tx flow control */ + if (pp->tx_pause) + data |= TX_FLOW_EN1_MASK; + else + data &= ~TX_FLOW_EN1_MASK; + + xgene_enet_wr(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, data); + + return 0; +} + +static void xgene_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + u32 data; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + pp->rx_pause = RX_FLOW_EN1_RD(data); + + xgene_enet_rd(priv, BLOCK_MCX_MAC, MAC_CONFIG_1_ADDR, &data); + pp->tx_pause = TX_FLOW_EN1_RD(data); +} + +static int xgene_ethtool_nway_reset(struct net_device *ndev) +{ + u32 data = 0, retry = 0; + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + + if (priv->phy_mode == PHY_MODE_RGMII) + mutex_lock(&pdev->mdio_bus->mdio_lock); + + /* Power-down PHY */ + data = MII_CR_POWER_DOWN; + xgene_genericmiiphy_write(priv, priv->phy_addr, + MII_CTRL_REG, data); + + /* Power-up PHY */ + data = 0x0; + xgene_genericmiiphy_write(priv, priv->phy_addr, + MII_CTRL_REG, data); + + /* Reset PHY */ + data = MII_CR_RESET; + xgene_genericmiiphy_write(priv, priv->phy_addr, + MII_CTRL_REG, data); + + /* PHY reset may take 100 ms */ + retry = 100; + do { + xgene_genericmiiphy_read(priv, priv->phy_addr, + MII_CTRL_REG, &data); + usleep_range(1000, 2000); + } while (--retry && (data & MII_CR_RESET)); + + xgene_genericmiiphy_write(priv, priv->phy_addr, MII_CTRL_REG, + MII_CR_AUTO_EN|MII_CR_RESTART|MII_CR_FDX); + + priv->autoneg_set = 1; + priv->speed = XGENE_ENET_SPEED_1000; + priv->mac_init(priv, ndev->dev_addr, priv->speed, + HW_MTU(ndev->mtu), priv->crc); + + if (priv->phy_mode == PHY_MODE_RGMII) + mutex_unlock(&pdev->mdio_bus->mdio_lock); + + return 0; +} + +static void xgene_get_strings(struct net_device *ndev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + case ETH_SS_STATS: + for (i = 0; i < XGENE_GLOBAL_STATS_LEN; i++) { + memcpy(p, xgene_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int xgene_get_sset_count(struct net_device *ndev, int sset) +{ + switch (sset) { + case ETH_SS_TEST: + return XGENE_GLOBAL_STATS_LEN; + case ETH_SS_STATS: + return XGENE_GLOBAL_STATS_LEN; + default: + return -EOPNOTSUPP; + } + +} + +static void xgene_ethtool_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *ethtool_stats, + u64 *data) +{ + + struct xgene_enet_pdev *pdev = netdev_priv(ndev); + struct xgene_enet_priv *priv = &pdev->priv; + struct xgene_enet_detailed_stats *stats = &pdev->stats; + int i; + + xgene_enet_get_stats(priv, stats); + for (i = 0; i < XGENE_GLOBAL_STATS_LEN; i++) { + char *p = (char *)pdev + xgene_gstrings_stats[i].stat_offset; + data[i] = (xgene_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } +} + +static void xgene_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, ndev->name); + strcpy(info->version, XGENE_ENET_DRIVER_VERSION); + strcpy(info->fw_version, "N/A"); +} + +const struct ethtool_ops xgene_ethtool_ops = { + .get_settings = xgene_ethtool_get_settings, + .set_settings = xgene_ethtool_set_settings, + .get_drvinfo = xgene_ethtool_get_drvinfo, + .nway_reset = xgene_ethtool_nway_reset, + .get_pauseparam = xgene_ethtool_get_pauseparam, + .set_pauseparam = xgene_ethtool_set_pauseparam, + .get_ethtool_stats = xgene_ethtool_get_ethtool_stats, + .get_sset_count = xgene_get_sset_count, + .get_strings = xgene_get_strings, + .get_link = ethtool_op_get_link, +};