summaryrefslogtreecommitdiffstats
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/bcm7xxx.c43
-rw-r--r--drivers/net/phy/dp83640.c17
-rw-r--r--drivers/net/phy/marvell.c15
-rw-r--r--drivers/net/phy/phy.c46
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/phy/smsc.c54
7 files changed, 108 insertions, 70 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 60994a83a0d6..f0a77020037a 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/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index bf241a3ec5e5..db507e3bcab9 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -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), \
@@ -337,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,
@@ -349,7 +340,7 @@ static struct phy_driver bcm7xxx_driver[] = {
.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,
@@ -361,7 +352,7 @@ static struct phy_driver bcm7xxx_driver[] = {
.phy_id = PHY_ID_BCM7435,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM7435",
- .features = PHY_GBIT_FEATURES |
+ .features = PHY_BASIC_FEATURES |
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
.flags = PHY_IS_INTERNAL,
.config_init = bcm7xxx_config_init,
@@ -369,30 +360,6 @@ static struct phy_driver bcm7xxx_driver[] = {
.read_status = genphy_read_status,
.suspend = bcm7xxx_suspend,
.resume = bcm7xxx_config_init,
-}, {
- .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,
-}, {
- .phy_id = PHY_BCM_OUI_5,
- .phy_id_mask = 0xffffff00,
- .name = "Broadcom BCM7XXX 65nm",
- .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,
} };
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
@@ -404,8 +371,6 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
{ 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/dp83640.c b/drivers/net/phy/dp83640.c
index 180f69952779..7a240fce3a7e 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -846,6 +846,11 @@ static void decode_rxts(struct dp83640_private *dp83640,
struct skb_shared_hwtstamps *shhwtstamps = NULL;
struct sk_buff *skb;
unsigned long flags;
+ u8 overflow;
+
+ overflow = (phy_rxts->ns_hi >> 14) & 0x3;
+ if (overflow)
+ pr_debug("rx timestamp queue overflow, count %d\n", overflow);
spin_lock_irqsave(&dp83640->rx_lock, flags);
@@ -888,6 +893,7 @@ static void decode_txts(struct dp83640_private *dp83640,
struct skb_shared_hwtstamps shhwtstamps;
struct sk_buff *skb;
u64 ns;
+ u8 overflow;
/* We must already have the skb that triggered this. */
@@ -897,6 +903,17 @@ static void decode_txts(struct dp83640_private *dp83640,
pr_debug("have timestamp but tx_queue empty\n");
return;
}
+
+ overflow = (phy_txts->ns_hi >> 14) & 0x3;
+ if (overflow) {
+ pr_debug("tx timestamp queue overflow, count %d\n", overflow);
+ while (skb) {
+ skb_complete_tx_timestamp(skb, NULL);
+ skb = skb_dequeue(&dp83640->tx_queue);
+ }
+ return;
+ }
+
ns = phy2txts(phy_txts);
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ns_to_ktime(ns);
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index e3eb96443c97..ab1d0fcaf1d9 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -446,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);
}
@@ -495,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)
@@ -514,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)
@@ -1078,6 +1084,7 @@ static struct phy_driver marvell_drivers[] = {
.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,
@@ -1149,6 +1156,7 @@ static struct phy_driver marvell_drivers[] = {
.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,
@@ -1167,6 +1175,7 @@ static struct phy_driver marvell_drivers[] = {
.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,
@@ -1259,6 +1268,7 @@ static struct phy_driver marvell_drivers[] = {
.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,
@@ -1277,6 +1287,7 @@ static struct phy_driver marvell_drivers[] = {
.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,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 8763bb20988a..5590b9c182c9 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -692,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);
@@ -905,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)
@@ -1000,15 +1004,21 @@ void phy_state_machine(struct work_struct *work)
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);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index bad3f005faee..e551f3a89cfd 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1410,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);
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index e485f2653c82..2e21e9366f76 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->mdio.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,
@@ -180,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,
@@ -201,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,
@@ -222,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,
@@ -242,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,
@@ -263,6 +295,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,
OpenPOWER on IntegriCloud