aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorMarcin Slusarz <marcin.slusarz@gmail.com>2009-03-13 18:41:19 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-13 18:41:19 -0400
commita390d1f379cf821248b735f43d2e1147ebb8241d (patch)
tree8011cb8a5056055bedb4a9f4948929e2543a727d /drivers/net/phy
parent34cd347cec6dba8075ceca06efd4fb0c6574cb75 (diff)
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 <marcin.slusarz@gmail.com> Acked-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/phy.c41
1 files changed, 11 insertions, 30 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e4ede6080c9d..58b73b08dde0 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -414,7 +414,6 @@ EXPORT_SYMBOL(phy_start_aneg);
414 414
415static void phy_change(struct work_struct *work); 415static void phy_change(struct work_struct *work);
416static void phy_state_machine(struct work_struct *work); 416static void phy_state_machine(struct work_struct *work);
417static void phy_timer(unsigned long data);
418 417
419/** 418/**
420 * phy_start_machine - start PHY state machine tracking 419 * phy_start_machine - start PHY state machine tracking
@@ -434,11 +433,8 @@ void phy_start_machine(struct phy_device *phydev,
434{ 433{
435 phydev->adjust_state = handler; 434 phydev->adjust_state = handler;
436 435
437 INIT_WORK(&phydev->state_queue, phy_state_machine); 436 INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
438 init_timer(&phydev->phy_timer); 437 schedule_delayed_work(&phydev->state_queue, jiffies + HZ);
439 phydev->phy_timer.function = &phy_timer;
440 phydev->phy_timer.data = (unsigned long) phydev;
441 mod_timer(&phydev->phy_timer, jiffies + HZ);
442} 438}
443 439
444/** 440/**
@@ -451,8 +447,7 @@ void phy_start_machine(struct phy_device *phydev,
451 */ 447 */
452void phy_stop_machine(struct phy_device *phydev) 448void phy_stop_machine(struct phy_device *phydev)
453{ 449{
454 del_timer_sync(&phydev->phy_timer); 450 cancel_delayed_work_sync(&phydev->state_queue);
455 cancel_work_sync(&phydev->state_queue);
456 451
457 mutex_lock(&phydev->lock); 452 mutex_lock(&phydev->lock);
458 if (phydev->state > PHY_UP) 453 if (phydev->state > PHY_UP)
@@ -680,11 +675,9 @@ static void phy_change(struct work_struct *work)
680 if (err) 675 if (err)
681 goto irq_enable_err; 676 goto irq_enable_err;
682 677
683 /* Stop timer and run the state queue now. The work function for 678 /* reschedule state queue work to run as soon as possible */
684 * state_queue will start the timer up again. 679 cancel_delayed_work_sync(&phydev->state_queue);
685 */ 680 schedule_delayed_work(&phydev->state_queue, 0);
686 del_timer(&phydev->phy_timer);
687 schedule_work(&phydev->state_queue);
688 681
689 return; 682 return;
690 683
@@ -761,14 +754,13 @@ EXPORT_SYMBOL(phy_start);
761/** 754/**
762 * phy_state_machine - Handle the state machine 755 * phy_state_machine - Handle the state machine
763 * @work: work_struct that describes the work to be done 756 * @work: work_struct that describes the work to be done
764 *
765 * Description: Scheduled by the state_queue workqueue each time
766 * phy_timer is triggered.
767 */ 757 */
768static void phy_state_machine(struct work_struct *work) 758static void phy_state_machine(struct work_struct *work)
769{ 759{
760 struct delayed_work *dwork =
761 container_of(work, struct delayed_work, work);
770 struct phy_device *phydev = 762 struct phy_device *phydev =
771 container_of(work, struct phy_device, state_queue); 763 container_of(dwork, struct phy_device, state_queue);
772 int needs_aneg = 0; 764 int needs_aneg = 0;
773 int err = 0; 765 int err = 0;
774 766
@@ -946,17 +938,6 @@ static void phy_state_machine(struct work_struct *work)
946 if (err < 0) 938 if (err < 0)
947 phy_error(phydev); 939 phy_error(phydev);
948 940
949 mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); 941 schedule_delayed_work(&phydev->state_queue,
950} 942 jiffies + PHY_STATE_TIME * HZ);
951
952/* PHY timer which schedules the state machine work */
953static void phy_timer(unsigned long data)
954{
955 struct phy_device *phydev = (struct phy_device *)data;
956
957 /*
958 * PHY I/O operations can potentially sleep so we ensure that
959 * it's done from a process context
960 */
961 schedule_work(&phydev->state_queue);
962} 943}