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 @@ ...@@ -10,7 +10,7 @@
O_TARGET := e100.o O_TARGET := e100.o
obj-y := e100_main.o e100_config.o e100_proc.o e100_phy.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) obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -899,6 +899,15 @@ struct cfg_params { ...@@ -899,6 +899,15 @@ struct cfg_params {
int PollingMaxWork; int PollingMaxWork;
u32 b_params; 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 { struct e100_private {
u32 flags; /* board management flags */ u32 flags; /* board management flags */
...@@ -988,6 +997,9 @@ struct e100_private { ...@@ -988,6 +997,9 @@ struct e100_private {
u32 wolopts; u32 wolopts;
u16 ip_lbytes; u16 ip_lbytes;
#endif #endif
#ifdef ETHTOOL_TEST
struct ethtool_lpbk_data loopback;
#endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
u32 pci_state[16]; u32 pci_state[16];
...@@ -1028,4 +1040,23 @@ extern void e100_deisolate_driver(struct e100_private *bdp, ...@@ -1028,4 +1040,23 @@ extern void e100_deisolate_driver(struct e100_private *bdp,
extern unsigned char e100_hw_reset_recover(struct e100_private *bdp, extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
u32 reset_cmd); 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 #endif
...@@ -593,3 +593,102 @@ e100_config_wol(struct e100_private *bdp) ...@@ -593,3 +593,102 @@ e100_config_wol(struct e100_private *bdp)
} }
#endif #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. ...@@ -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 CB_CFIG_LONG_RX_OK BIT_3
#define NO_LOOPBACK 0
#define MAC_LOOPBACK 0x01
#define PHY_LOOPBACK 0x02
/* function prototypes */ /* function prototypes */
extern void e100_config_init(struct e100_private *bdp); extern void e100_config_init(struct e100_private *bdp);
extern unsigned char e100_force_config(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, ...@@ -201,5 +205,8 @@ extern void e100_config_mulcast_enbl(struct e100_private *bdp,
unsigned char enable); unsigned char enable);
extern void e100_config_ifs(struct e100_private *bdp); extern void e100_config_ifs(struct e100_private *bdp);
extern void e100_config_force_dplx(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_ */ #endif /* _E100_CONFIG_INC_ */
...@@ -146,6 +146,23 @@ static unsigned char e100_setup_filter(struct e100_private *bdp); ...@@ -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 void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
static u16 e100_get_ip_lbytes(struct net_device *dev); static u16 e100_get_ip_lbytes(struct net_device *dev);
extern void e100_config_wol(struct e100_private *bdp); 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
#endif /*E100_ETHTOOL_IOCTL */ #endif /*E100_ETHTOOL_IOCTL */
...@@ -3304,6 +3321,16 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -3304,6 +3321,16 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
case ETHTOOL_SWOL: case ETHTOOL_SWOL:
rc = e100_ethtool_wol(dev, ifr); rc = e100_ethtool_wol(dev, ifr);
break; 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 #endif
default: default:
break; break;
...@@ -3467,6 +3494,36 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr) ...@@ -3467,6 +3494,36 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
} }
#endif #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 #ifdef ETHTOOL_NWAY_RST
static int static int
e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) 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) ...@@ -3508,7 +3565,9 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
#ifdef ETHTOOL_GEEPROM #ifdef ETHTOOL_GEEPROM
info.eedump_len = (bdp->eeprom_size << 1); info.eedump_len = (bdp->eeprom_size << 1);
#endif #endif
#ifdef ETHTOOL_TEST
info.testinfo_len = E100_MAX_TEST_RES;
#endif
if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
...@@ -3740,6 +3799,51 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) ...@@ -3740,6 +3799,51 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
return res; 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
#endif /*E100_ETHTOOL_IOCTL */ #endif /*E100_ETHTOOL_IOCTL */
......
...@@ -36,7 +36,8 @@ struct ethtool_drvinfo { ...@@ -36,7 +36,8 @@ struct ethtool_drvinfo {
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
/* For PCI devices, use pci_dev->slot_name. */ /* For PCI devices, use pci_dev->slot_name. */
char reserved1[32]; char reserved1[32];
char reserved2[24]; char reserved2[20];
u32 testinfo_len;
u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
}; };
...@@ -210,6 +211,34 @@ struct ethtool_pauseparam { ...@@ -210,6 +211,34 @@ struct ethtool_pauseparam {
u32 tx_pause; 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 */ /* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
...@@ -222,13 +251,13 @@ struct ethtool_pauseparam { ...@@ -222,13 +251,13 @@ struct ethtool_pauseparam {
#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */ #define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */
#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */ #define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ #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_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_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_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_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
#define ETHTOOL_SRXCSUM 0x00000015 /* Set 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) */ #define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
...@@ -236,7 +265,9 @@ struct ethtool_pauseparam { ...@@ -236,7 +265,9 @@ struct ethtool_pauseparam {
#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable #define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
* (ethtool_value) */ * (ethtool_value) */
#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable #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 */ /* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET #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