summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig4
-rw-r--r--drivers/net/phy/amd.c33
-rw-r--r--drivers/net/phy/at803x.c6
-rw-r--r--drivers/net/phy/ax88796b.c2
-rw-r--r--drivers/net/phy/bcm-phy-ptp.c1
-rw-r--r--drivers/net/phy/bcm87xx.c1
-rw-r--r--drivers/net/phy/broadcom.c154
-rw-r--r--drivers/net/phy/dp83867.c137
-rw-r--r--drivers/net/phy/mediatek-ge-soc.c147
-rw-r--r--drivers/net/phy/micrel.c28
-rw-r--r--drivers/net/phy/nxp-tja11xx.c6
-rw-r--r--drivers/net/phy/phy.c207
-rw-r--r--drivers/net/phy/phylink.c46
-rw-r--r--drivers/net/phy/realtek.c4
-rw-r--r--drivers/net/phy/sfp.c34
-rw-r--r--drivers/net/phy/smsc.c6
16 files changed, 553 insertions, 263 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 107880d13d..421d2b6291 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -69,9 +69,9 @@ config SFP
comment "MII PHY device drivers"
config AMD_PHY
- tristate "AMD PHYs"
+ tristate "AMD and Altima PHYs"
help
- Currently supports the am79c874
+ Currently supports the AMD am79c874 and Altima AC101L.
config MESON_GXL_PHY
tristate "Amlogic Meson GXL Internal PHY"
diff --git a/drivers/net/phy/amd.c b/drivers/net/phy/amd.c
index 001bb6d8bf..930b15fa6c 100644
--- a/drivers/net/phy/amd.c
+++ b/drivers/net/phy/amd.c
@@ -13,6 +13,7 @@
#include <linux/mii.h>
#include <linux/phy.h>
+#define PHY_ID_AC101L 0x00225520
#define PHY_ID_AM79C874 0x0022561b
#define MII_AM79C_IR 17 /* Interrupt Status/Control Register */
@@ -87,19 +88,31 @@ static irqreturn_t am79c_handle_interrupt(struct phy_device *phydev)
return IRQ_HANDLED;
}
-static struct phy_driver am79c_driver[] = { {
- .phy_id = PHY_ID_AM79C874,
- .name = "AM79C874",
- .phy_id_mask = 0xfffffff0,
- /* PHY_BASIC_FEATURES */
- .config_init = am79c_config_init,
- .config_intr = am79c_config_intr,
- .handle_interrupt = am79c_handle_interrupt,
-} };
+static struct phy_driver am79c_drivers[] = {
+ {
+ .phy_id = PHY_ID_AM79C874,
+ .name = "AM79C874",
+ .phy_id_mask = 0xfffffff0,
+ /* PHY_BASIC_FEATURES */
+ .config_init = am79c_config_init,
+ .config_intr = am79c_config_intr,
+ .handle_interrupt = am79c_handle_interrupt,
+ },
+ {
+ .phy_id = PHY_ID_AC101L,
+ .name = "AC101L",
+ .phy_id_mask = 0xfffffff0,
+ /* PHY_BASIC_FEATURES */
+ .config_init = am79c_config_init,
+ .config_intr = am79c_config_intr,
+ .handle_interrupt = am79c_handle_interrupt,
+ },
+};
-module_phy_driver(am79c_driver);
+module_phy_driver(am79c_drivers);
static struct mdio_device_id __maybe_unused amd_tbl[] = {
+ { PHY_ID_AC101L, 0xfffffff0 },
{ PHY_ID_AM79C874, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 37fb033e1c..ef203b0807 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -2104,7 +2104,7 @@ static struct phy_driver at803x_driver[] = {
.write_page = at803x_write_page,
.get_features = at803x_get_features,
.read_status = at803x_read_status,
- .config_intr = &at803x_config_intr,
+ .config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
@@ -2134,7 +2134,7 @@ static struct phy_driver at803x_driver[] = {
.resume = at803x_resume,
.flags = PHY_POLL_CABLE_TEST,
/* PHY_BASIC_FEATURES */
- .config_intr = &at803x_config_intr,
+ .config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
.cable_test_get_status = at803x_cable_test_get_status,
@@ -2150,7 +2150,7 @@ static struct phy_driver at803x_driver[] = {
.resume = at803x_resume,
.flags = PHY_POLL_CABLE_TEST,
/* PHY_BASIC_FEATURES */
- .config_intr = &at803x_config_intr,
+ .config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
.cable_test_get_status = at803x_cable_test_get_status,
diff --git a/drivers/net/phy/ax88796b.c b/drivers/net/phy/ax88796b.c
index 0f1e617a26..eb74a8cf8d 100644
--- a/drivers/net/phy/ax88796b.c
+++ b/drivers/net/phy/ax88796b.c
@@ -90,7 +90,7 @@ static void asix_ax88772a_link_change_notify(struct phy_device *phydev)
*/
if (phydev->state == PHY_NOLINK) {
phy_init_hw(phydev);
- phy_start_aneg(phydev);
+ _phy_start_aneg(phydev);
}
}
diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c
index ef00d61630..cb4b91af5e 100644
--- a/drivers/net/phy/bcm-phy-ptp.c
+++ b/drivers/net/phy/bcm-phy-ptp.c
@@ -942,3 +942,4 @@ struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev)
EXPORT_SYMBOL_GPL(bcm_ptp_probe);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Broadcom PHY PTP driver");
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index cc28581076..e81404bf89 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -223,3 +223,4 @@ static struct phy_driver bcm87xx_driver[] = {
module_phy_driver(bcm87xx_driver);
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Broadcom BCM87xx PHY driver");
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 04b2e6eeb1..3a62710567 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -704,16 +704,21 @@ static int brcm_fet_config_init(struct phy_device *phydev)
if (err < 0 && err != -EIO)
return err;
+ /* Read to clear status bits */
reg = phy_read(phydev, MII_BRCM_FET_INTREG);
if (reg < 0)
return reg;
/* Unmask events we are interested in and mask interrupts globally. */
- reg = MII_BRCM_FET_IR_DUPLEX_EN |
- MII_BRCM_FET_IR_SPEED_EN |
- MII_BRCM_FET_IR_LINK_EN |
- MII_BRCM_FET_IR_ENABLE |
- MII_BRCM_FET_IR_MASK;
+ if (phydev->phy_id == PHY_ID_BCM5221)
+ reg = MII_BRCM_FET_IR_ENABLE |
+ MII_BRCM_FET_IR_MASK;
+ else
+ reg = MII_BRCM_FET_IR_DUPLEX_EN |
+ MII_BRCM_FET_IR_SPEED_EN |
+ MII_BRCM_FET_IR_LINK_EN |
+ MII_BRCM_FET_IR_ENABLE |
+ MII_BRCM_FET_IR_MASK;
err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
if (err < 0)
@@ -726,42 +731,49 @@ static int brcm_fet_config_init(struct phy_device *phydev)
reg = brcmtest | MII_BRCM_FET_BT_SRE;
- err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
- if (err < 0)
- return err;
+ phy_lock_mdio_bus(phydev);
- /* Set the LED mode */
- reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
- if (reg < 0) {
- err = reg;
- goto done;
+ err = __phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
+ if (err < 0) {
+ phy_unlock_mdio_bus(phydev);
+ return err;
}
- reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
- reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
+ if (phydev->phy_id != PHY_ID_BCM5221) {
+ /* Set the LED mode */
+ reg = __phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
+ if (reg < 0) {
+ err = reg;
+ goto done;
+ }
- err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
- if (err < 0)
- goto done;
+ err = __phy_modify(phydev, MII_BRCM_FET_SHDW_AUXMODE4,
+ MII_BRCM_FET_SHDW_AM4_LED_MASK,
+ MII_BRCM_FET_SHDW_AM4_LED_MODE1);
+ if (err < 0)
+ goto done;
- /* Enable auto MDIX */
- err = phy_set_bits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
- MII_BRCM_FET_SHDW_MC_FAME);
- if (err < 0)
- goto done;
+ /* Enable auto MDIX */
+ err = __phy_set_bits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
+ MII_BRCM_FET_SHDW_MC_FAME);
+ if (err < 0)
+ goto done;
+ }
if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
/* Enable auto power down */
- err = phy_set_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
- MII_BRCM_FET_SHDW_AS2_APDE);
+ err = __phy_set_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
+ MII_BRCM_FET_SHDW_AS2_APDE);
}
done:
/* Disable shadow register access */
- err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
+ err2 = __phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
if (!err)
err = err2;
+ phy_unlock_mdio_bus(phydev);
+
return err;
}
@@ -840,23 +852,86 @@ static int brcm_fet_suspend(struct phy_device *phydev)
reg = brcmtest | MII_BRCM_FET_BT_SRE;
- err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
- if (err < 0)
+ phy_lock_mdio_bus(phydev);
+
+ err = __phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
+ if (err < 0) {
+ phy_unlock_mdio_bus(phydev);
return err;
+ }
+
+ if (phydev->phy_id == PHY_ID_BCM5221)
+ /* Force Low Power Mode with clock enabled */
+ reg = BCM5221_SHDW_AM4_EN_CLK_LPM | BCM5221_SHDW_AM4_FORCE_LPM;
+ else
+ /* Set standby mode */
+ reg = MII_BRCM_FET_SHDW_AM4_STANDBY;
- /* Set standby mode */
- err = phy_modify(phydev, MII_BRCM_FET_SHDW_AUXMODE4,
- MII_BRCM_FET_SHDW_AM4_STANDBY,
- MII_BRCM_FET_SHDW_AM4_STANDBY);
+ err = __phy_set_bits(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
/* Disable shadow register access */
- err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
+ err2 = __phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
if (!err)
err = err2;
+ phy_unlock_mdio_bus(phydev);
+
return err;
}
+static int bcm5221_config_aneg(struct phy_device *phydev)
+{
+ int ret, val;
+
+ ret = genphy_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ switch (phydev->mdix_ctrl) {
+ case ETH_TP_MDI:
+ val = BCM5221_AEGSR_MDIX_DIS;
+ break;
+ case ETH_TP_MDI_X:
+ val = BCM5221_AEGSR_MDIX_DIS | BCM5221_AEGSR_MDIX_MAN_SWAP;
+ break;
+ case ETH_TP_MDI_AUTO:
+ val = 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return phy_modify(phydev, BCM5221_AEGSR, BCM5221_AEGSR_MDIX_MAN_SWAP |
+ BCM5221_AEGSR_MDIX_DIS,
+ val);
+}
+
+static int bcm5221_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Read MDIX status */
+ ret = phy_read(phydev, BCM5221_AEGSR);
+ if (ret < 0)
+ return ret;
+
+ if (ret & BCM5221_AEGSR_MDIX_DIS) {
+ if (ret & BCM5221_AEGSR_MDIX_MAN_SWAP)
+ phydev->mdix_ctrl = ETH_TP_MDI_X;
+ else
+ phydev->mdix_ctrl = ETH_TP_MDI;
+ } else {
+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+ }
+
+ if (ret & BCM5221_AEGSR_MDIX_STATUS)
+ phydev->mdix = ETH_TP_MDI_X;
+ else
+ phydev->mdix = ETH_TP_MDI;
+
+ return genphy_read_status(phydev);
+}
+
static void bcm54xx_phy_get_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
@@ -1222,6 +1297,18 @@ static struct phy_driver broadcom_drivers[] = {
.suspend = brcm_fet_suspend,
.resume = brcm_fet_config_init,
}, {
+ .phy_id = PHY_ID_BCM5221,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM5221",
+ /* PHY_BASIC_FEATURES */
+ .config_init = brcm_fet_config_init,
+ .config_intr = brcm_fet_config_intr,
+ .handle_interrupt = brcm_fet_handle_interrupt,
+ .suspend = brcm_fet_suspend,
+ .resume = brcm_fet_config_init,
+ .config_aneg = bcm5221_config_aneg,
+ .read_status = bcm5221_read_status,
+}, {
.phy_id = PHY_ID_BCM5395,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5395",
@@ -1296,6 +1383,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM50610M, 0xfffffff0 },
{ PHY_ID_BCM57780, 0xfffffff0 },
{ PHY_ID_BCMAC131, 0xfffffff0 },
+ { PHY_ID_BCM5221, 0xfffffff0 },
{ PHY_ID_BCM5241, 0xfffffff0 },
{ PHY_ID_BCM5395, 0xfffffff0 },
{ PHY_ID_BCM53125, 0xfffffff0 },
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index e397e7d642..5f08f9d38b 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -159,6 +159,23 @@
#define DP83867_LED_DRV_EN(x) BIT((x) * 4)
#define DP83867_LED_DRV_VAL(x) BIT((x) * 4 + 1)
+#define DP83867_LED_FN(idx, val) (((val) & 0xf) << ((idx) * 4))
+#define DP83867_LED_FN_MASK(idx) (0xf << ((idx) * 4))
+#define DP83867_LED_FN_RX_ERR 0xe /* Receive Error */
+#define DP83867_LED_FN_RX_TX_ERR 0xd /* Receive Error or Transmit Error */
+#define DP83867_LED_FN_LINK_RX_TX 0xb /* Link established, blink for rx or tx activity */
+#define DP83867_LED_FN_FULL_DUPLEX 0xa /* Full duplex */
+#define DP83867_LED_FN_LINK_100_1000_BT 0x9 /* 100/1000BT link established */
+#define DP83867_LED_FN_LINK_10_100_BT 0x8 /* 10/100BT link established */
+#define DP83867_LED_FN_LINK_10_BT 0x7 /* 10BT link established */
+#define DP83867_LED_FN_LINK_100_BTX 0x6 /* 100 BTX link established */
+#define DP83867_LED_FN_LINK_1000_BT 0x5 /* 1000 BT link established */
+#define DP83867_LED_FN_COLLISION 0x4 /* Collision detected */
+#define DP83867_LED_FN_RX 0x3 /* Receive activity */
+#define DP83867_LED_FN_TX 0x2 /* Transmit activity */
+#define DP83867_LED_FN_RX_TX 0x1 /* Receive or Transmit activity */
+#define DP83867_LED_FN_LINK 0x0 /* Link established */
+
enum {
DP83867_PORT_MIRROING_KEEP,
DP83867_PORT_MIRROING_EN,
@@ -1018,6 +1035,123 @@ dp83867_led_brightness_set(struct phy_device *phydev,
val);
}
+static int dp83867_led_mode(u8 index, unsigned long rules)
+{
+ if (index >= DP83867_LED_COUNT)
+ return -EINVAL;
+
+ switch (rules) {
+ case BIT(TRIGGER_NETDEV_LINK):
+ return DP83867_LED_FN_LINK;
+ case BIT(TRIGGER_NETDEV_LINK_10):
+ return DP83867_LED_FN_LINK_10_BT;
+ case BIT(TRIGGER_NETDEV_LINK_100):
+ return DP83867_LED_FN_LINK_100_BTX;
+ case BIT(TRIGGER_NETDEV_FULL_DUPLEX):
+ return DP83867_LED_FN_FULL_DUPLEX;
+ case BIT(TRIGGER_NETDEV_TX):
+ return DP83867_LED_FN_TX;
+ case BIT(TRIGGER_NETDEV_RX):
+ return DP83867_LED_FN_RX;
+ case BIT(TRIGGER_NETDEV_LINK_1000):
+ return DP83867_LED_FN_LINK_1000_BT;
+ case BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
+ return DP83867_LED_FN_RX_TX;
+ case BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000):
+ return DP83867_LED_FN_LINK_100_1000_BT;
+ case BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100):
+ return DP83867_LED_FN_LINK_10_100_BT;
+ case BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
+ return DP83867_LED_FN_LINK_RX_TX;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int dp83867_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ int ret;
+
+ ret = dp83867_led_mode(index, rules);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int dp83867_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ int mode, ret;
+
+ mode = dp83867_led_mode(index, rules);
+ if (mode < 0)
+ return mode;
+
+ ret = phy_modify(phydev, DP83867_LEDCR1, DP83867_LED_FN_MASK(index),
+ DP83867_LED_FN(index, mode));
+ if (ret)
+ return ret;
+
+ return phy_modify(phydev, DP83867_LEDCR2, DP83867_LED_DRV_EN(index), 0);
+}
+
+static int dp83867_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ int val;
+
+ val = phy_read(phydev, DP83867_LEDCR1);
+ if (val < 0)
+ return val;
+
+ val &= DP83867_LED_FN_MASK(index);
+ val >>= index * 4;
+
+ switch (val) {
+ case DP83867_LED_FN_LINK:
+ *rules = BIT(TRIGGER_NETDEV_LINK);
+ break;
+ case DP83867_LED_FN_LINK_10_BT:
+ *rules = BIT(TRIGGER_NETDEV_LINK_10);
+ break;
+ case DP83867_LED_FN_LINK_100_BTX:
+ *rules = BIT(TRIGGER_NETDEV_LINK_100);
+ break;
+ case DP83867_LED_FN_FULL_DUPLEX:
+ *rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+ break;
+ case DP83867_LED_FN_TX:
+ *rules = BIT(TRIGGER_NETDEV_TX);
+ break;
+ case DP83867_LED_FN_RX:
+ *rules = BIT(TRIGGER_NETDEV_RX);
+ break;
+ case DP83867_LED_FN_LINK_1000_BT:
+ *rules = BIT(TRIGGER_NETDEV_LINK_1000);
+ break;
+ case DP83867_LED_FN_RX_TX:
+ *rules = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
+ break;
+ case DP83867_LED_FN_LINK_100_1000_BT:
+ *rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000);
+ break;
+ case DP83867_LED_FN_LINK_10_100_BT:
+ *rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100);
+ break;
+ case DP83867_LED_FN_LINK_RX_TX:
+ *rules = BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) |
+ BIT(TRIGGER_NETDEV_RX);
+ break;
+ default:
+ *rules = 0;
+ break;
+ }
+
+ return 0;
+}
+
static struct phy_driver dp83867_driver[] = {
{
.phy_id = DP83867_PHY_ID,
@@ -1047,6 +1181,9 @@ static struct phy_driver dp83867_driver[] = {
.set_loopback = dp83867_loopback,
.led_brightness_set = dp83867_led_brightness_set,
+ .led_hw_is_supported = dp83867_led_hw_is_supported,
+ .led_hw_control_set = dp83867_led_hw_control_set,
+ .led_hw_control_get = dp83867_led_hw_control_get,
},
};
module_phy_driver(dp83867_driver);
diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c
index 8a20d9889f..0f3a1538a8 100644
--- a/drivers/net/phy/mediatek-ge-soc.c
+++ b/drivers/net/phy/mediatek-ge-soc.c
@@ -489,7 +489,7 @@ static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
u16 reg, val;
if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
- bias = -2;
+ bias = -1;
val = clamp_val(bias + tx_r50_cal_val, 0, 63);
@@ -705,6 +705,11 @@ restore:
static void mt798x_phy_common_finetune(struct phy_device *phydev)
{
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+ __phy_write(phydev, 0x11, 0xc71);
+ __phy_write(phydev, 0x12, 0xc);
+ __phy_write(phydev, 0x10, 0x8fae);
+
/* EnabRandUpdTrig = 1 */
__phy_write(phydev, 0x11, 0x2f00);
__phy_write(phydev, 0x12, 0xe);
@@ -715,15 +720,56 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x83aa);
- /* TrFreeze = 0 */
+ /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+ __phy_write(phydev, 0x11, 0x240);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x9680);
+
+ /* TrFreeze = 0 (mt7988 default) */
__phy_write(phydev, 0x11, 0x0);
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x9686);
+ /* SSTrKp100 = 5 */
+ /* SSTrKf100 = 6 */
+ /* SSTrKp1000Mas = 5 */
+ /* SSTrKf1000Mas = 6 */
/* SSTrKp1000Slv = 5 */
+ /* SSTrKf1000Slv = 6 */
__phy_write(phydev, 0x11, 0xbaef);
__phy_write(phydev, 0x12, 0x2e);
__phy_write(phydev, 0x10, 0x968c);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+}
+
+static void mt7981_phy_finetune(struct phy_device *phydev)
+{
+ u16 val[8] = { 0x01ce, 0x01c1,
+ 0x020f, 0x0202,
+ 0x03d0, 0x03c0,
+ 0x0013, 0x0005 };
+ int i, k;
+
+ /* 100M eye finetune:
+ * Keep middle level of TX MLT3 shapper as default.
+ * Only change TX MLT3 overshoot level here.
+ */
+ for (k = 0, i = 1; i < 12; i++) {
+ if (i % 3 == 0)
+ continue;
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+ }
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ /* ResetSyncOffset = 6 */
+ __phy_write(phydev, 0x11, 0x600);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x8fc0);
+
+ /* VgaDecRate = 1 */
+ __phy_write(phydev, 0x11, 0x4c2a);
+ __phy_write(phydev, 0x12, 0x3e);
+ __phy_write(phydev, 0x10, 0x8fa4);
/* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
* MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
@@ -738,7 +784,7 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
__phy_write(phydev, 0x10, 0x8ec0);
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
@@ -771,48 +817,6 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
}
-static void mt7981_phy_finetune(struct phy_device *phydev)
-{
- u16 val[8] = { 0x01ce, 0x01c1,
- 0x020f, 0x0202,
- 0x03d0, 0x03c0,
- 0x0013, 0x0005 };
- int i, k;
-
- /* 100M eye finetune:
- * Keep middle level of TX MLT3 shapper as default.
- * Only change TX MLT3 overshoot level here.
- */
- for (k = 0, i = 1; i < 12; i++) {
- if (i % 3 == 0)
- continue;
- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
- }
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
- __phy_write(phydev, 0x11, 0xc71);
- __phy_write(phydev, 0x12, 0xc);
- __phy_write(phydev, 0x10, 0x8fae);
-
- /* ResetSyncOffset = 6 */
- __phy_write(phydev, 0x11, 0x600);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x8fc0);
-
- /* VgaDecRate = 1 */
- __phy_write(phydev, 0x11, 0x4c2a);
- __phy_write(phydev, 0x12, 0x3e);
- __phy_write(phydev, 0x10, 0x8fa4);
-
- /* FfeUpdGainForce = 4 */
- __phy_write(phydev, 0x11, 0x240);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9680);
-
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-}
-
static void mt7988_phy_finetune(struct phy_device *phydev)
{
u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
@@ -827,17 +831,7 @@ static void mt7988_phy_finetune(struct phy_device *phydev)
/* TCT finetune */
phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
- /* Disable TX power saving */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
- MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
-
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-
- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */
- __phy_write(phydev, 0x11, 0x671);
- __phy_write(phydev, 0x12, 0xc);
- __phy_write(phydev, 0x10, 0x8fae);
-
/* ResetSyncOffset = 5 */
__phy_write(phydev, 0x11, 0x500);
__phy_write(phydev, 0x12, 0x0);
@@ -845,13 +839,27 @@ static void mt7988_phy_finetune(struct phy_device *phydev)
/* VgaDecRate is 1 at default on mt7988 */
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+ * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+ */
+ __phy_write(phydev, 0x11, 0xb90a);
+ __phy_write(phydev, 0x12, 0x6f);
+ __phy_write(phydev, 0x10, 0x8f82);
+
+ /* RemAckCntLimitCtrl = 1 */
+ __phy_write(phydev, 0x11, 0xfbba);
+ __phy_write(phydev, 0x12, 0xc3);
+ __phy_write(phydev, 0x10, 0x87f8);
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30);
- /* TxClkOffset = 2 */
- __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK,
- FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2));
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+
+ /* rg_tr_lpf_cnt_val = 1023 */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
}
static void mt798x_phy_eee(struct phy_device *phydev)
@@ -884,11 +892,11 @@ static void mt798x_phy_eee(struct phy_device *phydev)
MTK_PHY_LPI_SLV_SEND_TX_EN,
FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
- MTK_PHY_LPI_SEND_LOC_TIMER_MASK |
- MTK_PHY_LPI_TXPCS_LOC_RCV,
- FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117));
+ /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+ MTK_PHY_LPI_TXPCS_LOC_RCV);
+ /* This also fixes some IoT issues, such as CH340 */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
@@ -922,7 +930,7 @@ static void mt798x_phy_eee(struct phy_device *phydev)
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x9690);
- /* REG_EEE_st2TrKf1000 = 3 */
+ /* REG_EEE_st2TrKf1000 = 2 */
__phy_write(phydev, 0x11, 0x114f);
__phy_write(phydev, 0x12, 0x2);
__phy_write(phydev, 0x10, 0x969a);
@@ -947,7 +955,7 @@ static void mt798x_phy_eee(struct phy_device *phydev)
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x96b8);
- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */
+ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
__phy_write(phydev, 0x11, 0x1463);
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x96ca);
@@ -1459,6 +1467,13 @@ static int mt7988_phy_probe(struct phy_device *phydev)
if (err)
return err;
+ /* Disable TX power saving at probing to:
+ * 1. Meet common mode compliance test criteria
+ * 2. Make sure that TX-VCM calibration works fine
+ */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+
return mt798x_phy_calibration(phydev);
}
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 27ca25bbd1..ca2db4adcb 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -1738,6 +1738,28 @@ static int ksz886x_config_aneg(struct phy_device *phydev)
if (ret)
return ret;
+ if (phydev->autoneg != AUTONEG_ENABLE) {
+ /* When autonegotation is disabled, we need to manually force
+ * the link state. If we don't do this, the PHY will keep
+ * sending Fast Link Pulses (FLPs) which are part of the
+ * autonegotiation process. This is not desired when
+ * autonegotiation is off.
+ */
+ ret = phy_set_bits(phydev, MII_KSZPHY_CTRL,
+ KSZ886X_CTRL_FORCE_LINK);
+ if (ret)
+ return ret;
+ } else {
+ /* If we had previously forced the link state, we need to
+ * clear KSZ886X_CTRL_FORCE_LINK bit now. Otherwise, the PHY
+ * will not perform autonegotiation.
+ */
+ ret = phy_clear_bits(phydev, MII_KSZPHY_CTRL,
+ KSZ886X_CTRL_FORCE_LINK);
+ if (ret)
+ return ret;
+ }
+
/* The MDI-X configuration is automatically changed by the PHY after
* switching from autoneg off to on. So, take MDI-X configuration under
* own control and set it after autoneg configuration was done.
@@ -3628,12 +3650,8 @@ static int lan8841_ts_info(struct mii_timestamper *mii_ts,
info->phc_index = ptp_priv->ptp_clock ?
ptp_clock_index(ptp_priv->ptp_clock) : -1;
- if (info->phc_index == -1) {
- info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
- SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE;
+ if (info->phc_index == -1)
return 0;
- }
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index b13e15310f..a713999651 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -414,10 +414,8 @@ static void tja11xx_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++) {
- strncpy(data + i * ETH_GSTRING_LEN,
- tja11xx_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++)
+ ethtool_sprintf(&data, "%s", tja11xx_hw_stats[i].string);
}
static void tja11xx_get_stats(struct phy_device *phydev,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index df54c137c5..a5fa077650 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -981,7 +981,7 @@ static int phy_check_link_status(struct phy_device *phydev)
* If the PHYCONTROL Layer is operating, we change the state to
* reflect the beginning of Auto-negotiation or forcing.
*/
-static int _phy_start_aneg(struct phy_device *phydev)
+int _phy_start_aneg(struct phy_device *phydev)
{
int err;
@@ -1002,6 +1002,7 @@ static int _phy_start_aneg(struct phy_device *phydev)
return err;
}
+EXPORT_SYMBOL(_phy_start_aneg);
/**
* phy_start_aneg - start auto-negotiation for this PHY device
@@ -1231,9 +1232,7 @@ static void phy_error_precise(struct phy_device *phydev,
const void *func, int err)
{
WARN(1, "%pS: returned: %d\n", func, err);
- mutex_lock(&phydev->lock);
phy_process_error(phydev);
- mutex_unlock(&phydev->lock);
}
/**
@@ -1355,6 +1354,113 @@ void phy_free_interrupt(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_free_interrupt);
+enum phy_state_work {
+ PHY_STATE_WORK_NONE,
+ PHY_STATE_WORK_ANEG,
+ PHY_STATE_WORK_SUSPEND,
+};
+
+static enum phy_state_work _phy_state_machine(struct phy_device *phydev)
+{
+ enum phy_state_work state_work = PHY_STATE_WORK_NONE;
+ struct net_device *dev = phydev->attached_dev;
+ enum phy_state old_state = phydev->state;
+ const void *func = NULL;
+ bool finished = false;
+ int err = 0;
+
+ switch (phydev->state) {
+ case PHY_DOWN:
+ case PHY_READY:
+ break;
+ case PHY_UP:
+ state_work = PHY_STATE_WORK_ANEG;
+ break;
+ case PHY_NOLINK:
+ case PHY_RUNNING:
+ err = phy_check_link_status(phydev);
+ func = &phy_check_link_status;
+ break;
+ case PHY_CABLETEST:
+ err = phydev->drv->cable_test_get_status(phydev, &finished);
+ if (err) {
+ phy_abort_cable_test(phydev);
+ netif_testing_off(dev);
+ state_work = PHY_STATE_WORK_ANEG;
+ phydev->state = PHY_UP;
+ break;
+ }
+
+ if (finished) {
+ ethnl_cable_test_finished(phydev);
+ netif_testing_off(dev);
+ state_work = PHY_STATE_WORK_ANEG;
+ phydev->state = PHY_UP;
+ }
+ break;
+ case PHY_HALTED:
+ case PHY_ERROR:
+ if (phydev->link) {
+ phydev->link = 0;
+ phy_link_down(phydev);
+ }
+ state_work = PHY_STATE_WORK_SUSPEND;
+ break;
+ }
+
+ if (state_work == PHY_STATE_WORK_ANEG) {
+ err = _phy_start_aneg(phydev);
+ func = &_phy_start_aneg;
+ }
+
+ if (err == -ENODEV)
+ return state_work;
+
+ if (err < 0)
+ phy_error_precise(phydev, func, err);
+
+ phy_process_state_change(phydev, old_state);
+
+ /* Only re-schedule a PHY state machine change if we are polling the
+ * PHY, if PHY_MAC_INTERRUPT is set, then we will be moving
+ * between states from phy_mac_interrupt().
+ *
+ * In state PHY_HALTED the PHY gets suspended, so rescheduling the
+ * state machine would be pointless and possibly error prone when
+ * called from phy_disconnect() synchronously.
+ */
+ if (phy_polling_mode(phydev) && phy_is_started(phydev))
+ phy_queue_state_machine(phydev, PHY_STATE_TIME);
+
+ return state_work;
+}
+
+/* unlocked part of the PHY state machine */
+static void _phy_state_machine_post_work(struct phy_device *phydev,
+ enum phy_state_work state_work)
+{
+ if (state_work == PHY_STATE_WORK_SUSPEND)
+ phy_suspend(phydev);
+}
+
+/**
+ * phy_state_machine - Handle the state machine
+ * @work: work_struct that describes the work to be done
+ */
+void phy_state_machine(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct phy_device *phydev =
+ container_of(dwork, struct phy_device, state_queue);
+ enum phy_state_work state_work;
+
+ mutex_lock(&phydev->lock);
+ state_work = _phy_state_machine(phydev);
+ mutex_unlock(&phydev->lock);
+
+ _phy_state_machine_post_work(phydev, state_work);
+}
+
/**
* phy_stop - Bring down the PHY link, and stop checking the status
* @phydev: target phy_device struct
@@ -1362,6 +1468,7 @@ EXPORT_SYMBOL(phy_free_interrupt);
void phy_stop(struct phy_device *phydev)
{
struct net_device *dev = phydev->attached_dev;
+ enum phy_state_work state_work;
enum phy_state old_state;
if (!phy_is_started(phydev) && phydev->state != PHY_DOWN &&
@@ -1385,9 +1492,10 @@ void phy_stop(struct phy_device *phydev)
phydev->state = PHY_HALTED;
phy_process_state_change(phydev, old_state);
+ state_work = _phy_state_machine(phydev);
mutex_unlock(&phydev->lock);
- phy_state_machine(&phydev->state_queue.work);
+ _phy_state_machine_post_work(phydev, state_work);
phy_stop_machine(phydev);
/* Cannot call flush_scheduled_work() here as desired because
@@ -1432,97 +1540,6 @@ out:
EXPORT_SYMBOL(phy_start);
/**
- * phy_state_machine - Handle the state machine
- * @work: work_struct that describes the work to be done
- */
-void phy_state_machine(struct work_struct *work)
-{
- struct delayed_work *dwork = to_delayed_work(work);
- struct phy_device *phydev =
- container_of(dwork, struct phy_device, state_queue);
- struct net_device *dev = phydev->attached_dev;
- bool needs_aneg = false, do_suspend = false;
- enum phy_state old_state;
- const void *func = NULL;
- bool finished = false;
- int err = 0;
-
- mutex_lock(&phydev->lock);
-
- old_state = phydev->state;
-
- switch (phydev->state) {
- case PHY_DOWN:
- case PHY_READY:
- break;
- case PHY_UP:
- needs_aneg = true;
-
- break;
- case PHY_NOLINK:
- case PHY_RUNNING:
- err = phy_check_link_status(phydev);
- func = &phy_check_link_status;
- break;
- case PHY_CABLETEST:
- err = phydev->drv->cable_test_get_status(phydev, &finished);
- if (err) {
- phy_abort_cable_test(phydev);
- netif_testing_off(dev);
- needs_aneg = true;
- phydev->state = PHY_UP;
- break;
- }
-
- if (finished) {
- ethnl_cable_test_finished(phydev);
- netif_testing_off(dev);
- needs_aneg = true;
- phydev->state = PHY_UP;
- }
- break;
- case PHY_HALTED:
- case PHY_ERROR:
- if (phydev->link) {
- phydev->link = 0;
- phy_link_down(phydev);
- }
- do_suspend = true;
- break;
- }
-
- mutex_unlock(&phydev->lock);
-
- if (needs_aneg) {
- err = phy_start_aneg(phydev);
- func = &phy_start_aneg;
- } else if (do_suspend) {
- phy_suspend(phydev);
- }
-
- if (err == -ENODEV)
- return;
-
- if (err < 0)
- phy_error_precise(phydev, func, err);
-
- phy_process_state_change(phydev, old_state);
-
- /* Only re-schedule a PHY state machine change if we are polling the
- * PHY, if PHY_MAC_INTERRUPT is set, then we will be moving
- * between states from phy_mac_interrupt().
- *
- * In state PHY_HALTED the PHY gets suspended, so rescheduling the
- * state machine would be pointless and possibly error prone when
- * called from phy_disconnect() synchronously.
- */
- mutex_lock(&phydev->lock);
- if (phy_polling_mode(phydev) && phy_is_started(phydev))
- phy_queue_state_machine(phydev, PHY_STATE_TIME);
- mutex_unlock(&phydev->lock);
-}
-
-/**
* phy_mac_interrupt - MAC says the link has changed
* @phydev: phy_device struct with changed link
*
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index b5f012619e..25c19496a3 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -257,7 +257,8 @@ static int phylink_interface_max_speed(phy_interface_t interface)
* Set all possible pause, speed and duplex linkmodes in @linkmodes that are
* supported by the @caps. @linkmodes must have been initialised previously.
*/
-void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps)
+static void phylink_caps_to_linkmodes(unsigned long *linkmodes,
+ unsigned long caps)
{
if (caps & MAC_SYM_PAUSE)
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes);
@@ -400,7 +401,6 @@ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps)
__set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes);
}
}
-EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes);
static struct {
unsigned long mask;
@@ -477,9 +477,9 @@ static unsigned long phylink_cap_from_speed_duplex(int speed,
* Get the MAC capabilities that are supported by the @interface mode and
* @mac_capabilities.
*/
-unsigned long phylink_get_capabilities(phy_interface_t interface,
- unsigned long mac_capabilities,
- int rate_matching)
+static unsigned long phylink_get_capabilities(phy_interface_t interface,
+ unsigned long mac_capabilities,
+ int rate_matching)
{
int max_speed = phylink_interface_max_speed(interface);
unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
@@ -606,7 +606,6 @@ unsigned long phylink_get_capabilities(phy_interface_t interface,
return (caps & mac_capabilities) | matched_caps;
}
-EXPORT_SYMBOL_GPL(phylink_get_capabilities);
/**
* phylink_validate_mask_caps() - Restrict link modes based on caps
@@ -618,9 +617,9 @@ EXPORT_SYMBOL_GPL(phylink_get_capabilities);
* @supported and @state based on that. Use this function if your capabiliies
* aren't constant, such as if they vary depending on the interface.
*/
-void phylink_validate_mask_caps(unsigned long *supported,
- struct phylink_link_state *state,
- unsigned long mac_capabilities)
+static void phylink_validate_mask_caps(unsigned long *supported,
+ struct phylink_link_state *state,
+ unsigned long mac_capabilities)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
unsigned long caps;
@@ -634,29 +633,12 @@ void phylink_validate_mask_caps(unsigned long *supported,
linkmode_and(supported, supported, mask);
linkmode_and(state->advertising, state->advertising, mask);
}
-EXPORT_SYMBOL_GPL(phylink_validate_mask_caps);
-
-/**
- * phylink_generic_validate() - generic validate() callback implementation
- * @config: a pointer to a &struct phylink_config.
- * @supported: ethtool bitmask for supported link modes.
- * @state: a pointer to a &struct phylink_link_state.
- *
- * Generic implementation of the validate() callback that MAC drivers can
- * use when they pass the range of supported interfaces and MAC capabilities.
- */
-void phylink_generic_validate(struct phylink_config *config,
- unsigned long *supported,
- struct phylink_link_state *state)
-{
- phylink_validate_mask_caps(supported, state, config->mac_capabilities);
-}
-EXPORT_SYMBOL_GPL(phylink_generic_validate);
static int phylink_validate_mac_and_pcs(struct phylink *pl,
unsigned long *supported,
struct phylink_link_state *state)
{
+ unsigned long capabilities;
struct phylink_pcs *pcs;
int ret;
@@ -696,10 +678,13 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl,
}
/* Then validate the link parameters with the MAC */
- if (pl->mac_ops->validate)
- pl->mac_ops->validate(pl->config, supported, state);
+ if (pl->mac_ops->mac_get_caps)
+ capabilities = pl->mac_ops->mac_get_caps(pl->config,
+ state->interface);
else
- phylink_generic_validate(pl->config, supported, state);
+ capabilities = pl->config->mac_capabilities;
+
+ phylink_validate_mask_caps(supported, state, capabilities);
return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
}
@@ -3742,3 +3727,4 @@ static int __init phylink_init(void)
module_init(phylink_init);
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("phylink models the MAC to optional PHY connection");
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 894172a3e1..337899c697 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -421,9 +421,11 @@ static int rtl8211f_config_init(struct phy_device *phydev)
ERR_PTR(ret));
return ret;
}
+
+ return genphy_soft_reset(phydev);
}
- return genphy_soft_reset(phydev);
+ return 0;
}
static int rtl821x_suspend(struct phy_device *phydev)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 3679a43f4e..5468bd209f 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -257,6 +257,7 @@ struct sfp {
unsigned int state_hw_drive;
unsigned int state_hw_mask;
unsigned int state_soft_mask;
+ unsigned int state_ignore_mask;
unsigned int state;
struct delayed_work poll;
@@ -280,7 +281,6 @@ struct sfp {
unsigned int rs_state_mask;
bool have_a2;
- bool tx_fault_ignore;
const struct sfp_quirk *quirk;
@@ -345,9 +345,24 @@ static void sfp_fixup_long_startup(struct sfp *sfp)
sfp->module_t_start_up = T_START_UP_BAD_GPON;
}
+static void sfp_fixup_ignore_los(struct sfp *sfp)
+{
+ /* This forces LOS to zero, so we ignore transitions */
+ sfp->state_ignore_mask |= SFP_F_LOS;
+ /* Make sure that LOS options are clear */
+ sfp->id.ext.options &= ~cpu_to_be16(SFP_OPTIONS_LOS_INVERTED |
+ SFP_OPTIONS_LOS_NORMAL);
+}
+
static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
{
- sfp->tx_fault_ignore = true;
+ sfp->state_ignore_mask |= SFP_F_TX_FAULT;
+}
+
+static void sfp_fixup_nokia(struct sfp *sfp)
+{
+ sfp_fixup_long_startup(sfp);
+ sfp_fixup_ignore_los(sfp);
}
// For 10GBASE-T short-reach modules
@@ -446,7 +461,7 @@ static const struct sfp_quirk sfp_quirks[] = {
// Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd
// NRZ in their EEPROM
SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
- sfp_fixup_long_startup),
+ sfp_fixup_nokia),
// Fiberstore SFP-10G-T doesn't identify as copper, and uses the
// Rollball protocol to talk to the PHY.
@@ -792,7 +807,8 @@ static void sfp_soft_start_poll(struct sfp *sfp)
mutex_lock(&sfp->st_mutex);
// Poll the soft state for hardware pins we want to ignore
- sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
+ sfp->state_soft_mask = ~sfp->state_hw_mask & ~sfp->state_ignore_mask &
+ mask;
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
!sfp->need_poll)
@@ -2317,7 +2333,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
sfp->module_t_start_up = T_START_UP;
sfp->module_t_wait = T_WAIT;
- sfp->tx_fault_ignore = false;
+ sfp->state_ignore_mask = 0;
if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
@@ -2340,6 +2356,8 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
if (sfp->quirk && sfp->quirk->fixup)
sfp->quirk->fixup(sfp);
+
+ sfp->state_hw_mask &= ~sfp->state_ignore_mask;
mutex_unlock(&sfp->st_mutex);
return 0;
@@ -2841,10 +2859,7 @@ static void sfp_check_state(struct sfp *sfp)
mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp);
changed = state ^ sfp->state;
- if (sfp->tx_fault_ignore)
- changed &= SFP_F_PRESENT | SFP_F_LOS;
- else
- changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
+ changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
for (i = 0; i < GPIO_MAX; i++)
if (changed & BIT(i))
@@ -3138,3 +3153,4 @@ module_exit(sfp_exit);
MODULE_ALIAS("platform:sfp");
MODULE_AUTHOR("Russell King");
MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SFP cage support");
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index c88edb19d2..1c7306a1af 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -507,10 +507,8 @@ static void smsc_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) {
- strncpy(data + i * ETH_GSTRING_LEN,
- smsc_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)
+ ethtool_sprintf(&data, "%s", smsc_hw_stats[i].string);
}
static u64 smsc_get_stat(struct phy_device *phydev, int i)