diff options
author | Matthew Vick <matthew.vick@intel.com> | 2013-02-20 22:32:52 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2013-04-18 19:40:28 -0400 |
commit | 87371b9de5becc32af2f9be84008b8a8a424c58a (patch) | |
tree | 58128b8de909c4fab1d389e70ed81464a4e20822 | |
parent | b980ac18c95f3251038da7a3826370aff05a7434 (diff) |
igb: Enable EEE LP advertisement
On EEE-capable devices, query the PHY to determine what the link partner is
advertising.
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.c | 35 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_defines.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_i210.c | 65 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_i210.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_regs.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 30 |
7 files changed, 142 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 9d83058f2075..8ff938d94912 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c | |||
@@ -2285,6 +2285,41 @@ out: | |||
2285 | } | 2285 | } |
2286 | 2286 | ||
2287 | /** | 2287 | /** |
2288 | * __igb_access_emi_reg - Read/write EMI register | ||
2289 | * @hw: pointer to the HW structure | ||
2290 | * @addr: EMI address to program | ||
2291 | * @data: pointer to value to read/write from/to the EMI address | ||
2292 | * @read: boolean flag to indicate read or write | ||
2293 | **/ | ||
2294 | static s32 __igb_access_emi_reg(struct e1000_hw *hw, u16 address, | ||
2295 | u16 *data, bool read) | ||
2296 | { | ||
2297 | s32 ret_val = E1000_SUCCESS; | ||
2298 | |||
2299 | ret_val = hw->phy.ops.write_reg(hw, E1000_EMIADD, address); | ||
2300 | if (ret_val) | ||
2301 | return ret_val; | ||
2302 | |||
2303 | if (read) | ||
2304 | ret_val = hw->phy.ops.read_reg(hw, E1000_EMIDATA, data); | ||
2305 | else | ||
2306 | ret_val = hw->phy.ops.write_reg(hw, E1000_EMIDATA, *data); | ||
2307 | |||
2308 | return ret_val; | ||
2309 | } | ||
2310 | |||
2311 | /** | ||
2312 | * igb_read_emi_reg - Read Extended Management Interface register | ||
2313 | * @hw: pointer to the HW structure | ||
2314 | * @addr: EMI address to program | ||
2315 | * @data: value to be read from the EMI address | ||
2316 | **/ | ||
2317 | s32 igb_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data) | ||
2318 | { | ||
2319 | return __igb_access_emi_reg(hw, addr, data, true); | ||
2320 | } | ||
2321 | |||
2322 | /** | ||
2288 | * igb_set_eee_i350 - Enable/disable EEE support | 2323 | * igb_set_eee_i350 - Enable/disable EEE support |
2289 | * @hw: pointer to the HW structure | 2324 | * @hw: pointer to the HW structure |
2290 | * | 2325 | * |
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index 73ab41f0e032..0d318ac14818 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h | |||
@@ -263,6 +263,7 @@ void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *, bool, int); | |||
263 | void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool); | 263 | void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool); |
264 | void igb_vmdq_set_replication_pf(struct e1000_hw *, bool); | 264 | void igb_vmdq_set_replication_pf(struct e1000_hw *, bool); |
265 | u16 igb_rxpbs_adjust_82580(u32 data); | 265 | u16 igb_rxpbs_adjust_82580(u32 data); |
266 | s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data); | ||
266 | s32 igb_set_eee_i350(struct e1000_hw *); | 267 | s32 igb_set_eee_i350(struct e1000_hw *); |
267 | s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *); | 268 | s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *); |
268 | s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw); | 269 | s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw); |
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 66a1df974284..f3d87d7b9fdc 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h | |||
@@ -885,6 +885,10 @@ | |||
885 | #define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */ | 885 | #define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */ |
886 | #define E1000_EEE_SU_LPI_CLK_STP 0X00800000 /* EEE LPI Clock Stop */ | 886 | #define E1000_EEE_SU_LPI_CLK_STP 0X00800000 /* EEE LPI Clock Stop */ |
887 | #define E1000_EEER_EEE_NEG 0x20000000 /* EEE capability nego */ | 887 | #define E1000_EEER_EEE_NEG 0x20000000 /* EEE capability nego */ |
888 | #define E1000_EEE_LP_ADV_ADDR_I350 0x040F /* EEE LP Advertisement */ | ||
889 | #define E1000_EEE_LP_ADV_DEV_I210 7 /* EEE LP Adv Device */ | ||
890 | #define E1000_EEE_LP_ADV_ADDR_I210 61 /* EEE LP Adv Register */ | ||
891 | #define E1000_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */ | ||
888 | 892 | ||
889 | /* SerDes Control */ | 893 | /* SerDes Control */ |
890 | #define E1000_GEN_CTL_READY 0x80000000 | 894 | #define E1000_GEN_CTL_READY 0x80000000 |
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c index 7df442a3cdfd..9764cd3610e5 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.c +++ b/drivers/net/ethernet/intel/igb/e1000_i210.c | |||
@@ -708,3 +708,68 @@ s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data) | |||
708 | out: | 708 | out: |
709 | return ret_val; | 709 | return ret_val; |
710 | } | 710 | } |
711 | |||
712 | /** | ||
713 | * __igb_access_xmdio_reg - Read/write XMDIO register | ||
714 | * @hw: pointer to the HW structure | ||
715 | * @address: XMDIO address to program | ||
716 | * @dev_addr: device address to program | ||
717 | * @data: pointer to value to read/write from/to the XMDIO address | ||
718 | * @read: boolean flag to indicate read or write | ||
719 | **/ | ||
720 | static s32 __igb_access_xmdio_reg(struct e1000_hw *hw, u16 address, | ||
721 | u8 dev_addr, u16 *data, bool read) | ||
722 | { | ||
723 | s32 ret_val = E1000_SUCCESS; | ||
724 | |||
725 | ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, dev_addr); | ||
726 | if (ret_val) | ||
727 | return ret_val; | ||
728 | |||
729 | ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, address); | ||
730 | if (ret_val) | ||
731 | return ret_val; | ||
732 | |||
733 | ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, E1000_MMDAC_FUNC_DATA | | ||
734 | dev_addr); | ||
735 | if (ret_val) | ||
736 | return ret_val; | ||
737 | |||
738 | if (read) | ||
739 | ret_val = hw->phy.ops.read_reg(hw, E1000_MMDAAD, data); | ||
740 | else | ||
741 | ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, *data); | ||
742 | if (ret_val) | ||
743 | return ret_val; | ||
744 | |||
745 | /* Recalibrate the device back to 0 */ | ||
746 | ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0); | ||
747 | if (ret_val) | ||
748 | return ret_val; | ||
749 | |||
750 | return ret_val; | ||
751 | } | ||
752 | |||
753 | /** | ||
754 | * igb_read_xmdio_reg - Read XMDIO register | ||
755 | * @hw: pointer to the HW structure | ||
756 | * @addr: XMDIO address to program | ||
757 | * @dev_addr: device address to program | ||
758 | * @data: value to be read from the EMI address | ||
759 | **/ | ||
760 | s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data) | ||
761 | { | ||
762 | return __igb_access_xmdio_reg(hw, addr, dev_addr, data, true); | ||
763 | } | ||
764 | |||
765 | /** | ||
766 | * igb_write_xmdio_reg - Write XMDIO register | ||
767 | * @hw: pointer to the HW structure | ||
768 | * @addr: XMDIO address to program | ||
769 | * @dev_addr: device address to program | ||
770 | * @data: value to be written to the XMDIO address | ||
771 | **/ | ||
772 | s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data) | ||
773 | { | ||
774 | return __igb_access_xmdio_reg(hw, addr, dev_addr, &data, false); | ||
775 | } | ||
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h index e4e1a73b7c75..bfc08e05c907 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.h +++ b/drivers/net/ethernet/intel/igb/e1000_i210.h | |||
@@ -45,6 +45,10 @@ extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, | |||
45 | u16 *data); | 45 | u16 *data); |
46 | extern s32 igb_read_invm_version(struct e1000_hw *hw, | 46 | extern s32 igb_read_invm_version(struct e1000_hw *hw, |
47 | struct e1000_fw_version *invm_ver); | 47 | struct e1000_fw_version *invm_ver); |
48 | extern s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, | ||
49 | u16 *data); | ||
50 | extern s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, | ||
51 | u16 data); | ||
48 | 52 | ||
49 | #define E1000_STM_OPCODE 0xDB00 | 53 | #define E1000_STM_OPCODE 0xDB00 |
50 | #define E1000_EEPROM_FLASH_SIZE_WORD 0x11 | 54 | #define E1000_EEPROM_FLASH_SIZE_WORD 0x11 |
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index 971b6389358f..bdfc0403c6fc 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h | |||
@@ -365,6 +365,10 @@ | |||
365 | #define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */ | 365 | #define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */ |
366 | #define E1000_EEER 0x0E30 /* Energy Efficient Ethernet */ | 366 | #define E1000_EEER 0x0E30 /* Energy Efficient Ethernet */ |
367 | #define E1000_EEE_SU 0X0E34 /* EEE Setup */ | 367 | #define E1000_EEE_SU 0X0E34 /* EEE Setup */ |
368 | #define E1000_EMIADD 0x10 /* Extended Memory Indirect Address */ | ||
369 | #define E1000_EMIDATA 0x11 /* Extended Memory Indirect Data */ | ||
370 | #define E1000_MMDAC 13 /* MMD Access Control */ | ||
371 | #define E1000_MMDAAD 14 /* MMD Access Address/Data */ | ||
368 | 372 | ||
369 | /* Thermal Sensor Register */ | 373 | /* Thermal Sensor Register */ |
370 | #define E1000_THSTAT 0x08110 /* Thermal Sensor Status */ | 374 | #define E1000_THSTAT 0x08110 /* Thermal Sensor Status */ |
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 08195bd0a23a..8412f9746c78 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/pm_runtime.h> | 39 | #include <linux/pm_runtime.h> |
40 | #include <linux/highmem.h> | 40 | #include <linux/highmem.h> |
41 | #include <linux/mdio.h> | ||
41 | 42 | ||
42 | #include "igb.h" | 43 | #include "igb.h" |
43 | 44 | ||
@@ -2533,7 +2534,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) | |||
2533 | { | 2534 | { |
2534 | struct igb_adapter *adapter = netdev_priv(netdev); | 2535 | struct igb_adapter *adapter = netdev_priv(netdev); |
2535 | struct e1000_hw *hw = &adapter->hw; | 2536 | struct e1000_hw *hw = &adapter->hw; |
2536 | u32 ipcnfg, eeer; | 2537 | u32 ipcnfg, eeer, ret_val; |
2538 | u16 phy_data; | ||
2537 | 2539 | ||
2538 | if ((hw->mac.type < e1000_i350) || | 2540 | if ((hw->mac.type < e1000_i350) || |
2539 | (hw->phy.media_type != e1000_media_type_copper)) | 2541 | (hw->phy.media_type != e1000_media_type_copper)) |
@@ -2552,6 +2554,32 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) | |||
2552 | if (ipcnfg & E1000_IPCNFG_EEE_100M_AN) | 2554 | if (ipcnfg & E1000_IPCNFG_EEE_100M_AN) |
2553 | edata->advertised |= ADVERTISED_100baseT_Full; | 2555 | edata->advertised |= ADVERTISED_100baseT_Full; |
2554 | 2556 | ||
2557 | /* EEE Link Partner Advertised */ | ||
2558 | switch (hw->mac.type) { | ||
2559 | case e1000_i350: | ||
2560 | ret_val = igb_read_emi_reg(hw, E1000_EEE_LP_ADV_ADDR_I350, | ||
2561 | &phy_data); | ||
2562 | if (ret_val) | ||
2563 | return -ENODATA; | ||
2564 | |||
2565 | edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); | ||
2566 | |||
2567 | break; | ||
2568 | case e1000_i210: | ||
2569 | case e1000_i211: | ||
2570 | ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210, | ||
2571 | E1000_EEE_LP_ADV_DEV_I210, | ||
2572 | &phy_data); | ||
2573 | if (ret_val) | ||
2574 | return -ENODATA; | ||
2575 | |||
2576 | edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); | ||
2577 | |||
2578 | break; | ||
2579 | default: | ||
2580 | break; | ||
2581 | } | ||
2582 | |||
2555 | if (eeer & E1000_EEER_EEE_NEG) | 2583 | if (eeer & E1000_EEER_EEE_NEG) |
2556 | edata->eee_active = true; | 2584 | edata->eee_active = true; |
2557 | 2585 | ||