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

net: arcnet: Fix RESET flag handling

The main arcnet interrupt handler calls arcnet_close() then
arcnet_open(), if the RESET status flag is encountered.

This is invalid:

1) In general, interrupt handlers should never call ->ndo_stop() and
->ndo_open() functions. They are usually full of blocking calls and
other methods that are expected to be called only from drivers
init and exit code paths.

2) arcnet_close() contains a del_timer_sync(). If the irq handler
interrupts the to-be-deleted timer, del_timer_sync() will just loop
forever.

3) arcnet_close() also calls tasklet_kill(), which has a warning if
called from irq context.

4) For device reset, the sequence "arcnet_close(); arcnet_open();" is
not complete. Some children arcnet drivers have special init/exit
code sequences, which then embed a call to arcnet_open() and
arcnet_close() accordingly. Check drivers/net/arcnet/com20020.c.

Run the device RESET sequence from a scheduled workqueue instead.

Signed-off-by: Ahmed S. Darwish <a.darwish@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://lore.kernel.org/r/20210128194802.727770-1-a.darwish@linutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Ahmed S. Darwish and committed by
Jakub Kicinski
01365633 06cc6e5d

+78 -14
+2 -2
drivers/net/arcnet/arc-rimi.c
··· 332 332 dev->irq = 9; 333 333 334 334 if (arcrimi_probe(dev)) { 335 - free_netdev(dev); 335 + free_arcdev(dev); 336 336 return -EIO; 337 337 } 338 338 ··· 349 349 iounmap(lp->mem_start); 350 350 release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); 351 351 free_irq(dev->irq, dev); 352 - free_netdev(dev); 352 + free_arcdev(dev); 353 353 } 354 354 355 355 #ifndef MODULE
+6
drivers/net/arcnet/arcdevice.h
··· 298 298 299 299 int excnak_pending; /* We just got an excesive nak interrupt */ 300 300 301 + /* RESET flag handling */ 302 + int reset_in_progress; 303 + struct work_struct reset_work; 304 + 301 305 struct { 302 306 uint16_t sequence; /* sequence number (incs with each packet) */ 303 307 __be16 aborted_seq; ··· 354 350 355 351 void arcnet_unregister_proto(struct ArcProto *proto); 356 352 irqreturn_t arcnet_interrupt(int irq, void *dev_id); 353 + 357 354 struct net_device *alloc_arcdev(const char *name); 355 + void free_arcdev(struct net_device *dev); 358 356 359 357 int arcnet_open(struct net_device *dev); 360 358 int arcnet_close(struct net_device *dev);
+62 -4
drivers/net/arcnet/arcnet.c
··· 387 387 struct arcnet_local *lp = from_timer(lp, t, timer); 388 388 struct net_device *dev = lp->dev; 389 389 390 - if (!netif_carrier_ok(dev)) { 390 + spin_lock_irq(&lp->lock); 391 + 392 + if (!lp->reset_in_progress && !netif_carrier_ok(dev)) { 391 393 netif_carrier_on(dev); 392 394 netdev_info(dev, "link up\n"); 393 395 } 396 + 397 + spin_unlock_irq(&lp->lock); 398 + } 399 + 400 + static void reset_device_work(struct work_struct *work) 401 + { 402 + struct arcnet_local *lp; 403 + struct net_device *dev; 404 + 405 + lp = container_of(work, struct arcnet_local, reset_work); 406 + dev = lp->dev; 407 + 408 + /* Do not bring the network interface back up if an ifdown 409 + * was already done. 410 + */ 411 + if (!netif_running(dev) || !lp->reset_in_progress) 412 + return; 413 + 414 + rtnl_lock(); 415 + 416 + /* Do another check, in case of an ifdown that was triggered in 417 + * the small race window between the exit condition above and 418 + * acquiring RTNL. 419 + */ 420 + if (!netif_running(dev) || !lp->reset_in_progress) 421 + goto out; 422 + 423 + dev_close(dev); 424 + dev_open(dev, NULL); 425 + 426 + out: 427 + rtnl_unlock(); 394 428 } 395 429 396 430 static void arcnet_reply_tasklet(unsigned long data) ··· 486 452 lp->dev = dev; 487 453 spin_lock_init(&lp->lock); 488 454 timer_setup(&lp->timer, arcnet_timer, 0); 455 + INIT_WORK(&lp->reset_work, reset_device_work); 489 456 } 490 457 491 458 return dev; 492 459 } 493 460 EXPORT_SYMBOL(alloc_arcdev); 461 + 462 + void free_arcdev(struct net_device *dev) 463 + { 464 + struct arcnet_local *lp = netdev_priv(dev); 465 + 466 + /* Do not cancel this at ->ndo_close(), as the workqueue itself 467 + * indirectly calls the ifdown path through dev_close(). 468 + */ 469 + cancel_work_sync(&lp->reset_work); 470 + free_netdev(dev); 471 + } 472 + EXPORT_SYMBOL(free_arcdev); 494 473 495 474 /* Open/initialize the board. This is called sometime after booting when 496 475 * the 'ifconfig' program is run. ··· 634 587 635 588 /* shut down the card */ 636 589 lp->hw.close(dev); 590 + 591 + /* reset counters */ 592 + lp->reset_in_progress = 0; 593 + 637 594 module_put(lp->hw.owner); 638 595 return 0; 639 596 } ··· 871 820 872 821 spin_lock_irqsave(&lp->lock, flags); 873 822 823 + if (lp->reset_in_progress) 824 + goto out; 825 + 874 826 /* RESET flag was enabled - if device is not running, we must 875 827 * clear it right away (but nothing else). 876 828 */ ··· 906 852 if (status & RESETflag) { 907 853 arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)\n", 908 854 status); 909 - arcnet_close(dev); 910 - arcnet_open(dev); 855 + 856 + lp->reset_in_progress = 1; 857 + netif_stop_queue(dev); 858 + netif_carrier_off(dev); 859 + schedule_work(&lp->reset_work); 911 860 912 861 /* get out of the interrupt handler! */ 913 - break; 862 + goto out; 914 863 } 915 864 /* RX is inhibited - we must have received something. 916 865 * Prepare to receive into the next buffer. ··· 1109 1052 udelay(1); 1110 1053 lp->hw.intmask(dev, lp->intmask); 1111 1054 1055 + out: 1112 1056 spin_unlock_irqrestore(&lp->lock, flags); 1113 1057 return retval; 1114 1058 }
+2 -2
drivers/net/arcnet/com20020-isa.c
··· 169 169 dev->irq = 9; 170 170 171 171 if (com20020isa_probe(dev)) { 172 - free_netdev(dev); 172 + free_arcdev(dev); 173 173 return -EIO; 174 174 } 175 175 ··· 182 182 unregister_netdev(my_dev); 183 183 free_irq(my_dev->irq, my_dev); 184 184 release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE); 185 - free_netdev(my_dev); 185 + free_arcdev(my_dev); 186 186 } 187 187 188 188 #ifndef MODULE
+1 -1
drivers/net/arcnet/com20020-pci.c
··· 291 291 292 292 unregister_netdev(dev); 293 293 free_irq(dev->irq, dev); 294 - free_netdev(dev); 294 + free_arcdev(dev); 295 295 } 296 296 } 297 297
+1 -1
drivers/net/arcnet/com20020_cs.c
··· 177 177 dev = info->dev; 178 178 if (dev) { 179 179 dev_dbg(&link->dev, "kfree...\n"); 180 - free_netdev(dev); 180 + free_arcdev(dev); 181 181 } 182 182 dev_dbg(&link->dev, "kfree2...\n"); 183 183 kfree(info);
+2 -2
drivers/net/arcnet/com90io.c
··· 396 396 err = com90io_probe(dev); 397 397 398 398 if (err) { 399 - free_netdev(dev); 399 + free_arcdev(dev); 400 400 return err; 401 401 } 402 402 ··· 419 419 420 420 free_irq(dev->irq, dev); 421 421 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 422 - free_netdev(dev); 422 + free_arcdev(dev); 423 423 } 424 424 425 425 module_init(com90io_init)
+2 -2
drivers/net/arcnet/com90xx.c
··· 554 554 err_release_mem: 555 555 release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); 556 556 err_free_dev: 557 - free_netdev(dev); 557 + free_arcdev(dev); 558 558 return -EIO; 559 559 } 560 560 ··· 672 672 release_region(dev->base_addr, ARCNET_TOTAL_SIZE); 673 673 release_mem_region(dev->mem_start, 674 674 dev->mem_end - dev->mem_start + 1); 675 - free_netdev(dev); 675 + free_arcdev(dev); 676 676 } 677 677 } 678 678