linux/drivers/net/wireless/libertas/ethtool.c
<<
>>
Prefs
   1#include <linux/netdevice.h>
   2#include <linux/ethtool.h>
   3#include <linux/delay.h>
   4
   5#include "host.h"
   6#include "decl.h"
   7#include "defs.h"
   8#include "dev.h"
   9#include "wext.h"
  10#include "cmd.h"
  11
  12static const char * mesh_stat_strings[]= {
  13                        "drop_duplicate_bcast",
  14                        "drop_ttl_zero",
  15                        "drop_no_fwd_route",
  16                        "drop_no_buffers",
  17                        "fwded_unicast_cnt",
  18                        "fwded_bcast_cnt",
  19                        "drop_blind_table",
  20                        "tx_failed_cnt"
  21};
  22
  23static void lbs_ethtool_get_drvinfo(struct net_device *dev,
  24                                         struct ethtool_drvinfo *info)
  25{
  26        struct lbs_private *priv = dev->ml_priv;
  27
  28        snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
  29                priv->fwrelease >> 24 & 0xff,
  30                priv->fwrelease >> 16 & 0xff,
  31                priv->fwrelease >>  8 & 0xff,
  32                priv->fwrelease       & 0xff);
  33        strcpy(info->driver, "libertas");
  34        strcpy(info->version, lbs_driver_version);
  35}
  36
  37/* All 8388 parts have 16KiB EEPROM size at the time of writing.
  38 * In case that changes this needs fixing.
  39 */
  40#define LBS_EEPROM_LEN 16384
  41
  42static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
  43{
  44        return LBS_EEPROM_LEN;
  45}
  46
  47static int lbs_ethtool_get_eeprom(struct net_device *dev,
  48                                  struct ethtool_eeprom *eeprom, u8 * bytes)
  49{
  50        struct lbs_private *priv = dev->ml_priv;
  51        struct cmd_ds_802_11_eeprom_access cmd;
  52        int ret;
  53
  54        lbs_deb_enter(LBS_DEB_ETHTOOL);
  55
  56        if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN ||
  57            eeprom->len > LBS_EEPROM_READ_LEN) {
  58                ret = -EINVAL;
  59                goto out;
  60        }
  61
  62        cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) -
  63                LBS_EEPROM_READ_LEN + eeprom->len);
  64        cmd.action = cpu_to_le16(CMD_ACT_GET);
  65        cmd.offset = cpu_to_le16(eeprom->offset);
  66        cmd.len    = cpu_to_le16(eeprom->len);
  67        ret = lbs_cmd_with_response(priv, CMD_802_11_EEPROM_ACCESS, &cmd);
  68        if (!ret)
  69                memcpy(bytes, cmd.value, eeprom->len);
  70
  71out:
  72        lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret);
  73        return ret;
  74}
  75
  76static void lbs_ethtool_get_stats(struct net_device *dev,
  77                                  struct ethtool_stats *stats, uint64_t *data)
  78{
  79        struct lbs_private *priv = dev->ml_priv;
  80        struct cmd_ds_mesh_access mesh_access;
  81        int ret;
  82
  83        lbs_deb_enter(LBS_DEB_ETHTOOL);
  84
  85        /* Get Mesh Statistics */
  86        ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
  87
  88        if (ret) {
  89                memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
  90                return;
  91        }
  92
  93        priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
  94        priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
  95        priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
  96        priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
  97        priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
  98        priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
  99        priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
 100        priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
 101
 102        data[0] = priv->mstats.fwd_drop_rbt;
 103        data[1] = priv->mstats.fwd_drop_ttl;
 104        data[2] = priv->mstats.fwd_drop_noroute;
 105        data[3] = priv->mstats.fwd_drop_nobuf;
 106        data[4] = priv->mstats.fwd_unicast_cnt;
 107        data[5] = priv->mstats.fwd_bcast_cnt;
 108        data[6] = priv->mstats.drop_blind;
 109        data[7] = priv->mstats.tx_failed_cnt;
 110
 111        lbs_deb_enter(LBS_DEB_ETHTOOL);
 112}
 113
 114static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
 115{
 116        struct lbs_private *priv = dev->ml_priv;
 117
 118        if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
 119                return MESH_STATS_NUM;
 120
 121        return -EOPNOTSUPP;
 122}
 123
 124static void lbs_ethtool_get_strings(struct net_device *dev,
 125                                    uint32_t stringset, uint8_t *s)
 126{
 127        int i;
 128
 129        lbs_deb_enter(LBS_DEB_ETHTOOL);
 130
 131        switch (stringset) {
 132        case ETH_SS_STATS:
 133                for (i=0; i < MESH_STATS_NUM; i++) {
 134                        memcpy(s + i * ETH_GSTRING_LEN,
 135                                        mesh_stat_strings[i],
 136                                        ETH_GSTRING_LEN);
 137                }
 138                break;
 139        }
 140        lbs_deb_enter(LBS_DEB_ETHTOOL);
 141}
 142
 143static void lbs_ethtool_get_wol(struct net_device *dev,
 144                                struct ethtool_wolinfo *wol)
 145{
 146        struct lbs_private *priv = dev->ml_priv;
 147
 148        if (priv->wol_criteria == 0xffffffff) {
 149                /* Interface driver didn't configure wake */
 150                wol->supported = wol->wolopts = 0;
 151                return;
 152        }
 153
 154        wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
 155
 156        if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
 157                wol->wolopts |= WAKE_UCAST;
 158        if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
 159                wol->wolopts |= WAKE_MCAST;
 160        if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA)
 161                wol->wolopts |= WAKE_BCAST;
 162        if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT)
 163                wol->wolopts |= WAKE_PHY;
 164}
 165
 166static int lbs_ethtool_set_wol(struct net_device *dev,
 167                               struct ethtool_wolinfo *wol)
 168{
 169        struct lbs_private *priv = dev->ml_priv;
 170        uint32_t criteria = 0;
 171
 172        if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
 173                return -EOPNOTSUPP;
 174
 175        if (wol->wolopts & WAKE_UCAST)
 176                criteria |= EHS_WAKE_ON_UNICAST_DATA;
 177        if (wol->wolopts & WAKE_MCAST)
 178                criteria |= EHS_WAKE_ON_MULTICAST_DATA;
 179        if (wol->wolopts & WAKE_BCAST)
 180                criteria |= EHS_WAKE_ON_BROADCAST_DATA;
 181        if (wol->wolopts & WAKE_PHY)
 182                criteria |= EHS_WAKE_ON_MAC_EVENT;
 183        if (wol->wolopts == 0)
 184                criteria |= EHS_REMOVE_WAKEUP;
 185
 186        return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
 187}
 188
 189const struct ethtool_ops lbs_ethtool_ops = {
 190        .get_drvinfo = lbs_ethtool_get_drvinfo,
 191        .get_eeprom =  lbs_ethtool_get_eeprom,
 192        .get_eeprom_len = lbs_ethtool_get_eeprom_len,
 193        .get_sset_count = lbs_ethtool_get_sset_count,
 194        .get_ethtool_stats = lbs_ethtool_get_stats,
 195        .get_strings = lbs_ethtool_get_strings,
 196        .get_wol = lbs_ethtool_get_wol,
 197        .set_wol = lbs_ethtool_set_wol,
 198};
 199
 200