aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarolyn Wyborny <carolyn.wyborny@intel.com>2013-10-17 01:36:26 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2013-12-10 04:27:35 -0500
commit56cec249167b44ee2ba7a3cbf4431bee937e08e3 (patch)
tree99ac283efa0b7bd5fc2efec5e8db3848130782c3
parent89dbefb213a0b3e53fe1a99ec9c1a230aad5f404 (diff)
igb: Add new feature Media Auto Sense for 82580 devices only
This patch adds support for the hardware feature Media Auto Sense. This feature requires a custom EEPROM image provided by our customer support team. The feature allows hardware designed with dual PHY's, fiber and copper to be used with either media without additional EEPROM changes. Fiber is preferred and driver will swap and configure for fiber media if sensed by the device at any time. Device will swap back to copper if it is the only media detected. Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com> Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c13
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h5
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h1
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h10
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c4
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c193
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
540struct e1000_hw { 541struct 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 **/
1613static 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 **/
1793static 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
1722void igb_reset(struct igb_adapter *adapter) 1820void 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 **/
2091static 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