1 /******************************************************************************/
3 /* bypass library, Copyright (c) 2004-2007 Silicom, Ltd */
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation, located in the file LICENSE. */
12 /******************************************************************************/
14 #if defined(CONFIG_SMP) && !defined(__SMP__)
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <asm/unistd.h>
22 #include <linux/sched.h>
23 #include <linux/wait.h>
25 #include <linux/netdevice.h> /* struct device, and other headers */
26 #include <linux/kernel_stat.h>
27 #include <linux/pci.h>
28 #include <linux/rtnetlink.h>
29 #include <linux/ethtool.h>
31 #include <net/net_namespace.h>
35 #define MOD_NAME "bypass"
37 #define VERSION "\n"MOD_NAME" version 9.0.4\n"
39 MODULE_AUTHOR("www.silicom.co.il");
41 MODULE_LICENSE("GPL");
43 static int do_cmd(struct net_device
*dev
, struct ifreq
*ifr
, int cmd
, int *data
)
46 struct if_bypass
*bypass_cb
;
48 bypass_cb
= (struct if_bypass
*)ifr
;
50 bypass_cb
->data
= *data
;
52 if (dev
->netdev_ops
&& dev
->netdev_ops
->ndo_do_ioctl
) {
53 ret
= dev
->netdev_ops
->ndo_do_ioctl(dev
, ifr
, SIOCGIFBYPASS
);
54 *data
= bypass_cb
->data
;
60 static int doit(int cmd
, int if_index
, int *data
)
64 struct net_device
*dev
;
67 for_each_netdev_safe(&init_net
, dev
, n
) {
68 if (dev
->ifindex
== if_index
) {
69 ret
= do_cmd(dev
, &ifr
, cmd
, data
);
78 #define bp_symbol_get(fn_name) symbol_get(fn_name)
79 #define bp_symbol_put(fn_name) symbol_put(fn_name)
81 #define SET_BPLIB_INT_FN(fn_name, arg_type, arg, ret) \
82 ({ int (*fn_ex)(arg_type) = NULL; \
83 fn_ex = bp_symbol_get(fn_name##_sd); \
86 bp_symbol_put(fn_name##_sd); \
92 #define SET_BPLIB_INT_FN2(fn_name, arg_type, arg, arg_type1, arg1, ret)\
93 ({ int (*fn_ex)(arg_type, arg_type1) = NULL; \
94 fn_ex = bp_symbol_get(fn_name##_sd); \
96 ret = fn_ex(arg, arg1); \
97 bp_symbol_put(fn_name##_sd); \
103 #define SET_BPLIB_INT_FN3(fn_name, arg_type, arg, arg_type1, arg1, \
104 arg_type2, arg2, ret) \
105 ({ int (*fn_ex)(arg_type, arg_type1, arg_type2) = NULL; \
106 fn_ex = bp_symbol_get(fn_name##_sd); \
108 ret = fn_ex(arg, arg1, arg2); \
109 bp_symbol_put(fn_name##_sd); \
115 #define DO_BPLIB_GET_ARG_FN(fn_name, ioctl_val, if_index) \
116 ({ int data, ret = 0; \
117 if (is_dev_sd(if_index)) { \
118 SET_BPLIB_INT_FN(fn_name, int, if_index, ret); \
121 return doit(ioctl_val, if_index, &data); \
124 #define DO_BPLIB_SET_ARG_FN(fn_name, ioctl_val, if_index, arg) \
125 ({ int data, ret = 0; \
126 if (is_dev_sd(if_index)) { \
127 SET_BPLIB_INT_FN2(fn_name, int, if_index, int, \
132 return doit(ioctl_val, if_index, &data); \
135 static int is_dev_sd(int if_index
)
139 SET_BPLIB_INT_FN(is_bypass
, int, if_index
, ret
);
140 return ret
>= 0 ? 1 : 0;
143 static int is_bypass_dev(int if_index
)
145 struct pci_dev
*pdev
= NULL
;
146 struct net_device
*dev
= NULL
;
151 while ((pdev
= pci_get_class(PCI_CLASS_NETWORK_ETHERNET
<< 8, pdev
))) {
152 dev
= pci_get_drvdata(pdev
);
153 if ((dev
!= NULL
) && (dev
->ifindex
== if_index
)) {
154 if ((pdev
->vendor
== SILICOM_VID
) &&
155 (pdev
->device
>= SILICOM_BP_PID_MIN
) &&
156 (pdev
->device
<= SILICOM_BP_PID_MAX
)) {
159 #if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO)
161 struct ethtool_drvinfo info
;
162 const struct ethtool_ops
*ops
=
166 if (ops
->get_drvinfo
) {
167 memset(&info
, 0, sizeof(info
));
168 info
.cmd
= ETHTOOL_GDRVINFO
;
169 ops
->get_drvinfo(dev
, &info
);
170 for (; bp_desc_array
[k
]; k
++)
171 if (!(strcmp(bp_desc_array
[k
],
183 ret
= do_cmd(dev
, &ifr
, IS_BYPASS
, &data
);
184 return ret
< 0 ? -1 : ret
;
187 static int is_bypass(int if_index
)
191 SET_BPLIB_INT_FN(is_bypass
, int, if_index
, ret
);
194 return is_bypass_dev(if_index
);
197 EXPORT_SYMBOL(is_bypass
);
199 static int get_bypass_slave(int if_index
)
201 DO_BPLIB_GET_ARG_FN(get_bypass_slave
, GET_BYPASS_SLAVE
, if_index
);
203 EXPORT_SYMBOL(get_bypass_slave
);
205 static int get_bypass_caps(int if_index
)
207 DO_BPLIB_GET_ARG_FN(get_bypass_caps
, GET_BYPASS_CAPS
, if_index
);
209 EXPORT_SYMBOL(get_bypass_caps
);
211 static int get_wd_set_caps(int if_index
)
213 DO_BPLIB_GET_ARG_FN(get_wd_set_caps
, GET_WD_SET_CAPS
, if_index
);
215 EXPORT_SYMBOL(get_wd_set_caps
);
217 static int set_bypass(int if_index
, int bypass_mode
)
219 DO_BPLIB_SET_ARG_FN(set_bypass
, SET_BYPASS
, if_index
, bypass_mode
);
221 EXPORT_SYMBOL(set_bypass
);
223 static int get_bypass(int if_index
)
225 DO_BPLIB_GET_ARG_FN(get_bypass
, GET_BYPASS
, if_index
);
227 EXPORT_SYMBOL(get_bypass
);
229 static int get_bypass_change(int if_index
)
231 DO_BPLIB_GET_ARG_FN(get_bypass_change
, GET_BYPASS_CHANGE
, if_index
);
233 EXPORT_SYMBOL(get_bypass_change
);
235 static int set_dis_bypass(int if_index
, int dis_bypass
)
237 DO_BPLIB_SET_ARG_FN(set_dis_bypass
, SET_DIS_BYPASS
, if_index
,
240 EXPORT_SYMBOL(set_dis_bypass
);
242 static int get_dis_bypass(int if_index
)
244 DO_BPLIB_GET_ARG_FN(get_dis_bypass
, GET_DIS_BYPASS
, if_index
);
246 EXPORT_SYMBOL(get_dis_bypass
);
248 static int set_bypass_pwoff(int if_index
, int bypass_mode
)
250 DO_BPLIB_SET_ARG_FN(set_bypass_pwoff
, SET_BYPASS_PWOFF
, if_index
,
253 EXPORT_SYMBOL(set_bypass_pwoff
);
255 static int get_bypass_pwoff(int if_index
)
257 DO_BPLIB_GET_ARG_FN(get_bypass_pwoff
, GET_BYPASS_PWOFF
, if_index
);
259 EXPORT_SYMBOL(get_bypass_pwoff
);
261 static int set_bypass_pwup(int if_index
, int bypass_mode
)
263 DO_BPLIB_SET_ARG_FN(set_bypass_pwup
, SET_BYPASS_PWUP
, if_index
,
266 EXPORT_SYMBOL(set_bypass_pwup
);
268 static int get_bypass_pwup(int if_index
)
270 DO_BPLIB_GET_ARG_FN(get_bypass_pwup
, GET_BYPASS_PWUP
, if_index
);
272 EXPORT_SYMBOL(get_bypass_pwup
);
274 static int set_bypass_wd(int if_index
, int ms_timeout
, int *ms_timeout_set
)
276 int data
= ms_timeout
;
279 if (is_dev_sd(if_index
)) {
280 SET_BPLIB_INT_FN3(set_bypass_wd
, int, if_index
, int, ms_timeout
,
281 int *, ms_timeout_set
, ret
);
283 ret
= doit(SET_BYPASS_WD
, if_index
, &data
);
285 *ms_timeout_set
= ret
;
291 EXPORT_SYMBOL(set_bypass_wd
);
293 static int get_bypass_wd(int if_index
, int *ms_timeout_set
)
295 int *data
= ms_timeout_set
;
298 if (is_dev_sd(if_index
))
299 SET_BPLIB_INT_FN2(get_bypass_wd
, int, if_index
, int *,
300 ms_timeout_set
, ret
);
302 ret
= doit(GET_BYPASS_WD
, if_index
, data
);
305 EXPORT_SYMBOL(get_bypass_wd
);
307 static int get_wd_expire_time(int if_index
, int *ms_time_left
)
309 int *data
= ms_time_left
, ret
= 0;
311 if (is_dev_sd(if_index
)) {
312 SET_BPLIB_INT_FN2(get_wd_expire_time
, int, if_index
, int *,
315 ret
= doit(GET_WD_EXPIRE_TIME
, if_index
, data
);
316 if ((ret
== 0) && (*data
!= 0))
321 EXPORT_SYMBOL(get_wd_expire_time
);
323 static int reset_bypass_wd_timer(int if_index
)
325 DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer
, RESET_BYPASS_WD_TIMER
,
328 EXPORT_SYMBOL(reset_bypass_wd_timer
);
330 static int set_std_nic(int if_index
, int bypass_mode
)
332 DO_BPLIB_SET_ARG_FN(set_std_nic
, SET_STD_NIC
, if_index
, bypass_mode
);
334 EXPORT_SYMBOL(set_std_nic
);
336 static int get_std_nic(int if_index
)
338 DO_BPLIB_GET_ARG_FN(get_std_nic
, GET_STD_NIC
, if_index
);
340 EXPORT_SYMBOL(get_std_nic
);
342 static int set_tx(int if_index
, int tx_state
)
344 DO_BPLIB_SET_ARG_FN(set_tx
, SET_TX
, if_index
, tx_state
);
346 EXPORT_SYMBOL(set_tx
);
348 static int get_tx(int if_index
)
350 DO_BPLIB_GET_ARG_FN(get_tx
, GET_TX
, if_index
);
352 EXPORT_SYMBOL(get_tx
);
354 static int set_tap(int if_index
, int tap_mode
)
356 DO_BPLIB_SET_ARG_FN(set_tap
, SET_TAP
, if_index
, tap_mode
);
358 EXPORT_SYMBOL(set_tap
);
360 static int get_tap(int if_index
)
362 DO_BPLIB_GET_ARG_FN(get_tap
, GET_TAP
, if_index
);
364 EXPORT_SYMBOL(get_tap
);
366 static int get_tap_change(int if_index
)
368 DO_BPLIB_GET_ARG_FN(get_tap_change
, GET_TAP_CHANGE
, if_index
);
370 EXPORT_SYMBOL(get_tap_change
);
372 static int set_dis_tap(int if_index
, int dis_tap
)
374 DO_BPLIB_SET_ARG_FN(set_dis_tap
, SET_DIS_TAP
, if_index
, dis_tap
);
376 EXPORT_SYMBOL(set_dis_tap
);
378 static int get_dis_tap(int if_index
)
380 DO_BPLIB_GET_ARG_FN(get_dis_tap
, GET_DIS_TAP
, if_index
);
382 EXPORT_SYMBOL(get_dis_tap
);
384 static int set_tap_pwup(int if_index
, int tap_mode
)
386 DO_BPLIB_SET_ARG_FN(set_tap_pwup
, SET_TAP_PWUP
, if_index
, tap_mode
);
388 EXPORT_SYMBOL(set_tap_pwup
);
390 static int get_tap_pwup(int if_index
)
392 DO_BPLIB_GET_ARG_FN(get_tap_pwup
, GET_TAP_PWUP
, if_index
);
394 EXPORT_SYMBOL(get_tap_pwup
);
396 static int set_bp_disc(int if_index
, int disc_mode
)
398 DO_BPLIB_SET_ARG_FN(set_bp_disc
, SET_DISC
, if_index
, disc_mode
);
400 EXPORT_SYMBOL(set_bp_disc
);
402 static int get_bp_disc(int if_index
)
404 DO_BPLIB_GET_ARG_FN(get_bp_disc
, GET_DISC
, if_index
);
406 EXPORT_SYMBOL(get_bp_disc
);
408 static int get_bp_disc_change(int if_index
)
410 DO_BPLIB_GET_ARG_FN(get_bp_disc_change
, GET_DISC_CHANGE
, if_index
);
412 EXPORT_SYMBOL(get_bp_disc_change
);
414 static int set_bp_dis_disc(int if_index
, int dis_disc
)
416 DO_BPLIB_SET_ARG_FN(set_bp_dis_disc
, SET_DIS_DISC
, if_index
, dis_disc
);
418 EXPORT_SYMBOL(set_bp_dis_disc
);
420 static int get_bp_dis_disc(int if_index
)
422 DO_BPLIB_GET_ARG_FN(get_bp_dis_disc
, GET_DIS_DISC
, if_index
);
424 EXPORT_SYMBOL(get_bp_dis_disc
);
426 static int set_bp_disc_pwup(int if_index
, int disc_mode
)
428 DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup
, SET_DISC_PWUP
, if_index
,
431 EXPORT_SYMBOL(set_bp_disc_pwup
);
433 static int get_bp_disc_pwup(int if_index
)
435 DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup
, GET_DISC_PWUP
, if_index
);
437 EXPORT_SYMBOL(get_bp_disc_pwup
);
439 static int set_wd_exp_mode(int if_index
, int mode
)
441 DO_BPLIB_SET_ARG_FN(set_wd_exp_mode
, SET_WD_EXP_MODE
, if_index
, mode
);
443 EXPORT_SYMBOL(set_wd_exp_mode
);
445 static int get_wd_exp_mode(int if_index
)
447 DO_BPLIB_GET_ARG_FN(get_wd_exp_mode
, GET_WD_EXP_MODE
, if_index
);
449 EXPORT_SYMBOL(get_wd_exp_mode
);
451 static int set_wd_autoreset(int if_index
, int time
)
453 DO_BPLIB_SET_ARG_FN(set_wd_autoreset
, SET_WD_AUTORESET
, if_index
, time
);
455 EXPORT_SYMBOL(set_wd_autoreset
);
457 static int get_wd_autoreset(int if_index
)
459 DO_BPLIB_GET_ARG_FN(get_wd_autoreset
, GET_WD_AUTORESET
, if_index
);
461 EXPORT_SYMBOL(get_wd_autoreset
);
463 static int set_tpl(int if_index
, int tpl_mode
)
465 DO_BPLIB_SET_ARG_FN(set_tpl
, SET_TPL
, if_index
, tpl_mode
);
467 EXPORT_SYMBOL(set_tpl
);
469 static int get_tpl(int if_index
)
471 DO_BPLIB_GET_ARG_FN(get_tpl
, GET_TPL
, if_index
);
473 EXPORT_SYMBOL(get_tpl
);
475 static int set_bp_hw_reset(int if_index
, int mode
)
477 DO_BPLIB_SET_ARG_FN(set_tpl
, SET_BP_HW_RESET
, if_index
, mode
);
479 EXPORT_SYMBOL(set_bp_hw_reset
);
481 static int get_bp_hw_reset(int if_index
)
483 DO_BPLIB_GET_ARG_FN(get_tpl
, GET_BP_HW_RESET
, if_index
);
485 EXPORT_SYMBOL(get_bp_hw_reset
);
487 static int get_bypass_info(int if_index
, struct bp_info
*bp_info
)
491 if (is_dev_sd(if_index
)) {
492 SET_BPLIB_INT_FN2(get_bypass_info
, int, if_index
,
493 struct bp_info
*, bp_info
, ret
);
495 struct net_device
*dev
;
496 struct net_device
*n
;
498 for_each_netdev_safe(&init_net
, dev
, n
) {
499 if (dev
->ifindex
== if_index
) {
500 struct if_bypass_info
*bypass_cb
;
503 memset(&ifr
, 0, sizeof(ifr
));
504 bypass_cb
= (struct if_bypass_info
*)&ifr
;
505 bypass_cb
->cmd
= GET_BYPASS_INFO
;
507 if (dev
->netdev_ops
&&
508 dev
->netdev_ops
->ndo_do_ioctl
)
509 ret
= dev
->netdev_ops
->ndo_do_ioctl(dev
,
510 &ifr
, SIOCGIFBYPASS
);
514 memcpy(bp_info
, &bypass_cb
->bp_info
,
515 sizeof(struct bp_info
));
516 ret
= ret
< 0 ? -1 : 0;
523 EXPORT_SYMBOL(get_bypass_info
);
525 static int __init
init_lib_module(void)
531 static void __exit
cleanup_lib_module(void)
535 module_init(init_lib_module
);
536 module_exit(cleanup_lib_module
);