1 #include <linux/netdevice.h>
2 #include <linux/ethtool.h>
3 #include <linux/delay.h>
13 static const char * mesh_stat_strings
[]= {
14 "drop_duplicate_bcast",
24 static void lbs_ethtool_get_drvinfo(struct net_device
*dev
,
25 struct ethtool_drvinfo
*info
)
27 struct lbs_private
*priv
= (struct lbs_private
*) dev
->priv
;
30 lbs_get_fwversion(priv
, fwver
, sizeof(fwver
) - 1);
32 strcpy(info
->driver
, "libertas");
33 strcpy(info
->version
, lbs_driver_version
);
34 strcpy(info
->fw_version
, fwver
);
37 /* All 8388 parts have 16KiB EEPROM size at the time of writing.
38 * In case that changes this needs fixing.
40 #define LBS_EEPROM_LEN 16384
42 static int lbs_ethtool_get_eeprom_len(struct net_device
*dev
)
44 return LBS_EEPROM_LEN
;
47 static int lbs_ethtool_get_eeprom(struct net_device
*dev
,
48 struct ethtool_eeprom
*eeprom
, u8
* bytes
)
50 struct lbs_private
*priv
= (struct lbs_private
*) dev
->priv
;
51 struct lbs_ioctl_regrdwr regctrl
;
56 regctrl
.offset
= eeprom
->offset
;
57 regctrl
.NOB
= eeprom
->len
;
59 if (eeprom
->offset
+ eeprom
->len
> LBS_EEPROM_LEN
)
62 // mutex_lock(&priv->mutex);
64 priv
->prdeeprom
= kmalloc(eeprom
->len
+sizeof(regctrl
), GFP_KERNEL
);
67 memcpy(priv
->prdeeprom
, ®ctrl
, sizeof(regctrl
));
69 /* +14 is for action, offset, and NOB in
71 lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n",
72 regctrl
.action
, regctrl
.offset
, regctrl
.NOB
);
74 ret
= lbs_prepare_and_send_command(priv
,
75 CMD_802_11_EEPROM_ACCESS
,
77 CMD_OPTION_WAITFORRSP
, 0,
82 kfree(priv
->prdeeprom
);
88 ptr
= (char *)priv
->prdeeprom
;
90 /* skip the command header, but include the "value" u32 variable */
91 ptr
= ptr
+ sizeof(struct lbs_ioctl_regrdwr
) - 4;
94 * Return the result back to the user
96 memcpy(bytes
, ptr
, eeprom
->len
);
99 kfree(priv
->prdeeprom
);
100 // mutex_unlock(&priv->mutex);
105 lbs_deb_enter_args(LBS_DEB_ETHTOOL
, "ret %d", ret
);
109 static void lbs_ethtool_get_stats(struct net_device
* dev
,
110 struct ethtool_stats
* stats
, u64
* data
)
112 struct lbs_private
*priv
= dev
->priv
;
113 struct cmd_ds_mesh_access mesh_access
;
116 lbs_deb_enter(LBS_DEB_ETHTOOL
);
118 /* Get Mesh Statistics */
119 ret
= lbs_prepare_and_send_command(priv
,
120 CMD_MESH_ACCESS
, CMD_ACT_MESH_GET_STATS
,
121 CMD_OPTION_WAITFORRSP
, 0, &mesh_access
);
126 priv
->mstats
.fwd_drop_rbt
= le32_to_cpu(mesh_access
.data
[0]);
127 priv
->mstats
.fwd_drop_ttl
= le32_to_cpu(mesh_access
.data
[1]);
128 priv
->mstats
.fwd_drop_noroute
= le32_to_cpu(mesh_access
.data
[2]);
129 priv
->mstats
.fwd_drop_nobuf
= le32_to_cpu(mesh_access
.data
[3]);
130 priv
->mstats
.fwd_unicast_cnt
= le32_to_cpu(mesh_access
.data
[4]);
131 priv
->mstats
.fwd_bcast_cnt
= le32_to_cpu(mesh_access
.data
[5]);
132 priv
->mstats
.drop_blind
= le32_to_cpu(mesh_access
.data
[6]);
133 priv
->mstats
.tx_failed_cnt
= le32_to_cpu(mesh_access
.data
[7]);
135 data
[0] = priv
->mstats
.fwd_drop_rbt
;
136 data
[1] = priv
->mstats
.fwd_drop_ttl
;
137 data
[2] = priv
->mstats
.fwd_drop_noroute
;
138 data
[3] = priv
->mstats
.fwd_drop_nobuf
;
139 data
[4] = priv
->mstats
.fwd_unicast_cnt
;
140 data
[5] = priv
->mstats
.fwd_bcast_cnt
;
141 data
[6] = priv
->mstats
.drop_blind
;
142 data
[7] = priv
->mstats
.tx_failed_cnt
;
144 lbs_deb_enter(LBS_DEB_ETHTOOL
);
147 static int lbs_ethtool_get_sset_count(struct net_device
* dev
, int sset
)
151 return MESH_STATS_NUM
;
157 static void lbs_ethtool_get_strings(struct net_device
*dev
,
163 lbs_deb_enter(LBS_DEB_ETHTOOL
);
167 for (i
=0; i
< MESH_STATS_NUM
; i
++) {
168 memcpy(s
+ i
* ETH_GSTRING_LEN
,
169 mesh_stat_strings
[i
],
174 lbs_deb_enter(LBS_DEB_ETHTOOL
);
177 static void lbs_ethtool_get_wol(struct net_device
*dev
,
178 struct ethtool_wolinfo
*wol
)
180 struct lbs_private
*priv
= dev
->priv
;
182 if (priv
->wol_criteria
== 0xffffffff) {
183 /* Interface driver didn't configure wake */
184 wol
->supported
= wol
->wolopts
= 0;
188 wol
->supported
= WAKE_UCAST
|WAKE_MCAST
|WAKE_BCAST
|WAKE_PHY
;
190 if (priv
->wol_criteria
& EHS_WAKE_ON_UNICAST_DATA
)
191 wol
->wolopts
|= WAKE_UCAST
;
192 if (priv
->wol_criteria
& EHS_WAKE_ON_MULTICAST_DATA
)
193 wol
->wolopts
|= WAKE_MCAST
;
194 if (priv
->wol_criteria
& EHS_WAKE_ON_BROADCAST_DATA
)
195 wol
->wolopts
|= WAKE_BCAST
;
196 if (priv
->wol_criteria
& EHS_WAKE_ON_MAC_EVENT
)
197 wol
->wolopts
|= WAKE_PHY
;
200 static int lbs_ethtool_set_wol(struct net_device
*dev
,
201 struct ethtool_wolinfo
*wol
)
203 struct lbs_private
*priv
= dev
->priv
;
204 uint32_t criteria
= 0;
206 if (priv
->wol_criteria
== 0xffffffff && wol
->wolopts
)
209 if (wol
->wolopts
& ~(WAKE_UCAST
|WAKE_MCAST
|WAKE_BCAST
|WAKE_PHY
))
212 if (wol
->wolopts
& WAKE_UCAST
) criteria
|= EHS_WAKE_ON_UNICAST_DATA
;
213 if (wol
->wolopts
& WAKE_MCAST
) criteria
|= EHS_WAKE_ON_MULTICAST_DATA
;
214 if (wol
->wolopts
& WAKE_BCAST
) criteria
|= EHS_WAKE_ON_BROADCAST_DATA
;
215 if (wol
->wolopts
& WAKE_PHY
) criteria
|= EHS_WAKE_ON_MAC_EVENT
;
217 return lbs_host_sleep_cfg(priv
, criteria
);
220 struct ethtool_ops lbs_ethtool_ops
= {
221 .get_drvinfo
= lbs_ethtool_get_drvinfo
,
222 .get_eeprom
= lbs_ethtool_get_eeprom
,
223 .get_eeprom_len
= lbs_ethtool_get_eeprom_len
,
224 .get_sset_count
= lbs_ethtool_get_sset_count
,
225 .get_ethtool_stats
= lbs_ethtool_get_stats
,
226 .get_strings
= lbs_ethtool_get_strings
,
227 .get_wol
= lbs_ethtool_get_wol
,
228 .set_wol
= lbs_ethtool_set_wol
,