diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-12-13 00:50:46 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-13 00:58:17 -0500 |
commit | 04cc8cacb01c09fba2297faf1477cd570ba43f0b (patch) | |
tree | f17dbd584b072d14f1500c6f6d659be993ae35c7 /drivers/net/sfc | |
parent | 177dfcd80f28f8fbc3e22c2d8b24d21cb86f1d97 (diff) |
sfc: Implement auto-negotiation
Add infrastructure for auto-negotiation of speed, duplex and flow
control.
When using 10Xpress, auto-negotiate flow control. While we're
at it, clean up the code to warn when partner is not 10GBASE-T
capable.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r-- | drivers/net/sfc/ethtool.c | 57 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 6 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_gmac.c | 4 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 2 | ||||
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 348 | ||||
-rw-r--r-- | drivers/net/sfc/mdio_10g.h | 32 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 38 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 138 | ||||
-rw-r--r-- | drivers/net/sfc/xfp_phy.c | 1 |
9 files changed, 472 insertions, 154 deletions
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 1b33f89df4d5..0e81af6d8348 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -12,11 +12,13 @@ | |||
12 | #include <linux/ethtool.h> | 12 | #include <linux/ethtool.h> |
13 | #include <linux/rtnetlink.h> | 13 | #include <linux/rtnetlink.h> |
14 | #include "net_driver.h" | 14 | #include "net_driver.h" |
15 | #include "workarounds.h" | ||
15 | #include "selftest.h" | 16 | #include "selftest.h" |
16 | #include "efx.h" | 17 | #include "efx.h" |
17 | #include "ethtool.h" | 18 | #include "ethtool.h" |
18 | #include "falcon.h" | 19 | #include "falcon.h" |
19 | #include "spi.h" | 20 | #include "spi.h" |
21 | #include "mdio_10g.h" | ||
20 | 22 | ||
21 | const char *efx_loopback_mode_names[] = { | 23 | const char *efx_loopback_mode_names[] = { |
22 | [LOOPBACK_NONE] = "NONE", | 24 | [LOOPBACK_NONE] = "NONE", |
@@ -674,14 +676,51 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, | |||
674 | struct ethtool_pauseparam *pause) | 676 | struct ethtool_pauseparam *pause) |
675 | { | 677 | { |
676 | struct efx_nic *efx = netdev_priv(net_dev); | 678 | struct efx_nic *efx = netdev_priv(net_dev); |
677 | enum efx_fc_type flow_control = efx->flow_control; | 679 | enum efx_fc_type wanted_fc; |
680 | bool reset; | ||
678 | 681 | ||
679 | flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO); | 682 | wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | |
680 | flow_control |= pause->rx_pause ? EFX_FC_RX : 0; | 683 | (pause->tx_pause ? EFX_FC_TX : 0) | |
681 | flow_control |= pause->tx_pause ? EFX_FC_TX : 0; | 684 | (pause->autoneg ? EFX_FC_AUTO : 0)); |
682 | flow_control |= pause->autoneg ? EFX_FC_AUTO : 0; | 685 | |
686 | if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { | ||
687 | EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); | ||
688 | return -EINVAL; | ||
689 | } | ||
690 | |||
691 | if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) && | ||
692 | (wanted_fc & EFX_FC_AUTO)) { | ||
693 | EFX_LOG(efx, "PHY does not support flow control " | ||
694 | "autonegotiation\n"); | ||
695 | return -EINVAL; | ||
696 | } | ||
697 | |||
698 | /* TX flow control may automatically turn itself off if the | ||
699 | * link partner (intermittently) stops responding to pause | ||
700 | * frames. There isn't any indication that this has happened, | ||
701 | * so the best we do is leave it up to the user to spot this | ||
702 | * and fix it be cycling transmit flow control on this end. */ | ||
703 | reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); | ||
704 | if (EFX_WORKAROUND_11482(efx) && reset) { | ||
705 | if (falcon_rev(efx) >= FALCON_REV_B0) { | ||
706 | /* Recover by resetting the EM block */ | ||
707 | if (efx->link_up) | ||
708 | falcon_drain_tx_fifo(efx); | ||
709 | } else { | ||
710 | /* Schedule a reset to recover */ | ||
711 | efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); | ||
712 | } | ||
713 | } | ||
714 | |||
715 | /* Try to push the pause parameters */ | ||
716 | mutex_lock(&efx->mac_lock); | ||
717 | |||
718 | efx->wanted_fc = wanted_fc; | ||
719 | mdio_clause45_set_pause(efx); | ||
720 | __efx_reconfigure_port(efx); | ||
721 | |||
722 | mutex_unlock(&efx->mac_lock); | ||
683 | 723 | ||
684 | efx_reconfigure_port(efx); | ||
685 | return 0; | 724 | return 0; |
686 | } | 725 | } |
687 | 726 | ||
@@ -690,9 +729,9 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, | |||
690 | { | 729 | { |
691 | struct efx_nic *efx = netdev_priv(net_dev); | 730 | struct efx_nic *efx = netdev_priv(net_dev); |
692 | 731 | ||
693 | pause->rx_pause = !!(efx->flow_control & EFX_FC_RX); | 732 | pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX); |
694 | pause->tx_pause = !!(efx->flow_control & EFX_FC_TX); | 733 | pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX); |
695 | pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO); | 734 | pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); |
696 | } | 735 | } |
697 | 736 | ||
698 | 737 | ||
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index f09eded40fba..fde4e7912c39 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -1998,7 +1998,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) | |||
1998 | /* Transmission of pause frames when RX crosses the threshold is | 1998 | /* Transmission of pause frames when RX crosses the threshold is |
1999 | * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. | 1999 | * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. |
2000 | * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ | 2000 | * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ |
2001 | tx_fc = !!(efx->flow_control & EFX_FC_TX); | 2001 | tx_fc = !!(efx->link_fc & EFX_FC_TX); |
2002 | falcon_read(efx, ®, RX_CFG_REG_KER); | 2002 | falcon_read(efx, ®, RX_CFG_REG_KER); |
2003 | EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); | 2003 | EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); |
2004 | 2004 | ||
@@ -2328,9 +2328,9 @@ int falcon_probe_port(struct efx_nic *efx) | |||
2328 | 2328 | ||
2329 | /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ | 2329 | /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ |
2330 | if (falcon_rev(efx) >= FALCON_REV_B0) | 2330 | if (falcon_rev(efx) >= FALCON_REV_B0) |
2331 | efx->flow_control = EFX_FC_RX | EFX_FC_TX; | 2331 | efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; |
2332 | else | 2332 | else |
2333 | efx->flow_control = EFX_FC_RX; | 2333 | efx->wanted_fc = EFX_FC_RX; |
2334 | 2334 | ||
2335 | /* Allocate buffer for stats */ | 2335 | /* Allocate buffer for stats */ |
2336 | rc = falcon_alloc_buffer(efx, &efx->stats_buffer, | 2336 | rc = falcon_alloc_buffer(efx, &efx->stats_buffer, |
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c index 247f8025ef00..b6e6eb963905 100644 --- a/drivers/net/sfc/falcon_gmac.c +++ b/drivers/net/sfc/falcon_gmac.c | |||
@@ -31,8 +31,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx) | |||
31 | efx_oword_t reg; | 31 | efx_oword_t reg; |
32 | 32 | ||
33 | /* Configuration register 1 */ | 33 | /* Configuration register 1 */ |
34 | tx_fc = (efx->flow_control & EFX_FC_TX) || !efx->link_fd; | 34 | tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd; |
35 | rx_fc = !!(efx->flow_control & EFX_FC_RX); | 35 | rx_fc = !!(efx->link_fc & EFX_FC_RX); |
36 | loopback = (efx->loopback_mode == LOOPBACK_GMAC); | 36 | loopback = (efx->loopback_mode == LOOPBACK_GMAC); |
37 | bytemode = (efx->link_speed == 1000); | 37 | bytemode = (efx->link_speed == 1000); |
38 | 38 | ||
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 2206eada3463..0ce8f015386c 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c | |||
@@ -142,7 +142,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) | |||
142 | { | 142 | { |
143 | unsigned int max_frame_len; | 143 | unsigned int max_frame_len; |
144 | efx_oword_t reg; | 144 | efx_oword_t reg; |
145 | bool rx_fc = !!(efx->flow_control & EFX_FC_RX); | 145 | bool rx_fc = !!(efx->link_fc & EFX_FC_RX); |
146 | 146 | ||
147 | /* Configure MAC - cut-thru mode is hard wired on */ | 147 | /* Configure MAC - cut-thru mode is hard wired on */ |
148 | EFX_POPULATE_DWORD_3(reg, | 148 | EFX_POPULATE_DWORD_3(reg, |
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 8d91131aa5ab..037601e0b9d7 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c | |||
@@ -47,13 +47,16 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, | |||
47 | if (LOOPBACK_INTERNAL(efx)) | 47 | if (LOOPBACK_INTERNAL(efx)) |
48 | return 0; | 48 | return 0; |
49 | 49 | ||
50 | /* Read MMD STATUS2 to check it is responding. */ | 50 | if (mmd != MDIO_MMD_AN) { |
51 | status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2); | 51 | /* Read MMD STATUS2 to check it is responding. */ |
52 | if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & | 52 | status = mdio_clause45_read(efx, phy_id, mmd, |
53 | ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != | 53 | MDIO_MMDREG_STAT2); |
54 | MDIO_MMDREG_STAT2_PRESENT_VAL) { | 54 | if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & |
55 | EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); | 55 | ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != |
56 | return -EIO; | 56 | MDIO_MMDREG_STAT2_PRESENT_VAL) { |
57 | EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); | ||
58 | return -EIO; | ||
59 | } | ||
57 | } | 60 | } |
58 | 61 | ||
59 | /* Read MMD STATUS 1 to check for fault. */ | 62 | /* Read MMD STATUS 1 to check for fault. */ |
@@ -179,12 +182,15 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) | |||
179 | else if (efx->loopback_mode == LOOPBACK_PHYXS) | 182 | else if (efx->loopback_mode == LOOPBACK_PHYXS) |
180 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | | 183 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | |
181 | MDIO_MMDREG_DEVS_PCS | | 184 | MDIO_MMDREG_DEVS_PCS | |
182 | MDIO_MMDREG_DEVS_PMAPMD); | 185 | MDIO_MMDREG_DEVS_PMAPMD | |
186 | MDIO_MMDREG_DEVS_AN); | ||
183 | else if (efx->loopback_mode == LOOPBACK_PCS) | 187 | else if (efx->loopback_mode == LOOPBACK_PCS) |
184 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | | 188 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | |
185 | MDIO_MMDREG_DEVS_PMAPMD); | 189 | MDIO_MMDREG_DEVS_PMAPMD | |
190 | MDIO_MMDREG_DEVS_AN); | ||
186 | else if (efx->loopback_mode == LOOPBACK_PMAPMD) | 191 | else if (efx->loopback_mode == LOOPBACK_PMAPMD) |
187 | mmd_mask &= ~MDIO_MMDREG_DEVS_PMAPMD; | 192 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | |
193 | MDIO_MMDREG_DEVS_AN); | ||
188 | 194 | ||
189 | while (mmd_mask) { | 195 | while (mmd_mask) { |
190 | if (mmd_mask & 1) { | 196 | if (mmd_mask & 1) { |
@@ -244,6 +250,7 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |||
244 | int low_power, unsigned int mmd_mask) | 250 | int low_power, unsigned int mmd_mask) |
245 | { | 251 | { |
246 | int mmd = 0; | 252 | int mmd = 0; |
253 | mmd_mask &= ~MDIO_MMDREG_DEVS_AN; | ||
247 | while (mmd_mask) { | 254 | while (mmd_mask) { |
248 | if (mmd_mask & 1) | 255 | if (mmd_mask & 1) |
249 | mdio_clause45_set_mmd_lpower(efx, low_power, mmd); | 256 | mdio_clause45_set_mmd_lpower(efx, low_power, mmd); |
@@ -252,103 +259,302 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |||
252 | } | 259 | } |
253 | } | 260 | } |
254 | 261 | ||
262 | static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) | ||
263 | { | ||
264 | int phy_id = efx->mii.phy_id; | ||
265 | u32 result = 0; | ||
266 | int reg; | ||
267 | |||
268 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); | ||
269 | if (reg & ADVERTISE_10HALF) | ||
270 | result |= ADVERTISED_10baseT_Half; | ||
271 | if (reg & ADVERTISE_10FULL) | ||
272 | result |= ADVERTISED_10baseT_Full; | ||
273 | if (reg & ADVERTISE_100HALF) | ||
274 | result |= ADVERTISED_100baseT_Half; | ||
275 | if (reg & ADVERTISE_100FULL) | ||
276 | result |= ADVERTISED_100baseT_Full; | ||
277 | if (reg & LPA_RESV) | ||
278 | result |= xnp; | ||
279 | |||
280 | return result; | ||
281 | } | ||
282 | |||
255 | /** | 283 | /** |
256 | * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. | 284 | * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. |
257 | * @efx: Efx NIC | 285 | * @efx: Efx NIC |
258 | * @ecmd: Buffer for settings | 286 | * @ecmd: Buffer for settings |
259 | * | 287 | * |
260 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of | 288 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of |
261 | * ecmd have been filled out based on the PMA type. | 289 | * ecmd have been filled out. |
262 | */ | 290 | */ |
263 | void mdio_clause45_get_settings(struct efx_nic *efx, | 291 | void mdio_clause45_get_settings(struct efx_nic *efx, |
264 | struct ethtool_cmd *ecmd) | 292 | struct ethtool_cmd *ecmd) |
265 | { | 293 | { |
266 | int pma_type; | 294 | mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); |
295 | } | ||
267 | 296 | ||
268 | /* If no PMA is present we are presumably talking something XAUI-ish | 297 | /** |
269 | * like CX4. Which we report as FIBRE (see below) */ | 298 | * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. |
270 | if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) { | 299 | * @efx: Efx NIC |
271 | ecmd->speed = SPEED_10000; | 300 | * @ecmd: Buffer for settings |
272 | ecmd->port = PORT_FIBRE; | 301 | * @xnp: Advertised Extended Next Page state |
273 | ecmd->supported = SUPPORTED_FIBRE; | 302 | * @xnp_lpa: Link Partner's advertised XNP state |
274 | ecmd->advertising = ADVERTISED_FIBRE; | 303 | * |
275 | return; | 304 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of |
276 | } | 305 | * ecmd have been filled out. |
306 | */ | ||
307 | void mdio_clause45_get_settings_ext(struct efx_nic *efx, | ||
308 | struct ethtool_cmd *ecmd, | ||
309 | u32 xnp, u32 xnp_lpa) | ||
310 | { | ||
311 | int phy_id = efx->mii.phy_id; | ||
312 | int reg; | ||
277 | 313 | ||
278 | pma_type = mdio_clause45_read(efx, efx->mii.phy_id, | 314 | ecmd->transceiver = XCVR_INTERNAL; |
279 | MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2); | 315 | ecmd->phy_address = phy_id; |
280 | pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK; | ||
281 | 316 | ||
282 | switch (pma_type) { | 317 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
283 | /* We represent CX4 as fibre in the absence of anything | 318 | MDIO_MMDREG_CTRL2); |
284 | better. */ | 319 | switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { |
285 | case MDIO_PMAPMD_CTRL2_10G_CX4: | ||
286 | ecmd->speed = SPEED_10000; | ||
287 | ecmd->port = PORT_FIBRE; | ||
288 | ecmd->supported = SUPPORTED_FIBRE; | ||
289 | ecmd->advertising = ADVERTISED_FIBRE; | ||
290 | break; | ||
291 | /* 10G Base-T */ | ||
292 | case MDIO_PMAPMD_CTRL2_10G_BT: | 320 | case MDIO_PMAPMD_CTRL2_10G_BT: |
293 | ecmd->speed = SPEED_10000; | ||
294 | ecmd->port = PORT_TP; | ||
295 | ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full; | ||
296 | ecmd->advertising = (ADVERTISED_FIBRE | ||
297 | | ADVERTISED_10000baseT_Full); | ||
298 | break; | ||
299 | case MDIO_PMAPMD_CTRL2_1G_BT: | 321 | case MDIO_PMAPMD_CTRL2_1G_BT: |
300 | ecmd->speed = SPEED_1000; | ||
301 | ecmd->port = PORT_TP; | ||
302 | ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full; | ||
303 | ecmd->advertising = (ADVERTISED_FIBRE | ||
304 | | ADVERTISED_1000baseT_Full); | ||
305 | break; | ||
306 | case MDIO_PMAPMD_CTRL2_100_BT: | 322 | case MDIO_PMAPMD_CTRL2_100_BT: |
307 | ecmd->speed = SPEED_100; | ||
308 | ecmd->port = PORT_TP; | ||
309 | ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full; | ||
310 | ecmd->advertising = (ADVERTISED_FIBRE | ||
311 | | ADVERTISED_100baseT_Full); | ||
312 | break; | ||
313 | case MDIO_PMAPMD_CTRL2_10_BT: | 323 | case MDIO_PMAPMD_CTRL2_10_BT: |
314 | ecmd->speed = SPEED_10; | ||
315 | ecmd->port = PORT_TP; | 324 | ecmd->port = PORT_TP; |
316 | ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full; | 325 | ecmd->supported = SUPPORTED_TP; |
317 | ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full; | 326 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
327 | MDIO_MMDREG_SPEED); | ||
328 | if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) | ||
329 | ecmd->supported |= SUPPORTED_10000baseT_Full; | ||
330 | if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) | ||
331 | ecmd->supported |= (SUPPORTED_1000baseT_Full | | ||
332 | SUPPORTED_1000baseT_Half); | ||
333 | if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) | ||
334 | ecmd->supported |= (SUPPORTED_100baseT_Full | | ||
335 | SUPPORTED_100baseT_Half); | ||
336 | if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) | ||
337 | ecmd->supported |= (SUPPORTED_10baseT_Full | | ||
338 | SUPPORTED_10baseT_Half); | ||
339 | ecmd->advertising = ADVERTISED_TP; | ||
318 | break; | 340 | break; |
319 | /* All the other defined modes are flavours of | 341 | |
320 | * 10G optical */ | 342 | /* We represent CX4 as fibre in the absence of anything better */ |
343 | case MDIO_PMAPMD_CTRL2_10G_CX4: | ||
344 | /* All the other defined modes are flavours of optical */ | ||
321 | default: | 345 | default: |
322 | ecmd->speed = SPEED_10000; | ||
323 | ecmd->port = PORT_FIBRE; | 346 | ecmd->port = PORT_FIBRE; |
324 | ecmd->supported = SUPPORTED_FIBRE; | 347 | ecmd->supported = SUPPORTED_FIBRE; |
325 | ecmd->advertising = ADVERTISED_FIBRE; | 348 | ecmd->advertising = ADVERTISED_FIBRE; |
326 | break; | 349 | break; |
327 | } | 350 | } |
351 | |||
352 | if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { | ||
353 | ecmd->supported |= SUPPORTED_Autoneg; | ||
354 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
355 | MDIO_MMDREG_CTRL1); | ||
356 | if (reg & BMCR_ANENABLE) { | ||
357 | ecmd->autoneg = AUTONEG_ENABLE; | ||
358 | ecmd->advertising |= | ||
359 | ADVERTISED_Autoneg | | ||
360 | mdio_clause45_get_an(efx, | ||
361 | MDIO_AN_ADVERTISE, xnp); | ||
362 | } else | ||
363 | ecmd->autoneg = AUTONEG_DISABLE; | ||
364 | } else | ||
365 | ecmd->autoneg = AUTONEG_DISABLE; | ||
366 | |||
367 | /* If AN is enabled and complete, report best common mode */ | ||
368 | if (ecmd->autoneg && | ||
369 | (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_MMDREG_STAT1) & | ||
370 | (1 << MDIO_AN_STATUS_AN_DONE_LBN))) { | ||
371 | u32 common, lpa; | ||
372 | lpa = mdio_clause45_get_an(efx, MDIO_AN_LPA, xnp_lpa); | ||
373 | common = ecmd->advertising & lpa; | ||
374 | if (common & ADVERTISED_10000baseT_Full) { | ||
375 | ecmd->speed = SPEED_10000; | ||
376 | ecmd->duplex = DUPLEX_FULL; | ||
377 | } else if (common & (ADVERTISED_1000baseT_Full | | ||
378 | ADVERTISED_1000baseT_Half)) { | ||
379 | ecmd->speed = SPEED_1000; | ||
380 | ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); | ||
381 | } else if (common & (ADVERTISED_100baseT_Full | | ||
382 | ADVERTISED_100baseT_Half)) { | ||
383 | ecmd->speed = SPEED_100; | ||
384 | ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); | ||
385 | } else { | ||
386 | ecmd->speed = SPEED_10; | ||
387 | ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); | ||
388 | } | ||
389 | } else { | ||
390 | /* Report forced settings */ | ||
391 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | ||
392 | MDIO_MMDREG_CTRL1); | ||
393 | ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * | ||
394 | ((reg & BMCR_SPEED100) ? 100 : 10)); | ||
395 | ecmd->duplex = (reg & BMCR_FULLDPLX || | ||
396 | ecmd->speed == SPEED_10000); | ||
397 | } | ||
328 | } | 398 | } |
329 | 399 | ||
330 | /** | 400 | /** |
331 | * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. | 401 | * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. |
332 | * @efx: Efx NIC | 402 | * @efx: Efx NIC |
333 | * @ecmd: New settings | 403 | * @ecmd: New settings |
334 | * | ||
335 | * Currently this just enforces that we are _not_ changing the | ||
336 | * 'port', 'speed', 'supported' or 'advertising' settings as these | ||
337 | * cannot be changed on any currently supported PHY. | ||
338 | */ | 404 | */ |
339 | int mdio_clause45_set_settings(struct efx_nic *efx, | 405 | int mdio_clause45_set_settings(struct efx_nic *efx, |
340 | struct ethtool_cmd *ecmd) | 406 | struct ethtool_cmd *ecmd) |
341 | { | 407 | { |
342 | struct ethtool_cmd tmpcmd; | 408 | int phy_id = efx->mii.phy_id; |
343 | mdio_clause45_get_settings(efx, &tmpcmd); | 409 | struct ethtool_cmd prev; |
344 | /* None of the current PHYs support more than one mode | 410 | u32 required; |
345 | * of operation (and only 10GBT ever will), so keep things | 411 | int ctrl1_bits, reg; |
346 | * simple for now */ | 412 | |
347 | if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) && | 413 | efx->phy_op->get_settings(efx, &prev); |
348 | (ecmd->supported == tmpcmd.supported) && | 414 | |
349 | (ecmd->advertising == tmpcmd.advertising)) | 415 | if (ecmd->advertising == prev.advertising && |
416 | ecmd->speed == prev.speed && | ||
417 | ecmd->duplex == prev.duplex && | ||
418 | ecmd->port == prev.port && | ||
419 | ecmd->autoneg == prev.autoneg) | ||
350 | return 0; | 420 | return 0; |
351 | return -EOPNOTSUPP; | 421 | |
422 | /* We can only change these settings for -T PHYs */ | ||
423 | if (prev.port != PORT_TP || ecmd->port != PORT_TP) | ||
424 | return -EINVAL; | ||
425 | |||
426 | /* Check that PHY supports these settings and work out the | ||
427 | * basic control bits */ | ||
428 | if (ecmd->duplex) { | ||
429 | switch (ecmd->speed) { | ||
430 | case SPEED_10: | ||
431 | ctrl1_bits = BMCR_FULLDPLX; | ||
432 | required = SUPPORTED_10baseT_Full; | ||
433 | break; | ||
434 | case SPEED_100: | ||
435 | ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; | ||
436 | required = SUPPORTED_100baseT_Full; | ||
437 | break; | ||
438 | case SPEED_1000: | ||
439 | ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; | ||
440 | required = SUPPORTED_1000baseT_Full; | ||
441 | break; | ||
442 | case SPEED_10000: | ||
443 | ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | | ||
444 | BMCR_FULLDPLX); | ||
445 | required = SUPPORTED_10000baseT_Full; | ||
446 | break; | ||
447 | default: | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | } else { | ||
451 | switch (ecmd->speed) { | ||
452 | case SPEED_10: | ||
453 | ctrl1_bits = 0; | ||
454 | required = SUPPORTED_10baseT_Half; | ||
455 | break; | ||
456 | case SPEED_100: | ||
457 | ctrl1_bits = BMCR_SPEED100; | ||
458 | required = SUPPORTED_100baseT_Half; | ||
459 | break; | ||
460 | case SPEED_1000: | ||
461 | ctrl1_bits = BMCR_SPEED1000; | ||
462 | required = SUPPORTED_1000baseT_Half; | ||
463 | break; | ||
464 | default: | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | } | ||
468 | if (ecmd->autoneg) | ||
469 | required |= SUPPORTED_Autoneg; | ||
470 | required |= ecmd->advertising; | ||
471 | if (required & ~prev.supported) | ||
472 | return -EINVAL; | ||
473 | |||
474 | /* Set the basic control bits */ | ||
475 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | ||
476 | MDIO_MMDREG_CTRL1); | ||
477 | reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); | ||
478 | reg |= ctrl1_bits; | ||
479 | mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, | ||
480 | reg); | ||
481 | |||
482 | /* Set the AN registers */ | ||
483 | if (ecmd->autoneg != prev.autoneg || | ||
484 | ecmd->advertising != prev.advertising) { | ||
485 | bool xnp = false; | ||
486 | |||
487 | if (efx->phy_op->set_xnp_advertise) | ||
488 | xnp = efx->phy_op->set_xnp_advertise(efx, | ||
489 | ecmd->advertising); | ||
490 | |||
491 | if (ecmd->autoneg) { | ||
492 | reg = 0; | ||
493 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | ||
494 | reg |= ADVERTISE_10HALF; | ||
495 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | ||
496 | reg |= ADVERTISE_10FULL; | ||
497 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | ||
498 | reg |= ADVERTISE_100HALF; | ||
499 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | ||
500 | reg |= ADVERTISE_100FULL; | ||
501 | if (xnp) | ||
502 | reg |= ADVERTISE_RESV; | ||
503 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
504 | MDIO_AN_ADVERTISE, reg); | ||
505 | } | ||
506 | |||
507 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
508 | MDIO_MMDREG_CTRL1); | ||
509 | if (ecmd->autoneg) | ||
510 | reg |= BMCR_ANENABLE | BMCR_ANRESTART; | ||
511 | else | ||
512 | reg &= ~BMCR_ANENABLE; | ||
513 | if (xnp) | ||
514 | reg |= 1 << MDIO_AN_CTRL_XNP_LBN; | ||
515 | else | ||
516 | reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); | ||
517 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
518 | MDIO_MMDREG_CTRL1, reg); | ||
519 | } | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | void mdio_clause45_set_pause(struct efx_nic *efx) | ||
525 | { | ||
526 | int phy_id = efx->mii.phy_id; | ||
527 | int reg; | ||
528 | |||
529 | if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { | ||
530 | /* Set pause capability advertising */ | ||
531 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
532 | MDIO_AN_ADVERTISE); | ||
533 | reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); | ||
534 | reg |= efx_fc_advertise(efx->wanted_fc); | ||
535 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
536 | MDIO_AN_ADVERTISE, reg); | ||
537 | |||
538 | /* Restart auto-negotiation */ | ||
539 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
540 | MDIO_MMDREG_CTRL1); | ||
541 | if (reg & BMCR_ANENABLE) { | ||
542 | reg |= BMCR_ANRESTART; | ||
543 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | ||
544 | MDIO_MMDREG_CTRL1, reg); | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | |||
549 | enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) | ||
550 | { | ||
551 | int phy_id = efx->mii.phy_id; | ||
552 | int lpa; | ||
553 | |||
554 | if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) | ||
555 | return efx->wanted_fc; | ||
556 | lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); | ||
557 | return efx_fc_resolve(efx->wanted_fc, lpa); | ||
352 | } | 558 | } |
353 | 559 | ||
354 | void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, | 560 | void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, |
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 4830e0c1da0b..80c63dde8864 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h | |||
@@ -81,6 +81,17 @@ | |||
81 | #define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) | 81 | #define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) |
82 | #define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) | 82 | #define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) |
83 | #define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) | 83 | #define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) |
84 | #define MDIO_MMDREG_DEVS_AN DEV_PRESENT_BIT(MDIO_MMD_AN) | ||
85 | |||
86 | /* Bits in MMDREG_SPEED */ | ||
87 | #define MDIO_MMDREG_SPEED_10G_LBN 0 | ||
88 | #define MDIO_MMDREG_SPEED_10G_WIDTH 1 | ||
89 | #define MDIO_MMDREG_SPEED_1000M_LBN 4 | ||
90 | #define MDIO_MMDREG_SPEED_1000M_WIDTH 1 | ||
91 | #define MDIO_MMDREG_SPEED_100M_LBN 5 | ||
92 | #define MDIO_MMDREG_SPEED_100M_WIDTH 1 | ||
93 | #define MDIO_MMDREG_SPEED_10M_LBN 6 | ||
94 | #define MDIO_MMDREG_SPEED_10M_WIDTH 1 | ||
84 | 95 | ||
85 | /* Bits in MMDREG_STAT2 */ | 96 | /* Bits in MMDREG_STAT2 */ |
86 | #define MDIO_MMDREG_STAT2_PRESENT_VAL (2) | 97 | #define MDIO_MMDREG_STAT2_PRESENT_VAL (2) |
@@ -119,12 +130,20 @@ | |||
119 | #define MDIO_PHYXS_LANE_ALIGNED_LBN (12) | 130 | #define MDIO_PHYXS_LANE_ALIGNED_LBN (12) |
120 | 131 | ||
121 | /* AN registers */ | 132 | /* AN registers */ |
133 | #define MDIO_AN_CTRL_XNP_LBN 13 | ||
122 | #define MDIO_AN_STATUS (1) | 134 | #define MDIO_AN_STATUS (1) |
123 | #define MDIO_AN_STATUS_XNP_LBN (7) | 135 | #define MDIO_AN_STATUS_XNP_LBN (7) |
124 | #define MDIO_AN_STATUS_PAGE_LBN (6) | 136 | #define MDIO_AN_STATUS_PAGE_LBN (6) |
125 | #define MDIO_AN_STATUS_AN_DONE_LBN (5) | 137 | #define MDIO_AN_STATUS_AN_DONE_LBN (5) |
126 | #define MDIO_AN_STATUS_LP_AN_CAP_LBN (0) | 138 | #define MDIO_AN_STATUS_LP_AN_CAP_LBN (0) |
127 | 139 | ||
140 | #define MDIO_AN_ADVERTISE 16 | ||
141 | #define MDIO_AN_ADVERTISE_XNP_LBN 12 | ||
142 | #define MDIO_AN_LPA 19 | ||
143 | #define MDIO_AN_XNP 22 | ||
144 | #define MDIO_AN_LPA_XNP 25 | ||
145 | |||
146 | #define MDIO_AN_10GBT_ADVERTISE 32 | ||
128 | #define MDIO_AN_10GBT_STATUS (33) | 147 | #define MDIO_AN_10GBT_STATUS (33) |
129 | #define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ | 148 | #define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ |
130 | #define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ | 149 | #define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ |
@@ -251,10 +270,23 @@ extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |||
251 | extern void mdio_clause45_get_settings(struct efx_nic *efx, | 270 | extern void mdio_clause45_get_settings(struct efx_nic *efx, |
252 | struct ethtool_cmd *ecmd); | 271 | struct ethtool_cmd *ecmd); |
253 | 272 | ||
273 | /* Read (some of) the PHY settings over MDIO */ | ||
274 | extern void | ||
275 | mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd, | ||
276 | u32 xnp, u32 xnp_lpa); | ||
277 | |||
254 | /* Set (some of) the PHY settings over MDIO */ | 278 | /* Set (some of) the PHY settings over MDIO */ |
255 | extern int mdio_clause45_set_settings(struct efx_nic *efx, | 279 | extern int mdio_clause45_set_settings(struct efx_nic *efx, |
256 | struct ethtool_cmd *ecmd); | 280 | struct ethtool_cmd *ecmd); |
257 | 281 | ||
282 | /* Set pause parameters to be advertised through AN (if available) */ | ||
283 | extern void mdio_clause45_set_pause(struct efx_nic *efx); | ||
284 | |||
285 | /* Get pause parameters from AN if available (otherwise return | ||
286 | * requested pause parameters) | ||
287 | */ | ||
288 | enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx); | ||
289 | |||
258 | /* Wait for specified MMDs to exit reset within a timeout */ | 290 | /* Wait for specified MMDs to exit reset within a timeout */ |
259 | extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, | 291 | extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, |
260 | unsigned int mmd_mask); | 292 | unsigned int mmd_mask); |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 883086e39455..fb8d72527a34 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -511,6 +511,35 @@ enum efx_mac_type { | |||
511 | EFX_XMAC = 2, | 511 | EFX_XMAC = 2, |
512 | }; | 512 | }; |
513 | 513 | ||
514 | static inline unsigned int efx_fc_advertise(enum efx_fc_type wanted_fc) | ||
515 | { | ||
516 | unsigned int adv = 0; | ||
517 | if (wanted_fc & EFX_FC_RX) | ||
518 | adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | ||
519 | if (wanted_fc & EFX_FC_TX) | ||
520 | adv ^= ADVERTISE_PAUSE_ASYM; | ||
521 | return adv; | ||
522 | } | ||
523 | |||
524 | static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, | ||
525 | unsigned int lpa) | ||
526 | { | ||
527 | unsigned int adv = efx_fc_advertise(wanted_fc); | ||
528 | |||
529 | if (!(wanted_fc & EFX_FC_AUTO)) | ||
530 | return wanted_fc; | ||
531 | |||
532 | if (adv & lpa & ADVERTISE_PAUSE_CAP) | ||
533 | return EFX_FC_RX | EFX_FC_TX; | ||
534 | if (adv & lpa & ADVERTISE_PAUSE_ASYM) { | ||
535 | if (adv & ADVERTISE_PAUSE_CAP) | ||
536 | return EFX_FC_RX; | ||
537 | if (lpa & ADVERTISE_PAUSE_CAP) | ||
538 | return EFX_FC_TX; | ||
539 | } | ||
540 | return 0; | ||
541 | } | ||
542 | |||
514 | /** | 543 | /** |
515 | * struct efx_mac_operations - Efx MAC operations table | 544 | * struct efx_mac_operations - Efx MAC operations table |
516 | * @reconfigure: Reconfigure MAC. Serialised by the mac_lock | 545 | * @reconfigure: Reconfigure MAC. Serialised by the mac_lock |
@@ -533,6 +562,8 @@ struct efx_mac_operations { | |||
533 | * @check_hw: Check hardware | 562 | * @check_hw: Check hardware |
534 | * @get_settings: Get ethtool settings. Serialised by the mac_lock. | 563 | * @get_settings: Get ethtool settings. Serialised by the mac_lock. |
535 | * @set_settings: Set ethtool settings. Serialised by the mac_lock. | 564 | * @set_settings: Set ethtool settings. Serialised by the mac_lock. |
565 | * @set_xnp_advertise: Set abilities advertised in Extended Next Page | ||
566 | * (only needed where AN bit is set in mmds) | ||
536 | * @mmds: MMD presence mask | 567 | * @mmds: MMD presence mask |
537 | * @loopbacks: Supported loopback modes mask | 568 | * @loopbacks: Supported loopback modes mask |
538 | */ | 569 | */ |
@@ -548,6 +579,7 @@ struct efx_phy_operations { | |||
548 | struct ethtool_cmd *ecmd); | 579 | struct ethtool_cmd *ecmd); |
549 | int (*set_settings) (struct efx_nic *efx, | 580 | int (*set_settings) (struct efx_nic *efx, |
550 | struct ethtool_cmd *ecmd); | 581 | struct ethtool_cmd *ecmd); |
582 | bool (*set_xnp_advertise) (struct efx_nic *efx, u32); | ||
551 | int mmds; | 583 | int mmds; |
552 | unsigned loopbacks; | 584 | unsigned loopbacks; |
553 | }; | 585 | }; |
@@ -724,11 +756,12 @@ union efx_multicast_hash { | |||
724 | * @mac_up: MAC link state | 756 | * @mac_up: MAC link state |
725 | * @link_up: Link status | 757 | * @link_up: Link status |
726 | * @link_fd: Link is full duplex | 758 | * @link_fd: Link is full duplex |
759 | * @link_fc: Actualy flow control flags | ||
727 | * @link_speed: Link speed (Mbps) | 760 | * @link_speed: Link speed (Mbps) |
728 | * @n_link_state_changes: Number of times the link has changed state | 761 | * @n_link_state_changes: Number of times the link has changed state |
729 | * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. | 762 | * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. |
730 | * @multicast_hash: Multicast hash table | 763 | * @multicast_hash: Multicast hash table |
731 | * @flow_control: Flow control flags - separate RX/TX so can't use link_options | 764 | * @wanted_fc: Wanted flow control flags |
732 | * @reconfigure_work: work item for dealing with PHY events | 765 | * @reconfigure_work: work item for dealing with PHY events |
733 | * @loopback_mode: Loopback status | 766 | * @loopback_mode: Loopback status |
734 | * @loopback_modes: Supported loopback mode bitmask | 767 | * @loopback_modes: Supported loopback mode bitmask |
@@ -805,12 +838,13 @@ struct efx_nic { | |||
805 | bool mac_up; | 838 | bool mac_up; |
806 | bool link_up; | 839 | bool link_up; |
807 | bool link_fd; | 840 | bool link_fd; |
841 | enum efx_fc_type link_fc; | ||
808 | unsigned int link_speed; | 842 | unsigned int link_speed; |
809 | unsigned int n_link_state_changes; | 843 | unsigned int n_link_state_changes; |
810 | 844 | ||
811 | bool promiscuous; | 845 | bool promiscuous; |
812 | union efx_multicast_hash multicast_hash; | 846 | union efx_multicast_hash multicast_hash; |
813 | enum efx_fc_type flow_control; | 847 | enum efx_fc_type wanted_fc; |
814 | struct work_struct reconfigure_work; | 848 | struct work_struct reconfigure_work; |
815 | 849 | ||
816 | atomic_t rx_reset; | 850 | atomic_t rx_reset; |
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index d60353bb40b6..634ff9198823 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -17,10 +17,10 @@ | |||
17 | #include "boards.h" | 17 | #include "boards.h" |
18 | 18 | ||
19 | /* We expect these MMDs to be in the package */ | 19 | /* We expect these MMDs to be in the package */ |
20 | /* AN not here as mdio_check_mmds() requires STAT2 support */ | ||
21 | #define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ | 20 | #define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ |
22 | MDIO_MMDREG_DEVS_PCS | \ | 21 | MDIO_MMDREG_DEVS_PCS | \ |
23 | MDIO_MMDREG_DEVS_PHYXS) | 22 | MDIO_MMDREG_DEVS_PHYXS | \ |
23 | MDIO_MMDREG_DEVS_AN) | ||
24 | 24 | ||
25 | #define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ | 25 | #define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ |
26 | (1 << LOOPBACK_PCS) | \ | 26 | (1 << LOOPBACK_PCS) | \ |
@@ -57,6 +57,7 @@ | |||
57 | #define PMA_PMD_LED_ON (1) | 57 | #define PMA_PMD_LED_ON (1) |
58 | #define PMA_PMD_LED_OFF (2) | 58 | #define PMA_PMD_LED_OFF (2) |
59 | #define PMA_PMD_LED_FLASH (3) | 59 | #define PMA_PMD_LED_FLASH (3) |
60 | #define PMA_PMD_LED_MASK 3 | ||
60 | /* All LEDs under hardware control */ | 61 | /* All LEDs under hardware control */ |
61 | #define PMA_PMD_LED_FULL_AUTO (0) | 62 | #define PMA_PMD_LED_FULL_AUTO (0) |
62 | /* Green and Amber under hardware control, Red off */ | 63 | /* Green and Amber under hardware control, Red off */ |
@@ -242,78 +243,60 @@ unlock: | |||
242 | return rc; | 243 | return rc; |
243 | } | 244 | } |
244 | 245 | ||
245 | static void tenxpress_set_bad_lp(struct efx_nic *efx, bool bad_lp) | 246 | static void tenxpress_check_bad_lp(struct efx_nic *efx, bool link_ok) |
246 | { | 247 | { |
247 | struct tenxpress_phy_data *pd = efx->phy_data; | 248 | struct tenxpress_phy_data *pd = efx->phy_data; |
249 | int phy_id = efx->mii.phy_id; | ||
250 | bool bad_lp; | ||
248 | int reg; | 251 | int reg; |
249 | 252 | ||
253 | if (link_ok) { | ||
254 | bad_lp = false; | ||
255 | } else { | ||
256 | /* Check that AN has started but not completed. */ | ||
257 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
258 | MDIO_AN_STATUS); | ||
259 | if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN))) | ||
260 | return; /* LP status is unknown */ | ||
261 | bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN)); | ||
262 | if (bad_lp) | ||
263 | pd->bad_lp_tries++; | ||
264 | } | ||
265 | |||
250 | /* Nothing to do if all is well and was previously so. */ | 266 | /* Nothing to do if all is well and was previously so. */ |
251 | if (!(bad_lp || pd->bad_lp_tries)) | 267 | if (!pd->bad_lp_tries) |
252 | return; | 268 | return; |
253 | 269 | ||
254 | reg = mdio_clause45_read(efx, efx->mii.phy_id, | 270 | /* Use the RX (red) LED as an error indicator once we've seen AN |
255 | MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG); | 271 | * failure several times in a row, and also log a message. */ |
256 | 272 | if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { | |
257 | if (bad_lp) | 273 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
258 | pd->bad_lp_tries++; | 274 | PMA_PMD_LED_OVERR_REG); |
259 | else | 275 | reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); |
260 | pd->bad_lp_tries = 0; | 276 | if (!bad_lp) { |
261 | 277 | reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; | |
262 | if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) { | 278 | } else { |
263 | pd->bad_lp_tries = 0; /* Restart count */ | 279 | reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN; |
264 | reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); | 280 | EFX_ERR(efx, "appears to be plugged into a port" |
265 | reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); | 281 | " that is not 10GBASE-T capable. The PHY" |
266 | EFX_ERR(efx, "This NIC appears to be plugged into" | 282 | " supports 10GBASE-T ONLY, so no link can" |
267 | " a port that is not 10GBASE-T capable.\n" | 283 | " be established\n"); |
268 | " This PHY is 10GBASE-T ONLY, so no link can" | 284 | } |
269 | " be established.\n"); | 285 | mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, |
270 | } else { | 286 | PMA_PMD_LED_OVERR_REG, reg); |
271 | reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN); | 287 | pd->bad_lp_tries = bad_lp; |
272 | } | 288 | } |
273 | mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
274 | PMA_PMD_LED_OVERR_REG, reg); | ||
275 | } | 289 | } |
276 | 290 | ||
277 | /* Check link status and return a boolean OK value. If the link is NOT | 291 | static bool tenxpress_link_ok(struct efx_nic *efx) |
278 | * OK we have a quick rummage round to see if we appear to be plugged | ||
279 | * into a non-10GBT port and if so warn the user that they won't get | ||
280 | * link any time soon as we are 10GBT only, unless caller specified | ||
281 | * not to do this check (it isn't useful in loopback) */ | ||
282 | static bool tenxpress_link_ok(struct efx_nic *efx, bool check_lp) | ||
283 | { | 292 | { |
284 | bool ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS); | 293 | if (efx->loopback_mode == LOOPBACK_NONE) |
285 | 294 | return mdio_clause45_links_ok(efx, MDIO_MMDREG_DEVS_AN); | |
286 | if (ok) { | 295 | else |
287 | tenxpress_set_bad_lp(efx, false); | 296 | return mdio_clause45_links_ok(efx, |
288 | } else if (check_lp) { | 297 | MDIO_MMDREG_DEVS_PMAPMD | |
289 | /* Are we plugged into the wrong sort of link? */ | 298 | MDIO_MMDREG_DEVS_PCS | |
290 | bool bad_lp = false; | 299 | MDIO_MMDREG_DEVS_PHYXS); |
291 | int phy_id = efx->mii.phy_id; | ||
292 | int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
293 | MDIO_AN_STATUS); | ||
294 | int xphy_stat = mdio_clause45_read(efx, phy_id, | ||
295 | MDIO_MMD_PMAPMD, | ||
296 | PMA_PMD_XSTATUS_REG); | ||
297 | /* Are we plugged into anything that sends FLPs? If | ||
298 | * not we can't distinguish between not being plugged | ||
299 | * in and being plugged into a non-AN antique. The FLP | ||
300 | * bit has the advantage of not clearing when autoneg | ||
301 | * restarts. */ | ||
302 | if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) { | ||
303 | tenxpress_set_bad_lp(efx, false); | ||
304 | return ok; | ||
305 | } | ||
306 | |||
307 | /* If it can do 10GBT it must be XNP capable */ | ||
308 | bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN)); | ||
309 | if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) { | ||
310 | bad_lp = !(mdio_clause45_read(efx, phy_id, | ||
311 | MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) & | ||
312 | (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)); | ||
313 | } | ||
314 | tenxpress_set_bad_lp(efx, bad_lp); | ||
315 | } | ||
316 | return ok; | ||
317 | } | 300 | } |
318 | 301 | ||
319 | static void tenxpress_phyxs_loopback(struct efx_nic *efx) | 302 | static void tenxpress_phyxs_loopback(struct efx_nic *efx) |
@@ -359,9 +342,10 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) | |||
359 | 342 | ||
360 | phy_data->loopback_mode = efx->loopback_mode; | 343 | phy_data->loopback_mode = efx->loopback_mode; |
361 | phy_data->phy_mode = efx->phy_mode; | 344 | phy_data->phy_mode = efx->phy_mode; |
362 | efx->link_up = tenxpress_link_ok(efx, false); | 345 | efx->link_up = tenxpress_link_ok(efx); |
363 | efx->link_speed = 10000; | 346 | efx->link_speed = 10000; |
364 | efx->link_fd = true; | 347 | efx->link_fd = true; |
348 | efx->link_fc = mdio_clause45_get_pause(efx); | ||
365 | } | 349 | } |
366 | 350 | ||
367 | static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) | 351 | static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) |
@@ -377,7 +361,8 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx) | |||
377 | bool link_ok; | 361 | bool link_ok; |
378 | int rc = 0; | 362 | int rc = 0; |
379 | 363 | ||
380 | link_ok = tenxpress_link_ok(efx, true); | 364 | link_ok = tenxpress_link_ok(efx); |
365 | tenxpress_check_bad_lp(efx, link_ok); | ||
381 | 366 | ||
382 | if (link_ok != efx->link_up) | 367 | if (link_ok != efx->link_up) |
383 | falcon_sim_phy_event(efx); | 368 | falcon_sim_phy_event(efx); |
@@ -451,6 +436,27 @@ static int tenxpress_phy_test(struct efx_nic *efx) | |||
451 | return tenxpress_special_reset(efx); | 436 | return tenxpress_special_reset(efx); |
452 | } | 437 | } |
453 | 438 | ||
439 | static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) | ||
440 | { | ||
441 | int phy = efx->mii.phy_id; | ||
442 | u32 lpa = 0; | ||
443 | int reg; | ||
444 | |||
445 | reg = mdio_clause45_read(efx, phy, MDIO_MMD_AN, MDIO_AN_10GBT_STATUS); | ||
446 | if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) | ||
447 | lpa |= ADVERTISED_10000baseT_Full; | ||
448 | return lpa; | ||
449 | } | ||
450 | |||
451 | static void | ||
452 | tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | ||
453 | { | ||
454 | mdio_clause45_get_settings_ext(efx, ecmd, ADVERTISED_10000baseT_Full, | ||
455 | tenxpress_get_xnp_lpa(efx)); | ||
456 | ecmd->supported |= SUPPORTED_10000baseT_Full; | ||
457 | ecmd->advertising |= ADVERTISED_10000baseT_Full; | ||
458 | } | ||
459 | |||
454 | struct efx_phy_operations falcon_tenxpress_phy_ops = { | 460 | struct efx_phy_operations falcon_tenxpress_phy_ops = { |
455 | .macs = EFX_XMAC, | 461 | .macs = EFX_XMAC, |
456 | .init = tenxpress_phy_init, | 462 | .init = tenxpress_phy_init, |
@@ -459,7 +465,7 @@ struct efx_phy_operations falcon_tenxpress_phy_ops = { | |||
459 | .fini = tenxpress_phy_fini, | 465 | .fini = tenxpress_phy_fini, |
460 | .clear_interrupt = tenxpress_phy_clear_interrupt, | 466 | .clear_interrupt = tenxpress_phy_clear_interrupt, |
461 | .test = tenxpress_phy_test, | 467 | .test = tenxpress_phy_test, |
462 | .get_settings = mdio_clause45_get_settings, | 468 | .get_settings = tenxpress_get_settings, |
463 | .set_settings = mdio_clause45_set_settings, | 469 | .set_settings = mdio_clause45_set_settings, |
464 | .mmds = TENXPRESS_REQUIRED_DEVS, | 470 | .mmds = TENXPRESS_REQUIRED_DEVS, |
465 | .loopbacks = TENXPRESS_LOOPBACKS, | 471 | .loopbacks = TENXPRESS_LOOPBACKS, |
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index d4e203ddcf1c..fbe8e25a1ed5 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c | |||
@@ -155,6 +155,7 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) | |||
155 | efx->link_up = xfp_link_ok(efx); | 155 | efx->link_up = xfp_link_ok(efx); |
156 | efx->link_speed = 10000; | 156 | efx->link_speed = 10000; |
157 | efx->link_fd = true; | 157 | efx->link_fd = true; |
158 | efx->link_fc = efx->wanted_fc; | ||
158 | } | 159 | } |
159 | 160 | ||
160 | 161 | ||