diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 149ac85b5f9e328d584aaa2a40d899527739edc5..41a2fa2fc67dff1ff1c03f9fc6e09234e4c8897e 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -220,12 +220,12 @@ config IXGBE_DCB If unsure, say N. config IXGBEVF - tristate "Intel(R) 82599 Virtual Function Ethernet support" + tristate "Intel(R) 10GbE PCI Express Virtual Function Ethernet support" depends on PCI_MSI ---help--- - This driver supports Intel(R) 82599 virtual functions. For more - information on how to identify your adapter, go to the Adapter & - Driver ID Guide at: + This driver supports Intel(R) PCI Express virtual functions for the + Intel(R) ixgbe driver. For more information on how to identify your + adapter, go to the Adapter & Driver ID Guide at: diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 0b52fbc7d56de605d39e72dff85092011f3166a4..e526d40e9cf81ee11ae1dc46645e0560dec8cccb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -562,6 +562,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, hw_link_info->link_info = resp->link_info; hw_link_info->an_info = resp->an_info; hw_link_info->ext_info = resp->ext_info; + hw_link_info->loopback = resp->loopback; if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE)) hw_link_info->lse_enable = true; diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.h b/drivers/net/ethernet/intel/i40e/i40e_diag.h index 3d98277f45268afd00457fa63c758ea225bd077b..d1fc68cd6c942b3e4f84302d71415b2e13132aa0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.h +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.h @@ -31,10 +31,10 @@ #include "i40e_type.h" enum i40e_lb_mode { - I40E_LB_MODE_NONE = 0, - I40E_LB_MODE_PHY_LOCAL, - I40E_LB_MODE_PHY_REMOTE, - I40E_LB_MODE_MAC_LOCAL, + I40E_LB_MODE_NONE = 0x0, + I40E_LB_MODE_PHY_LOCAL = I40E_AQ_LB_PHY_LOCAL, + I40E_LB_MODE_PHY_REMOTE = I40E_AQ_LB_PHY_REMOTE, + I40E_LB_MODE_MAC_LOCAL = I40E_AQ_LB_MAC_LOCAL, }; struct i40e_diag_reg_test_info { diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f0bab1704dd14c72cc8b7d7d14620e75ad32be7b..fd3e379de6da0a211a9626ce2e2e117fd693f249 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -422,15 +422,19 @@ static int i40e_set_ringparam(struct net_device *netdev, if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - new_tx_count = clamp_t(u32, ring->tx_pending, - I40E_MIN_NUM_DESCRIPTORS, - I40E_MAX_NUM_DESCRIPTORS); - new_tx_count = ALIGN(new_tx_count, I40E_REQ_DESCRIPTOR_MULTIPLE); + if (ring->tx_pending > I40E_MAX_NUM_DESCRIPTORS || + ring->tx_pending < I40E_MIN_NUM_DESCRIPTORS || + ring->rx_pending > I40E_MAX_NUM_DESCRIPTORS || + ring->rx_pending < I40E_MIN_NUM_DESCRIPTORS) { + netdev_info(netdev, + "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n", + ring->tx_pending, ring->rx_pending, + I40E_MIN_NUM_DESCRIPTORS, I40E_MAX_NUM_DESCRIPTORS); + return -EINVAL; + } - new_rx_count = clamp_t(u32, ring->rx_pending, - I40E_MIN_NUM_DESCRIPTORS, - I40E_MAX_NUM_DESCRIPTORS); - new_rx_count = ALIGN(new_rx_count, I40E_REQ_DESCRIPTOR_MULTIPLE); + new_tx_count = ALIGN(ring->tx_pending, I40E_REQ_DESCRIPTOR_MULTIPLE); + new_rx_count = ALIGN(ring->rx_pending, I40E_REQ_DESCRIPTOR_MULTIPLE); /* if nothing to do return success */ if ((new_tx_count == vsi->tx_rings[0]->count) && @@ -711,7 +715,7 @@ static int i40e_link_test(struct net_device *netdev, u64 *data) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - netdev_info(netdev, "link test\n"); + netif_info(pf, hw, netdev, "link test\n"); if (i40e_get_link_status(&pf->hw)) *data = 0; else @@ -725,7 +729,7 @@ static int i40e_reg_test(struct net_device *netdev, u64 *data) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - netdev_info(netdev, "register test\n"); + netif_info(pf, hw, netdev, "register test\n"); *data = i40e_diag_reg_test(&pf->hw); i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); @@ -737,7 +741,7 @@ static int i40e_eeprom_test(struct net_device *netdev, u64 *data) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - netdev_info(netdev, "eeprom test\n"); + netif_info(pf, hw, netdev, "eeprom test\n"); *data = i40e_diag_eeprom_test(&pf->hw); return *data; @@ -749,7 +753,7 @@ static int i40e_intr_test(struct net_device *netdev, u64 *data) struct i40e_pf *pf = np->vsi->back; u16 swc_old = pf->sw_int_count; - netdev_info(netdev, "interrupt test\n"); + netif_info(pf, hw, netdev, "interrupt test\n"); wr32(&pf->hw, I40E_PFINT_DYN_CTL0, (I40E_PFINT_DYN_CTL0_INTENA_MASK | I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK)); @@ -761,7 +765,10 @@ static int i40e_intr_test(struct net_device *netdev, u64 *data) static int i40e_loopback_test(struct net_device *netdev, u64 *data) { - netdev_info(netdev, "loopback test not implemented\n"); + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + + netif_info(pf, hw, netdev, "loopback test not implemented\n"); *data = 0; return *data; @@ -776,8 +783,7 @@ static void i40e_diag_test(struct net_device *netdev, set_bit(__I40E_TESTING, &pf->state); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ - - netdev_info(netdev, "offline testing starting\n"); + netif_info(pf, drv, netdev, "offline testing starting\n"); /* Link test performed before hardware reset * so autoneg doesn't interfere with test result @@ -798,8 +804,9 @@ static void i40e_diag_test(struct net_device *netdev, eth_test->flags |= ETH_TEST_FL_FAILED; } else { - netdev_info(netdev, "online test starting\n"); /* Online tests */ + netif_info(pf, drv, netdev, "online testing starting\n"); + if (i40e_link_test(netdev, &data[I40E_ETH_TEST_LINK])) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -811,7 +818,7 @@ static void i40e_diag_test(struct net_device *netdev, } clear_bit(__I40E_TESTING, &pf->state); - netdev_info(netdev, "testing finished\n"); + netif_info(pf, drv, netdev, "testing finished\n"); } static void i40e_get_wol(struct net_device *netdev, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d2b48bb237fd3111d253007ec3b86e72c8cbc094..a6291e23fe5f7b7859bf5aa60c749a4149af13ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -36,7 +36,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 12 +#define DRV_VERSION_BUILD 13 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index db55d9947f151cf19c17f2f55e8ee24e69364cbd..faabf22fbd202751343053daf839f7edf838191b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -49,10 +49,23 @@ #define I40E_QUEUE_END_OF_LIST 0x7FF -#define I40E_ITR_NONE 3 -#define I40E_RX_ITR 0 -#define I40E_TX_ITR 1 -#define I40E_PE_ITR 2 +/* this enum matches hardware bits and is meant to be used by DYN_CTLN + * registers and QINT registers or more generally anywhere in the manual + * mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any + * register but instead is a special value meaning "don't update" ITR0/1/2. + */ +enum i40e_dyn_idx_t { + I40E_IDX_ITR0 = 0, + I40E_IDX_ITR1 = 1, + I40E_IDX_ITR2 = 2, + I40E_ITR_NONE = 3 /* ITR_NONE must not be used as an index */ +}; + +/* these are indexes into ITRN registers */ +#define I40E_RX_ITR I40E_IDX_ITR0 +#define I40E_TX_ITR I40E_IDX_ITR1 +#define I40E_PE_ITR I40E_IDX_ITR2 + /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ #define I40E_RXBUFFER_2048 2048 diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 88b37e07b255338dfe7af2d28c115c3cf7097411..8ae64457026348deb5ac8aa3efdcad35abe09d3c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -172,6 +172,7 @@ struct i40e_link_status { u8 link_info; u8 an_info; u8 ext_info; + u8 loopback; /* is Link Status Event notification to SW enabled */ bool lse_enable; }; diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 47c2d10df8263422d8e23169939adc84a5f3012b..06df6928f44c2942f3e9b51647d047d790a2d6af 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -112,6 +112,59 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw) return ext_mdio; } +/** + * igb_check_for_link_media_swap - Check which M88E1112 interface linked + * @hw: pointer to the HW structure + * + * Poll the M88E1112 interfaces to see which interface achieved link. + */ +static s32 igb_check_for_link_media_swap(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + u8 port = 0; + + /* Check the copper medium. */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; + + ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data); + if (ret_val) + return ret_val; + + if (data & E1000_M88E1112_STATUS_LINK) + port = E1000_MEDIA_PORT_COPPER; + + /* Check the other medium. */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 1); + if (ret_val) + return ret_val; + + ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data); + if (ret_val) + return ret_val; + + /* reset page to 0 */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; + + if (data & E1000_M88E1112_STATUS_LINK) + port = E1000_MEDIA_PORT_OTHER; + + /* Determine if a swap needs to happen. */ + if (port && (hw->dev_spec._82575.media_port != port)) { + hw->dev_spec._82575.media_port = port; + hw->dev_spec._82575.media_changed = true; + } else { + ret_val = igb_check_for_link_82575(hw); + } + + return E1000_SUCCESS; +} + /** * igb_init_phy_params_82575 - Init PHY func ptrs. * @hw: pointer to the HW structure @@ -189,6 +242,29 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) else phy->ops.get_cable_length = igb_get_cable_length_m88; phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; + /* Check if this PHY is confgured for media swap. */ + if (phy->id == M88E1112_E_PHY_ID) { + u16 data; + + ret_val = phy->ops.write_reg(hw, + E1000_M88E1112_PAGE_ADDR, + 2); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, + E1000_M88E1112_MAC_CTRL_1, + &data); + if (ret_val) + goto out; + + data = (data & E1000_M88E1112_MAC_CTRL_1_MODE_MASK) >> + E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT; + if (data == E1000_M88E1112_AUTO_COPPER_SGMII || + data == E1000_M88E1112_AUTO_COPPER_BASEX) + hw->mac.ops.check_for_link = + igb_check_for_link_media_swap; + } break; case IGP03E1000_E_PHY_ID: phy->type = e1000_phy_igp_3; @@ -365,6 +441,19 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw) ? igb_setup_copper_link_82575 : igb_setup_serdes_link_82575; + if (mac->type == e1000_82580) { + switch (hw->device_id) { + /* feature not supported on these id's */ + case E1000_DEV_ID_DH89XXCC_SGMII: + case E1000_DEV_ID_DH89XXCC_SERDES: + case E1000_DEV_ID_DH89XXCC_BACKPLANE: + case E1000_DEV_ID_DH89XXCC_SFP: + break; + default: + hw->dev_spec._82575.mas_capable = true; + break; + } + } return 0; } diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 978eca31ceda94a146bc9095221a0205f65325e8..0571b973be80d357bbbe4fec67c0fef0b3859546 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -205,6 +205,11 @@ */ #define E1000_CONNSW_ENRGSRC 0x4 +#define E1000_CONNSW_PHYSD 0x400 +#define E1000_CONNSW_PHY_PDN 0x800 +#define E1000_CONNSW_SERDESD 0x200 +#define E1000_CONNSW_AUTOSENSE_CONF 0x2 +#define E1000_CONNSW_AUTOSENSE_EN 0x1 #define E1000_PCS_CFG_PCS_EN 8 #define E1000_PCS_LCTL_FLV_LINK_UP 1 #define E1000_PCS_LCTL_FSV_100 2 @@ -532,6 +537,17 @@ #define E1000_MDICNFG_PHY_MASK 0x03E00000 #define E1000_MDICNFG_PHY_SHIFT 21 +#define E1000_MEDIA_PORT_COPPER 1 +#define E1000_MEDIA_PORT_OTHER 2 +#define E1000_M88E1112_AUTO_COPPER_SGMII 0x2 +#define E1000_M88E1112_AUTO_COPPER_BASEX 0x3 +#define E1000_M88E1112_STATUS_LINK 0x0004 /* Interface Link Bit */ +#define E1000_M88E1112_MAC_CTRL_1 0x10 +#define E1000_M88E1112_MAC_CTRL_1_MODE_MASK 0x0380 /* Mode Select */ +#define E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT 7 +#define E1000_M88E1112_PAGE_ADDR 0x16 +#define E1000_M88E1112_STATUS 0x01 + /* PCI Express Control */ #define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 #define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 2e166b22d52b6374e3814a9526d6cad9decfa5a3..ab99e2b582a85c7b445d54ec85f867c431cf1e29 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -533,6 +533,9 @@ struct e1000_dev_spec_82575 { bool clear_semaphore_once; struct e1000_sfp_flags eth_flags; bool module_plugged; + u8 media_port; + bool media_changed; + bool mas_capable; }; struct e1000_hw { diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 5e9ed89403aa45adb9238330e4937e8aa1f4cd09..8aaca0a1dca0781566d32788ea44b084f7eeb8a3 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -337,8 +337,10 @@ struct hwmon_attr { }; struct hwmon_buff { - struct device *device; - struct hwmon_attr *hwmon_list; + struct attribute_group group; + const struct attribute_group *groups[2]; + struct attribute *attrs[E1000_MAX_SENSORS * 4 + 1]; + struct hwmon_attr hwmon_list[E1000_MAX_SENSORS * 4]; unsigned int n_hwmon; }; #endif @@ -440,7 +442,7 @@ struct igb_adapter { char fw_version[32]; #ifdef CONFIG_IGB_HWMON - struct hwmon_buff igb_hwmon_buff; + struct hwmon_buff *igb_hwmon_buff; bool ets; #endif struct i2c_algo_bit_data i2c_algo; @@ -450,6 +452,8 @@ struct igb_adapter { u8 rss_indir_tbl[IGB_RETA_SIZE]; unsigned long link_check_timeout; + int copper_tries; + struct e1000_info ei; }; #define IGB_FLAG_HAS_MSI (1 << 0) @@ -462,6 +466,15 @@ struct igb_adapter { #define IGB_FLAG_RSS_FIELD_IPV6_UDP (1 << 7) #define IGB_FLAG_WOL_SUPPORTED (1 << 8) #define IGB_FLAG_NEED_LINK_UPDATE (1 << 9) +#define IGB_FLAG_MEDIA_RESET (1 << 10) +#define IGB_FLAG_MAS_CAPABLE (1 << 11) +#define IGB_FLAG_MAS_ENABLE (1 << 12) + +/* Media Auto Sense */ +#define IGB_MAS_ENABLE_0 0X0001 +#define IGB_MAS_ENABLE_1 0X0002 +#define IGB_MAS_ENABLE_2 0X0004 +#define IGB_MAS_ENABLE_3 0X0008 /* DMA Coalescing defines */ #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 c3143da497c82be85c4f580776290872e647e317..1c7d2381af8c626e7f5175223597257c323be2ba 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, bool if_running = netif_running(netdev); set_bit(__IGB_TESTING, &adapter->state); + + /* can't do offline tests on media switching devices */ + if (adapter->hw.dev_spec._82575.mas_capable) + eth_test->flags &= ~ETH_TEST_FL_OFFLINE; if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 58f1ce967aebfed707ed2986c968654dd49fa829..e0af5bc616139bc6540577952175345053399dd1 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -117,29 +117,29 @@ static int igb_add_hwmon_attr(struct igb_adapter *adapter, unsigned int n_attr; struct hwmon_attr *igb_attr; - n_attr = adapter->igb_hwmon_buff.n_hwmon; - igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr]; + n_attr = adapter->igb_hwmon_buff->n_hwmon; + igb_attr = &adapter->igb_hwmon_buff->hwmon_list[n_attr]; switch (type) { case IGB_HWMON_TYPE_LOC: igb_attr->dev_attr.show = igb_hwmon_show_location; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_label", offset); + "temp%u_label", offset + 1); break; case IGB_HWMON_TYPE_TEMP: igb_attr->dev_attr.show = igb_hwmon_show_temp; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_input", offset); + "temp%u_input", offset + 1); break; case IGB_HWMON_TYPE_CAUTION: igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_max", offset); + "temp%u_max", offset + 1); break; case IGB_HWMON_TYPE_MAX: igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh; snprintf(igb_attr->name, sizeof(igb_attr->name), - "temp%u_crit", offset); + "temp%u_crit", offset + 1); break; default: rc = -EPERM; @@ -154,30 +154,16 @@ static int igb_add_hwmon_attr(struct igb_adapter *adapter, igb_attr->dev_attr.attr.mode = S_IRUGO; igb_attr->dev_attr.attr.name = igb_attr->name; sysfs_attr_init(&igb_attr->dev_attr.attr); - rc = device_create_file(&adapter->pdev->dev, - &igb_attr->dev_attr); - if (rc == 0) - ++adapter->igb_hwmon_buff.n_hwmon; - return rc; + adapter->igb_hwmon_buff->attrs[n_attr] = &igb_attr->dev_attr.attr; + + ++adapter->igb_hwmon_buff->n_hwmon; + + return 0; } static void igb_sysfs_del_adapter(struct igb_adapter *adapter) { - int i; - - if (adapter == NULL) - return; - - for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) { - device_remove_file(&adapter->pdev->dev, - &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr); - } - - kfree(adapter->igb_hwmon_buff.hwmon_list); - - if (adapter->igb_hwmon_buff.device) - hwmon_device_unregister(adapter->igb_hwmon_buff.device); } /* called from igb_main.c */ @@ -189,11 +175,11 @@ void igb_sysfs_exit(struct igb_adapter *adapter) /* called from igb_main.c */ int igb_sysfs_init(struct igb_adapter *adapter) { - struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff; + struct hwmon_buff *igb_hwmon; + struct i2c_client *client; + struct device *hwmon_dev; unsigned int i; - int n_attrs; int rc = 0; - struct i2c_client *client = NULL; /* If this method isn't defined we don't support thermals */ if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) @@ -201,34 +187,16 @@ int igb_sysfs_init(struct igb_adapter *adapter) /* Don't create thermal hwmon interface if no sensors present */ rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw)); - if (rc) - goto exit; - - /* init i2c_client */ - client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); - if (client == NULL) { - dev_info(&adapter->pdev->dev, - "Failed to create new i2c device..\n"); + if (rc) goto exit; - } - adapter->i2c_client = client; - /* Allocation space for max attributes - * max num sensors * values (loc, temp, max, caution) - */ - n_attrs = E1000_MAX_SENSORS * 4; - igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr), - GFP_KERNEL); - if (!igb_hwmon->hwmon_list) { + igb_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*igb_hwmon), + GFP_KERNEL); + if (!igb_hwmon) { rc = -ENOMEM; - goto err; - } - - igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev); - if (IS_ERR(igb_hwmon->device)) { - rc = PTR_ERR(igb_hwmon->device); - goto err; + goto exit; } + adapter->igb_hwmon_buff = igb_hwmon; for (i = 0; i < E1000_MAX_SENSORS; i++) { @@ -240,11 +208,39 @@ int igb_sysfs_init(struct igb_adapter *adapter) /* Bail if any hwmon attr struct fails to initialize */ rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION); - rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC); - rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP); - rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX); if (rc) - goto err; + goto exit; + rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC); + if (rc) + goto exit; + rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP); + if (rc) + goto exit; + rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX); + if (rc) + goto exit; + } + + /* init i2c_client */ + client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); + if (client == NULL) { + dev_info(&adapter->pdev->dev, + "Failed to create new i2c device.\n"); + rc = -ENODEV; + goto exit; + } + adapter->i2c_client = client; + + igb_hwmon->groups[0] = &igb_hwmon->group; + igb_hwmon->group.attrs = igb_hwmon->attrs; + + hwmon_dev = devm_hwmon_device_register_with_groups(&adapter->pdev->dev, + client->name, + igb_hwmon, + igb_hwmon->groups); + if (IS_ERR(hwmon_dev)) { + rc = PTR_ERR(hwmon_dev); + goto err; } goto exit; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 025e5f4b7481d680f6b2dff0491a857615af250b..3bc10bd5bbc199ef3ade30d5ec28dea7b683392e 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1606,6 +1606,73 @@ static void igb_power_down_link(struct igb_adapter *adapter) igb_shutdown_serdes_link_82575(&adapter->hw); } +/** + * Detect and switch function for Media Auto Sense + * @adapter: address of the board private structure + **/ +static void igb_check_swap_media(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext, connsw; + bool swap_now = false; + + ctrl_ext = rd32(E1000_CTRL_EXT); + connsw = rd32(E1000_CONNSW); + + /* need to live swap if current media is copper and we have fiber/serdes + * to go to. + */ + + if ((hw->phy.media_type == e1000_media_type_copper) && + (!(connsw & E1000_CONNSW_AUTOSENSE_EN))) { + swap_now = true; + } else if (!(connsw & E1000_CONNSW_SERDESD)) { + /* copper signal takes time to appear */ + if (adapter->copper_tries < 4) { + adapter->copper_tries++; + connsw |= E1000_CONNSW_AUTOSENSE_CONF; + wr32(E1000_CONNSW, connsw); + return; + } else { + adapter->copper_tries = 0; + if ((connsw & E1000_CONNSW_PHYSD) && + (!(connsw & E1000_CONNSW_PHY_PDN))) { + swap_now = true; + connsw &= ~E1000_CONNSW_AUTOSENSE_CONF; + wr32(E1000_CONNSW, connsw); + } + } + } + + if (!swap_now) + return; + + switch (hw->phy.media_type) { + case e1000_media_type_copper: + netdev_info(adapter->netdev, + "MAS: changing media to fiber/serdes\n"); + ctrl_ext |= + E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + adapter->flags |= IGB_FLAG_MEDIA_RESET; + adapter->copper_tries = 0; + break; + case e1000_media_type_internal_serdes: + case e1000_media_type_fiber: + netdev_info(adapter->netdev, + "MAS: changing media to copper\n"); + ctrl_ext &= + ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + adapter->flags |= IGB_FLAG_MEDIA_RESET; + break; + default: + /* shouldn't get here during regular operation */ + netdev_err(adapter->netdev, + "AMS: Invalid media type found, returning\n"); + break; + } + wr32(E1000_CTRL_EXT, ctrl_ext); +} + /** * igb_up - Open the interface and prepare it to handle traffic * @adapter: board private structure @@ -1719,6 +1786,37 @@ void igb_reinit_locked(struct igb_adapter *adapter) clear_bit(__IGB_RESETTING, &adapter->state); } +/** igb_enable_mas - Media Autosense re-enable after swap + * + * @adapter: adapter struct + **/ +static s32 igb_enable_mas(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 connsw; + s32 ret_val = 0; + + connsw = rd32(E1000_CONNSW); + if (!(hw->phy.media_type == e1000_media_type_copper)) + return ret_val; + + /* configure for SerDes media detect */ + if (!(connsw & E1000_CONNSW_SERDESD)) { + connsw |= E1000_CONNSW_ENRGSRC; + connsw |= E1000_CONNSW_AUTOSENSE_EN; + wr32(E1000_CONNSW, connsw); + wrfl(); + } else if (connsw & E1000_CONNSW_SERDESD) { + /* already SerDes, no need to enable anything */ + return ret_val; + } else { + netdev_info(adapter->netdev, + "MAS: Unable to configure feature, disabling..\n"); + adapter->flags &= ~IGB_FLAG_MAS_ENABLE; + } + return ret_val; +} + void igb_reset(struct igb_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -1830,6 +1928,16 @@ void igb_reset(struct igb_adapter *adapter) hw->mac.ops.reset_hw(hw); wr32(E1000_WUC, 0); + if (adapter->flags & IGB_FLAG_MEDIA_RESET) { + /* need to resetup here after media swap */ + adapter->ei.get_invariants(hw); + adapter->flags &= ~IGB_FLAG_MEDIA_RESET; + } + if (adapter->flags & IGB_FLAG_MAS_ENABLE) { + if (igb_enable_mas(adapter)) + dev_err(&pdev->dev, + "Error enabling Media Auto Sense\n"); + } if (hw->mac.ops.init_hw(hw)) dev_err(&pdev->dev, "Hardware Error\n"); @@ -1975,6 +2083,58 @@ void igb_set_fw_version(struct igb_adapter *adapter) return; } +/** + * igb_init_mas - init Media Autosense feature if enabled in the NVM + * + * @adapter: adapter struct + **/ +static void igb_init_mas(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 eeprom_data; + + hw->nvm.ops.read(hw, NVM_COMPAT, 1, &eeprom_data); + switch (hw->bus.func) { + case E1000_FUNC_0: + if (eeprom_data & IGB_MAS_ENABLE_0) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + case E1000_FUNC_1: + if (eeprom_data & IGB_MAS_ENABLE_1) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + case E1000_FUNC_2: + if (eeprom_data & IGB_MAS_ENABLE_2) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + case E1000_FUNC_3: + if (eeprom_data & IGB_MAS_ENABLE_3) { + adapter->flags |= IGB_FLAG_MAS_ENABLE; + netdev_info(adapter->netdev, + "MAS: Enabling Media Autosense for port %d\n", + hw->bus.func); + } + break; + default: + /* Shouldn't get here */ + netdev_err(adapter->netdev, + "MAS: Invalid port configuration, returning\n"); + break; + } +} + /** * igb_init_i2c - Init I2C interface * @adapter: pointer to adapter structure @@ -2022,7 +2182,6 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) s32 ret_val; static int global_quad_port_a; /* global quad port a indication */ const struct e1000_info *ei = igb_info_tbl[ent->driver_data]; - unsigned long mmio_start, mmio_len; int err, pci_using_dac; u8 part_str[E1000_PBANUM_LENGTH]; @@ -2079,11 +2238,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->back = adapter; adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); - mmio_start = pci_resource_start(pdev, 0); - mmio_len = pci_resource_len(pdev, 0); - err = -EIO; - hw->hw_addr = ioremap(mmio_start, mmio_len); + hw->hw_addr = pci_iomap(pdev, 0, 0); if (!hw->hw_addr) goto err_ioremap; @@ -2093,8 +2249,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len; + netdev->mem_start = pci_resource_start(pdev, 0); + netdev->mem_end = pci_resource_end(pdev, 0); /* PCI config space info */ hw->vendor_id = pdev->vendor; @@ -2350,6 +2506,11 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->ets = false; } #endif + /* Check if Media Autosense is enabled */ + adapter->ei = *ei; + if (hw->dev_spec._82575.mas_capable) + igb_init_mas(adapter); + /* do hw tstamp init after resetting */ igb_ptp_init(adapter); @@ -3935,6 +4096,7 @@ static void igb_watchdog_task(struct work_struct *work) struct net_device *netdev = adapter->netdev; u32 link; int i; + u32 connsw; link = igb_has_link(adapter); @@ -3945,7 +4107,21 @@ static void igb_watchdog_task(struct work_struct *work) link = false; } + /* Force link down if we have fiber to swap to */ + if (adapter->flags & IGB_FLAG_MAS_ENABLE) { + if (hw->phy.media_type == e1000_media_type_copper) { + connsw = rd32(E1000_CONNSW); + if (!(connsw & E1000_CONNSW_AUTOSENSE_EN)) + link = 0; + } + } if (link) { + /* Perform a reset if the media type changed. */ + if (hw->dev_spec._82575.media_changed) { + hw->dev_spec._82575.media_changed = false; + adapter->flags |= IGB_FLAG_MEDIA_RESET; + igb_reset(adapter); + } /* Cancel scheduled suspend requests. */ pm_runtime_resume(netdev->dev.parent); @@ -4026,8 +4202,27 @@ static void igb_watchdog_task(struct work_struct *work) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); + /* link is down, time to check for alternate media */ + if (adapter->flags & IGB_FLAG_MAS_ENABLE) { + igb_check_swap_media(adapter); + if (adapter->flags & IGB_FLAG_MEDIA_RESET) { + schedule_work(&adapter->reset_task); + /* return immediately */ + return; + } + } pm_schedule_suspend(netdev->dev.parent, MSEC_PER_SEC * 5); + + /* also check for alternate media here */ + } else if (!netif_carrier_ok(netdev) && + (adapter->flags & IGB_FLAG_MAS_ENABLE)) { + igb_check_swap_media(adapter); + if (adapter->flags & IGB_FLAG_MEDIA_RESET) { + schedule_work(&adapter->reset_task); + /* return immediately */ + return; + } } } diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 8971e2d0a984d74055b788742190f9654fb5ac13..eaaa3ecacfd7d338abd723c0f2826b685feb19f7 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -86,9 +86,7 @@ struct ixgbevf_ring { u64 bp_misses; u64 bp_cleaned; #endif - - u16 head; - u16 tail; + u8 __iomem *tail; u16 reg_idx; /* holds the special value that gets the hardware register * offset associated with this ring, which is different diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 92ef4cb5a8e8e1f3d4de0e457399861ab2d1b8bf..84b55fe71546ef3526d55ee6b4a1c70d7dddd376 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -98,10 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector); static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter); -static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw, - struct ixgbevf_ring *rx_ring, +static inline void ixgbevf_release_rx_desc(struct ixgbevf_ring *rx_ring, u32 val) { + rx_ring->next_to_use = val; + /* * Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only @@ -109,7 +110,7 @@ static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw, * such as IA-64). */ wmb(); - IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rx_ring->reg_idx), val); + writel(val, rx_ring->tail); } /** @@ -406,10 +407,8 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter, } no_buffers: - if (rx_ring->next_to_use != i) { - rx_ring->next_to_use = i; - ixgbevf_release_rx_desc(&adapter->hw, rx_ring, i); - } + if (rx_ring->next_to_use != i) + ixgbevf_release_rx_desc(rx_ring, i); } static inline void ixgbevf_irq_enable_queues(struct ixgbevf_adapter *adapter, @@ -1110,8 +1109,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), tdlen); IXGBE_WRITE_REG(hw, IXGBE_VFTDH(j), 0); IXGBE_WRITE_REG(hw, IXGBE_VFTDT(j), 0); - adapter->tx_ring[i].head = IXGBE_VFTDH(j); - adapter->tx_ring[i].tail = IXGBE_VFTDT(j); + ring->tail = hw->hw_addr + IXGBE_VFTDT(j); + ring->next_to_clean = 0; + ring->next_to_use = 0; /* Disable Tx Head Writeback RO bit, since this hoses * bookkeeping if things aren't delivered in order. */ @@ -1208,20 +1208,22 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter) /* set_rx_buffer_len must be called before ring initialization */ ixgbevf_set_rx_buffer_len(adapter); - rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ for (i = 0; i < adapter->num_rx_queues; i++) { - rdba = adapter->rx_ring[i].dma; - j = adapter->rx_ring[i].reg_idx; + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; + rdba = ring->dma; + j = ring->reg_idx; + rdlen = ring->count * sizeof(union ixgbe_adv_rx_desc); IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(j), (rdba & DMA_BIT_MASK(32))); IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32)); IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), rdlen); IXGBE_WRITE_REG(hw, IXGBE_VFRDH(j), 0); IXGBE_WRITE_REG(hw, IXGBE_VFRDT(j), 0); - adapter->rx_ring[i].head = IXGBE_VFRDH(j); - adapter->rx_ring[i].tail = IXGBE_VFRDT(j); + ring->tail = hw->hw_addr + IXGBE_VFRDT(j); + ring->next_to_clean = 0; + ring->next_to_use = 0; ixgbevf_configure_srrctl(adapter, j); } @@ -1402,7 +1404,7 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, hw_dbg(hw, "RXDCTL.ENABLE queue %d not set while polling\n", rxr); - ixgbevf_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr], + ixgbevf_release_rx_desc(&adapter->rx_ring[rxr], (adapter->rx_ring[rxr].count - 1)); } @@ -1680,14 +1682,6 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter, /* Zero out the descriptor ring */ memset(rx_ring->desc, 0, rx_ring->size); - - rx_ring->next_to_clean = 0; - rx_ring->next_to_use = 0; - - if (rx_ring->head) - writel(0, adapter->hw.hw_addr + rx_ring->head); - if (rx_ring->tail) - writel(0, adapter->hw.hw_addr + rx_ring->tail); } /** @@ -1715,14 +1709,6 @@ static void ixgbevf_clean_tx_ring(struct ixgbevf_adapter *adapter, memset(tx_ring->tx_buffer_info, 0, size); memset(tx_ring->desc, 0, tx_ring->size); - - tx_ring->next_to_use = 0; - tx_ring->next_to_clean = 0; - - if (tx_ring->head) - writel(0, adapter->hw.hw_addr + tx_ring->head); - if (tx_ring->tail) - writel(0, adapter->hw.hw_addr + tx_ring->tail); } /** @@ -2473,8 +2459,6 @@ int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter, if (!tx_ring->desc) goto err; - tx_ring->next_to_use = 0; - tx_ring->next_to_clean = 0; return 0; err: @@ -2542,9 +2526,6 @@ int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter, goto alloc_failed; } - rx_ring->next_to_clean = 0; - rx_ring->next_to_use = 0; - return 0; alloc_failed: return -ENOMEM; @@ -3181,7 +3162,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ixgbevf_tx_map(tx_ring, skb, tx_flags), first, skb->len, hdr_len); - writel(tx_ring->next_to_use, adapter->hw.hw_addr + tx_ring->tail); + writel(tx_ring->next_to_use, tx_ring->tail); ixgbevf_maybe_stop_tx(tx_ring, DESC_NEEDED);