summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorLendacky, Thomas2015-01-16 19:47:00 +0100
committerDavid S. Miller2015-01-17 04:24:20 +0100
commitc3152d4728ca5f87688b1d9bf3e61de43235cbb0 (patch)
tree1e01fad3b329fb800d20f9f8f998664f42eae46c /drivers/net/ethernet
parentamd-xgbe: Remove need for Tx path spinlock (diff)
downloadkernel-qcow2-linux-c3152d4728ca5f87688b1d9bf3e61de43235cbb0.tar.gz
kernel-qcow2-linux-c3152d4728ca5f87688b1d9bf3e61de43235cbb0.tar.xz
kernel-qcow2-linux-c3152d4728ca5f87688b1d9bf3e61de43235cbb0.zip
amd-xgbe-phy: Change auto-negotiation logic
The auto negotiation logic was geared to being the initiator of the auto negotiation. This presented problems when auto negotiation was initiated by the remote end. Change the auto negotiation logic to make use of the auto negotiation event interrupt thus allowing the auto negotiation state machine to function properly in either scenario. This also removes the polling during auto-negotiation. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 5dff127a0823..950ad2e02dcb 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -115,6 +115,7 @@
*/
#include <linux/phy.h>
+#include <linux/mdio.h>
#include <linux/clk.h>
#include <linux/bitrev.h>
#include <linux/crc32.h>
@@ -673,6 +674,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata)
{
+ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x3)
+ return 0;
+
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3);
return 0;
@@ -680,6 +684,9 @@ static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata)
static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata)
{
+ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x2)
+ return 0;
+
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2);
return 0;
@@ -687,6 +694,9 @@ static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata)
static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata)
{
+ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0)
+ return 0;
+
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0);
return 0;
@@ -881,6 +891,23 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
else
mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
+ /* If the PCS is changing modes, match the MAC speed to it */
+ if (((mmd_address >> 16) == MDIO_MMD_PCS) &&
+ ((mmd_address & 0xffff) == MDIO_CTRL2)) {
+ struct phy_device *phydev = pdata->phydev;
+
+ if (mmd_data & MDIO_PCS_CTRL2_TYPE) {
+ /* KX mode */
+ if (phydev->supported & SUPPORTED_1000baseKX_Full)
+ xgbe_set_gmii_speed(pdata);
+ else
+ xgbe_set_gmii_2500_speed(pdata);
+ } else {
+ /* KR mode */
+ xgbe_set_xgmii_speed(pdata);
+ }
+ }
+
/* The PCS registers are accessed using mmio. The underlying APB3
* management interface uses indirect addressing to access the MMD
* register sets. This requires accessing of the PCS register in two