]> Pileus Git - ~andy/linux/commitdiff
igb: Support to read and export SFF-8472/8079 data
authorAkeem G. Abodunrin <akeem.g.abodunrin@intel.com>
Thu, 11 Apr 2013 06:36:35 +0000 (06:36 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 18 Apr 2013 23:39:33 +0000 (16:39 -0700)
This patch adds support to read and export SFF-8472/8079 (SFP data)
over i2c, through Ethtool.

v2: Changed implementation to accommodate any offset within SFF module
    length boundary.

Reported-by: Aurélien Guillaume <footplus@gmail.com>
CC: Aurélien Guillaume <footplus@gmail.com>
CC: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Akeem G Abodunrin <akeem.g.abodunrin@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_ethtool.c

index 25151401c2abe54dcec7fe1fe6f48791e0660a64..7cb039827a0c2599e5902fc6a40e585938645bd0 100644 (file)
@@ -178,6 +178,14 @@ enum igb_tx_flags {
 #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGB_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
 
+/* EEPROM byte offsets */
+#define IGB_SFF_8472_SWAP              0x5C
+#define IGB_SFF_8472_COMP              0x5E
+
+/* Bitmasks */
+#define IGB_SFF_ADDRESSING_MODE                0x4
+#define IGB_SFF_8472_UNSUP             0x00
+
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct igb_tx_buffer {
index 8499c48090c697df60a78cc0a53df62c6787093f..6afd7278ad6778f53b519d12eefda97c0786c559 100644 (file)
@@ -2622,6 +2622,85 @@ static int igb_set_eee(struct net_device *netdev,
        return 0;
 }
 
+static int igb_get_module_info(struct net_device *netdev,
+                              struct ethtool_modinfo *modinfo)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 status = E1000_SUCCESS;
+       u16 sff8472_rev, addr_mode;
+       bool page_swap = false;
+
+       if ((hw->phy.media_type == e1000_media_type_copper) ||
+           (hw->phy.media_type == e1000_media_type_unknown))
+               return -EOPNOTSUPP;
+
+       /* Check whether we support SFF-8472 or not */
+       status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_COMP, &sff8472_rev);
+       if (status != E1000_SUCCESS)
+               return -EIO;
+
+       /* addressing mode is not supported */
+       status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_SWAP, &addr_mode);
+       if (status != E1000_SUCCESS)
+               return -EIO;
+
+       /* addressing mode is not supported */
+       if ((addr_mode & 0xFF) & IGB_SFF_ADDRESSING_MODE) {
+               hw_dbg("Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
+               page_swap = true;
+       }
+
+       if ((sff8472_rev & 0xFF) == IGB_SFF_8472_UNSUP || page_swap) {
+               /* We have an SFP, but it does not support SFF-8472 */
+               modinfo->type = ETH_MODULE_SFF_8079;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+       } else {
+               /* We have an SFP which supports a revision of SFF-8472 */
+               modinfo->type = ETH_MODULE_SFF_8472;
+               modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+       }
+
+       return 0;
+}
+
+static int igb_get_module_eeprom(struct net_device *netdev,
+                                struct ethtool_eeprom *ee, u8 *data)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 status = E1000_SUCCESS;
+       u16 *dataword;
+       u16 first_word, last_word;
+       int i = 0;
+
+       if (ee->len == 0)
+               return -EINVAL;
+
+       first_word = ee->offset >> 1;
+       last_word = (ee->offset + ee->len - 1) >> 1;
+
+       dataword = kmalloc(sizeof(u16) * (last_word - first_word + 1),
+                          GFP_KERNEL);
+       if (!dataword)
+               return -ENOMEM;
+
+       /* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
+       for (i = 0; i < last_word - first_word + 1; i++) {
+               status = igb_read_phy_reg_i2c(hw, first_word + i, &dataword[i]);
+               if (status != E1000_SUCCESS)
+                       /* Error occurred while reading module */
+                       return -EIO;
+
+               be16_to_cpus(&dataword[i]);
+       }
+
+       memcpy(data, (u8 *)dataword + (ee->offset & 1), ee->len);
+       kfree(dataword);
+
+       return 0;
+}
+
 static int igb_ethtool_begin(struct net_device *netdev)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
@@ -2666,6 +2745,8 @@ static const struct ethtool_ops igb_ethtool_ops = {
        .set_rxnfc              = igb_set_rxnfc,
        .get_eee                = igb_get_eee,
        .set_eee                = igb_set_eee,
+       .get_module_info        = igb_get_module_info,
+       .get_module_eeprom      = igb_get_module_eeprom,
        .begin                  = igb_ethtool_begin,
        .complete               = igb_ethtool_complete,
 };