linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ath5k: prevent infinite loop
@ 2009-05-19  0:28 Steven Rostedt
  2009-05-19  0:34 ` Nick Kossifidis
  0 siblings, 1 reply; 11+ messages in thread
From: Steven Rostedt @ 2009-05-19  0:28 UTC (permalink / raw)
  To: LKML
  Cc: jirislaby, mickflemm, lrodriguez, me, linux-wireless, ath5k-devel,
	Andrew Morton


After updating my laptop with the latest kernel (had 2.6.26 before that),
my laptop load went to 100%. The daemon phy0 was at 99.9% of the CPU.
Luckily I compiled with a preempt kernel otherwise this would have
been a lock up.

Using ftrace to dig into the problem I found that that the ath5k driver
was in an infinite loop. The code in ath5k_get_linear_pcdac_min has:

	pwr_i = pwrR[0];
	do {
		pwr_i--;
		tmp = (s8) ath5k_get_interpolated_value(pwr_i,
						pwrR[0], pwrR[1],
						stepR[0], stepR[1]);
	} while (tmp > 1);


But ath5k_get_interpolated returns stepR[0] if pwrR[0] == pwrR[1] or 
stepR[0] == stepR[1]. The pwr_i is ignored and we enter an infinite loop
because tmp never changes between iterations. Using ftrace, I was able to 
determine that is exactly what happened in the case of my laptop.

This patch tries to keep the same result that would happen when this case 
occurs. That is, the pwr_i becomes a minimal number. I used the minimum 
number that a signed short may be to initialize the min pwrL and pwrR.
Then if the case that the code would cause an infinite loop, we bypass it.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index 9e2faae..2c916fc 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -1473,6 +1473,8 @@ ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
 	return result;
 }
 
+#define MIN_PWR (-32768)
+
 /*
  * Find vertical boundary (min pwr) for the linear PCDAC curve.
  *
@@ -1486,29 +1488,32 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
 				const s16 *pwrL, const s16 *pwrR)
 {
 	s8 tmp;
-	s16 min_pwrL, min_pwrR;
+	s16 min_pwrL = MIN_PWR, min_pwrR = MIN_PWR;
 	s16 pwr_i = pwrL[0];
 
-	do {
-		pwr_i--;
-		tmp = (s8) ath5k_get_interpolated_value(pwr_i,
-						pwrL[0], pwrL[1],
-						stepL[0], stepL[1]);
-
-	} while (tmp > 1);
-
-	min_pwrL = pwr_i;
+	/* Avoid infinite loop */
+	if (pwrL[0] != pwrL[1] && stepL[0] != stepL[1]) {
+		do {
+			pwr_i--;
+			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+							pwrL[0], pwrL[1],
+							stepL[0], stepL[1]);
+		} while (tmp > 1);
+		min_pwrL = pwr_i;
+	}
 
 	pwr_i = pwrR[0];
-	do {
-		pwr_i--;
-		tmp = (s8) ath5k_get_interpolated_value(pwr_i,
-						pwrR[0], pwrR[1],
-						stepR[0], stepR[1]);
-
-	} while (tmp > 1);
 
-	min_pwrR = pwr_i;
+	/* Avoid infinite loop */
+	if (pwrR[0] != pwrR[1] && stepR[0] != stepR[1]) {
+		do {
+			pwr_i--;
+			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+							pwrR[0], pwrR[1],
+							stepR[0], stepR[1]);
+		} while (tmp > 1);
+		min_pwrR = pwr_i;
+	}
 
 	/* Keep the right boundary so that it works for both curves */
 	return max(min_pwrL, min_pwrR);

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

end of thread, other threads:[~2009-05-20  3:38 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-19  0:28 [PATCH] ath5k: prevent infinite loop Steven Rostedt
2009-05-19  0:34 ` Nick Kossifidis
2009-05-19  0:43   ` Steven Rostedt
2009-05-19  6:32     ` Nick Kossifidis
2009-05-19  6:39       ` [ath5k-devel] " Luis R. Rodriguez
2009-05-19 11:45         ` Steven Rostedt
2009-05-19 16:38           ` Luis R. Rodriguez
2009-05-19 11:42       ` Bob Copeland
2009-05-19 11:54         ` Steven Rostedt
2009-05-19 12:34           ` Bob Copeland
2009-05-20  3:37           ` [PATCH] ath5k: avoid and warn on potential " Bob Copeland

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).