Skip to content

Commit c1ce2f7

Browse files
tlendackydavem330
authored andcommitted
amd-xgbe: Fix flow control setting logic
The flow control negotiation logic is flawed and does not properly advertise and process auto-negotiation of the flow control settings. Update the flow control support to properly set the flow control auto-negotiation settings and process the results approrpriately. Signed-off-by: Tom Lendacky <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 34bfff4 commit c1ce2f7

File tree

4 files changed

+72
-40
lines changed

4 files changed

+72
-40
lines changed

drivers/net/ethernet/amd/xgbe/xgbe-drv.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -782,8 +782,6 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
782782
{
783783
pdata->phy_link = -1;
784784
pdata->phy_speed = SPEED_UNKNOWN;
785-
pdata->phy_tx_pause = pdata->tx_pause;
786-
pdata->phy_rx_pause = pdata->rx_pause;
787785

788786
return pdata->phy_if.phy_reset(pdata);
789787
}

drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,9 @@ static void xgbe_get_pauseparam(struct net_device *netdev,
247247

248248
DBGPR("-->xgbe_get_pauseparam\n");
249249

250-
pause->autoneg = pdata->pause_autoneg;
251-
pause->tx_pause = pdata->tx_pause;
252-
pause->rx_pause = pdata->rx_pause;
250+
pause->autoneg = pdata->phy.pause_autoneg;
251+
pause->tx_pause = pdata->phy.tx_pause;
252+
pause->rx_pause = pdata->phy.rx_pause;
253253

254254
DBGPR("<--xgbe_get_pauseparam\n");
255255
}
@@ -265,19 +265,24 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
265265
DBGPR(" autoneg = %d, tx_pause = %d, rx_pause = %d\n",
266266
pause->autoneg, pause->tx_pause, pause->rx_pause);
267267

268-
pdata->pause_autoneg = pause->autoneg;
269-
if (pause->autoneg) {
270-
pdata->phy.advertising |= ADVERTISED_Pause;
271-
pdata->phy.advertising |= ADVERTISED_Asym_Pause;
268+
if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE))
269+
return -EINVAL;
270+
271+
pdata->phy.pause_autoneg = pause->autoneg;
272+
pdata->phy.tx_pause = pause->tx_pause;
273+
pdata->phy.rx_pause = pause->rx_pause;
272274

273-
} else {
274-
pdata->phy.advertising &= ~ADVERTISED_Pause;
275-
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
275+
pdata->phy.advertising &= ~ADVERTISED_Pause;
276+
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
276277

277-
pdata->tx_pause = pause->tx_pause;
278-
pdata->rx_pause = pause->rx_pause;
278+
if (pause->rx_pause) {
279+
pdata->phy.advertising |= ADVERTISED_Pause;
280+
pdata->phy.advertising |= ADVERTISED_Asym_Pause;
279281
}
280282

283+
if (pause->tx_pause)
284+
pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
285+
281286
if (netif_running(netdev))
282287
ret = pdata->phy_if.phy_config_aneg(pdata);
283288

drivers/net/ethernet/amd/xgbe/xgbe-mdio.c

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,18 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata)
737737
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
738738
}
739739

740+
static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
741+
{
742+
if (pdata->tx_pause && pdata->rx_pause)
743+
return "rx/tx";
744+
else if (pdata->rx_pause)
745+
return "rx";
746+
else if (pdata->tx_pause)
747+
return "tx";
748+
else
749+
return "off";
750+
}
751+
740752
static const char *xgbe_phy_speed_string(int speed)
741753
{
742754
switch (speed) {
@@ -760,7 +772,7 @@ static void xgbe_phy_print_status(struct xgbe_prv_data *pdata)
760772
"Link is Up - %s/%s - flow control %s\n",
761773
xgbe_phy_speed_string(pdata->phy.speed),
762774
pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
763-
pdata->phy.pause ? "rx/tx" : "off");
775+
xgbe_phy_fc_string(pdata));
764776
else
765777
netdev_info(pdata->netdev, "Link is Down\n");
766778
}
@@ -771,24 +783,18 @@ static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
771783

772784
if (pdata->phy.link) {
773785
/* Flow control support */
774-
if (pdata->pause_autoneg) {
775-
if (pdata->phy.pause || pdata->phy.asym_pause) {
776-
pdata->tx_pause = 1;
777-
pdata->rx_pause = 1;
778-
} else {
779-
pdata->tx_pause = 0;
780-
pdata->rx_pause = 0;
781-
}
782-
}
786+
pdata->pause_autoneg = pdata->phy.pause_autoneg;
783787

784-
if (pdata->tx_pause != pdata->phy_tx_pause) {
788+
if (pdata->tx_pause != pdata->phy.tx_pause) {
789+
new_state = 1;
785790
pdata->hw_if.config_tx_flow_control(pdata);
786-
pdata->phy_tx_pause = pdata->tx_pause;
791+
pdata->tx_pause = pdata->phy.tx_pause;
787792
}
788793

789-
if (pdata->rx_pause != pdata->phy_rx_pause) {
794+
if (pdata->rx_pause != pdata->phy.rx_pause) {
795+
new_state = 1;
790796
pdata->hw_if.config_rx_flow_control(pdata);
791-
pdata->phy_rx_pause = pdata->rx_pause;
797+
pdata->rx_pause = pdata->phy.rx_pause;
792798
}
793799

794800
/* Speed support */
@@ -835,9 +841,6 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
835841
if (pdata->phy.duplex != DUPLEX_FULL)
836842
return -EINVAL;
837843

838-
pdata->phy.pause = 0;
839-
pdata->phy.asym_pause = 0;
840-
841844
return 0;
842845
}
843846

@@ -933,8 +936,6 @@ static void xgbe_phy_status_force(struct xgbe_prv_data *pdata)
933936
}
934937
}
935938
pdata->phy.duplex = DUPLEX_FULL;
936-
pdata->phy.pause = 0;
937-
pdata->phy.asym_pause = 0;
938939
}
939940

940941
static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
@@ -957,9 +958,21 @@ static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
957958
if (lp_reg & 0x800)
958959
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
959960

960-
ad_reg &= lp_reg;
961-
pdata->phy.pause = (ad_reg & 0x400) ? 1 : 0;
962-
pdata->phy.asym_pause = (ad_reg & 0x800) ? 1 : 0;
961+
if (pdata->phy.pause_autoneg) {
962+
/* Set flow control based on auto-negotiation result */
963+
pdata->phy.tx_pause = 0;
964+
pdata->phy.rx_pause = 0;
965+
966+
if (ad_reg & lp_reg & 0x400) {
967+
pdata->phy.tx_pause = 1;
968+
pdata->phy.rx_pause = 1;
969+
} else if (ad_reg & lp_reg & 0x800) {
970+
if (ad_reg & 0x400)
971+
pdata->phy.rx_pause = 1;
972+
else if (lp_reg & 0x400)
973+
pdata->phy.tx_pause = 1;
974+
}
975+
}
963976

964977
/* Compare Advertisement and Link Partner register 2 */
965978
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
@@ -1223,6 +1236,22 @@ static void xgbe_phy_init(struct xgbe_prv_data *pdata)
12231236

12241237
pdata->phy.link = 0;
12251238

1239+
pdata->phy.pause_autoneg = pdata->pause_autoneg;
1240+
pdata->phy.tx_pause = pdata->tx_pause;
1241+
pdata->phy.rx_pause = pdata->rx_pause;
1242+
1243+
/* Fix up Flow Control advertising */
1244+
pdata->phy.advertising &= ~ADVERTISED_Pause;
1245+
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
1246+
1247+
if (pdata->rx_pause) {
1248+
pdata->phy.advertising |= ADVERTISED_Pause;
1249+
pdata->phy.advertising |= ADVERTISED_Asym_Pause;
1250+
}
1251+
1252+
if (pdata->tx_pause)
1253+
pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
1254+
12261255
if (netif_msg_drv(pdata))
12271256
xgbe_dump_phy_registers(pdata);
12281257
}

drivers/net/ethernet/amd/xgbe/xgbe.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -539,10 +539,12 @@ struct xgbe_phy {
539539
int autoneg;
540540
int speed;
541541
int duplex;
542-
int pause;
543-
int asym_pause;
544542

545543
int link;
544+
545+
int pause_autoneg;
546+
int tx_pause;
547+
int rx_pause;
546548
};
547549

548550
struct xgbe_mmc_stats {
@@ -910,8 +912,6 @@ struct xgbe_prv_data {
910912
phy_interface_t phy_mode;
911913
int phy_link;
912914
int phy_speed;
913-
unsigned int phy_tx_pause;
914-
unsigned int phy_rx_pause;
915915

916916
/* MDIO/PHY related settings */
917917
struct xgbe_phy phy;

0 commit comments

Comments
 (0)