blob: 765fce84d9dd15494794b46dc282c5df6bf731f9 [file] [log] [blame]
/******************************************************************************/
/* */
/* Bypass Control utility, Copyright (c) 2005-2011 Silicom */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation, located in the file LICENSE. */
/* Copyright(c) 2007 - 2009, 2013 Intel Corporation. All rights reserved. */
/* */
/* */
/******************************************************************************/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/rcupdate.h>
#include <linux/etherdevice.h>
#include <linux/uaccess.h> /* for get_user and put_user */
#include <linux/sched.h>
#include <linux/ethtool.h>
#include <linux/proc_fs.h>
#include "bp_ioctl.h"
#include "bp_mod.h"
#include "bypass.h"
#include "libbp_sd.h"
#define SUCCESS 0
#define BP_MOD_VER "9.0.4"
#define BP_MOD_DESCR "Silicom Bypass-SD Control driver"
#define BP_SYNC_FLAG 1
static int major_num;
MODULE_AUTHOR("Anna Lukin, annal@silicom.co.il");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(BP_MOD_DESCR);
MODULE_VERSION(BP_MOD_VER);
static spinlock_t bpvm_lock;
#define unlock_bpctl() \
up(&bpctl_sema);
/* Media Types */
enum bp_media_type {
BP_COPPER = 0,
BP_FIBER,
BP_CX4,
BP_NONE,
};
struct bypass_pfs_sd {
char dir_name[32];
struct proc_dir_entry *bypass_entry;
};
struct bpctl_dev {
char *name;
char *desc;
struct pci_dev *pdev; /* PCI device */
struct net_device *ndev; /* net device */
unsigned long mem_map;
uint8_t bus;
uint8_t slot;
uint8_t func;
u_int32_t device;
u_int32_t vendor;
u_int32_t subvendor;
u_int32_t subdevice;
int ifindex;
uint32_t bp_caps;
uint32_t bp_caps_ex;
uint8_t bp_fw_ver;
int bp_ext_ver;
int wdt_status;
unsigned long bypass_wdt_on_time;
uint32_t bypass_timer_interval;
struct timer_list bp_timer;
uint32_t reset_time;
uint8_t bp_status_un;
atomic_t wdt_busy;
enum bp_media_type media_type;
int bp_tpl_flag;
struct timer_list bp_tpl_timer;
spinlock_t bypass_wr_lock;
int bp_10g;
int bp_10gb;
int bp_fiber5;
int bp_10g9;
int bp_i80;
int bp_540;
int (*hard_start_xmit_save) (struct sk_buff *skb,
struct net_device *dev);
const struct net_device_ops *old_ops;
struct net_device_ops new_ops;
int bp_self_test_flag;
char *bp_tx_data;
struct bypass_pfs_sd bypass_pfs_set;
};
static struct bpctl_dev *bpctl_dev_arr;
static struct semaphore bpctl_sema;
static int device_num;
static int get_dev_idx(int ifindex);
static struct bpctl_dev *get_master_port_fn(struct bpctl_dev *pbpctl_dev);
static int disc_status(struct bpctl_dev *pbpctl_dev);
static int bypass_status(struct bpctl_dev *pbpctl_dev);
static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left);
static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev);
static void if_scan_init(void);
static int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block);
static int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block);
static int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
static int get_dev_idx_bsf(int bus, int slot, int func);
static int bp_get_dev_idx_bsf(struct net_device *dev, int *index)
{
struct ethtool_drvinfo drvinfo = {0};
char *buf;
int bus, slot, func;
if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo)
dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
else
return -EOPNOTSUPP;
if (!strcmp(drvinfo.bus_info, "N/A"))
return -ENODATA;
buf = strchr(drvinfo.bus_info, ':');
if (!buf)
return -EINVAL;
buf++;
if (sscanf(buf, "%x:%x.%x", &bus, &slot, &func) != 3)
return -EINVAL;
*index = get_dev_idx_bsf(bus, slot, func);
return 0;
}
static int bp_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
static struct bpctl_dev *pbpctl_dev, *pbpctl_dev_m;
int dev_num = 0, ret = 0, ret_d = 0, time_left = 0;
/* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */
/* return NOTIFY_DONE; */
if (!dev)
return NOTIFY_DONE;
if (event == NETDEV_REGISTER) {
int idx_dev;
if (bp_get_dev_idx_bsf(dev, &idx_dev))
return NOTIFY_DONE;
if (idx_dev == -1)
return NOTIFY_DONE;
bpctl_dev_arr[idx_dev].ifindex = dev->ifindex;
bpctl_dev_arr[idx_dev].ndev = dev;
bypass_proc_remove_dev_sd(&bpctl_dev_arr[idx_dev]);
bypass_proc_create_dev_sd(&bpctl_dev_arr[idx_dev]);
return NOTIFY_DONE;
}
if (event == NETDEV_UNREGISTER) {
int idx_dev = 0;
for (idx_dev = 0;
((bpctl_dev_arr[idx_dev].pdev != NULL)
&& (idx_dev < device_num)); idx_dev++) {
if (bpctl_dev_arr[idx_dev].ndev == dev) {
bypass_proc_remove_dev_sd(&bpctl_dev_arr
[idx_dev]);
bpctl_dev_arr[idx_dev].ndev = NULL;
return NOTIFY_DONE;
}
}
return NOTIFY_DONE;
}
if (event == NETDEV_CHANGENAME) {
int idx_dev = 0;
for (idx_dev = 0;
((bpctl_dev_arr[idx_dev].pdev != NULL)
&& (idx_dev < device_num)); idx_dev++) {
if (bpctl_dev_arr[idx_dev].ndev == dev) {
bypass_proc_remove_dev_sd(&bpctl_dev_arr
[idx_dev]);
bypass_proc_create_dev_sd(&bpctl_dev_arr
[idx_dev]);
return NOTIFY_DONE;
}
}
return NOTIFY_DONE;
}
switch (event) {
case NETDEV_CHANGE:{
if (netif_carrier_ok(dev))
return NOTIFY_DONE;
dev_num = get_dev_idx(dev->ifindex);
if (dev_num == -1)
return NOTIFY_DONE;
pbpctl_dev = &bpctl_dev_arr[dev_num];
if (!pbpctl_dev)
return NOTIFY_DONE;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
else
pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
if (!pbpctl_dev_m)
return NOTIFY_DONE;
ret = bypass_status(pbpctl_dev_m);
if (ret == 1)
printk("bpmod: %s is in the Bypass mode now",
dev->name);
ret_d = disc_status(pbpctl_dev_m);
if (ret_d == 1)
printk
("bpmod: %s is in the Disconnect mode now",
dev->name);
if (ret || ret_d) {
wdt_timer(pbpctl_dev_m, &time_left);
if (time_left == -1)
printk("; WDT has expired");
printk(".\n");
}
return NOTIFY_DONE;
}
default:
return NOTIFY_DONE;
}
return NOTIFY_DONE;
}
static struct notifier_block bp_notifier_block = {
.notifier_call = bp_device_event,
};
static int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
int wdt_time_left(struct bpctl_dev *pbpctl_dev);
static void write_pulse(struct bpctl_dev *pbpctl_dev,
unsigned int ctrl_ext,
unsigned char value, unsigned char len)
{
unsigned char ctrl_val = 0;
unsigned int i = len;
unsigned int ctrl = 0;
struct bpctl_dev *pbpctl_dev_c = NULL;
if (pbpctl_dev->bp_i80)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
if (pbpctl_dev->bp_540)
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
if (pbpctl_dev->bp_10g9) {
pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_c)
return;
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
}
while (i--) {
ctrl_val = (value >> i) & 0x1;
if (ctrl_val) {
if (pbpctl_dev->bp_10g9) {
/* To start management : MCLK 1, MDIO 1, output */
/* DATA 1 CLK 1 */
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
ctrl_ext |
BP10G_MDIO_DATA_OUT9);
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
(ctrl | BP10G_MCLK_DATA_OUT9 |
BP10G_MCLK_DIR_OUT9));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DATA5
|
BPCTLI_CTRL_EXT_MCLK_DATA5));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80
|
BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, (ctrl |
BPCTLI_CTRL_EXT_MCLK_DIR80
|
BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl |
BP540_MDIO_DIR
|
BP540_MDIO_DATA
|
BP540_MCLK_DIR
|
BP540_MCLK_DATA));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_SET |
BP10GB_MCLK_SET) &
~(BP10GB_MCLK_DIR |
BP10GB_MDIO_DIR |
BP10GB_MDIO_CLR |
BP10GB_MCLK_CLR));
} else if (!pbpctl_dev->bp_10g)
/* To start management : MCLK 1, MDIO 1, output */
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
(ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR |
BPCTLI_CTRL_EXT_MDIO_DIR |
BPCTLI_CTRL_EXT_MDIO_DATA |
BPCTLI_CTRL_EXT_MCLK_DATA));
else {
/* To start management : MCLK 1, MDIO 1, output*/
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext | BP10G_MCLK_DATA_OUT
| BP10G_MDIO_DATA_OUT));
}
usec_delay(PULSE_TIME);
if (pbpctl_dev->bp_10g9) {
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~(BP10G_MCLK_DATA_OUT9))); */
/* DATA 1 CLK 0 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
ctrl_ext |
BP10G_MDIO_DATA_OUT9);
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
(ctrl | BP10G_MCLK_DIR_OUT9) &
~BP10G_MCLK_DATA_OUT9);
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5 |
BPCTLI_CTRL_EXT_MDIO_DIR5 |
BPCTLI_CTRL_EXT_MDIO_DATA5)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80
|
BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl |
BPCTLI_CTRL_EXT_MCLK_DIR80)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA80)));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(ctrl | BP540_MDIO_DIR |
BP540_MDIO_DATA |
BP540_MCLK_DIR) &
~(BP540_MCLK_DATA));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_SET |
BP10GB_MCLK_CLR) &
~(BP10GB_MCLK_DIR |
BP10GB_MDIO_DIR |
BP10GB_MDIO_CLR |
BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR |
BPCTLI_CTRL_EXT_MDIO_DIR |
BPCTLI_CTRL_EXT_MDIO_DATA)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
((ctrl_ext |
BP10G_MDIO_DATA_OUT) &
~(BP10G_MCLK_DATA_OUT)));
}
usec_delay(PULSE_TIME);
} else {
if (pbpctl_dev->bp_10g9) {
/* DATA 0 CLK 1 */
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext &
~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
(ctrl | BP10G_MCLK_DATA_OUT9 |
BP10G_MCLK_DIR_OUT9));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5 |
BPCTLI_CTRL_EXT_MDIO_DIR5 |
BPCTLI_CTRL_EXT_MCLK_DATA5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA80)));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
(ctrl |
BPCTLI_CTRL_EXT_MCLK_DIR80 |
BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP540_MCLK_DIR |
BP540_MCLK_DATA |
BP540_MDIO_DIR) &
~(BP540_MDIO_DATA)));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR |
BP10GB_MCLK_SET) &
~(BP10GB_MCLK_DIR |
BP10GB_MDIO_DIR |
BP10GB_MDIO_SET |
BP10GB_MCLK_CLR));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR |
BPCTLI_CTRL_EXT_MDIO_DIR |
BPCTLI_CTRL_EXT_MCLK_DATA)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
((ctrl_ext |
BP10G_MCLK_DATA_OUT) &
~BP10G_MDIO_DATA_OUT));
}
usec_delay(PULSE_TIME);
if (pbpctl_dev->bp_10g9) {
/* DATA 0 CLK 0 */
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext &
~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5 |
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~(BPCTLI_CTRL_EXT_MCLK_DATA5
|
BPCTLI_CTRL_EXT_MDIO_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl |
BPCTLI_CTRL_EXT_MCLK_DIR80)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA80)));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP540_MCLK_DIR |
BP540_MDIO_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR |
BP10GB_MCLK_CLR) &
~(BP10GB_MCLK_DIR |
BP10GB_MDIO_DIR |
BP10GB_MDIO_SET |
BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR |
BPCTLI_CTRL_EXT_MDIO_DIR) &
~(BPCTLI_CTRL_EXT_MCLK_DATA
|
BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT |
BP10G_MDIO_DATA_OUT)));
}
usec_delay(PULSE_TIME);
}
}
}
static int read_pulse(struct bpctl_dev *pbpctl_dev, unsigned int ctrl_ext,
unsigned char len)
{
unsigned char ctrl_val = 0;
unsigned int i = len;
unsigned int ctrl = 0;
struct bpctl_dev *pbpctl_dev_c = NULL;
if (pbpctl_dev->bp_i80)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
if (pbpctl_dev->bp_540)
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
if (pbpctl_dev->bp_10g9) {
pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_c)
return -1;
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
}
while (i--) {
if (pbpctl_dev->bp_10g9) {
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~BP10G_MCLK_DATA_OUT9)); */
/* DATA ? CLK 0 */
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DIR5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl_ext &
~BPCTLI_CTRL_EXT_MDIO_DIR80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80)
& ~(BPCTLI_CTRL_EXT_MCLK_DATA80)));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP540_MCLK_DIR) &
~(BP540_MDIO_DIR | BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_DIR |
BP10GB_MCLK_CLR) & ~(BP10GB_MCLK_DIR |
BP10GB_MDIO_CLR |
BP10GB_MDIO_SET |
BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR)
&
~
(BPCTLI_CTRL_EXT_MDIO_DIR
|
BPCTLI_CTRL_EXT_MCLK_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP, ((ctrl_ext | BP10G_MDIO_DATA_OUT) & ~BP10G_MCLK_DATA_OUT)); /* ? */
/* printk("0x28=0x%x\n",BP10G_READ_REG(pbpctl_dev,EODSDP);); */
}
usec_delay(PULSE_TIME);
if (pbpctl_dev->bp_10g9) {
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */
/* DATA ? CLK 1 */
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
(ctrl | BP10G_MCLK_DATA_OUT9 |
BP10G_MCLK_DIR_OUT9));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DIR5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl_ext &
~(BPCTLI_CTRL_EXT_MDIO_DIR80)));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
(ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 |
BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP540_MCLK_DIR |
BP540_MCLK_DATA) &
~(BP540_MDIO_DIR)));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_DIR |
BP10GB_MCLK_SET) & ~(BP10GB_MCLK_DIR |
BP10GB_MDIO_CLR |
BP10GB_MDIO_SET |
BP10GB_MCLK_CLR));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MCLK_DATA)
&
~
(BPCTLI_CTRL_EXT_MDIO_DIR)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext | BP10G_MCLK_DATA_OUT |
BP10G_MDIO_DATA_OUT));
}
if (pbpctl_dev->bp_10g9)
ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
else if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_i80))
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
else if (pbpctl_dev->bp_540)
ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP);
else if (pbpctl_dev->bp_10gb)
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
else if (!pbpctl_dev->bp_10g)
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
else
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
usec_delay(PULSE_TIME);
if (pbpctl_dev->bp_10g9) {
if (ctrl_ext & BP10G_MDIO_DATA_IN9)
ctrl_val |= 1 << i;
} else if (pbpctl_dev->bp_fiber5) {
if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA5)
ctrl_val |= 1 << i;
} else if (pbpctl_dev->bp_i80) {
if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA80)
ctrl_val |= 1 << i;
} else if (pbpctl_dev->bp_540) {
if (ctrl_ext & BP540_MDIO_DATA)
ctrl_val |= 1 << i;
} else if (pbpctl_dev->bp_10gb) {
if (ctrl_ext & BP10GB_MDIO_DATA)
ctrl_val |= 1 << i;
} else if (!pbpctl_dev->bp_10g) {
if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA)
ctrl_val |= 1 << i;
} else {
if (ctrl_ext & BP10G_MDIO_DATA_IN)
ctrl_val |= 1 << i;
}
}
return ctrl_val;
}
static void write_reg(struct bpctl_dev *pbpctl_dev, unsigned char value,
unsigned char addr)
{
uint32_t ctrl_ext = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_c = NULL;
unsigned long flags;
if (pbpctl_dev->bp_10g9) {
pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_c)
return;
}
if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) &&
(pbpctl_dev->bp_ext_ver < PXG4BPFI_VER))
wdt_time_left(pbpctl_dev);
#ifdef BP_SYNC_FLAG
spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 1);
#endif
if (pbpctl_dev->bp_10g9) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
/* DATA 0 CLK 0 */
/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
~BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
ctrl = ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |
BP540_MDIO_DIR |
BP540_MCLK_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA
|
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
}
usec_delay(CMND_INTERVAL);
/*send sync cmd */
write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN);
/*send wr cmd */
write_pulse(pbpctl_dev, ctrl_ext, WR_CMD_VAL, WR_CMD_LEN);
write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN);
/*write data */
write_pulse(pbpctl_dev, ctrl_ext, value, WR_DATA_LEN);
if (pbpctl_dev->bp_10g9) {
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
/* DATA 0 CLK 0 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
~BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |
BP540_MDIO_DIR |
BP540_MCLK_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA
|
BPCTLI_CTRL_EXT_MCLK_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
}
usec_delay(CMND_INTERVAL * 4);
if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) &&
(pbpctl_dev->bp_ext_ver < PXG4BPFI_VER) && (addr == CMND_REG_ADDR))
pbpctl_dev->bypass_wdt_on_time = jiffies;
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 0);
#endif
}
static void write_data(struct bpctl_dev *pbpctl_dev, unsigned char value)
{
write_reg(pbpctl_dev, value, CMND_REG_ADDR);
}
static int read_reg(struct bpctl_dev *pbpctl_dev, unsigned char addr)
{
uint32_t ctrl_ext = 0, ctrl = 0, ctrl_value = 0;
struct bpctl_dev *pbpctl_dev_c = NULL;
#ifdef BP_SYNC_FLAG
unsigned long flags;
spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 1);
#endif
if (pbpctl_dev->bp_10g9) {
pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_c)
return -1;
}
if (pbpctl_dev->bp_10g9) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
/* DATA 0 CLK 0 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
~BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
BP540_MDIO_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_SET));
#if 0
/*BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, (ctrl_ext | BP10GB_MCLK_DIR | BP10GB_MDIO_DIR|
BP10GB_MCLK_CLR|BP10GB_MDIO_CLR));
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
printk("1reg=%x\n", ctrl_ext); */
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, ((ctrl_ext |
BP10GB_MCLK_SET |
BP10GB_MDIO_CLR))
& ~(BP10GB_MCLK_CLR | BP10GB_MDIO_SET |
BP10GB_MCLK_DIR | BP10GB_MDIO_DIR));
/* bnx2x_set_spio(pbpctl_dev, 5, MISC_REGISTERS_SPIO_OUTPUT_LOW);
bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_OUTPUT_LOW);
bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_INPUT_HI_Z); */
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
printk("2reg=%x\n", ctrl_ext);
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 0);
#endif
return 0;
#endif
} else if (!pbpctl_dev->bp_10g) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA
|
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
}
usec_delay(CMND_INTERVAL);
/*send sync cmd */
write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN);
/*send rd cmd */
write_pulse(pbpctl_dev, ctrl_ext, RD_CMD_VAL, RD_CMD_LEN);
/*send addr */
write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN);
/*read data */
/* zero */
if (pbpctl_dev->bp_10g9) {
/* DATA 0 CLK 1 */
/*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext | BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
(ctrl | BP10G_MCLK_DATA_OUT9 |
BP10G_MCLK_DIR_OUT9));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl_ext &
~(BPCTLI_CTRL_EXT_MDIO_DATA80 |
BPCTLI_CTRL_EXT_MDIO_DIR80)));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
(ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 |
BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(((ctrl | BP540_MDIO_DIR | BP540_MCLK_DIR |
BP540_MCLK_DATA) & ~BP540_MDIO_DATA)));
} else if (pbpctl_dev->bp_10gb) {
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_DIR | BP10GB_MCLK_SET)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_SET |
BP10GB_MDIO_CLR | BP10GB_MCLK_CLR));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MCLK_DATA)
&
~
(BPCTLI_CTRL_EXT_MDIO_DIR
|
BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext | BP10G_MCLK_DATA_OUT |
BP10G_MDIO_DATA_OUT));
}
usec_delay(PULSE_TIME);
ctrl_value = read_pulse(pbpctl_dev, ctrl_ext, RD_DATA_LEN);
if (pbpctl_dev->bp_10g9) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
/* DATA 0 CLK 0 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
~BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
BP540_MDIO_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA
|
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
}
usec_delay(CMND_INTERVAL * 4);
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 0);
#endif
return ctrl_value;
}
static int wdt_pulse(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_c = NULL;
#ifdef BP_SYNC_FLAG
unsigned long flags;
spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
#else
if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
return -1;
#endif
if (pbpctl_dev->bp_10g9) {
pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_c)
return -1;
}
if (pbpctl_dev->bp_10g9) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL);
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
/* DATA 0 CLK 0 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)));
} else if (pbpctl_dev->bp_i80) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL);
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
~BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
ctrl_ext = ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
BP540_MDIO_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA
|
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
}
if (pbpctl_dev->bp_10g9) {
/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */
/* DATA 0 CLK 1 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
(ctrl | BP10G_MCLK_DATA_OUT9 |
BP10G_MCLK_DIR_OUT9));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5
|
BPCTLI_CTRL_EXT_MCLK_DATA5)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
(ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 |
BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |
BP540_MDIO_DIR |
BP540_MCLK_DIR |
BP540_MCLK_DATA) &
~BP540_MDIO_DATA));
} else if (pbpctl_dev->bp_10gb) {
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_SET)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_CLR));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR
|
BPCTLI_CTRL_EXT_MCLK_DATA)
&
~
(BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
((ctrl_ext | BP10G_MCLK_DATA_OUT) &
~BP10G_MDIO_DATA_OUT));
}
usec_delay(WDT_INTERVAL);
if (pbpctl_dev->bp_10g9) {
/* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */
/* DATA 0 CLK 0 */
BP10G_WRITE_REG(pbpctl_dev, I2CCTL,
(ctrl_ext & ~BP10G_MDIO_DATA_OUT9));
BP10G_WRITE_REG(pbpctl_dev_c, ESDP,
((ctrl | BP10G_MCLK_DIR_OUT9) &
~(BP10G_MCLK_DATA_OUT9)));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR5
|
BPCTLI_CTRL_EXT_MDIO_DIR5)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA5
|
BPCTLI_CTRL_EXT_MDIO_DATA5)));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext |
BPCTLI_CTRL_EXT_MDIO_DIR80)
&
~BPCTLI_CTRL_EXT_MDIO_DATA80));
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) &
~BPCTLI_CTRL_EXT_MCLK_DATA80));
} else if (pbpctl_dev->bp_540) {
BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR |
BP540_MDIO_DIR) &
~(BP540_MDIO_DATA |
BP540_MCLK_DATA)));
} else if (pbpctl_dev->bp_10gb) {
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO,
(ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)
& ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR |
BP10GB_MDIO_SET | BP10GB_MCLK_SET));
} else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR
|
BPCTLI_CTRL_EXT_MDIO_DIR)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA
|
BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
}
if ((pbpctl_dev->wdt_status == WDT_STATUS_EN))
/*&& (pbpctl_dev->bp_ext_ver<PXG4BPFI_VER) */
pbpctl_dev->bypass_wdt_on_time = jiffies;
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
#endif
usec_delay(CMND_INTERVAL * 4);
return 0;
}
static void data_pulse(struct bpctl_dev *pbpctl_dev, unsigned char value)
{
uint32_t ctrl_ext = 0;
#ifdef BP_SYNC_FLAG
unsigned long flags;
#endif
wdt_time_left(pbpctl_dev);
#ifdef BP_SYNC_FLAG
spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 1);
#endif
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP7_DIR) &
~(BPCTLI_CTRL_EXT_SDP6_DATA |
BPCTLI_CTRL_EXT_SDP7_DATA)));
usec_delay(INIT_CMND_INTERVAL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP7_DIR |
BPCTLI_CTRL_EXT_SDP6_DATA) &
~
(BPCTLI_CTRL_EXT_SDP7_DATA)));
usec_delay(INIT_CMND_INTERVAL);
while (value) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP7_DIR |
BPCTLI_CTRL_EXT_SDP6_DATA |
BPCTLI_CTRL_EXT_SDP7_DATA);
usec_delay(PULSE_INTERVAL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR
|
BPCTLI_CTRL_EXT_SDP7_DIR
|
BPCTLI_CTRL_EXT_SDP6_DATA)
&
~BPCTLI_CTRL_EXT_SDP7_DATA));
usec_delay(PULSE_INTERVAL);
value--;
}
usec_delay(INIT_CMND_INTERVAL - PULSE_INTERVAL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP7_DIR) &
~(BPCTLI_CTRL_EXT_SDP6_DATA |
BPCTLI_CTRL_EXT_SDP7_DATA)));
usec_delay(WDT_TIME_CNT);
if (pbpctl_dev->wdt_status == WDT_STATUS_EN)
pbpctl_dev->bypass_wdt_on_time = jiffies;
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
#else
atomic_set(&pbpctl_dev->wdt_busy, 0);
#endif
}
static int send_wdt_pulse(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
#ifdef BP_SYNC_FLAG
unsigned long flags;
spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags);
#else
if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
return -1;
#endif
wdt_time_left(pbpctl_dev);
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | /* 1 */
BPCTLI_CTRL_EXT_SDP7_DIR |
BPCTLI_CTRL_EXT_SDP7_DATA);
usec_delay(PULSE_INTERVAL);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */
BPCTLI_CTRL_EXT_SDP7_DIR) &
~BPCTLI_CTRL_EXT_SDP7_DATA));
usec_delay(PULSE_INTERVAL);
if (pbpctl_dev->wdt_status == WDT_STATUS_EN)
pbpctl_dev->bypass_wdt_on_time = jiffies;
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
#endif
return 0;
}
static void send_bypass_clear_pulse(struct bpctl_dev *pbpctl_dev,
unsigned int value)
{
uint32_t ctrl_ext = 0;
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */
BPCTLI_CTRL_EXT_SDP6_DIR) &
~BPCTLI_CTRL_EXT_SDP6_DATA));
usec_delay(PULSE_INTERVAL);
while (value) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | /* 1 */
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP6_DATA);
usec_delay(PULSE_INTERVAL);
value--;
}
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */
BPCTLI_CTRL_EXT_SDP6_DIR) &
~BPCTLI_CTRL_EXT_SDP6_DATA));
usec_delay(PULSE_INTERVAL);
}
/* #endif OLD_FW */
#ifdef BYPASS_DEBUG
int pulse_set_fn(struct bpctl_dev *pbpctl_dev, unsigned int counter)
{
uint32_t ctrl_ext = 0;
if (!pbpctl_dev)
return -1;
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter);
pbpctl_dev->bypass_wdt_status = 0;
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter);
} else {
wdt_time_left(pbpctl_dev);
if (pbpctl_dev->wdt_status == WDT_STATUS_EN) {
pbpctl_dev->wdt_status = 0;
data_pulse(pbpctl_dev, counter);
pbpctl_dev->wdt_status = WDT_STATUS_EN;
pbpctl_dev->bypass_wdt_on_time = jiffies;
} else
data_pulse(pbpctl_dev, counter);
}
return 0;
}
int zero_set_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
if (!pbpctl_dev)
return -1;
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
printk("zero_set");
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_MCLK_DIR)
&
~
(BPCTLI_CTRL_EXT_MCLK_DATA
|
BPCTLI_CTRL_EXT_MDIO_DIR
|
BPCTLI_CTRL_EXT_MDIO_DATA)));
}
return 0;
}
int pulse_get2_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl_value = 0;
if (!pbpctl_dev)
return -1;
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
printk("pulse_get_fn\n");
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
ctrl_value = read_pulse_2(pbpctl_dev, ctrl_ext);
printk("read:%d\n", ctrl_value);
}
return ctrl_value;
}
int pulse_get1_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl_value = 0;
if (!pbpctl_dev)
return -1;
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
printk("pulse_get_fn\n");
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
ctrl_value = read_pulse_1(pbpctl_dev, ctrl_ext);
printk("read:%d\n", ctrl_value);
}
return ctrl_value;
}
int gpio6_set_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP6_DATA);
return 0;
}
int gpio7_set_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext |
BPCTLI_CTRL_EXT_SDP7_DIR |
BPCTLI_CTRL_EXT_SDP7_DATA);
return 0;
}
int gpio7_clear_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_SDP7_DIR) &
~BPCTLI_CTRL_EXT_SDP7_DATA));
return 0;
}
int gpio6_clear_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext |
BPCTLI_CTRL_EXT_SDP6_DIR) &
~BPCTLI_CTRL_EXT_SDP6_DATA));
return 0;
}
#endif /*BYPASS_DEBUG */
static struct bpctl_dev *lookup_port(struct bpctl_dev *dev)
{
struct bpctl_dev *p;
int n;
for (n = 0, p = bpctl_dev_arr; n < device_num && p->pdev; n++) {
if (p->bus == dev->bus
&& p->slot == dev->slot
&& p->func == (dev->func ^ 1))
return p;
}
return NULL;
}
static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev) {
if (pbpctl_dev->func == 0 || pbpctl_dev->func == 2)
return lookup_port(pbpctl_dev);
}
return NULL;
}
static struct bpctl_dev *get_master_port_fn(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev) {
if (pbpctl_dev->func == 1 || pbpctl_dev->func == 3)
return lookup_port(pbpctl_dev);
}
return NULL;
}
/**************************************/
/**************INTEL API***************/
/**************************************/
static void write_data_port_int(struct bpctl_dev *pbpctl_dev,
unsigned char ctrl_value)
{
uint32_t value;
value = BPCTL_READ_REG(pbpctl_dev, CTRL);
/* Make SDP0 Pin Directonality to Output */
value |= BPCTLI_CTRL_SDP0_DIR;
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value);
value &= ~BPCTLI_CTRL_SDP0_DATA;
value |= ((ctrl_value & 0x1) << BPCTLI_CTRL_SDP0_SHIFT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value);
value = (BPCTL_READ_REG(pbpctl_dev, CTRL_EXT));
/* Make SDP2 Pin Directonality to Output */
value |= BPCTLI_CTRL_EXT_SDP6_DIR;
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value);
value &= ~BPCTLI_CTRL_EXT_SDP6_DATA;
value |= (((ctrl_value & 0x2) >> 1) << BPCTLI_CTRL_EXT_SDP6_SHIFT);
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value);
}
static int write_data_int(struct bpctl_dev *pbpctl_dev, unsigned char value)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
return -1;
atomic_set(&pbpctl_dev->wdt_busy, 1);
write_data_port_int(pbpctl_dev, value & 0x3);
write_data_port_int(pbpctl_dev_b, ((value & 0xc) >> 2));
atomic_set(&pbpctl_dev->wdt_busy, 0);
return 0;
}
static int wdt_pulse_int(struct bpctl_dev *pbpctl_dev)
{
if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
return -1;
if ((write_data_int(pbpctl_dev, RESET_WDT_INT)) < 0)
return -1;
msec_delay_bp(CMND_INTERVAL_INT);
if ((write_data_int(pbpctl_dev, CMND_OFF_INT)) < 0)
return -1;
msec_delay_bp(CMND_INTERVAL_INT);
if (pbpctl_dev->wdt_status == WDT_STATUS_EN)
pbpctl_dev->bypass_wdt_on_time = jiffies;
return 0;
}
/*************************************/
/************* COMMANDS **************/
/*************************************/
/* CMND_ON 0x4 (100)*/
static int cmnd_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
return 0;
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
write_data(pbpctl_dev, CMND_ON);
else
data_pulse(pbpctl_dev, CMND_ON);
ret = 0;
}
return ret;
}
/* CMND_OFF 0x2 (10)*/
static int cmnd_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, CMND_OFF_INT);
msec_delay_bp(CMND_INTERVAL_INT);
} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
write_data(pbpctl_dev, CMND_OFF);
else
data_pulse(pbpctl_dev, CMND_OFF);
ret = 0;
}
return ret;
}
/* BYPASS_ON (0xa)*/
static int bypass_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & BP_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, BYPASS_ON_INT);
msec_delay_bp(BYPASS_DELAY_INT);
pbpctl_dev->bp_status_un = 0;
} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
write_data(pbpctl_dev, BYPASS_ON);
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
msec_delay_bp(LATCH_DELAY);
} else
data_pulse(pbpctl_dev, BYPASS_ON);
ret = 0;
}
return ret;
}
/* BYPASS_OFF (0x8 111)*/
static int bypass_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & BP_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
msec_delay_bp(BYPASS_DELAY_INT);
write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT);
msec_delay_bp(BYPASS_DELAY_INT);
pbpctl_dev->bp_status_un = 0;
} else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
write_data(pbpctl_dev, BYPASS_OFF);
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
msec_delay_bp(LATCH_DELAY);
} else
data_pulse(pbpctl_dev, BYPASS_OFF);
ret = 0;
}
return ret;
}
/* TAP_OFF (0x9)*/
static int tap_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if ((pbpctl_dev->bp_caps & TAP_CAP)
&& (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) {
write_data(pbpctl_dev, TAP_OFF);
msec_delay_bp(LATCH_DELAY);
ret = 0;
}
return ret;
}
/* TAP_ON (0xb)*/
static int tap_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if ((pbpctl_dev->bp_caps & TAP_CAP)
&& (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) {
write_data(pbpctl_dev, TAP_ON);
msec_delay_bp(LATCH_DELAY);
ret = 0;
}
return ret;
}
/* DISC_OFF (0x9)*/
static int disc_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
write_data(pbpctl_dev, DISC_OFF);
msec_delay_bp(LATCH_DELAY);
} else
ret = BP_NOT_CAP;
return ret;
}
/* DISC_ON (0xb)*/
static int disc_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
write_data(pbpctl_dev, /*DISC_ON */ 0x85);
msec_delay_bp(LATCH_DELAY);
} else
ret = BP_NOT_CAP;
return ret;
}
/*TWO_PORT_LINK_HW_EN (0xe)*/
static int tpl_hw_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
return BP_NOT_CAP;
if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
cmnd_on(pbpctl_dev);
write_data(pbpctl_dev, TPL2_ON);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
cmnd_off(pbpctl_dev);
return ret;
}
if (TPL_IF_SERIES(pbpctl_dev->subdevice)) {
ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL);
BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL,
((ctrl | BPCTLI_CTRL_SWDPIO0) &
~BPCTLI_CTRL_SWDPIN0));
} else
ret = BP_NOT_CAP;
return ret;
}
/*TWO_PORT_LINK_HW_DIS (0xc)*/
static int tpl_hw_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
return BP_NOT_CAP;
if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
cmnd_on(pbpctl_dev);
write_data(pbpctl_dev, TPL2_OFF);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
cmnd_off(pbpctl_dev);
return ret;
}
if (TPL_IF_SERIES(pbpctl_dev->subdevice)) {
ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL);
BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL,
(ctrl | BPCTLI_CTRL_SWDPIO0 |
BPCTLI_CTRL_SWDPIN0));
} else
ret = BP_NOT_CAP;
return ret;
}
/* WDT_OFF (0x6 110)*/
static int wdt_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
bypass_off(pbpctl_dev);
else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
write_data(pbpctl_dev, WDT_OFF);
else
data_pulse(pbpctl_dev, WDT_OFF);
pbpctl_dev->wdt_status = WDT_STATUS_DIS;
ret = 0;
}
return ret;
}
/* WDT_ON (0x10)*/
/***Global***/
static unsigned int
wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 };
static int wdt_on(struct bpctl_dev *pbpctl_dev, unsigned int timeout)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
unsigned int pulse = 0, temp_value = 0, temp_cnt = 0;
pbpctl_dev->wdt_status = 0;
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
for (; wdt_val_array[temp_cnt]; temp_cnt++)
if (timeout <= wdt_val_array[temp_cnt])
break;
if (!wdt_val_array[temp_cnt])
temp_cnt--;
timeout = wdt_val_array[temp_cnt];
temp_cnt += 0x7;
write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
msec_delay_bp(BYPASS_DELAY_INT);
pbpctl_dev->bp_status_un = 0;
write_data_int(pbpctl_dev, temp_cnt);
pbpctl_dev->bypass_wdt_on_time = jiffies;
msec_delay_bp(CMND_INTERVAL_INT);
pbpctl_dev->bypass_timer_interval = timeout;
} else {
timeout =
(timeout <
TIMEOUT_UNIT ? TIMEOUT_UNIT : (timeout >
WDT_TIMEOUT_MAX ?
WDT_TIMEOUT_MAX :
timeout));
temp_value = timeout / 100;
while ((temp_value >>= 1))
temp_cnt++;
if (timeout > ((1 << temp_cnt) * 100))
temp_cnt++;
pbpctl_dev->bypass_wdt_on_time = jiffies;
pulse = (WDT_ON | temp_cnt);
if (pbpctl_dev->bp_ext_ver == OLD_IF_VER)
data_pulse(pbpctl_dev, pulse);
else
write_data(pbpctl_dev, pulse);
pbpctl_dev->bypass_timer_interval =
(1 << temp_cnt) * 100;
}
pbpctl_dev->wdt_status = WDT_STATUS_EN;
return 0;
}
return BP_NOT_CAP;
}
static void bp75_put_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
{
u32 swsm;
swsm = BPCTL_READ_REG(pbpctl_dev, SWSM);
swsm &= ~(BPCTLI_SWSM_SMBI | BPCTLI_SWSM_SWESMBI);
BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm);
}
static s32 bp75_get_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
{
u32 swsm;
s32 ret_val = 0;
s32 timeout = 8192 + 1;
s32 i = 0;
/* Get the SW semaphore */
while (i < timeout) {
swsm = BPCTL_READ_REG(pbpctl_dev, SWSM);
if (!(swsm & BPCTLI_SWSM_SMBI))
break;
usec_delay(50);
i++;
}
if (i == timeout) {
printk
("bpctl_mod: Driver can't access device - SMBI bit is set.\n");
ret_val = -1;
goto out;
}
/* Get the FW semaphore. */
for (i = 0; i < timeout; i++) {
swsm = BPCTL_READ_REG(pbpctl_dev, SWSM);
BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm | BPCTLI_SWSM_SWESMBI);
/* Semaphore acquired if bit latched */
if (BPCTL_READ_REG(pbpctl_dev, SWSM) & BPCTLI_SWSM_SWESMBI)
break;
usec_delay(50);
}
if (i == timeout) {
/* Release semaphores */
bp75_put_hw_semaphore_generic(pbpctl_dev);
printk("bpctl_mod: Driver can't access the NVM\n");
ret_val = -1;
goto out;
}
out:
return ret_val;
}
static void bp75_release_phy(struct bpctl_dev *pbpctl_dev)
{
u16 mask = BPCTLI_SWFW_PHY0_SM;
u32 swfw_sync;
s32 ret_val;
if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3))
mask = BPCTLI_SWFW_PHY1_SM;
do
ret_val = bp75_get_hw_semaphore_generic(pbpctl_dev);
while (ret_val != 0);
swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC);
swfw_sync &= ~mask;
BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync);
bp75_put_hw_semaphore_generic(pbpctl_dev);
}
static s32 bp75_acquire_phy(struct bpctl_dev *pbpctl_dev)
{
u16 mask = BPCTLI_SWFW_PHY0_SM;
u32 swfw_sync;
u32 swmask;
u32 fwmask;
s32 ret_val = 0;
s32 i = 0, timeout = 200;
if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3))
mask = BPCTLI_SWFW_PHY1_SM;
swmask = mask;
fwmask = mask << 16;
while (i < timeout) {
if (bp75_get_hw_semaphore_generic(pbpctl_dev)) {
ret_val = -1;
goto out;
}
swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC);
if (!(swfw_sync & (fwmask | swmask)))
break;
bp75_put_hw_semaphore_generic(pbpctl_dev);
mdelay(5);
i++;
}
if (i == timeout) {
printk
("bpctl_mod: Driver can't access resource, SW_FW_SYNC timeout.\n");
ret_val = -1;
goto out;
}
swfw_sync |= swmask;
BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync);
bp75_put_hw_semaphore_generic(pbpctl_dev);
out:
return ret_val;
}
static s32 bp75_read_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset,
u16 *data)
{
u32 i, mdic = 0;
s32 ret_val = 0;
u32 phy_addr = 1;
mdic = ((offset << BPCTLI_MDIC_REG_SHIFT) |
(phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_READ));
BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic);
for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) {
usec_delay(50);
mdic = BPCTL_READ_REG(pbpctl_dev, MDIC);
if (mdic & BPCTLI_MDIC_READY)
break;
}
if (!(mdic & BPCTLI_MDIC_READY)) {
printk("bpctl_mod: MDI Read did not complete\n");
ret_val = -1;
goto out;
}
if (mdic & BPCTLI_MDIC_ERROR) {
printk("bpctl_mod: MDI Error\n");
ret_val = -1;
goto out;
}
*data = (u16) mdic;
out:
return ret_val;
}
static s32 bp75_write_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset,
u16 data)
{
u32 i, mdic = 0;
s32 ret_val = 0;
u32 phy_addr = 1;
mdic = (((u32) data) |
(offset << BPCTLI_MDIC_REG_SHIFT) |
(phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_WRITE));
BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic);
for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) {
usec_delay(50);
mdic = BPCTL_READ_REG(pbpctl_dev, MDIC);
if (mdic & BPCTLI_MDIC_READY)
break;
}
if (!(mdic & BPCTLI_MDIC_READY)) {
printk("bpctl_mod: MDI Write did not complete\n");
ret_val = -1;
goto out;
}
if (mdic & BPCTLI_MDIC_ERROR) {
printk("bpctl_mod: MDI Error\n");
ret_val = -1;
goto out;
}
out:
return ret_val;
}
static s32 bp75_read_phy_reg(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
{
s32 ret_val = 0;
ret_val = bp75_acquire_phy(pbpctl_dev);
if (ret_val)
goto out;
if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) {
ret_val = bp75_write_phy_reg_mdic(pbpctl_dev,
BPCTLI_IGP01E1000_PHY_PAGE_SELECT,
(u16) offset);
if (ret_val)
goto release;
}
ret_val =
bp75_read_phy_reg_mdic(pbpctl_dev,
BPCTLI_MAX_PHY_REG_ADDRESS & offset, data);
release:
bp75_release_phy(pbpctl_dev);
out:
return ret_val;
}
static s32 bp75_write_phy_reg(struct bpctl_dev *pbpctl_dev, u32 offset, u16 data)
{
s32 ret_val = 0;
ret_val = bp75_acquire_phy(pbpctl_dev);
if (ret_val)
goto out;
if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) {
ret_val = bp75_write_phy_reg_mdic(pbpctl_dev,
BPCTLI_IGP01E1000_PHY_PAGE_SELECT,
(u16) offset);
if (ret_val)
goto release;
}
ret_val =
bp75_write_phy_reg_mdic(pbpctl_dev,
BPCTLI_MAX_PHY_REG_ADDRESS & offset, data);
release:
bp75_release_phy(pbpctl_dev);
out:
return ret_val;
}
/* SET_TX (non-Bypass command :)) */
static int set_tx(struct bpctl_dev *pbpctl_dev, int tx_state)
{
int ret = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
else
pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
if (pbpctl_dev_m == NULL)
return BP_NOT_CAP;
if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
if (!tx_state) {
if (pbpctl_dev->bp_540) {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(ctrl | BP10G_SDP1_DIR |
BP10G_SDP1_DATA));
} else {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl | BPCTLI_CTRL_SDP1_DIR
| BPCTLI_CTRL_SWDPIN1));
}
} else {
if (pbpctl_dev->bp_540) {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP10G_SDP1_DIR) &
~BP10G_SDP1_DATA));
} else {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl |
BPCTLI_CTRL_SDP1_DIR) &
~BPCTLI_CTRL_SWDPIN1));
}
return ret;
}
} else if (pbpctl_dev->bp_caps & TX_CTL_CAP) {
if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) {
if (tx_state) {
uint16_t mii_reg;
ret = bp75_read_phy_reg(pbpctl_dev,
BPCTLI_PHY_CONTROL,
&mii_reg);
if (!ret) {
if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) {
ret =
bp75_write_phy_reg
(pbpctl_dev,
BPCTLI_PHY_CONTROL,
mii_reg &
~BPCTLI_MII_CR_POWER_DOWN);
}
}
} else {
uint16_t mii_reg;
ret = bp75_read_phy_reg(pbpctl_dev,
BPCTLI_PHY_CONTROL,
&mii_reg);
if (!ret) {
mii_reg |= BPCTLI_MII_CR_POWER_DOWN;
ret = bp75_write_phy_reg(pbpctl_dev,
BPCTLI_PHY_CONTROL,
mii_reg);
}
}
}
if (pbpctl_dev->bp_fiber5)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
else if (pbpctl_dev->bp_10gb)
ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO);
else if (!pbpctl_dev->bp_10g)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
else
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
if (!tx_state)
if (pbpctl_dev->bp_10g9) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(ctrl | BP10G_SDP3_DATA |
BP10G_SDP3_DIR));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
(ctrl |
BPCTLI_CTRL_EXT_SDP6_DIR |
BPCTLI_CTRL_EXT_SDP6_DATA));
} else if (pbpctl_dev->bp_10gb) {
if ((pbpctl_dev->func == 1)
|| (pbpctl_dev->func == 3))
BP10GB_WRITE_REG(pbpctl_dev,
MISC_REG_GPIO,
(ctrl |
BP10GB_GPIO0_SET_P1) &
~(BP10GB_GPIO0_CLR_P1 |
BP10GB_GPIO0_OE_P1));
else
BP10GB_WRITE_REG(pbpctl_dev,
MISC_REG_GPIO,
(ctrl |
BP10GB_GPIO0_OE_P0 |
BP10GB_GPIO0_SET_P0));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl | BPCTLI_CTRL_SDP1_DIR
| BPCTLI_CTRL_SWDPIN1));
} else if (pbpctl_dev->bp_540) {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(ctrl | BP10G_SDP1_DIR |
BP10G_SDP1_DATA));
}
else if (!pbpctl_dev->bp_10g)
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl | BPCTLI_CTRL_SWDPIO0 |
BPCTLI_CTRL_SWDPIN0));
else
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(ctrl | BP10G_SDP0_DATA |
BP10G_SDP0_DIR));
else {
if (pbpctl_dev->bp_10g9) {
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP10G_SDP3_DIR) &
~BP10G_SDP3_DATA));
} else if (pbpctl_dev->bp_fiber5) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT,
((ctrl |
BPCTLI_CTRL_EXT_SDP6_DIR) &
~BPCTLI_CTRL_EXT_SDP6_DATA));
} else if (pbpctl_dev->bp_10gb) {
if ((bpctl_dev_arr->func == 1)
|| (bpctl_dev_arr->func == 3))
BP10GB_WRITE_REG(pbpctl_dev,
MISC_REG_GPIO,
(ctrl |
BP10GB_GPIO0_CLR_P1) &
~(BP10GB_GPIO0_SET_P1 |
BP10GB_GPIO0_OE_P1));
else
BP10GB_WRITE_REG(pbpctl_dev,
MISC_REG_GPIO,
(ctrl |
BP10GB_GPIO0_OE_P0 |
BP10GB_GPIO0_CLR_P0));
} else if (pbpctl_dev->bp_i80) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl |
BPCTLI_CTRL_SDP1_DIR) &
~BPCTLI_CTRL_SWDPIN1));
} else if (pbpctl_dev->bp_540) {
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP10G_SDP1_DIR) &
~BP10G_SDP1_DATA));
}
else if (!pbpctl_dev->bp_10g) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
((ctrl | BPCTLI_CTRL_SWDPIO0)
& ~BPCTLI_CTRL_SWDPIN0));
if (!PEGF_IF_SERIES(pbpctl_dev->subdevice)) {
BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL,
(ctrl &
~
(BPCTLI_CTRL_SDP0_DATA
|
BPCTLI_CTRL_SDP0_DIR)));
}
} else
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP10G_SDP0_DIR) &
~BP10G_SDP0_DATA));
}
} else
ret = BP_NOT_CAP;
return ret;
}
/* SET_FORCE_LINK (non-Bypass command :)) */
static int set_bp_force_link(struct bpctl_dev *pbpctl_dev, int tx_state)
{
int ret = 0, ctrl = 0;
if (DBI_IF_SERIES(pbpctl_dev->subdevice)) {
if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) {
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
if (!tx_state)
BP10G_WRITE_REG(pbpctl_dev, ESDP,
ctrl & ~BP10G_SDP1_DIR);
else
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP10G_SDP1_DIR) &
~BP10G_SDP1_DATA));
return ret;
}
}
return BP_NOT_CAP;
}
/*RESET_CONT 0x20 */
static int reset_cont(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
return BP_NOT_CAP;
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER)
write_data(pbpctl_dev, RESET_CONT);
else
data_pulse(pbpctl_dev, RESET_CONT);
ret = 0;
}
return ret;
}
/*DIS_BYPASS_CAP 0x22 */
static int dis_bypass_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
msec_delay_bp(BYPASS_DELAY_INT);
} else {
write_data(pbpctl_dev, BYPASS_OFF);
msec_delay_bp(LATCH_DELAY);
write_data(pbpctl_dev, DIS_BYPASS_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
return 0;
}
return BP_NOT_CAP;
}
/*EN_BYPASS_CAP 0x24 */
static int en_bypass_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT);
msec_delay_bp(BYPASS_DELAY_INT);
} else {
write_data(pbpctl_dev, EN_BYPASS_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
return 0;
}
return BP_NOT_CAP;
}
/* BYPASS_STATE_PWRON 0x26*/
static int bypass_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWRON);
if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
msec_delay_bp(DFLT_PWRON_DELAY);
else
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/* NORMAL_STATE_PWRON 0x28*/
static int normal_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)
|| (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) {
write_data(pbpctl_dev, NORMAL_STATE_PWRON);
if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
msec_delay_bp(DFLT_PWRON_DELAY);
else
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/* BYPASS_STATE_PWROFF 0x27*/
static int bypass_state_pwroff(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWROFF);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/* NORMAL_STATE_PWROFF 0x29*/
static int normal_state_pwroff(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) {
write_data(pbpctl_dev, NORMAL_STATE_PWROFF);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/*TAP_STATE_PWRON 0x2a*/
static int tap_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, TAP_STATE_PWRON);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/*DIS_TAP_CAP 0x2c*/
static int dis_tap_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, DIS_TAP_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/*EN_TAP_CAP 0x2e*/
static int en_tap_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, EN_TAP_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
return 0;
}
return BP_NOT_CAP;
}
/*DISC_STATE_PWRON 0x2a*/
static int disc_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
write_data(pbpctl_dev, DISC_STATE_PWRON);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
return BP_OK;
}
}
return BP_NOT_CAP;
}
/*DIS_DISC_CAP 0x2c*/
static int dis_disc_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
write_data(pbpctl_dev, DIS_DISC_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
return BP_OK;
}
}
return BP_NOT_CAP;
}
/*EN_TAP_CAP 0x2e*/
static int en_disc_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
write_data(pbpctl_dev, EN_DISC_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
return BP_OK;
}
}
return BP_NOT_CAP;
}
static int std_nic_on(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT);
msec_delay_bp(BYPASS_DELAY_INT);
pbpctl_dev->bp_status_un = 0;
return BP_OK;
}
if (pbpctl_dev->bp_ext_ver >= 0x8) {
write_data(pbpctl_dev, STD_NIC_ON);
msec_delay_bp(BYPASS_CAP_DELAY);
return BP_OK;
}
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
wdt_off(pbpctl_dev);
if (pbpctl_dev->bp_caps & BP_CAP) {
write_data(pbpctl_dev, BYPASS_OFF);
msec_delay_bp(LATCH_DELAY);
}
if (pbpctl_dev->bp_caps & TAP_CAP) {
write_data(pbpctl_dev, TAP_OFF);
msec_delay_bp(LATCH_DELAY);
}
write_data(pbpctl_dev, NORMAL_STATE_PWRON);
if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
msec_delay_bp(DFLT_PWRON_DELAY);
else
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
write_data(pbpctl_dev, DIS_BYPASS_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, DIS_TAP_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
return 0;
}
}
return BP_NOT_CAP;
}
static int std_nic_off(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT);
msec_delay_bp(BYPASS_DELAY_INT);
return BP_OK;
}
if (pbpctl_dev->bp_ext_ver >= 0x8) {
write_data(pbpctl_dev, STD_NIC_OFF);
msec_delay_bp(BYPASS_CAP_DELAY);
return BP_OK;
}
if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, TAP_STATE_PWRON);
msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY);
}
if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWRON);
if (pbpctl_dev->bp_ext_ver > PXG2BPI_VER)
msec_delay_bp(LATCH_DELAY +
EEPROM_WR_DELAY);
else
msec_delay_bp(DFLT_PWRON_DELAY);
}
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, EN_TAP_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
write_data(pbpctl_dev, EN_DISC_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
write_data(pbpctl_dev, EN_BYPASS_CAP);
msec_delay_bp(BYPASS_CAP_DELAY);
}
return 0;
}
}
return BP_NOT_CAP;
}
int wdt_time_left(struct bpctl_dev *pbpctl_dev)
{
/* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */
unsigned long curr_time = jiffies, delta_time = 0, wdt_on_time =
pbpctl_dev->bypass_wdt_on_time, delta_time_msec = 0;
int time_left = 0;
switch (pbpctl_dev->wdt_status) {
case WDT_STATUS_DIS:
time_left = 0;
break;
case WDT_STATUS_EN:
delta_time =
(curr_time >=
wdt_on_time) ? (curr_time - wdt_on_time) : (~wdt_on_time +
curr_time);
delta_time_msec = jiffies_to_msecs(delta_time);
time_left = pbpctl_dev->bypass_timer_interval - delta_time_msec;
if (time_left < 0) {
time_left = -1;
pbpctl_dev->wdt_status = WDT_STATUS_EXP;
}
break;
case WDT_STATUS_EXP:
time_left = -1;
break;
}
return time_left;
}
static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left)
{
int ret = 0;
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
{
if (pbpctl_dev->wdt_status == WDT_STATUS_UNKNOWN)
ret = BP_NOT_CAP;
else
*time_left = wdt_time_left(pbpctl_dev);
}
} else
ret = BP_NOT_CAP;
return ret;
}