1/* 2 * linux/drivers/net/ehea/ehea_ethtool.c 3 * 4 * eHEA ethernet device driver for IBM eServer System p 5 * 6 * (C) Copyright IBM Corp. 2006 7 * 8 * Authors: 9 * Christoph Raisch <raisch@de.ibm.com> 10 * Jan-Bernd Themann <themann@de.ibm.com> 11 * Thomas Klein <tklein@de.ibm.com> 12 * 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2, or (at your option) 17 * any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 */ 28 29#include "ehea.h" 30#include "ehea_phyp.h" 31 32static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 33{ 34 struct ehea_port *port = netdev_priv(dev); 35 int ret; 36 37 ret = ehea_sense_port_attr(port); 38 39 if (ret) 40 return ret; 41 42 if (netif_carrier_ok(dev)) { 43 switch(port->port_speed) { 44 case EHEA_SPEED_10M: cmd->speed = SPEED_10; break; 45 case EHEA_SPEED_100M: cmd->speed = SPEED_100; break; 46 case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break; 47 case EHEA_SPEED_10G: cmd->speed = SPEED_10000; break; 48 } 49 cmd->duplex = port->full_duplex == 1 ? 50 DUPLEX_FULL : DUPLEX_HALF; 51 } else { 52 cmd->speed = -1; 53 cmd->duplex = -1; 54 } 55 56 cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full 57 | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half 58 | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half 59 | SUPPORTED_Autoneg | SUPPORTED_FIBRE); 60 61 cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg 62 | ADVERTISED_FIBRE); 63 64 cmd->port = PORT_FIBRE; 65 cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE; 66 67 return 0; 68} 69 70static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 71{ 72 struct ehea_port *port = netdev_priv(dev); 73 int ret = 0; 74 u32 sp; 75 76 if (cmd->autoneg == AUTONEG_ENABLE) { 77 sp = EHEA_SPEED_AUTONEG; 78 goto doit; 79 } 80 81 switch(cmd->speed) { 82 case SPEED_10: 83 if (cmd->duplex == DUPLEX_FULL) 84 sp = H_SPEED_10M_F; 85 else 86 sp = H_SPEED_10M_H; 87 break; 88 89 case SPEED_100: 90 if (cmd->duplex == DUPLEX_FULL) 91 sp = H_SPEED_100M_F; 92 else 93 sp = H_SPEED_100M_H; 94 break; 95 96 case SPEED_1000: 97 if (cmd->duplex == DUPLEX_FULL) 98 sp = H_SPEED_1G_F; 99 else 100 ret = -EINVAL; 101 break; 102 103 case SPEED_10000: 104 if (cmd->duplex == DUPLEX_FULL) 105 sp = H_SPEED_10G_F; 106 else 107 ret = -EINVAL; 108 break; 109 110 default: 111 ret = -EINVAL; 112 break; 113 } 114 115 if (ret) 116 goto out; 117doit: 118 ret = ehea_set_portspeed(port, sp); 119 120 if (!ret) 121 ehea_info("%s: Port speed succesfully set: %dMbps " 122 "%s Duplex", 123 port->netdev->name, port->port_speed, 124 port->full_duplex == 1 ? "Full" : "Half"); 125out: 126 return ret; 127} 128 129static int ehea_nway_reset(struct net_device *dev) 130{ 131 struct ehea_port *port = netdev_priv(dev); 132 int ret; 133 134 ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG); 135 136 if (!ret) 137 ehea_info("%s: Port speed succesfully set: %dMbps " 138 "%s Duplex", 139 port->netdev->name, port->port_speed, 140 port->full_duplex == 1 ? "Full" : "Half"); 141 return ret; 142} 143 144static void ehea_get_drvinfo(struct net_device *dev, 145 struct ethtool_drvinfo *info) 146{ 147 strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 148 strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 149} 150 151static u32 ehea_get_msglevel(struct net_device *dev) 152{ 153 struct ehea_port *port = netdev_priv(dev); 154 return port->msg_enable; 155} 156 157static void ehea_set_msglevel(struct net_device *dev, u32 value) 158{ 159 struct ehea_port *port = netdev_priv(dev); 160 port->msg_enable = value; 161} 162 163static u32 ehea_get_rx_csum(struct net_device *dev) 164{ 165 return 1; 166} 167 168static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { 169 {"sig_comp_iv"}, 170 {"swqe_refill_th"}, 171 {"port resets"}, 172 {"Receive errors"}, 173 {"TCP cksum errors"}, 174 {"IP cksum errors"}, 175 {"Frame cksum errors"}, 176 {"num SQ stopped"}, 177 {"SQ stopped"}, 178 {"PR0 free_swqes"}, 179 {"PR1 free_swqes"}, 180 {"PR2 free_swqes"}, 181 {"PR3 free_swqes"}, 182 {"PR4 free_swqes"}, 183 {"PR5 free_swqes"}, 184 {"PR6 free_swqes"}, 185 {"PR7 free_swqes"}, 186}; 187 188static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) 189{ 190 if (stringset == ETH_SS_STATS) { 191 memcpy(data, &ehea_ethtool_stats_keys, 192 sizeof(ehea_ethtool_stats_keys)); 193 } 194} 195 196static int ehea_get_stats_count(struct net_device *dev) 197{ 198 return ARRAY_SIZE(ehea_ethtool_stats_keys); 199} 200 201static void ehea_get_ethtool_stats(struct net_device *dev, 202 struct ethtool_stats *stats, u64 *data) 203{ 204 int i, k, tmp; 205 struct ehea_port *port = netdev_priv(dev); 206 207 for (i = 0; i < ehea_get_stats_count(dev); i++) 208 data[i] = 0; 209 i = 0; 210 211 data[i++] = port->sig_comp_iv; 212 data[i++] = port->port_res[0].swqe_refill_th; 213 data[i++] = port->resets; 214 215 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) 216 tmp += port->port_res[k].p_stats.poll_receive_errors; 217 data[i++] = tmp; 218 219 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) 220 tmp += port->port_res[k].p_stats.err_tcp_cksum; 221 data[i++] = tmp; 222 223 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) 224 tmp += port->port_res[k].p_stats.err_ip_cksum; 225 data[i++] = tmp; 226 227 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) 228 tmp += port->port_res[k].p_stats.err_frame_crc; 229 data[i++] = tmp; 230 231 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) 232 tmp += port->port_res[k].p_stats.queue_stopped; 233 data[i++] = tmp; 234 235 for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) 236 tmp |= port->port_res[k].queue_stopped; 237 data[i++] = tmp; 238 239 for (k = 0; k < 8; k++) 240 data[i++] = atomic_read(&port->port_res[k].swqe_avail); 241 242} 243 244const struct ethtool_ops ehea_ethtool_ops = { 245 .get_settings = ehea_get_settings, 246 .get_drvinfo = ehea_get_drvinfo, 247 .get_msglevel = ehea_get_msglevel, 248 .set_msglevel = ehea_set_msglevel, 249 .get_link = ethtool_op_get_link, 250 .get_tx_csum = ethtool_op_get_tx_csum, 251 .get_sg = ethtool_op_get_sg, 252 .get_tso = ethtool_op_get_tso, 253 .set_tso = ethtool_op_set_tso, 254 .get_strings = ehea_get_strings, 255 .get_stats_count = ehea_get_stats_count, 256 .get_ethtool_stats = ehea_get_ethtool_stats, 257 .get_rx_csum = ehea_get_rx_csum, 258 .set_settings = ehea_set_settings, 259 .nway_reset = ehea_nway_reset, /* Restart autonegotiation */ 260}; 261 262void ehea_set_ethtool_ops(struct net_device *netdev) 263{ 264 SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops); 265} 266