]> Pileus Git - ~andy/linux/blob - drivers/staging/silicom/bypasslib/bypass.c
Merge branch 'for-linus' of git://git.linaro.org/people/rmk/linux-arm
[~andy/linux] / drivers / staging / silicom / bypasslib / bypass.c
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 /******************************************************************************/
13
14 #if defined(CONFIG_SMP) && ! defined(__SMP__)
15 #define __SMP__
16 #endif
17
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <asm/unistd.h>
21
22 #include <linux/sched.h>
23 #include <linux/wait.h>
24
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>
30
31 #include <net/net_namespace.h>
32
33 #include "bplibk.h"
34
35 #define MOD_NAME "bypass"
36
37 #define VERSION "\n"MOD_NAME" version 9.0.4\n"
38
39 MODULE_AUTHOR("www.silicom.co.il");
40
41 MODULE_LICENSE("GPL");
42
43 int init_lib_module(void);
44 void cleanup_lib_module(void);
45
46 static int do_cmd(struct net_device *dev, struct ifreq *ifr, int cmd, int *data)
47 {
48         int ret = -1;
49         struct if_bypass *bypass_cb;
50         static int (*ioctl) (struct net_device *, struct ifreq *, int);
51
52         bypass_cb = (struct if_bypass *)ifr;
53         bypass_cb->cmd = cmd;
54         bypass_cb->data = *data;
55         if ((dev->netdev_ops) && (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
56                 ret = ioctl(dev, ifr, SIOCGIFBYPASS);
57                 *data = bypass_cb->data;
58         }
59
60         return ret;
61 }
62
63 static int doit(int cmd, int if_index, int *data)
64 {
65         struct ifreq ifr;
66         int ret = -1;
67         struct net_device *dev;
68         struct net_device *n;
69         for_each_netdev_safe(&init_net, dev, n) {
70
71                 if (dev->ifindex == if_index) {
72                         ret = do_cmd(dev, &ifr, cmd, data);
73                         if (ret < 0)
74                                 ret = -1;
75
76                 }
77         }
78
79         return ret;
80 }
81
82 #define bp_symbol_get(fn_name) symbol_get(fn_name)
83 #define bp_symbol_put(fn_name) symbol_put(fn_name)
84
85 #define SET_BPLIB_INT_FN(fn_name, arg_type, arg, ret) \
86     ({ int (* fn_ex)(arg_type)=NULL; \
87     fn_ex=bp_symbol_get(fn_name##_sd); \
88        if(fn_ex) {  \
89         ret= fn_ex(arg); \
90        bp_symbol_put(fn_name##_sd); \
91        } else ret=-1; \
92     })
93
94 #define  SET_BPLIB_INT_FN2(fn_name, arg_type, arg, arg_type1, arg1, ret) \
95     ({ int (* fn_ex)(arg_type,arg_type1)=NULL; \
96         fn_ex=bp_symbol_get(fn_name##_sd); \
97        if(fn_ex) {  \
98         ret= fn_ex(arg,arg1); \
99         bp_symbol_put(fn_name##_sd); \
100        } else ret=-1; \
101     })
102 #define SET_BPLIB_INT_FN3(fn_name, arg_type, arg, arg_type1, arg1,arg_type2, arg2, ret) \
103     ({ int (* fn_ex)(arg_type,arg_type1, arg_type2)=NULL; \
104         fn_ex=bp_symbol_get(fn_name##_sd); \
105        if(fn_ex) {  \
106         ret= fn_ex(arg,arg1,arg2); \
107         bp_symbol_put(fn_name##_sd); \
108        } else ret=-1; \
109     })
110
111 #define DO_BPLIB_GET_ARG_FN(fn_name,ioctl_val, if_index) \
112     ({    int data, ret=0; \
113             if(is_dev_sd(if_index)){ \
114             SET_BPLIB_INT_FN(fn_name, int, if_index, ret); \
115             return ret; \
116             }  \
117             return doit(ioctl_val,if_index, &data); \
118     })
119
120 #define DO_BPLIB_SET_ARG_FN(fn_name,ioctl_val,if_index,arg) \
121     ({    int data, ret=0; \
122             if(is_dev_sd(if_index)){ \
123             SET_BPLIB_INT_FN2(fn_name, int, if_index, int, arg, ret); \
124             return ret; \
125             }  \
126             data=arg; \
127             return doit(ioctl_val,if_index, &data); \
128     })
129
130 static int is_dev_sd(int if_index)
131 {
132         int ret = 0;
133         SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
134         return (ret >= 0 ? 1 : 0);
135 }
136
137 static int is_bypass_dev(int if_index)
138 {
139         struct pci_dev *pdev = NULL;
140         struct net_device *dev = NULL;
141         struct ifreq ifr;
142         int ret = 0, data = 0;
143
144         while ((pdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) {
145                 if ((dev = pci_get_drvdata(pdev)) != NULL)
146                         if (((dev = pci_get_drvdata(pdev)) != NULL) &&
147                             (dev->ifindex == if_index)) {
148                                 if ((pdev->vendor == SILICOM_VID) &&
149                                     (pdev->device >= SILICOM_BP_PID_MIN) &&
150                                     (pdev->device <= SILICOM_BP_PID_MAX))
151                                         goto send_cmd;
152 #if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO)
153                                 else {
154                                         struct ethtool_drvinfo info;
155                                         const struct ethtool_ops *ops =
156                                             dev->ethtool_ops;
157                                         int k = 0;
158
159                                         if (ops->get_drvinfo) {
160                                                 memset(&info, 0, sizeof(info));
161                                                 info.cmd = ETHTOOL_GDRVINFO;
162                                                 ops->get_drvinfo(dev, &info);
163                                                 for (; bp_desc_array[k]; k++)
164                                                         if (!
165                                                             (strcmp
166                                                              (bp_desc_array[k],
167                                                               info.driver)))
168                                                                 goto send_cmd;
169
170                                         }
171
172                                 }
173 #endif
174                                 return -1;
175                         }
176         }
177  send_cmd:
178         ret = do_cmd(dev, &ifr, IS_BYPASS, &data);
179         return (ret < 0 ? -1 : ret);
180 }
181
182 static int is_bypass(int if_index)
183 {
184         int ret = 0;
185         SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
186
187         if (ret < 0)
188                 return is_bypass_dev(if_index);
189         return ret;
190 }
191 EXPORT_SYMBOL(is_bypass);
192
193 static int get_bypass_slave(int if_index)
194 {
195         DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index);
196 }
197 EXPORT_SYMBOL(get_bypass_slave);
198
199 static int get_bypass_caps(int if_index)
200 {
201         DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index);
202 }
203 EXPORT_SYMBOL(get_bypass_caps);
204
205 static int get_wd_set_caps(int if_index)
206 {
207         DO_BPLIB_GET_ARG_FN(get_wd_set_caps, GET_WD_SET_CAPS, if_index);
208 }
209 EXPORT_SYMBOL(get_wd_set_caps);
210
211 static int set_bypass(int if_index, int bypass_mode)
212 {
213         DO_BPLIB_SET_ARG_FN(set_bypass, SET_BYPASS, if_index, bypass_mode);
214 }
215 EXPORT_SYMBOL(set_bypass);
216
217 static int get_bypass(int if_index)
218 {
219         DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index);
220 }
221 EXPORT_SYMBOL(get_bypass);
222
223 static int get_bypass_change(int if_index)
224 {
225         DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index);
226 }
227 EXPORT_SYMBOL(get_bypass_change);
228
229 static int set_dis_bypass(int if_index, int dis_bypass)
230 {
231         DO_BPLIB_SET_ARG_FN(set_dis_bypass, SET_DIS_BYPASS, if_index,
232                             dis_bypass);
233 }
234 EXPORT_SYMBOL(set_dis_bypass);
235
236 static int get_dis_bypass(int if_index)
237 {
238         DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index);
239 }
240 EXPORT_SYMBOL(get_dis_bypass);
241
242 static int set_bypass_pwoff(int if_index, int bypass_mode)
243 {
244         DO_BPLIB_SET_ARG_FN(set_bypass_pwoff, SET_BYPASS_PWOFF, if_index,
245                             bypass_mode);
246 }
247 EXPORT_SYMBOL(set_bypass_pwoff);
248
249 static int get_bypass_pwoff(int if_index)
250 {
251         DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index);
252 }
253 EXPORT_SYMBOL(get_bypass_pwoff);
254
255 static int set_bypass_pwup(int if_index, int bypass_mode)
256 {
257         DO_BPLIB_SET_ARG_FN(set_bypass_pwup, SET_BYPASS_PWUP, if_index,
258                             bypass_mode);
259 }
260 EXPORT_SYMBOL(set_bypass_pwup);
261
262 static int get_bypass_pwup(int if_index)
263 {
264         DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index);
265 }
266 EXPORT_SYMBOL(get_bypass_pwup);
267
268 static int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
269 {
270         int data = ms_timeout, ret = 0;
271         if (is_dev_sd(if_index))
272                 SET_BPLIB_INT_FN3(set_bypass_wd, int, if_index, int, ms_timeout,
273                                   int *, ms_timeout_set, ret);
274         else {
275                 ret = doit(SET_BYPASS_WD, if_index, &data);
276                 if (ret > 0) {
277                         *ms_timeout_set = ret;
278                         ret = 0;
279                 }
280         }
281         return ret;
282 }
283 EXPORT_SYMBOL(set_bypass_wd);
284
285 static int get_bypass_wd(int if_index, int *ms_timeout_set)
286 {
287         int *data = ms_timeout_set, ret = 0;
288         if (is_dev_sd(if_index))
289                 SET_BPLIB_INT_FN2(get_bypass_wd, int, if_index, int *,
290                                   ms_timeout_set, ret);
291         else
292                 ret = doit(GET_BYPASS_WD, if_index, data);
293         return ret;
294 }
295 EXPORT_SYMBOL(get_bypass_wd);
296
297 static int get_wd_expire_time(int if_index, int *ms_time_left)
298 {
299         int *data = ms_time_left, ret = 0;
300         if (is_dev_sd(if_index))
301                 SET_BPLIB_INT_FN2(get_wd_expire_time, int, if_index, int *,
302                                   ms_time_left, ret);
303         else {
304                 ret = doit(GET_WD_EXPIRE_TIME, if_index, data);
305                 if ((ret == 0) && (*data != 0))
306                         ret = 1;
307         }
308         return ret;
309 }
310 EXPORT_SYMBOL(get_wd_expire_time);
311
312 static int reset_bypass_wd_timer(int if_index)
313 {
314         DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer, RESET_BYPASS_WD_TIMER,
315                             if_index);
316 }
317 EXPORT_SYMBOL(reset_bypass_wd_timer);
318
319 static int set_std_nic(int if_index, int bypass_mode)
320 {
321         DO_BPLIB_SET_ARG_FN(set_std_nic, SET_STD_NIC, if_index, bypass_mode);
322 }
323 EXPORT_SYMBOL(set_std_nic);
324
325 static int get_std_nic(int if_index)
326 {
327         DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index);
328 }
329 EXPORT_SYMBOL(get_std_nic);
330
331 static int set_tx(int if_index, int tx_state)
332 {
333         DO_BPLIB_SET_ARG_FN(set_tx, SET_TX, if_index, tx_state);
334 }
335 EXPORT_SYMBOL(set_tx);
336
337 static int get_tx(int if_index)
338 {
339         DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index);
340 }
341 EXPORT_SYMBOL(get_tx);
342
343 static int set_tap(int if_index, int tap_mode)
344 {
345         DO_BPLIB_SET_ARG_FN(set_tap, SET_TAP, if_index, tap_mode);
346 }
347 EXPORT_SYMBOL(set_tap);
348
349 static int get_tap(int if_index)
350 {
351         DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index);
352 }
353 EXPORT_SYMBOL(get_tap);
354
355 static int get_tap_change(int if_index)
356 {
357         DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index);
358 }
359 EXPORT_SYMBOL(get_tap_change);
360
361 static int set_dis_tap(int if_index, int dis_tap)
362 {
363         DO_BPLIB_SET_ARG_FN(set_dis_tap, SET_DIS_TAP, if_index, dis_tap);
364 }
365 EXPORT_SYMBOL(set_dis_tap);
366
367 static int get_dis_tap(int if_index)
368 {
369         DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index);
370 }
371 EXPORT_SYMBOL(get_dis_tap);
372
373 static int set_tap_pwup(int if_index, int tap_mode)
374 {
375         DO_BPLIB_SET_ARG_FN(set_tap_pwup, SET_TAP_PWUP, if_index, tap_mode);
376 }
377 EXPORT_SYMBOL(set_tap_pwup);
378
379 static int get_tap_pwup(int if_index)
380 {
381         DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index);
382 }
383 EXPORT_SYMBOL(get_tap_pwup);
384
385 static int set_bp_disc(int if_index, int disc_mode)
386 {
387         DO_BPLIB_SET_ARG_FN(set_bp_disc, SET_DISC, if_index, disc_mode);
388 }
389 EXPORT_SYMBOL(set_bp_disc);
390
391 static int get_bp_disc(int if_index)
392 {
393         DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index);
394 }
395 EXPORT_SYMBOL(get_bp_disc);
396
397 static int get_bp_disc_change(int if_index)
398 {
399         DO_BPLIB_GET_ARG_FN(get_bp_disc_change, GET_DISC_CHANGE, if_index);
400 }
401 EXPORT_SYMBOL(get_bp_disc_change);
402
403 static int set_bp_dis_disc(int if_index, int dis_disc)
404 {
405         DO_BPLIB_SET_ARG_FN(set_bp_dis_disc, SET_DIS_DISC, if_index, dis_disc);
406 }
407 EXPORT_SYMBOL(set_bp_dis_disc);
408
409 static int get_bp_dis_disc(int if_index)
410 {
411         DO_BPLIB_GET_ARG_FN(get_bp_dis_disc, GET_DIS_DISC, if_index);
412 }
413 EXPORT_SYMBOL(get_bp_dis_disc);
414
415 static int set_bp_disc_pwup(int if_index, int disc_mode)
416 {
417         DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup, SET_DISC_PWUP, if_index,
418                             disc_mode);
419 }
420 EXPORT_SYMBOL(set_bp_disc_pwup);
421
422 static int get_bp_disc_pwup(int if_index)
423 {
424         DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup, GET_DISC_PWUP, if_index);
425 }
426 EXPORT_SYMBOL(get_bp_disc_pwup);
427
428 static int set_wd_exp_mode(int if_index, int mode)
429 {
430         DO_BPLIB_SET_ARG_FN(set_wd_exp_mode, SET_WD_EXP_MODE, if_index, mode);
431 }
432 EXPORT_SYMBOL(set_wd_exp_mode);
433
434 static int get_wd_exp_mode(int if_index)
435 {
436         DO_BPLIB_GET_ARG_FN(get_wd_exp_mode, GET_WD_EXP_MODE, if_index);
437 }
438 EXPORT_SYMBOL(get_wd_exp_mode);
439
440 static int set_wd_autoreset(int if_index, int time)
441 {
442         DO_BPLIB_SET_ARG_FN(set_wd_autoreset, SET_WD_AUTORESET, if_index, time);
443 }
444 EXPORT_SYMBOL(set_wd_autoreset);
445
446 static int get_wd_autoreset(int if_index)
447 {
448         DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index);
449 }
450 EXPORT_SYMBOL(get_wd_autoreset);
451
452 static int set_tpl(int if_index, int tpl_mode)
453 {
454         DO_BPLIB_SET_ARG_FN(set_tpl, SET_TPL, if_index, tpl_mode);
455 }
456 EXPORT_SYMBOL(set_tpl);
457
458 static int get_tpl(int if_index)
459 {
460         DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index);
461 }
462 EXPORT_SYMBOL(get_tpl);
463
464 static int set_bp_hw_reset(int if_index, int mode)
465 {
466         DO_BPLIB_SET_ARG_FN(set_tpl, SET_BP_HW_RESET, if_index, mode);
467 }
468 EXPORT_SYMBOL(set_bp_hw_reset);
469
470 static int get_bp_hw_reset(int if_index)
471 {
472         DO_BPLIB_GET_ARG_FN(get_tpl, GET_BP_HW_RESET, if_index);
473 }
474 EXPORT_SYMBOL(get_bp_hw_reset);
475
476 static int get_bypass_info(int if_index, struct bp_info *bp_info)
477 {
478         int ret = 0;
479         if (is_dev_sd(if_index)) {
480                 SET_BPLIB_INT_FN2(get_bypass_info, int, if_index,
481                                   struct bp_info *, bp_info, ret);
482         } else {
483                 static int (*ioctl) (struct net_device *, struct ifreq *, int);
484                 struct net_device *dev;
485
486                 struct net_device *n;
487                 for_each_netdev_safe(&init_net, dev, n) {
488                         if (dev->ifindex == if_index) {
489                                 struct if_bypass_info *bypass_cb;
490                                 struct ifreq ifr;
491
492                                 memset(&ifr, 0, sizeof(ifr));
493                                 bypass_cb = (struct if_bypass_info *)&ifr;
494                                 bypass_cb->cmd = GET_BYPASS_INFO;
495
496                                 if ((dev->netdev_ops) &&
497                                     (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
498                                         ret = ioctl(dev, &ifr, SIOCGIFBYPASS);
499                                 }
500
501                                 else
502                                         ret = -1;
503                                 if (ret == 0)
504                                         memcpy(bp_info, &bypass_cb->bp_info,
505                                                sizeof(struct bp_info));
506                                 ret = (ret < 0 ? -1 : 0);
507                                 break;
508                         }
509                 }
510         }
511         return ret;
512 }
513 EXPORT_SYMBOL(get_bypass_info);
514
515 int init_lib_module(void)
516 {
517
518         printk(VERSION);
519         return 0;
520 }
521
522 void cleanup_lib_module(void)
523 {
524 }
525
526 module_init(init_lib_module);
527 module_exit(cleanup_lib_module);