]> git.neil.brown.name Git - history.git/commitdiff
Merge ethtool initiate-nic-self-test ioctl, and support for it in e100 net drvr.
authorJeff Garzik <jgarzik@mandrakesoft.com>
Wed, 20 Mar 2002 02:15:13 +0000 (21:15 -0500)
committerJeff Garzik <jgarzik@mandrakesoft.com>
Wed, 20 Mar 2002 02:15:13 +0000 (21:15 -0500)
Contributed by Eli Kupermann @ Intel, modified by me.

drivers/net/e100/Makefile
drivers/net/e100/e100.h
drivers/net/e100/e100_config.c
drivers/net/e100/e100_config.h
drivers/net/e100/e100_main.c
include/linux/ethtool.h

index 587a0f1ff5ed2215bf4fe75d71b52563b608b31d..066956eac1a205a153f157906f66a586570a6514 100644 (file)
@@ -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
index 4295e9c85712fde681c9080bd4b55474a9cb4223..cd380d8f027c0d19ffa7d3428cdd7038b794a25e 100644 (file)
@@ -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
index 2606aff405ccf620d708e9c4d1e3c703bc4cb8a3..c965393db4e27aff5bc9e38b3f71b86ab46b5b90 100644 (file)
@@ -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
+
index a46e531e564f108cc2632a5d9678d34ef53a15cc..6172ce27ef4b5495ff982ac5b05fbb21af3a3615 100644 (file)
@@ -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_ */
index 1c78f63b9863fca9713529abbfc5fd199a2c9cc0..7b8c32f351f933e76a11da33071949d226f1b806 100644 (file)
@@ -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 */
 
index 192959f7477d158a8ce740ab1487557e12e44b52..6f8ebf32d744539e1ae37bfebd34ffe71323b83c 100644 (file)
@@ -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