All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Salih Erim" <salih.erim@amd.com>
Cc: conor+dt@kernel.org, robh@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH v12 4/5] iio: adc: versal-sysmon: add threshold event support
Date: Wed, 24 Jun 2026 14:53:48 +0000	[thread overview]
Message-ID: <20260624145349.2228E1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260624143722.4047649-5-salih.erim@amd.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Supply voltage threshold events permanently disable themselves in hardware upon triggering.
- [High] Unmask worker silently drops voltage alarms.
- [High] Use-After-Free due to delayed work scheduling after cancellation during unbind.
- [High] Race condition in interrupt configuration re-enables masked alarms.
- [High] Hard IRQ handler triggers sleep-in-atomic panic on I2C devices.
- [Medium] Data corruption when setting negative temperature thresholds.
- [Medium] Integer underflow in lower threshold calculation breaks hardware alarms.
--

commit 5011ca744b3ab433f6a307686494ec49213c41b4
Author: Salih Erim <salih.erim@amd.com>

iio: adc: versal-sysmon: add threshold event support

Add threshold event support for temperature and supply voltage channels,
introducing hysteresis mode for temperature and window mode for supply alarms.

> diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
> index 03a745d3fb4f3..8f2c502d9cb6d 100644
> --- a/drivers/iio/adc/versal-sysmon-core.c
> +++ b/drivers/iio/adc/versal-sysmon-core.c
[ ... ]
> @@ -52,6 +102,16 @@ static const struct iio_chan_spec temp_channels[] = {
>  	SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"),
>  };
>  
> +static void sysmon_q8p7_to_millicelsius(s16 raw_data, int *val)
> +{
> +	*val = (raw_data * MILLIDEGREE_PER_DEGREE) >> SYSMON_FRACTIONAL_SHIFT;
> +}
> +
> +static void sysmon_millicelsius_to_q8p7(u32 *raw_data, int val)
> +{
> +	*raw_data = (val << SYSMON_FRACTIONAL_SHIFT) / MILLIDEGREE_PER_DEGREE;
> +}

[Severity: Medium]
When a negative threshold (e.g., -256000 mC) is converted to Q8.7 format in
sysmon_millicelsius_to_q8p7(), will it produce a negative 32-bit integer due
to sign extension?

If this negative value is subsequently written directly to the 32-bit
hardware registers without masking, could it overwrite the upper 16 bits with
1s and corrupt the hardware register state?

[ ... ]
> +static int sysmon_write_event_config(struct iio_dev *indio_dev,
> +				     const struct iio_chan_spec *chan,
> +				     enum iio_event_type type,
> +				     enum iio_event_direction dir,
> +				     bool state)
> +{
[ ... ]
> +	case IIO_TEMP:
> +		if (state) {
> +			ret = regmap_write(sysmon->regmap, SYSMON_IER, mask);
> +			if (ret)
> +				return ret;
> +
> +			scoped_guard(spinlock_irq, &sysmon->irq_lock)
> +				sysmon->temp_mask &= ~mask;
> +		} else {
> +			ret = regmap_write(sysmon->regmap, SYSMON_IDR, mask);
> +			if (ret)
> +				return ret;
> +
> +			scoped_guard(spinlock_irq, &sysmon->irq_lock)
> +				sysmon->temp_mask |= mask;
> +		}
> +		return 0;

[Severity: High]
Because the hardware interrupt is disabled via SYSMON_IDR outside the
sysmon->irq_lock, can a race condition occur with the unmask worker?

If the worker runs concurrently, holds the lock, and calculates the enable
mask using the old state, might it write to SYSMON_IER and override this
disable command, resulting in unexpected interrupts?

[ ... ]
> +static int sysmon_update_temp_lower(struct sysmon *sysmon)
> +{
> +	unsigned int upper_reg;
> +	int upper_mc, lower_mc;
> +	u32 raw_val;
> +	int ret;
> +
> +	ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
> +	if (ret)
> +		return ret;
> +
> +	sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
> +	lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992);

[Severity: Medium]
Since sysmon->temp_hysteresis can accept any positive value up to INT_MAX,
will subtracting a large hysteresis from a negative upper threshold
mathematically underflow a 32-bit signed integer? 

If an underflow occurs here, wrapping to a positive value, will clamp() then
incorrectly set the lower re-arm threshold higher than the upper threshold
and break the hardware alarm logic?

> +	sysmon_millicelsius_to_q8p7(&raw_val, lower_mc);
> +
> +	return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val);
> +}
[ ... ]
> +static int sysmon_write_event_value(struct iio_dev *indio_dev,
> +				    const struct iio_chan_spec *chan,
> +				    enum iio_event_type type,
> +				    enum iio_event_direction dir,
> +				    enum iio_event_info info,
> +				    int val, int val2)
> +{
[ ... ]
> +	case IIO_TEMP:
> +		switch (info) {
> +		case IIO_EV_INFO_VALUE:
> +			/* Q8.7 signed range: -256000 to +255992 mC */
> +			if (val < -256000 || val > 255992)
> +				return -EINVAL;
> +
> +			sysmon_millicelsius_to_q8p7(&raw_val, val);
> +
> +			ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val);
> +			if (ret)
> +				return ret;
> +
> +			/* Recompute lower = upper - hysteresis */
> +			return sysmon_update_temp_lower(sysmon);
> +
> +		case IIO_EV_INFO_HYSTERESIS:
> +			if (val < 0)
> +				return -EINVAL;
> +
> +			sysmon->temp_hysteresis = val;
> +
> +			return sysmon_update_temp_lower(sysmon);

[ ... ]
> +static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event)
> +{
[ ... ]
> +	case SYSMON_BIT_ALARM0:
> +	case SYSMON_BIT_ALARM1:
> +	case SYSMON_BIT_ALARM2:
> +	case SYSMON_BIT_ALARM3:
> +	case SYSMON_BIT_ALARM4:
> +		ret = regmap_read(sysmon->regmap, alarm_flag_offset, &reg_val);
> +		if (ret)
> +			return ret;
> +
> +		alarm_flag_reg = reg_val;
> +
> +		for_each_set_bit(bit, &alarm_flag_reg, SYSMON_ALARM_BITS_PER_REG) {
> +			address = bit + SYSMON_ALARM_BITS_PER_REG * event;
> +			sysmon_push_event(indio_dev, address);
> +			ret = regmap_clear_bits(sysmon->regmap, alarm_reg_offset, BIT(bit));

[Severity: High]
The IRQ handler clears the administrative alarm configuration bit in hardware
when a voltage alarm triggers. Does the driver ever re-arm supply alarms like
it does for temperature alarms in the delayed worker? 

If not, will a single threshold event permanently disable the supply alarm in
hardware?

> +			if (ret)
> +				return ret;
> +		}
> +
> +		return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg);
[ ... ]
> +static void sysmon_unmask_worker(struct work_struct *work)
> +{
> +	struct sysmon *sysmon =
> +		container_of(work, struct sysmon, sysmon_unmask_work.work);
> +	unsigned int isr;
> +
> +	/*
> +	 * If the ISR read fails, skip processing to avoid acting
> +	 * on undefined data.
> +	 */
> +	scoped_guard(spinlock_irq, &sysmon->irq_lock) {
> +		if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr))
> +			break;
> +		regmap_write(sysmon->regmap, SYSMON_ISR, isr);
> +		sysmon_unmask_temp(sysmon, isr);
> +	}

[Severity: High]
Since SYSMON_ISR is a write-1-to-clear register, does writing the entire ISR
back clear all pending interrupts, including any newly asserted voltage alarms?

Because the worker only calls sysmon_unmask_temp() and ignores the voltage
alarm bits, will this silently drop any voltage alarms that fired during the
worker's execution?

> +
> +	if (sysmon->masked_temp)
> +		schedule_delayed_work(&sysmon->sysmon_unmask_work,
> +				      msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
> +	else
> +		regmap_write(sysmon->regmap, SYSMON_STATUS_RESET, 1);
> +}
> +
> +static irqreturn_t sysmon_iio_irq(int irq, void *data)
> +{
> +	struct iio_dev *indio_dev = data;
> +	struct sysmon *sysmon = iio_priv(indio_dev);
> +	unsigned int isr, imr;
> +
> +	guard(spinlock)(&sysmon->irq_lock);
> +
> +	if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr) ||
> +	    regmap_read(sysmon->regmap, SYSMON_IMR, &imr))
> +		return IRQ_NONE;

[Severity: High]
If the device is instantiated on an I2C bus and the device tree provides an
interrupts property, will this hardirq handler trigger a scheduling while
atomic panic?

The handler acquires a spinlock and calls regmap_read(), which would sleep
when using the I2C bus's mutex-based locking. Should the driver verify if the
regmap is suitable for atomic context before requesting the IRQ?

[ ... ]
> +static void sysmon_disable_interrupts(void *data)
> +{
> +	struct sysmon *sysmon = data;
> +
> +	regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
> +
> +	scoped_guard(spinlock_irq, &sysmon->irq_lock)
> +		sysmon->masked_temp = 0;
> +
> +	cancel_delayed_work_sync(&sysmon->sysmon_unmask_work);
> +}
> +
> +static int sysmon_init_interrupt(struct sysmon *sysmon,
> +				 struct device *dev,
> +				 struct iio_dev *indio_dev,
> +				 int irq)
> +{
[ ... ]
> +	ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon);
> +}

[Severity: High]
During unbind, sysmon_disable_interrupts() cancels the delayed work before
the IRQ handler is freed. If an interrupt fires after
cancel_delayed_work_sync() returns, will the still-active sysmon_iio_irq()
handler reschedule the delayed work?

Could this cause a use-after-free when the sysmon structure is freed shortly
after, allowing the delayed work to execute 500ms later on freed memory?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260624143722.4047649-1-salih.erim@amd.com?part=4

  reply	other threads:[~2026-06-24 14:53 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-24 14:37 [PATCH v12 0/5] iio: adc: add Versal SysMon driver Salih Erim
2026-06-24 14:37 ` [PATCH v12 1/5] dt-bindings: iio: adc: add xlnx,versal-sysmon binding Salih Erim
2026-06-24 14:37 ` [PATCH v12 2/5] iio: adc: add Versal SysMon driver Salih Erim
2026-06-24 14:37 ` [PATCH v12 3/5] iio: adc: versal-sysmon: add I2C driver Salih Erim
2026-06-24 14:50   ` sashiko-bot
2026-06-24 14:37 ` [PATCH v12 4/5] iio: adc: versal-sysmon: add threshold event support Salih Erim
2026-06-24 14:53   ` sashiko-bot [this message]
2026-06-24 14:37 ` [PATCH v12 5/5] iio: adc: versal-sysmon: add oversampling support Salih Erim
2026-06-24 14:50   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260624145349.2228E1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=salih.erim@amd.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.