Re: [PATCH 2/3] drivers: thermal: tsens: Add watchdog support

From: Amit Kucheria
Date: Thu Nov 28 2019 - 14:19:16 EST


On Wed, Nov 13, 2019 at 12:52 AM Bjorn Andersson
<bjorn.andersson@xxxxxxxxxx> 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@xxxxxxxxxx>
> > ---
> > 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
> >