diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igb/igb_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 198 |
1 files changed, 125 insertions, 73 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 70591117051b..2ea012849825 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c | |||
@@ -148,9 +148,9 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
148 | SUPPORTED_100baseT_Full | | 148 | SUPPORTED_100baseT_Full | |
149 | SUPPORTED_1000baseT_Full| | 149 | SUPPORTED_1000baseT_Full| |
150 | SUPPORTED_Autoneg | | 150 | SUPPORTED_Autoneg | |
151 | SUPPORTED_TP); | 151 | SUPPORTED_TP | |
152 | ecmd->advertising = (ADVERTISED_TP | | 152 | SUPPORTED_Pause); |
153 | ADVERTISED_Pause); | 153 | ecmd->advertising = ADVERTISED_TP; |
154 | 154 | ||
155 | if (hw->mac.autoneg == 1) { | 155 | if (hw->mac.autoneg == 1) { |
156 | ecmd->advertising |= ADVERTISED_Autoneg; | 156 | ecmd->advertising |= ADVERTISED_Autoneg; |
@@ -158,6 +158,21 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
158 | ecmd->advertising |= hw->phy.autoneg_advertised; | 158 | ecmd->advertising |= hw->phy.autoneg_advertised; |
159 | } | 159 | } |
160 | 160 | ||
161 | if (hw->mac.autoneg != 1) | ||
162 | ecmd->advertising &= ~(ADVERTISED_Pause | | ||
163 | ADVERTISED_Asym_Pause); | ||
164 | |||
165 | if (hw->fc.requested_mode == e1000_fc_full) | ||
166 | ecmd->advertising |= ADVERTISED_Pause; | ||
167 | else if (hw->fc.requested_mode == e1000_fc_rx_pause) | ||
168 | ecmd->advertising |= (ADVERTISED_Pause | | ||
169 | ADVERTISED_Asym_Pause); | ||
170 | else if (hw->fc.requested_mode == e1000_fc_tx_pause) | ||
171 | ecmd->advertising |= ADVERTISED_Asym_Pause; | ||
172 | else | ||
173 | ecmd->advertising &= ~(ADVERTISED_Pause | | ||
174 | ADVERTISED_Asym_Pause); | ||
175 | |||
161 | ecmd->port = PORT_TP; | 176 | ecmd->port = PORT_TP; |
162 | ecmd->phy_address = hw->phy.addr; | 177 | ecmd->phy_address = hw->phy.addr; |
163 | } else { | 178 | } else { |
@@ -198,6 +213,19 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
198 | } | 213 | } |
199 | 214 | ||
200 | ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; | 215 | ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; |
216 | |||
217 | /* MDI-X => 2; MDI =>1; Invalid =>0 */ | ||
218 | if (hw->phy.media_type == e1000_media_type_copper) | ||
219 | ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : | ||
220 | ETH_TP_MDI; | ||
221 | else | ||
222 | ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; | ||
223 | |||
224 | if (hw->phy.mdix == AUTO_ALL_MODES) | ||
225 | ecmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; | ||
226 | else | ||
227 | ecmd->eth_tp_mdix_ctrl = hw->phy.mdix; | ||
228 | |||
201 | return 0; | 229 | return 0; |
202 | } | 230 | } |
203 | 231 | ||
@@ -214,6 +242,22 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
214 | return -EINVAL; | 242 | return -EINVAL; |
215 | } | 243 | } |
216 | 244 | ||
245 | /* | ||
246 | * MDI setting is only allowed when autoneg enabled because | ||
247 | * some hardware doesn't allow MDI setting when speed or | ||
248 | * duplex is forced. | ||
249 | */ | ||
250 | if (ecmd->eth_tp_mdix_ctrl) { | ||
251 | if (hw->phy.media_type != e1000_media_type_copper) | ||
252 | return -EOPNOTSUPP; | ||
253 | |||
254 | if ((ecmd->eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) && | ||
255 | (ecmd->autoneg != AUTONEG_ENABLE)) { | ||
256 | dev_err(&adapter->pdev->dev, "forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); | ||
257 | return -EINVAL; | ||
258 | } | ||
259 | } | ||
260 | |||
217 | while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) | 261 | while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) |
218 | msleep(1); | 262 | msleep(1); |
219 | 263 | ||
@@ -227,12 +271,25 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
227 | hw->fc.requested_mode = e1000_fc_default; | 271 | hw->fc.requested_mode = e1000_fc_default; |
228 | } else { | 272 | } else { |
229 | u32 speed = ethtool_cmd_speed(ecmd); | 273 | u32 speed = ethtool_cmd_speed(ecmd); |
274 | /* calling this overrides forced MDI setting */ | ||
230 | if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) { | 275 | if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) { |
231 | clear_bit(__IGB_RESETTING, &adapter->state); | 276 | clear_bit(__IGB_RESETTING, &adapter->state); |
232 | return -EINVAL; | 277 | return -EINVAL; |
233 | } | 278 | } |
234 | } | 279 | } |
235 | 280 | ||
281 | /* MDI-X => 2; MDI => 1; Auto => 3 */ | ||
282 | if (ecmd->eth_tp_mdix_ctrl) { | ||
283 | /* | ||
284 | * fix up the value for auto (3 => 0) as zero is mapped | ||
285 | * internally to auto | ||
286 | */ | ||
287 | if (ecmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) | ||
288 | hw->phy.mdix = AUTO_ALL_MODES; | ||
289 | else | ||
290 | hw->phy.mdix = ecmd->eth_tp_mdix_ctrl; | ||
291 | } | ||
292 | |||
236 | /* reset the link */ | 293 | /* reset the link */ |
237 | if (netif_running(adapter->netdev)) { | 294 | if (netif_running(adapter->netdev)) { |
238 | igb_down(adapter); | 295 | igb_down(adapter); |
@@ -1469,33 +1526,22 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) | |||
1469 | { | 1526 | { |
1470 | struct e1000_hw *hw = &adapter->hw; | 1527 | struct e1000_hw *hw = &adapter->hw; |
1471 | u32 ctrl_reg = 0; | 1528 | u32 ctrl_reg = 0; |
1472 | u16 phy_reg = 0; | ||
1473 | 1529 | ||
1474 | hw->mac.autoneg = false; | 1530 | hw->mac.autoneg = false; |
1475 | 1531 | ||
1476 | switch (hw->phy.type) { | 1532 | if (hw->phy.type == e1000_phy_m88) { |
1477 | case e1000_phy_m88: | 1533 | if (hw->phy.id != I210_I_PHY_ID) { |
1478 | /* Auto-MDI/MDIX Off */ | 1534 | /* Auto-MDI/MDIX Off */ |
1479 | igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); | 1535 | igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); |
1480 | /* reset to update Auto-MDI/MDIX */ | 1536 | /* reset to update Auto-MDI/MDIX */ |
1481 | igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); | 1537 | igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); |
1482 | /* autoneg off */ | 1538 | /* autoneg off */ |
1483 | igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); | 1539 | igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); |
1484 | break; | 1540 | } else { |
1485 | case e1000_phy_82580: | 1541 | /* force 1000, set loopback */ |
1486 | /* enable MII loopback */ | 1542 | igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0); |
1487 | igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041); | 1543 | igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); |
1488 | break; | 1544 | } |
1489 | case e1000_phy_i210: | ||
1490 | /* set loopback speed in PHY */ | ||
1491 | igb_read_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), | ||
1492 | &phy_reg); | ||
1493 | phy_reg |= GS40G_MAC_SPEED_1G; | ||
1494 | igb_write_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), | ||
1495 | phy_reg); | ||
1496 | ctrl_reg = rd32(E1000_CTRL_EXT); | ||
1497 | default: | ||
1498 | break; | ||
1499 | } | 1545 | } |
1500 | 1546 | ||
1501 | /* add small delay to avoid loopback test failure */ | 1547 | /* add small delay to avoid loopback test failure */ |
@@ -1513,7 +1559,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) | |||
1513 | E1000_CTRL_FD | /* Force Duplex to FULL */ | 1559 | E1000_CTRL_FD | /* Force Duplex to FULL */ |
1514 | E1000_CTRL_SLU); /* Set link up enable bit */ | 1560 | E1000_CTRL_SLU); /* Set link up enable bit */ |
1515 | 1561 | ||
1516 | if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210)) | 1562 | if (hw->phy.type == e1000_phy_m88) |
1517 | ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ | 1563 | ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ |
1518 | 1564 | ||
1519 | wr32(E1000_CTRL, ctrl_reg); | 1565 | wr32(E1000_CTRL, ctrl_reg); |
@@ -1521,11 +1567,10 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) | |||
1521 | /* Disable the receiver on the PHY so when a cable is plugged in, the | 1567 | /* Disable the receiver on the PHY so when a cable is plugged in, the |
1522 | * PHY does not begin to autoneg when a cable is reconnected to the NIC. | 1568 | * PHY does not begin to autoneg when a cable is reconnected to the NIC. |
1523 | */ | 1569 | */ |
1524 | if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210)) | 1570 | if (hw->phy.type == e1000_phy_m88) |
1525 | igb_phy_disable_receiver(adapter); | 1571 | igb_phy_disable_receiver(adapter); |
1526 | 1572 | ||
1527 | udelay(500); | 1573 | mdelay(500); |
1528 | |||
1529 | return 0; | 1574 | return 0; |
1530 | } | 1575 | } |
1531 | 1576 | ||
@@ -1785,13 +1830,6 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data) | |||
1785 | *data = 0; | 1830 | *data = 0; |
1786 | goto out; | 1831 | goto out; |
1787 | } | 1832 | } |
1788 | if ((adapter->hw.mac.type == e1000_i210) | ||
1789 | || (adapter->hw.mac.type == e1000_i211)) { | ||
1790 | dev_err(&adapter->pdev->dev, | ||
1791 | "Loopback test not supported on this part at this time.\n"); | ||
1792 | *data = 0; | ||
1793 | goto out; | ||
1794 | } | ||
1795 | *data = igb_setup_desc_rings(adapter); | 1833 | *data = igb_setup_desc_rings(adapter); |
1796 | if (*data) | 1834 | if (*data) |
1797 | goto out; | 1835 | goto out; |
@@ -2257,6 +2295,54 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) | |||
2257 | } | 2295 | } |
2258 | } | 2296 | } |
2259 | 2297 | ||
2298 | static int igb_get_ts_info(struct net_device *dev, | ||
2299 | struct ethtool_ts_info *info) | ||
2300 | { | ||
2301 | struct igb_adapter *adapter = netdev_priv(dev); | ||
2302 | |||
2303 | switch (adapter->hw.mac.type) { | ||
2304 | #ifdef CONFIG_IGB_PTP | ||
2305 | case e1000_82576: | ||
2306 | case e1000_82580: | ||
2307 | case e1000_i350: | ||
2308 | case e1000_i210: | ||
2309 | case e1000_i211: | ||
2310 | info->so_timestamping = | ||
2311 | SOF_TIMESTAMPING_TX_HARDWARE | | ||
2312 | SOF_TIMESTAMPING_RX_HARDWARE | | ||
2313 | SOF_TIMESTAMPING_RAW_HARDWARE; | ||
2314 | |||
2315 | if (adapter->ptp_clock) | ||
2316 | info->phc_index = ptp_clock_index(adapter->ptp_clock); | ||
2317 | else | ||
2318 | info->phc_index = -1; | ||
2319 | |||
2320 | info->tx_types = | ||
2321 | (1 << HWTSTAMP_TX_OFF) | | ||
2322 | (1 << HWTSTAMP_TX_ON); | ||
2323 | |||
2324 | info->rx_filters = 1 << HWTSTAMP_FILTER_NONE; | ||
2325 | |||
2326 | /* 82576 does not support timestamping all packets. */ | ||
2327 | if (adapter->hw.mac.type >= e1000_82580) | ||
2328 | info->rx_filters |= 1 << HWTSTAMP_FILTER_ALL; | ||
2329 | else | ||
2330 | info->rx_filters |= | ||
2331 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | | ||
2332 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | | ||
2333 | (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | | ||
2334 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | | ||
2335 | (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | | ||
2336 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | | ||
2337 | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); | ||
2338 | |||
2339 | return 0; | ||
2340 | #endif /* CONFIG_IGB_PTP */ | ||
2341 | default: | ||
2342 | return -EOPNOTSUPP; | ||
2343 | } | ||
2344 | } | ||
2345 | |||
2260 | static int igb_ethtool_begin(struct net_device *netdev) | 2346 | static int igb_ethtool_begin(struct net_device *netdev) |
2261 | { | 2347 | { |
2262 | struct igb_adapter *adapter = netdev_priv(netdev); | 2348 | struct igb_adapter *adapter = netdev_priv(netdev); |
@@ -2270,38 +2356,6 @@ static void igb_ethtool_complete(struct net_device *netdev) | |||
2270 | pm_runtime_put(&adapter->pdev->dev); | 2356 | pm_runtime_put(&adapter->pdev->dev); |
2271 | } | 2357 | } |
2272 | 2358 | ||
2273 | #ifdef CONFIG_IGB_PTP | ||
2274 | static int igb_ethtool_get_ts_info(struct net_device *dev, | ||
2275 | struct ethtool_ts_info *info) | ||
2276 | { | ||
2277 | struct igb_adapter *adapter = netdev_priv(dev); | ||
2278 | |||
2279 | info->so_timestamping = | ||
2280 | SOF_TIMESTAMPING_TX_HARDWARE | | ||
2281 | SOF_TIMESTAMPING_RX_HARDWARE | | ||
2282 | SOF_TIMESTAMPING_RAW_HARDWARE; | ||
2283 | |||
2284 | if (adapter->ptp_clock) | ||
2285 | info->phc_index = ptp_clock_index(adapter->ptp_clock); | ||
2286 | else | ||
2287 | info->phc_index = -1; | ||
2288 | |||
2289 | info->tx_types = | ||
2290 | (1 << HWTSTAMP_TX_OFF) | | ||
2291 | (1 << HWTSTAMP_TX_ON); | ||
2292 | |||
2293 | info->rx_filters = | ||
2294 | (1 << HWTSTAMP_FILTER_NONE) | | ||
2295 | (1 << HWTSTAMP_FILTER_ALL) | | ||
2296 | (1 << HWTSTAMP_FILTER_SOME) | | ||
2297 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | | ||
2298 | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | | ||
2299 | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); | ||
2300 | |||
2301 | return 0; | ||
2302 | } | ||
2303 | |||
2304 | #endif | ||
2305 | static const struct ethtool_ops igb_ethtool_ops = { | 2359 | static const struct ethtool_ops igb_ethtool_ops = { |
2306 | .get_settings = igb_get_settings, | 2360 | .get_settings = igb_get_settings, |
2307 | .set_settings = igb_set_settings, | 2361 | .set_settings = igb_set_settings, |
@@ -2328,11 +2382,9 @@ static const struct ethtool_ops igb_ethtool_ops = { | |||
2328 | .get_ethtool_stats = igb_get_ethtool_stats, | 2382 | .get_ethtool_stats = igb_get_ethtool_stats, |
2329 | .get_coalesce = igb_get_coalesce, | 2383 | .get_coalesce = igb_get_coalesce, |
2330 | .set_coalesce = igb_set_coalesce, | 2384 | .set_coalesce = igb_set_coalesce, |
2385 | .get_ts_info = igb_get_ts_info, | ||
2331 | .begin = igb_ethtool_begin, | 2386 | .begin = igb_ethtool_begin, |
2332 | .complete = igb_ethtool_complete, | 2387 | .complete = igb_ethtool_complete, |
2333 | #ifdef CONFIG_IGB_PTP | ||
2334 | .get_ts_info = igb_ethtool_get_ts_info, | ||
2335 | #endif | ||
2336 | }; | 2388 | }; |
2337 | 2389 | ||
2338 | void igb_set_ethtool_ops(struct net_device *netdev) | 2390 | void igb_set_ethtool_ops(struct net_device *netdev) |