Linux-ARM-MSM Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/3] thermal: tsens: Handle critical interrupts
@ 2019-11-11 19:21 Amit Kucheria
  2019-11-11 19:21 ` [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support Amit Kucheria
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-11-11 19:21 UTC (permalink / raw)
  To: linux-kernel, linux-arm-msm, bjorn.andersson, edubezval, swboyd,
	sivaa, Andy Gross
  Cc: Amit Kucheria, Daniel Lezcano, devicetree, linux-pm

TSENS IP v2.x supports critical interrupts and v2.3+ adds watchdog support
in case the FSM is frozen. Enable support in the driver.

Amit Kucheria (3):
  drivers: thermal: tsens: Add critical interrupt support
  drivers: thermal: tsens: Add watchdog support
  arm64: dts: sdm845: thermal: Add critical interrupt support

 arch/arm64/boot/dts/qcom/sdm845.dtsi |  10 +-
 drivers/thermal/qcom/tsens-common.c  | 170 +++++++++++++++++++++++++--
 drivers/thermal/qcom/tsens-v2.c      |  18 ++-
 drivers/thermal/qcom/tsens.c         |  21 ++++
 drivers/thermal/qcom/tsens.h         |  85 ++++++++++++++
 5 files changed, 289 insertions(+), 15 deletions(-)

-- 
2.17.1


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

* [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-11 19:21 [PATCH 0/3] thermal: tsens: Handle critical interrupts Amit Kucheria
@ 2019-11-11 19:21 ` Amit Kucheria
  2019-11-12 19:38   ` Bjorn Andersson
  2019-11-14 22:50   ` Stephen Boyd
  2019-11-11 19:21 ` [PATCH 2/3] drivers: thermal: tsens: Add watchdog support Amit Kucheria
  2019-11-11 19:21 ` [PATCH 3/3] arm64: dts: sdm845: thermal: Add critical interrupt support Amit Kucheria
  2 siblings, 2 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-11-11 19:21 UTC (permalink / raw)
  To: linux-kernel, linux-arm-msm, bjorn.andersson, edubezval, swboyd,
	sivaa, Andy Gross
  Cc: Daniel Lezcano, Amit Kucheria, linux-pm

TSENS IP v2.x adds critical threshold interrupt support for each sensor
in addition to the upper/lower threshold interrupt. Add support in the
driver.

Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
---
 drivers/thermal/qcom/tsens-common.c | 129 ++++++++++++++++++++++++++--
 drivers/thermal/qcom/tsens-v2.c     |   8 +-
 drivers/thermal/qcom/tsens.c        |  21 +++++
 drivers/thermal/qcom/tsens.h        |  73 ++++++++++++++++
 4 files changed, 220 insertions(+), 11 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
index 4359a4247ac3..2989cb952cdb 100644
--- a/drivers/thermal/qcom/tsens-common.c
+++ b/drivers/thermal/qcom/tsens-common.c
@@ -23,6 +23,10 @@
  * @low_thresh:     lower threshold temperature value
  * @low_irq_mask:   mask register for lower threshold irqs
  * @low_irq_clear:  clear register for lower threshold irqs
+ * @crit_viol:      critical threshold violated
+ * @crit_thresh:    critical threshold temperature value
+ * @crit_irq_mask:  mask register for critical threshold irqs
+ * @crit_irq_clear: clear register for critical threshold irqs
  *
  * Structure containing data about temperature threshold settings and
  * irq status if they were violated.
@@ -36,6 +40,10 @@ struct tsens_irq_data {
 	int low_thresh;
 	u32 low_irq_mask;
 	u32 low_irq_clear;
+	u32 crit_viol;
+	u32 crit_thresh;
+	u32 crit_irq_mask;
+	u32 crit_irq_clear;
 };
 
 char *qfprom_read(struct device *dev, const char *cname)
@@ -172,7 +180,7 @@ static int tsens_mC_to_hw(struct tsens_sensor *s, int temp)
 	return temp / 100;
 }
 
-static inline enum tsens_ver tsens_version(struct tsens_priv *priv)
+enum tsens_ver tsens_version(struct tsens_priv *priv)
 {
 	return priv->feat->ver_major;
 }
@@ -189,6 +197,9 @@ static void tsens_set_interrupt_v1(struct tsens_priv *priv, u32 hw_id,
 	case LOWER:
 		index = LOW_INT_CLEAR_0 + hw_id;
 		break;
+	case CRITICAL:
+		/* No critical interrupts before v2 */
+		break;
 	}
 	regmap_field_write(priv->rf[index], enable ? 0 : 1);
 }
@@ -214,6 +225,10 @@ static void tsens_set_interrupt_v2(struct tsens_priv *priv, u32 hw_id,
 		index_mask  = LOW_INT_MASK_0 + hw_id;
 		index_clear = LOW_INT_CLEAR_0 + hw_id;
 		break;
+	case CRITICAL:
+		index_mask  = CRIT_INT_MASK_0 + hw_id;
+		index_clear = CRIT_INT_CLEAR_0 + hw_id;
+		break;
 	}
 
 	if (enable) {
@@ -268,7 +283,14 @@ static int tsens_threshold_violated(struct tsens_priv *priv, u32 hw_id,
 	ret = regmap_field_read(priv->rf[LOWER_STATUS_0 + hw_id], &d->low_viol);
 	if (ret)
 		return ret;
-	if (d->up_viol || d->low_viol)
+
+	if (tsens_version(priv) > VER_1_X) {
+		ret = regmap_field_read(priv->rf[CRITICAL_STATUS_0 + hw_id], &d->crit_viol);
+		if (ret)
+			return ret;
+	}
+
+	if (d->up_viol || d->low_viol || d->crit_viol)
 		return 1;
 
 	return 0;
@@ -292,22 +314,36 @@ 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;
+
+		d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id);
 	} else {
 		/* No mask register on older TSENS */
 		d->up_irq_mask = 0;
 		d->low_irq_mask = 0;
+		d->crit_irq_clear = 0;
+		d->crit_irq_mask = 0;
+		d->crit_thresh = 0;
 	}
 
 	d->up_thresh  = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id);
 	d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id);
 
-	dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u) | clr(%u|%u) | mask(%u|%u)\n",
-		hw_id, __func__, (d->up_viol || d->low_viol) ? "(V)" : "",
-		d->low_viol, d->up_viol, d->low_irq_clear, d->up_irq_clear,
-		d->low_irq_mask, d->up_irq_mask);
-	dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d)\n", hw_id, __func__,
-		(d->up_viol || d->low_viol) ? "(violation)" : "",
-		d->low_thresh, d->up_thresh);
+	dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u|%u) |"
+		" clr(%u|%u|%u) | mask(%u|%u|%u)\n",
+		hw_id, __func__,
+		(d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "",
+		d->low_viol, d->up_viol, d->crit_viol,
+		d->low_irq_clear, d->up_irq_clear, d->crit_irq_clear,
+		d->low_irq_mask, d->up_irq_mask, d->crit_irq_mask);
+	dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d:%d)\n", hw_id, __func__,
+		(d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "",
+		d->low_thresh, d->up_thresh, d->crit_thresh);
 
 	return 0;
 }
@@ -321,6 +357,65 @@ static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
 	return 0;
 }
 
+/**
+ * tsens_critical_irq_thread - Threaded interrupt handler for critical interrupts
+ * @irq: irq number
+ * @data: tsens controller private data
+ *
+ * Check all sensors to find ones that violated their critical threshold limits.
+ * Clear and then re-enable the interrupt.
+ *
+ * The level-triggered interrupt might deassert if the temperature returned to
+ * within the threshold limits by the time the handler got scheduled. We
+ * consider the irq to have been handled in that case.
+ *
+ * Return: IRQ_HANDLED
+ */
+irqreturn_t tsens_critical_irq_thread(int irq, void *data)
+{
+	struct tsens_priv *priv = data;
+	struct tsens_irq_data d;
+	bool enable = true, disable = false;
+	unsigned long flags;
+	int temp, ret, i;
+
+	for (i = 0; i < priv->num_sensors; i++) {
+		struct tsens_sensor *s = &priv->sensor[i];
+		u32 hw_id = s->hw_id;
+
+		if (IS_ERR(priv->sensor[i].tzd))
+			continue;
+		if (!tsens_threshold_violated(priv, hw_id, &d))
+			continue;
+		ret = get_temp_tsens_valid(s, &temp);
+		if (ret) {
+			dev_err(priv->dev, "[%u] %s: error reading sensor\n", hw_id, __func__);
+			continue;
+		}
+
+		spin_lock_irqsave(&priv->ul_lock, flags);
+
+		tsens_read_irq_state(priv, hw_id, s, &d);
+
+		if (d.crit_viol &&
+		    !masked_irq(hw_id, d.crit_irq_mask, tsens_version(priv))) {
+			tsens_set_interrupt(priv, hw_id, CRITICAL, disable);
+			if (d.crit_thresh > temp) {
+				dev_dbg(priv->dev, "[%u] %s: re-arm upper\n",
+					priv->sensor[i].hw_id, __func__);
+			} else {
+				dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n",
+					hw_id, __func__, temp);
+			}
+			tsens_set_interrupt(priv, hw_id, CRITICAL, enable);
+		}
+
+		spin_unlock_irqrestore(&priv->crit_lock, flags);
+	}
+
+	return IRQ_HANDLED;
+}
+
 /**
  * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
  * @irq: irq number
@@ -683,6 +778,22 @@ int __init init_common(struct tsens_priv *priv)
 		}
 	}
 
+	if (tsens_version(priv) > VER_1_X) {
+		/* This loop might need changes if enum regfield_ids is reordered */
+		for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
+			for (i = 0; i < priv->feat->max_sensors; i++) {
+				int idx = j + i;
+
+				priv->rf[idx] = devm_regmap_field_alloc(dev, priv->tm_map,
+									priv->fields[idx]);
+				if (IS_ERR(priv->rf[idx])) {
+					ret = PTR_ERR(priv->rf[idx]);
+					goto err_put_device;
+				}
+			}
+		}
+	}
+
 	spin_lock_init(&priv->ul_lock);
 	tsens_enable_irq(priv);
 	tsens_debug_init(op);
diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
index a4d15e1abfdd..47d831df0803 100644
--- a/drivers/thermal/qcom/tsens-v2.c
+++ b/drivers/thermal/qcom/tsens-v2.c
@@ -51,8 +51,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 	[INT_EN]  = REG_FIELD(TM_INT_EN_OFF, 0, 2),
 
 	/* TEMPERATURE THRESHOLDS */
-	REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF,  0,  11),
-	REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH,  TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12,  23),
+	REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH,  TM_Sn_UPPER_LOWER_THRESHOLD_OFF,  0,  11),
+	REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH,   TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12,  23),
+	REG_FIELD_FOR_EACH_SENSOR16(CRIT_THRESH, TM_Sn_CRITICAL_THRESHOLD_OFF,     0,  11),
 
 	/* INTERRUPTS [CLEAR/STATUS/MASK] */
 	REG_FIELD_SPLIT_BITS_0_15(LOW_INT_STATUS,  TM_UPPER_LOWER_INT_STATUS_OFF),
@@ -61,6 +62,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 	REG_FIELD_SPLIT_BITS_16_31(UP_INT_STATUS,  TM_UPPER_LOWER_INT_STATUS_OFF),
 	REG_FIELD_SPLIT_BITS_16_31(UP_INT_CLEAR,   TM_UPPER_LOWER_INT_CLEAR_OFF),
 	REG_FIELD_SPLIT_BITS_16_31(UP_INT_MASK,    TM_UPPER_LOWER_INT_MASK_OFF),
+	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_STATUS, TM_CRITICAL_INT_STATUS_OFF),
+	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_CLEAR,  TM_CRITICAL_INT_CLEAR_OFF),
+	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_MASK,   TM_CRITICAL_INT_MASK_OFF),
 
 	/* Sn_STATUS */
 	REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 7d317660211e..784c4976c4f9 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
 
 	enable_irq_wake(irq);
 
+	if (tsens_version(priv) > VER_1_X) {
+		irq = platform_get_irq_byname(pdev, "critical");
+		if (irq < 0) {
+			ret = irq;
+			goto err_put_device;
+		}
+
+		ret = devm_request_threaded_irq(&pdev->dev, irq,
+						NULL, tsens_critical_irq_thread,
+						IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+						dev_name(&pdev->dev), priv);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: failed to get critical irq\n", __func__);
+			goto err_put_device;
+		}
+
+		enable_irq_wake(irq);
+	}
+
+	return 0;
+
 err_put_device:
 	put_device(&pdev->dev);
 	return ret;
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 8b20f28c5c51..9b5a30533c52 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -23,6 +23,7 @@
 
 struct tsens_priv;
 
+/* IP version numbers in ascending order */
 enum tsens_ver {
 	VER_0_1 = 0,
 	VER_1_X,
@@ -32,6 +33,7 @@ enum tsens_ver {
 enum tsens_irq_type {
 	LOWER,
 	UPPER,
+	CRITICAL,
 };
 
 /**
@@ -374,6 +376,70 @@ enum regfield_ids {
 	CRITICAL_STATUS_13,
 	CRITICAL_STATUS_14,
 	CRITICAL_STATUS_15,
+	CRIT_INT_STATUS_0,	/* CRITICAL interrupt status */
+	CRIT_INT_STATUS_1,
+	CRIT_INT_STATUS_2,
+	CRIT_INT_STATUS_3,
+	CRIT_INT_STATUS_4,
+	CRIT_INT_STATUS_5,
+	CRIT_INT_STATUS_6,
+	CRIT_INT_STATUS_7,
+	CRIT_INT_STATUS_8,
+	CRIT_INT_STATUS_9,
+	CRIT_INT_STATUS_10,
+	CRIT_INT_STATUS_11,
+	CRIT_INT_STATUS_12,
+	CRIT_INT_STATUS_13,
+	CRIT_INT_STATUS_14,
+	CRIT_INT_STATUS_15,
+	CRIT_INT_CLEAR_0,	/* CRITICAL interrupt clear */
+	CRIT_INT_CLEAR_1,
+	CRIT_INT_CLEAR_2,
+	CRIT_INT_CLEAR_3,
+	CRIT_INT_CLEAR_4,
+	CRIT_INT_CLEAR_5,
+	CRIT_INT_CLEAR_6,
+	CRIT_INT_CLEAR_7,
+	CRIT_INT_CLEAR_8,
+	CRIT_INT_CLEAR_9,
+	CRIT_INT_CLEAR_10,
+	CRIT_INT_CLEAR_11,
+	CRIT_INT_CLEAR_12,
+	CRIT_INT_CLEAR_13,
+	CRIT_INT_CLEAR_14,
+	CRIT_INT_CLEAR_15,
+	CRIT_INT_MASK_0,	/* CRITICAL interrupt mask */
+	CRIT_INT_MASK_1,
+	CRIT_INT_MASK_2,
+	CRIT_INT_MASK_3,
+	CRIT_INT_MASK_4,
+	CRIT_INT_MASK_5,
+	CRIT_INT_MASK_6,
+	CRIT_INT_MASK_7,
+	CRIT_INT_MASK_8,
+	CRIT_INT_MASK_9,
+	CRIT_INT_MASK_10,
+	CRIT_INT_MASK_11,
+	CRIT_INT_MASK_12,
+	CRIT_INT_MASK_13,
+	CRIT_INT_MASK_14,
+	CRIT_INT_MASK_15,
+	CRIT_THRESH_0,		/* CRITICAL threshold values */
+	CRIT_THRESH_1,
+	CRIT_THRESH_2,
+	CRIT_THRESH_3,
+	CRIT_THRESH_4,
+	CRIT_THRESH_5,
+	CRIT_THRESH_6,
+	CRIT_THRESH_7,
+	CRIT_THRESH_8,
+	CRIT_THRESH_9,
+	CRIT_THRESH_10,
+	CRIT_THRESH_11,
+	CRIT_THRESH_12,
+	CRIT_THRESH_13,
+	CRIT_THRESH_14,
+	CRIT_THRESH_15,
 	MIN_STATUS_0,		/* MIN threshold violated */
 	MIN_STATUS_1,
 	MIN_STATUS_2,
@@ -460,6 +526,8 @@ struct tsens_context {
  * @srot_map: pointer to SROT register address space
  * @tm_offset: deal with old device trees that don't address TM and SROT
  *             address space separately
+ * @ul_lock: lock while processing upper/lower threshold interrupts
+ * @crit_lock: lock while processing critical threshold interrupts
  * @rf: array of regmap_fields used to store value of the field
  * @ctx: registers to be saved and restored during suspend/resume
  * @feat: features of the IP
@@ -479,6 +547,9 @@ struct tsens_priv {
 	/* lock for upper/lower threshold interrupts */
 	spinlock_t			ul_lock;
 
+	/* lock for critical threshold interrupts */
+	spinlock_t			crit_lock;
+
 	struct regmap_field		*rf[MAX_REGFIELDS];
 	struct tsens_context		ctx;
 	const struct tsens_features	*feat;
@@ -499,7 +570,9 @@ int get_temp_common(struct tsens_sensor *s, int *temp);
 int tsens_enable_irq(struct tsens_priv *priv);
 void tsens_disable_irq(struct tsens_priv *priv);
 int tsens_set_trips(void *_sensor, int low, int high);
+enum tsens_ver tsens_version(struct tsens_priv *priv);
 irqreturn_t tsens_irq_thread(int irq, void *data);
+irqreturn_t tsens_critical_irq_thread(int irq, void *data);
 
 /* TSENS target */
 extern const struct tsens_plat_data data_8960;
-- 
2.17.1


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

* [PATCH 2/3] drivers: thermal: tsens: Add watchdog support
  2019-11-11 19:21 [PATCH 0/3] thermal: tsens: Handle critical interrupts Amit Kucheria
  2019-11-11 19:21 ` [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support Amit Kucheria
@ 2019-11-11 19:21 ` Amit Kucheria
  2019-11-12 19:22   ` Bjorn Andersson
  2019-11-14 22:38   ` Stephen Boyd
  2019-11-11 19:21 ` [PATCH 3/3] arm64: dts: sdm845: thermal: Add critical interrupt support Amit Kucheria
  2 siblings, 2 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-11-11 19:21 UTC (permalink / raw)
  To: linux-kernel, linux-arm-msm, bjorn.andersson, edubezval, swboyd,
	sivaa, Andy Gross
  Cc: Daniel Lezcano, Amit Kucheria, linux-pm

TSENS IP v2.3 onwards adds support for a watchdog to detect if the TSENS
HW FSM is frozen. Add support to detect and restart the FSM in the
driver. The watchdog is configured by the bootloader, we just enable the
feature in the kernel.

Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
---
 drivers/thermal/qcom/tsens-common.c | 41 +++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens-v2.c     | 10 +++++++
 drivers/thermal/qcom/tsens.h        | 12 +++++++++
 3 files changed, 63 insertions(+)

diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
index 2989cb952cdb..9432518502a7 100644
--- a/drivers/thermal/qcom/tsens-common.c
+++ b/drivers/thermal/qcom/tsens-common.c
@@ -378,6 +378,28 @@ irqreturn_t tsens_critical_irq_thread(int irq, void *data)
 	bool enable = true, disable = false;
 	unsigned long flags;
 	int temp, ret, i;
+	u32 wdog_status, wdog_count, ver_minor;
+
+	ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
+	if (ret)
+		return ret;
+
+	if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
+		/* Watchdog is present only on v2.3+ */
+		ret = regmap_field_read(priv->rf[WDOG_BARK_STATUS], &wdog_status);
+		if (ret)
+			return ret;
+
+		/* Clear WDOG interrupt */
+		regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1);
+		regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0);
+
+		ret = regmap_field_read(priv->rf[WDOG_BARK_COUNT], &wdog_count);
+		if (ret)
+			return ret;
+		if (wdog_count)
+			dev_err(priv->dev, "%s: watchdog count: %d\n", __func__, wdog_count);
+	}
 
 	for (i = 0; i < priv->num_sensors; i++) {
 		struct tsens_sensor *s = &priv->sensor[i];
@@ -685,6 +707,7 @@ int __init init_common(struct tsens_priv *priv)
 {
 	void __iomem *tm_base, *srot_base;
 	struct device *dev = priv->dev;
+	u32 ver_minor;
 	struct resource *res;
 	u32 enabled;
 	int ret, i, j;
@@ -734,6 +757,9 @@ int __init init_common(struct tsens_priv *priv)
 			if (IS_ERR(priv->rf[i]))
 				return PTR_ERR(priv->rf[i]);
 		}
+		ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
+		if (ret)
+			goto err_put_device;
 	}
 
 	priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
@@ -794,6 +820,21 @@ int __init init_common(struct tsens_priv *priv)
 		}
 	}
 
+	if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
+		/* Watchdog is present only on v2.3+ */
+		for (i = 0, j = WDOG_BARK_STATUS; j <= CC_MON_MASK; i++, j++) {
+			priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
+							      priv->fields[j]);
+			if (IS_ERR(priv->rf[j])) {
+				ret = PTR_ERR(priv->rf[j]);
+				goto err_put_device;
+			}
+		}
+		/* Enable WDOG and disable cycle completion monitoring */
+		regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
+		regmap_field_write(priv->rf[CC_MON_MASK], 1);
+	}
+
 	spin_lock_init(&priv->ul_lock);
 	tsens_enable_irq(priv);
 	tsens_debug_init(op);
diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
index 47d831df0803..4184850d1e42 100644
--- a/drivers/thermal/qcom/tsens-v2.c
+++ b/drivers/thermal/qcom/tsens-v2.c
@@ -24,6 +24,7 @@
 #define TM_Sn_CRITICAL_THRESHOLD_OFF	0x0060
 #define TM_Sn_STATUS_OFF		0x00a0
 #define TM_TRDY_OFF			0x00e4
+#define TM_WDOG_LOG_OFF		0x013c
 
 /* v2.x: 8996, 8998, sdm845 */
 
@@ -66,6 +67,15 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_CLEAR,  TM_CRITICAL_INT_CLEAR_OFF),
 	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_MASK,   TM_CRITICAL_INT_MASK_OFF),
 
+	/* WATCHDOG on v2.3 or later */
+	[WDOG_BARK_STATUS] = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 31, 31),
+	[WDOG_BARK_CLEAR]  = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  31, 31),
+	[WDOG_BARK_MASK]   = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   31, 31),
+	[CC_MON_STATUS]    = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 30, 30),
+	[CC_MON_CLEAR]     = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  30, 30),
+	[CC_MON_MASK]      = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   30, 30),
+	[WDOG_BARK_COUNT]  = REG_FIELD(TM_WDOG_LOG_OFF,             0,  7),
+
 	/* Sn_STATUS */
 	REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
 	REG_FIELD_FOR_EACH_SENSOR16(VALID,           TM_Sn_STATUS_OFF, 21,  21),
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 9b5a30533c52..7608e7877a7b 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -440,6 +440,18 @@ enum regfield_ids {
 	CRIT_THRESH_13,
 	CRIT_THRESH_14,
 	CRIT_THRESH_15,
+
+	/* WATCHDOG */
+	WDOG_BARK_STATUS,
+	WDOG_BARK_CLEAR,
+	WDOG_BARK_MASK,
+	WDOG_BARK_COUNT,
+
+	/* CYCLE COMPLETION MONITOR */
+	CC_MON_STATUS,
+	CC_MON_CLEAR,
+	CC_MON_MASK,
+
 	MIN_STATUS_0,		/* MIN threshold violated */
 	MIN_STATUS_1,
 	MIN_STATUS_2,
-- 
2.17.1


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

* [PATCH 3/3] arm64: dts: sdm845: thermal: Add critical interrupt support
  2019-11-11 19:21 [PATCH 0/3] thermal: tsens: Handle critical interrupts Amit Kucheria
  2019-11-11 19:21 ` [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support Amit Kucheria
  2019-11-11 19:21 ` [PATCH 2/3] drivers: thermal: tsens: Add watchdog support Amit Kucheria
@ 2019-11-11 19:21 ` Amit Kucheria
  2019-11-12 19:43   ` Bjorn Andersson
  2 siblings, 1 reply; 15+ messages in thread
From: Amit Kucheria @ 2019-11-11 19:21 UTC (permalink / raw)
  To: linux-kernel, linux-arm-msm, bjorn.andersson, edubezval, swboyd,
	sivaa, Andy Gross
  Cc: devicetree

Register critical interrupts for each of the two tsens controllers

Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
Message-Id: <3686bd40c99692feb955e936b608b080e2cb1826.1568624011.git.amit.kucheria@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 0990d5761860..3b643b04ab5a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -2950,8 +2950,9 @@
 			reg = <0 0x0c263000 0 0x1ff>, /* TM */
 			      <0 0x0c222000 0 0x1ff>; /* SROT */
 			#qcom,sensors = <13>;
-			interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "uplow";
+			interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "uplow", "critical";
 			#thermal-sensor-cells = <1>;
 		};
 
@@ -2960,8 +2961,9 @@
 			reg = <0 0x0c265000 0 0x1ff>, /* TM */
 			      <0 0x0c223000 0 0x1ff>; /* SROT */
 			#qcom,sensors = <8>;
-			interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "uplow";
+			interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "uplow", "critical";
 			#thermal-sensor-cells = <1>;
 		};
 
-- 
2.17.1


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

* Re: [PATCH 2/3] drivers: thermal: tsens: Add watchdog support
  2019-11-11 19:21 ` [PATCH 2/3] drivers: thermal: tsens: Add watchdog support Amit Kucheria
@ 2019-11-12 19:22   ` Bjorn Andersson
  2019-11-28 19:18     ` Amit Kucheria
  2019-11-14 22:38   ` Stephen Boyd
  1 sibling, 1 reply; 15+ messages in thread
From: Bjorn Andersson @ 2019-11-12 19:22 UTC (permalink / raw)
  To: Amit Kucheria
  Cc: linux-kernel, linux-arm-msm, edubezval, swboyd, sivaa,
	Andy Gross, Daniel Lezcano, Amit Kucheria, linux-pm

On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:

> TSENS IP v2.3 onwards adds support for a watchdog to detect if the TSENS
> HW FSM is frozen. Add support to detect and restart the FSM in the
> driver. The watchdog is configured by the bootloader, we just enable the
> feature in the kernel.
> 
> Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> ---
>  drivers/thermal/qcom/tsens-common.c | 41 +++++++++++++++++++++++++++++
>  drivers/thermal/qcom/tsens-v2.c     | 10 +++++++
>  drivers/thermal/qcom/tsens.h        | 12 +++++++++
>  3 files changed, 63 insertions(+)
> 
> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> index 2989cb952cdb..9432518502a7 100644
> --- a/drivers/thermal/qcom/tsens-common.c
> +++ b/drivers/thermal/qcom/tsens-common.c
> @@ -378,6 +378,28 @@ irqreturn_t tsens_critical_irq_thread(int irq, void *data)
>  	bool enable = true, disable = false;
>  	unsigned long flags;
>  	int temp, ret, i;
> +	u32 wdog_status, wdog_count, ver_minor;
> +
> +	ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);

The version is unlikely to change from one interrupt to the next, so I
suggest that you add a boolean "has_watchdog" to your context that you
populate in init_common.

> +	if (ret)
> +		return ret;
> +
> +	if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
> +		/* Watchdog is present only on v2.3+ */
> +		ret = regmap_field_read(priv->rf[WDOG_BARK_STATUS], &wdog_status);
> +		if (ret)
> +			return ret;
> +
> +		/* Clear WDOG interrupt */
> +		regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1);
> +		regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0);
> +
> +		ret = regmap_field_read(priv->rf[WDOG_BARK_COUNT], &wdog_count);
> +		if (ret)
> +			return ret;
> +		if (wdog_count)
> +			dev_err(priv->dev, "%s: watchdog count: %d\n", __func__, wdog_count);

What's the benefit of reading wdog_count and who's the audience for this
print? What do I do when this goes to 11?

Regards,
Bjorn

> +	}
>  
>  	for (i = 0; i < priv->num_sensors; i++) {
>  		struct tsens_sensor *s = &priv->sensor[i];
> @@ -685,6 +707,7 @@ int __init init_common(struct tsens_priv *priv)
>  {
>  	void __iomem *tm_base, *srot_base;
>  	struct device *dev = priv->dev;
> +	u32 ver_minor;
>  	struct resource *res;
>  	u32 enabled;
>  	int ret, i, j;
> @@ -734,6 +757,9 @@ int __init init_common(struct tsens_priv *priv)
>  			if (IS_ERR(priv->rf[i]))
>  				return PTR_ERR(priv->rf[i]);
>  		}
> +		ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
> +		if (ret)
> +			goto err_put_device;
>  	}
>  
>  	priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
> @@ -794,6 +820,21 @@ int __init init_common(struct tsens_priv *priv)
>  		}
>  	}
>  
> +	if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
> +		/* Watchdog is present only on v2.3+ */
> +		for (i = 0, j = WDOG_BARK_STATUS; j <= CC_MON_MASK; i++, j++) {
> +			priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
> +							      priv->fields[j]);
> +			if (IS_ERR(priv->rf[j])) {
> +				ret = PTR_ERR(priv->rf[j]);
> +				goto err_put_device;
> +			}
> +		}
> +		/* Enable WDOG and disable cycle completion monitoring */
> +		regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
> +		regmap_field_write(priv->rf[CC_MON_MASK], 1);
> +	}
> +
>  	spin_lock_init(&priv->ul_lock);
>  	tsens_enable_irq(priv);
>  	tsens_debug_init(op);
> diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
> index 47d831df0803..4184850d1e42 100644
> --- a/drivers/thermal/qcom/tsens-v2.c
> +++ b/drivers/thermal/qcom/tsens-v2.c
> @@ -24,6 +24,7 @@
>  #define TM_Sn_CRITICAL_THRESHOLD_OFF	0x0060
>  #define TM_Sn_STATUS_OFF		0x00a0
>  #define TM_TRDY_OFF			0x00e4
> +#define TM_WDOG_LOG_OFF		0x013c
>  
>  /* v2.x: 8996, 8998, sdm845 */
>  
> @@ -66,6 +67,15 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
>  	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_CLEAR,  TM_CRITICAL_INT_CLEAR_OFF),
>  	REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_MASK,   TM_CRITICAL_INT_MASK_OFF),
>  
> +	/* WATCHDOG on v2.3 or later */
> +	[WDOG_BARK_STATUS] = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 31, 31),
> +	[WDOG_BARK_CLEAR]  = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  31, 31),
> +	[WDOG_BARK_MASK]   = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   31, 31),
> +	[CC_MON_STATUS]    = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 30, 30),
> +	[CC_MON_CLEAR]     = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  30, 30),
> +	[CC_MON_MASK]      = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   30, 30),
> +	[WDOG_BARK_COUNT]  = REG_FIELD(TM_WDOG_LOG_OFF,             0,  7),
> +
>  	/* Sn_STATUS */
>  	REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
>  	REG_FIELD_FOR_EACH_SENSOR16(VALID,           TM_Sn_STATUS_OFF, 21,  21),
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> index 9b5a30533c52..7608e7877a7b 100644
> --- a/drivers/thermal/qcom/tsens.h
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -440,6 +440,18 @@ enum regfield_ids {
>  	CRIT_THRESH_13,
>  	CRIT_THRESH_14,
>  	CRIT_THRESH_15,
> +
> +	/* WATCHDOG */
> +	WDOG_BARK_STATUS,
> +	WDOG_BARK_CLEAR,
> +	WDOG_BARK_MASK,
> +	WDOG_BARK_COUNT,
> +
> +	/* CYCLE COMPLETION MONITOR */
> +	CC_MON_STATUS,
> +	CC_MON_CLEAR,
> +	CC_MON_MASK,
> +
>  	MIN_STATUS_0,		/* MIN threshold violated */
>  	MIN_STATUS_1,
>  	MIN_STATUS_2,
> -- 
> 2.17.1
> 

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

* Re: [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-11 19:21 ` [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support Amit Kucheria
@ 2019-11-12 19:38   ` Bjorn Andersson
  2019-11-28 18:46     ` Amit Kucheria
  2019-11-14 22:50   ` Stephen Boyd
  1 sibling, 1 reply; 15+ messages in thread
From: Bjorn Andersson @ 2019-11-12 19:38 UTC (permalink / raw)
  To: Amit Kucheria
  Cc: linux-kernel, linux-arm-msm, edubezval, swboyd, sivaa,
	Andy Gross, Daniel Lezcano, Amit Kucheria, linux-pm

On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:

> TSENS IP v2.x adds critical threshold interrupt support for each sensor
> in addition to the upper/lower threshold interrupt. Add support in the
> driver.
> 
> Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> ---
>  drivers/thermal/qcom/tsens-common.c | 129 ++++++++++++++++++++++++++--
>  drivers/thermal/qcom/tsens-v2.c     |   8 +-
>  drivers/thermal/qcom/tsens.c        |  21 +++++
>  drivers/thermal/qcom/tsens.h        |  73 ++++++++++++++++
>  4 files changed, 220 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> index 4359a4247ac3..2989cb952cdb 100644
> --- a/drivers/thermal/qcom/tsens-common.c
> +++ b/drivers/thermal/qcom/tsens-common.c
> @@ -23,6 +23,10 @@
>   * @low_thresh:     lower threshold temperature value
>   * @low_irq_mask:   mask register for lower threshold irqs
>   * @low_irq_clear:  clear register for lower threshold irqs
> + * @crit_viol:      critical threshold violated

"violated" as in "temperature is above crit_thresh"?

> + * @crit_thresh:    critical threshold temperature value
> + * @crit_irq_mask:  mask register for critical threshold irqs
> + * @crit_irq_clear: clear register for critical threshold irqs
>   *
[..]
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 7d317660211e..784c4976c4f9 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
>  
>  	enable_irq_wake(irq);
>  
> +	if (tsens_version(priv) > VER_1_X) {
> +		irq = platform_get_irq_byname(pdev, "critical");
> +		if (irq < 0) {

Treating this as a fatal error breaks backwards compatibility with
current devicetree; and even within your patch series, tsens should fail
to probe between this patch and the application of patch 3.

Please flip this around and do:

irq = platform_get_irq_byname(pdev, "critical");
if (irq >= 0 && tsens_version(priv) > VER_1_X) {
	request_irq()...
}

> +			ret = irq;
> +			goto err_put_device;
> +		}
> +
> +		ret = devm_request_threaded_irq(&pdev->dev, irq,
> +						NULL, tsens_critical_irq_thread,
> +						IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> +						dev_name(&pdev->dev), priv);
> +		if (ret) {
> +			dev_err(&pdev->dev, "%s: failed to get critical irq\n", __func__);
> +			goto err_put_device;
> +		}
> +
> +		enable_irq_wake(irq);
> +	}
> +
> +	return 0;
> +
>  err_put_device:
>  	put_device(&pdev->dev);
>  	return ret;

Regards,
Bjorn

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

* Re: [PATCH 3/3] arm64: dts: sdm845: thermal: Add critical interrupt support
  2019-11-11 19:21 ` [PATCH 3/3] arm64: dts: sdm845: thermal: Add critical interrupt support Amit Kucheria
@ 2019-11-12 19:43   ` Bjorn Andersson
  0 siblings, 0 replies; 15+ messages in thread
From: Bjorn Andersson @ 2019-11-12 19:43 UTC (permalink / raw)
  To: Amit Kucheria
  Cc: linux-kernel, linux-arm-msm, edubezval, swboyd, sivaa,
	Andy Gross, devicetree

On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:

> Register critical interrupts for each of the two tsens controllers
> 
> Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> Message-Id: <3686bd40c99692feb955e936b608b080e2cb1826.1568624011.git.amit.kucheria@linaro.org>

Picked up for v5.6.

Regards,
Bjorn

> ---
>  arch/arm64/boot/dts/qcom/sdm845.dtsi | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> index 0990d5761860..3b643b04ab5a 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> @@ -2950,8 +2950,9 @@
>  			reg = <0 0x0c263000 0 0x1ff>, /* TM */
>  			      <0 0x0c222000 0 0x1ff>; /* SROT */
>  			#qcom,sensors = <13>;
> -			interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>;
> -			interrupt-names = "uplow";
> +			interrupts = <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "uplow", "critical";
>  			#thermal-sensor-cells = <1>;
>  		};
>  
> @@ -2960,8 +2961,9 @@
>  			reg = <0 0x0c265000 0 0x1ff>, /* TM */
>  			      <0 0x0c223000 0 0x1ff>; /* SROT */
>  			#qcom,sensors = <8>;
> -			interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>;
> -			interrupt-names = "uplow";
> +			interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>,
> +				     <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>;
> +			interrupt-names = "uplow", "critical";
>  			#thermal-sensor-cells = <1>;
>  		};
>  
> -- 
> 2.17.1
> 

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

* Re: [PATCH 2/3] drivers: thermal: tsens: Add watchdog support
  2019-11-11 19:21 ` [PATCH 2/3] drivers: thermal: tsens: Add watchdog support Amit Kucheria
  2019-11-12 19:22   ` Bjorn Andersson
@ 2019-11-14 22:38   ` Stephen Boyd
  2019-11-28 19:16     ` Amit Kucheria
  1 sibling, 1 reply; 15+ messages in thread
From: Stephen Boyd @ 2019-11-14 22:38 UTC (permalink / raw)
  To: Amit Kucheria, Andy Gross, bjorn.andersson, edubezval,
	linux-arm-msm, linux-kernel, sivaa
  Cc: Daniel Lezcano, Amit Kucheria, linux-pm

Quoting Amit Kucheria (2019-11-11 11:21:28)
> TSENS IP v2.3 onwards adds support for a watchdog to detect if the TSENS
> HW FSM is frozen. Add support to detect and restart the FSM in the

Maybe 'frozen' is an ambiguous term? Maybe 'stuck' or 'has stopped
making progress'?

> driver. The watchdog is configured by the bootloader, we just enable the
> feature in the kernel.

Does it work to enable it if we don't configure it in the bootloader?

> 
> Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> ---
>  drivers/thermal/qcom/tsens-common.c | 41 +++++++++++++++++++++++++++++
>  drivers/thermal/qcom/tsens-v2.c     | 10 +++++++
>  drivers/thermal/qcom/tsens.h        | 12 +++++++++
>  3 files changed, 63 insertions(+)
> 
> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> index 2989cb952cdb..9432518502a7 100644
> --- a/drivers/thermal/qcom/tsens-common.c
> +++ b/drivers/thermal/qcom/tsens-common.c
> @@ -794,6 +820,21 @@ int __init init_common(struct tsens_priv *priv)
>                 }
>         }
>  
> +       if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
> +               /* Watchdog is present only on v2.3+ */
> +               for (i = 0, j = WDOG_BARK_STATUS; j <= CC_MON_MASK; i++, j++) {

The variable 'i' is not actually used in this loop. What's going on?

> +                       priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
> +                                                             priv->fields[j]);
> +                       if (IS_ERR(priv->rf[j])) {
> +                               ret = PTR_ERR(priv->rf[j]);
> +                               goto err_put_device;
> +                       }
> +               }
> +               /* Enable WDOG and disable cycle completion monitoring */
> +               regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
> +               regmap_field_write(priv->rf[CC_MON_MASK], 1);
> +       }

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

* Re: [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-11 19:21 ` [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support Amit Kucheria
  2019-11-12 19:38   ` Bjorn Andersson
@ 2019-11-14 22:50   ` Stephen Boyd
  2019-12-03  4:57     ` Amit Kucheria
  1 sibling, 1 reply; 15+ messages in thread
From: Stephen Boyd @ 2019-11-14 22:50 UTC (permalink / raw)
  To: Amit Kucheria, Andy Gross, bjorn.andersson, edubezval,
	linux-arm-msm, linux-kernel, sivaa
  Cc: Daniel Lezcano, Amit Kucheria, linux-pm

Quoting Amit Kucheria (2019-11-11 11:21:27)
> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> index 4359a4247ac3..2989cb952cdb 100644
> --- a/drivers/thermal/qcom/tsens-common.c
> +++ b/drivers/thermal/qcom/tsens-common.c
> @@ -321,6 +357,65 @@ static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
>         return 0;
>  }
>  
> +/**
> + * tsens_critical_irq_thread - Threaded interrupt handler for critical interrupts
> + * @irq: irq number
> + * @data: tsens controller private data
> + *
> + * Check all sensors to find ones that violated their critical threshold limits.
> + * Clear and then re-enable the interrupt.
> + *
> + * The level-triggered interrupt might deassert if the temperature returned to
> + * within the threshold limits by the time the handler got scheduled. We
> + * consider the irq to have been handled in that case.
> + *
> + * Return: IRQ_HANDLED
> + */
> +irqreturn_t tsens_critical_irq_thread(int irq, void *data)
> +{
> +       struct tsens_priv *priv = data;
> +       struct tsens_irq_data d;
> +       bool enable = true, disable = false;

Why not just use true and false in the one place these variables are
used?

> +       unsigned long flags;
> +       int temp, ret, i;
> +
> +       for (i = 0; i < priv->num_sensors; i++) {
> +               struct tsens_sensor *s = &priv->sensor[i];

Maybe make this const?

> +               u32 hw_id = s->hw_id;
> +
> +               if (IS_ERR(priv->sensor[i].tzd))

IS_ERR(s->tzd)?

> +                       continue;
> +               if (!tsens_threshold_violated(priv, hw_id, &d))
> +                       continue;
> +               ret = get_temp_tsens_valid(s, &temp);

Can this accept a const 's'?

> +               if (ret) {
> +                       dev_err(priv->dev, "[%u] %s: error reading sensor\n", hw_id, __func__);
> +                       continue;
> +               }
> +
> +               spin_lock_irqsave(&priv->ul_lock, flags);
> +
> +               tsens_read_irq_state(priv, hw_id, s, &d);
> +
> +               if (d.crit_viol &&
> +                   !masked_irq(hw_id, d.crit_irq_mask, tsens_version(priv))) {
> +                       tsens_set_interrupt(priv, hw_id, CRITICAL, disable);
> +                       if (d.crit_thresh > temp) {
> +                               dev_dbg(priv->dev, "[%u] %s: re-arm upper\n",
> +                                       priv->sensor[i].hw_id, __func__);

hw_id instead of priv->sensor...?

> +                       } else {
> +                               dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n",
> +                                       hw_id, __func__, temp);
> +                       }
> +                       tsens_set_interrupt(priv, hw_id, CRITICAL, enable);
> +               }
> +
> +               spin_unlock_irqrestore(&priv->crit_lock, flags);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
>  /**
>   * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
>   * @irq: irq number
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 7d317660211e..784c4976c4f9 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
>  
>         enable_irq_wake(irq);
>  
> +       if (tsens_version(priv) > VER_1_X) {
> +               irq = platform_get_irq_byname(pdev, "critical");
> +               if (irq < 0) {
> +                       ret = irq;
> +                       goto err_put_device;
> +               }
> +
> +               ret = devm_request_threaded_irq(&pdev->dev, irq,
> +                                               NULL, tsens_critical_irq_thread,
> +                                               IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> +                                               dev_name(&pdev->dev), priv);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "%s: failed to get critical irq\n", __func__);
> +                       goto err_put_device;

Do we need to disable_irq_wake() for the previous irq here?

> +               }
> +
> +               enable_irq_wake(irq);
> +       }
> +
> +       return 0;
> +
>  err_put_device:
>         put_device(&pdev->dev);
>         return ret;

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

* Re: [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-12 19:38   ` Bjorn Andersson
@ 2019-11-28 18:46     ` Amit Kucheria
  2019-11-28 21:43       ` Bjorn Andersson
  0 siblings, 1 reply; 15+ messages in thread
From: Amit Kucheria @ 2019-11-28 18:46 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: LKML, linux-arm-msm, Eduardo Valentin, Stephen Boyd, sivaa,
	Andy Gross, Daniel Lezcano, Linux PM list

On Wed, Nov 13, 2019 at 1:08 AM Bjorn Andersson
<bjorn.andersson@linaro.org> wrote:
>
> On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:
>
> > TSENS IP v2.x adds critical threshold interrupt support for each sensor
> > in addition to the upper/lower threshold interrupt. Add support in the
> > driver.
> >
> > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > ---
> >  drivers/thermal/qcom/tsens-common.c | 129 ++++++++++++++++++++++++++--
> >  drivers/thermal/qcom/tsens-v2.c     |   8 +-
> >  drivers/thermal/qcom/tsens.c        |  21 +++++
> >  drivers/thermal/qcom/tsens.h        |  73 ++++++++++++++++
> >  4 files changed, 220 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> > index 4359a4247ac3..2989cb952cdb 100644
> > --- a/drivers/thermal/qcom/tsens-common.c
> > +++ b/drivers/thermal/qcom/tsens-common.c
> > @@ -23,6 +23,10 @@
> >   * @low_thresh:     lower threshold temperature value
> >   * @low_irq_mask:   mask register for lower threshold irqs
> >   * @low_irq_clear:  clear register for lower threshold irqs
> > + * @crit_viol:      critical threshold violated
>
> "violated" as in "temperature is above crit_thresh"?

Yes.

>
> > + * @crit_thresh:    critical threshold temperature value
> > + * @crit_irq_mask:  mask register for critical threshold irqs
> > + * @crit_irq_clear: clear register for critical threshold irqs
> >   *
> [..]
> > diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> > index 7d317660211e..784c4976c4f9 100644
> > --- a/drivers/thermal/qcom/tsens.c
> > +++ b/drivers/thermal/qcom/tsens.c
> > @@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
> >
> >       enable_irq_wake(irq);
> >
> > +     if (tsens_version(priv) > VER_1_X) {
> > +             irq = platform_get_irq_byname(pdev, "critical");
> > +             if (irq < 0) {
>
> Treating this as a fatal error breaks backwards compatibility with
> current devicetree; and even within your patch series, tsens should fail
> to probe between this patch and the application of patch 3.

Good catch.

> Please flip this around and do:
>
> irq = platform_get_irq_byname(pdev, "critical");
> if (irq >= 0 && tsens_version(priv) > VER_1_X) {
>         request_irq()...
> }

Won't this still break with current devicetree since irq < 0 until
patch 3? Or are you saying we shouldn't check for
platform_get_irq_byname() failure?

I can see two ways out:
1. We patch the dtsi before the code change.
2. We make critical interrupt failure non-fatal by just printing some
messages and still returning success.

Regards,
Amit


> > +                     ret = irq;
> > +                     goto err_put_device;
> > +             }
> > +
> > +             ret = devm_request_threaded_irq(&pdev->dev, irq,
> > +                                             NULL, tsens_critical_irq_thread,
> > +                                             IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> > +                                             dev_name(&pdev->dev), priv);
> > +             if (ret) {
> > +                     dev_err(&pdev->dev, "%s: failed to get critical irq\n", __func__);
> > +                     goto err_put_device;
> > +             }
> > +
> > +             enable_irq_wake(irq);
> > +     }
> > +
> > +     return 0;
> > +
> >  err_put_device:
> >       put_device(&pdev->dev);
> >       return ret;
>
> Regards,
> Bjorn

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

* Re: [PATCH 2/3] drivers: thermal: tsens: Add watchdog support
  2019-11-14 22:38   ` Stephen Boyd
@ 2019-11-28 19:16     ` Amit Kucheria
  0 siblings, 0 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-11-28 19:16 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Andy Gross, Bjorn Andersson, Eduardo Valentin, linux-arm-msm,
	LKML, sivaa, Daniel Lezcano, Linux PM list

On Fri, Nov 15, 2019 at 4:08 AM Stephen Boyd <swboyd@chromium.org> wrote:
>
> Quoting Amit Kucheria (2019-11-11 11:21:28)
> > TSENS IP v2.3 onwards adds support for a watchdog to detect if the TSENS
> > HW FSM is frozen. Add support to detect and restart the FSM in the
>
> Maybe 'frozen' is an ambiguous term? Maybe 'stuck' or 'has stopped
> making progress'?

Alright, let's keep Disney out of this. Will use 'stuck'.

> > driver. The watchdog is configured by the bootloader, we just enable the
> > feature in the kernel.
>
> Does it work to enable it if we don't configure it in the bootloader?

TBH, I don't know. Getting modified firmware to test this will be a
bit of a challenge.

> >
> > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > ---
> >  drivers/thermal/qcom/tsens-common.c | 41 +++++++++++++++++++++++++++++
> >  drivers/thermal/qcom/tsens-v2.c     | 10 +++++++
> >  drivers/thermal/qcom/tsens.h        | 12 +++++++++
> >  3 files changed, 63 insertions(+)
> >
> > diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> > index 2989cb952cdb..9432518502a7 100644
> > --- a/drivers/thermal/qcom/tsens-common.c
> > +++ b/drivers/thermal/qcom/tsens-common.c
> > @@ -794,6 +820,21 @@ int __init init_common(struct tsens_priv *priv)
> >                 }
> >         }
> >
> > +       if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
> > +               /* Watchdog is present only on v2.3+ */
> > +               for (i = 0, j = WDOG_BARK_STATUS; j <= CC_MON_MASK; i++, j++) {
>
> The variable 'i' is not actually used in this loop. What's going on?

Sorry, left over from a botched copy-paste job from the loop above
this. Will fix.

>
> > +                       priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
> > +                                                             priv->fields[j]);
> > +                       if (IS_ERR(priv->rf[j])) {
> > +                               ret = PTR_ERR(priv->rf[j]);
> > +                               goto err_put_device;
> > +                       }
> > +               }
> > +               /* Enable WDOG and disable cycle completion monitoring */
> > +               regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
> > +               regmap_field_write(priv->rf[CC_MON_MASK], 1);
> > +       }

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

* Re: [PATCH 2/3] drivers: thermal: tsens: Add watchdog support
  2019-11-12 19:22   ` Bjorn Andersson
@ 2019-11-28 19:18     ` Amit Kucheria
  0 siblings, 0 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-11-28 19:18 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: LKML, linux-arm-msm, Eduardo Valentin, Stephen Boyd, sivaa,
	Andy Gross, Daniel Lezcano, Linux PM list

On Wed, Nov 13, 2019 at 12:52 AM Bjorn Andersson
<bjorn.andersson@linaro.org> wrote:
>
> On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:
>
> > TSENS IP v2.3 onwards adds support for a watchdog to detect if the TSENS
> > HW FSM is frozen. Add support to detect and restart the FSM in the
> > driver. The watchdog is configured by the bootloader, we just enable the
> > feature in the kernel.
> >
> > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > ---
> >  drivers/thermal/qcom/tsens-common.c | 41 +++++++++++++++++++++++++++++
> >  drivers/thermal/qcom/tsens-v2.c     | 10 +++++++
> >  drivers/thermal/qcom/tsens.h        | 12 +++++++++
> >  3 files changed, 63 insertions(+)
> >
> > diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> > index 2989cb952cdb..9432518502a7 100644
> > --- a/drivers/thermal/qcom/tsens-common.c
> > +++ b/drivers/thermal/qcom/tsens-common.c
> > @@ -378,6 +378,28 @@ irqreturn_t tsens_critical_irq_thread(int irq, void *data)
> >       bool enable = true, disable = false;
> >       unsigned long flags;
> >       int temp, ret, i;
> > +     u32 wdog_status, wdog_count, ver_minor;
> > +
> > +     ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
>
> The version is unlikely to change from one interrupt to the next, so I
> suggest that you add a boolean "has_watchdog" to your context that you
> populate in init_common.

Fair enough, will de-const tsense_features pointer and add a flag
there. It has been overdue, now that we're starting to look at
features that were introduced midway through an IP version cycle. That
is where this should reside instead of tsens_priv.

> > +     if (ret)
> > +             return ret;
> > +
> > +     if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
> > +             /* Watchdog is present only on v2.3+ */
> > +             ret = regmap_field_read(priv->rf[WDOG_BARK_STATUS], &wdog_status);
> > +             if (ret)
> > +                     return ret;
> > +
> > +             /* Clear WDOG interrupt */
> > +             regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1);
> > +             regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0);
> > +
> > +             ret = regmap_field_read(priv->rf[WDOG_BARK_COUNT], &wdog_count);
> > +             if (ret)
> > +                     return ret;
> > +             if (wdog_count)
> > +                     dev_err(priv->dev, "%s: watchdog count: %d\n", __func__, wdog_count);
>
> What's the benefit of reading wdog_count and who's the audience for this
> print? What do I do when this goes to 11?

Should be a debug statement. Will convert to dev_dbg.


> Regards,
> Bjorn
>
> > +     }
> >
> >       for (i = 0; i < priv->num_sensors; i++) {
> >               struct tsens_sensor *s = &priv->sensor[i];
> > @@ -685,6 +707,7 @@ int __init init_common(struct tsens_priv *priv)
> >  {
> >       void __iomem *tm_base, *srot_base;
> >       struct device *dev = priv->dev;
> > +     u32 ver_minor;
> >       struct resource *res;
> >       u32 enabled;
> >       int ret, i, j;
> > @@ -734,6 +757,9 @@ int __init init_common(struct tsens_priv *priv)
> >                       if (IS_ERR(priv->rf[i]))
> >                               return PTR_ERR(priv->rf[i]);
> >               }
> > +             ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
> > +             if (ret)
> > +                     goto err_put_device;
> >       }
> >
> >       priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
> > @@ -794,6 +820,21 @@ int __init init_common(struct tsens_priv *priv)
> >               }
> >       }
> >
> > +     if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
> > +             /* Watchdog is present only on v2.3+ */
> > +             for (i = 0, j = WDOG_BARK_STATUS; j <= CC_MON_MASK; i++, j++) {
> > +                     priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
> > +                                                           priv->fields[j]);
> > +                     if (IS_ERR(priv->rf[j])) {
> > +                             ret = PTR_ERR(priv->rf[j]);
> > +                             goto err_put_device;
> > +                     }
> > +             }
> > +             /* Enable WDOG and disable cycle completion monitoring */
> > +             regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
> > +             regmap_field_write(priv->rf[CC_MON_MASK], 1);
> > +     }
> > +
> >       spin_lock_init(&priv->ul_lock);
> >       tsens_enable_irq(priv);
> >       tsens_debug_init(op);
> > diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
> > index 47d831df0803..4184850d1e42 100644
> > --- a/drivers/thermal/qcom/tsens-v2.c
> > +++ b/drivers/thermal/qcom/tsens-v2.c
> > @@ -24,6 +24,7 @@
> >  #define TM_Sn_CRITICAL_THRESHOLD_OFF 0x0060
> >  #define TM_Sn_STATUS_OFF             0x00a0
> >  #define TM_TRDY_OFF                  0x00e4
> > +#define TM_WDOG_LOG_OFF              0x013c
> >
> >  /* v2.x: 8996, 8998, sdm845 */
> >
> > @@ -66,6 +67,15 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
> >       REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_CLEAR,  TM_CRITICAL_INT_CLEAR_OFF),
> >       REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_MASK,   TM_CRITICAL_INT_MASK_OFF),
> >
> > +     /* WATCHDOG on v2.3 or later */
> > +     [WDOG_BARK_STATUS] = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 31, 31),
> > +     [WDOG_BARK_CLEAR]  = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  31, 31),
> > +     [WDOG_BARK_MASK]   = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   31, 31),
> > +     [CC_MON_STATUS]    = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 30, 30),
> > +     [CC_MON_CLEAR]     = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  30, 30),
> > +     [CC_MON_MASK]      = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   30, 30),
> > +     [WDOG_BARK_COUNT]  = REG_FIELD(TM_WDOG_LOG_OFF,             0,  7),
> > +
> >       /* Sn_STATUS */
> >       REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
> >       REG_FIELD_FOR_EACH_SENSOR16(VALID,           TM_Sn_STATUS_OFF, 21,  21),
> > diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> > index 9b5a30533c52..7608e7877a7b 100644
> > --- a/drivers/thermal/qcom/tsens.h
> > +++ b/drivers/thermal/qcom/tsens.h
> > @@ -440,6 +440,18 @@ enum regfield_ids {
> >       CRIT_THRESH_13,
> >       CRIT_THRESH_14,
> >       CRIT_THRESH_15,
> > +
> > +     /* WATCHDOG */
> > +     WDOG_BARK_STATUS,
> > +     WDOG_BARK_CLEAR,
> > +     WDOG_BARK_MASK,
> > +     WDOG_BARK_COUNT,
> > +
> > +     /* CYCLE COMPLETION MONITOR */
> > +     CC_MON_STATUS,
> > +     CC_MON_CLEAR,
> > +     CC_MON_MASK,
> > +
> >       MIN_STATUS_0,           /* MIN threshold violated */
> >       MIN_STATUS_1,
> >       MIN_STATUS_2,
> > --
> > 2.17.1
> >

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

* Re: [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-28 18:46     ` Amit Kucheria
@ 2019-11-28 21:43       ` Bjorn Andersson
  2019-12-03  5:02         ` Amit Kucheria
  0 siblings, 1 reply; 15+ messages in thread
From: Bjorn Andersson @ 2019-11-28 21:43 UTC (permalink / raw)
  To: Amit Kucheria
  Cc: LKML, linux-arm-msm, Eduardo Valentin, Stephen Boyd, sivaa,
	Andy Gross, Daniel Lezcano, Linux PM list

On Thu 28 Nov 10:46 PST 2019, Amit Kucheria wrote:

> On Wed, Nov 13, 2019 at 1:08 AM Bjorn Andersson
> <bjorn.andersson@linaro.org> wrote:
> >
> > On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:
> >
> > > TSENS IP v2.x adds critical threshold interrupt support for each sensor
> > > in addition to the upper/lower threshold interrupt. Add support in the
> > > driver.
> > >
> > > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > > ---
> > >  drivers/thermal/qcom/tsens-common.c | 129 ++++++++++++++++++++++++++--
> > >  drivers/thermal/qcom/tsens-v2.c     |   8 +-
> > >  drivers/thermal/qcom/tsens.c        |  21 +++++
> > >  drivers/thermal/qcom/tsens.h        |  73 ++++++++++++++++
> > >  4 files changed, 220 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> > > index 4359a4247ac3..2989cb952cdb 100644
> > > --- a/drivers/thermal/qcom/tsens-common.c
> > > +++ b/drivers/thermal/qcom/tsens-common.c
> > > @@ -23,6 +23,10 @@
> > >   * @low_thresh:     lower threshold temperature value
> > >   * @low_irq_mask:   mask register for lower threshold irqs
> > >   * @low_irq_clear:  clear register for lower threshold irqs
> > > + * @crit_viol:      critical threshold violated
> >
> > "violated" as in "temperature is above crit_thresh"?
> 
> Yes.
> 
> >
> > > + * @crit_thresh:    critical threshold temperature value
> > > + * @crit_irq_mask:  mask register for critical threshold irqs
> > > + * @crit_irq_clear: clear register for critical threshold irqs
> > >   *
> > [..]
> > > diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> > > index 7d317660211e..784c4976c4f9 100644
> > > --- a/drivers/thermal/qcom/tsens.c
> > > +++ b/drivers/thermal/qcom/tsens.c
> > > @@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
> > >
> > >       enable_irq_wake(irq);
> > >
> > > +     if (tsens_version(priv) > VER_1_X) {
> > > +             irq = platform_get_irq_byname(pdev, "critical");
> > > +             if (irq < 0) {
> >
> > Treating this as a fatal error breaks backwards compatibility with
> > current devicetree; and even within your patch series, tsens should fail
> > to probe between this patch and the application of patch 3.
> 
> Good catch.
> 
> > Please flip this around and do:
> >
> > irq = platform_get_irq_byname(pdev, "critical");
> > if (irq >= 0 && tsens_version(priv) > VER_1_X) {
> >         request_irq()...
> > }
> 
> Won't this still break with current devicetree since irq < 0 until
> patch 3? Or are you saying we shouldn't check for
> platform_get_irq_byname() failure?
> 

I'm trying to say that dtsi without "critical" defined should cause the
driver to simply skip this segment, not fail to initialize.

> I can see two ways out:
> 1. We patch the dtsi before the code change.

You're expected to maintain backwards compatibility with existing dtb
files out there. The support for critical interrupt is an additional
feature, so you should be able to do this by detecting if "critical" is
defined (e.g. by checking the return value of
platform_get_irq_byname()).

> 2. We make critical interrupt failure non-fatal by just printing some
> messages and still returning success.
> 

Try to make it as specific as possible (without adding a bunch of code)
and throw in a dev_info() if no "critical" is found.

Regards,
Bjorn

> Regards,
> Amit
> 
> 
> > > +                     ret = irq;
> > > +                     goto err_put_device;
> > > +             }
> > > +
> > > +             ret = devm_request_threaded_irq(&pdev->dev, irq,
> > > +                                             NULL, tsens_critical_irq_thread,
> > > +                                             IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> > > +                                             dev_name(&pdev->dev), priv);
> > > +             if (ret) {
> > > +                     dev_err(&pdev->dev, "%s: failed to get critical irq\n", __func__);
> > > +                     goto err_put_device;
> > > +             }
> > > +
> > > +             enable_irq_wake(irq);
> > > +     }
> > > +
> > > +     return 0;
> > > +
> > >  err_put_device:
> > >       put_device(&pdev->dev);
> > >       return ret;
> >
> > Regards,
> > Bjorn

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

* Re: [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-14 22:50   ` Stephen Boyd
@ 2019-12-03  4:57     ` Amit Kucheria
  0 siblings, 0 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-12-03  4:57 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Andy Gross, Bjorn Andersson, Eduardo Valentin, linux-arm-msm,
	LKML, sivaa, Daniel Lezcano, Linux PM list

On Fri, Nov 15, 2019 at 4:20 AM Stephen Boyd <swboyd@chromium.org> wrote:
>
> Quoting Amit Kucheria (2019-11-11 11:21:27)
> > diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> > index 4359a4247ac3..2989cb952cdb 100644
> > --- a/drivers/thermal/qcom/tsens-common.c
> > +++ b/drivers/thermal/qcom/tsens-common.c
> > @@ -321,6 +357,65 @@ static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
> >         return 0;
> >  }
> >
> > +/**
> > + * tsens_critical_irq_thread - Threaded interrupt handler for critical interrupts
> > + * @irq: irq number
> > + * @data: tsens controller private data
> > + *
> > + * Check all sensors to find ones that violated their critical threshold limits.
> > + * Clear and then re-enable the interrupt.
> > + *
> > + * The level-triggered interrupt might deassert if the temperature returned to
> > + * within the threshold limits by the time the handler got scheduled. We
> > + * consider the irq to have been handled in that case.
> > + *
> > + * Return: IRQ_HANDLED
> > + */
> > +irqreturn_t tsens_critical_irq_thread(int irq, void *data)
> > +{
> > +       struct tsens_priv *priv = data;
> > +       struct tsens_irq_data d;
> > +       bool enable = true, disable = false;
>
> Why not just use true and false in the one place these variables are
> used?

Will fix.

> > +       unsigned long flags;
> > +       int temp, ret, i;
> > +
> > +       for (i = 0; i < priv->num_sensors; i++) {
> > +               struct tsens_sensor *s = &priv->sensor[i];
>
> Maybe make this const?

OK.

>
> > +               u32 hw_id = s->hw_id;
> > +
> > +               if (IS_ERR(priv->sensor[i].tzd))
>
> IS_ERR(s->tzd)?

Yup.

>
> > +                       continue;
> > +               if (!tsens_threshold_violated(priv, hw_id, &d))
> > +                       continue;
> > +               ret = get_temp_tsens_valid(s, &temp);
>
> Can this accept a const 's'?

Yes.

> > +               if (ret) {
> > +                       dev_err(priv->dev, "[%u] %s: error reading sensor\n", hw_id, __func__);
> > +                       continue;
> > +               }
> > +
> > +               spin_lock_irqsave(&priv->ul_lock, flags);
> > +
> > +               tsens_read_irq_state(priv, hw_id, s, &d);
> > +
> > +               if (d.crit_viol &&
> > +                   !masked_irq(hw_id, d.crit_irq_mask, tsens_version(priv))) {
> > +                       tsens_set_interrupt(priv, hw_id, CRITICAL, disable);
> > +                       if (d.crit_thresh > temp) {
> > +                               dev_dbg(priv->dev, "[%u] %s: re-arm upper\n",
> > +                                       priv->sensor[i].hw_id, __func__);
>
> hw_id instead of priv->sensor...?

Done. Will fixup for older code in a separate patch.

> > +                       } else {
> > +                               dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n",
> > +                                       hw_id, __func__, temp);
> > +                       }
> > +                       tsens_set_interrupt(priv, hw_id, CRITICAL, enable);
> > +               }
> > +
> > +               spin_unlock_irqrestore(&priv->crit_lock, flags);
> > +       }
> > +
> > +       return IRQ_HANDLED;
> > +}
> > +
> >  /**
> >   * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
> >   * @irq: irq number
> > diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> > index 7d317660211e..784c4976c4f9 100644
> > --- a/drivers/thermal/qcom/tsens.c
> > +++ b/drivers/thermal/qcom/tsens.c
> > @@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
> >
> >         enable_irq_wake(irq);
> >
> > +       if (tsens_version(priv) > VER_1_X) {
> > +               irq = platform_get_irq_byname(pdev, "critical");
> > +               if (irq < 0) {
> > +                       ret = irq;
> > +                       goto err_put_device;
> > +               }
> > +
> > +               ret = devm_request_threaded_irq(&pdev->dev, irq,
> > +                                               NULL, tsens_critical_irq_thread,
> > +                                               IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> > +                                               dev_name(&pdev->dev), priv);
> > +               if (ret) {
> > +                       dev_err(&pdev->dev, "%s: failed to get critical irq\n", __func__);
> > +                       goto err_put_device;
>
> Do we need to disable_irq_wake() for the previous irq here?

Or we could just move the earlier enable_irq_wake() to after
successful registration of the critical interrupt to avoid the error
branch. See v2 posting.



> > +               }
> > +
> > +               enable_irq_wake(irq);
> > +       }
> > +
> > +       return 0;
> > +
> >  err_put_device:
> >         put_device(&pdev->dev);
> >         return ret;

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

* Re: [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support
  2019-11-28 21:43       ` Bjorn Andersson
@ 2019-12-03  5:02         ` Amit Kucheria
  0 siblings, 0 replies; 15+ messages in thread
From: Amit Kucheria @ 2019-12-03  5:02 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: LKML, linux-arm-msm, Eduardo Valentin, Stephen Boyd, sivaa,
	Andy Gross, Daniel Lezcano, Linux PM list

On Fri, Nov 29, 2019 at 3:13 AM Bjorn Andersson
<bjorn.andersson@linaro.org> wrote:
>
> On Thu 28 Nov 10:46 PST 2019, Amit Kucheria wrote:
>
> > On Wed, Nov 13, 2019 at 1:08 AM Bjorn Andersson
> > <bjorn.andersson@linaro.org> wrote:
> > >
> > > On Mon 11 Nov 11:21 PST 2019, Amit Kucheria wrote:
> > >
> > > > TSENS IP v2.x adds critical threshold interrupt support for each sensor
> > > > in addition to the upper/lower threshold interrupt. Add support in the
> > > > driver.
> > > >
> > > > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > > > ---
> > > >  drivers/thermal/qcom/tsens-common.c | 129 ++++++++++++++++++++++++++--
> > > >  drivers/thermal/qcom/tsens-v2.c     |   8 +-
> > > >  drivers/thermal/qcom/tsens.c        |  21 +++++
> > > >  drivers/thermal/qcom/tsens.h        |  73 ++++++++++++++++
> > > >  4 files changed, 220 insertions(+), 11 deletions(-)
> > > >
> > > > diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> > > > index 4359a4247ac3..2989cb952cdb 100644
> > > > --- a/drivers/thermal/qcom/tsens-common.c
> > > > +++ b/drivers/thermal/qcom/tsens-common.c
> > > > @@ -23,6 +23,10 @@
> > > >   * @low_thresh:     lower threshold temperature value
> > > >   * @low_irq_mask:   mask register for lower threshold irqs
> > > >   * @low_irq_clear:  clear register for lower threshold irqs
> > > > + * @crit_viol:      critical threshold violated
> > >
> > > "violated" as in "temperature is above crit_thresh"?
> >
> > Yes.
> >
> > >
> > > > + * @crit_thresh:    critical threshold temperature value
> > > > + * @crit_irq_mask:  mask register for critical threshold irqs
> > > > + * @crit_irq_clear: clear register for critical threshold irqs
> > > >   *
> > > [..]
> > > > diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> > > > index 7d317660211e..784c4976c4f9 100644
> > > > --- a/drivers/thermal/qcom/tsens.c
> > > > +++ b/drivers/thermal/qcom/tsens.c
> > > > @@ -121,6 +121,27 @@ static int tsens_register(struct tsens_priv *priv)
> > > >
> > > >       enable_irq_wake(irq);
> > > >
> > > > +     if (tsens_version(priv) > VER_1_X) {
> > > > +             irq = platform_get_irq_byname(pdev, "critical");
> > > > +             if (irq < 0) {
> > >
> > > Treating this as a fatal error breaks backwards compatibility with
> > > current devicetree; and even within your patch series, tsens should fail
> > > to probe between this patch and the application of patch 3.
> >
> > Good catch.
> >
> > > Please flip this around and do:
> > >
> > > irq = platform_get_irq_byname(pdev, "critical");
> > > if (irq >= 0 && tsens_version(priv) > VER_1_X) {
> > >         request_irq()...
> > > }
> >
> > Won't this still break with current devicetree since irq < 0 until
> > patch 3? Or are you saying we shouldn't check for
> > platform_get_irq_byname() failure?
> >
>
> I'm trying to say that dtsi without "critical" defined should cause the
> driver to simply skip this segment, not fail to initialize.
>
> > I can see two ways out:
> > 1. We patch the dtsi before the code change.
>
> You're expected to maintain backwards compatibility with existing dtb
> files out there. The support for critical interrupt is an additional
> feature, so you should be able to do this by detecting if "critical" is
> defined (e.g. by checking the return value of
> platform_get_irq_byname()).
>
> > 2. We make critical interrupt failure non-fatal by just printing some
> > messages and still returning success.
> >
>
> Try to make it as specific as possible (without adding a bunch of code)
> and throw in a dev_info() if no "critical" is found.

I believe I have now addressed the problem in v2 explicitly overriding
the return value in case of failure in the critical interrupt irq
setup path and simply printing a warning.

In hindsight, critical interrupt support should've been added in the
same series as uplow interrupt support so avoid having to support
"intermediate" DTS file state for one kernel version.

Regards,
Amit

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

end of thread, back to index

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-11 19:21 [PATCH 0/3] thermal: tsens: Handle critical interrupts Amit Kucheria
2019-11-11 19:21 ` [PATCH 1/3] drivers: thermal: tsens: Add critical interrupt support Amit Kucheria
2019-11-12 19:38   ` Bjorn Andersson
2019-11-28 18:46     ` Amit Kucheria
2019-11-28 21:43       ` Bjorn Andersson
2019-12-03  5:02         ` Amit Kucheria
2019-11-14 22:50   ` Stephen Boyd
2019-12-03  4:57     ` Amit Kucheria
2019-11-11 19:21 ` [PATCH 2/3] drivers: thermal: tsens: Add watchdog support Amit Kucheria
2019-11-12 19:22   ` Bjorn Andersson
2019-11-28 19:18     ` Amit Kucheria
2019-11-14 22:38   ` Stephen Boyd
2019-11-28 19:16     ` Amit Kucheria
2019-11-11 19:21 ` [PATCH 3/3] arm64: dts: sdm845: thermal: Add critical interrupt support Amit Kucheria
2019-11-12 19:43   ` Bjorn Andersson

Linux-ARM-MSM Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-arm-msm/0 linux-arm-msm/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-arm-msm linux-arm-msm/ https://lore.kernel.org/linux-arm-msm \
		linux-arm-msm@vger.kernel.org
	public-inbox-index linux-arm-msm

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-arm-msm


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git