lkml.org 
[lkml]   [2017]   [Oct]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 3/6] staging: fsl-dpaa2/ethsw: Add ethtool support
    Date
    Add driver information, link details and hardware statistics to be
    reported via ethtool -S.

    Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
    ---
    Changelog:
    v2:
    - no changes

    drivers/staging/fsl-dpaa2/ethsw/Makefile | 2 +-
    drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 13 ++
    drivers/staging/fsl-dpaa2/ethsw/dpsw.c | 32 ++++
    drivers/staging/fsl-dpaa2/ethsw/dpsw.h | 32 ++++
    drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c | 207 ++++++++++++++++++++++++
    drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 3 +
    drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 3 +
    7 files changed, 291 insertions(+), 1 deletion(-)
    create mode 100644 drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c

    diff --git a/drivers/staging/fsl-dpaa2/ethsw/Makefile b/drivers/staging/fsl-dpaa2/ethsw/Makefile
    index a6d72d1..de92cd9 100644
    --- a/drivers/staging/fsl-dpaa2/ethsw/Makefile
    +++ b/drivers/staging/fsl-dpaa2/ethsw/Makefile
    @@ -4,4 +4,4 @@

    obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o

    -dpaa2-ethsw-objs := ethsw.o dpsw.o
    +dpaa2-ethsw-objs := ethsw.o ethsw-ethtool.o dpsw.o
    diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
    index ddfd820..06b71122 100644
    --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
    +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
    @@ -74,6 +74,8 @@
    #define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047)
    #define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048)

    +#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C)
    +
    #define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060)
    #define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_ID(0x061)
    #define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062)
    @@ -262,6 +264,17 @@ struct dpsw_cmd_if_set_max_frame_length {
    __le16 frame_length;
    };

    +struct dpsw_cmd_if_set_link_cfg {
    + /* cmd word 0 */
    + __le16 if_id;
    + u8 pad[6];
    + /* cmd word 1 */
    + __le32 rate;
    + __le32 pad1;
    + /* cmd word 2 */
    + __le64 options;
    +};
    +
    struct dpsw_cmd_if_get_link_state {
    __le16 if_id;
    };
    diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
    index e65b6f5..f1a1fac 100644
    --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
    +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
    @@ -383,6 +383,38 @@ int dpsw_get_attributes(struct fsl_mc_io *mc_io,
    }

    /**
    + * dpsw_if_set_link_cfg() - Set the link configuration.
    + * @mc_io: Pointer to MC portal's I/O object
    + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
    + * @token: Token of DPSW object
    + * @if_id: Interface id
    + * @cfg: Link configuration
    + *
    + * Return: '0' on Success; Error code otherwise.
    + */
    +int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io,
    + u32 cmd_flags,
    + u16 token,
    + u16 if_id,
    + struct dpsw_link_cfg *cfg)
    +{
    + struct mc_command cmd = { 0 };
    + struct dpsw_cmd_if_set_link_cfg *cmd_params;
    +
    + /* prepare command */
    + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LINK_CFG,
    + cmd_flags,
    + token);
    + cmd_params = (struct dpsw_cmd_if_set_link_cfg *)cmd.params;
    + cmd_params->if_id = cpu_to_le16(if_id);
    + cmd_params->rate = cpu_to_le32(cfg->rate);
    + cmd_params->options = cpu_to_le64(cfg->options);
    +
    + /* send command to mc*/
    + return mc_send_command(mc_io, &cmd);
    +}
    +
    +/**
    * dpsw_if_get_link_state - Return the link state
    * @mc_io: Pointer to MC portal's I/O object
    * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
    diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
    index 7fa8a61..87369a5 100644
    --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
    +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
    @@ -245,6 +245,38 @@ enum dpsw_action {
    };

    /**
    + * Enable auto-negotiation
    + */
    +#define DPSW_LINK_OPT_AUTONEG 0x0000000000000001ULL
    +/**
    + * Enable half-duplex mode
    + */
    +#define DPSW_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL
    +/**
    + * Enable pause frames
    + */
    +#define DPSW_LINK_OPT_PAUSE 0x0000000000000004ULL
    +/**
    + * Enable a-symmetric pause frames
    + */
    +#define DPSW_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
    +
    +/**
    + * struct dpsw_link_cfg - Structure representing DPSW link configuration
    + * @rate: Rate
    + * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values
    + */
    +struct dpsw_link_cfg {
    + u32 rate;
    + u64 options;
    +};
    +
    +int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io,
    + u32 cmd_flags,
    + u16 token,
    + u16 if_id,
    + struct dpsw_link_cfg *cfg);
    +/**
    * struct dpsw_link_state - Structure representing DPSW link state
    * @rate: Rate
    * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values
    diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
    new file mode 100644
    index 0000000..dcd49d2
    --- /dev/null
    +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
    @@ -0,0 +1,207 @@
    +/* Copyright 2014-2016 Freescale Semiconductor Inc.
    + * Copyright 2017 NXP
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions are met:
    + * * Redistributions of source code must retain the above copyright
    + * notice, this list of conditions and the following disclaimer.
    + * * Redistributions in binary form must reproduce the above copyright
    + * notice, this list of conditions and the following disclaimer in the
    + * documentation and/or other materials provided with the distribution.
    + * * Neither the name of the above-listed copyright holders nor the
    + * names of any contributors may be used to endorse or promote products
    + * derived from this software without specific prior written permission.
    + *
    + *
    + * ALTERNATIVELY, this software may be distributed under the terms of the
    + * GNU General Public License ("GPL") as published by the Free Software
    + * Foundation, either version 2 of that License or (at your option) any
    + * later version.
    + *
    + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
    + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    + * POSSIBILITY OF SUCH DAMAGE.
    + */
    +
    +#include "ethsw.h"
    +
    +static struct {
    + enum dpsw_counter id;
    + char name[ETH_GSTRING_LEN];
    +} ethsw_ethtool_counters[] = {
    + {DPSW_CNT_ING_FRAME, "rx frames"},
    + {DPSW_CNT_ING_BYTE, "rx bytes"},
    + {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"},
    + {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"},
    + {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"},
    + {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"},
    + {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"},
    + {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"},
    + {DPSW_CNT_EGR_FRAME, "tx frames"},
    + {DPSW_CNT_EGR_BYTE, "tx bytes"},
    + {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"},
    +
    +};
    +
    +#define ETHSW_NUM_COUNTERS ARRAY_SIZE(ethsw_ethtool_counters)
    +
    +static void ethsw_get_drvinfo(struct net_device *netdev,
    + struct ethtool_drvinfo *drvinfo)
    +{
    + struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    + u16 version_major, version_minor;
    + int err;
    +
    + strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
    + strlcpy(drvinfo->version, ethsw_drv_version, sizeof(drvinfo->version));
    +
    + err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0,
    + &version_major,
    + &version_minor);
    + if (err)
    + strlcpy(drvinfo->fw_version, "N/A",
    + sizeof(drvinfo->fw_version));
    + else
    + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
    + "%u.%u", version_major, version_minor);
    +
    + strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
    + sizeof(drvinfo->bus_info));
    +}
    +
    +static int
    +ethsw_get_link_ksettings(struct net_device *netdev,
    + struct ethtool_link_ksettings *link_ksettings)
    +{
    + struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    + struct dpsw_link_state state = {0};
    + int err = 0;
    +
    + err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
    + port_priv->ethsw_data->dpsw_handle,
    + port_priv->idx,
    + &state);
    + if (err) {
    + netdev_err(netdev, "ERROR %d getting link state", err);
    + goto out;
    + }
    +
    + /* At the moment, we have no way of interrogating the DPMAC
    + * from the DPSW side or there may not exist a DPMAC at all.
    + * Report only autoneg state, duplexity and speed.
    + */
    + if (state.options & DPSW_LINK_OPT_AUTONEG)
    + link_ksettings->base.autoneg = AUTONEG_ENABLE;
    + if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX))
    + link_ksettings->base.duplex = DUPLEX_FULL;
    + link_ksettings->base.speed = state.rate;
    +
    +out:
    + return err;
    +}
    +
    +static int
    +ethsw_set_link_ksettings(struct net_device *netdev,
    + const struct ethtool_link_ksettings *link_ksettings)
    +{
    + struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    + struct dpsw_link_cfg cfg = {0};
    + int err = 0;
    +
    + netdev_dbg(netdev, "Setting link parameters...");
    +
    + /* Due to a temporary MC limitation, the DPSW port must be down
    + * in order to be able to change link settings. Taking steps to let
    + * the user know that.
    + */
    + if (netif_running(netdev)) {
    + netdev_info(netdev, "Sorry, interface must be brought down first.\n");
    + return -EACCES;
    + }
    +
    + cfg.rate = link_ksettings->base.speed;
    + if (link_ksettings->base.autoneg == AUTONEG_ENABLE)
    + cfg.options |= DPSW_LINK_OPT_AUTONEG;
    + else
    + cfg.options &= ~DPSW_LINK_OPT_AUTONEG;
    + if (link_ksettings->base.duplex == DUPLEX_HALF)
    + cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX;
    + else
    + cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX;
    +
    + err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0,
    + port_priv->ethsw_data->dpsw_handle,
    + port_priv->idx,
    + &cfg);
    + if (err)
    + /* ethtool will be loud enough if we return an error; no point
    + * in putting our own error message on the console by default
    + */
    + netdev_dbg(netdev, "ERROR %d setting link cfg", err);
    +
    + return err;
    +}
    +
    +static int ethsw_ethtool_get_sset_count(struct net_device *dev, int sset)
    +{
    + switch (sset) {
    + case ETH_SS_STATS:
    + return ETHSW_NUM_COUNTERS;
    + default:
    + return -EOPNOTSUPP;
    + }
    +}
    +
    +static void ethsw_ethtool_get_strings(struct net_device *netdev,
    + u32 stringset, u8 *data)
    +{
    + int i;
    +
    + switch (stringset) {
    + case ETH_SS_STATS:
    + for (i = 0; i < ETHSW_NUM_COUNTERS; i++)
    + memcpy(data + i * ETH_GSTRING_LEN,
    + ethsw_ethtool_counters[i].name, ETH_GSTRING_LEN);
    + break;
    + }
    +}
    +
    +static void ethsw_ethtool_get_stats(struct net_device *netdev,
    + struct ethtool_stats *stats,
    + u64 *data)
    +{
    + struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    + int i, err;
    +
    + memset(data, 0,
    + sizeof(u64) * ETHSW_NUM_COUNTERS);
    +
    + for (i = 0; i < ETHSW_NUM_COUNTERS; i++) {
    + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
    + port_priv->ethsw_data->dpsw_handle,
    + port_priv->idx,
    + ethsw_ethtool_counters[i].id,
    + &data[i]);
    + if (err)
    + netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",
    + ethsw_ethtool_counters[i].name, err);
    + }
    +}
    +
    +const struct ethtool_ops ethsw_port_ethtool_ops = {
    + .get_drvinfo = ethsw_get_drvinfo,
    + .get_link = ethtool_op_get_link,
    + .get_link_ksettings = ethsw_get_link_ksettings,
    + .set_link_ksettings = ethsw_set_link_ksettings,
    + .get_strings = ethsw_ethtool_get_strings,
    + .get_ethtool_stats = ethsw_ethtool_get_stats,
    + .get_sset_count = ethsw_ethtool_get_sset_count,
    +};
    diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
    index f45e5bb..f1ba23c 100644
    --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
    +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
    @@ -44,6 +44,8 @@

    static struct workqueue_struct *ethsw_owq;

    +const char ethsw_drv_version[] = "0.1";
    +
    /* Minimal supported DPSW version */
    #define DPSW_MIN_VER_MAJOR 8
    #define DPSW_MIN_VER_MINOR 0
    @@ -1402,6 +1404,7 @@ static int ethsw_probe_port(struct ethsw_core *ethsw, u16 port_idx)

    SET_NETDEV_DEV(port_netdev, dev);
    port_netdev->netdev_ops = &ethsw_port_ops;
    + port_netdev->ethtool_ops = &ethsw_port_ethtool_ops;
    port_netdev->switchdev_ops = &ethsw_port_switchdev_ops;

    /* Set MTU limits */
    diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
    index 8c1d645..ba53cc5 100644
    --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
    +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
    @@ -57,6 +57,9 @@
    #define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN)
    #define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN)

    +extern const char ethsw_drv_version[];
    +extern const struct ethtool_ops ethsw_port_ethtool_ops;
    +
    struct ethsw_core;

    /* Per port private data */
    --
    1.9.1
    \
     
     \ /
      Last update: 2017-10-02 10:39    [W:4.392 / U:1.360 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site