Skip to contentSkip to conversation

drivers: thermal: tsens: add timeout to get_tem_tsens_valid

PATCH New Ansuel Smith 1 participant 3 messages May 18, 2021

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 2/3 drivers: thermal: tsens: add timeout to get_tem_tsens_valid

The function can loop and lock the system if for whatever reason the bit for the target sensor is NEVER valid. This is the case if a sensor is disabled by the factory and the valid bit is never reported as actually valid. Add a timeout check and exit if a timeout occurs. As this is a very rare condition, handle the timeout only if the first read fails.

---
 drivers/thermal/qcom/tsens.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)
drivers/thermal/qcom/tsens.c +16 -7
index b1162e566a70..38afde1a599f 100644
@@ -599,6 +599,7 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
 	int hw_id = s->hw_id;
 	u32 temp_idx = LAST_TEMP_0 + hw_id;
 	u32 valid_idx = VALID_0 + hw_id;
+	unsigned long timeout;
 	u32 valid;
 	int ret;
 
@@ -607,13 +608,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
 		ret = regmap_field_read(priv->rf[valid_idx], &valid);
 		if (ret)
 			return ret;
-		while (!valid) {
-			/* Valid bit is 0 for 6 AHB clock cycles.
-			 * At 19.2MHz, 1 AHB clock is ~60ns.
-			 * We should enter this loop very, very rarely.
-			 */
-			ndelay(400);
-			ret = regmap_field_read(priv->rf[valid_idx], &valid);
+
+		if (!valid) {
+			timeout = jiffies + msecs_to_jiffies(20);
+
+			do {
+				/* Valid bit is 0 for 6 AHB clock cycles.
+				 * At 19.2MHz, 1 AHB clock is ~60ns.
+				 * We should enter this loop very, very rarely.
+				 */
+				ndelay(400);
+				ret = regmap_field_read(priv->rf[valid_idx], &valid);
+				if (valid || ret)
+					break;
+			} while (!(ret = time_after_eq(jiffies, timeout)));
+
 			if (ret)
 				return ret;
 		}
Signature · 1 line
2.30.2
#1 lore raw

PATCH 1/3 drivers: thermal: tsens: fix wrong check for tzd in irq handlers

Some device can have some thermal sensor disabled from the factory. The current 2 irq handler functions check all the sensor by default and the check if the sensor was actually registered is wrong. The tzd is actually never set if the registration fail hence the IS_ERR check is wrong.

---
 drivers/thermal/qcom/tsens.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/thermal/qcom/tsens.c +2 -2
index 4c7ebd1d3f9c..b1162e566a70 100644
@@ -417,7 +417,7 @@ static irqreturn_t tsens_critical_irq_thread(int irq, void *data)
 		const struct tsens_sensor *s = &priv->sensor[i];
 		u32 hw_id = s->hw_id;
 
-		if (IS_ERR(s->tzd))
+		if (!s->tzd)
 			continue;
 		if (!tsens_threshold_violated(priv, hw_id, &d))
 			continue;
@@ -467,7 +467,7 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
 		const struct tsens_sensor *s = &priv->sensor[i];
 		u32 hw_id = s->hw_id;
 
-		if (IS_ERR(s->tzd))
+		if (!s->tzd)
 			continue;
 		if (!tsens_threshold_violated(priv, hw_id, &d))
 			continue;
Signature · 1 line
2.30.2
#2 lore raw

PATCH 3/3 drivers: thermal: tsens: check if crit_int is supported in read_irq_state

In reply to Ansuel Smith

From: Robert Marko <[email protected]>

Check if crit_int is supported by the current tsens feat and read crit field only if needed or the kernel panic for reading unreadable memory.

---
 drivers/thermal/qcom/tsens.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)
drivers/thermal/qcom/tsens.c +15 -9
index 38afde1a599f..27777a05f755 100644
@@ -325,16 +325,22 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
 		ret = regmap_field_read(priv->rf[LOW_INT_MASK_0 + hw_id], &d->low_irq_mask);
 		if (ret)
 			return ret;
-		ret = regmap_field_read(priv->rf[CRIT_INT_CLEAR_0 + hw_id],
-					&d->crit_irq_clear);
-		if (ret)
-			return ret;
-		ret = regmap_field_read(priv->rf[CRIT_INT_MASK_0 + hw_id],
-					&d->crit_irq_mask);
-		if (ret)
-			return ret;
+		if (priv->feat->crit_int) {
+			ret = regmap_field_read(priv->rf[CRIT_INT_CLEAR_0 + hw_id],
+						&d->crit_irq_clear);
+			if (ret)
+				return ret;
+			ret = regmap_field_read(priv->rf[CRIT_INT_MASK_0 + hw_id],
+						&d->crit_irq_mask);
+			if (ret)
+				return ret;
 
-		d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id);
+			d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id);
+		} else {
+			d->crit_irq_clear = 0;
+			d->crit_irq_mask = 0;
+			d->crit_thresh = 0;
+		}
 	} else {
 		/* No mask register on older TSENS */
 		d->up_irq_mask = 0;
Signature · 1 line
2.30.2