Message ID | 1366327822-10741-6-git-send-email-jeffrey.t.kirsher@intel.com |
---|---|
State | Changes Requested, archived |
Delegated to: | David Miller |
Headers | show |
On Thu, 2013-04-18 at 16:30 -0700, Jeff Kirsher wrote: > From: "Akeem G. Abodunrin" <akeem.g.abodunrin@intel.com> > > 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 <bhuntchings@solarflare.com> Looks like Akeem made a typo in your email Ben. > 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 | 8 +++ > drivers/net/ethernet/intel/igb/igb_ethtool.c | 81 ++++++++++++++++++++++++++++ > 2 files changed, 89 insertions(+) > > diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h > index 2515140..7cb0398 100644 > --- a/drivers/net/ethernet/intel/igb/igb.h > +++ b/drivers/net/ethernet/intel/igb/igb.h > @@ -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 { > diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c > index 8499c48..6afd727 100644 > --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c > +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c > @@ -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, > };
On Thu, 2013-04-18 at 16:37 -0700, Jeff Kirsher wrote: > On Thu, 2013-04-18 at 16:30 -0700, Jeff Kirsher wrote: > > From: "Akeem G. Abodunrin" <akeem.g.abodunrin@intel.com> > > > > 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 <bhuntchings@solarflare.com> > > Looks like Akeem made a typo in your email Ben. I have fixed up your email in the patch that resides in my net-next tree. > > > 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>
From: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Date: Thu, 18 Apr 2013 16:41:55 -0700 > On Thu, 2013-04-18 at 16:37 -0700, Jeff Kirsher wrote: >> On Thu, 2013-04-18 at 16:30 -0700, Jeff Kirsher wrote: >> > From: "Akeem G. Abodunrin" <akeem.g.abodunrin@intel.com> >> > >> > 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 <bhuntchings@solarflare.com> >> >> Looks like Akeem made a typo in your email Ben. > > I have fixed up your email in the patch that resides in my net-next > tree. Thanks for fixing this up. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 2515140..7cb0398 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -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 { diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 8499c48..6afd727 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -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, };