Contributed by Eli Kupermann @ Intel, modified by me.
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
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 */
u32 wolopts;
u16 ip_lbytes;
#endif
+#ifdef ETHTOOL_TEST
+struct ethtool_lpbk_data loopback;
+#endif
#ifdef CONFIG_PM
u32 pci_state[16];
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
}
#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
+
#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);
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_ */
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 */
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;
}
#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)
#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;
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 */
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) */
};
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. */
#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) */
#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