278 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * linux/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c4 *5 * eHEA ethernet device driver for IBM eServer System p6 *7 * (C) Copyright IBM Corp. 20068 *9 * Authors:10 * Christoph Raisch <raisch@de.ibm.com>11 * Jan-Bernd Themann <themann@de.ibm.com>12 * Thomas Klein <tklein@de.ibm.com>13 */14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt16 17#include "ehea.h"18#include "ehea_phyp.h"19 20static int ehea_get_link_ksettings(struct net_device *dev,21 struct ethtool_link_ksettings *cmd)22{23 struct ehea_port *port = netdev_priv(dev);24 u32 supported, advertising;25 u32 speed;26 int ret;27 28 ret = ehea_sense_port_attr(port);29 30 if (ret)31 return ret;32 33 if (netif_carrier_ok(dev)) {34 switch (port->port_speed) {35 case EHEA_SPEED_10M:36 speed = SPEED_10;37 break;38 case EHEA_SPEED_100M:39 speed = SPEED_100;40 break;41 case EHEA_SPEED_1G:42 speed = SPEED_1000;43 break;44 case EHEA_SPEED_10G:45 speed = SPEED_10000;46 break;47 default:48 speed = -1;49 break; /* BUG */50 }51 cmd->base.duplex = port->full_duplex == 1 ?52 DUPLEX_FULL : DUPLEX_HALF;53 } else {54 speed = SPEED_UNKNOWN;55 cmd->base.duplex = DUPLEX_UNKNOWN;56 }57 cmd->base.speed = speed;58 59 if (cmd->base.speed == SPEED_10000) {60 supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);61 advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);62 cmd->base.port = PORT_FIBRE;63 } else {64 supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full65 | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full66 | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg67 | SUPPORTED_TP);68 advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg69 | ADVERTISED_TP);70 cmd->base.port = PORT_TP;71 }72 73 cmd->base.autoneg = port->autoneg == 1 ?74 AUTONEG_ENABLE : AUTONEG_DISABLE;75 76 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,77 supported);78 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,79 advertising);80 81 return 0;82}83 84static int ehea_set_link_ksettings(struct net_device *dev,85 const struct ethtool_link_ksettings *cmd)86{87 struct ehea_port *port = netdev_priv(dev);88 int ret = 0;89 u32 sp;90 91 if (cmd->base.autoneg == AUTONEG_ENABLE) {92 sp = EHEA_SPEED_AUTONEG;93 goto doit;94 }95 96 switch (cmd->base.speed) {97 case SPEED_10:98 if (cmd->base.duplex == DUPLEX_FULL)99 sp = H_SPEED_10M_F;100 else101 sp = H_SPEED_10M_H;102 break;103 104 case SPEED_100:105 if (cmd->base.duplex == DUPLEX_FULL)106 sp = H_SPEED_100M_F;107 else108 sp = H_SPEED_100M_H;109 break;110 111 case SPEED_1000:112 if (cmd->base.duplex == DUPLEX_FULL)113 sp = H_SPEED_1G_F;114 else115 ret = -EINVAL;116 break;117 118 case SPEED_10000:119 if (cmd->base.duplex == DUPLEX_FULL)120 sp = H_SPEED_10G_F;121 else122 ret = -EINVAL;123 break;124 125 default:126 ret = -EINVAL;127 break;128 }129 130 if (ret)131 goto out;132doit:133 ret = ehea_set_portspeed(port, sp);134 135 if (!ret)136 netdev_info(dev,137 "Port speed successfully set: %dMbps %s Duplex\n",138 port->port_speed,139 port->full_duplex == 1 ? "Full" : "Half");140out:141 return ret;142}143 144static int ehea_nway_reset(struct net_device *dev)145{146 struct ehea_port *port = netdev_priv(dev);147 int ret;148 149 ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);150 151 if (!ret)152 netdev_info(port->netdev,153 "Port speed successfully set: %dMbps %s Duplex\n",154 port->port_speed,155 port->full_duplex == 1 ? "Full" : "Half");156 return ret;157}158 159static void ehea_get_drvinfo(struct net_device *dev,160 struct ethtool_drvinfo *info)161{162 strscpy(info->driver, DRV_NAME, sizeof(info->driver));163 strscpy(info->version, DRV_VERSION, sizeof(info->version));164}165 166static u32 ehea_get_msglevel(struct net_device *dev)167{168 struct ehea_port *port = netdev_priv(dev);169 return port->msg_enable;170}171 172static void ehea_set_msglevel(struct net_device *dev, u32 value)173{174 struct ehea_port *port = netdev_priv(dev);175 port->msg_enable = value;176}177 178static const char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {179 {"sig_comp_iv"},180 {"swqe_refill_th"},181 {"port resets"},182 {"Receive errors"},183 {"TCP cksum errors"},184 {"IP cksum errors"},185 {"Frame cksum errors"},186 {"num SQ stopped"},187 {"PR0 free_swqes"},188 {"PR1 free_swqes"},189 {"PR2 free_swqes"},190 {"PR3 free_swqes"},191 {"PR4 free_swqes"},192 {"PR5 free_swqes"},193 {"PR6 free_swqes"},194 {"PR7 free_swqes"},195 {"PR8 free_swqes"},196 {"PR9 free_swqes"},197 {"PR10 free_swqes"},198 {"PR11 free_swqes"},199 {"PR12 free_swqes"},200 {"PR13 free_swqes"},201 {"PR14 free_swqes"},202 {"PR15 free_swqes"},203};204 205static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)206{207 if (stringset == ETH_SS_STATS) {208 memcpy(data, &ehea_ethtool_stats_keys,209 sizeof(ehea_ethtool_stats_keys));210 }211}212 213static int ehea_get_sset_count(struct net_device *dev, int sset)214{215 switch (sset) {216 case ETH_SS_STATS:217 return ARRAY_SIZE(ehea_ethtool_stats_keys);218 default:219 return -EOPNOTSUPP;220 }221}222 223static void ehea_get_ethtool_stats(struct net_device *dev,224 struct ethtool_stats *stats, u64 *data)225{226 int i, k, tmp;227 struct ehea_port *port = netdev_priv(dev);228 229 for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)230 data[i] = 0;231 i = 0;232 233 data[i++] = port->sig_comp_iv;234 data[i++] = port->port_res[0].swqe_refill_th;235 data[i++] = port->resets;236 237 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)238 tmp += port->port_res[k].p_stats.poll_receive_errors;239 data[i++] = tmp;240 241 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)242 tmp += port->port_res[k].p_stats.err_tcp_cksum;243 data[i++] = tmp;244 245 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)246 tmp += port->port_res[k].p_stats.err_ip_cksum;247 data[i++] = tmp;248 249 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)250 tmp += port->port_res[k].p_stats.err_frame_crc;251 data[i++] = tmp;252 253 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)254 tmp += port->port_res[k].p_stats.queue_stopped;255 data[i++] = tmp;256 257 for (k = 0; k < 16; k++)258 data[i++] = atomic_read(&port->port_res[k].swqe_avail);259}260 261static const struct ethtool_ops ehea_ethtool_ops = {262 .get_drvinfo = ehea_get_drvinfo,263 .get_msglevel = ehea_get_msglevel,264 .set_msglevel = ehea_set_msglevel,265 .get_link = ethtool_op_get_link,266 .get_strings = ehea_get_strings,267 .get_sset_count = ehea_get_sset_count,268 .get_ethtool_stats = ehea_get_ethtool_stats,269 .nway_reset = ehea_nway_reset, /* Restart autonegotiation */270 .get_link_ksettings = ehea_get_link_ksettings,271 .set_link_ksettings = ehea_set_link_ksettings,272};273 274void ehea_set_ethtool_ops(struct net_device *netdev)275{276 netdev->ethtool_ops = &ehea_ethtool_ops;277}278