linux/drivers/net/benet/be_ethtool.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005 - 2009 ServerEngines
   3 * All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License version 2
   7 * as published by the Free Software Foundation.  The full GNU General
   8 * Public License is included in this distribution in the file called COPYING.
   9 *
  10 * Contact Information:
  11 * linux-drivers@serverengines.com
  12 *
  13 * ServerEngines
  14 * 209 N. Fair Oaks Ave
  15 * Sunnyvale, CA 94085
  16 */
  17
  18#include "be.h"
  19#include "be_cmds.h"
  20#include <linux/ethtool.h>
  21
  22struct be_ethtool_stat {
  23        char desc[ETH_GSTRING_LEN];
  24        int type;
  25        int size;
  26        int offset;
  27};
  28
  29enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT};
  30#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
  31                                        offsetof(_struct, field)
  32#define NETSTAT_INFO(field)     #field, NETSTAT,\
  33                                        FIELDINFO(struct net_device_stats,\
  34                                                field)
  35#define DRVSTAT_INFO(field)     #field, DRVSTAT,\
  36                                        FIELDINFO(struct be_drvr_stats, field)
  37#define MISCSTAT_INFO(field)    #field, MISCSTAT,\
  38                                        FIELDINFO(struct be_rxf_stats, field)
  39#define PORTSTAT_INFO(field)    #field, PORTSTAT,\
  40                                        FIELDINFO(struct be_port_rxf_stats, \
  41                                                field)
  42#define ERXSTAT_INFO(field)     #field, ERXSTAT,\
  43                                        FIELDINFO(struct be_erx_stats, field)
  44
  45static const struct be_ethtool_stat et_stats[] = {
  46        {NETSTAT_INFO(rx_packets)},
  47        {NETSTAT_INFO(tx_packets)},
  48        {NETSTAT_INFO(rx_bytes)},
  49        {NETSTAT_INFO(tx_bytes)},
  50        {NETSTAT_INFO(rx_errors)},
  51        {NETSTAT_INFO(tx_errors)},
  52        {NETSTAT_INFO(rx_dropped)},
  53        {NETSTAT_INFO(tx_dropped)},
  54        {DRVSTAT_INFO(be_tx_reqs)},
  55        {DRVSTAT_INFO(be_tx_stops)},
  56        {DRVSTAT_INFO(be_fwd_reqs)},
  57        {DRVSTAT_INFO(be_tx_wrbs)},
  58        {DRVSTAT_INFO(be_polls)},
  59        {DRVSTAT_INFO(be_tx_events)},
  60        {DRVSTAT_INFO(be_rx_events)},
  61        {DRVSTAT_INFO(be_tx_compl)},
  62        {DRVSTAT_INFO(be_rx_compl)},
  63        {DRVSTAT_INFO(be_ethrx_post_fail)},
  64        {DRVSTAT_INFO(be_802_3_dropped_frames)},
  65        {DRVSTAT_INFO(be_802_3_malformed_frames)},
  66        {DRVSTAT_INFO(be_tx_rate)},
  67        {DRVSTAT_INFO(be_rx_rate)},
  68        {PORTSTAT_INFO(rx_unicast_frames)},
  69        {PORTSTAT_INFO(rx_multicast_frames)},
  70        {PORTSTAT_INFO(rx_broadcast_frames)},
  71        {PORTSTAT_INFO(rx_crc_errors)},
  72        {PORTSTAT_INFO(rx_alignment_symbol_errors)},
  73        {PORTSTAT_INFO(rx_pause_frames)},
  74        {PORTSTAT_INFO(rx_control_frames)},
  75        {PORTSTAT_INFO(rx_in_range_errors)},
  76        {PORTSTAT_INFO(rx_out_range_errors)},
  77        {PORTSTAT_INFO(rx_frame_too_long)},
  78        {PORTSTAT_INFO(rx_address_match_errors)},
  79        {PORTSTAT_INFO(rx_vlan_mismatch)},
  80        {PORTSTAT_INFO(rx_dropped_too_small)},
  81        {PORTSTAT_INFO(rx_dropped_too_short)},
  82        {PORTSTAT_INFO(rx_dropped_header_too_small)},
  83        {PORTSTAT_INFO(rx_dropped_tcp_length)},
  84        {PORTSTAT_INFO(rx_dropped_runt)},
  85        {PORTSTAT_INFO(rx_fifo_overflow)},
  86        {PORTSTAT_INFO(rx_input_fifo_overflow)},
  87        {PORTSTAT_INFO(rx_ip_checksum_errs)},
  88        {PORTSTAT_INFO(rx_tcp_checksum_errs)},
  89        {PORTSTAT_INFO(rx_udp_checksum_errs)},
  90        {PORTSTAT_INFO(rx_non_rss_packets)},
  91        {PORTSTAT_INFO(rx_ipv4_packets)},
  92        {PORTSTAT_INFO(rx_ipv6_packets)},
  93        {PORTSTAT_INFO(tx_unicastframes)},
  94        {PORTSTAT_INFO(tx_multicastframes)},
  95        {PORTSTAT_INFO(tx_broadcastframes)},
  96        {PORTSTAT_INFO(tx_pauseframes)},
  97        {PORTSTAT_INFO(tx_controlframes)},
  98        {MISCSTAT_INFO(rx_drops_no_pbuf)},
  99        {MISCSTAT_INFO(rx_drops_no_txpb)},
 100        {MISCSTAT_INFO(rx_drops_no_erx_descr)},
 101        {MISCSTAT_INFO(rx_drops_no_tpre_descr)},
 102        {MISCSTAT_INFO(rx_drops_too_many_frags)},
 103        {MISCSTAT_INFO(rx_drops_invalid_ring)},
 104        {MISCSTAT_INFO(forwarded_packets)},
 105        {MISCSTAT_INFO(rx_drops_mtu)},
 106        {ERXSTAT_INFO(rx_drops_no_fragments)},
 107};
 108#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
 109
 110static void
 111be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
 112{
 113        struct be_adapter *adapter = netdev_priv(netdev);
 114
 115        strcpy(drvinfo->driver, DRV_NAME);
 116        strcpy(drvinfo->version, DRV_VER);
 117        strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
 118        strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
 119        drvinfo->testinfo_len = 0;
 120        drvinfo->regdump_len = 0;
 121        drvinfo->eedump_len = 0;
 122}
 123
 124static int
 125be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
 126{
 127        struct be_adapter *adapter = netdev_priv(netdev);
 128        struct be_eq_obj *rx_eq = &adapter->rx_eq;
 129        struct be_eq_obj *tx_eq = &adapter->tx_eq;
 130
 131        coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
 132        coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
 133        coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
 134
 135        coalesce->tx_coalesce_usecs = tx_eq->cur_eqd;
 136        coalesce->tx_coalesce_usecs_high = tx_eq->max_eqd;
 137        coalesce->tx_coalesce_usecs_low = tx_eq->min_eqd;
 138
 139        coalesce->use_adaptive_rx_coalesce = rx_eq->enable_aic;
 140        coalesce->use_adaptive_tx_coalesce = tx_eq->enable_aic;
 141
 142        return 0;
 143}
 144
 145/*
 146 * This routine is used to set interrup coalescing delay
 147 */
 148static int
 149be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
 150{
 151        struct be_adapter *adapter = netdev_priv(netdev);
 152        struct be_eq_obj *rx_eq = &adapter->rx_eq;
 153        struct be_eq_obj *tx_eq = &adapter->tx_eq;
 154        u32 tx_max, tx_min, tx_cur;
 155        u32 rx_max, rx_min, rx_cur;
 156        int status = 0;
 157
 158        if (coalesce->use_adaptive_tx_coalesce == 1)
 159                return -EINVAL;
 160
 161        /* if AIC is being turned on now, start with an EQD of 0 */
 162        if (rx_eq->enable_aic == 0 &&
 163                coalesce->use_adaptive_rx_coalesce == 1) {
 164                rx_eq->cur_eqd = 0;
 165        }
 166        rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;
 167
 168        rx_max = coalesce->rx_coalesce_usecs_high;
 169        rx_min = coalesce->rx_coalesce_usecs_low;
 170        rx_cur = coalesce->rx_coalesce_usecs;
 171
 172        tx_max = coalesce->tx_coalesce_usecs_high;
 173        tx_min = coalesce->tx_coalesce_usecs_low;
 174        tx_cur = coalesce->tx_coalesce_usecs;
 175
 176        if (tx_cur > BE_MAX_EQD)
 177                tx_cur = BE_MAX_EQD;
 178        if (tx_eq->cur_eqd != tx_cur) {
 179                status = be_cmd_modify_eqd(adapter, tx_eq->q.id, tx_cur);
 180                if (!status)
 181                        tx_eq->cur_eqd = tx_cur;
 182        }
 183
 184        if (rx_eq->enable_aic) {
 185                if (rx_max > BE_MAX_EQD)
 186                        rx_max = BE_MAX_EQD;
 187                if (rx_min > rx_max)
 188                        rx_min = rx_max;
 189                rx_eq->max_eqd = rx_max;
 190                rx_eq->min_eqd = rx_min;
 191                if (rx_eq->cur_eqd > rx_max)
 192                        rx_eq->cur_eqd = rx_max;
 193                if (rx_eq->cur_eqd < rx_min)
 194                        rx_eq->cur_eqd = rx_min;
 195        } else {
 196                if (rx_cur > BE_MAX_EQD)
 197                        rx_cur = BE_MAX_EQD;
 198                if (rx_eq->cur_eqd != rx_cur) {
 199                        status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
 200                                        rx_cur);
 201                        if (!status)
 202                                rx_eq->cur_eqd = rx_cur;
 203                }
 204        }
 205        return 0;
 206}
 207
 208static u32 be_get_rx_csum(struct net_device *netdev)
 209{
 210        struct be_adapter *adapter = netdev_priv(netdev);
 211
 212        return adapter->rx_csum;
 213}
 214
 215static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
 216{
 217        struct be_adapter *adapter = netdev_priv(netdev);
 218
 219        if (data)
 220                adapter->rx_csum = true;
 221        else
 222                adapter->rx_csum = false;
 223
 224        return 0;
 225}
 226
 227static void
 228be_get_ethtool_stats(struct net_device *netdev,
 229                struct ethtool_stats *stats, uint64_t *data)
 230{
 231        struct be_adapter *adapter = netdev_priv(netdev);
 232        struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats;
 233        struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
 234        struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
 235        struct be_port_rxf_stats *port_stats =
 236                        &rxf_stats->port[adapter->port_num];
 237        struct net_device_stats *net_stats = &adapter->stats.net_stats;
 238        struct be_erx_stats *erx_stats = &hw_stats->erx;
 239        void *p = NULL;
 240        int i;
 241
 242        for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
 243                switch (et_stats[i].type) {
 244                case NETSTAT:
 245                        p = net_stats;
 246                        break;
 247                case DRVSTAT:
 248                        p = drvr_stats;
 249                        break;
 250                case PORTSTAT:
 251                        p = port_stats;
 252                        break;
 253                case MISCSTAT:
 254                        p = rxf_stats;
 255                        break;
 256                case ERXSTAT: /* Currently only one ERX stat is provided */
 257                        p = (u32 *)erx_stats + adapter->rx_obj.q.id;
 258                        break;
 259                }
 260
 261                p = (u8 *)p + et_stats[i].offset;
 262                data[i] = (et_stats[i].size == sizeof(u64)) ?
 263                                *(u64 *)p: *(u32 *)p;
 264        }
 265
 266        return;
 267}
 268
 269static void
 270be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
 271                uint8_t *data)
 272{
 273        int i;
 274        switch (stringset) {
 275        case ETH_SS_STATS:
 276                for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
 277                        memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
 278                        data += ETH_GSTRING_LEN;
 279                }
 280                break;
 281        }
 282}
 283
 284static int be_get_stats_count(struct net_device *netdev)
 285{
 286        return ETHTOOL_STATS_NUM;
 287}
 288
 289static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 290{
 291        ecmd->speed = SPEED_10000;
 292        ecmd->duplex = DUPLEX_FULL;
 293        ecmd->autoneg = AUTONEG_DISABLE;
 294        return 0;
 295}
 296
 297static void
 298be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
 299{
 300        struct be_adapter *adapter = netdev_priv(netdev);
 301
 302        ring->rx_max_pending = adapter->rx_obj.q.len;
 303        ring->tx_max_pending = adapter->tx_obj.q.len;
 304
 305        ring->rx_pending = atomic_read(&adapter->rx_obj.q.used);
 306        ring->tx_pending = atomic_read(&adapter->tx_obj.q.used);
 307}
 308
 309static void
 310be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
 311{
 312        struct be_adapter *adapter = netdev_priv(netdev);
 313
 314        be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause);
 315        ecmd->autoneg = 0;
 316}
 317
 318static int
 319be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
 320{
 321        struct be_adapter *adapter = netdev_priv(netdev);
 322        int status;
 323
 324        if (ecmd->autoneg != 0)
 325                return -EINVAL;
 326        adapter->tx_fc = ecmd->tx_pause;
 327        adapter->rx_fc = ecmd->rx_pause;
 328
 329        status = be_cmd_set_flow_control(adapter,
 330                                        adapter->tx_fc, adapter->rx_fc);
 331        if (status)
 332                dev_warn(&adapter->pdev->dev, "Pause param set failed.\n");
 333
 334        return status;
 335}
 336
 337static int
 338be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
 339{
 340        struct be_adapter *adapter = netdev_priv(netdev);
 341        char file_name[ETHTOOL_FLASH_MAX_FILENAME];
 342        u32 region;
 343
 344        file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
 345        strcpy(file_name, efl->data);
 346        region = efl->region;
 347
 348        return be_load_fw(adapter, file_name);
 349}
 350
 351const struct ethtool_ops be_ethtool_ops = {
 352        .get_settings = be_get_settings,
 353        .get_drvinfo = be_get_drvinfo,
 354        .get_link = ethtool_op_get_link,
 355        .get_coalesce = be_get_coalesce,
 356        .set_coalesce = be_set_coalesce,
 357        .get_ringparam = be_get_ringparam,
 358        .get_pauseparam = be_get_pauseparam,
 359        .set_pauseparam = be_set_pauseparam,
 360        .get_rx_csum = be_get_rx_csum,
 361        .set_rx_csum = be_set_rx_csum,
 362        .get_tx_csum = ethtool_op_get_tx_csum,
 363        .set_tx_csum = ethtool_op_set_tx_hw_csum,
 364        .get_sg = ethtool_op_get_sg,
 365        .set_sg = ethtool_op_set_sg,
 366        .get_tso = ethtool_op_get_tso,
 367        .set_tso = ethtool_op_set_tso,
 368        .get_strings = be_get_stat_strings,
 369        .get_stats_count = be_get_stats_count,
 370        .get_ethtool_stats = be_get_ethtool_stats,
 371        .flash_device = be_do_flash,
 372};
 373