summaryrefslogtreecommitdiff
path: root/drivers/net/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig1
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/amd.c1
-rw-r--r--drivers/net/phy/aquantia.c4
-rw-r--r--drivers/net/phy/at803x.c125
-rw-r--r--drivers/net/phy/bcm-phy-lib.c8
-rw-r--r--drivers/net/phy/bcm63xx.c2
-rw-r--r--drivers/net/phy/bcm7xxx.c57
-rw-r--r--drivers/net/phy/bcm87xx.c11
-rw-r--r--drivers/net/phy/broadcom.c12
-rw-r--r--drivers/net/phy/cicada.c2
-rw-r--r--drivers/net/phy/davicom.c4
-rw-r--r--drivers/net/phy/dp83640.c25
-rw-r--r--drivers/net/phy/dp83848.c2
-rw-r--r--drivers/net/phy/dp83867.c17
-rw-r--r--drivers/net/phy/et1011c.c1
-rw-r--r--drivers/net/phy/fixed_phy.c14
-rw-r--r--drivers/net/phy/icplus.c21
-rw-r--r--drivers/net/phy/lxt.c4
-rw-r--r--drivers/net/phy/marvell.c168
-rw-r--r--drivers/net/phy/mdio-bcm-unimac.c11
-rw-r--r--drivers/net/phy/mdio-gpio.c2
-rw-r--r--drivers/net/phy/mdio-moxart.c7
-rw-r--r--drivers/net/phy/mdio-mux.c3
-rw-r--r--drivers/net/phy/mdio-octeon.c14
-rw-r--r--drivers/net/phy/mdio-sun4i.c12
-rw-r--r--drivers/net/phy/mdio_bus.c294
-rw-r--r--drivers/net/phy/mdio_device.c171
-rw-r--r--drivers/net/phy/micrel.c177
-rw-r--r--drivers/net/phy/microchip.c11
-rw-r--r--drivers/net/phy/national.c1
-rw-r--r--drivers/net/phy/phy.c108
-rw-r--r--drivers/net/phy/phy_device.c343
-rw-r--r--drivers/net/phy/qsemi.c1
-rw-r--r--drivers/net/phy/realtek.c5
-rw-r--r--drivers/net/phy/smsc.c84
-rw-r--r--drivers/net/phy/ste10Xp.c2
-rw-r--r--drivers/net/phy/teranetics.c1
-rw-r--r--drivers/net/phy/vitesse.c8
39 files changed, 1166 insertions, 570 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 60994a83a..f0a770200 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -186,6 +186,7 @@ config MDIO_GPIO
config MDIO_OCTEON
tristate "Support for MDIO buses on Octeon and ThunderX SOCs"
depends on 64BIT
+ depends on HAS_IOMEM
help
This module provides a driver for the Octeon and ThunderX MDIO
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index f31a4e25c..680e88f99 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -1,6 +1,6 @@
# Makefile for Linux PHY drivers
-libphy-objs := phy.o phy_device.o mdio_bus.o
+libphy-objs := phy.o phy_device.o mdio_bus.o mdio_device.o
obj-$(CONFIG_PHYLIB) += libphy.o
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
diff --git a/drivers/net/phy/amd.c b/drivers/net/phy/amd.c
index 65a488f82..18141c022 100644
--- a/drivers/net/phy/amd.c
+++ b/drivers/net/phy/amd.c
@@ -72,7 +72,6 @@ static struct phy_driver am79c_driver[] = { {
.read_status = genphy_read_status,
.ack_interrupt = am79c_ack_interrupt,
.config_intr = am79c_config_intr,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(am79c_driver);
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index f1936b7a7..09b0b0aa8 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -128,7 +128,6 @@ static struct phy_driver aquantia_driver[] = {
.config_intr = aquantia_config_intr,
.ack_interrupt = aquantia_ack_interrupt,
.read_status = aquantia_read_status,
- .driver = { .owner = THIS_MODULE,},
},
{
.phy_id = PHY_ID_AQ2104,
@@ -141,7 +140,6 @@ static struct phy_driver aquantia_driver[] = {
.config_intr = aquantia_config_intr,
.ack_interrupt = aquantia_ack_interrupt,
.read_status = aquantia_read_status,
- .driver = { .owner = THIS_MODULE,},
},
{
.phy_id = PHY_ID_AQR105,
@@ -154,7 +152,6 @@ static struct phy_driver aquantia_driver[] = {
.config_intr = aquantia_config_intr,
.ack_interrupt = aquantia_ack_interrupt,
.read_status = aquantia_read_status,
- .driver = { .owner = THIS_MODULE,},
},
{
.phy_id = PHY_ID_AQR405,
@@ -167,7 +164,6 @@ static struct phy_driver aquantia_driver[] = {
.config_intr = aquantia_config_intr,
.ack_interrupt = aquantia_ack_interrupt,
.read_status = aquantia_read_status,
- .driver = { .owner = THIS_MODULE,},
},
};
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 2d020a3ec..2174ec937 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -20,10 +20,21 @@
#include <linux/gpio/consumer.h>
#define AT803X_INTR_ENABLE 0x12
+#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
+#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
+#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
+#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
+#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
+#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
+#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
+#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
+#define AT803X_INTR_ENABLE_WOL BIT(0)
+
#define AT803X_INTR_STATUS 0x13
+
#define AT803X_SMART_SPEED 0x14
#define AT803X_LED_CONTROL 0x18
-#define AT803X_WOL_ENABLE 0x01
+
#define AT803X_DEVICE_ADDR 0x03
#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
@@ -31,13 +42,15 @@
#define AT803X_MMD_ACCESS_CONTROL 0x0D
#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
#define AT803X_FUNC_DATA 0x4003
-#define AT803X_INER 0x0012
-#define AT803X_INER_INIT 0xec00
-#define AT803X_INSR 0x0013
+
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
-#define AT803X_DEBUG_SYSTEM_MODE_CTRL 0x05
-#define AT803X_DEBUG_RGMII_TX_CLK_DLY BIT(8)
+
+#define AT803X_DEBUG_REG_0 0x00
+#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
+
+#define AT803X_DEBUG_REG_5 0x05
+#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
@@ -61,6 +74,46 @@ struct at803x_context {
u16 led_control;
};
+static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
+{
+ int ret;
+
+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
+ if (ret < 0)
+ return ret;
+
+ return phy_read(phydev, AT803X_DEBUG_DATA);
+}
+
+static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
+ u16 clear, u16 set)
+{
+ u16 val;
+ int ret;
+
+ ret = at803x_debug_reg_read(phydev, reg);
+ if (ret < 0)
+ return ret;
+
+ val = ret & 0xffff;
+ val &= ~clear;
+ val |= set;
+
+ return phy_write(phydev, AT803X_DEBUG_DATA, val);
+}
+
+static inline int at803x_enable_rx_delay(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
+ AT803X_DEBUG_RX_CLK_DLY_EN);
+}
+
+static inline int at803x_enable_tx_delay(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
+ AT803X_DEBUG_TX_CLK_DLY_EN);
+}
+
/* save relevant PHY registers to private copy */
static void at803x_context_save(struct phy_device *phydev,
struct at803x_context *context)
@@ -119,14 +172,14 @@ static int at803x_set_wol(struct phy_device *phydev,
}
value = phy_read(phydev, AT803X_INTR_ENABLE);
- value |= AT803X_WOL_ENABLE;
+ value |= AT803X_INTR_ENABLE_WOL;
ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
if (ret)
return ret;
value = phy_read(phydev, AT803X_INTR_STATUS);
} else {
value = phy_read(phydev, AT803X_INTR_ENABLE);
- value &= (~AT803X_WOL_ENABLE);
+ value &= (~AT803X_INTR_ENABLE_WOL);
ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
if (ret)
return ret;
@@ -145,7 +198,7 @@ static void at803x_get_wol(struct phy_device *phydev,
wol->wolopts = 0;
value = phy_read(phydev, AT803X_INTR_ENABLE);
- if (value & AT803X_WOL_ENABLE)
+ if (value & AT803X_INTR_ENABLE_WOL)
wol->wolopts |= WAKE_MAGIC;
}
@@ -157,7 +210,7 @@ static int at803x_suspend(struct phy_device *phydev)
mutex_lock(&phydev->lock);
value = phy_read(phydev, AT803X_INTR_ENABLE);
- wol_enabled = value & AT803X_WOL_ENABLE;
+ wol_enabled = value & AT803X_INTR_ENABLE_WOL;
value = phy_read(phydev, MII_BMCR);
@@ -190,7 +243,7 @@ static int at803x_resume(struct phy_device *phydev)
static int at803x_probe(struct phy_device *phydev)
{
- struct device *dev = &phydev->dev;
+ struct device *dev = &phydev->mdio.dev;
struct at803x_priv *priv;
struct gpio_desc *gpiod_reset;
@@ -217,14 +270,17 @@ static int at803x_config_init(struct phy_device *phydev)
if (ret < 0)
return ret;
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
- ret = phy_write(phydev, AT803X_DEBUG_ADDR,
- AT803X_DEBUG_SYSTEM_MODE_CTRL);
- if (ret)
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ ret = at803x_enable_rx_delay(phydev);
+ if (ret < 0)
return ret;
- ret = phy_write(phydev, AT803X_DEBUG_DATA,
- AT803X_DEBUG_RGMII_TX_CLK_DLY);
- if (ret)
+ }
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ ret = at803x_enable_tx_delay(phydev);
+ if (ret < 0)
return ret;
}
@@ -235,7 +291,7 @@ static int at803x_ack_interrupt(struct phy_device *phydev)
{
int err;
- err = phy_read(phydev, AT803X_INSR);
+ err = phy_read(phydev, AT803X_INTR_STATUS);
return (err < 0) ? err : 0;
}
@@ -245,13 +301,19 @@ static int at803x_config_intr(struct phy_device *phydev)
int err;
int value;
- value = phy_read(phydev, AT803X_INER);
+ value = phy_read(phydev, AT803X_INTR_ENABLE);
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
+ value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
+ value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
+ value |= AT803X_INTR_ENABLE_LINK_FAIL;
+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
- err = phy_write(phydev, AT803X_INER,
- value | AT803X_INER_INIT);
+ err = phy_write(phydev, AT803X_INTR_ENABLE, value);
+ }
else
- err = phy_write(phydev, AT803X_INER, 0);
+ err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
return err;
}
@@ -281,8 +343,8 @@ static void at803x_link_change_notify(struct phy_device *phydev)
at803x_context_restore(phydev, &context);
- dev_dbg(&phydev->dev, "%s(): phy was reset\n",
- __func__);
+ phydev_dbg(phydev, "%s(): phy was reset\n",
+ __func__);
priv->phy_reset = true;
}
} else {
@@ -310,9 +372,6 @@ static struct phy_driver at803x_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = at803x_ack_interrupt,
.config_intr = at803x_config_intr,
- .driver = {
- .owner = THIS_MODULE,
- },
}, {
/* ATHEROS 8030 */
.phy_id = ATH8030_PHY_ID,
@@ -325,15 +384,12 @@ static struct phy_driver at803x_driver[] = {
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
- .features = PHY_GBIT_FEATURES,
+ .features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = at803x_ack_interrupt,
.config_intr = at803x_config_intr,
- .driver = {
- .owner = THIS_MODULE,
- },
}, {
/* ATHEROS 8031 */
.phy_id = ATH8031_PHY_ID,
@@ -352,9 +408,6 @@ static struct phy_driver at803x_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = &at803x_ack_interrupt,
.config_intr = &at803x_config_intr,
- .driver = {
- .owner = THIS_MODULE,
- },
} };
module_phy_driver(at803x_driver);
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index ddb377e53..df0416db0 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -184,25 +184,25 @@ int bcm_phy_enable_eee(struct phy_device *phydev)
/* Enable EEE at PHY level */
val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
- MDIO_MMD_AN, phydev->addr);
+ MDIO_MMD_AN);
if (val < 0)
return val;
val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
- MDIO_MMD_AN, phydev->addr, (u32)val);
+ MDIO_MMD_AN, (u32)val);
/* Advertise EEE */
val = phy_read_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
- MDIO_MMD_AN, phydev->addr);
+ MDIO_MMD_AN);
if (val < 0)
return val;
val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
- MDIO_MMD_AN, phydev->addr, (u32)val);
+ MDIO_MMD_AN, (u32)val);
return 0;
}
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index 86b28052b..e741bf614 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -56,7 +56,6 @@ static struct phy_driver bcm63xx_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
/* same phy as above, with just a different OUI */
.phy_id = 0x002bdc00,
@@ -69,7 +68,6 @@ static struct phy_driver bcm63xx_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
} };
module_phy_driver(bcm63xx_driver);
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 03d4809a9..db507e3bc 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -170,7 +170,7 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
int ret = 0;
pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
- dev_name(&phydev->dev), phydev->drv->name, rev, patch);
+ phydev_name(phydev), phydev->drv->name, rev, patch);
/* Dummy read to a register to workaround an issue upon reset where the
* internal inverter may not allow the first MDIO transaction to pass
@@ -250,10 +250,6 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
phy_read(phydev, MII_BCM7XXX_AUX_MODE);
- /* Workaround only required for 100Mbits/sec capable PHYs */
- if (phydev->supported & PHY_GBIT_FEATURES)
- return 0;
-
/* set shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
@@ -270,7 +266,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
/* reset shadow mode 2 */
- ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
+ ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
if (ret < 0)
return ret;
@@ -307,11 +303,6 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
return 0;
}
-static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
-{
- return 0;
-}
-
#define BCM7XXX_28NM_GPHY(_oui, _name) \
{ \
.phy_id = (_oui), \
@@ -324,7 +315,6 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
.config_aneg = genphy_config_aneg, \
.read_status = genphy_read_status, \
.resume = bcm7xxx_28nm_resume, \
- .driver = { .owner = THIS_MODULE }, \
}
static struct phy_driver bcm7xxx_driver[] = {
@@ -338,7 +328,7 @@ static struct phy_driver bcm7xxx_driver[] = {
.phy_id = PHY_ID_BCM7425,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM7425",
- .features = PHY_GBIT_FEATURES |
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_IS_INTERNAL,
.config_init = bcm7xxx_config_init,
@@ -346,12 +336,11 @@ static struct phy_driver bcm7xxx_driver[] = {
.read_status = genphy_read_status,
.suspend = bcm7xxx_suspend,
.resume = bcm7xxx_config_init,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM7429,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM7429",
- .features = PHY_GBIT_FEATURES |
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_IS_INTERNAL,
.config_init = bcm7xxx_config_init,
@@ -359,33 +348,18 @@ static struct phy_driver bcm7xxx_driver[] = {
.read_status = genphy_read_status,
.suspend = bcm7xxx_suspend,
.resume = bcm7xxx_config_init,
- .driver = { .owner = THIS_MODULE },
-}, {
- .phy_id = PHY_BCM_OUI_4,
- .phy_id_mask = 0xffff0000,
- .name = "Broadcom BCM7XXX 40nm",
- .features = PHY_GBIT_FEATURES |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .suspend = bcm7xxx_suspend,
- .resume = bcm7xxx_config_init,
- .driver = { .owner = THIS_MODULE },
}, {
- .phy_id = PHY_BCM_OUI_5,
- .phy_id_mask = 0xffffff00,
- .name = "Broadcom BCM7XXX 65nm",
- .features = PHY_BASIC_FEATURES |
+ .phy_id = PHY_ID_BCM7435,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM7435",
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_dummy_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .suspend = bcm7xxx_suspend,
- .resume = bcm7xxx_config_init,
- .driver = { .owner = THIS_MODULE },
+ .flags = PHY_IS_INTERNAL,
+ .config_init = bcm7xxx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .suspend = bcm7xxx_suspend,
+ .resume = bcm7xxx_config_init,
} };
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
@@ -395,9 +369,8 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
{ PHY_ID_BCM7425, 0xfffffff0, },
{ PHY_ID_BCM7429, 0xfffffff0, },
{ PHY_ID_BCM7439, 0xfffffff0, },
+ { PHY_ID_BCM7435, 0xfffffff0, },
{ PHY_ID_BCM7445, 0xfffffff0, },
- { PHY_BCM_OUI_4, 0xffff0000 },
- { PHY_BCM_OUI_5, 0xffffff00 },
{ }
};
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index 1eca20452..f7ebdcff5 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -40,10 +40,10 @@ static int bcm87xx_of_reg_init(struct phy_device *phydev)
const __be32 *paddr_end;
int len, ret;
- if (!phydev->dev.of_node)
+ if (!phydev->mdio.dev.of_node)
return 0;
- paddr = of_get_property(phydev->dev.of_node,
+ paddr = of_get_property(phydev->mdio.dev.of_node,
"broadcom,c45-reg-init", &len);
if (!paddr)
return 0;
@@ -163,8 +163,9 @@ static int bcm87xx_did_interrupt(struct phy_device *phydev)
reg = phy_read(phydev, BCM87XX_LASI_STATUS);
if (reg < 0) {
- dev_err(&phydev->dev,
- "Error: Read of BCM87XX_LASI_STATUS failed: %d\n", reg);
+ phydev_err(phydev,
+ "Error: Read of BCM87XX_LASI_STATUS failed: %d\n",
+ reg);
return 0;
}
return (reg & 1) != 0;
@@ -200,7 +201,6 @@ static struct phy_driver bcm87xx_driver[] = {
.config_intr = bcm87xx_config_intr,
.did_interrupt = bcm87xx_did_interrupt,
.match_phy_device = bcm8706_match_phy_device,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM8727,
.phy_id_mask = 0xffffffff,
@@ -213,7 +213,6 @@ static struct phy_driver bcm87xx_driver[] = {
.config_intr = bcm87xx_config_intr,
.did_interrupt = bcm87xx_did_interrupt,
.match_phy_device = bcm8727_match_phy_device,
- .driver = { .owner = THIS_MODULE },
} };
module_phy_driver(bcm87xx_driver);
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 3ce5d9514..870327efc 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -460,7 +460,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM5421,
.phy_id_mask = 0xfffffff0,
@@ -473,7 +472,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM5461,
.phy_id_mask = 0xfffffff0,
@@ -486,7 +484,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM54616S,
.phy_id_mask = 0xfffffff0,
@@ -499,7 +496,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM5464,
.phy_id_mask = 0xfffffff0,
@@ -512,7 +508,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM5481,
.phy_id_mask = 0xfffffff0,
@@ -525,7 +520,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM5482,
.phy_id_mask = 0xfffffff0,
@@ -538,7 +532,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = bcm5482_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM50610,
.phy_id_mask = 0xfffffff0,
@@ -551,7 +544,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM50610M,
.phy_id_mask = 0xfffffff0,
@@ -564,7 +556,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM57780,
.phy_id_mask = 0xfffffff0,
@@ -577,7 +568,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCMAC131,
.phy_id_mask = 0xfffffff0,
@@ -590,7 +580,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = brcm_fet_ack_interrupt,
.config_intr = brcm_fet_config_intr,
- .driver = { .owner = THIS_MODULE },
}, {
.phy_id = PHY_ID_BCM5241,
.phy_id_mask = 0xfffffff0,
@@ -603,7 +592,6 @@ static struct phy_driver broadcom_drivers[] = {
.read_status = genphy_read_status,
.ack_interrupt = brcm_fet_ack_interrupt,
.config_intr = brcm_fet_config_intr,
- .driver = { .owner = THIS_MODULE },
} };
module_phy_driver(broadcom_drivers);
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 27f546489..d339c1afe 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -114,7 +114,6 @@ static struct phy_driver cis820x_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &cis820x_ack_interrupt,
.config_intr = &cis820x_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x000fc440,
.name = "Cicada Cis8204",
@@ -126,7 +125,6 @@ static struct phy_driver cis820x_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &cis820x_ack_interrupt,
.config_intr = &cis820x_config_intr,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(cis820x_driver);
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index 2a328703b..36e3e2033 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -156,7 +156,6 @@ static struct phy_driver dm91xx_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = dm9161_ack_interrupt,
.config_intr = dm9161_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x0181b8b0,
.name = "Davicom DM9161B/C",
@@ -168,7 +167,6 @@ static struct phy_driver dm91xx_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = dm9161_ack_interrupt,
.config_intr = dm9161_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x0181b8a0,
.name = "Davicom DM9161A",
@@ -180,7 +178,6 @@ static struct phy_driver dm91xx_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = dm9161_ack_interrupt,
.config_intr = dm9161_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x00181b80,
.name = "Davicom DM9131",
@@ -191,7 +188,6 @@ static struct phy_driver dm91xx_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = dm9161_ack_interrupt,
.config_intr = dm9161_config_intr,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(dm91xx_driver);
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index e6cefd0e3..7a240fce3 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -220,9 +220,10 @@ static void rx_timestamp_work(struct work_struct *work);
#define BROADCAST_ADDR 31
-static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val)
+static inline int broadcast_write(struct phy_device *phydev, u32 regnum,
+ u16 val)
{
- return mdiobus_write(bus, BROADCAST_ADDR, regnum, val);
+ return mdiobus_write(phydev->mdio.bus, BROADCAST_ADDR, regnum, val);
}
/* Caller must hold extreg_lock. */
@@ -232,7 +233,7 @@ static int ext_read(struct phy_device *phydev, int page, u32 regnum)
int val;
if (dp83640->clock->page != page) {
- broadcast_write(phydev->bus, PAGESEL, page);
+ broadcast_write(phydev, PAGESEL, page);
dp83640->clock->page = page;
}
val = phy_read(phydev, regnum);
@@ -247,11 +248,11 @@ static void ext_write(int broadcast, struct phy_device *phydev,
struct dp83640_private *dp83640 = phydev->priv;
if (dp83640->clock->page != page) {
- broadcast_write(phydev->bus, PAGESEL, page);
+ broadcast_write(phydev, PAGESEL, page);
dp83640->clock->page = page;
}
if (broadcast)
- broadcast_write(phydev->bus, regnum, val);
+ broadcast_write(phydev, regnum, val);
else
phy_write(phydev, regnum, val);
}
@@ -1056,7 +1057,7 @@ static int choose_this_phy(struct dp83640_clock *clock,
if (chosen_phy == -1 && !clock->chosen)
return 1;
- if (chosen_phy == phydev->addr)
+ if (chosen_phy == phydev->mdio.addr)
return 1;
return 0;
@@ -1120,10 +1121,10 @@ static int dp83640_probe(struct phy_device *phydev)
struct dp83640_private *dp83640;
int err = -ENOMEM, i;
- if (phydev->addr == BROADCAST_ADDR)
+ if (phydev->mdio.addr == BROADCAST_ADDR)
return 0;
- clock = dp83640_clock_get_bus(phydev->bus);
+ clock = dp83640_clock_get_bus(phydev->mdio.bus);
if (!clock)
goto no_clock;
@@ -1149,7 +1150,8 @@ static int dp83640_probe(struct phy_device *phydev)
if (choose_this_phy(clock, phydev)) {
clock->chosen = dp83640;
- clock->ptp_clock = ptp_clock_register(&clock->caps, &phydev->dev);
+ clock->ptp_clock = ptp_clock_register(&clock->caps,
+ &phydev->mdio.dev);
if (IS_ERR(clock->ptp_clock)) {
err = PTR_ERR(clock->ptp_clock);
goto no_register;
@@ -1175,7 +1177,7 @@ static void dp83640_remove(struct phy_device *phydev)
struct list_head *this, *next;
struct dp83640_private *tmp, *dp83640 = phydev->priv;
- if (phydev->addr == BROADCAST_ADDR)
+ if (phydev->mdio.addr == BROADCAST_ADDR)
return;
enable_status_frames(phydev, false);
@@ -1507,12 +1509,11 @@ static struct phy_driver dp83640_driver = {
.hwtstamp = dp83640_hwtstamp,
.rxtstamp = dp83640_rxtstamp,
.txtstamp = dp83640_txtstamp,
- .driver = {.owner = THIS_MODULE,}
};
static int __init dp83640_init(void)
{
- return phy_driver_register(&dp83640_driver);
+ return phy_driver_register(&dp83640_driver, THIS_MODULE);
}
static void __exit dp83640_exit(void)
diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c
index 5ce9bef54..5e14e629c 100644
--- a/drivers/net/phy/dp83848.c
+++ b/drivers/net/phy/dp83848.c
@@ -88,8 +88,6 @@ static struct phy_driver dp83848_driver[] = {
/* IRQ related */
.ack_interrupt = dp83848_ack_interrupt,
.config_intr = dp83848_config_intr,
-
- .driver = { .owner = THIS_MODULE, },
},
};
module_phy_driver(dp83848_driver);
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 32f10662f..2afa61b51 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -103,14 +103,11 @@ static int dp83867_config_intr(struct phy_device *phydev)
static int dp83867_of_init(struct phy_device *phydev)
{
struct dp83867_private *dp83867 = phydev->priv;
- struct device *dev = &phydev->dev;
+ struct device *dev = &phydev->mdio.dev;
struct device_node *of_node = dev->of_node;
int ret;
- if (!of_node && dev->parent->of_node)
- of_node = dev->parent->of_node;
-
- if (!phydev->dev.of_node)
+ if (!of_node)
return -ENODEV;
ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
@@ -140,7 +137,7 @@ static int dp83867_config_init(struct phy_device *phydev)
u16 val, delay;
if (!phydev->priv) {
- dp83867 = devm_kzalloc(&phydev->dev, sizeof(*dp83867),
+ dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867),
GFP_KERNEL);
if (!dp83867)
return -ENOMEM;
@@ -163,7 +160,7 @@ static int dp83867_config_init(struct phy_device *phydev)
if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
(phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
- DP83867_DEVADDR, phydev->addr);
+ DP83867_DEVADDR);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
@@ -175,13 +172,13 @@ static int dp83867_config_init(struct phy_device *phydev)
val |= DP83867_RGMII_RX_CLK_DELAY_EN;
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
- DP83867_DEVADDR, phydev->addr, val);
+ DP83867_DEVADDR, val);
delay = (dp83867->rx_id_delay |
(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
- DP83867_DEVADDR, phydev->addr, delay);
+ DP83867_DEVADDR, delay);
}
return 0;
@@ -217,8 +214,6 @@ static struct phy_driver dp83867_driver[] = {
.read_status = genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
-
- .driver = {.owner = THIS_MODULE,}
},
};
module_phy_driver(dp83867_driver);
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
index a90774381..a9a4edfa2 100644
--- a/drivers/net/phy/et1011c.c
+++ b/drivers/net/phy/et1011c.c
@@ -95,7 +95,6 @@ static struct phy_driver et1011c_driver[] = { {
.flags = PHY_POLL,
.config_aneg = et1011c_config_aneg,
.read_status = et1011c_read_status,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(et1011c_driver);
diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c
index e23bf5b90..ab9c473d7 100644
--- a/drivers/net/phy/fixed_phy.c
+++ b/drivers/net/phy/fixed_phy.c
@@ -27,7 +27,6 @@
#define MII_REGS_NUM 29
struct fixed_mdio_bus {
- int irqs[PHY_MAX_ADDR];
struct mii_bus *mii_bus;
struct list_head phys;
};
@@ -198,11 +197,11 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp;
- if (!phydev || !phydev->bus)
+ if (!phydev || !phydev->mdio.bus)
return -EINVAL;
list_for_each_entry(fp, &fmb->phys, node) {
- if (fp->addr == phydev->addr) {
+ if (fp->addr == phydev->mdio.addr) {
fp->link_update = link_update;
fp->phydev = phydev;
return 0;
@@ -220,11 +219,11 @@ int fixed_phy_update_state(struct phy_device *phydev,
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp;
- if (!phydev || phydev->bus != fmb->mii_bus)
+ if (!phydev || phydev->mdio.bus != fmb->mii_bus)
return -EINVAL;
list_for_each_entry(fp, &fmb->phys, node) {
- if (fp->addr == phydev->addr) {
+ if (fp->addr == phydev->mdio.addr) {
#define _UPD(x) if (changed->x) \
fp->status.x = status->x
_UPD(link);
@@ -256,7 +255,7 @@ int fixed_phy_add(unsigned int irq, int phy_addr,
memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM);
- fmb->irqs[phy_addr] = irq;
+ fmb->mii_bus->irq[phy_addr] = irq;
fp->addr = phy_addr;
fp->status = *status;
@@ -345,7 +344,7 @@ struct phy_device *fixed_phy_register(unsigned int irq,
}
of_node_get(np);
- phy->dev.of_node = np;
+ phy->mdio.dev.of_node = np;
phy->is_pseudo_fixed_link = true;
switch (status->speed) {
@@ -395,7 +394,6 @@ static int __init fixed_mdio_bus_init(void)
fmb->mii_bus->parent = &pdev->dev;
fmb->mii_bus->read = &fixed_mdio_read;
fmb->mii_bus->write = &fixed_mdio_write;
- fmb->mii_bus->irq = fmb->irqs;
ret = mdiobus_register(fmb->mii_bus);
if (ret)
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 0dbc445a5..e5f251b91 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -53,43 +53,43 @@ static int ip175c_config_init(struct phy_device *phydev)
if (full_reset_performed == 0) {
/* master reset */
- err = mdiobus_write(phydev->bus, 30, 0, 0x175c);
+ err = mdiobus_write(phydev->mdio.bus, 30, 0, 0x175c);
if (err < 0)
return err;
/* ensure no bus delays overlap reset period */
- err = mdiobus_read(phydev->bus, 30, 0);
+ err = mdiobus_read(phydev->mdio.bus, 30, 0);
/* data sheet specifies reset period is 2 msec */
mdelay(2);
/* enable IP175C mode */
- err = mdiobus_write(phydev->bus, 29, 31, 0x175c);
+ err = mdiobus_write(phydev->mdio.bus, 29, 31, 0x175c);
if (err < 0)
return err;
/* Set MII0 speed and duplex (in PHY mode) */
- err = mdiobus_write(phydev->bus, 29, 22, 0x420);
+ err = mdiobus_write(phydev->mdio.bus, 29, 22, 0x420);
if (err < 0)
return err;
/* reset switch ports */
for (i = 0; i < 5; i++) {
- err = mdiobus_write(phydev->bus, i,
+ err = mdiobus_write(phydev->mdio.bus, i,
MII_BMCR, BMCR_RESET);
if (err < 0)
return err;
}
for (i = 0; i < 5; i++)
- err = mdiobus_read(phydev->bus, i, MII_BMCR);
+ err = mdiobus_read(phydev->mdio.bus, i, MII_BMCR);
mdelay(2);
full_reset_performed = 1;
}
- if (phydev->addr != 4) {
+ if (phydev->mdio.addr != 4) {
phydev->state = PHY_RUNNING;
phydev->speed = SPEED_100;
phydev->duplex = DUPLEX_FULL;
@@ -184,7 +184,7 @@ static int ip101a_g_config_init(struct phy_device *phydev)
static int ip175c_read_status(struct phy_device *phydev)
{
- if (phydev->addr == 4) /* WAN port */
+ if (phydev->mdio.addr == 4) /* WAN port */
genphy_read_status(phydev);
else
/* Don't need to read status for switch ports */
@@ -195,7 +195,7 @@ static int ip175c_read_status(struct phy_device *phydev)
static int ip175c_config_aneg(struct phy_device *phydev)
{
- if (phydev->addr == 4) /* WAN port */
+ if (phydev->mdio.addr == 4) /* WAN port */
genphy_config_aneg(phydev);
return 0;
@@ -221,7 +221,6 @@ static struct phy_driver icplus_driver[] = {
.read_status = &ip175c_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x02430d90,
.name = "ICPlus IP1001",
@@ -233,7 +232,6 @@ static struct phy_driver icplus_driver[] = {
.read_status = &genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x02430c54,
.name = "ICPlus IP101A/G",
@@ -247,7 +245,6 @@ static struct phy_driver icplus_driver[] = {
.read_status = &genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(icplus_driver);
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index a3a5a7036..f6078376e 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -278,7 +278,6 @@ static struct phy_driver lxt97x_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = lxt970_ack_interrupt,
.config_intr = lxt970_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x001378e0,
.name = "LXT971",
@@ -289,7 +288,6 @@ static struct phy_driver lxt97x_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = lxt971_ack_interrupt,
.config_intr = lxt971_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x00137a10,
.name = "LXT973-A2",
@@ -299,7 +297,6 @@ static struct phy_driver lxt97x_driver[] = {
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
.read_status = lxt973a2_read_status,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x00137a10,
.name = "LXT973",
@@ -309,7 +306,6 @@ static struct phy_driver lxt97x_driver[] = {
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
.read_status = genphy_read_status,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(lxt97x_driver);
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 0240552b5..ab1d0fcaf 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -137,6 +137,22 @@ MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
+struct marvell_hw_stat {
+ const char *string;
+ u8 page;
+ u8 reg;
+ u8 bits;
+};
+
+static struct marvell_hw_stat marvell_hw_stats[] = {
+ { "phy_receive_errors", 0, 21, 16},
+ { "phy_idle_errors", 0, 10, 8 },
+};
+
+struct marvell_priv {
+ u64 stats[ARRAY_SIZE(marvell_hw_stats)];
+};
+
static int marvell_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -284,10 +300,11 @@ static int marvell_of_reg_init(struct phy_device *phydev)
const __be32 *paddr;
int len, i, saved_page, current_page, page_changed, ret;
- if (!phydev->dev.of_node)
+ if (!phydev->mdio.dev.of_node)
return 0;
- paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
+ paddr = of_get_property(phydev->mdio.dev.of_node,
+ "marvell,reg-init", &len);
if (!paddr || len < (4 * sizeof(*paddr)))
return 0;
@@ -429,6 +446,12 @@ static int m88e1510_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
+ return 0;
+}
+
+static int marvell_config_init(struct phy_device *phydev)
+{
+ /* Set registers from marvell,reg-init DT property */
return marvell_of_reg_init(phydev);
}
@@ -478,7 +501,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
mdelay(500);
- return 0;
+ return marvell_config_init(phydev);
}
static int m88e3016_config_init(struct phy_device *phydev)
@@ -497,7 +520,7 @@ static int m88e3016_config_init(struct phy_device *phydev)
if (reg < 0)
return reg;
- return 0;
+ return marvell_config_init(phydev);
}
static int m88e1111_config_init(struct phy_device *phydev)
@@ -986,20 +1009,91 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w
return 0;
}
+static int marvell_get_sset_count(struct phy_device *phydev)
+{
+ return ARRAY_SIZE(marvell_hw_stats);
+}
+
+static void marvell_get_strings(struct phy_device *phydev, u8 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) {
+ memcpy(data + i * ETH_GSTRING_LEN,
+ marvell_hw_stats[i].string, ETH_GSTRING_LEN);
+ }
+}
+
+#ifndef UINT64_MAX
+#define UINT64_MAX (u64)(~((u64)0))
+#endif
+static u64 marvell_get_stat(struct phy_device *phydev, int i)
+{
+ struct marvell_hw_stat stat = marvell_hw_stats[i];
+ struct marvell_priv *priv = phydev->priv;
+ int err, oldpage;
+ u64 val;
+
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
+ stat.page);
+ if (err < 0)
+ return UINT64_MAX;
+
+ val = phy_read(phydev, stat.reg);
+ if (val < 0) {
+ val = UINT64_MAX;
+ } else {
+ val = val & ((1 << stat.bits) - 1);
+ priv->stats[i] += val;
+ val = priv->stats[i];
+ }
+
+ phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
+
+ return val;
+}
+
+static void marvell_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++)
+ data[i] = marvell_get_stat(phydev, i);
+}
+
+static int marvell_probe(struct phy_device *phydev)
+{
+ struct marvell_priv *priv;
+
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
static struct phy_driver marvell_drivers[] = {
{
.phy_id = MARVELL_PHY_ID_88E1101,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1101",
.features = PHY_GBIT_FEATURES,
+ .probe = marvell_probe,
.flags = PHY_HAS_INTERRUPT,
+ .config_init = &marvell_config_init,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1112,
@@ -1007,6 +1101,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1112",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1111_config_init,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
@@ -1014,7 +1109,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1111,
@@ -1022,6 +1119,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1111",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1111_config_init,
.config_aneg = &marvell_config_aneg,
.read_status = &marvell_read_status,
@@ -1029,7 +1127,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1118,
@@ -1037,6 +1137,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1118",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1118_config_init,
.config_aneg = &m88e1118_config_aneg,
.read_status = &genphy_read_status,
@@ -1044,7 +1145,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = {.owner = THIS_MODULE,},
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1121R,
@@ -1052,6 +1155,8 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1121R",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1121_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1059,7 +1164,9 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1318S,
@@ -1067,6 +1174,8 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1318S",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1318_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1076,7 +1185,9 @@ static struct phy_driver marvell_drivers[] = {
.set_wol = &m88e1318_set_wol,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1145,
@@ -1084,6 +1195,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1145",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1145_config_init,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
@@ -1091,7 +1203,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1149R,
@@ -1099,6 +1213,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1149R",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1149_config_init,
.config_aneg = &m88e1118_config_aneg,
.read_status = &genphy_read_status,
@@ -1106,7 +1221,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1240,
@@ -1114,6 +1231,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1240",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1111_config_init,
.config_aneg = &marvell_config_aneg,
.read_status = &genphy_read_status,
@@ -1121,7 +1239,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1116R,
@@ -1129,6 +1249,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1116R",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_init = &m88e1116r_config_init,
.config_aneg = &genphy_config_aneg,
.read_status = &genphy_read_status,
@@ -1136,7 +1257,9 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1510,
@@ -1144,6 +1267,8 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1510",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1510_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1151,7 +1276,9 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
@@ -1159,6 +1286,8 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E1540",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
+ .config_init = &marvell_config_init,
.config_aneg = &m88e1510_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
@@ -1166,7 +1295,9 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
{
.phy_id = MARVELL_PHY_ID_88E3016,
@@ -1174,6 +1305,7 @@ static struct phy_driver marvell_drivers[] = {
.name = "Marvell 88E3016",
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
+ .probe = marvell_probe,
.config_aneg = &genphy_config_aneg,
.config_init = &m88e3016_config_init,
.aneg_done = &marvell_aneg_done,
@@ -1183,7 +1315,9 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
- .driver = { .owner = THIS_MODULE },
+ .get_sset_count = marvell_get_sset_count,
+ .get_strings = marvell_get_strings,
+ .get_stats = marvell_get_stats,
},
};
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
index 4bde5e728..8c73b2e77 100644
--- a/drivers/net/phy/mdio-bcm-unimac.c
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -200,16 +200,10 @@ static int unimac_mdio_probe(struct platform_device *pdev)
bus->reset = unimac_mdio_reset;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
- bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
- if (!bus->irq) {
- ret = -ENOMEM;
- goto out_mdio_free;
- }
-
ret = of_mdiobus_register(bus, np);
if (ret) {
dev_err(&pdev->dev, "MDIO bus registration failed\n");
- goto out_mdio_irq;
+ goto out_mdio_free;
}
platform_set_drvdata(pdev, priv);
@@ -218,8 +212,6 @@ static int unimac_mdio_probe(struct platform_device *pdev)
return 0;
-out_mdio_irq:
- kfree(bus->irq);
out_mdio_free:
mdiobus_free(bus);
return ret;
@@ -230,7 +222,6 @@ static int unimac_mdio_remove(struct platform_device *pdev)
struct unimac_mdio_priv *priv = platform_get_drvdata(pdev);
mdiobus_unregister(priv->mii_bus);
- kfree(priv->mii_bus->irq);
mdiobus_free(priv->mii_bus);
return 0;
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 95f51d726..27ab63064 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -159,7 +159,7 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
new_bus->phy_mask = pdata->phy_mask;
new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
- new_bus->irq = pdata->irqs;
+ memcpy(new_bus->irq, pdata->irqs, sizeof(new_bus->irq));
new_bus->parent = dev;
if (new_bus->phy_mask == ~0)
diff --git a/drivers/net/phy/mdio-moxart.c b/drivers/net/phy/mdio-moxart.c
index f1fc51f65..5bb56d126 100644
--- a/drivers/net/phy/mdio-moxart.c
+++ b/drivers/net/phy/mdio-moxart.c
@@ -130,13 +130,6 @@ static int moxart_mdio_probe(struct platform_device *pdev)
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d-mii", pdev->name, pdev->id);
bus->parent = &pdev->dev;
- bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
- GFP_KERNEL);
- if (!bus->irq) {
- ret = -ENOMEM;
- goto err_out_free_mdiobus;
- }
-
/* Setting PHY_IGNORE_INTERRUPT here even if it has no effect,
* of_mdiobus_register() sets these PHY_POLL.
* Ideally, the interrupt from MAC controller could be used to
diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c
index 7f8e7662e..308ade0eb 100644
--- a/drivers/net/phy/mdio-mux.c
+++ b/drivers/net/phy/mdio-mux.c
@@ -34,7 +34,6 @@ struct mdio_mux_child_bus {
struct mdio_mux_parent_bus *parent;
struct mdio_mux_child_bus *next;
int bus_number;
- int phy_irq[PHY_MAX_ADDR];
};
/*
@@ -157,7 +156,7 @@ int mdio_mux_init(struct device *dev,
break;
}
cb->mii_bus->priv = cb;
- cb->mii_bus->irq = cb->phy_irq;
+
cb->mii_bus->name = "mdio_mux";
snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%x.%x",
pb->parent_id, v);
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
index fcf4e4df7..47d4f2f26 100644
--- a/drivers/net/phy/mdio-octeon.c
+++ b/drivers/net/phy/mdio-octeon.c
@@ -113,7 +113,6 @@ struct octeon_mdiobus {
resource_size_t mdio_phys;
resource_size_t regsize;
enum octeon_mdiobus_mode mode;
- int phy_irq[PHY_MAX_ADDR];
};
#ifdef CONFIG_CAVIUM_OCTEON_SOC
@@ -268,12 +267,13 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
static int octeon_mdiobus_probe(struct platform_device *pdev)
{
struct octeon_mdiobus *bus;
+ struct mii_bus *mii_bus;
struct resource *res_mem;
union cvmx_smix_en smi_en;
int err = -ENOENT;
- bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
- if (!bus)
+ mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus));
+ if (!mii_bus)
return -ENOMEM;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -282,6 +282,8 @@ static int octeon_mdiobus_probe(struct platform_device *pdev)
return -ENXIO;
}
+ bus = mii_bus->priv;
+ bus->mii_bus = mii_bus;
bus->mdio_phys = res_mem->start;
bus->regsize = resource_size(res_mem);
@@ -298,16 +300,11 @@ static int octeon_mdiobus_probe(struct platform_device *pdev)
return -ENOMEM;
}
- bus->mii_bus = mdiobus_alloc();
- if (!bus->mii_bus)
- goto fail;
-
smi_en.u64 = 0;
smi_en.s.en = 1;
oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
bus->mii_bus->priv = bus;
- bus->mii_bus->irq = bus->phy_irq;
bus->mii_bus->name = "mdio-octeon";
snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base);
bus->mii_bus->parent = &pdev->dev;
@@ -326,7 +323,6 @@ static int octeon_mdiobus_probe(struct platform_device *pdev)
return 0;
fail_register:
mdiobus_free(bus->mii_bus);
-fail:
smi_en.u64 = 0;
oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
return err;
diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c
index 15bc7f9ea..f70522c35 100644
--- a/drivers/net/phy/mdio-sun4i.c
+++ b/drivers/net/phy/mdio-sun4i.c
@@ -96,7 +96,7 @@ static int sun4i_mdio_probe(struct platform_device *pdev)
struct mii_bus *bus;
struct sun4i_mdio_data *data;
struct resource *res;
- int ret, i;
+ int ret;
bus = mdiobus_alloc_size(sizeof(*data));
if (!bus)
@@ -108,16 +108,6 @@ static int sun4i_mdio_probe(struct platform_device *pdev)
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
bus->parent = &pdev->dev;
- bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
- GFP_KERNEL);
- if (!bus->irq) {
- ret = -ENOMEM;
- goto err_out_free_mdiobus;
- }
-
- for (i = 0; i < PHY_MAX_ADDR; i++)
- bus->irq[i] = PHY_POLL;
-
data = bus->priv;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->membase = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 88cb4592b..0cba64f1e 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -38,6 +38,48 @@
#include <asm/irq.h>
+int mdiobus_register_device(struct mdio_device *mdiodev)
+{
+ if (mdiodev->bus->mdio_map[mdiodev->addr])
+ return -EBUSY;
+
+ mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;
+
+ return 0;
+}
+EXPORT_SYMBOL(mdiobus_register_device);
+
+int mdiobus_unregister_device(struct mdio_device *mdiodev)
+{
+ if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
+ return -EINVAL;
+
+ mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(mdiobus_unregister_device);
+
+struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
+{
+ struct mdio_device *mdiodev = bus->mdio_map[addr];
+
+ if (!mdiodev)
+ return NULL;
+
+ if (!(mdiodev->flags & MDIO_DEVICE_FLAG_PHY))
+ return NULL;
+
+ return container_of(mdiodev, struct phy_device, mdio);
+}
+EXPORT_SYMBOL(mdiobus_get_phy);
+
+bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
+{
+ return bus->mdio_map[addr];
+}
+EXPORT_SYMBOL(mdiobus_is_registered_device);
+
/**
* mdiobus_alloc_size - allocate a mii_bus structure
* @size: extra amount of memory to allocate for private storage.
@@ -51,6 +93,7 @@ struct mii_bus *mdiobus_alloc_size(size_t size)
struct mii_bus *bus;
size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN);
size_t alloc_size;
+ int i;
/* If we alloc extra space, it should be aligned */
if (size)
@@ -59,11 +102,16 @@ struct mii_bus *mdiobus_alloc_size(size_t size)
alloc_size = sizeof(*bus);
bus = kzalloc(alloc_size, GFP_KERNEL);
- if (bus) {
- bus->state = MDIOBUS_ALLOCATED;
- if (size)
- bus->priv = (void *)bus + aligned_size;
- }
+ if (!bus)
+ return NULL;
+
+ bus->state = MDIOBUS_ALLOCATED;
+ if (size)
+ bus->priv = (void *)bus + aligned_size;
+
+ /* Initialise the interrupts to polling */
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
return bus;
}
@@ -190,47 +238,48 @@ struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np)
}
EXPORT_SYMBOL(of_mdio_find_bus);
-/* Walk the list of subnodes of a mdio bus and look for a node that matches the
- * phy's address with its 'reg' property. If found, set the of_node pointer for
- * the phy. This allows auto-probed pyh devices to be supplied with information
- * passed in via DT.
+/* Walk the list of subnodes of a mdio bus and look for a node that
+ * matches the mdio device's address with its 'reg' property. If
+ * found, set the of_node pointer for the mdio device. This allows
+ * auto-probed phy devices to be supplied with information passed in
+ * via DT.
*/
-static void of_mdiobus_link_phydev(struct mii_bus *mdio,
- struct phy_device *phydev)
+static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
+ struct mdio_device *mdiodev)
{
- struct device *dev = &phydev->dev;
+ struct device *dev = &mdiodev->dev;
struct device_node *child;
- if (dev->of_node || !mdio->dev.of_node)
+ if (dev->of_node || !bus->dev.of_node)
return;
- for_each_available_child_of_node(mdio->dev.of_node, child) {
+ for_each_available_child_of_node(bus->dev.of_node, child) {
int addr;
int ret;
ret = of_property_read_u32(child, "reg", &addr);
if (ret < 0) {
- dev_err(dev, "%s has invalid PHY address\n",
+ dev_err(dev, "%s has invalid MDIO address\n",
child->full_name);
continue;
}
- /* A PHY must have a reg property in the range [0-31] */
+ /* A MDIO device must have a reg property in the range [0-31] */
if (addr >= PHY_MAX_ADDR) {
- dev_err(dev, "%s PHY address %i is too large\n",
+ dev_err(dev, "%s MDIO address %i is too large\n",
child->full_name, addr);
continue;
}
- if (addr == phydev->addr) {
+ if (addr == mdiodev->addr) {
dev->of_node = child;
return;
}
}
}
#else /* !IS_ENABLED(CONFIG_OF_MDIO) */
-static inline void of_mdiobus_link_phydev(struct mii_bus *mdio,
- struct phy_device *phydev)
+static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
+ struct mdio_device *mdiodev)
{
}
#endif
@@ -243,12 +292,15 @@ static inline void of_mdiobus_link_phydev(struct mii_bus *mdio,
* Description: Called by a bus driver to bring up all the PHYs
* on a given bus, and attach them to the bus. Drivers should use
* mdiobus_register() rather than __mdiobus_register() unless they
- * need to pass a specific owner module.
+ * need to pass a specific owner module. MDIO devices which are not
+ * PHYs will not be brought up by this function. They are expected to
+ * to be explicitly listed in DT and instantiated by of_mdiobus_register().
*
* Returns 0 on success or < 0 on error.
*/
int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{
+ struct mdio_device *mdiodev;
int i, err;
if (NULL == bus || NULL == bus->name ||
@@ -294,11 +346,12 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
error:
while (--i >= 0) {
- struct phy_device *phydev = bus->phy_map[i];
- if (phydev) {
- phy_device_remove(phydev);
- phy_device_free(phydev);
- }
+ mdiodev = bus->mdio_map[i];
+ if (!mdiodev)
+ continue;
+
+ mdiodev->device_remove(mdiodev);
+ mdiodev->device_free(mdiodev);
}
device_del(&bus->dev);
return err;
@@ -307,17 +360,19 @@ EXPORT_SYMBOL(__mdiobus_register);
void mdiobus_unregister(struct mii_bus *bus)
{
+ struct mdio_device *mdiodev;
int i;
BUG_ON(bus->state != MDIOBUS_REGISTERED);
bus->state = MDIOBUS_UNREGISTERED;
for (i = 0; i < PHY_MAX_ADDR; i++) {
- struct phy_device *phydev = bus->phy_map[i];
- if (phydev) {
- phy_device_remove(phydev);
- phy_device_free(phydev);
- }
+ mdiodev = bus->mdio_map[i];
+ if (!mdiodev)
+ continue;
+
+ mdiodev->device_remove(mdiodev);
+ mdiodev->device_free(mdiodev);
}
device_del(&bus->dev);
}
@@ -346,6 +401,18 @@ void mdiobus_free(struct mii_bus *bus)
}
EXPORT_SYMBOL(mdiobus_free);
+/**
+ * mdiobus_scan - scan a bus for MDIO devices.
+ * @bus: mii_bus to scan
+ * @addr: address on bus to scan
+ *
+ * This function scans the MDIO bus, looking for devices which can be
+ * identified using a vendor/product ID in registers 2 and 3. Not all
+ * MDIO devices have such registers, but PHY devices typically
+ * do. Hence this function assumes anything found is a PHY, or can be
+ * treated as a PHY. Other MDIO devices, such as switches, will
+ * probably not be found during the scan.
+ */
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
struct phy_device *phydev;
@@ -359,7 +426,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
* For DT, see if the auto-probed phy has a correspoding child
* in the bus node, and set the of_node pointer in this case.
*/
- of_mdiobus_link_phydev(bus, phydev);
+ of_mdiobus_link_mdiodev(bus, &phydev->mdio);
err = phy_device_register(phydev);
if (err) {
@@ -476,133 +543,56 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
EXPORT_SYMBOL(mdiobus_write);
/**
- * mdio_bus_match - determine if given PHY driver supports the given PHY device
- * @dev: target PHY device
- * @drv: given PHY driver
+ * mdio_bus_match - determine if given MDIO driver supports the given
+ * MDIO device
+ * @dev: target MDIO device
+ * @drv: given MDIO driver
*
- * Description: Given a PHY device, and a PHY driver, return 1 if
- * the driver supports the device. Otherwise, return 0.
+ * Description: Given a MDIO device, and a MDIO driver, return 1 if
+ * the driver supports the device. Otherwise, return 0. This may
+ * require calling the devices own match function, since different classes
+ * of MDIO devices have different match criteria.
*/
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
- struct phy_device *phydev = to_phy_device(dev);
- struct phy_driver *phydrv = to_phy_driver(drv);
- const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
- int i;
+ struct mdio_device *mdio = to_mdio_device(dev);
if (of_driver_match_device(dev, drv))
return 1;
- if (phydrv->match_phy_device)
- return phydrv->match_phy_device(phydev);
-
- if (phydev->is_c45) {
- for (i = 1; i < num_ids; i++) {
- if (!(phydev->c45_ids.devices_in_package & (1 << i)))
- continue;
+ if (mdio->bus_match)
+ return mdio->bus_match(dev, drv);
- if ((phydrv->phy_id & phydrv->phy_id_mask) ==
- (phydev->c45_ids.device_ids[i] &
- phydrv->phy_id_mask))
- return 1;
- }
- return 0;
- } else {
- return (phydrv->phy_id & phydrv->phy_id_mask) ==
- (phydev->phy_id & phydrv->phy_id_mask);
- }
+ return 0;
}
#ifdef CONFIG_PM
-
-static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
-{
- struct device_driver *drv = phydev->dev.driver;
- struct phy_driver *phydrv = to_phy_driver(drv);
- struct net_device *netdev = phydev->attached_dev;
-
- if (!drv || !phydrv->suspend)
- return false;
-
- /* PHY not attached? May suspend if the PHY has not already been
- * suspended as part of a prior call to phy_disconnect() ->
- * phy_detach() -> phy_suspend() because the parent netdev might be the
- * MDIO bus driver and clock gated at this point.
- */
- if (!netdev)
- return !phydev->suspended;
-
- /* Don't suspend PHY if the attched netdev parent may wakeup.
- * The parent may point to a PCI device, as in tg3 driver.
- */
- if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent))
- return false;
-
- /* Also don't suspend PHY if the netdev itself may wakeup. This
- * is the case for devices w/o underlaying pwr. mgmt. aware bus,
- * e.g. SoC devices.
- */
- if (device_may_wakeup(&netdev->dev))
- return false;
-
- return true;
-}
-
static int mdio_bus_suspend(struct device *dev)
{
- struct phy_device *phydev = to_phy_device(dev);
+ struct mdio_device *mdio = to_mdio_device(dev);
- /* We must stop the state machine manually, otherwise it stops out of
- * control, possibly with the phydev->lock held. Upon resume, netdev
- * may call phy routines that try to grab the same lock, and that may
- * lead to a deadlock.
- */
- if (phydev->attached_dev && phydev->adjust_link)
- phy_stop_machine(phydev);
+ if (mdio->pm_ops && mdio->pm_ops->suspend)
+ return mdio->pm_ops->suspend(dev);
- if (!mdio_bus_phy_may_suspend(phydev))
- return 0;
-
- return phy_suspend(phydev);
+ return 0;
}
static int mdio_bus_resume(struct device *dev)
{
- struct phy_device *phydev = to_phy_device(dev);
- int ret;
-
- if (!mdio_bus_phy_may_suspend(phydev))
- goto no_resume;
-
- ret = phy_resume(phydev);
- if (ret < 0)
- return ret;
+ struct mdio_device *mdio = to_mdio_device(dev);
-no_resume:
- if (phydev->attached_dev && phydev->adjust_link)
- phy_start_machine(phydev);
+ if (mdio->pm_ops && mdio->pm_ops->resume)
+ return mdio->pm_ops->resume(dev);
return 0;
}
static int mdio_bus_restore(struct device *dev)
{
- struct phy_device *phydev = to_phy_device(dev);
- struct net_device *netdev = phydev->attached_dev;
- int ret;
-
- if (!netdev)
- return 0;
+ struct mdio_device *mdio = to_mdio_device(dev);
- ret = phy_init_hw(phydev);
- if (ret < 0)
- return ret;
-
- /* The PHY needs to renegotiate. */
- phydev->link = 0;
- phydev->state = PHY_UP;
-
- phy_start_machine(phydev);
+ if (mdio->pm_ops && mdio->pm_ops->restore)
+ return mdio->pm_ops->restore(dev);
return 0;
}
@@ -623,52 +613,10 @@ static const struct dev_pm_ops mdio_bus_pm_ops = {
#endif /* CONFIG_PM */
-static ssize_t
-phy_id_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct phy_device *phydev = to_phy_device(dev);
-
- return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id);
-}
-static DEVICE_ATTR_RO(phy_id);
-
-static ssize_t
-phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct phy_device *phydev = to_phy_device(dev);
- const char *mode = NULL;
-
- if (phy_is_internal(phydev))
- mode = "internal";
- else
- mode = phy_modes(phydev->interface);
-
- return sprintf(buf, "%s\n", mode);
-}
-static DEVICE_ATTR_RO(phy_interface);
-
-static ssize_t
-phy_has_fixups_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct phy_device *phydev = to_phy_device(dev);
-
- return sprintf(buf, "%d\n", phydev->has_fixups);
-}
-static DEVICE_ATTR_RO(phy_has_fixups);
-
-static struct attribute *mdio_dev_attrs[] = {
- &dev_attr_phy_id.attr,
- &dev_attr_phy_interface.attr,
- &dev_attr_phy_has_fixups.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(mdio_dev);
-
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
.pm = MDIO_BUS_PM_OPS,
- .dev_groups = mdio_dev_groups,
};
EXPORT_SYMBOL(mdio_bus_type);
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
new file mode 100644
index 000000000..9c88e6749
--- /dev/null
+++ b/drivers/net/phy/mdio_device.c
@@ -0,0 +1,171 @@
+/* Framework for MDIO devices, other than PHYs.
+ *
+ * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/unistd.h>
+
+void mdio_device_free(struct mdio_device *mdiodev)
+{
+ put_device(&mdiodev->dev);
+}
+EXPORT_SYMBOL(mdio_device_free);
+
+static void mdio_device_release(struct device *dev)
+{
+ kfree(to_mdio_device(dev));
+}
+
+struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
+{
+ struct mdio_device *mdiodev;
+
+ /* We allocate the device, and initialize the default values */
+ mdiodev = kzalloc(sizeof(*mdiodev), GFP_KERNEL);
+ if (!mdiodev)
+ return ERR_PTR(-ENOMEM);
+
+ mdiodev->dev.release = mdio_device_release;
+ mdiodev->dev.parent = &bus->dev;
+ mdiodev->dev.bus = &mdio_bus_type;
+ mdiodev->device_free = mdio_device_free;
+ mdiodev->device_remove = mdio_device_remove;
+ mdiodev->bus = bus;
+ mdiodev->addr = addr;
+
+ dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
+
+ device_initialize(&mdiodev->dev);
+
+ return mdiodev;
+}
+EXPORT_SYMBOL(mdio_device_create);
+
+/**
+ * mdio_device_register - Register the mdio device on the MDIO bus
+ * @mdiodev: mdio_device structure to be added to the MDIO bus
+ */
+int mdio_device_register(struct mdio_device *mdiodev)
+{
+ int err;
+
+ dev_info(&mdiodev->dev, "mdio_device_register\n");
+
+ err = mdiobus_register_device(mdiodev);
+ if (err)
+ return err;
+
+ err = device_add(&mdiodev->dev);
+ if (err) {
+ pr_err("MDIO %d failed to add\n", mdiodev->addr);
+ goto out;
+ }
+
+ return 0;
+
+ out:
+ mdiobus_unregister_device(mdiodev);
+ return err;
+}
+EXPORT_SYMBOL(mdio_device_register);
+
+/**
+ * mdio_device_remove - Remove a previously registered mdio device from the
+ * MDIO bus
+ * @mdiodev: mdio_device structure to remove
+ *
+ * This doesn't free the mdio_device itself, it merely reverses the effects
+ * of mdio_device_register(). Use mdio_device_free() to free the device
+ * after calling this function.
+ */
+void mdio_device_remove(struct mdio_device *mdiodev)
+{
+ device_del(&mdiodev->dev);
+ mdiobus_unregister_device(mdiodev);
+}
+EXPORT_SYMBOL(mdio_device_remove);
+
+/**
+ * mdio_probe - probe an MDIO device
+ * @dev: device to probe
+ *
+ * Description: Take care of setting up the mdio_device structure
+ * and calling the driver to probe the device.
+ */
+static int mdio_probe(struct device *dev)
+{
+ struct mdio_device *mdiodev = to_mdio_device(dev);
+ struct device_driver *drv = mdiodev->dev.driver;
+ struct mdio_driver *mdiodrv = to_mdio_driver(drv);
+ int err = 0;
+
+ if (mdiodrv->probe)
+ err = mdiodrv->probe(mdiodev);
+
+ return err;
+}
+
+static int mdio_remove(struct device *dev)
+{
+ struct mdio_device *mdiodev = to_mdio_device(dev);
+ struct device_driver *drv = mdiodev->dev.driver;
+ struct mdio_driver *mdiodrv = to_mdio_driver(drv);
+
+ if (mdiodrv->remove)
+ mdiodrv->remove(mdiodev);
+
+ return 0;
+}
+
+/**
+ * mdio_driver_register - register an mdio_driver with the MDIO layer
+ * @new_driver: new mdio_driver to register
+ */
+int mdio_driver_register(struct mdio_driver *drv)
+{
+ struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
+ int retval;
+
+ pr_info("mdio_driver_register: %s\n", mdiodrv->driver.name);
+
+ mdiodrv->driver.bus = &mdio_bus_type;
+ mdiodrv->driver.probe = mdio_probe;
+ mdiodrv->driver.remove = mdio_remove;
+
+ retval = driver_register(&mdiodrv->driver);
+ if (retval) {
+ pr_err("%s: Error %d in registering driver\n",
+ mdiodrv->driver.name, retval);
+
+ return retval;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mdio_driver_register);
+
+void mdio_driver_unregister(struct mdio_driver *drv)
+{
+ struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
+
+ driver_unregister(&mdiodrv->driver);
+}
+EXPORT_SYMBOL(mdio_driver_unregister);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index e13ad6cdc..dc85f7095 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -73,6 +73,17 @@
#define PS_TO_REG 200
+struct kszphy_hw_stat {
+ const char *string;
+ u8 reg;
+ u8 bits;
+};
+
+static struct kszphy_hw_stat kszphy_hw_stats[] = {
+ { "phy_receive_errors", 21, 16},
+ { "phy_idle_errors", 10, 8 },
+};
+
struct kszphy_type {
u32 led_mode_reg;
u16 interrupt_level_mask;
@@ -86,6 +97,7 @@ struct kszphy_priv {
int led_mode;
bool rmii_ref_clk_sel;
bool rmii_ref_clk_sel_val;
+ u64 stats[ARRAY_SIZE(kszphy_hw_stats)];
};
static const struct kszphy_type ksz8021_type = {
@@ -212,7 +224,7 @@ static int kszphy_setup_led(struct phy_device *phydev, u32 reg, int val)
rc = phy_write(phydev, reg, temp);
out:
if (rc < 0)
- dev_err(&phydev->dev, "failed to set led mode\n");
+ phydev_err(phydev, "failed to set led mode\n");
return rc;
}
@@ -231,7 +243,7 @@ static int kszphy_broadcast_disable(struct phy_device *phydev)
ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
out:
if (ret)
- dev_err(&phydev->dev, "failed to disable broadcast address\n");
+ phydev_err(phydev, "failed to disable broadcast address\n");
return ret;
}
@@ -251,7 +263,7 @@ static int kszphy_nand_tree_disable(struct phy_device *phydev)
ret & ~KSZPHY_OMSO_NAND_TREE_ON);
out:
if (ret)
- dev_err(&phydev->dev, "failed to disable NAND tree mode\n");
+ phydev_err(phydev, "failed to disable NAND tree mode\n");
return ret;
}
@@ -276,7 +288,8 @@ static int kszphy_config_init(struct phy_device *phydev)
if (priv->rmii_ref_clk_sel) {
ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val);
if (ret) {
- dev_err(&phydev->dev, "failed to set rmii reference clock\n");
+ phydev_err(phydev,
+ "failed to set rmii reference clock\n");
return ret;
}
}
@@ -284,6 +297,17 @@ static int kszphy_config_init(struct phy_device *phydev)
if (priv->led_mode >= 0)
kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode);
+ if (phy_interrupt_is_valid(phydev)) {
+ int ctl = phy_read(phydev, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ ret = phy_write(phydev, MII_BMCR, ctl & ~BMCR_ANENABLE);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
@@ -337,7 +361,7 @@ static int ksz9021_load_values_from_of(struct phy_device *phydev,
static int ksz9021_config_init(struct phy_device *phydev)
{
- const struct device *dev = &phydev->dev;
+ const struct device *dev = &phydev->mdio.dev;
const struct device_node *of_node = dev->of_node;
const struct device *dev_walker;
@@ -345,7 +369,7 @@ static int ksz9021_config_init(struct phy_device *phydev)
* properties in the MAC node. Walk up the tree of devices to
* find a device with an OF node.
*/
- dev_walker = &phydev->dev;
+ dev_walker = &phydev->mdio.dev;
do {
of_node = dev_walker->of_node;
dev_walker = dev_walker->parent;
@@ -458,7 +482,7 @@ static int ksz9031_center_flp_timing(struct phy_device *phydev)
static int ksz9031_config_init(struct phy_device *phydev)
{
- const struct device *dev = &phydev->dev;
+ const struct device *dev = &phydev->mdio.dev;
const struct device_node *of_node = dev->of_node;
static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
static const char *rx_data_skews[4] = {
@@ -470,9 +494,17 @@ static int ksz9031_config_init(struct phy_device *phydev)
"txd2-skew-ps", "txd3-skew-ps"
};
static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
+ const struct device *dev_walker;
- if (!of_node && dev->parent->of_node)
- of_node = dev->parent->of_node;
+ /* The Micrel driver has a deprecated option to place phy OF
+ * properties in the MAC node. Walk up the tree of devices to
+ * find a device with an OF node.
+ */
+ dev_walker = &phydev->mdio.dev;
+ do {
+ of_node = dev_walker->of_node;
+ dev_walker = dev_walker->parent;
+ } while (!of_node && dev_walker);
if (of_node) {
ksz9031_of_load_skew_values(phydev, of_node,
@@ -569,15 +601,75 @@ ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
{
}
+static int kszphy_get_sset_count(struct phy_device *phydev)
+{
+ return ARRAY_SIZE(kszphy_hw_stats);
+}
+
+static void kszphy_get_strings(struct phy_device *phydev, u8 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) {
+ memcpy(data + i * ETH_GSTRING_LEN,
+ kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
+ }
+}
+
+#ifndef UINT64_MAX
+#define UINT64_MAX (u64)(~((u64)0))
+#endif
+static u64 kszphy_get_stat(struct phy_device *phydev, int i)
+{
+ struct kszphy_hw_stat stat = kszphy_hw_stats[i];
+ struct kszphy_priv *priv = phydev->priv;
+ u64 val;
+
+ val = phy_read(phydev, stat.reg);
+ if (val < 0) {
+ val = UINT64_MAX;
+ } else {
+ val = val & ((1 << stat.bits) - 1);
+ priv->stats[i] += val;
+ val = priv->stats[i];
+ }
+
+ return val;
+}
+
+static void kszphy_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++)
+ data[i] = kszphy_get_stat(phydev, i);
+}
+
+static int kszphy_resume(struct phy_device *phydev)
+{
+ int value;
+
+ mutex_lock(&phydev->lock);
+
+ value = phy_read(phydev, MII_BMCR);
+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+ kszphy_config_intr(phydev);
+ mutex_unlock(&phydev->lock);
+
+ return 0;
+}
+
static int kszphy_probe(struct phy_device *phydev)
{
const struct kszphy_type *type = phydev->drv->driver_data;
- const struct device_node *np = phydev->dev.of_node;
+ const struct device_node *np = phydev->mdio.dev.of_node;
struct kszphy_priv *priv;
struct clk *clk;
int ret;
- priv = devm_kzalloc(&phydev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -592,15 +684,15 @@ static int kszphy_probe(struct phy_device *phydev)
priv->led_mode = -1;
if (priv->led_mode > 3) {
- dev_err(&phydev->dev, "invalid led mode: 0x%02x\n",
- priv->led_mode);
+ phydev_err(phydev, "invalid led mode: 0x%02x\n",
+ priv->led_mode);
priv->led_mode = -1;
}
} else {
priv->led_mode = -1;
}
- clk = devm_clk_get(&phydev->dev, "rmii-ref");
+ clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref");
/* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
if (!IS_ERR_OR_NULL(clk)) {
unsigned long rate = clk_get_rate(clk);
@@ -615,7 +707,8 @@ static int kszphy_probe(struct phy_device *phydev)
} else if (rate > 49500000 && rate < 50500000) {
priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz;
} else {
- dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate);
+ phydev_err(phydev, "Clock rate out of range: %ld\n",
+ rate);
return -EINVAL;
}
}
@@ -642,9 +735,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8021,
.phy_id_mask = 0x00ffffff,
@@ -659,9 +754,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8031,
.phy_id_mask = 0x00ffffff,
@@ -676,9 +773,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8041,
.phy_id_mask = 0x00fffff0,
@@ -693,9 +792,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8041RNLI,
.phy_id_mask = 0x00fffff0,
@@ -710,9 +811,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8051,
.phy_id_mask = 0x00fffff0,
@@ -727,9 +830,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8001,
.name = "Micrel KSZ8001 or KS8721",
@@ -743,9 +848,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ8081,
.name = "Micrel KSZ8081 or KSZ8091",
@@ -759,9 +866,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
- .resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
+ .resume = kszphy_resume,
}, {
.phy_id = PHY_ID_KSZ8061,
.name = "Micrel KSZ8061",
@@ -773,9 +882,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_KSZ9021,
.phy_id_mask = 0x000ffffe,
@@ -788,11 +899,13 @@ static struct phy_driver ksphy_driver[] = {
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_mmd_indirect = ksz9021_rd_mmd_phyreg,
.write_mmd_indirect = ksz9021_wr_mmd_phyreg,
- .driver = { .owner = THIS_MODULE, },
}, {
.phy_id = PHY_ID_KSZ9031,
.phy_id_mask = 0x00fffff0,
@@ -805,9 +918,11 @@ static struct phy_driver ksphy_driver[] = {
.read_status = ksz9031_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE, },
}, {
.phy_id = PHY_ID_KSZ8873MLL,
.phy_id_mask = 0x00fffff0,
@@ -817,9 +932,11 @@ static struct phy_driver ksphy_driver[] = {
.config_init = kszphy_config_init,
.config_aneg = ksz8873mll_config_aneg,
.read_status = ksz8873mll_read_status,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE, },
}, {
.phy_id = PHY_ID_KSZ886X,
.phy_id_mask = 0x00fffff0,
@@ -829,9 +946,11 @@ static struct phy_driver ksphy_driver[] = {
.config_init = kszphy_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE, },
} };
module_phy_driver(ksphy_driver);
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index c0a20ebd0..15f820648 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -68,7 +68,7 @@ int lan88xx_suspend(struct phy_device *phydev)
static int lan88xx_probe(struct phy_device *phydev)
{
- struct device *dev = &phydev->dev;
+ struct device *dev = &phydev->mdio.dev;
struct lan88xx_priv *priv;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -78,10 +78,9 @@ static int lan88xx_probe(struct phy_device *phydev)
priv->wolopts = 0;
/* these values can be used to identify internal PHY */
- priv->chip_id = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_ID,
- 3, phydev->addr);
+ priv->chip_id = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_ID, 3);
priv->chip_rev = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_REV,
- 3, phydev->addr);
+ 3);
phydev->priv = priv;
@@ -90,7 +89,7 @@ static int lan88xx_probe(struct phy_device *phydev)
static void lan88xx_remove(struct phy_device *phydev)
{
- struct device *dev = &phydev->dev;
+ struct device *dev = &phydev->mdio.dev;
struct lan88xx_priv *priv = phydev->priv;
if (priv)
@@ -130,8 +129,6 @@ static struct phy_driver microchip_phy_driver[] = {
.suspend = lan88xx_suspend,
.resume = genphy_resume,
.set_wol = lan88xx_set_wol,
-
- .driver = { .owner = THIS_MODULE, }
} };
module_phy_driver(microchip_phy_driver);
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index 0a7b9c7f0..2a1b490bc 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -140,7 +140,6 @@ static struct phy_driver dp83865_driver[] = { {
.read_status = genphy_read_status,
.ack_interrupt = ns_ack_interrupt,
.config_intr = ns_config_intr,
- .driver = {.owner = THIS_MODULE,}
} };
module_phy_driver(dp83865_driver);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 47cd306db..5590b9c18 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -319,7 +319,7 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
u32 speed = ethtool_cmd_speed(cmd);
- if (cmd->phy_address != phydev->addr)
+ if (cmd->phy_address != phydev->mdio.addr)
return -EINVAL;
/* We make sure that we don't pass unsupported values in to the PHY */
@@ -375,7 +375,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
cmd->port = PORT_BNC;
else
cmd->port = PORT_MII;
- cmd->phy_address = phydev->addr;
+ cmd->phy_address = phydev->mdio.addr;
cmd->transceiver = phy_is_internal(phydev) ?
XCVR_INTERNAL : XCVR_EXTERNAL;
cmd->autoneg = phydev->autoneg;
@@ -403,16 +403,17 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCGMIIPHY:
- mii_data->phy_id = phydev->addr;
+ mii_data->phy_id = phydev->mdio.addr;
/* fall through */
case SIOCGMIIREG:
- mii_data->val_out = mdiobus_read(phydev->bus, mii_data->phy_id,
+ mii_data->val_out = mdiobus_read(phydev->mdio.bus,
+ mii_data->phy_id,
mii_data->reg_num);
return 0;
case SIOCSMIIREG:
- if (mii_data->phy_id == phydev->addr) {
+ if (mii_data->phy_id == phydev->mdio.addr) {
switch (mii_data->reg_num) {
case MII_BMCR:
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
@@ -445,10 +446,10 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
}
}
- mdiobus_write(phydev->bus, mii_data->phy_id,
+ mdiobus_write(phydev->mdio.bus, mii_data->phy_id,
mii_data->reg_num, val);
- if (mii_data->phy_id == phydev->addr &&
+ if (mii_data->phy_id == phydev->mdio.addr &&
mii_data->reg_num == MII_BMCR &&
val & BMCR_RESET)
return phy_init_hw(phydev);
@@ -643,7 +644,7 @@ int phy_start_interrupts(struct phy_device *phydev)
if (request_irq(phydev->irq, phy_interrupt, 0, "phy_interrupt",
phydev) < 0) {
pr_warn("%s: Can't get IRQ %d (PHY)\n",
- phydev->bus->name, phydev->irq);
+ phydev->mdio.bus->name, phydev->irq);
phydev->irq = PHY_POLL;
return 0;
}
@@ -691,25 +692,29 @@ void phy_change(struct work_struct *work)
struct phy_device *phydev =
container_of(work, struct phy_device, phy_queue);
- if (phydev->drv->did_interrupt &&
- !phydev->drv->did_interrupt(phydev))
- goto ignore;
+ if (phy_interrupt_is_valid(phydev)) {
+ if (phydev->drv->did_interrupt &&
+ !phydev->drv->did_interrupt(phydev))
+ goto ignore;
- if (phy_disable_interrupts(phydev))
- goto phy_err;
+ if (phy_disable_interrupts(phydev))
+ goto phy_err;
+ }
mutex_lock(&phydev->lock);
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
phydev->state = PHY_CHANGELINK;
mutex_unlock(&phydev->lock);
- atomic_dec(&phydev->irq_disable);
- enable_irq(phydev->irq);
+ if (phy_interrupt_is_valid(phydev)) {
+ atomic_dec(&phydev->irq_disable);
+ enable_irq(phydev->irq);
- /* Reenable interrupts */
- if (PHY_HALTED != phydev->state &&
- phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED))
- goto irq_enable_err;
+ /* Reenable interrupts */
+ if (PHY_HALTED != phydev->state &&
+ phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED))
+ goto irq_enable_err;
+ }
/* reschedule state queue work to run as soon as possible */
cancel_delayed_work_sync(&phydev->state_queue);
@@ -904,10 +909,10 @@ void phy_state_machine(struct work_struct *work)
phydev->adjust_link(phydev->attached_dev);
break;
case PHY_RUNNING:
- /* Only register a CHANGE if we are polling or ignoring
- * interrupts and link changed since latest checking.
+ /* Only register a CHANGE if we are polling and link changed
+ * since latest checking.
*/
- if (!phy_interrupt_is_valid(phydev)) {
+ if (phydev->irq == PHY_POLL) {
old_link = phydev->link;
err = phy_read_status(phydev);
if (err)
@@ -995,18 +1000,25 @@ void phy_state_machine(struct work_struct *work)
if (err < 0)
phy_error(phydev);
- dev_dbg(&phydev->dev, "PHY state change %s -> %s\n",
- phy_state_to_str(old_state), phy_state_to_str(phydev->state));
+ phydev_dbg(phydev, "PHY state change %s -> %s\n",
+ phy_state_to_str(old_state),
+ phy_state_to_str(phydev->state));
- queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
- PHY_STATE_TIME * HZ);
+ /* Only re-schedule a PHY state machine change if we are polling the
+ * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving
+ * between states from phy_mac_interrupt()
+ */
+ if (phydev->irq == PHY_POLL)
+ queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
+ PHY_STATE_TIME * HZ);
}
void phy_mac_interrupt(struct phy_device *phydev, int new_link)
{
- cancel_work_sync(&phydev->phy_queue);
phydev->link = new_link;
- schedule_work(&phydev->phy_queue);
+
+ /* Trigger a state machine change */
+ queue_work(system_power_efficient_wq, &phydev->phy_queue);
}
EXPORT_SYMBOL(phy_mac_interrupt);
@@ -1028,7 +1040,6 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
* @phydev: The PHY device bus
* @prtad: MMD Address
* @devad: MMD DEVAD
- * @addr: PHY address on the MII bus
*
* Description: it reads data from the MMD registers (clause 22 to access to
* clause 45) of the specified phy address.
@@ -1038,14 +1049,14 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Read reg 14 // Read MMD data
*/
-int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
- int devad, int addr)
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, int devad)
{
struct phy_driver *phydrv = phydev->drv;
+ int addr = phydev->mdio.addr;
int value = -1;
if (!phydrv->read_mmd_indirect) {
- struct mii_bus *bus = phydev->bus;
+ struct mii_bus *bus = phydev->mdio.bus;
mutex_lock(&bus->mdio_lock);
mmd_phy_indirect(bus, prtad, devad, addr);
@@ -1065,7 +1076,6 @@ EXPORT_SYMBOL(phy_read_mmd_indirect);
* @phydev: The PHY device
* @prtad: MMD Address
* @devad: MMD DEVAD
- * @addr: PHY address on the MII bus
* @data: data to write in the MMD register
*
* Description: Write data from the MMD registers of the specified
@@ -1077,12 +1087,13 @@ EXPORT_SYMBOL(phy_read_mmd_indirect);
* 3) Write reg 14 // Write MMD data
*/
void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
- int devad, int addr, u32 data)
+ int devad, u32 data)
{
struct phy_driver *phydrv = phydev->drv;
+ int addr = phydev->mdio.addr;
if (!phydrv->write_mmd_indirect) {
- struct mii_bus *bus = phydev->bus;
+ struct mii_bus *bus = phydev->mdio.bus;
mutex_lock(&bus->mdio_lock);
mmd_phy_indirect(bus, prtad, devad, addr);
@@ -1129,7 +1140,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
/* First check if the EEE ability is supported */
eee_cap = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE,
- MDIO_MMD_PCS, phydev->addr);
+ MDIO_MMD_PCS);
if (eee_cap <= 0)
goto eee_exit_err;
@@ -1141,12 +1152,12 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
* the EEE advertising registers.
*/
eee_lp = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE,
- MDIO_MMD_AN, phydev->addr);
+ MDIO_MMD_AN);
if (eee_lp <= 0)
goto eee_exit_err;
eee_adv = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
- MDIO_MMD_AN, phydev->addr);
+ MDIO_MMD_AN);
if (eee_adv <= 0)
goto eee_exit_err;
@@ -1160,15 +1171,13 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
* clock while it is signaling LPI.
*/
int val = phy_read_mmd_indirect(phydev, MDIO_CTRL1,
- MDIO_MMD_PCS,
- phydev->addr);
+ MDIO_MMD_PCS);
if (val < 0)
return val;
val |= MDIO_PCS_CTRL1_CLKSTOP_EN;
phy_write_mmd_indirect(phydev, MDIO_CTRL1,
- MDIO_MMD_PCS, phydev->addr,
- val);
+ MDIO_MMD_PCS, val);
}
return 0; /* EEE supported */
@@ -1187,8 +1196,7 @@ EXPORT_SYMBOL(phy_init_eee);
*/
int phy_get_eee_err(struct phy_device *phydev)
{
- return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR,
- MDIO_MMD_PCS, phydev->addr);
+ return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS);
}
EXPORT_SYMBOL(phy_get_eee_err);
@@ -1205,22 +1213,19 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
int val;
/* Get Supported EEE */
- val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE,
- MDIO_MMD_PCS, phydev->addr);
+ val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS);
if (val < 0)
return val;
data->supported = mmd_eee_cap_to_ethtool_sup_t(val);
/* Get advertisement EEE */
- val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
- MDIO_MMD_AN, phydev->addr);
+ val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN);
if (val < 0)
return val;
data->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
/* Get LP advertisement EEE */
- val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE,
- MDIO_MMD_AN, phydev->addr);
+ val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN);
if (val < 0)
return val;
data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
@@ -1240,8 +1245,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
{
int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
- phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN,
- phydev->addr, val);
+ phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, val);
return 0;
}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 0bfbabad4..e551f3a89 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -43,15 +43,31 @@ MODULE_LICENSE("GPL");
void phy_device_free(struct phy_device *phydev)
{
- put_device(&phydev->dev);
+ put_device(&phydev->mdio.dev);
}
EXPORT_SYMBOL(phy_device_free);
+static void phy_mdio_device_free(struct mdio_device *mdiodev)
+{
+ struct phy_device *phydev;
+
+ phydev = container_of(mdiodev, struct phy_device, mdio);
+ phy_device_free(phydev);
+}
+
static void phy_device_release(struct device *dev)
{
kfree(to_phy_device(dev));
}
+static void phy_mdio_device_remove(struct mdio_device *mdiodev)
+{
+ struct phy_device *phydev;
+
+ phydev = container_of(mdiodev, struct phy_device, mdio);
+ phy_device_remove(phydev);
+}
+
enum genphy_driver {
GENPHY_DRV_1G,
GENPHY_DRV_10G,
@@ -63,9 +79,118 @@ static struct phy_driver genphy_driver[GENPHY_DRV_MAX];
static LIST_HEAD(phy_fixup_list);
static DEFINE_MUTEX(phy_fixup_lock);
+#ifdef CONFIG_PM
+static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
+{
+ struct device_driver *drv = phydev->mdio.dev.driver;
+ struct phy_driver *phydrv = to_phy_driver(drv);
+ struct net_device *netdev = phydev->attached_dev;
+
+ if (!drv || !phydrv->suspend)
+ return false;
+
+ /* PHY not attached? May suspend if the PHY has not already been
+ * suspended as part of a prior call to phy_disconnect() ->
+ * phy_detach() -> phy_suspend() because the parent netdev might be the
+ * MDIO bus driver and clock gated at this point.
+ */
+ if (!netdev)
+ return !phydev->suspended;
+
+ /* Don't suspend PHY if the attached netdev parent may wakeup.
+ * The parent may point to a PCI device, as in tg3 driver.
+ */
+ if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent))
+ return false;
+
+ /* Also don't suspend PHY if the netdev itself may wakeup. This
+ * is the case for devices w/o underlaying pwr. mgmt. aware bus,
+ * e.g. SoC devices.
+ */
+ if (device_may_wakeup(&netdev->dev))
+ return false;
+
+ return true;
+}
+
+static int mdio_bus_phy_suspend(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ /* We must stop the state machine manually, otherwise it stops out of
+ * control, possibly with the phydev->lock held. Upon resume, netdev
+ * may call phy routines that try to grab the same lock, and that may
+ * lead to a deadlock.
+ */
+ if (phydev->attached_dev && phydev->adjust_link)
+ phy_stop_machine(phydev);
+
+ if (!mdio_bus_phy_may_suspend(phydev))
+ return 0;
+
+ return phy_suspend(phydev);
+}
+
+static int mdio_bus_phy_resume(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ int ret;
+
+ if (!mdio_bus_phy_may_suspend(phydev))
+ goto no_resume;
+
+ ret = phy_resume(phydev);
+ if (ret < 0)
+ return ret;
+
+no_resume:
+ if (phydev->attached_dev && phydev->adjust_link)
+ phy_start_machine(phydev);
+
+ return 0;
+}
+
+static int mdio_bus_phy_restore(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct net_device *netdev = phydev->attached_dev;
+ int ret;
+
+ if (!netdev)
+ return 0;
+
+ ret = phy_init_hw(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* The PHY needs to renegotiate. */
+ phydev->link = 0;
+ phydev->state = PHY_UP;
+
+ phy_start_machine(phydev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mdio_bus_phy_pm_ops = {
+ .suspend = mdio_bus_phy_suspend,
+ .resume = mdio_bus_phy_resume,
+ .freeze = mdio_bus_phy_suspend,
+ .thaw = mdio_bus_phy_resume,
+ .restore = mdio_bus_phy_restore,
+};
+
+#define MDIO_BUS_PHY_PM_OPS (&mdio_bus_phy_pm_ops)
+
+#else
+
+#define MDIO_BUS_PHY_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
/**
* phy_register_fixup - creates a new phy_fixup and adds it to the list
- * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
+ * @bus_id: A string which matches phydev->mdio.dev.bus_id (or PHY_ANY_ID)
* @phy_uid: Used to match against phydev->phy_id (the UID of the PHY)
* It can also be PHY_ANY_UID
* @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before
@@ -114,7 +239,7 @@ EXPORT_SYMBOL(phy_register_fixup_for_id);
*/
static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
{
- if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0)
+ if (strcmp(fixup->bus_id, phydev_name(phydev)) != 0)
if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)
return 0;
@@ -148,18 +273,59 @@ static int phy_scan_fixups(struct phy_device *phydev)
return 0;
}
+static int phy_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct phy_driver *phydrv = to_phy_driver(drv);
+ const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
+ int i;
+
+ if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY))
+ return 0;
+
+ if (phydrv->match_phy_device)
+ return phydrv->match_phy_device(phydev);
+
+ if (phydev->is_c45) {
+ for (i = 1; i < num_ids; i++) {
+ if (!(phydev->c45_ids.devices_in_package & (1 << i)))
+ continue;
+
+ if ((phydrv->phy_id & phydrv->phy_id_mask) ==
+ (phydev->c45_ids.device_ids[i] &
+ phydrv->phy_id_mask))
+ return 1;
+ }
+ return 0;
+ } else {
+ return (phydrv->phy_id & phydrv->phy_id_mask) ==
+ (phydev->phy_id & phydrv->phy_id_mask);
+ }
+}
+
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
bool is_c45,
struct phy_c45_device_ids *c45_ids)
{
struct phy_device *dev;
+ struct mdio_device *mdiodev;
/* We allocate the device, and initialize the default values */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
- dev->dev.release = phy_device_release;
+ mdiodev = &dev->mdio;
+ mdiodev->dev.release = phy_device_release;
+ mdiodev->dev.parent = &bus->dev;
+ mdiodev->dev.bus = &mdio_bus_type;
+ mdiodev->bus = bus;
+ mdiodev->pm_ops = MDIO_BUS_PHY_PM_OPS;
+ mdiodev->bus_match = phy_bus_match;
+ mdiodev->addr = addr;
+ mdiodev->flags = MDIO_DEVICE_FLAG_PHY;
+ mdiodev->device_free = phy_mdio_device_free;
+ mdiodev->device_remove = phy_mdio_device_remove;
dev->speed = 0;
dev->duplex = -1;
@@ -171,15 +337,11 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
dev->autoneg = AUTONEG_ENABLE;
dev->is_c45 = is_c45;
- dev->addr = addr;
dev->phy_id = phy_id;
if (c45_ids)
dev->c45_ids = *c45_ids;
- dev->bus = bus;
- dev->dev.parent = &bus->dev;
- dev->dev.bus = &mdio_bus_type;
- dev->irq = bus->irq ? bus->irq[addr] : PHY_POLL;
- dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);
+ dev->irq = bus->irq[addr];
+ dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
dev->state = PHY_DOWN;
@@ -199,7 +361,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
*/
request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
- device_initialize(&dev->dev);
+ device_initialize(&mdiodev->dev);
return dev;
}
@@ -373,6 +535,48 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
}
EXPORT_SYMBOL(get_phy_device);
+static ssize_t
+phy_id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id);
+}
+static DEVICE_ATTR_RO(phy_id);
+
+static ssize_t
+phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ const char *mode = NULL;
+
+ if (phy_is_internal(phydev))
+ mode = "internal";
+ else
+ mode = phy_modes(phydev->interface);
+
+ return sprintf(buf, "%s\n", mode);
+}
+static DEVICE_ATTR_RO(phy_interface);
+
+static ssize_t
+phy_has_fixups_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return sprintf(buf, "%d\n", phydev->has_fixups);
+}
+static DEVICE_ATTR_RO(phy_has_fixups);
+
+static struct attribute *phy_dev_attrs[] = {
+ &dev_attr_phy_id.attr,
+ &dev_attr_phy_interface.attr,
+ &dev_attr_phy_has_fixups.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(phy_dev);
+
/**
* phy_device_register - Register the phy device on the MDIO bus
* @phydev: phy_device structure to be added to the MDIO bus
@@ -381,28 +585,29 @@ int phy_device_register(struct phy_device *phydev)
{
int err;
- /* Don't register a phy if one is already registered at this address */
- if (phydev->bus->phy_map[phydev->addr])
- return -EINVAL;
- phydev->bus->phy_map[phydev->addr] = phydev;
+ err = mdiobus_register_device(&phydev->mdio);
+ if (err)
+ return err;
/* Run all of the fixups for this PHY */
err = phy_scan_fixups(phydev);
if (err) {
- pr_err("PHY %d failed to initialize\n", phydev->addr);
+ pr_err("PHY %d failed to initialize\n", phydev->mdio.addr);
goto out;
}
- err = device_add(&phydev->dev);
+ phydev->mdio.dev.groups = phy_dev_groups;
+
+ err = device_add(&phydev->mdio.dev);
if (err) {
- pr_err("PHY %d failed to add\n", phydev->addr);
+ pr_err("PHY %d failed to add\n", phydev->mdio.addr);
goto out;
}
return 0;
out:
- phydev->bus->phy_map[phydev->addr] = NULL;
+ mdiobus_unregister_device(&phydev->mdio);
return err;
}
EXPORT_SYMBOL(phy_device_register);
@@ -417,11 +622,8 @@ EXPORT_SYMBOL(phy_device_register);
*/
void phy_device_remove(struct phy_device *phydev)
{
- struct mii_bus *bus = phydev->bus;
- int addr = phydev->addr;
-
- device_del(&phydev->dev);
- bus->phy_map[addr] = NULL;
+ device_del(&phydev->mdio.dev);
+ mdiobus_unregister_device(&phydev->mdio);
}
EXPORT_SYMBOL(phy_device_remove);
@@ -431,11 +633,13 @@ EXPORT_SYMBOL(phy_device_remove);
*/
struct phy_device *phy_find_first(struct mii_bus *bus)
{
+ struct phy_device *phydev;
int addr;
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
- if (bus->phy_map[addr])
- return bus->phy_map[addr];
+ phydev = mdiobus_get_phy(bus, addr);
+ if (phydev)
+ return phydev;
}
return NULL;
}
@@ -607,6 +811,33 @@ int phy_init_hw(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_init_hw);
+void phy_attached_info(struct phy_device *phydev)
+{
+ phy_attached_print(phydev, NULL);
+}
+EXPORT_SYMBOL(phy_attached_info);
+
+#define ATTACHED_FMT "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)"
+void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
+{
+ if (!fmt) {
+ dev_info(&phydev->mdio.dev, ATTACHED_FMT "\n",
+ phydev->drv->name, phydev_name(phydev),
+ phydev->irq);
+ } else {
+ va_list ap;
+
+ dev_info(&phydev->mdio.dev, ATTACHED_FMT,
+ phydev->drv->name, phydev_name(phydev),
+ phydev->irq);
+
+ va_start(ap, fmt);
+ vprintk(fmt, ap);
+ va_end(ap);
+ }
+}
+EXPORT_SYMBOL(phy_attached_print);
+
/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
@@ -625,8 +856,8 @@ EXPORT_SYMBOL(phy_init_hw);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
- struct mii_bus *bus = phydev->bus;
- struct device *d = &phydev->dev;
+ struct mii_bus *bus = phydev->mdio.bus;
+ struct device *d = &phydev->mdio.dev;
int err;
if (!try_module_get(bus->owner)) {
@@ -641,9 +872,11 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
*/
if (!d->driver) {
if (phydev->is_c45)
- d->driver = &genphy_driver[GENPHY_DRV_10G].driver;
+ d->driver =
+ &genphy_driver[GENPHY_DRV_10G].mdiodrv.driver;
else
- d->driver = &genphy_driver[GENPHY_DRV_1G].driver;
+ d->driver =
+ &genphy_driver[GENPHY_DRV_1G].mdiodrv.driver;
err = d->driver->probe(d);
if (err >= 0)
@@ -668,6 +901,11 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
phydev->state = PHY_READY;
+ /* Initial carrier state is off as the phy is about to be
+ * (re)initialized.
+ */
+ netif_carrier_off(phydev->attached_dev);
+
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface)
@@ -744,8 +982,9 @@ void phy_detach(struct phy_device *phydev)
* real driver could be loaded
*/
for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) {
- if (phydev->dev.driver == &genphy_driver[i].driver) {
- device_release_driver(&phydev->dev);
+ if (phydev->mdio.dev.driver ==
+ &genphy_driver[i].mdiodrv.driver) {
+ device_release_driver(&phydev->mdio.dev);
break;
}
}
@@ -754,16 +993,16 @@ void phy_detach(struct phy_device *phydev)
* The phydev might go away on the put_device() below, so avoid
* a use-after-free bug by reading the underlying bus first.
*/
- bus = phydev->bus;
+ bus = phydev->mdio.bus;
- put_device(&phydev->dev);
+ put_device(&phydev->mdio.dev);
module_put(bus->owner);
}
EXPORT_SYMBOL(phy_detach);
int phy_suspend(struct phy_device *phydev)
{
- struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
+ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
int ret = 0;
@@ -786,7 +1025,7 @@ EXPORT_SYMBOL(phy_suspend);
int phy_resume(struct phy_device *phydev)
{
- struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
+ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
int ret = 0;
if (phydrv->resume)
@@ -1171,7 +1410,7 @@ int genphy_config_init(struct phy_device *phydev)
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
- SUPPORTED_BNC);
+ SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause);
/* Do we support autonegotiation? */
val = phy_read(phydev, MII_BMSR);
@@ -1303,7 +1542,7 @@ EXPORT_SYMBOL(phy_set_max_speed);
static void of_set_phy_supported(struct phy_device *phydev)
{
- struct device_node *node = phydev->dev.of_node;
+ struct device_node *node = phydev->mdio.dev.of_node;
u32 max_speed;
if (!IS_ENABLED(CONFIG_OF_MDIO))
@@ -1327,7 +1566,7 @@ static void of_set_phy_supported(struct phy_device *phydev)
static int phy_probe(struct device *dev)
{
struct phy_device *phydev = to_phy_device(dev);
- struct device_driver *drv = phydev->dev.driver;
+ struct device_driver *drv = phydev->mdio.dev.driver;
struct phy_driver *phydrv = to_phy_driver(drv);
int err = 0;
@@ -1382,17 +1621,20 @@ static int phy_remove(struct device *dev)
/**
* phy_driver_register - register a phy_driver with the PHY layer
* @new_driver: new phy_driver to register
+ * @owner: module owning this PHY
*/
-int phy_driver_register(struct phy_driver *new_driver)
+int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
{
int retval;
- new_driver->driver.name = new_driver->name;
- new_driver->driver.bus = &mdio_bus_type;
- new_driver->driver.probe = phy_probe;
- new_driver->driver.remove = phy_remove;
+ new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY;
+ new_driver->mdiodrv.driver.name = new_driver->name;
+ new_driver->mdiodrv.driver.bus = &mdio_bus_type;
+ new_driver->mdiodrv.driver.probe = phy_probe;
+ new_driver->mdiodrv.driver.remove = phy_remove;
+ new_driver->mdiodrv.driver.owner = owner;
- retval = driver_register(&new_driver->driver);
+ retval = driver_register(&new_driver->mdiodrv.driver);
if (retval) {
pr_err("%s: Error %d in registering driver\n",
new_driver->name, retval);
@@ -1406,12 +1648,13 @@ int phy_driver_register(struct phy_driver *new_driver)
}
EXPORT_SYMBOL(phy_driver_register);
-int phy_drivers_register(struct phy_driver *new_driver, int n)
+int phy_drivers_register(struct phy_driver *new_driver, int n,
+ struct module *owner)
{
int i, ret = 0;
for (i = 0; i < n; i++) {
- ret = phy_driver_register(new_driver + i);
+ ret = phy_driver_register(new_driver + i, owner);
if (ret) {
while (i-- > 0)
phy_driver_unregister(new_driver + i);
@@ -1424,7 +1667,7 @@ EXPORT_SYMBOL(phy_drivers_register);
void phy_driver_unregister(struct phy_driver *drv)
{
- driver_unregister(&drv->driver);
+ driver_unregister(&drv->mdiodrv.driver);
}
EXPORT_SYMBOL(phy_driver_unregister);
@@ -1452,7 +1695,6 @@ static struct phy_driver genphy_driver[] = {
.read_status = genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE, },
}, {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
@@ -1464,7 +1706,6 @@ static struct phy_driver genphy_driver[] = {
.read_status = gen10g_read_status,
.suspend = gen10g_suspend,
.resume = gen10g_resume,
- .driver = {.owner = THIS_MODULE, },
} };
static int __init phy_init(void)
@@ -1476,7 +1717,7 @@ static int __init phy_init(void)
return rc;
rc = phy_drivers_register(genphy_driver,
- ARRAY_SIZE(genphy_driver));
+ ARRAY_SIZE(genphy_driver), THIS_MODULE);
if (rc)
mdio_bus_exit();
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c
index be4c6f7c3..d470db89e 100644
--- a/drivers/net/phy/qsemi.c
+++ b/drivers/net/phy/qsemi.c
@@ -122,7 +122,6 @@ static struct phy_driver qs6612_driver[] = { {
.read_status = genphy_read_status,
.ack_interrupt = qs6612_ack_interrupt,
.config_intr = qs6612_config_intr,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(qs6612_driver);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 43ab69136..aadd6e9f5 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -124,7 +124,6 @@ static struct phy_driver realtek_drvs[] = {
.flags = PHY_HAS_INTERRUPT,
.config_aneg = &genphy_config_aneg,
.read_status = &genphy_read_status,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x001cc912,
.name = "RTL8211B Gigabit Ethernet",
@@ -135,7 +134,6 @@ static struct phy_driver realtek_drvs[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &rtl821x_ack_interrupt,
.config_intr = &rtl8211b_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x001cc914,
.name = "RTL8211DN Gigabit Ethernet",
@@ -148,7 +146,6 @@ static struct phy_driver realtek_drvs[] = {
.config_intr = rtl8211e_config_intr,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x001cc915,
.name = "RTL8211E Gigabit Ethernet",
@@ -161,7 +158,6 @@ static struct phy_driver realtek_drvs[] = {
.config_intr = &rtl8211e_config_intr,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = 0x001cc916,
.name = "RTL8211F Gigabit Ethernet",
@@ -175,7 +171,6 @@ static struct phy_driver realtek_drvs[] = {
.config_intr = &rtl8211f_config_intr,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = { .owner = THIS_MODULE },
},
};
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index dc2da8770..2e21e9366 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -24,6 +24,10 @@
#include <linux/netdevice.h>
#include <linux/smscphy.h>
+struct smsc_phy_priv {
+ bool energy_enable;
+};
+
static int smsc_phy_config_intr(struct phy_device *phydev)
{
int rc = phy_write (phydev, MII_LAN83C185_IM,
@@ -43,19 +47,14 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
static int smsc_phy_config_init(struct phy_device *phydev)
{
- int __maybe_unused len;
- struct device *dev __maybe_unused = &phydev->dev;
- struct device_node *of_node __maybe_unused = dev->of_node;
+ struct smsc_phy_priv *priv = phydev->priv;
+
int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
- int enable_energy = 1;
if (rc < 0)
return rc;
- if (of_find_property(of_node, "smsc,disable-energy-detect", &len))
- enable_energy = 0;
-
- if (enable_energy) {
+ if (priv->energy_enable) {
/* Enable energy detect mode for this SMSC Transceivers */
rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
rc | MII_LAN83C185_EDPWRDOWN);
@@ -110,10 +109,13 @@ static int lan911x_config_init(struct phy_device *phydev)
*/
static int lan87xx_read_status(struct phy_device *phydev)
{
+ struct smsc_phy_priv *priv = phydev->priv;
+
int err = genphy_read_status(phydev);
- int i;
- if (!phydev->link) {
+ if (!phydev->link && priv->energy_enable) {
+ int i;
+
/* Disable EDPD to wake up PHY */
int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
if (rc < 0)
@@ -149,6 +151,26 @@ static int lan87xx_read_status(struct phy_device *phydev)
return err;
}
+static int smsc_phy_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct device_node *of_node = dev->of_node;
+ struct smsc_phy_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->energy_enable = true;
+
+ if (of_property_read_bool(of_node, "smsc,disable-energy-detect"))
+ priv->energy_enable = false;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
static struct phy_driver smsc_phy_driver[] = {
{
.phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
@@ -159,6 +181,8 @@ static struct phy_driver smsc_phy_driver[] = {
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+ .probe = smsc_phy_probe,
+
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
@@ -171,8 +195,6 @@ static struct phy_driver smsc_phy_driver[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
-
- .driver = { .owner = THIS_MODULE, }
}, {
.phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
.phy_id_mask = 0xfffffff0,
@@ -182,6 +204,8 @@ static struct phy_driver smsc_phy_driver[] = {
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+ .probe = smsc_phy_probe,
+
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
@@ -194,8 +218,6 @@ static struct phy_driver smsc_phy_driver[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
-
- .driver = { .owner = THIS_MODULE, }
}, {
.phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
.phy_id_mask = 0xfffffff0,
@@ -205,6 +227,8 @@ static struct phy_driver smsc_phy_driver[] = {
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+ .probe = smsc_phy_probe,
+
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = lan87xx_read_status,
@@ -217,8 +241,6 @@ static struct phy_driver smsc_phy_driver[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
-
- .driver = { .owner = THIS_MODULE, }
}, {
.phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
.phy_id_mask = 0xfffffff0,
@@ -228,6 +250,8 @@ static struct phy_driver smsc_phy_driver[] = {
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+ .probe = smsc_phy_probe,
+
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
@@ -239,8 +263,6 @@ static struct phy_driver smsc_phy_driver[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
-
- .driver = { .owner = THIS_MODULE, }
}, {
.phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
.phy_id_mask = 0xfffffff0,
@@ -250,6 +272,8 @@ static struct phy_driver smsc_phy_driver[] = {
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+ .probe = smsc_phy_probe,
+
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = lan87xx_read_status,
@@ -262,8 +286,29 @@ static struct phy_driver smsc_phy_driver[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
+}, {
+ .phy_id = 0x0007c110,
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8740",
- .driver = { .owner = THIS_MODULE, }
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ .probe = smsc_phy_probe,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = lan87xx_read_status,
+ .config_init = smsc_phy_config_init,
+ .soft_reset = smsc_phy_reset,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
} };
module_phy_driver(smsc_phy_driver);
@@ -278,6 +323,7 @@ static struct mdio_device_id __maybe_unused smsc_tbl[] = {
{ 0x0007c0c0, 0xfffffff0 },
{ 0x0007c0d0, 0xfffffff0 },
{ 0x0007c0f0, 0xfffffff0 },
+ { 0x0007c110, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c
index 3fc199b77..d00cfb645 100644
--- a/drivers/net/phy/ste10Xp.c
+++ b/drivers/net/phy/ste10Xp.c
@@ -95,7 +95,6 @@ static struct phy_driver ste10xp_pdriver[] = {
.config_intr = ste10Xp_config_intr,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = {.owner = THIS_MODULE,}
}, {
.phy_id = STE100P_PHY_ID,
.phy_id_mask = 0xffffffff,
@@ -109,7 +108,6 @@ static struct phy_driver ste10xp_pdriver[] = {
.config_intr = ste10Xp_config_intr,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .driver = {.owner = THIS_MODULE,}
} };
module_phy_driver(ste10xp_pdriver);
diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c
index 07463fcca..fb2cef764 100644
--- a/drivers/net/phy/teranetics.c
+++ b/drivers/net/phy/teranetics.c
@@ -108,7 +108,6 @@ static struct phy_driver teranetics_driver[] = {
.config_aneg = teranetics_config_aneg,
.read_status = teranetics_read_status,
.match_phy_device = teranetics_match_phy_device,
- .driver = { .owner = THIS_MODULE,},
},
};
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index dd295dbaa..2e37eb337 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -236,7 +236,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_VSC8244,
.name = "Vitesse VSC8244",
@@ -248,7 +247,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_VSC8514,
.name = "Vitesse VSC8514",
@@ -260,7 +258,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_VSC8574,
.name = "Vitesse VSC8574",
@@ -272,7 +269,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_VSC8601,
.name = "Vitesse VSC8601",
@@ -284,7 +280,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
.phy_id = PHY_ID_VSC8662,
.name = "Vitesse VSC8662",
@@ -296,7 +291,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
/* Vitesse 8221 */
.phy_id = PHY_ID_VSC8221,
@@ -309,7 +303,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
}, {
/* Vitesse 8211 */
.phy_id = PHY_ID_VSC8211,
@@ -322,7 +315,6 @@ static struct phy_driver vsc82xx_driver[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
- .driver = { .owner = THIS_MODULE,},
} };
module_phy_driver(vsc82xx_driver);