brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · 6bc1988 Raw
223 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * DPAA2 Ethernet Switch ethtool support4 *5 * Copyright 2014-2016 Freescale Semiconductor Inc.6 * Copyright 2017-2018 NXP7 *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	else50		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 int58dpaa2_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;64 65	mutex_lock(&port_priv->mac_lock);66 67	if (dpaa2_switch_port_is_type_phy(port_priv)) {68		err = phylink_ethtool_ksettings_get(port_priv->mac->phylink,69						    link_ksettings);70		mutex_unlock(&port_priv->mac_lock);71		return err;72	}73 74	mutex_unlock(&port_priv->mac_lock);75 76	err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,77				     port_priv->ethsw_data->dpsw_handle,78				     port_priv->idx,79				     &state);80	if (err) {81		netdev_err(netdev, "ERROR %d getting link state\n", err);82		goto out;83	}84 85	/* At the moment, we have no way of interrogating the DPMAC86	 * from the DPSW side or there may not exist a DPMAC at all.87	 * Report only autoneg state, duplexity and speed.88	 */89	if (state.options & DPSW_LINK_OPT_AUTONEG)90		link_ksettings->base.autoneg = AUTONEG_ENABLE;91	if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX))92		link_ksettings->base.duplex = DUPLEX_FULL;93	link_ksettings->base.speed = state.rate;94 95out:96	return err;97}98 99static int100dpaa2_switch_set_link_ksettings(struct net_device *netdev,101				const struct ethtool_link_ksettings *link_ksettings)102{103	struct ethsw_port_priv *port_priv = netdev_priv(netdev);104	struct ethsw_core *ethsw = port_priv->ethsw_data;105	struct dpsw_link_cfg cfg = {0};106	bool if_running;107	int err = 0, ret;108 109	mutex_lock(&port_priv->mac_lock);110 111	if (dpaa2_switch_port_is_type_phy(port_priv)) {112		err = phylink_ethtool_ksettings_set(port_priv->mac->phylink,113						    link_ksettings);114		mutex_unlock(&port_priv->mac_lock);115		return err;116	}117 118	mutex_unlock(&port_priv->mac_lock);119 120	/* Interface needs to be down to change link settings */121	if_running = netif_running(netdev);122	if (if_running) {123		err = dpsw_if_disable(ethsw->mc_io, 0,124				      ethsw->dpsw_handle,125				      port_priv->idx);126		if (err) {127			netdev_err(netdev, "dpsw_if_disable err %d\n", err);128			return err;129		}130	}131 132	cfg.rate = link_ksettings->base.speed;133	if (link_ksettings->base.autoneg == AUTONEG_ENABLE)134		cfg.options |= DPSW_LINK_OPT_AUTONEG;135	else136		cfg.options &= ~DPSW_LINK_OPT_AUTONEG;137	if (link_ksettings->base.duplex  == DUPLEX_HALF)138		cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX;139	else140		cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX;141 142	err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0,143				   port_priv->ethsw_data->dpsw_handle,144				   port_priv->idx,145				   &cfg);146 147	if (if_running) {148		ret = dpsw_if_enable(ethsw->mc_io, 0,149				     ethsw->dpsw_handle,150				     port_priv->idx);151		if (ret) {152			netdev_err(netdev, "dpsw_if_enable err %d\n", ret);153			return ret;154		}155	}156	return err;157}158 159static int160dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)161{162	switch (sset) {163	case ETH_SS_STATS:164		return DPAA2_SWITCH_NUM_COUNTERS + dpaa2_mac_get_sset_count();165	default:166		return -EOPNOTSUPP;167	}168}169 170static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,171					     u32 stringset, u8 *data)172{173	u8 *p = data;174	int i;175 176	switch (stringset) {177	case ETH_SS_STATS:178		for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {179			memcpy(p, dpaa2_switch_ethtool_counters[i].name,180			       ETH_GSTRING_LEN);181			p += ETH_GSTRING_LEN;182		}183		dpaa2_mac_get_strings(p);184		break;185	}186}187 188static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev,189					   struct ethtool_stats *stats,190					   u64 *data)191{192	struct ethsw_port_priv *port_priv = netdev_priv(netdev);193	int i, err;194 195	for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {196		err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,197					  port_priv->ethsw_data->dpsw_handle,198					  port_priv->idx,199					  dpaa2_switch_ethtool_counters[i].id,200					  &data[i]);201		if (err)202			netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",203				   dpaa2_switch_ethtool_counters[i].name, err);204	}205 206	mutex_lock(&port_priv->mac_lock);207 208	if (dpaa2_switch_port_has_mac(port_priv))209		dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i);210 211	mutex_unlock(&port_priv->mac_lock);212}213 214const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {215	.get_drvinfo		= dpaa2_switch_get_drvinfo,216	.get_link		= ethtool_op_get_link,217	.get_link_ksettings	= dpaa2_switch_get_link_ksettings,218	.set_link_ksettings	= dpaa2_switch_set_link_ksettings,219	.get_strings		= dpaa2_switch_ethtool_get_strings,220	.get_ethtool_stats	= dpaa2_switch_ethtool_get_stats,221	.get_sset_count		= dpaa2_switch_ethtool_get_sset_count,222};223