Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: adis: add '__adis_enable_irq()' implementation

Add '__adis_enable_irq()' implementation which is the unlocked
version of 'adis_enable_irq()'.
Call '__adis_enable_irq()' instead of 'adis_enable_irq()' from
'__adis_intial_startup()' to keep the expected unlocked functionality.

This fix is needed to remove a deadlock for all devices which are
using 'adis_initial_startup()'. The deadlock occurs because the
same mutex is acquired twice, without releasing it.
The mutex is acquired once inside 'adis_initial_startup()', before
calling '__adis_initial_startup()', and once inside
'adis_enable_irq()', which is called by '__adis_initial_startup()'.
The deadlock is removed by calling '__adis_enable_irq()', instead of
'adis_enable_irq()' from within '__adis_initial_startup()'.

Fixes: b600bd7eb3335 ("iio: adis: do not disabe IRQs in 'adis_init()'")
Signed-off-by: Ramona Bolboaca <ramona.bolboaca@analog.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20221122082757.449452-2-ramona.bolboaca@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Ramona Bolboaca and committed by
Jonathan Cameron
99c05e42 99b43a15

+22 -19
+10 -18
drivers/iio/imu/adis.c
··· 270 270 #endif 271 271 272 272 /** 273 - * adis_enable_irq() - Enable or disable data ready IRQ 273 + * __adis_enable_irq() - Enable or disable data ready IRQ (unlocked) 274 274 * @adis: The adis device 275 275 * @enable: Whether to enable the IRQ 276 276 * 277 277 * Returns 0 on success, negative error code otherwise 278 278 */ 279 - int adis_enable_irq(struct adis *adis, bool enable) 279 + int __adis_enable_irq(struct adis *adis, bool enable) 280 280 { 281 - int ret = 0; 281 + int ret; 282 282 u16 msc; 283 283 284 - mutex_lock(&adis->state_lock); 285 - 286 - if (adis->data->enable_irq) { 287 - ret = adis->data->enable_irq(adis, enable); 288 - goto out_unlock; 289 - } 284 + if (adis->data->enable_irq) 285 + return adis->data->enable_irq(adis, enable); 290 286 291 287 if (adis->data->unmasked_drdy) { 292 288 if (enable) ··· 290 294 else 291 295 disable_irq(adis->spi->irq); 292 296 293 - goto out_unlock; 297 + return 0; 294 298 } 295 299 296 300 ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc); 297 301 if (ret) 298 - goto out_unlock; 302 + return ret; 299 303 300 304 msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH; 301 305 msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2; ··· 304 308 else 305 309 msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN; 306 310 307 - ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc); 308 - 309 - out_unlock: 310 - mutex_unlock(&adis->state_lock); 311 - return ret; 311 + return __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc); 312 312 } 313 - EXPORT_SYMBOL_NS(adis_enable_irq, IIO_ADISLIB); 313 + EXPORT_SYMBOL_NS(__adis_enable_irq, IIO_ADISLIB); 314 314 315 315 /** 316 316 * __adis_check_status() - Check the device for error conditions (unlocked) ··· 437 445 * with 'IRQF_NO_AUTOEN' anyways. 438 446 */ 439 447 if (!adis->data->unmasked_drdy) 440 - adis_enable_irq(adis, false); 448 + __adis_enable_irq(adis, false); 441 449 442 450 if (!adis->data->prod_id_reg) 443 451 return 0;
+12 -1
include/linux/iio/imu/adis.h
··· 402 402 __adis_update_bits_base(adis, reg, mask, val, sizeof(val)); \ 403 403 }) 404 404 405 - int adis_enable_irq(struct adis *adis, bool enable); 406 405 int __adis_check_status(struct adis *adis); 407 406 int __adis_initial_startup(struct adis *adis); 407 + int __adis_enable_irq(struct adis *adis, bool enable); 408 + 409 + static inline int adis_enable_irq(struct adis *adis, bool enable) 410 + { 411 + int ret; 412 + 413 + mutex_lock(&adis->state_lock); 414 + ret = __adis_enable_irq(adis, enable); 415 + mutex_unlock(&adis->state_lock); 416 + 417 + return ret; 418 + } 408 419 409 420 static inline int adis_check_status(struct adis *adis) 410 421 {