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

i2c: pnx: Fix potential deadlock warning from del_timer_sync() call in isr

When del_timer_sync() is called in an interrupt context it throws a warning
because of potential deadlock. The timer is used only to exit from
wait_for_completion() after a timeout so replacing the call with
wait_for_completion_timeout() allows to remove the problematic timer and
its related functions altogether.

Fixes: 41561f28e76a ("i2c: New Philips PNX bus driver")
Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>

authored by

Piotr Wojtaszczyk and committed by
Andi Shyti
f63b94be 22a40d14

+10 -38
+10 -38
drivers/i2c/busses/i2c-pnx.c
··· 15 15 #include <linux/ioport.h> 16 16 #include <linux/delay.h> 17 17 #include <linux/i2c.h> 18 - #include <linux/timer.h> 19 18 #include <linux/completion.h> 20 19 #include <linux/platform_device.h> 21 20 #include <linux/io.h> ··· 31 32 int ret; /* Return value */ 32 33 int mode; /* Interface mode */ 33 34 struct completion complete; /* I/O completion */ 34 - struct timer_list timer; /* Timeout */ 35 35 u8 * buf; /* Data buffer */ 36 36 int len; /* Length of data buffer */ 37 37 int order; /* RX Bytes to order via TX */ ··· 113 115 timeout--; 114 116 } 115 117 return (timeout <= 0); 116 - } 117 - 118 - static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) 119 - { 120 - struct timer_list *timer = &alg_data->mif.timer; 121 - unsigned long expires = msecs_to_jiffies(alg_data->timeout); 122 - 123 - if (expires <= 1) 124 - expires = 2; 125 - 126 - del_timer_sync(timer); 127 - 128 - dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n", 129 - jiffies, expires); 130 - 131 - timer->expires = jiffies + expires; 132 - 133 - add_timer(timer); 134 118 } 135 119 136 120 /** ··· 239 259 ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), 240 260 I2C_REG_CTL(alg_data)); 241 261 242 - del_timer_sync(&alg_data->mif.timer); 243 - 244 262 dev_dbg(&alg_data->adapter.dev, 245 263 "%s(): Waking up xfer routine.\n", 246 264 __func__); ··· 254 276 ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), 255 277 I2C_REG_CTL(alg_data)); 256 278 257 - /* Stop timer. */ 258 - del_timer_sync(&alg_data->mif.timer); 259 279 dev_dbg(&alg_data->adapter.dev, 260 280 "%s(): Waking up xfer routine after zero-xfer.\n", 261 281 __func__); ··· 340 364 mcntrl_drmie | mcntrl_daie); 341 365 iowrite32(ctl, I2C_REG_CTL(alg_data)); 342 366 343 - /* Kill timer. */ 344 - del_timer_sync(&alg_data->mif.timer); 345 367 complete(&alg_data->mif.complete); 346 368 } 347 369 } ··· 374 400 mcntrl_drmie); 375 401 iowrite32(ctl, I2C_REG_CTL(alg_data)); 376 402 377 - /* Stop timer, to prevent timeout. */ 378 - del_timer_sync(&alg_data->mif.timer); 379 403 complete(&alg_data->mif.complete); 380 404 } else if (stat & mstatus_nai) { 381 405 /* Slave did not acknowledge, generate a STOP */ ··· 391 419 /* Our return value. */ 392 420 alg_data->mif.ret = -EIO; 393 421 394 - /* Stop timer, to prevent timeout. */ 395 - del_timer_sync(&alg_data->mif.timer); 396 422 complete(&alg_data->mif.complete); 397 423 } else { 398 424 /* ··· 423 453 return IRQ_HANDLED; 424 454 } 425 455 426 - static void i2c_pnx_timeout(struct timer_list *t) 456 + static void i2c_pnx_timeout(struct i2c_pnx_algo_data *alg_data) 427 457 { 428 - struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); 429 458 u32 ctl; 430 459 431 460 dev_err(&alg_data->adapter.dev, ··· 441 472 iowrite32(ctl, I2C_REG_CTL(alg_data)); 442 473 wait_reset(alg_data); 443 474 alg_data->mif.ret = -EIO; 444 - complete(&alg_data->mif.complete); 445 475 } 446 476 447 477 static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) ··· 482 514 struct i2c_msg *pmsg; 483 515 int rc = 0, completed = 0, i; 484 516 struct i2c_pnx_algo_data *alg_data = adap->algo_data; 517 + unsigned long time_left; 485 518 u32 stat; 486 519 487 520 dev_dbg(&alg_data->adapter.dev, ··· 517 548 dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", 518 549 __func__, alg_data->mif.mode, alg_data->mif.len); 519 550 520 - i2c_pnx_arm_timer(alg_data); 521 551 522 552 /* initialize the completion var */ 523 553 init_completion(&alg_data->mif.complete); ··· 532 564 break; 533 565 534 566 /* Wait for completion */ 535 - wait_for_completion(&alg_data->mif.complete); 567 + time_left = wait_for_completion_timeout(&alg_data->mif.complete, 568 + alg_data->timeout); 569 + if (time_left == 0) 570 + i2c_pnx_timeout(alg_data); 536 571 537 572 if (!(rc = alg_data->mif.ret)) 538 573 completed++; ··· 624 653 alg_data->adapter.algo_data = alg_data; 625 654 alg_data->adapter.nr = pdev->id; 626 655 627 - alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT; 656 + alg_data->timeout = msecs_to_jiffies(I2C_PNX_TIMEOUT_DEFAULT); 657 + if (alg_data->timeout <= 1) 658 + alg_data->timeout = 2; 659 + 628 660 #ifdef CONFIG_OF 629 661 alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node); 630 662 if (pdev->dev.of_node) { ··· 646 672 alg_data->clk = devm_clk_get(&pdev->dev, NULL); 647 673 if (IS_ERR(alg_data->clk)) 648 674 return PTR_ERR(alg_data->clk); 649 - 650 - timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); 651 675 652 676 snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), 653 677 "%s", pdev->name);