Re: [PATCH net-next 09/12] gpio: tc956x: add TC956x/QPS615 support

Alex Elder <[email protected]> Fri, 29 May 2026 21:04:42 -0500
Newsgroups dev.linux.lists.sashiko,org.kernel.vger.bpf
Message-ID <[email protected]>
On 5/2/26 10:56 AM, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
> - [High] Function signature mismatch for `tc956x_gpio_set` causing build failures.
> - [High] Sleeping in atomic context bug on PREEMPT_RT due to `can_sleep = false`.
> - [Medium] Uninitialized stack variable used if `regmap_read()` fails.
> - [Medium] Ignored `regmap_update_bits()` return value can cause incorrect hardware state.
> - [Low] Kconfig depends on a non-existent symbol.
> --
> 
> commit ff81a192de0fcb35d3c4b8a32cad777cd0bff29e
> Author: Alex Elder <[email protected]>
> 
> gpio: tc956x: add TC956x/QPS615 support
> 
> This commit adds support for the GPIO controller embedded in the Toshiba
> TC956x Ethernet-AVB/TSN bridge. It implements an auxiliary device driver
> for the GPIO block using regmap.
> 
>> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
>> --- a/drivers/gpio/Kconfig
>> +++ b/drivers/gpio/Kconfig
> [ ... ]
>> +config GPIO_TC956X
>> +	tristate "Toshiba TC956X GPIO support"
>> +	depends on TOSHIBA_TC956X_PCI
> 
> Does TOSHIBA_TC956X_PCI exist in the tree at this point? Reference to a
> non-existent config symbol causes silent build failures. If it is added
> later in the patch series, this temporarily leaves the driver unselectable
> and breaks bisectability.

In version 2 of the series, the patch that defines TOSHIBA_TC956X_PCI
will come earlier than this one in the series.

> 
> [ ... ]
>> diff --git a/drivers/gpio/gpio-tc956x.c b/drivers/gpio/gpio-tc956x.c
>> --- /dev/null
>> +++ b/drivers/gpio/gpio-tc956x.c
> [ ... ]
>> +static int tc956x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
>> +{
>> +	struct tc956x_gpio *gpio = gpiochip_get_data(gc);
>> +	u32 reg;
>> +	u32 val;
>> +
>> +	if (test_bit(offset, gpio->input_only))
>> +		return GPIO_LINE_DIRECTION_IN;
>> +
>> +	reg = offset < 32 ? GPIO_EN0_OFFSET : GPIO_EN1_OFFSET;
>> +
>> +	regmap_read(gpio->regmap, reg, &val);
> 
> If regmap_read() fails, does it leave the stack variable val uninitialized?
> Should the return value be checked before evaluating val in the next line?

In this case, we know we are using an MMIO-based regmap, and
since we have no clock, regmap_mmio_read() always returns 0.

>> +	if (val & BIT(offset % 32))
>> +		return GPIO_LINE_DIRECTION_IN;
>> +
>> +	return GPIO_LINE_DIRECTION_OUT;
>> +}
> [ ... ]
>> +static int tc956x_gpio_direction_output(struct gpio_chip *gc,
>> +					unsigned int offset, int value)
>> +{
>> +	struct tc956x_gpio *gpio = gpiochip_get_data(gc);
>> +	u32 vreg;
>> +	u32 dreg;
>> +	u32 mask;
> [ ... ]
>> +	/* Set output value first, then direction */
>> +	regmap_update_bits(gpio->regmap, vreg, mask, value ? mask : 0);
> 
> If this first regmap_update_bits() fails, should the function bail out
> early? Ignoring the error and proceeding to change the direction to output
> anyway could actively drive an unintended logic level onto the pin.

Again, we do not expect regmap_update_bits() to return an error
for an MMIO-based regmap.

>> +
>> +	return regmap_update_bits(gpio->regmap, dreg, mask, 0);
>> +}
>> +
>> +static int tc956x_gpio_get(struct gpio_chip *gc, unsigned int offset)
>> +{
>> +	u32 reg = offset < 32 ? GPIO_IN0_OFFSET : GPIO_IN1_OFFSET;
>> +	struct tc956x_gpio *gpio = gpiochip_get_data(gc);
>> +	u32 val;
>> +
>> +	regmap_read(gpio->regmap, reg, &val);
> 
> Similar to tc956x_gpio_get_direction(), does this leave val uninitialized
> and return unpredictable states if regmap_read() fails?

This should not fail, so we expect val will be initialized.

> 
>> +
>> +	return val & BIT(offset % 32) ? 1 : 0;
>> +}
>> +
>> +static int tc956x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
> 
> Does the set function pointer in struct gpio_chip expect a void return
> type? Assigning a function returning int could trigger an incompatible
> pointer type compiler error or cause Control Flow Integrity panics at
> runtime.

I might be missing something but I don't understand this comment.
In any case, the next version of the code implements the GPIO
controller using the gpio-regmap framework.

> 
>> +{
>> +	u32 reg = offset < 32 ? GPIO_OUT0_OFFSET : GPIO_OUT1_OFFSET;
>> +	struct tc956x_gpio *gpio = gpiochip_get_data(gc);
>> +	u32 mask = BIT(offset % 32);
>> +
>> +	return regmap_update_bits(gpio->regmap, reg, mask, value ? mask : 0);
>> +}
> [ ... ]
>> +static int tc956x_gpio_probe(struct auxiliary_device *adev,
>> +			     const struct auxiliary_device_id *id)
>> +{
> [ ... ]
>> +	gc->base = -1;
>> +	gc->ngpio = TC956X_GPIO_COUNT;
>> +	gc->can_sleep = false;
> 
> Is it safe to set can_sleep to false while using a regmap? By default,
> MMIO regmaps use spinlock_t for synchronization, which becomes a sleepable
> rt_mutex on PREEMPT_RT kernels. Calling these GPIO methods from an atomic
> context on PREEMPT_RT could cause a panic.

Here too, even if this were an issue, the issue will move into
the gpio-regmap code with the new version of the code.

					-Alex

> 
>> +
>> +	dev_set_drvdata(dev, gpio);
>> +
>> +	return devm_gpiochip_add_data(dev, gc, gpio);
>> +}
>