From: sashiko-bot@kernel.org
To: "Salih Erim" <salih.erim@amd.com>
Cc: robh@kernel.org, devicetree@vger.kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v9 4/5] iio: adc: versal-sysmon: add threshold event support
Date: Wed, 17 Jun 2026 21:01:13 +0000 [thread overview]
Message-ID: <20260617210113.CF40C1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260617180147.3370346-5-salih.erim@amd.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Integer Overflow and Missing Bit Masking in Threshold Calculations
- [High] Supply Voltage Threshold Events Permanently Disabled on Trigger
- [High] Kernel Panic from Sleeping in Atomic Context on I2C Devices
- [High] Race Condition Desynchronizes Hardware Interrupt State
--
commit 0d7222f55024a692e00cced200dc17d0764c1060
Author: Salih Erim <salih.erim@amd.com>
iio: adc: versal-sysmon: add threshold event support
Adds threshold event support for temperature and supply voltage channels.
It uses hysteresis mode for temperature and provides per-channel alarm
enable for supply voltages. The interrupt handler masks active threshold
interrupts and schedules a delayed worker to poll.
> diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
> index e0b9b3d2b6d13..19a8edd89198c 100644
> --- a/drivers/iio/adc/versal-sysmon-core.c
> +++ b/drivers/iio/adc/versal-sysmon-core.c
[ ... ]
> @@ -52,6 +101,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: High]
Can this left shift overflow on negative or large sysfs values? Unlike the
voltage path, this function also seems to lack value clamping and a (u16)
bitmask. Since sysmon_write_event_value() writes this raw 32-bit value
directly to SYSMON_TEMP_TH_UP, could it overwrite reserved hardware bits
with sign-extended negative values like 0xFFFFEC00?
> +
> static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
> {
> int mantissa, format, exponent;
> @@ -69,6 +128,33 @@ static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
> *val = (mantissa * (int)MILLI) >> exponent;
> }
>
> +static void sysmon_supply_processedtoraw(int val, u32 reg_val, u32 *raw_data)
> +{
> + int exponent = FIELD_GET(SYSMON_MODE_MASK, reg_val);
> + int format = FIELD_GET(SYSMON_FMT_MASK, reg_val);
> + int scale, tmp;
> +
> + scale = BIT(SYSMON_SUPPLY_MANTISSA_BITS - exponent);
> + tmp = (val * scale) / (int)MILLI;
[Severity: High]
Can this 32-bit multiplication overflow on large sysfs inputs? If scale is up
to 65536, a large val could cause an integer overflow before the division.
> +
> + if (format)
> + tmp = clamp(tmp, S16_MIN, S16_MAX);
> + else
> + tmp = clamp(tmp, 0, U16_MAX);
> +
> + *raw_data = (u16)tmp;
> +}
[ ... ]
> +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]
Is there a race condition here if sysmon_unmask_worker() runs concurrently?
By writing to SYSMON_IDR before acquiring sysmon->irq_lock to update
sysmon->temp_mask, the concurrent worker might read the old temp_mask (where
the bit is still 0/enabled). Could the worker then write to SYSMON_IER in
sysmon_unmask_temp(), effectively re-enabling the interrupt in hardware
immediately after userspace administratively disabled it?
[ ... ]
> +static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event)
> +{
> + u32 alarm_flag_offset = SYSMON_ALARM_FLAG + event * SYSMON_REG_STRIDE;
> + u32 alarm_reg_offset = SYSMON_ALARM_REG + event * SYSMON_REG_STRIDE;
> + struct sysmon *sysmon = iio_priv(indio_dev);
> + unsigned long alarm_flag_reg;
> + unsigned int reg_val;
> + u32 address, bit;
> + int ret;
> +
> + switch (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, ®_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]
Does clearing this bit permanently disable the supply voltage hardware alarm?
The alarm_reg_offset here points to SYSMON_ALARM_REG, which
sysmon_write_alarm_config() uses as the alarm configuration/enable register.
Since there is no mechanism to re-enable voltage alarms later, does this turn
continuous threshold events into one-shot events?
> + if (ret)
> + return ret;
> + }
> +
> + return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg);
> +
> + default:
> + return -EINVAL;
> + }
> +}
[ ... ]
> +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;
[Severity: High]
Can this cause a "scheduling while atomic" panic on I2C devices?
The driver takes a spinlock with interrupts disabled via spinlock_irq,
but then calls regmap_read() which uses a sleeping mutex on I2C buses.
A similar sequence occurs in the hardirq handler sysmon_iio_irq().
> + regmap_write(sysmon->regmap, SYSMON_ISR, isr);
> + sysmon_unmask_temp(sysmon, isr);
> + }
[ ... ]
> +static int sysmon_init_interrupt(struct sysmon *sysmon,
> + struct device *dev,
> + struct iio_dev *indio_dev,
> + int irq)
> +{
> + unsigned int imr;
> + int ret;
> +
> + /* Events not supported without IRQ (e.g. I2C path) */
> + if (!irq)
> + return 0;
> +
> + INIT_DELAYED_WORK(&sysmon->sysmon_unmask_work, sysmon_unmask_worker);
> +
> + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
> + if (ret)
> + return ret;
> + sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK;
> +
> + ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev);
[Severity: High]
Should we verify that the regmap doesn't sleep before requesting the IRQ?
If a user provides an interrupts property for an I2C-connected device in
the Device Tree, it looks like this will register sysmon_iio_irq() as a
hardirq handler and trigger the atomic sleep violations mentioned above.
> + if (ret)
> + return ret;
> +
> + return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617180147.3370346-1-salih.erim@amd.com?part=4
next prev parent reply other threads:[~2026-06-17 21:01 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-17 18:01 [PATCH v9 0/5] iio: adc: add Versal SysMon driver Salih Erim
2026-06-17 18:01 ` [PATCH v9 1/5] dt-bindings: iio: adc: add xlnx,versal-sysmon binding Salih Erim
2026-06-17 18:01 ` [PATCH v9 2/5] iio: adc: add Versal SysMon driver Salih Erim
2026-06-17 18:01 ` [PATCH v9 3/5] iio: adc: versal-sysmon: add I2C driver Salih Erim
2026-06-17 20:47 ` sashiko-bot
2026-06-17 18:01 ` [PATCH v9 4/5] iio: adc: versal-sysmon: add threshold event support Salih Erim
2026-06-17 21:01 ` sashiko-bot [this message]
2026-06-17 18:01 ` [PATCH v9 5/5] iio: adc: versal-sysmon: add oversampling support Salih Erim
2026-06-17 21:07 ` 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=20260617210113.CF40C1F000E9@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.