qede: Add driver callbacks for eeprom module query.
authorSudarsana Reddy Kalluru <sudarsana.kalluru@cavium.com>
Wed, 18 Jul 2018 13:27:23 +0000 (06:27 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 20 Jul 2018 06:35:37 +0000 (23:35 -0700)
This patch implements the ethtool callbacks for querying sfp/eeprom module.

Signed-off-by: Sudarsana Reddy Kalluru <Sudarsana.Kalluru@cavium.com>
Signed-off-by: Ariel Elior <ariel.elior@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qede/qede_ethtool.c

index f4a0f8ff826108436a3ddb973c7e424c1cd71e4e..b37857f3f950895ff2060317f3920b158ba0119c 100644 (file)
@@ -1780,6 +1780,92 @@ static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata)
        return 0;
 }
 
+static int qede_get_module_info(struct net_device *dev,
+                               struct ethtool_modinfo *modinfo)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       u8 buf[4];
+       int rc;
+
+       /* Read first 4 bytes to find the sfp type */
+       rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
+                                                  QED_I2C_DEV_ADDR_A0, 0, 4);
+       if (rc) {
+               DP_ERR(edev, "Failed reading EEPROM data %d\n", rc);
+               return rc;
+       }
+
+       switch (buf[0]) {
+       case 0x3: /* SFP, SFP+, SFP-28 */
+               modinfo->type = ETH_MODULE_SFF_8472;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+               break;
+       case 0xc: /* QSFP */
+       case 0xd: /* QSFP+ */
+               modinfo->type = ETH_MODULE_SFF_8436;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+               break;
+       case 0x11: /* QSFP-28 */
+               modinfo->type = ETH_MODULE_SFF_8636;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+               break;
+       default:
+               DP_ERR(edev, "Unknown transceiver type 0x%x\n", buf[0]);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int qede_get_module_eeprom(struct net_device *dev,
+                                 struct ethtool_eeprom *ee, u8 *data)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       u32 start_addr = ee->offset, size = 0;
+       u8 *buf = data;
+       int rc = 0;
+
+       /* Read A0 section */
+       if (ee->offset < ETH_MODULE_SFF_8079_LEN) {
+               /* Limit transfer size to the A0 section boundary */
+               if (ee->offset + ee->len > ETH_MODULE_SFF_8079_LEN)
+                       size = ETH_MODULE_SFF_8079_LEN - ee->offset;
+               else
+                       size = ee->len;
+
+               rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
+                                                          QED_I2C_DEV_ADDR_A0,
+                                                          start_addr, size);
+               if (rc) {
+                       DP_ERR(edev, "Failed reading A0 section  %d\n", rc);
+                       return rc;
+               }
+
+               buf += size;
+               start_addr += size;
+       }
+
+       /* Read A2 section */
+       if (start_addr >= ETH_MODULE_SFF_8079_LEN &&
+           start_addr < ETH_MODULE_SFF_8472_LEN) {
+               size = ee->len - size;
+               /* Limit transfer size to the A2 section boundary */
+               if (start_addr + size > ETH_MODULE_SFF_8472_LEN)
+                       size = ETH_MODULE_SFF_8472_LEN - start_addr;
+               start_addr -= ETH_MODULE_SFF_8079_LEN;
+               rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
+                                                          QED_I2C_DEV_ADDR_A2,
+                                                          start_addr, size);
+               if (rc) {
+                       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                                  "Failed reading A2 section %d\n", rc);
+                       return 0;
+               }
+       }
+
+       return rc;
+}
+
 static const struct ethtool_ops qede_ethtool_ops = {
        .get_link_ksettings = qede_get_link_ksettings,
        .set_link_ksettings = qede_set_link_ksettings,
@@ -1813,6 +1899,8 @@ static const struct ethtool_ops qede_ethtool_ops = {
        .get_channels = qede_get_channels,
        .set_channels = qede_set_channels,
        .self_test = qede_self_test,
+       .get_module_info = qede_get_module_info,
+       .get_module_eeprom = qede_get_module_eeprom,
        .get_eee = qede_get_eee,
        .set_eee = qede_set_eee,