mfd: arizona: Only free the CTRLIF_ERR IRQ if we requested it
[linux-2.6/btrfs-unstable.git] / drivers / staging / silicom / bypasslib / bypass.c
blob8e714a8ea3a0ba510099ffb02f612741d306051f
1 /******************************************************************************/
2 /* */
3 /* bypass library, Copyright (c) 2004-2007 Silicom, Ltd */
4 /* */
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. */
8 /* */
9 /* */
10 /* bypass.c */
11 /* */
12 /******************************************************************************/
14 #if defined(CONFIG_SMP) && !defined(__SMP__)
15 #define __SMP__
16 #endif
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>
33 #include "bplibk.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)
45 int ret = -1;
46 struct if_bypass *bypass_cb;
48 bypass_cb = (struct if_bypass *)ifr;
49 bypass_cb->cmd = cmd;
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;
57 return ret;
60 static int doit(int cmd, int if_index, int *data)
62 struct ifreq ifr;
63 int ret = -1;
64 struct net_device *dev;
65 struct net_device *n;
67 for_each_netdev_safe(&init_net, dev, n) {
68 if (dev->ifindex == if_index) {
69 ret = do_cmd(dev, &ifr, cmd, data);
70 if (ret < 0)
71 ret = -1;
75 return ret;
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); \
84 if (fn_ex) { \
85 ret = fn_ex(arg); \
86 bp_symbol_put(fn_name##_sd); \
87 } else { \
88 ret = -1; \
89 } \
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); \
95 if (fn_ex) { \
96 ret = fn_ex(arg, arg1); \
97 bp_symbol_put(fn_name##_sd); \
98 } else { \
99 ret = -1; \
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); \
107 if (fn_ex) { \
108 ret = fn_ex(arg, arg1, arg2); \
109 bp_symbol_put(fn_name##_sd); \
110 } else { \
111 ret = -1; \
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); \
119 return 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, \
128 arg, ret); \
129 return ret; \
131 data = arg; \
132 return doit(ioctl_val, if_index, &data); \
135 static int is_dev_sd(int if_index)
137 int ret = 0;
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;
147 struct ifreq ifr;
148 int ret = 0;
149 int data = 0;
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)) {
157 goto send_cmd;
159 #if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO)
160 else {
161 struct ethtool_drvinfo info;
162 const struct ethtool_ops *ops =
163 dev->ethtool_ops;
164 int k = 0;
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],
172 info.driver)))
173 goto send_cmd;
178 #endif
179 return -1;
182 send_cmd:
183 ret = do_cmd(dev, &ifr, IS_BYPASS, &data);
184 return ret < 0 ? -1 : ret;
187 static int is_bypass(int if_index)
189 int ret = 0;
191 SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
193 if (ret < 0)
194 return is_bypass_dev(if_index);
195 return ret;
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,
238 dis_bypass);
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,
251 bypass_mode);
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,
264 bypass_mode);
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;
277 int ret = 0;
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);
282 } else {
283 ret = doit(SET_BYPASS_WD, if_index, &data);
284 if (ret > 0) {
285 *ms_timeout_set = ret;
286 ret = 0;
289 return 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;
296 int ret = 0;
298 if (is_dev_sd(if_index))
299 SET_BPLIB_INT_FN2(get_bypass_wd, int, if_index, int *,
300 ms_timeout_set, ret);
301 else
302 ret = doit(GET_BYPASS_WD, if_index, data);
303 return ret;
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 *,
313 ms_time_left, ret);
314 } else {
315 ret = doit(GET_WD_EXPIRE_TIME, if_index, data);
316 if ((ret == 0) && (*data != 0))
317 ret = 1;
319 return ret;
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,
326 if_index);
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,
429 disc_mode);
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)
489 int ret = 0;
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);
494 } else {
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;
501 struct ifreq ifr;
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);
511 else
512 ret = -1;
513 if (ret == 0)
514 memcpy(bp_info, &bypass_cb->bp_info,
515 sizeof(struct bp_info));
516 ret = ret < 0 ? -1 : 0;
517 break;
521 return ret;
523 EXPORT_SYMBOL(get_bypass_info);
525 static int __init init_lib_module(void)
527 printk(VERSION);
528 return 0;
531 static void __exit cleanup_lib_module(void)
535 module_init(init_lib_module);
536 module_exit(cleanup_lib_module);