Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[linux-2.6] / drivers / net / wireless / libertas / ethtool.c
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"
11 static 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
22 static 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
40 static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
41 {
42         return LIBERTAS_EEPROM_LEN;
43 }
44
45 static 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 = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
64         if (!adapter->prdeeprom)
65                 return -ENOMEM;
66         memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
67
68         /* +14 is for action, offset, and NOB in
69          * response */
70         lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n",
71                regctrl.action, regctrl.offset, regctrl.NOB);
72
73         ret = libertas_prepare_and_send_command(priv,
74                                     CMD_802_11_EEPROM_ACCESS,
75                                     regctrl.action,
76                                     CMD_OPTION_WAITFORRSP, 0,
77                                     &regctrl);
78
79         if (ret) {
80                 if (adapter->prdeeprom)
81                         kfree(adapter->prdeeprom);
82                 goto done;
83         }
84
85         mdelay(10);
86
87         ptr = (char *)adapter->prdeeprom;
88
89         /* skip the command header, but include the "value" u32 variable */
90         ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
91
92         /*
93          * Return the result back to the user
94          */
95         memcpy(bytes, ptr, eeprom->len);
96
97         if (adapter->prdeeprom)
98                 kfree(adapter->prdeeprom);
99 //      mutex_unlock(&priv->mutex);
100
101         ret = 0;
102
103 done:
104         lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
105         return ret;
106 }
107
108 static void libertas_ethtool_get_stats(struct net_device * dev,
109                                 struct ethtool_stats * stats, u64 * data)
110 {
111         wlan_private *priv = dev->priv;
112         struct cmd_ds_mesh_access mesh_access;
113         int ret;
114
115         lbs_deb_enter(LBS_DEB_ETHTOOL);
116
117         /* Get Mesh Statistics */
118         ret = libertas_prepare_and_send_command(priv,
119                         CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
120                         CMD_OPTION_WAITFORRSP, 0, &mesh_access);
121
122         if (ret)
123                 return;
124
125         priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
126         priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
127         priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
128         priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
129         priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
130         priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
131         priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
132         priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
133
134         data[0] = priv->mstats.fwd_drop_rbt;
135         data[1] = priv->mstats.fwd_drop_ttl;
136         data[2] = priv->mstats.fwd_drop_noroute;
137         data[3] = priv->mstats.fwd_drop_nobuf;
138         data[4] = priv->mstats.fwd_unicast_cnt;
139         data[5] = priv->mstats.fwd_bcast_cnt;
140         data[6] = priv->mstats.drop_blind;
141         data[7] = priv->mstats.tx_failed_cnt;
142
143         lbs_deb_enter(LBS_DEB_ETHTOOL);
144 }
145
146 static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset)
147 {
148         switch (sset) {
149         case ETH_SS_STATS:
150                 return MESH_STATS_NUM;
151         default:
152                 return -EOPNOTSUPP;
153         }
154 }
155
156 static void libertas_ethtool_get_strings (struct net_device * dev,
157                                           u32 stringset,
158                                           u8 * s)
159 {
160         int i;
161
162         lbs_deb_enter(LBS_DEB_ETHTOOL);
163
164         switch (stringset) {
165         case ETH_SS_STATS:
166                 for (i=0; i < MESH_STATS_NUM; i++) {
167                         memcpy(s + i * ETH_GSTRING_LEN,
168                                         mesh_stat_strings[i],
169                                         ETH_GSTRING_LEN);
170                 }
171                 break;
172         }
173         lbs_deb_enter(LBS_DEB_ETHTOOL);
174 }
175
176 struct ethtool_ops libertas_ethtool_ops = {
177         .get_drvinfo = libertas_ethtool_get_drvinfo,
178         .get_eeprom =  libertas_ethtool_get_eeprom,
179         .get_eeprom_len = libertas_ethtool_get_eeprom_len,
180         .get_sset_count = libertas_ethtool_get_sset_count,
181         .get_ethtool_stats = libertas_ethtool_get_stats,
182         .get_strings = libertas_ethtool_get_strings,
183 };
184