diff mbox series

[net-next,1/5] net: txgbe: Identify PHY and SFP module

Message ID 20221108111907.48599-2-mengyuanlou@net-swift.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: WangXun ethernet drivers | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 7 maintainers not CCed: pabeni@redhat.com corbet@lwn.net davem@davemloft.net edumazet@google.com kuba@kernel.org linux-doc@vger.kernel.org yuehaibing@huawei.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Mengyuan Lou Nov. 8, 2022, 11:19 a.m. UTC
From: Jiawen Wu <jiawenwu@trustnetic.com>

Add to get media type and physical layer module, support I2C access.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 .../device_drivers/ethernet/wangxun/txgbe.rst |  37 ++
 drivers/net/ethernet/wangxun/libwx/wx_hw.c    |   6 +-
 drivers/net/ethernet/wangxun/libwx/wx_hw.h    |   2 +
 drivers/net/ethernet/wangxun/libwx/wx_type.h  |   1 +
 drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c | 421 ++++++++++++++++++
 .../net/ethernet/wangxun/txgbe/txgbe_main.c   |  29 +-
 .../net/ethernet/wangxun/txgbe/txgbe_type.h   | 124 ++++++
 7 files changed, 614 insertions(+), 6 deletions(-)

Comments

Andrew Lunn Nov. 8, 2022, 8:52 p.m. UTC | #1
> +/**
> + *  txgbe_identify_sfp_module - Identifies SFP modules
> + *  @hw: pointer to hardware structure
> + *
> + *  Searches for and identifies the SFP module and assigns appropriate PHY type.
> + **/
> +static int txgbe_identify_sfp_module(struct txgbe_hw *hw)
> +{
> +	u8 oui_bytes[3] = {0, 0, 0};
> +	u8 comp_codes_10g = 0;
> +	u8 comp_codes_1g = 0;
> +	int status = -EFAULT;
> +	u32 vendor_oui = 0;
> +	u8 identifier = 0;
> +	u8 cable_tech = 0;
> +	u8 cable_spec = 0;
> +
> +	/* LAN ID is needed for I2C access */
> +	txgbe_init_i2c(hw);
> +
> +	status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER, &identifier);
> +	if (status != 0)
> +		goto err_read_i2c_eeprom;
> +
> +	if (identifier != TXGBE_SFF_IDENTIFIER_SFP) {
> +		hw->phy.type = txgbe_phy_sfp_unsupported;
> +		status = -ENODEV;
> +	} else {
> +		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_1GBE_COMP_CODES,
> +					       &comp_codes_1g);
> +		if (status != 0)
> +			goto err_read_i2c_eeprom;
> +
> +		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_10GBE_COMP_CODES,
> +					       &comp_codes_10g);
> +		if (status != 0)
> +			goto err_read_i2c_eeprom;
> +
> +		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_CABLE_TECHNOLOGY,
> +					       &cable_tech);
> +		if (status != 0)
> +			goto err_read_i2c_eeprom;
> +
> +		 /* ID Module
> +		  * =========
> +		  * 1   SFP_DA_CORE
> +		  * 2   SFP_SR/LR_CORE
> +		  * 3   SFP_act_lmt_DA_CORE
> +		  * 4   SFP_1g_cu_CORE
> +		  * 5   SFP_1g_sx_CORE
> +		  * 6   SFP_1g_lx_CORE
> +		  */

So it looks like you have Linux driving the SFP, not firmware. In that
case, please throw all this code away. Implement a standard Linux I2C
bus master driver, and make use of driver/net/phy/sfp*.[ch].

    Andrew
Jiawen Wu Nov. 9, 2022, 6:32 a.m. UTC | #2
On Wednesday, November 9, 2022 4:53 AM, Andrew Lunn wrote:
> > +/**
> > + *  txgbe_identify_sfp_module - Identifies SFP modules
> > + *  @hw: pointer to hardware structure
> > + *
> > + *  Searches for and identifies the SFP module and assigns appropriate PHY type.
> > + **/
> > +static int txgbe_identify_sfp_module(struct txgbe_hw *hw) {
> > +	u8 oui_bytes[3] = {0, 0, 0};
> > +	u8 comp_codes_10g = 0;
> > +	u8 comp_codes_1g = 0;
> > +	int status = -EFAULT;
> > +	u32 vendor_oui = 0;
> > +	u8 identifier = 0;
> > +	u8 cable_tech = 0;
> > +	u8 cable_spec = 0;
> > +
> > +	/* LAN ID is needed for I2C access */
> > +	txgbe_init_i2c(hw);
> > +
> > +	status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER, &identifier);
> > +	if (status != 0)
> > +		goto err_read_i2c_eeprom;
> > +
> > +	if (identifier != TXGBE_SFF_IDENTIFIER_SFP) {
> > +		hw->phy.type = txgbe_phy_sfp_unsupported;
> > +		status = -ENODEV;
> > +	} else {
> > +		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_1GBE_COMP_CODES,
> > +					       &comp_codes_1g);
> > +		if (status != 0)
> > +			goto err_read_i2c_eeprom;
> > +
> > +		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_10GBE_COMP_CODES,
> > +					       &comp_codes_10g);
> > +		if (status != 0)
> > +			goto err_read_i2c_eeprom;
> > +
> > +		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_CABLE_TECHNOLOGY,
> > +					       &cable_tech);
> > +		if (status != 0)
> > +			goto err_read_i2c_eeprom;
> > +
> > +		 /* ID Module
> > +		  * =========
> > +		  * 1   SFP_DA_CORE
> > +		  * 2   SFP_SR/LR_CORE
> > +		  * 3   SFP_act_lmt_DA_CORE
> > +		  * 4   SFP_1g_cu_CORE
> > +		  * 5   SFP_1g_sx_CORE
> > +		  * 6   SFP_1g_lx_CORE
> > +		  */
> 
> So it looks like you have Linux driving the SFP, not firmware. In that case, please throw all this
code away.
> Implement a standard Linux I2C bus master driver, and make use of driver/net/phy/sfp*.[ch].
> 
>     Andrew
> 

I don't quite understand how to use driver/net/phy/sfp* files. In txgbe driver, I2C infos are read
from CAB registers, then SFP type identified.
Perhaps implement 'struct sfp_upstream_ops' ? And could you please guide me an example driver of
some docs?
Andrew Lunn Nov. 9, 2022, 1:26 p.m. UTC | #3
> > So it looks like you have Linux driving the SFP, not firmware. In that case, please throw all this
> code away.
> > Implement a standard Linux I2C bus master driver, and make use of driver/net/phy/sfp*.[ch].
> > 
> >     Andrew
> > 
> 
> I don't quite understand how to use driver/net/phy/sfp* files. In txgbe driver, I2C infos are read
> from CAB registers, then SFP type identified.
> Perhaps implement 'struct sfp_upstream_ops' ? And could you please guide me an example driver of
> some docs?

The SFP driver is currently device tree only, but it should be easy to
add support for a platform device and platform data. That driver needs
to be told about a standard Linux i2c master device, and optionally a
collection of GPIO which connect to the SFP socket.

So you need to implement a standard Linux I2C bus master. Which
basically means being able to send and receive an I2C message. Take a
look at for example drivers/net/ethernet/mellanox/mlxsw/i2c.c . This
driver however does not use it with the SFP driver, since the Mellanox
devices have firmware controlling the SFP. But it will give you the
idea how you can embed an I2C bus driver inside another driver.

For the GPIOs to the SFP socket, TX Enable, LOS, MODDEF etc, you want
a standard Linux GPIO driver. For an example, look at
drivers/net/dsa/vitesse-vsc73xx-core.c.

https://github.com/lunn/linux/blob/v5.0.7-rap/drivers/platform/x86/zii-rap.c
contains an example of registering a bit-bang MDIO
controller. zii_rap_mdio_gpiod_table would become a list of SFP
GPIOs. zii_rap_mdio_init() registers a platform devices which
instantiaces an MDIO bus. You would register a platform device which
instantiates an SFP device.

Once you have an SFP devices you need to extend phylink with a
platform data binding. So you can pass it your SFP device.

This should all be reasonably simple code.

     Andrew
Jiawen Wu Nov. 14, 2022, 9:34 a.m. UTC | #4
On Wednesday, November 9, 2022 9:27 PM, Andrew Lunn wrote:
> > > So it looks like you have Linux driving the SFP, not firmware. In
> > > that case, please throw all this
> > code away.
> > > Implement a standard Linux I2C bus master driver, and make use of driver/net/phy/sfp*.[ch].
> > >
> > >     Andrew
> > >
> >
> > I don't quite understand how to use driver/net/phy/sfp* files. In
> > txgbe driver, I2C infos are read from CAB registers, then SFP type identified.
> > Perhaps implement 'struct sfp_upstream_ops' ? And could you please
> > guide me an example driver of some docs?
> 
> The SFP driver is currently device tree only, but it should be easy to add support for a platform
device and
> platform data. That driver needs to be told about a standard Linux i2c master device, and
optionally a
> collection of GPIO which connect to the SFP socket.
> 
> So you need to implement a standard Linux I2C bus master. Which basically means being able to send
> and receive an I2C message. Take a look at for example drivers/net/ethernet/mellanox/mlxsw/i2c.c .
> This driver however does not use it with the SFP driver, since the Mellanox devices have firmware
> controlling the SFP. But it will give you the idea how you can embed an I2C bus driver inside
another
> driver.
> 
> For the GPIOs to the SFP socket, TX Enable, LOS, MODDEF etc, you want a standard Linux GPIO
driver.
> For an example, look at drivers/net/dsa/vitesse-vsc73xx-core.c.
> 
> https://github.com/lunn/linux/blob/v5.0.7-rap/drivers/platform/x86/zii-rap.c
> contains an example of registering a bit-bang MDIO controller. zii_rap_mdio_gpiod_table would
become
> a list of SFP GPIOs. zii_rap_mdio_init() registers a platform devices which instantiaces an MDIO
bus. You
> would register a platform device which instantiates an SFP device.
> 
> Once you have an SFP devices you need to extend phylink with a platform data binding. So you can
pass it
> your SFP device.
> 
> This should all be reasonably simple code.
> 
>      Andrew
> 

When ethernet driver does a reset to the hardware, like 'txgbe_reset_hw', the I2C configuration will
be reset.
It needs to be reconfigured once. So how could I call the I2C function here? Can I treat the I2C
driver as a lib?
Andrew Lunn Nov. 14, 2022, 1:25 p.m. UTC | #5
> When ethernet driver does a reset to the hardware, like
> 'txgbe_reset_hw', the I2C configuration will be reset.  It needs to
> be reconfigured once. So how could I call the I2C function here? Can
> I treat the I2C driver as a lib?

The I2C driver will be embedded within your MAC driver. So you have
control over it.

How often do you need to call txgbe_reset_hw()?  Hopefully just once
early in the probe? So you can register the I2C bus master with the
I2C core after the reset.

If you need to use txgbe_reset_hw() at other times, you will need a
mutex or similar in .master_xfer function so you don't perform a reset
while an I2C transfer is happening, or start another transfer while a
reset is happening.

	Andrew
Alexander Lobakin Nov. 14, 2022, 3:34 p.m. UTC | #6
From: Mengyuan Lou <mengyuanlou@net-swift.com>
Date: Tue,  8 Nov 2022 19:19:03 +0800

> From: Jiawen Wu <jiawenwu@trustnetic.com>
> 
> Add to get media type and physical layer module, support I2C access.
> 
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> ---

[...]

> @@ -277,11 +647,30 @@ int txgbe_reset_hw(struct txgbe_hw *hw)
>  	struct wx_hw *wxhw = &hw->wxhw;
>  	int status;
>  
> +	u32 sr_pcs_ctl, sr_pma_mmd_ctl1, sr_an_mmd_ctl, sr_an_mmd_adv_reg2;
> +	u32 vr_xs_or_pcs_mmd_digi_ctl1, curr_vr_xs_or_pcs_mmd_digi_ctl1;
> +	u32 curr_sr_an_mmd_ctl, curr_sr_an_mmd_adv_reg2;
> +	u32 curr_sr_pcs_ctl, curr_sr_pma_mmd_ctl1;

Please merge this with the first declaration block, there must be
only one.
Also, are you sure you need all this simultaneously? Maybe reuse
some of them?

> +
>  	/* Call adapter stop to disable tx/rx and clear interrupts */
>  	status = wx_stop_adapter(wxhw);
>  	if (status != 0)
>  		return status;
>  
> +	/* Identify PHY and related function pointers */

[...]

> +	if (!hw->phy.orig_link_settings_stored) {
> +		hw->phy.orig_sr_pcs_ctl2 = sr_pcs_ctl;
> +		hw->phy.orig_sr_pma_mmd_ctl1 = sr_pma_mmd_ctl1;
> +		hw->phy.orig_sr_an_mmd_ctl = sr_an_mmd_ctl;
> +		hw->phy.orig_sr_an_mmd_adv_reg2 = sr_an_mmd_adv_reg2;
> +		hw->phy.orig_vr_xs_or_pcs_mmd_digi_ctl1 =
> +						vr_xs_or_pcs_mmd_digi_ctl1;
> +		hw->phy.orig_link_settings_stored = true;
> +	} else {
> +		hw->phy.orig_sr_pcs_ctl2 = curr_sr_pcs_ctl;
> +		hw->phy.orig_sr_pma_mmd_ctl1 = curr_sr_pma_mmd_ctl1;
> +		hw->phy.orig_sr_an_mmd_ctl = curr_sr_an_mmd_ctl;
> +		hw->phy.orig_sr_an_mmd_adv_reg2 =
> +					curr_sr_an_mmd_adv_reg2;
> +		hw->phy.orig_vr_xs_or_pcs_mmd_digi_ctl1 =
> +					curr_vr_xs_or_pcs_mmd_digi_ctl1;
> +	}
> +
> +	/*make sure phy power is up*/
> +	msleep(100);

Can we poll something to check if it is up already? 100 ms is a ton,
I would try to avoid such huge sleeps if possible.

> +
>  	/* Store the permanent mac address */
>  	wx_get_mac_addr(wxhw, wxhw->mac.perm_addr);

[...]

> -- 
> 2.38.1

Thanks,
Olek
Andrew Lunn Nov. 14, 2022, 8:18 p.m. UTC | #7
On Mon, Nov 14, 2022 at 04:34:38PM +0100, Alexander Lobakin wrote:
> From: Mengyuan Lou <mengyuanlou@net-swift.com>
> Date: Tue,  8 Nov 2022 19:19:03 +0800
> 
> > From: Jiawen Wu <jiawenwu@trustnetic.com>
> > 
> > Add to get media type and physical layer module, support I2C access.
> > 
> > Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
> > ---
> 
> [...]
> 
> > @@ -277,11 +647,30 @@ int txgbe_reset_hw(struct txgbe_hw *hw)
> >  	struct wx_hw *wxhw = &hw->wxhw;
> >  	int status;
> >  
> > +	u32 sr_pcs_ctl, sr_pma_mmd_ctl1, sr_an_mmd_ctl, sr_an_mmd_adv_reg2;
> > +	u32 vr_xs_or_pcs_mmd_digi_ctl1, curr_vr_xs_or_pcs_mmd_digi_ctl1;
> > +	u32 curr_sr_an_mmd_ctl, curr_sr_an_mmd_adv_reg2;
> > +	u32 curr_sr_pcs_ctl, curr_sr_pma_mmd_ctl1;
> 
> Please merge this with the first declaration block, there must be
> only one.
> Also, are you sure you need all this simultaneously? Maybe reuse
> some of them?

I would not actually spend too much time reviewing this code. It needs
restructuring into a pcs driver, maybe in driver/net/pcs. And some of
it might get turning into generic PHY driver.

Very likely, this whole driver will get re-written as it is merged.

	Andrew
Jiawen Wu Nov. 29, 2022, 8:20 a.m. UTC | #8
> The SFP driver is currently device tree only, but it should be easy to add support for a platform
device and
> platform data. That driver needs to be told about a standard Linux i2c master device, and
optionally a
> collection of GPIO which connect to the SFP socket.
> 
> So you need to implement a standard Linux I2C bus master. Which basically means being able to send
> and receive an I2C message. Take a look at for example drivers/net/ethernet/mellanox/mlxsw/i2c.c .
> This driver however does not use it with the SFP driver, since the Mellanox devices have firmware
> controlling the SFP. But it will give you the idea how you can embed an I2C bus driver inside
another
> driver.
> 
> For the GPIOs to the SFP socket, TX Enable, LOS, MODDEF etc, you want a standard Linux GPIO
driver.
> For an example, look at drivers/net/dsa/vitesse-vsc73xx-core.c.
> 
> https://github.com/lunn/linux/blob/v5.0.7-rap/drivers/platform/x86/zii-rap.c
> contains an example of registering a bit-bang MDIO controller. zii_rap_mdio_gpiod_table would
become
> a list of SFP GPIOs. zii_rap_mdio_init() registers a platform devices which instantiaces an MDIO
bus. You
> would register a platform device which instantiates an SFP device.
> 
> Once you have an SFP devices you need to extend phylink with a platform data binding. So you can
pass it
> your SFP device.
> 
> This should all be reasonably simple code.
> 
>      Andrew
> 

Hi Andrew,

I have encountered some difficulties.
When I register a platform device for SFP, then it matches the SFP driver by name. I found that SFP
driver needs to find I2C adapter by device node.
Which device node it needs? There was no device node when I created the I2C device. So it always
probe failed.
Could you please give me some guidance? Thanks.
diff mbox series

Patch

diff --git a/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst b/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
index eaa87dbe8848..3cb9549fb7b0 100644
--- a/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
+++ b/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
@@ -14,6 +14,43 @@  Contents
 - Support
 
 
+Identifying Your Adapter
+========================
+The driver is compatible with WangXun Sapphire Dual ports Ethernet Adapters.
+
+SFP+ Devices with Pluggable Optics
+----------------------------------
+The following is a list of 3rd party SFP+ modules that have been tested and verified.
+
++----------+----------------------+----------------------+
+| Supplier | Type                 | Part Numbers         |
++==========+======================+======================+
+| Avago    | SFP+                 | AFBR-709SMZ          |
++----------+----------------------+----------------------+
+| F-tone   | SFP+                 | FTCS-851X-02D        |
++----------+----------------------+----------------------+
+| Finisar  | SFP+                 | FTLX8574D3BCL        |
++----------+----------------------+----------------------+
+| Hasense  | SFP+                 | AFBR-709SMZ          |
++----------+----------------------+----------------------+
+| HGTECH   | SFP+                 | MTRS-01X11-G         |
++----------+----------------------+----------------------+
+| HP       | SFP+                 | SR SFP+ 456096-001   |
++----------+----------------------+----------------------+
+| Huawei   | SFP+                 | AFBR-709SMZ          |
++----------+----------------------+----------------------+
+| Intel    | SFP+                 | FTLX8571D3BCV-IT     |
++----------+----------------------+----------------------+
+| JDSU     | SFP+                 | PLRXPL-SC-S43        |
++----------+----------------------+----------------------+
+| SONT     | SFP+                 | XP-8G10-01           |
++----------+----------------------+----------------------+
+| Trixon   | SFP+                 | TPS-TGM3-85DCR       |
++----------+----------------------+----------------------+
+| WTD      | SFP+                 | RTXM228-551          |
++----------+----------------------+----------------------+
+
+
 Support
 =======
 If you got any problem, contact Wangxun support team via support@trustnetic.com
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 1eb7388f1dd5..045d6e978598 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -114,12 +114,13 @@  static DEFINE_MUTEX(wx_sw_sync_lock);
  *  Releases the SW semaphore for the specified
  *  function (CSR, PHY0, PHY1, EEPROM, Flash)
  **/
-static void wx_release_sw_sync(struct wx_hw *wxhw, u32 mask)
+void wx_release_sw_sync(struct wx_hw *wxhw, u32 mask)
 {
 	mutex_lock(&wx_sw_sync_lock);
 	wr32m(wxhw, WX_MNG_SWFW_SYNC, mask, 0);
 	mutex_unlock(&wx_sw_sync_lock);
 }
+EXPORT_SYMBOL(wx_release_sw_sync);
 
 /**
  *  wx_acquire_sw_sync - Acquire SW semaphore
@@ -129,7 +130,7 @@  static void wx_release_sw_sync(struct wx_hw *wxhw, u32 mask)
  *  Acquires the SW semaphore for the specified
  *  function (CSR, PHY0, PHY1, EEPROM, Flash)
  **/
-static int wx_acquire_sw_sync(struct wx_hw *wxhw, u32 mask)
+int wx_acquire_sw_sync(struct wx_hw *wxhw, u32 mask)
 {
 	u32 sem = 0;
 	int ret = 0;
@@ -147,6 +148,7 @@  static int wx_acquire_sw_sync(struct wx_hw *wxhw, u32 mask)
 
 	return ret;
 }
+EXPORT_SYMBOL(wx_acquire_sw_sync);
 
 /**
  *  wx_host_interface_command - Issue command to manageability block
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
index a0652f5e9939..5058774381c1 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -7,6 +7,8 @@ 
 int wx_check_flash_load(struct wx_hw *hw, u32 check_bit);
 void wx_control_hw(struct wx_hw *wxhw, bool drv);
 int wx_mng_present(struct wx_hw *wxhw);
+void wx_release_sw_sync(struct wx_hw *wxhw, u32 mask);
+int wx_acquire_sw_sync(struct wx_hw *wxhw, u32 mask);
 int wx_host_interface_command(struct wx_hw *wxhw, u32 *buffer,
 			      u32 length, u32 timeout, bool return_data);
 int wx_read_ee_hostif(struct wx_hw *wxhw, u16 offset, u16 *data);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 1cbeef8230bf..c95cda53bf67 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -123,6 +123,7 @@ 
 
 /************************************** MNG ********************************/
 #define WX_MNG_SWFW_SYNC             0x1E008
+#define WX_MNG_SWFW_SYNC_SW_PHY      BIT(0)
 #define WX_MNG_SWFW_SYNC_SW_MB       BIT(2)
 #define WX_MNG_SWFW_SYNC_SW_FLASH    BIT(3)
 #define WX_MNG_MBOX                  0x1E100
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
index 0b1032195859..77a44e48fc9e 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
@@ -14,6 +14,375 @@ 
 #include "txgbe_hw.h"
 #include "txgbe.h"
 
+static u32 txgbe_rd32_epcs(struct txgbe_hw *hw, u32 addr)
+{
+	struct wx_hw *wxhw = &hw->wxhw;
+	u32 offset;
+
+	/* Set the LAN port indicator to offset[1] */
+	/* 1st, write the offset to IDA_ADDR register */
+	offset = TXGBE_XPCS_IDA_ADDR;
+	wr32(wxhw, offset, addr);
+
+	/* 2nd, read the data from IDA_DATA register */
+	offset = TXGBE_XPCS_IDA_DATA;
+	return rd32(wxhw, offset);
+}
+
+static void txgbe_init_i2c(struct txgbe_hw *hw)
+{
+	struct wx_hw *wxhw = &hw->wxhw;
+
+	wr32(wxhw, TXGBE_I2C_ENABLE, 0);
+
+	wr32(wxhw, TXGBE_I2C_CON,
+	     (TXGBE_I2C_CON_MASTER_MODE |
+	      TXGBE_I2C_CON_SPEED(1) |
+	      TXGBE_I2C_CON_RESTART_EN |
+	      TXGBE_I2C_CON_SLAVE_DISABLE));
+	/* Default addr is 0xA0 ,bit 0 is configure for read/write! */
+	wr32(wxhw, TXGBE_I2C_TAR, TXGBE_I2C_SLAVE_ADDR);
+	wr32(wxhw, TXGBE_I2C_SS_SCL_HCNT, 600);
+	wr32(wxhw, TXGBE_I2C_SS_SCL_LCNT, 600);
+	wr32(wxhw, TXGBE_I2C_RX_TL, 0); /* 1byte for rx full signal */
+	wr32(wxhw, TXGBE_I2C_TX_TL, 4);
+	wr32(wxhw, TXGBE_I2C_SCL_STUCK_TIMEOUT, 0xFFFFFF);
+	wr32(wxhw, TXGBE_I2C_SDA_STUCK_TIMEOUT, 0xFFFFFF);
+
+	wr32(wxhw, TXGBE_I2C_INTR_MASK, 0);
+	wr32(wxhw, TXGBE_I2C_ENABLE, 1);
+}
+
+/**
+ *  txgbe_read_i2c_byte_int - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+static int txgbe_read_i2c_byte_int(struct txgbe_hw *hw, u8 byte_offset, u8 *data)
+{
+	u32 sync = WX_MNG_SWFW_SYNC_SW_PHY;
+	struct wx_hw *wxhw = &hw->wxhw;
+	int status = 0;
+	u32 val;
+
+	status = wx_acquire_sw_sync(wxhw, sync);
+	if (status != 0)
+		return status;
+
+	/* wait tx empty */
+	status = read_poll_timeout(rd32, val,
+				   (val & TXGBE_I2C_INTR_STAT_TEMP) == TXGBE_I2C_INTR_STAT_TEMP,
+				   100, 1000, false, wxhw, TXGBE_I2C_RAW_INTR_STAT);
+	if (status != 0)
+		goto out;
+
+	/* read data */
+	wr32(wxhw, TXGBE_I2C_DATA_CMD, byte_offset | TXGBE_I2C_DATA_CMD_STOP);
+	wr32(wxhw, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_READ);
+
+	/* wait for read complete */
+	status = read_poll_timeout(rd32, val,
+				   (val & TXGBE_I2C_INTR_STAT_RFUL) == TXGBE_I2C_INTR_STAT_RFUL,
+				   100, 1000, false, wxhw, TXGBE_I2C_RAW_INTR_STAT);
+	if (status != 0)
+		goto out;
+
+	*data = 0xFF & rd32(wxhw, TXGBE_I2C_DATA_CMD);
+
+out:
+	wx_release_sw_sync(wxhw, sync);
+	return status;
+}
+
+/**
+ *  txgbe_switch_i2c_slave_addr - Switch I2C slave address
+ *  @hw: pointer to hardware structure
+ *  @dev_addr: slave addr to switch
+ **/
+static void txgbe_switch_i2c_slave_addr(struct txgbe_hw *hw, u8 dev_addr)
+{
+	struct wx_hw *wxhw = &hw->wxhw;
+
+	wr32(wxhw, TXGBE_I2C_ENABLE, 0);
+	wr32(wxhw, TXGBE_I2C_TAR, dev_addr >> 1);
+	wr32(wxhw, TXGBE_I2C_ENABLE, 1);
+}
+
+/**
+ *  txgbe_read_i2c_byte - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @dev_addr: device address
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+static int txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
+			       u8 dev_addr, u8 *data)
+{
+	txgbe_switch_i2c_slave_addr(hw, dev_addr);
+
+	return txgbe_read_i2c_byte_int(hw, byte_offset, data);
+}
+
+/**
+ *  txgbe_read_i2c_eeprom - Reads 8 bit EEPROM word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to read
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+static int txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
+				 u8 *eeprom_data)
+{
+	return txgbe_read_i2c_byte(hw, byte_offset,
+				   TXGBE_I2C_EEPROM_DEV_ADDR,
+				   eeprom_data);
+}
+
+/**
+ *  txgbe_identify_sfp_module - Identifies SFP modules
+ *  @hw: pointer to hardware structure
+ *
+ *  Searches for and identifies the SFP module and assigns appropriate PHY type.
+ **/
+static int txgbe_identify_sfp_module(struct txgbe_hw *hw)
+{
+	u8 oui_bytes[3] = {0, 0, 0};
+	u8 comp_codes_10g = 0;
+	u8 comp_codes_1g = 0;
+	int status = -EFAULT;
+	u32 vendor_oui = 0;
+	u8 identifier = 0;
+	u8 cable_tech = 0;
+	u8 cable_spec = 0;
+
+	/* LAN ID is needed for I2C access */
+	txgbe_init_i2c(hw);
+
+	status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER, &identifier);
+	if (status != 0)
+		goto err_read_i2c_eeprom;
+
+	if (identifier != TXGBE_SFF_IDENTIFIER_SFP) {
+		hw->phy.type = txgbe_phy_sfp_unsupported;
+		status = -ENODEV;
+	} else {
+		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_1GBE_COMP_CODES,
+					       &comp_codes_1g);
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_10GBE_COMP_CODES,
+					       &comp_codes_10g);
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		status = txgbe_read_i2c_eeprom(hw, TXGBE_SFF_CABLE_TECHNOLOGY,
+					       &cable_tech);
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		 /* ID Module
+		  * =========
+		  * 1   SFP_DA_CORE
+		  * 2   SFP_SR/LR_CORE
+		  * 3   SFP_act_lmt_DA_CORE
+		  * 4   SFP_1g_cu_CORE
+		  * 5   SFP_1g_sx_CORE
+		  * 6   SFP_1g_lx_CORE
+		  */
+		if (cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) {
+			hw->phy.sfp_type = txgbe_sfp_type_da_cu_core;
+		} else if (cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE) {
+			txgbe_read_i2c_eeprom(hw, TXGBE_SFF_CABLE_SPEC_COMP,
+					      &cable_spec);
+			if (cable_spec & TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING)
+				hw->phy.sfp_type = txgbe_sfp_type_da_act_lmt_core;
+			else
+				hw->phy.sfp_type = txgbe_sfp_type_unknown;
+		} else if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE |
+					     TXGBE_SFF_10GBASELR_CAPABLE)) {
+			hw->phy.sfp_type = txgbe_sfp_type_srlr_core;
+		} else if (comp_codes_1g & TXGBE_SFF_1GBASET_CAPABLE) {
+			hw->phy.sfp_type = txgbe_sfp_type_1g_cu_core;
+		} else if (comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) {
+			hw->phy.sfp_type = txgbe_sfp_type_1g_sx_core;
+		} else if (comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) {
+			hw->phy.sfp_type = txgbe_sfp_type_1g_lx_core;
+		} else {
+			hw->phy.sfp_type = txgbe_sfp_type_unknown;
+		}
+
+		/* Determine if the SFP+ PHY is dual speed or not. */
+		hw->phy.multispeed_fiber = false;
+		if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) &&
+		     (comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) ||
+		    ((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) &&
+		     (comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE)))
+			hw->phy.multispeed_fiber = true;
+
+		/* Determine PHY vendor */
+		status = txgbe_read_i2c_eeprom(hw,
+					       TXGBE_SFF_VENDOR_OUI_BYTE0,
+					       &oui_bytes[0]);
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		status = txgbe_read_i2c_eeprom(hw,
+					       TXGBE_SFF_VENDOR_OUI_BYTE1,
+					       &oui_bytes[1]);
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		status = txgbe_read_i2c_eeprom(hw,
+					       TXGBE_SFF_VENDOR_OUI_BYTE2,
+					       &oui_bytes[2]);
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		vendor_oui =
+			((oui_bytes[0] << TXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
+			 (oui_bytes[1] << TXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
+			 (oui_bytes[2] << TXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
+
+		switch (vendor_oui) {
+		case TXGBE_SFF_VENDOR_OUI_TYCO:
+			if (cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE)
+				hw->phy.type = txgbe_phy_sfp_passive_tyco;
+			break;
+		case TXGBE_SFF_VENDOR_OUI_FTL:
+			if (cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE)
+				hw->phy.type = txgbe_phy_sfp_ftl_active;
+			else
+				hw->phy.type = txgbe_phy_sfp_ftl;
+			break;
+		case TXGBE_SFF_VENDOR_OUI_AVAGO:
+			hw->phy.type = txgbe_phy_sfp_avago;
+			break;
+		case TXGBE_SFF_VENDOR_OUI_INTEL:
+			hw->phy.type = txgbe_phy_sfp_intel;
+			break;
+		default:
+			if (cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE)
+				hw->phy.type = txgbe_phy_sfp_passive_unknown;
+			else if (cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE)
+				hw->phy.type = txgbe_phy_sfp_active_unknown;
+			else
+				hw->phy.type = txgbe_phy_sfp_unknown;
+			break;
+		}
+
+		/* Allow any DA cable vendor */
+		if (cable_tech & (TXGBE_SFF_DA_PASSIVE_CABLE |
+				  TXGBE_SFF_DA_ACTIVE_CABLE))
+			return 0;
+
+		/* Verify supported 1G SFP modules */
+		if (comp_codes_10g == 0 &&
+		    !(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core)) {
+			hw->phy.type = txgbe_phy_sfp_unsupported;
+			return -ENODEV;
+		}
+	}
+
+	return status;
+
+err_read_i2c_eeprom:
+	hw->phy.sfp_type = txgbe_sfp_type_not_present;
+	hw->phy.type = txgbe_phy_unknown;
+
+	return -ENODEV;
+}
+
+/**
+ *  txgbe_get_media_type - Get media type
+ *  @hw: pointer to hardware structure
+ *
+ *  Returns the media type (fiber, copper, backplane)
+ **/
+static enum txgbe_media_type txgbe_get_media_type(struct txgbe_hw *hw)
+{
+	enum txgbe_media_type media_type;
+	struct wx_hw *wxhw = &hw->wxhw;
+	u8 device_type;
+
+	device_type = wxhw->subsystem_device_id & 0xF0;
+	switch (device_type) {
+	case TXGBE_ID_MAC_XAUI:
+	case TXGBE_ID_MAC_SGMII:
+	case TXGBE_ID_KR_KX_KX4:
+		/* Default device ID is mezzanine card KX/KX4 */
+		media_type = txgbe_media_type_backplane;
+		break;
+	case TXGBE_ID_SFP:
+		media_type = txgbe_media_type_fiber;
+		break;
+	case TXGBE_ID_XAUI:
+	case TXGBE_ID_SGMII:
+		media_type = txgbe_media_type_copper;
+		break;
+	case TXGBE_ID_SFI_XAUI:
+		if (wxhw->bus.func == 0)
+			media_type = txgbe_media_type_fiber;
+		else
+			media_type = txgbe_media_type_copper;
+		break;
+	default:
+		media_type = txgbe_media_type_unknown;
+		break;
+	}
+
+	return media_type;
+}
+
+/**
+ *  txgbe_identify_phy - Get physical layer module
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines the physical layer module found on the current adapter.
+ *  If PHY already detected, maintains current PHY type in hw struct,
+ *  otherwise executes the PHY detection routine.
+ **/
+static int txgbe_identify_phy(struct txgbe_hw *hw)
+{
+	int status;
+
+	/* Detect PHY if not unknown - returns success if already detected. */
+	hw->phy.media_type = txgbe_get_media_type(hw);
+	if (hw->phy.media_type == txgbe_media_type_fiber) {
+		status = txgbe_identify_sfp_module(hw);
+	} else {
+		hw->phy.type = txgbe_phy_none;
+		status = 0;
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_init_phy - PHY/SFP specific init
+ *  @hw: pointer to hardware structure
+ **/
+static int txgbe_init_phy(struct txgbe_hw *hw)
+{
+	int ret_val = 0;
+
+	txgbe_init_i2c(hw);
+	/* Identify the PHY or SFP module */
+	ret_val = txgbe_identify_phy(hw);
+
+	return ret_val;
+}
+
 /**
  *  txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
  *  @hw: pointer to hardware structure
@@ -260,6 +629,7 @@  static void txgbe_reset_misc(struct txgbe_hw *hw)
 {
 	struct wx_hw *wxhw = &hw->wxhw;
 
+	txgbe_init_i2c(hw);
 	wx_reset_misc(wxhw);
 	txgbe_init_thermal_sensor_thresh(hw);
 }
@@ -277,11 +647,30 @@  int txgbe_reset_hw(struct txgbe_hw *hw)
 	struct wx_hw *wxhw = &hw->wxhw;
 	int status;
 
+	u32 sr_pcs_ctl, sr_pma_mmd_ctl1, sr_an_mmd_ctl, sr_an_mmd_adv_reg2;
+	u32 vr_xs_or_pcs_mmd_digi_ctl1, curr_vr_xs_or_pcs_mmd_digi_ctl1;
+	u32 curr_sr_an_mmd_ctl, curr_sr_an_mmd_adv_reg2;
+	u32 curr_sr_pcs_ctl, curr_sr_pma_mmd_ctl1;
+
 	/* Call adapter stop to disable tx/rx and clear interrupts */
 	status = wx_stop_adapter(wxhw);
 	if (status != 0)
 		return status;
 
+	/* Identify PHY and related function pointers */
+	status = txgbe_init_phy(hw);
+	if (status != 0 && hw->phy.type == txgbe_phy_sfp_unsupported)
+		return status;
+
+	/* Remember internal phy regs from before we reset */
+	curr_sr_pcs_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_PCS_CTL2);
+	curr_sr_pma_mmd_ctl1 = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+	curr_sr_an_mmd_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_CTL);
+	curr_sr_an_mmd_adv_reg2 = txgbe_rd32_epcs(hw,
+						  TXGBE_SR_AN_MMD_ADV_REG2);
+	curr_vr_xs_or_pcs_mmd_digi_ctl1 =
+		txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1);
+
 	if (!(((wxhw->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
 	      ((wxhw->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP)))
 		wx_reset_hostif(wxhw);
@@ -294,6 +683,38 @@  int txgbe_reset_hw(struct txgbe_hw *hw)
 
 	txgbe_reset_misc(hw);
 
+	/* Store the original values if they have not been stored
+	 * off yet.  Otherwise restore the stored original values
+	 * since the reset operation sets back to defaults.
+	 */
+	sr_pcs_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_PCS_CTL2);
+	sr_pma_mmd_ctl1 = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+	sr_an_mmd_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_CTL);
+	sr_an_mmd_adv_reg2 = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG2);
+	vr_xs_or_pcs_mmd_digi_ctl1 =
+		txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1);
+
+	if (!hw->phy.orig_link_settings_stored) {
+		hw->phy.orig_sr_pcs_ctl2 = sr_pcs_ctl;
+		hw->phy.orig_sr_pma_mmd_ctl1 = sr_pma_mmd_ctl1;
+		hw->phy.orig_sr_an_mmd_ctl = sr_an_mmd_ctl;
+		hw->phy.orig_sr_an_mmd_adv_reg2 = sr_an_mmd_adv_reg2;
+		hw->phy.orig_vr_xs_or_pcs_mmd_digi_ctl1 =
+						vr_xs_or_pcs_mmd_digi_ctl1;
+		hw->phy.orig_link_settings_stored = true;
+	} else {
+		hw->phy.orig_sr_pcs_ctl2 = curr_sr_pcs_ctl;
+		hw->phy.orig_sr_pma_mmd_ctl1 = curr_sr_pma_mmd_ctl1;
+		hw->phy.orig_sr_an_mmd_ctl = curr_sr_an_mmd_ctl;
+		hw->phy.orig_sr_an_mmd_adv_reg2 =
+					curr_sr_an_mmd_adv_reg2;
+		hw->phy.orig_vr_xs_or_pcs_mmd_digi_ctl1 =
+					curr_vr_xs_or_pcs_mmd_digi_ctl1;
+	}
+
+	/*make sure phy power is up*/
+	msleep(100);
+
 	/* Store the permanent mac address */
 	wx_get_mac_addr(wxhw, wxhw->mac.perm_addr);
 
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 36780e7f05b7..1c00ecbc1c6a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -174,7 +174,9 @@  static void txgbe_reset(struct txgbe_adapter *adapter)
 	int err;
 
 	err = txgbe_reset_hw(hw);
-	if (err != 0)
+	if (err != 0 &&
+	    hw->phy.type != txgbe_phy_sfp_unsupported &&
+	    hw->phy.sfp_type != txgbe_sfp_type_not_present)
 		dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err);
 
 	/* do not flush user set addresses */
@@ -487,9 +489,19 @@  static int txgbe_probe(struct pci_dev *pdev,
 	}
 
 	err = txgbe_reset_hw(hw);
-	if (err) {
-		dev_err(&pdev->dev, "HW Init failed: %d\n", err);
-		goto err_free_mac_table;
+	if (err != 0) {
+		if (hw->phy.sfp_type == txgbe_sfp_type_not_present) {
+			err = 0;
+		} else if (hw->phy.type == txgbe_phy_sfp_unsupported) {
+			dev_err(&pdev->dev,
+				"An unsupported SFP+ module type was detected.\n");
+			dev_err(&pdev->dev,
+				"Reload the driver after installing a supported module.\n");
+			goto err_free_mac_table;
+		} else {
+			dev_err(&pdev->dev, "HW Init failed: %d\n", err);
+			goto err_free_mac_table;
+		}
 	}
 
 	netdev->features |= NETIF_F_HIGHDMA;
@@ -568,6 +580,15 @@  static int txgbe_probe(struct pci_dev *pdev,
 	err = txgbe_read_pba_string(hw, part_str, TXGBE_PBANUM_LENGTH);
 	if (err)
 		strncpy(part_str, "Unknown", TXGBE_PBANUM_LENGTH);
+	if (hw->phy.media_type == txgbe_media_type_fiber &&
+	    hw->phy.sfp_type != txgbe_sfp_type_not_present)
+		netif_info(adapter, probe, netdev,
+			   "PHY: %d, SFP+: %d, PBA No: %s\n",
+			   hw->phy.type, hw->phy.sfp_type, part_str);
+	else
+		netif_info(adapter, probe, netdev,
+			   "PHY: %d, PBA No: %s\n",
+			   hw->phy.type, part_str);
 
 	netif_info(adapter, probe, netdev, "%pM\n", netdev->dev_addr);
 
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 740a1c447e20..2f8be0118157 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -53,6 +53,72 @@ 
 #define TXGBE_TS_CTL                            0x10300
 #define TXGBE_TS_CTL_EVAL_MD                    BIT(31)
 
+/*********************** ETH PHY ***********************/
+#define TXGBE_XPCS_IDA_ADDR                     0x13000
+#define TXGBE_XPCS_IDA_DATA                     0x13004
+/* ETH PHY Registers */
+#define TXGBE_SR_PCS_CTL2                       0x30007
+#define TXGBE_SR_PMA_MMD_CTL1                   0x10000
+#define TXGBE_SR_AN_MMD_CTL                     0x70000
+#define TXGBE_SR_AN_MMD_ADV_REG2                0x70011
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1        0x38000
+/* I2C registers */
+#define TXGBE_I2C_CON                           0x14900 /* I2C Control */
+#define TXGBE_I2C_CON_SLAVE_DISABLE             BIT(6)
+#define TXGBE_I2C_CON_RESTART_EN                BIT(5)
+#define TXGBE_I2C_CON_SPEED(_v)                 (((_v) & 0x3) << 1)
+#define TXGBE_I2C_CON_MASTER_MODE               BIT(0)
+#define TXGBE_I2C_TAR                           0x14904 /* I2C Target Address */
+#define TXGBE_I2C_DATA_CMD                      0x14910 /* I2C Rx/Tx Data Buf and Cmd */
+#define TXGBE_I2C_DATA_CMD_STOP                 BIT(9)
+#define TXGBE_I2C_DATA_CMD_READ                 (BIT(8) | TXGBE_I2C_DATA_CMD_STOP)
+#define TXGBE_I2C_SS_SCL_HCNT                   0x14914
+#define TXGBE_I2C_SS_SCL_LCNT                   0x14918
+#define TXGBE_I2C_INTR_MASK                     0x14930 /* I2C Interrupt Mask */
+#define TXGBE_I2C_RAW_INTR_STAT                 0x14934 /* I2C Raw Interrupt Status */
+#define TXGBE_I2C_INTR_STAT_RFUL                BIT(2)
+#define TXGBE_I2C_INTR_STAT_TEMP                BIT(4)
+#define TXGBE_I2C_RX_TL                         0x14938 /* I2C Receive FIFO Threshold */
+#define TXGBE_I2C_TX_TL                         0x1493C /* I2C TX FIFO Threshold */
+#define TXGBE_I2C_ENABLE                        0x1496C /* I2C Enable */
+#define TXGBE_I2C_SCL_STUCK_TIMEOUT             0x149AC
+#define TXGBE_I2C_SDA_STUCK_TIMEOUT             0x149B0
+
+#define TXGBE_I2C_SLAVE_ADDR                    (0xA0 >> 1)
+#define TXGBE_I2C_EEPROM_DEV_ADDR               0xA0
+
+/* EEPROM byte offsets */
+#define TXGBE_SFF_IDENTIFIER                    0x0
+#define TXGBE_SFF_IDENTIFIER_SFP                0x3
+#define TXGBE_SFF_VENDOR_OUI_BYTE0              0x25
+#define TXGBE_SFF_VENDOR_OUI_BYTE1              0x26
+#define TXGBE_SFF_VENDOR_OUI_BYTE2              0x27
+#define TXGBE_SFF_1GBE_COMP_CODES               0x6
+#define TXGBE_SFF_10GBE_COMP_CODES              0x3
+#define TXGBE_SFF_CABLE_TECHNOLOGY              0x8
+#define TXGBE_SFF_CABLE_SPEC_COMP               0x3C
+
+/* Bitmasks */
+#define TXGBE_SFF_DA_PASSIVE_CABLE              BIT(2)
+#define TXGBE_SFF_DA_ACTIVE_CABLE               BIT(3)
+#define TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING       BIT(2)
+#define TXGBE_SFF_1GBASESX_CAPABLE              BIT(0)
+#define TXGBE_SFF_1GBASELX_CAPABLE              BIT(1)
+#define TXGBE_SFF_1GBASET_CAPABLE               BIT(3)
+#define TXGBE_SFF_10GBASESR_CAPABLE             BIT(4)
+#define TXGBE_SFF_10GBASELR_CAPABLE             BIT(5)
+
+/* Bit-shift macros */
+#define TXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT        24
+#define TXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT        16
+#define TXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT        8
+
+/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */
+#define TXGBE_SFF_VENDOR_OUI_TYCO               0x00407600
+#define TXGBE_SFF_VENDOR_OUI_FTL                0x00906500
+#define TXGBE_SFF_VENDOR_OUI_AVAGO              0x00176A00
+#define TXGBE_SFF_VENDOR_OUI_INTEL              0x001B2100
+
 /* Part Number String Length */
 #define TXGBE_PBANUM_LENGTH                     32
 
@@ -67,8 +133,66 @@ 
 #define TXGBE_PBANUM1_PTR                       0x06
 #define TXGBE_PBANUM_PTR_GUARD                  0xFAFA
 
+/* SFP+ module type IDs:
+ *
+ * ID   Module Type
+ * =============
+ * 0    SFP_DA_CU
+ * 1    SFP_SR
+ * 2    SFP_LR
+ * 3    SFP_DA_CU_CORE0
+ * 4    SFP_DA_CU_CORE1
+ * 5    SFP_SR/LR_CORE0
+ * 6    SFP_SR/LR_CORE1
+ */
+enum txgbe_sfp_type {
+	txgbe_sfp_type_da_cu_core = 1,
+	txgbe_sfp_type_srlr_core = 2,
+	txgbe_sfp_type_da_act_lmt_core = 3,
+	txgbe_sfp_type_1g_cu_core = 4,
+	txgbe_sfp_type_1g_sx_core = 5,
+	txgbe_sfp_type_1g_lx_core = 6,
+	txgbe_sfp_type_not_present = 0xFFFE,
+	txgbe_sfp_type_unknown = 0xFFFF
+};
+
+enum txgbe_phy_type {
+	txgbe_phy_unknown = 0,
+	txgbe_phy_none,
+	txgbe_phy_sfp_passive_tyco,
+	txgbe_phy_sfp_passive_unknown,
+	txgbe_phy_sfp_active_unknown,
+	txgbe_phy_sfp_avago,
+	txgbe_phy_sfp_ftl,
+	txgbe_phy_sfp_ftl_active,
+	txgbe_phy_sfp_unknown,
+	txgbe_phy_sfp_intel,
+	txgbe_phy_sfp_unsupported
+};
+
+enum txgbe_media_type {
+	txgbe_media_type_unknown = 0,
+	txgbe_media_type_fiber,
+	txgbe_media_type_copper,
+	txgbe_media_type_backplane
+};
+
+struct txgbe_phy_info {
+	enum txgbe_sfp_type sfp_type;
+	enum txgbe_phy_type type;
+	enum txgbe_media_type media_type;
+	u32 orig_sr_pcs_ctl2;
+	u32 orig_sr_pma_mmd_ctl1;
+	u32 orig_sr_an_mmd_ctl;
+	u32 orig_sr_an_mmd_adv_reg2;
+	u32 orig_vr_xs_or_pcs_mmd_digi_ctl1;
+	bool orig_link_settings_stored;
+	bool multispeed_fiber;
+};
+
 struct txgbe_hw {
 	struct wx_hw wxhw;
+	struct txgbe_phy_info phy;
 };
 
 #endif /* _TXGBE_TYPE_H_ */