diff options
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.c | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_defines.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_hw.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb.h | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 193 |
6 files changed, 226 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index fe9db48f9084..06df6928f44c 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c | |||
@@ -441,6 +441,19 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw) | |||
441 | ? igb_setup_copper_link_82575 | 441 | ? igb_setup_copper_link_82575 |
442 | : igb_setup_serdes_link_82575; | 442 | : igb_setup_serdes_link_82575; |
443 | 443 | ||
444 | if (mac->type == e1000_82580) { | ||
445 | switch (hw->device_id) { | ||
446 | /* feature not supported on these id's */ | ||
447 | case E1000_DEV_ID_DH89XXCC_SGMII: | ||
448 | case E1000_DEV_ID_DH89XXCC_SERDES: | ||
449 | case E1000_DEV_ID_DH89XXCC_BACKPLANE: | ||
450 | case E1000_DEV_ID_DH89XXCC_SFP: | ||
451 | break; | ||
452 | default: | ||
453 | hw->dev_spec._82575.mas_capable = true; | ||
454 | break; | ||
455 | } | ||
456 | } | ||
444 | return 0; | 457 | return 0; |
445 | } | 458 | } |
446 | 459 | ||
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 378ca21aa647..0571b973be80 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h | |||
@@ -205,6 +205,11 @@ | |||
205 | */ | 205 | */ |
206 | 206 | ||
207 | #define E1000_CONNSW_ENRGSRC 0x4 | 207 | #define E1000_CONNSW_ENRGSRC 0x4 |
208 | #define E1000_CONNSW_PHYSD 0x400 | ||
209 | #define E1000_CONNSW_PHY_PDN 0x800 | ||
210 | #define E1000_CONNSW_SERDESD 0x200 | ||
211 | #define E1000_CONNSW_AUTOSENSE_CONF 0x2 | ||
212 | #define E1000_CONNSW_AUTOSENSE_EN 0x1 | ||
208 | #define E1000_PCS_CFG_PCS_EN 8 | 213 | #define E1000_PCS_CFG_PCS_EN 8 |
209 | #define E1000_PCS_LCTL_FLV_LINK_UP 1 | 214 | #define E1000_PCS_LCTL_FLV_LINK_UP 1 |
210 | #define E1000_PCS_LCTL_FSV_100 2 | 215 | #define E1000_PCS_LCTL_FSV_100 2 |
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 5f9758f3206e..ab99e2b582a8 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h | |||
@@ -535,6 +535,7 @@ struct e1000_dev_spec_82575 { | |||
535 | bool module_plugged; | 535 | bool module_plugged; |
536 | u8 media_port; | 536 | u8 media_port; |
537 | bool media_changed; | 537 | bool media_changed; |
538 | bool mas_capable; | ||
538 | }; | 539 | }; |
539 | 540 | ||
540 | struct e1000_hw { | 541 | struct e1000_hw { |
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 6c807927171f..11173f46f436 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h | |||
@@ -450,6 +450,8 @@ struct igb_adapter { | |||
450 | u8 rss_indir_tbl[IGB_RETA_SIZE]; | 450 | u8 rss_indir_tbl[IGB_RETA_SIZE]; |
451 | 451 | ||
452 | unsigned long link_check_timeout; | 452 | unsigned long link_check_timeout; |
453 | int copper_tries; | ||
454 | struct e1000_info ei; | ||
453 | }; | 455 | }; |
454 | 456 | ||
455 | #define IGB_FLAG_HAS_MSI (1 << 0) | 457 | #define IGB_FLAG_HAS_MSI (1 << 0) |
@@ -463,6 +465,14 @@ struct igb_adapter { | |||
463 | #define IGB_FLAG_WOL_SUPPORTED (1 << 8) | 465 | #define IGB_FLAG_WOL_SUPPORTED (1 << 8) |
464 | #define IGB_FLAG_NEED_LINK_UPDATE (1 << 9) | 466 | #define IGB_FLAG_NEED_LINK_UPDATE (1 << 9) |
465 | #define IGB_FLAG_MEDIA_RESET (1 << 10) | 467 | #define IGB_FLAG_MEDIA_RESET (1 << 10) |
468 | #define IGB_FLAG_MAS_CAPABLE (1 << 11) | ||
469 | #define IGB_FLAG_MAS_ENABLE (1 << 12) | ||
470 | |||
471 | /* Media Auto Sense */ | ||
472 | #define IGB_MAS_ENABLE_0 0X0001 | ||
473 | #define IGB_MAS_ENABLE_1 0X0002 | ||
474 | #define IGB_MAS_ENABLE_2 0X0004 | ||
475 | #define IGB_MAS_ENABLE_3 0X0008 | ||
466 | 476 | ||
467 | /* DMA Coalescing defines */ | 477 | /* DMA Coalescing defines */ |
468 | #define IGB_MIN_TXPBSIZE 20408 | 478 | #define IGB_MIN_TXPBSIZE 20408 |
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index c3143da497c8..1c7d2381af8c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c | |||
@@ -1983,6 +1983,10 @@ static void igb_diag_test(struct net_device *netdev, | |||
1983 | bool if_running = netif_running(netdev); | 1983 | bool if_running = netif_running(netdev); |
1984 | 1984 | ||
1985 | set_bit(__IGB_TESTING, &adapter->state); | 1985 | set_bit(__IGB_TESTING, &adapter->state); |
1986 | |||
1987 | /* can't do offline tests on media switching devices */ | ||
1988 | if (adapter->hw.dev_spec._82575.mas_capable) | ||
1989 | eth_test->flags &= ~ETH_TEST_FL_OFFLINE; | ||
1986 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { | 1990 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { |
1987 | /* Offline tests */ | 1991 | /* Offline tests */ |
1988 | 1992 | ||
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ed129f1c5c3e..3bc10bd5bbc1 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c | |||
@@ -1607,6 +1607,73 @@ static void igb_power_down_link(struct igb_adapter *adapter) | |||
1607 | } | 1607 | } |
1608 | 1608 | ||
1609 | /** | 1609 | /** |
1610 | * Detect and switch function for Media Auto Sense | ||
1611 | * @adapter: address of the board private structure | ||
1612 | **/ | ||
1613 | static void igb_check_swap_media(struct igb_adapter *adapter) | ||
1614 | { | ||
1615 | struct e1000_hw *hw = &adapter->hw; | ||
1616 | u32 ctrl_ext, connsw; | ||
1617 | bool swap_now = false; | ||
1618 | |||
1619 | ctrl_ext = rd32(E1000_CTRL_EXT); | ||
1620 | connsw = rd32(E1000_CONNSW); | ||
1621 | |||
1622 | /* need to live swap if current media is copper and we have fiber/serdes | ||
1623 | * to go to. | ||
1624 | */ | ||
1625 | |||
1626 | if ((hw->phy.media_type == e1000_media_type_copper) && | ||
1627 | (!(connsw & E1000_CONNSW_AUTOSENSE_EN))) { | ||
1628 | swap_now = true; | ||
1629 | } else if (!(connsw & E1000_CONNSW_SERDESD)) { | ||
1630 | /* copper signal takes time to appear */ | ||
1631 | if (adapter->copper_tries < 4) { | ||
1632 | adapter->copper_tries++; | ||
1633 | connsw |= E1000_CONNSW_AUTOSENSE_CONF; | ||
1634 | wr32(E1000_CONNSW, connsw); | ||
1635 | return; | ||
1636 | } else { | ||
1637 | adapter->copper_tries = 0; | ||
1638 | if ((connsw & E1000_CONNSW_PHYSD) && | ||
1639 | (!(connsw & E1000_CONNSW_PHY_PDN))) { | ||
1640 | swap_now = true; | ||
1641 | connsw &= ~E1000_CONNSW_AUTOSENSE_CONF; | ||
1642 | wr32(E1000_CONNSW, connsw); | ||
1643 | } | ||
1644 | } | ||
1645 | } | ||
1646 | |||
1647 | if (!swap_now) | ||
1648 | return; | ||
1649 | |||
1650 | switch (hw->phy.media_type) { | ||
1651 | case e1000_media_type_copper: | ||
1652 | netdev_info(adapter->netdev, | ||
1653 | "MAS: changing media to fiber/serdes\n"); | ||
1654 | ctrl_ext |= | ||
1655 | E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; | ||
1656 | adapter->flags |= IGB_FLAG_MEDIA_RESET; | ||
1657 | adapter->copper_tries = 0; | ||
1658 | break; | ||
1659 | case e1000_media_type_internal_serdes: | ||
1660 | case e1000_media_type_fiber: | ||
1661 | netdev_info(adapter->netdev, | ||
1662 | "MAS: changing media to copper\n"); | ||
1663 | ctrl_ext &= | ||
1664 | ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; | ||
1665 | adapter->flags |= IGB_FLAG_MEDIA_RESET; | ||
1666 | break; | ||
1667 | default: | ||
1668 | /* shouldn't get here during regular operation */ | ||
1669 | netdev_err(adapter->netdev, | ||
1670 | "AMS: Invalid media type found, returning\n"); | ||
1671 | break; | ||
1672 | } | ||
1673 | wr32(E1000_CTRL_EXT, ctrl_ext); | ||
1674 | } | ||
1675 | |||
1676 | /** | ||
1610 | * igb_up - Open the interface and prepare it to handle traffic | 1677 | * igb_up - Open the interface and prepare it to handle traffic |
1611 | * @adapter: board private structure | 1678 | * @adapter: board private structure |
1612 | **/ | 1679 | **/ |
@@ -1719,6 +1786,37 @@ void igb_reinit_locked(struct igb_adapter *adapter) | |||
1719 | clear_bit(__IGB_RESETTING, &adapter->state); | 1786 | clear_bit(__IGB_RESETTING, &adapter->state); |
1720 | } | 1787 | } |
1721 | 1788 | ||
1789 | /** igb_enable_mas - Media Autosense re-enable after swap | ||
1790 | * | ||
1791 | * @adapter: adapter struct | ||
1792 | **/ | ||
1793 | static s32 igb_enable_mas(struct igb_adapter *adapter) | ||
1794 | { | ||
1795 | struct e1000_hw *hw = &adapter->hw; | ||
1796 | u32 connsw; | ||
1797 | s32 ret_val = 0; | ||
1798 | |||
1799 | connsw = rd32(E1000_CONNSW); | ||
1800 | if (!(hw->phy.media_type == e1000_media_type_copper)) | ||
1801 | return ret_val; | ||
1802 | |||
1803 | /* configure for SerDes media detect */ | ||
1804 | if (!(connsw & E1000_CONNSW_SERDESD)) { | ||
1805 | connsw |= E1000_CONNSW_ENRGSRC; | ||
1806 | connsw |= E1000_CONNSW_AUTOSENSE_EN; | ||
1807 | wr32(E1000_CONNSW, connsw); | ||
1808 | wrfl(); | ||
1809 | } else if (connsw & E1000_CONNSW_SERDESD) { | ||
1810 | /* already SerDes, no need to enable anything */ | ||
1811 | return ret_val; | ||
1812 | } else { | ||
1813 | netdev_info(adapter->netdev, | ||
1814 | "MAS: Unable to configure feature, disabling..\n"); | ||
1815 | adapter->flags &= ~IGB_FLAG_MAS_ENABLE; | ||
1816 | } | ||
1817 | return ret_val; | ||
1818 | } | ||
1819 | |||
1722 | void igb_reset(struct igb_adapter *adapter) | 1820 | void igb_reset(struct igb_adapter *adapter) |
1723 | { | 1821 | { |
1724 | struct pci_dev *pdev = adapter->pdev; | 1822 | struct pci_dev *pdev = adapter->pdev; |
@@ -1830,6 +1928,16 @@ void igb_reset(struct igb_adapter *adapter) | |||
1830 | hw->mac.ops.reset_hw(hw); | 1928 | hw->mac.ops.reset_hw(hw); |
1831 | wr32(E1000_WUC, 0); | 1929 | wr32(E1000_WUC, 0); |
1832 | 1930 | ||
1931 | if (adapter->flags & IGB_FLAG_MEDIA_RESET) { | ||
1932 | /* need to resetup here after media swap */ | ||
1933 | adapter->ei.get_invariants(hw); | ||
1934 | adapter->flags &= ~IGB_FLAG_MEDIA_RESET; | ||
1935 | } | ||
1936 | if (adapter->flags & IGB_FLAG_MAS_ENABLE) { | ||
1937 | if (igb_enable_mas(adapter)) | ||
1938 | dev_err(&pdev->dev, | ||
1939 | "Error enabling Media Auto Sense\n"); | ||
1940 | } | ||
1833 | if (hw->mac.ops.init_hw(hw)) | 1941 | if (hw->mac.ops.init_hw(hw)) |
1834 | dev_err(&pdev->dev, "Hardware Error\n"); | 1942 | dev_err(&pdev->dev, "Hardware Error\n"); |
1835 | 1943 | ||
@@ -1976,6 +2084,58 @@ void igb_set_fw_version(struct igb_adapter *adapter) | |||
1976 | } | 2084 | } |
1977 | 2085 | ||
1978 | /** | 2086 | /** |
2087 | * igb_init_mas - init Media Autosense feature if enabled in the NVM | ||
2088 | * | ||
2089 | * @adapter: adapter struct | ||
2090 | **/ | ||
2091 | static void igb_init_mas(struct igb_adapter *adapter) | ||
2092 | { | ||
2093 | struct e1000_hw *hw = &adapter->hw; | ||
2094 | u16 eeprom_data; | ||
2095 | |||
2096 | hw->nvm.ops.read(hw, NVM_COMPAT, 1, &eeprom_data); | ||
2097 | switch (hw->bus.func) { | ||
2098 | case E1000_FUNC_0: | ||
2099 | if (eeprom_data & IGB_MAS_ENABLE_0) { | ||
2100 | adapter->flags |= IGB_FLAG_MAS_ENABLE; | ||
2101 | netdev_info(adapter->netdev, | ||
2102 | "MAS: Enabling Media Autosense for port %d\n", | ||
2103 | hw->bus.func); | ||
2104 | } | ||
2105 | break; | ||
2106 | case E1000_FUNC_1: | ||
2107 | if (eeprom_data & IGB_MAS_ENABLE_1) { | ||
2108 | adapter->flags |= IGB_FLAG_MAS_ENABLE; | ||
2109 | netdev_info(adapter->netdev, | ||
2110 | "MAS: Enabling Media Autosense for port %d\n", | ||
2111 | hw->bus.func); | ||
2112 | } | ||
2113 | break; | ||
2114 | case E1000_FUNC_2: | ||
2115 | if (eeprom_data & IGB_MAS_ENABLE_2) { | ||
2116 | adapter->flags |= IGB_FLAG_MAS_ENABLE; | ||
2117 | netdev_info(adapter->netdev, | ||
2118 | "MAS: Enabling Media Autosense for port %d\n", | ||
2119 | hw->bus.func); | ||
2120 | } | ||
2121 | break; | ||
2122 | case E1000_FUNC_3: | ||
2123 | if (eeprom_data & IGB_MAS_ENABLE_3) { | ||
2124 | adapter->flags |= IGB_FLAG_MAS_ENABLE; | ||
2125 | netdev_info(adapter->netdev, | ||
2126 | "MAS: Enabling Media Autosense for port %d\n", | ||
2127 | hw->bus.func); | ||
2128 | } | ||
2129 | break; | ||
2130 | default: | ||
2131 | /* Shouldn't get here */ | ||
2132 | netdev_err(adapter->netdev, | ||
2133 | "MAS: Invalid port configuration, returning\n"); | ||
2134 | break; | ||
2135 | } | ||
2136 | } | ||
2137 | |||
2138 | /** | ||
1979 | * igb_init_i2c - Init I2C interface | 2139 | * igb_init_i2c - Init I2C interface |
1980 | * @adapter: pointer to adapter structure | 2140 | * @adapter: pointer to adapter structure |
1981 | **/ | 2141 | **/ |
@@ -2346,6 +2506,11 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2346 | adapter->ets = false; | 2506 | adapter->ets = false; |
2347 | } | 2507 | } |
2348 | #endif | 2508 | #endif |
2509 | /* Check if Media Autosense is enabled */ | ||
2510 | adapter->ei = *ei; | ||
2511 | if (hw->dev_spec._82575.mas_capable) | ||
2512 | igb_init_mas(adapter); | ||
2513 | |||
2349 | /* do hw tstamp init after resetting */ | 2514 | /* do hw tstamp init after resetting */ |
2350 | igb_ptp_init(adapter); | 2515 | igb_ptp_init(adapter); |
2351 | 2516 | ||
@@ -3931,6 +4096,7 @@ static void igb_watchdog_task(struct work_struct *work) | |||
3931 | struct net_device *netdev = adapter->netdev; | 4096 | struct net_device *netdev = adapter->netdev; |
3932 | u32 link; | 4097 | u32 link; |
3933 | int i; | 4098 | int i; |
4099 | u32 connsw; | ||
3934 | 4100 | ||
3935 | link = igb_has_link(adapter); | 4101 | link = igb_has_link(adapter); |
3936 | 4102 | ||
@@ -3941,6 +4107,14 @@ static void igb_watchdog_task(struct work_struct *work) | |||
3941 | link = false; | 4107 | link = false; |
3942 | } | 4108 | } |
3943 | 4109 | ||
4110 | /* Force link down if we have fiber to swap to */ | ||
4111 | if (adapter->flags & IGB_FLAG_MAS_ENABLE) { | ||
4112 | if (hw->phy.media_type == e1000_media_type_copper) { | ||
4113 | connsw = rd32(E1000_CONNSW); | ||
4114 | if (!(connsw & E1000_CONNSW_AUTOSENSE_EN)) | ||
4115 | link = 0; | ||
4116 | } | ||
4117 | } | ||
3944 | if (link) { | 4118 | if (link) { |
3945 | /* Perform a reset if the media type changed. */ | 4119 | /* Perform a reset if the media type changed. */ |
3946 | if (hw->dev_spec._82575.media_changed) { | 4120 | if (hw->dev_spec._82575.media_changed) { |
@@ -4028,8 +4202,27 @@ static void igb_watchdog_task(struct work_struct *work) | |||
4028 | mod_timer(&adapter->phy_info_timer, | 4202 | mod_timer(&adapter->phy_info_timer, |
4029 | round_jiffies(jiffies + 2 * HZ)); | 4203 | round_jiffies(jiffies + 2 * HZ)); |
4030 | 4204 | ||
4205 | /* link is down, time to check for alternate media */ | ||
4206 | if (adapter->flags & IGB_FLAG_MAS_ENABLE) { | ||
4207 | igb_check_swap_media(adapter); | ||
4208 | if (adapter->flags & IGB_FLAG_MEDIA_RESET) { | ||
4209 | schedule_work(&adapter->reset_task); | ||
4210 | /* return immediately */ | ||
4211 | return; | ||
4212 | } | ||
4213 | } | ||
4031 | pm_schedule_suspend(netdev->dev.parent, | 4214 | pm_schedule_suspend(netdev->dev.parent, |
4032 | MSEC_PER_SEC * 5); | 4215 | MSEC_PER_SEC * 5); |
4216 | |||
4217 | /* also check for alternate media here */ | ||
4218 | } else if (!netif_carrier_ok(netdev) && | ||
4219 | (adapter->flags & IGB_FLAG_MAS_ENABLE)) { | ||
4220 | igb_check_swap_media(adapter); | ||
4221 | if (adapter->flags & IGB_FLAG_MEDIA_RESET) { | ||
4222 | schedule_work(&adapter->reset_task); | ||
4223 | /* return immediately */ | ||
4224 | return; | ||
4225 | } | ||
4033 | } | 4226 | } |
4034 | } | 4227 | } |
4035 | 4228 | ||