From 57a574993d94671b495cdbe8aeb78b745abfe14f Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 19 Jan 2009 17:14:21 -0800 Subject: phylib: unsigneds go unnoticed both pdata->mdc and pdata->mdio are unsigned. Notice a negative return value. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- drivers/net/phy/mdio-gpio.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index a439ebeb431..3f460c56492 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -200,16 +200,21 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, { struct device_node *np = NULL; struct mdio_gpio_platform_data *pdata; + int ret; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->mdc = of_get_gpio(ofdev->node, 0); - pdata->mdio = of_get_gpio(ofdev->node, 1); - - if (pdata->mdc < 0 || pdata->mdio < 0) + ret = of_get_gpio(ofdev->node, 0); + if (ret < 0) goto out_free; + pdata->mdc = ret; + + ret = of_get_gpio(ofdev->node, 1); + if (ret < 0) + goto out_free; + pdata->mdio = ret; while ((np = of_get_next_child(ofdev->node, np))) if (!strcmp(np->type, "ethernet-phy")) -- cgit v1.2.3-70-g09d2 From 3d1e4db2b0698785f4e4dd139d88257e855e53b8 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 1 Feb 2009 00:53:34 -0800 Subject: phylib: Rework suspend/resume code to check netdev wakeup capability In most cases (e.g. PCI drivers) MDIO and MAC controllers are represented by the same device. But for SOC ethernets we have separate devices. So, in SOC case, checking whether MDIO controller may wakeup is not only makes little sense, but also prevents us from doing per-netdevice wakeup management. This patch reworks suspend/resume code so that now it checks for net device's wakeup flags, not MDIO controller's ones. Each netdevice should manage its wakeup flags, and phylib will decide whether suspend an attached PHY or not. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 54 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 811a637695c..bb29ae3ff17 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -286,33 +287,58 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) (phydev->phy_id & phydrv->phy_id_mask)); } +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 (!netdev) + return true; + + /* + * 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; +} + /* Suspend and resume. Copied from platform_suspend and * platform_resume */ static int mdio_bus_suspend(struct device * dev, pm_message_t state) { - int ret = 0; - struct device_driver *drv = dev->driver; - struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); - if (drv && phydrv->suspend && !device_may_wakeup(phydev->dev.parent)) - ret = phydrv->suspend(phydev); - - return ret; + if (!mdio_bus_phy_may_suspend(phydev)) + return 0; + return phydrv->suspend(phydev); } static int mdio_bus_resume(struct device * dev) { - int ret = 0; - struct device_driver *drv = dev->driver; - struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); - if (drv && phydrv->resume && !device_may_wakeup(phydev->dev.parent)) - ret = phydrv->resume(phydev); - - return ret; + if (!mdio_bus_phy_may_suspend(phydev)) + return 0; + return phydrv->resume(phydev); } struct bus_type mdio_bus_type = { -- cgit v1.2.3-70-g09d2 From 036b66879addb28ad7104ca975317528bfc79e47 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 26 Feb 2009 10:19:36 +0000 Subject: mdio: fix non-constant printk warnings Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index bb29ae3ff17..b754020cbe7 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -99,7 +99,7 @@ int mdiobus_register(struct mii_bus *bus) bus->dev.parent = bus->parent; bus->dev.class = &mdio_bus_class; bus->dev.groups = NULL; - dev_set_name(&bus->dev, bus->id); + dev_set_name(&bus->dev, "%s", bus->id); err = device_register(&bus->dev); if (err) { -- cgit v1.2.3-70-g09d2 From a390d1f379cf821248b735f43d2e1147ebb8241d Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Fri, 13 Mar 2009 15:41:19 -0700 Subject: phylib: convert state_queue work to delayed_work It closes a race in phy_stop_machine when reprogramming of phy_timer (from phy_state_machine) happens between del_timer_sync and cancel_work_sync. Without this change it could lead to crash if phy_device would be freed after phy_stop_machine (timer would fire and schedule freed work). Signed-off-by: Marcin Slusarz Acked-by: Jean Delvare Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 41 +++++++++++------------------------------ include/linux/phy.h | 3 +-- 2 files changed, 12 insertions(+), 32 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e4ede6080c9..58b73b08dde 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -414,7 +414,6 @@ EXPORT_SYMBOL(phy_start_aneg); static void phy_change(struct work_struct *work); static void phy_state_machine(struct work_struct *work); -static void phy_timer(unsigned long data); /** * phy_start_machine - start PHY state machine tracking @@ -434,11 +433,8 @@ void phy_start_machine(struct phy_device *phydev, { phydev->adjust_state = handler; - INIT_WORK(&phydev->state_queue, phy_state_machine); - init_timer(&phydev->phy_timer); - phydev->phy_timer.function = &phy_timer; - phydev->phy_timer.data = (unsigned long) phydev; - mod_timer(&phydev->phy_timer, jiffies + HZ); + INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine); + schedule_delayed_work(&phydev->state_queue, jiffies + HZ); } /** @@ -451,8 +447,7 @@ void phy_start_machine(struct phy_device *phydev, */ void phy_stop_machine(struct phy_device *phydev) { - del_timer_sync(&phydev->phy_timer); - cancel_work_sync(&phydev->state_queue); + cancel_delayed_work_sync(&phydev->state_queue); mutex_lock(&phydev->lock); if (phydev->state > PHY_UP) @@ -680,11 +675,9 @@ static void phy_change(struct work_struct *work) if (err) goto irq_enable_err; - /* Stop timer and run the state queue now. The work function for - * state_queue will start the timer up again. - */ - del_timer(&phydev->phy_timer); - schedule_work(&phydev->state_queue); + /* reschedule state queue work to run as soon as possible */ + cancel_delayed_work_sync(&phydev->state_queue); + schedule_delayed_work(&phydev->state_queue, 0); return; @@ -761,14 +754,13 @@ EXPORT_SYMBOL(phy_start); /** * phy_state_machine - Handle the state machine * @work: work_struct that describes the work to be done - * - * Description: Scheduled by the state_queue workqueue each time - * phy_timer is triggered. */ static void phy_state_machine(struct work_struct *work) { + struct delayed_work *dwork = + container_of(work, struct delayed_work, work); struct phy_device *phydev = - container_of(work, struct phy_device, state_queue); + container_of(dwork, struct phy_device, state_queue); int needs_aneg = 0; int err = 0; @@ -946,17 +938,6 @@ static void phy_state_machine(struct work_struct *work) if (err < 0) phy_error(phydev); - mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); -} - -/* PHY timer which schedules the state machine work */ -static void phy_timer(unsigned long data) -{ - struct phy_device *phydev = (struct phy_device *)data; - - /* - * PHY I/O operations can potentially sleep so we ensure that - * it's done from a process context - */ - schedule_work(&phydev->state_queue); + schedule_delayed_work(&phydev->state_queue, + jiffies + PHY_STATE_TIME * HZ); } diff --git a/include/linux/phy.h b/include/linux/phy.h index d7e54d98869..32cf14a4b03 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -315,8 +315,7 @@ struct phy_device { /* Interrupt and Polling infrastructure */ struct work_struct phy_queue; - struct work_struct state_queue; - struct timer_list phy_timer; + struct delayed_work state_queue; atomic_t irq_disable; struct mutex lock; -- cgit v1.2.3-70-g09d2 From e072b639dc13b06b65be487633dad9bb3d2067d5 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Mon, 23 Mar 2009 15:17:31 -0700 Subject: phy: add new LAN8710 and LAN8720 device ids to smsc phy driver LAN8710 and LAN8720 are two new 10/100 ethernet PHY models. The two share the same phy id, this patch adds it to the smsc phy driver. Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/phy/smsc.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 1387187543e..5123bb954dd 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -159,6 +159,30 @@ static struct phy_driver lan911x_int_driver = { .driver = { .owner = THIS_MODULE, } }; +static struct phy_driver lan8710_driver = { + .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */ + .phy_id_mask = 0xfffffff0, + .name = "SMSC LAN8710/LAN8720", + + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause + | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + + /* basic functions */ + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .config_init = smsc_phy_config_init, + + /* IRQ related */ + .ack_interrupt = smsc_phy_ack_interrupt, + .config_intr = smsc_phy_config_intr, + + .suspend = genphy_suspend, + .resume = genphy_resume, + + .driver = { .owner = THIS_MODULE, } +}; + static int __init smsc_init(void) { int ret; @@ -179,8 +203,14 @@ static int __init smsc_init(void) if (ret) goto err4; + ret = phy_driver_register (&lan8710_driver); + if (ret) + goto err5; + return 0; +err5: + phy_driver_unregister (&lan911x_int_driver); err4: phy_driver_unregister (&lan8700_driver); err3: @@ -193,6 +223,7 @@ err1: static void __exit smsc_exit(void) { + phy_driver_unregister (&lan8710_driver); phy_driver_unregister (&lan911x_int_driver); phy_driver_unregister (&lan8700_driver); phy_driver_unregister (&lan8187_driver); -- cgit v1.2.3-70-g09d2