cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dpaa2-switch-ethtool.c (6067B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * DPAA2 Ethernet Switch ethtool support
      4 *
      5 * Copyright 2014-2016 Freescale Semiconductor Inc.
      6 * Copyright 2017-2018 NXP
      7 *
      8 */
      9
     10#include <linux/ethtool.h>
     11
     12#include "dpaa2-switch.h"
     13
     14static struct {
     15	enum dpsw_counter id;
     16	char name[ETH_GSTRING_LEN];
     17} dpaa2_switch_ethtool_counters[] =  {
     18	{DPSW_CNT_ING_FRAME,		"[hw] rx frames"},
     19	{DPSW_CNT_ING_BYTE,		"[hw] rx bytes"},
     20	{DPSW_CNT_ING_FLTR_FRAME,	"[hw] rx filtered frames"},
     21	{DPSW_CNT_ING_FRAME_DISCARD,	"[hw] rx discarded frames"},
     22	{DPSW_CNT_ING_BCAST_FRAME,	"[hw] rx bcast frames"},
     23	{DPSW_CNT_ING_BCAST_BYTES,	"[hw] rx bcast bytes"},
     24	{DPSW_CNT_ING_MCAST_FRAME,	"[hw] rx mcast frames"},
     25	{DPSW_CNT_ING_MCAST_BYTE,	"[hw] rx mcast bytes"},
     26	{DPSW_CNT_EGR_FRAME,		"[hw] tx frames"},
     27	{DPSW_CNT_EGR_BYTE,		"[hw] tx bytes"},
     28	{DPSW_CNT_EGR_FRAME_DISCARD,	"[hw] tx discarded frames"},
     29	{DPSW_CNT_ING_NO_BUFF_DISCARD,	"[hw] rx nobuffer discards"},
     30};
     31
     32#define DPAA2_SWITCH_NUM_COUNTERS	ARRAY_SIZE(dpaa2_switch_ethtool_counters)
     33
     34static void dpaa2_switch_get_drvinfo(struct net_device *netdev,
     35				     struct ethtool_drvinfo *drvinfo)
     36{
     37	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
     38	u16 version_major, version_minor;
     39	int err;
     40
     41	strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
     42
     43	err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0,
     44				   &version_major,
     45				   &version_minor);
     46	if (err)
     47		strscpy(drvinfo->fw_version, "N/A",
     48			sizeof(drvinfo->fw_version));
     49	else
     50		snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
     51			 "%u.%u", version_major, version_minor);
     52
     53	strscpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
     54		sizeof(drvinfo->bus_info));
     55}
     56
     57static int
     58dpaa2_switch_get_link_ksettings(struct net_device *netdev,
     59				struct ethtool_link_ksettings *link_ksettings)
     60{
     61	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
     62	struct dpsw_link_state state = {0};
     63	int err = 0;
     64
     65	if (dpaa2_switch_port_is_type_phy(port_priv))
     66		return phylink_ethtool_ksettings_get(port_priv->mac->phylink,
     67						     link_ksettings);
     68
     69	err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
     70				     port_priv->ethsw_data->dpsw_handle,
     71				     port_priv->idx,
     72				     &state);
     73	if (err) {
     74		netdev_err(netdev, "ERROR %d getting link state\n", err);
     75		goto out;
     76	}
     77
     78	/* At the moment, we have no way of interrogating the DPMAC
     79	 * from the DPSW side or there may not exist a DPMAC at all.
     80	 * Report only autoneg state, duplexity and speed.
     81	 */
     82	if (state.options & DPSW_LINK_OPT_AUTONEG)
     83		link_ksettings->base.autoneg = AUTONEG_ENABLE;
     84	if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX))
     85		link_ksettings->base.duplex = DUPLEX_FULL;
     86	link_ksettings->base.speed = state.rate;
     87
     88out:
     89	return err;
     90}
     91
     92static int
     93dpaa2_switch_set_link_ksettings(struct net_device *netdev,
     94				const struct ethtool_link_ksettings *link_ksettings)
     95{
     96	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
     97	struct ethsw_core *ethsw = port_priv->ethsw_data;
     98	struct dpsw_link_cfg cfg = {0};
     99	bool if_running;
    100	int err = 0, ret;
    101
    102	if (dpaa2_switch_port_is_type_phy(port_priv))
    103		return phylink_ethtool_ksettings_set(port_priv->mac->phylink,
    104						     link_ksettings);
    105
    106	/* Interface needs to be down to change link settings */
    107	if_running = netif_running(netdev);
    108	if (if_running) {
    109		err = dpsw_if_disable(ethsw->mc_io, 0,
    110				      ethsw->dpsw_handle,
    111				      port_priv->idx);
    112		if (err) {
    113			netdev_err(netdev, "dpsw_if_disable err %d\n", err);
    114			return err;
    115		}
    116	}
    117
    118	cfg.rate = link_ksettings->base.speed;
    119	if (link_ksettings->base.autoneg == AUTONEG_ENABLE)
    120		cfg.options |= DPSW_LINK_OPT_AUTONEG;
    121	else
    122		cfg.options &= ~DPSW_LINK_OPT_AUTONEG;
    123	if (link_ksettings->base.duplex  == DUPLEX_HALF)
    124		cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX;
    125	else
    126		cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX;
    127
    128	err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0,
    129				   port_priv->ethsw_data->dpsw_handle,
    130				   port_priv->idx,
    131				   &cfg);
    132
    133	if (if_running) {
    134		ret = dpsw_if_enable(ethsw->mc_io, 0,
    135				     ethsw->dpsw_handle,
    136				     port_priv->idx);
    137		if (ret) {
    138			netdev_err(netdev, "dpsw_if_enable err %d\n", ret);
    139			return ret;
    140		}
    141	}
    142	return err;
    143}
    144
    145static int
    146dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)
    147{
    148	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    149	int num_ss_stats = DPAA2_SWITCH_NUM_COUNTERS;
    150
    151	switch (sset) {
    152	case ETH_SS_STATS:
    153		if (port_priv->mac)
    154			num_ss_stats += dpaa2_mac_get_sset_count();
    155		return num_ss_stats;
    156	default:
    157		return -EOPNOTSUPP;
    158	}
    159}
    160
    161static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,
    162					     u32 stringset, u8 *data)
    163{
    164	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    165	u8 *p = data;
    166	int i;
    167
    168	switch (stringset) {
    169	case ETH_SS_STATS:
    170		for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {
    171			memcpy(p, dpaa2_switch_ethtool_counters[i].name,
    172			       ETH_GSTRING_LEN);
    173			p += ETH_GSTRING_LEN;
    174		}
    175		if (port_priv->mac)
    176			dpaa2_mac_get_strings(p);
    177		break;
    178	}
    179}
    180
    181static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev,
    182					   struct ethtool_stats *stats,
    183					   u64 *data)
    184{
    185	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
    186	int i, err;
    187
    188	for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {
    189		err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
    190					  port_priv->ethsw_data->dpsw_handle,
    191					  port_priv->idx,
    192					  dpaa2_switch_ethtool_counters[i].id,
    193					  &data[i]);
    194		if (err)
    195			netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",
    196				   dpaa2_switch_ethtool_counters[i].name, err);
    197	}
    198
    199	if (port_priv->mac)
    200		dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i);
    201}
    202
    203const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
    204	.get_drvinfo		= dpaa2_switch_get_drvinfo,
    205	.get_link		= ethtool_op_get_link,
    206	.get_link_ksettings	= dpaa2_switch_get_link_ksettings,
    207	.set_link_ksettings	= dpaa2_switch_set_link_ksettings,
    208	.get_strings		= dpaa2_switch_ethtool_get_strings,
    209	.get_ethtool_stats	= dpaa2_switch_ethtool_get_stats,
    210	.get_sset_count		= dpaa2_switch_ethtool_get_sset_count,
    211};