linux/drivers/staging/silicom/bypasslib/bypass.c
<<
>>
Prefs
   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
  39MODULE_AUTHOR("www.silicom.co.il");
  40
  41MODULE_LICENSE("GPL");
  42
  43int init_lib_module(void);
  44void cleanup_lib_module(void);
  45
  46static 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
  63static 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
 130static 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
 137static 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
 182static 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
 192static int get_bypass_slave(int if_index)
 193{
 194        DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index);
 195}
 196
 197static int get_bypass_caps(int if_index)
 198{
 199        DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index);
 200}
 201
 202static int get_wd_set_caps(int if_index)
 203{
 204        DO_BPLIB_GET_ARG_FN(get_wd_set_caps, GET_WD_SET_CAPS, if_index);
 205}
 206
 207static int set_bypass(int if_index, int bypass_mode)
 208{
 209        DO_BPLIB_SET_ARG_FN(set_bypass, SET_BYPASS, if_index, bypass_mode);
 210}
 211
 212static int get_bypass(int if_index)
 213{
 214        DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index);
 215}
 216
 217static int get_bypass_change(int if_index)
 218{
 219        DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index);
 220}
 221
 222static int set_dis_bypass(int if_index, int dis_bypass)
 223{
 224        DO_BPLIB_SET_ARG_FN(set_dis_bypass, SET_DIS_BYPASS, if_index,
 225                            dis_bypass);
 226}
 227
 228static int get_dis_bypass(int if_index)
 229{
 230        DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index);
 231}
 232
 233static int set_bypass_pwoff(int if_index, int bypass_mode)
 234{
 235        DO_BPLIB_SET_ARG_FN(set_bypass_pwoff, SET_BYPASS_PWOFF, if_index,
 236                            bypass_mode);
 237}
 238
 239static int get_bypass_pwoff(int if_index)
 240{
 241        DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index);
 242}
 243
 244static int set_bypass_pwup(int if_index, int bypass_mode)
 245{
 246        DO_BPLIB_SET_ARG_FN(set_bypass_pwup, SET_BYPASS_PWUP, if_index,
 247                            bypass_mode);
 248}
 249
 250static int get_bypass_pwup(int if_index)
 251{
 252        DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index);
 253}
 254
 255static int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
 256{
 257        int data = ms_timeout, ret = 0;
 258        if (is_dev_sd(if_index))
 259                SET_BPLIB_INT_FN3(set_bypass_wd, int, if_index, int, ms_timeout,
 260                                  int *, ms_timeout_set, ret);
 261        else {
 262                ret = doit(SET_BYPASS_WD, if_index, &data);
 263                if (ret > 0) {
 264                        *ms_timeout_set = ret;
 265                        ret = 0;
 266                }
 267        }
 268        return ret;
 269}
 270
 271static int get_bypass_wd(int if_index, int *ms_timeout_set)
 272{
 273        int *data = ms_timeout_set, ret = 0;
 274        if (is_dev_sd(if_index))
 275                SET_BPLIB_INT_FN2(get_bypass_wd, int, if_index, int *,
 276                                  ms_timeout_set, ret);
 277        else
 278                ret = doit(GET_BYPASS_WD, if_index, data);
 279        return ret;
 280}
 281
 282static int get_wd_expire_time(int if_index, int *ms_time_left)
 283{
 284        int *data = ms_time_left, ret = 0;
 285        if (is_dev_sd(if_index))
 286                SET_BPLIB_INT_FN2(get_wd_expire_time, int, if_index, int *,
 287                                  ms_time_left, ret);
 288        else {
 289                ret = doit(GET_WD_EXPIRE_TIME, if_index, data);
 290                if ((ret == 0) && (*data != 0))
 291                        ret = 1;
 292        }
 293        return ret;
 294}
 295
 296static int reset_bypass_wd_timer(int if_index)
 297{
 298        DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer, RESET_BYPASS_WD_TIMER,
 299                            if_index);
 300}
 301
 302static int set_std_nic(int if_index, int bypass_mode)
 303{
 304        DO_BPLIB_SET_ARG_FN(set_std_nic, SET_STD_NIC, if_index, bypass_mode);
 305}
 306
 307static int get_std_nic(int if_index)
 308{
 309        DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index);
 310}
 311
 312static int set_tx(int if_index, int tx_state)
 313{
 314        DO_BPLIB_SET_ARG_FN(set_tx, SET_TX, if_index, tx_state);
 315}
 316
 317static int get_tx(int if_index)
 318{
 319        DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index);
 320}
 321
 322static int set_tap(int if_index, int tap_mode)
 323{
 324        DO_BPLIB_SET_ARG_FN(set_tap, SET_TAP, if_index, tap_mode);
 325}
 326
 327static int get_tap(int if_index)
 328{
 329        DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index);
 330}
 331
 332static int get_tap_change(int if_index)
 333{
 334        DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index);
 335}
 336
 337static int set_dis_tap(int if_index, int dis_tap)
 338{
 339        DO_BPLIB_SET_ARG_FN(set_dis_tap, SET_DIS_TAP, if_index, dis_tap);
 340}
 341
 342static int get_dis_tap(int if_index)
 343{
 344        DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index);
 345}
 346
 347static int set_tap_pwup(int if_index, int tap_mode)
 348{
 349        DO_BPLIB_SET_ARG_FN(set_tap_pwup, SET_TAP_PWUP, if_index, tap_mode);
 350}
 351
 352static int get_tap_pwup(int if_index)
 353{
 354        DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index);
 355}
 356
 357static int set_bp_disc(int if_index, int disc_mode)
 358{
 359        DO_BPLIB_SET_ARG_FN(set_bp_disc, SET_DISC, if_index, disc_mode);
 360}
 361
 362static int get_bp_disc(int if_index)
 363{
 364        DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index);
 365}
 366
 367static int get_bp_disc_change(int if_index)
 368{
 369        DO_BPLIB_GET_ARG_FN(get_bp_disc_change, GET_DISC_CHANGE, if_index);
 370}
 371
 372static int set_bp_dis_disc(int if_index, int dis_disc)
 373{
 374        DO_BPLIB_SET_ARG_FN(set_bp_dis_disc, SET_DIS_DISC, if_index, dis_disc);
 375}
 376
 377static int get_bp_dis_disc(int if_index)
 378{
 379        DO_BPLIB_GET_ARG_FN(get_bp_dis_disc, GET_DIS_DISC, if_index);
 380}
 381
 382static int set_bp_disc_pwup(int if_index, int disc_mode)
 383{
 384        DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup, SET_DISC_PWUP, if_index,
 385                            disc_mode);
 386}
 387
 388static int get_bp_disc_pwup(int if_index)
 389{
 390        DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup, GET_DISC_PWUP, if_index);
 391}
 392
 393static int set_wd_exp_mode(int if_index, int mode)
 394{
 395        DO_BPLIB_SET_ARG_FN(set_wd_exp_mode, SET_WD_EXP_MODE, if_index, mode);
 396}
 397
 398static int get_wd_exp_mode(int if_index)
 399{
 400        DO_BPLIB_GET_ARG_FN(get_wd_exp_mode, GET_WD_EXP_MODE, if_index);
 401}
 402
 403static int set_wd_autoreset(int if_index, int time)
 404{
 405        DO_BPLIB_SET_ARG_FN(set_wd_autoreset, SET_WD_AUTORESET, if_index, time);
 406}
 407
 408static int get_wd_autoreset(int if_index)
 409{
 410        DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index);
 411}
 412
 413static int set_tpl(int if_index, int tpl_mode)
 414{
 415        DO_BPLIB_SET_ARG_FN(set_tpl, SET_TPL, if_index, tpl_mode);
 416}
 417
 418static int get_tpl(int if_index)
 419{
 420        DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index);
 421}
 422
 423static int set_bp_hw_reset(int if_index, int mode)
 424{
 425        DO_BPLIB_SET_ARG_FN(set_tpl, SET_BP_HW_RESET, if_index, mode);
 426}
 427
 428static int get_bp_hw_reset(int if_index)
 429{
 430        DO_BPLIB_GET_ARG_FN(get_tpl, GET_BP_HW_RESET, if_index);
 431}
 432
 433static int get_bypass_info(int if_index, struct bp_info *bp_info)
 434{
 435        int ret = 0;
 436        if (is_dev_sd(if_index)) {
 437                SET_BPLIB_INT_FN2(get_bypass_info, int, if_index,
 438                                  struct bp_info *, bp_info, ret);
 439        } else {
 440                static int (*ioctl) (struct net_device *, struct ifreq *, int);
 441                struct net_device *dev;
 442
 443                struct net_device *n;
 444                for_each_netdev_safe(&init_net, dev, n) {
 445                        if (dev->ifindex == if_index) {
 446                                struct if_bypass_info *bypass_cb;
 447                                struct ifreq ifr;
 448
 449                                memset(&ifr, 0, sizeof(ifr));
 450                                bypass_cb = (struct if_bypass_info *)&ifr;
 451                                bypass_cb->cmd = GET_BYPASS_INFO;
 452
 453                                if ((dev->netdev_ops) &&
 454                                    (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
 455                                        ret = ioctl(dev, &ifr, SIOCGIFBYPASS);
 456                                }
 457
 458                                else
 459                                        ret = -1;
 460                                if (ret == 0)
 461                                        memcpy(bp_info, &bypass_cb->bp_info,
 462                                               sizeof(struct bp_info));
 463                                ret = (ret < 0 ? -1 : 0);
 464                                break;
 465                        }
 466                }
 467        }
 468        return ret;
 469}
 470
 471int init_lib_module(void)
 472{
 473
 474        printk(VERSION);
 475        return 0;
 476}
 477
 478void cleanup_lib_module(void)
 479{
 480}
 481
 482EXPORT_SYMBOL_NOVERS(is_bypass);
 483EXPORT_SYMBOL_NOVERS(get_bypass_slave);
 484EXPORT_SYMBOL_NOVERS(get_bypass_caps);
 485EXPORT_SYMBOL_NOVERS(get_wd_set_caps);
 486EXPORT_SYMBOL_NOVERS(set_bypass);
 487EXPORT_SYMBOL_NOVERS(get_bypass);
 488EXPORT_SYMBOL_NOVERS(get_bypass_change);
 489EXPORT_SYMBOL_NOVERS(set_dis_bypass);
 490EXPORT_SYMBOL_NOVERS(get_dis_bypass);
 491EXPORT_SYMBOL_NOVERS(set_bypass_pwoff);
 492EXPORT_SYMBOL_NOVERS(get_bypass_pwoff);
 493EXPORT_SYMBOL_NOVERS(set_bypass_pwup);
 494EXPORT_SYMBOL_NOVERS(get_bypass_pwup);
 495EXPORT_SYMBOL_NOVERS(set_bypass_wd);
 496EXPORT_SYMBOL_NOVERS(get_bypass_wd);
 497EXPORT_SYMBOL_NOVERS(get_wd_expire_time);
 498EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer);
 499EXPORT_SYMBOL_NOVERS(set_std_nic);
 500EXPORT_SYMBOL_NOVERS(get_std_nic);
 501EXPORT_SYMBOL_NOVERS(set_tx);
 502EXPORT_SYMBOL_NOVERS(get_tx);
 503EXPORT_SYMBOL_NOVERS(set_tap);
 504EXPORT_SYMBOL_NOVERS(get_tap);
 505EXPORT_SYMBOL_NOVERS(get_tap_change);
 506EXPORT_SYMBOL_NOVERS(set_dis_tap);
 507EXPORT_SYMBOL_NOVERS(get_dis_tap);
 508EXPORT_SYMBOL_NOVERS(set_tap_pwup);
 509EXPORT_SYMBOL_NOVERS(get_tap_pwup);
 510EXPORT_SYMBOL_NOVERS(set_bp_disc);
 511EXPORT_SYMBOL_NOVERS(get_bp_disc);
 512EXPORT_SYMBOL_NOVERS(get_bp_disc_change);
 513EXPORT_SYMBOL_NOVERS(set_bp_dis_disc);
 514EXPORT_SYMBOL_NOVERS(get_bp_dis_disc);
 515EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup);
 516EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup);
 517EXPORT_SYMBOL_NOVERS(set_wd_exp_mode);
 518EXPORT_SYMBOL_NOVERS(get_wd_exp_mode);
 519EXPORT_SYMBOL_NOVERS(set_wd_autoreset);
 520EXPORT_SYMBOL_NOVERS(get_wd_autoreset);
 521EXPORT_SYMBOL_NOVERS(set_tpl);
 522EXPORT_SYMBOL_NOVERS(get_tpl);
 523EXPORT_SYMBOL_NOVERS(set_bp_hw_reset);
 524EXPORT_SYMBOL_NOVERS(get_bp_hw_reset);
 525EXPORT_SYMBOL_NOVERS(get_bypass_info);
 526
 527module_init(init_lib_module);
 528module_exit(cleanup_lib_module);
 529