ethtool, net/mlx4_en: Cable info, get_module_info/eeprom ethtool support
authorSaeed Mahameed <saeedm@mellanox.com>
Mon, 27 Oct 2014 09:37:36 +0000 (11:37 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 28 Oct 2014 21:18:00 +0000 (17:18 -0400)
Added support for get_module_info/get_module_eeprom ethtool support for cable info reading.

Added new cable types enum in include/uapi/linux/ethtool.h for ethtool use.
+#define ETH_MODULE_SFF_8636            0x3
+#define ETH_MODULE_SFF_8636_LEN        256
+#define ETH_MODULE_SFF_8436            0x4
+#define ETH_MODULE_SFF_8436_LEN        256

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
include/uapi/linux/ethtool.h

index ae83da9cd18a3f870ab51bc3ff9cb207b6f0432e..279f4233de593fdc1fee930d2c684e9141f55e1f 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/mlx4/driver.h>
+#include <linux/mlx4/device.h>
 #include <linux/in.h>
 #include <net/ip.h>
 
@@ -1309,6 +1310,86 @@ static int mlx4_en_set_tunable(struct net_device *dev,
        return ret;
 }
 
+static int mlx4_en_get_module_info(struct net_device *dev,
+                                  struct ethtool_modinfo *modinfo)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = priv->mdev;
+       int ret;
+       u8 data[4];
+
+       /* Read first 2 bytes to get Module & REV ID */
+       ret = mlx4_get_module_info(mdev->dev, priv->port,
+                                  0/*offset*/, 2/*size*/, data);
+       if (ret < 2)
+               return -EIO;
+
+       switch (data[0] /* identifier */) {
+       case MLX4_MODULE_ID_QSFP:
+               modinfo->type = ETH_MODULE_SFF_8436;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+               break;
+       case MLX4_MODULE_ID_QSFP_PLUS:
+               if (data[1] >= 0x3) { /* revision id */
+                       modinfo->type = ETH_MODULE_SFF_8636;
+                       modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+               } else {
+                       modinfo->type = ETH_MODULE_SFF_8436;
+                       modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+               }
+               break;
+       case MLX4_MODULE_ID_QSFP28:
+               modinfo->type = ETH_MODULE_SFF_8636;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+               break;
+       case MLX4_MODULE_ID_SFP:
+               modinfo->type = ETH_MODULE_SFF_8472;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+
+static int mlx4_en_get_module_eeprom(struct net_device *dev,
+                                    struct ethtool_eeprom *ee,
+                                    u8 *data)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = priv->mdev;
+       int offset = ee->offset;
+       int i = 0, ret;
+
+       if (ee->len == 0)
+               return -EINVAL;
+
+       memset(data, 0, ee->len);
+
+       while (i < ee->len) {
+               en_dbg(DRV, priv,
+                      "mlx4_get_module_info i(%d) offset(%d) len(%d)\n",
+                      i, offset, ee->len - i);
+
+               ret = mlx4_get_module_info(mdev->dev, priv->port,
+                                          offset, ee->len - i, data + i);
+
+               if (!ret) /* Done reading */
+                       return 0;
+
+               if (ret < 0) {
+                       en_err(priv,
+                              "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n",
+                              i, offset, ee->len - i, ret);
+                       return 0;
+               }
+
+               i += ret;
+               offset += ret;
+       }
+       return 0;
+}
 
 const struct ethtool_ops mlx4_en_ethtool_ops = {
        .get_drvinfo = mlx4_en_get_drvinfo,
@@ -1341,6 +1422,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
        .get_priv_flags = mlx4_en_get_priv_flags,
        .get_tunable            = mlx4_en_get_tunable,
        .set_tunable            = mlx4_en_set_tunable,
+       .get_module_info = mlx4_en_get_module_info,
+       .get_module_eeprom = mlx4_en_get_module_eeprom
 };
 
 
index 99b43056a6feb3db4617143df6d7753bbf124ed2..b6acd78b821c34be931e8560a6d8e6fbd417903e 100644 (file)
@@ -1343,6 +1343,10 @@ enum ethtool_sfeatures_retval_bits {
 #define ETH_MODULE_SFF_8079_LEN                256
 #define ETH_MODULE_SFF_8472            0x2
 #define ETH_MODULE_SFF_8472_LEN                512
+#define ETH_MODULE_SFF_8636            0x3
+#define ETH_MODULE_SFF_8636_LEN                256
+#define ETH_MODULE_SFF_8436            0x4
+#define ETH_MODULE_SFF_8436_LEN                256
 
 /* Reset flags */
 /* The reset() operation must clear the flags for the components which