All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] pm/fan: drop the fan lock in fan_update() before rescheduling
@ 2014-03-24  1:03 Martin Peres
       [not found] ` <1395622983-2807-1-git-send-email-martin.peres-GANU6spQydw@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Martin Peres @ 2014-03-24  1:03 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW; +Cc: Martin Peres

From: Martin Peres <martin.peres@labri.fr>

This should fix a deadlock that has been reported to us where fan_update()
would hold the fan lock and try to grab the alarm_program_lock to reschedule
an update. On an other CPU, the alarm_program_lock would have been taken
before calling fan_update(), leading to a deadlock.

We should Cc: <stable@vger.kernel.org> # 3.9+

Reported-by: Marcin Slusarz <marcin.slusarz@gmail.com>
Tested-by: Timothée Ravier <tim@siosm.fr>
Signed-off-by: Martin Peres <martin.peres@free.fr>
---
 nvkm/subdev/therm/fan.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/nvkm/subdev/therm/fan.c b/nvkm/subdev/therm/fan.c
index 95f6129..29d4c41 100644
--- a/nvkm/subdev/therm/fan.c
+++ b/nvkm/subdev/therm/fan.c
@@ -54,8 +54,10 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
 
 	/* check that we're not already at the target duty cycle */
 	duty = fan->get(therm);
-	if (duty == target)
-		goto done;
+	if (duty == target) {
+		spin_unlock_irqrestore(&fan->lock, flags);
+		return 0;
+	}
 
 	/* smooth out the fanspeed increase/decrease */
 	if (!immediate && duty >= 0) {
@@ -73,8 +75,15 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
 
 	nv_debug(therm, "FAN update: %d\n", duty);
 	ret = fan->set(therm, duty);
-	if (ret)
-		goto done;
+	if (ret) {
+		spin_unlock_irqrestore(&fan->lock, flags);
+		return ret;
+	}
+
+	/* fan speed updated, drop the fan lock before grabbing the
+	 * alarm-scheduling lock and risking a deadlock
+	 */
+	spin_unlock_irqrestore(&fan->lock, flags);
 
 	/* schedule next fan update, if not at target speed already */
 	if (list_empty(&fan->alarm.head) && target != duty) {
@@ -92,8 +101,6 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
 		ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm);
 	}
 
-done:
-	spin_unlock_irqrestore(&fan->lock, flags);
 	return ret;
 }
 
-- 
1.9.1

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-03-25 13:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-24  1:03 [PATCH 1/4] pm/fan: drop the fan lock in fan_update() before rescheduling Martin Peres
     [not found] ` <1395622983-2807-1-git-send-email-martin.peres-GANU6spQydw@public.gmane.org>
2014-03-24  1:03   ` [PATCH 2/4] drm/nvd7/fan: handle another kind of PWM fans Martin Peres
2014-03-24  1:03   ` [PATCH 3/4] drm/therm/fan: let the vbios decide on the automatic fan management mode Martin Peres
2014-03-24  1:03   ` [PATCH 4/4] bios/hack: try 16 times when reading the vbios from PROM Martin Peres
2014-03-25 13:08   ` [PATCH 1/4] pm/fan: drop the fan lock in fan_update() before rescheduling Martin Peres

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.