Commit 855063a8 authored by Jeff Garzik's avatar Jeff Garzik

Merge ethtool initiate-nic-self-test ioctl, and support for it in e100 net drvr.

Contributed by Eli Kupermann @ Intel, modified by me.
parent ce40bb04
......@@ -10,7 +10,7 @@
O_TARGET := e100.o
obj-y := e100_main.o e100_config.o e100_proc.o e100_phy.o \
e100_eeprom.o
e100_eeprom.o e100_test.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
......@@ -899,6 +899,15 @@ struct cfg_params {
int PollingMaxWork;
u32 b_params;
};
#ifdef ETHTOOL_TEST
struct ethtool_lpbk_data{
dma_addr_t dma_handle;
tcb_t *tcb;
rfd_t *rfd;
};
#endif
struct e100_private {
u32 flags; /* board management flags */
......@@ -988,6 +997,9 @@ struct e100_private {
u32 wolopts;
u16 ip_lbytes;
#endif
#ifdef ETHTOOL_TEST
struct ethtool_lpbk_data loopback;
#endif
#ifdef CONFIG_PM
u32 pci_state[16];
......@@ -1028,4 +1040,23 @@ extern void e100_deisolate_driver(struct e100_private *bdp,
extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
u32 reset_cmd);
#ifdef ETHTOOL_TEST
#define ROM_TEST_FAIL 0x01
#define REGISTER_TEST_FAIL 0x02
#define SELF_TEST_FAIL 0x04
#define TEST_TIMEOUT 0x08
enum test_offsets {
E100_EEPROM_TEST_FAIL = 0,
E100_CHIP_TIMEOUT,
E100_ROM_TEST_FAIL,
E100_REG_TEST_FAIL,
E100_MAC_TEST_FAIL,
E100_LPBK_MAC_FAIL,
E100_LPBK_PHY_FAIL,
E100_MAX_TEST_RES
};
#endif
#endif
......@@ -593,3 +593,102 @@ e100_config_wol(struct e100_private *bdp)
}
#endif
#ifdef ETHTOOL_TEST
/**
* e100_config_loopback_mode
* @bdp: atapter's private data struct
* @mode: loopback mode(phy/mac/none)
*
*/
unsigned char
e100_config_loopback_mode(struct e100_private *bdp, u8 mode)
{
unsigned char bc_changed = false;
u8 config_byte;
spin_lock_bh(&(bdp->config_lock));
switch (mode) {
case NO_LOOPBACK:
config_byte = CB_CFIG_LOOPBACK_NORMAL;
break;
case MAC_LOOPBACK:
config_byte = CB_CFIG_LOOPBACK_INTERNAL;
break;
case PHY_LOOPBACK:
config_byte = CB_CFIG_LOOPBACK_EXTERNAL;
break;
default:
printk(KERN_NOTICE "e100_config_loopback_mode: "
"Invalid argument 'mode': %d\n", mode);
goto exit;
}
if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) {
bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE);
bdp->config[10] |= config_byte;
E100_CONFIG(bdp, 10);
bc_changed = true;
}
exit:
spin_unlock_bh(&(bdp->config_lock));
return bc_changed;
}
unsigned char
e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable)
{
unsigned char bc_changed = false;
spin_lock_bh(&(bdp->config_lock));
if (enable) {
if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) {
bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS);
E100_CONFIG(bdp, 6);
bc_changed = true;
}
} else {
if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) {
bdp->config[6] |= CB_CFIG_EXT_TCB_DIS;
E100_CONFIG(bdp, 6);
bc_changed = true;
}
}
spin_unlock_bh(&(bdp->config_lock));
return bc_changed;
}
unsigned char
e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable)
{
unsigned char bc_changed = false;
spin_lock_bh(&(bdp->config_lock));
if (enable) {
if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) {
bdp->config[7] |= CB_CFIG_DYNTBD_EN;
E100_CONFIG(bdp, 7);
bc_changed = true;
}
} else {
if (bdp->config[7] & CB_CFIG_DYNTBD_EN) {
bdp->config[7] &= (~CB_CFIG_DYNTBD_EN);
E100_CONFIG(bdp, 7);
bc_changed = true;
}
}
spin_unlock_bh(&(bdp->config_lock));
return bc_changed;
}
#endif
......@@ -190,6 +190,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CB_CFIG_LONG_RX_OK BIT_3
#define NO_LOOPBACK 0
#define MAC_LOOPBACK 0x01
#define PHY_LOOPBACK 0x02
/* function prototypes */
extern void e100_config_init(struct e100_private *bdp);
extern unsigned char e100_force_config(struct e100_private *bdp);
......@@ -201,5 +205,8 @@ extern void e100_config_mulcast_enbl(struct e100_private *bdp,
unsigned char enable);
extern void e100_config_ifs(struct e100_private *bdp);
extern void e100_config_force_dplx(struct e100_private *bdp);
extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
#endif /* _E100_CONFIG_INC_ */
......@@ -146,6 +146,23 @@ static unsigned char e100_setup_filter(struct e100_private *bdp);
static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
static u16 e100_get_ip_lbytes(struct net_device *dev);
extern void e100_config_wol(struct e100_private *bdp);
#endif
#ifdef ETHTOOL_TEST
extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
static int e100_ethtool_test(struct net_device *, struct ifreq *);
#endif
#ifdef ETHTOOL_GSTRINGS
static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
static char *test_strings[] = {
"E100_EEPROM_TEST_FAIL",
"E100_CHIP_TIMEOUT",
"E100_ROM_TEST_FAIL",
"E100_REG_TEST_FAIL",
"E100_MAC_TEST_FAIL",
"E100_LPBK_MAC_FAIL",
"E100_LPBK_PHY_FAIL"
};
#endif
#endif /*E100_ETHTOOL_IOCTL */
......@@ -3304,6 +3321,16 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
case ETHTOOL_SWOL:
rc = e100_ethtool_wol(dev, ifr);
break;
#endif
#ifdef ETHTOOL_TEST
case ETHTOOL_TEST:
rc = e100_ethtool_test(dev, ifr);
break;
#endif
#ifdef ETHTOOL_GSTRINGS
case ETHTOOL_GSTRINGS:
rc = e100_ethtool_gstrings(dev,ifr);
break;
#endif
default:
break;
......@@ -3467,6 +3494,36 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
}
#endif
#ifdef ETHTOOL_TEST
static int
e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
{
struct ethtool_test *info;
int rc = -EFAULT;
info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
GFP_ATOMIC);
if (!info)
return -EFAULT;
memset((void *) info, 0, sizeof(*info) +
E100_MAX_TEST_RES * sizeof(u64));
if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
goto exit;
info->flags = e100_run_diag(dev, info->data, info->flags);
if (!copy_to_user(ifr->ifr_data, info,
sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
rc = 0;
exit:
kfree(info);
return rc;
}
#endif
#ifdef ETHTOOL_NWAY_RST
static int
e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
......@@ -3508,7 +3565,9 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
#ifdef ETHTOOL_GEEPROM
info.eedump_len = (bdp->eeprom_size << 1);
#endif
#ifdef ETHTOOL_TEST
info.testinfo_len = E100_MAX_TEST_RES;
#endif
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
......@@ -3740,6 +3799,51 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
return res;
}
#endif
#ifdef ETHTOOL_GSTRINGS
static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
{
struct ethtool_gstrings info;
char *strings = NULL;
char *usr_strings;
int i;
memset((void *) &info, 0, sizeof(info));
usr_strings = (u8 *) (ifr->ifr_data +
offsetof(struct ethtool_gstrings, data));
if (copy_from_user(&info, ifr->ifr_data, sizeof (info)))
return -EFAULT;
switch (info.string_set) {
case ETH_SS_TEST:
if (info.len > E100_MAX_TEST_RES)
info.len = E100_MAX_TEST_RES;
strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
if (!strings)
return -EFAULT;
memset(strings, 0, info.len * ETH_GSTRING_LEN);
for (i = 0; i < info.len; i++) {
sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
test_strings[i]);
}
break;
default:
return -EOPNOTSUPP;
}
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
return -EFAULT;
kfree(strings);
return 0;
}
#endif
#endif /*E100_ETHTOOL_IOCTL */
......
......@@ -36,7 +36,8 @@ struct ethtool_drvinfo {
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
/* For PCI devices, use pci_dev->slot_name. */
char reserved1[32];
char reserved2[24];
char reserved2[20];
u32 testinfo_len;
u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
};
......@@ -210,6 +211,34 @@ struct ethtool_pauseparam {
u32 tx_pause;
};
#define ETH_GSTRING_LEN 32
enum ethtool_stringset {
ETH_SS_TEST = 0,
ETH_SS_STATS,
};
/* for passing string sets for data tagging */
struct ethtool_gstrings {
u32 cmd; /* ETHTOOL_GSTRINGS */
u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/
u32 len; /* number of strings in the string set */
u8 data[0];
};
enum ethtool_test_flags {
ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */
ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */
};
/* for requesting NIC test and getting results*/
struct ethtool_test {
u32 cmd; /* ETHTOOL_TEST */
u32 flags; /* ETH_TEST_FL_xxx */
u32 reserved;
u32 len; /* result length, in number of u64 elements */
u64 data[0];
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
......@@ -222,13 +251,13 @@ struct ethtool_pauseparam {
#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */
#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */
#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data, priv. */
#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */
#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config */
#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config, priv. */
#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */
#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters */
#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */
#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */
#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters */
#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters, priv. */
#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
......@@ -236,7 +265,9 @@ struct ethtool_pauseparam {
#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
* (ethtool_value) */
#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable
* (ethtool_value) */
* (ethtool_value), priv. */
#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */
#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment