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 "join.h" 10#include "wext.h" 11static const char * mesh_stat_strings[]= { 12 "drop_duplicate_bcast", 13 "drop_ttl_zero", 14 "drop_no_fwd_route", 15 "drop_no_buffers", 16 "fwded_unicast_cnt", 17 "fwded_bcast_cnt", 18 "drop_blind_table", 19 "tx_failed_cnt" 20}; 21 22static void libertas_ethtool_get_drvinfo(struct net_device *dev, 23 struct ethtool_drvinfo *info) 24{ 25 wlan_private *priv = (wlan_private *) dev->priv; 26 char fwver[32]; 27 28 libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1); 29 30 strcpy(info->driver, "libertas"); 31 strcpy(info->version, libertas_driver_version); 32 strcpy(info->fw_version, fwver); 33} 34 35/* All 8388 parts have 16KiB EEPROM size at the time of writing. 36 * In case that changes this needs fixing. 37 */ 38#define LIBERTAS_EEPROM_LEN 16384 39 40static int libertas_ethtool_get_eeprom_len(struct net_device *dev) 41{ 42 return LIBERTAS_EEPROM_LEN; 43} 44 45static int libertas_ethtool_get_eeprom(struct net_device *dev, 46 struct ethtool_eeprom *eeprom, u8 * bytes) 47{ 48 wlan_private *priv = (wlan_private *) dev->priv; 49 wlan_adapter *adapter = priv->adapter; 50 struct wlan_ioctl_regrdwr regctrl; 51 char *ptr; 52 int ret; 53 54 regctrl.action = 0; 55 regctrl.offset = eeprom->offset; 56 regctrl.NOB = eeprom->len; 57 58 if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN) 59 return -EINVAL; 60 61// mutex_lock(&priv->mutex); 62 63 adapter->prdeeprom = 64 (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); 65 if (!adapter->prdeeprom) 66 return -ENOMEM; 67 memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); 68 69 /* +14 is for action, offset, and NOB in 70 * response */ 71 lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n", 72 regctrl.action, regctrl.offset, regctrl.NOB); 73 74 ret = libertas_prepare_and_send_command(priv, 75 cmd_802_11_eeprom_access, 76 regctrl.action, 77 cmd_option_waitforrsp, 0, 78 ®ctrl); 79 80 if (ret) { 81 if (adapter->prdeeprom) 82 kfree(adapter->prdeeprom); 83 goto done; 84 } 85 86 mdelay(10); 87 88 ptr = (char *)adapter->prdeeprom; 89 90 /* skip the command header, but include the "value" u32 variable */ 91 ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4; 92 93 /* 94 * Return the result back to the user 95 */ 96 memcpy(bytes, ptr, eeprom->len); 97 98 if (adapter->prdeeprom) 99 kfree(adapter->prdeeprom); 100// mutex_unlock(&priv->mutex); 101 102 ret = 0; 103 104done: 105 lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret); 106 return ret; 107} 108 109static void libertas_ethtool_get_stats(struct net_device * dev, 110 struct ethtool_stats * stats, u64 * data) 111{ 112 wlan_private *priv = dev->priv; 113 114 lbs_deb_enter(LBS_DEB_ETHTOOL); 115 116 stats->cmd = ETHTOOL_GSTATS; 117 BUG_ON(stats->n_stats != MESH_STATS_NUM); 118 119 data[0] = priv->mstats.fwd_drop_rbt; 120 data[1] = priv->mstats.fwd_drop_ttl; 121 data[2] = priv->mstats.fwd_drop_noroute; 122 data[3] = priv->mstats.fwd_drop_nobuf; 123 data[4] = priv->mstats.fwd_unicast_cnt; 124 data[5] = priv->mstats.fwd_bcast_cnt; 125 data[6] = priv->mstats.drop_blind; 126 data[7] = priv->mstats.tx_failed_cnt; 127 128 lbs_deb_enter(LBS_DEB_ETHTOOL); 129} 130 131static int libertas_ethtool_get_stats_count(struct net_device * dev) 132{ 133 int ret; 134 wlan_private *priv = dev->priv; 135 struct cmd_ds_mesh_access mesh_access; 136 137 lbs_deb_enter(LBS_DEB_ETHTOOL); 138 139 /* Get Mesh Statistics */ 140 ret = libertas_prepare_and_send_command(priv, 141 cmd_mesh_access, cmd_act_mesh_get_stats, 142 cmd_option_waitforrsp, 0, &mesh_access); 143 144 if (ret) { 145 ret = 0; 146 goto done; 147 } 148 149 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); 150 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); 151 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); 152 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); 153 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); 154 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); 155 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); 156 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); 157 158 ret = MESH_STATS_NUM; 159 160done: 161 lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret); 162 return ret; 163} 164 165static void libertas_ethtool_get_strings (struct net_device * dev, 166 u32 stringset, 167 u8 * s) 168{ 169 int i; 170 171 lbs_deb_enter(LBS_DEB_ETHTOOL); 172 173 switch (stringset) { 174 case ETH_SS_STATS: 175 for (i=0; i < MESH_STATS_NUM; i++) { 176 memcpy(s + i * ETH_GSTRING_LEN, 177 mesh_stat_strings[i], 178 ETH_GSTRING_LEN); 179 } 180 break; 181 } 182 lbs_deb_enter(LBS_DEB_ETHTOOL); 183} 184 185struct ethtool_ops libertas_ethtool_ops = { 186 .get_drvinfo = libertas_ethtool_get_drvinfo, 187 .get_eeprom = libertas_ethtool_get_eeprom, 188 .get_eeprom_len = libertas_ethtool_get_eeprom_len, 189 .get_stats_count = libertas_ethtool_get_stats_count, 190 .get_ethtool_stats = libertas_ethtool_get_stats, 191 .get_strings = libertas_ethtool_get_strings, 192}; 193