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