From d75f326e15374b0bb6a9a71f2d3c50cff24d3b37 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Wed, 21 Mar 2012 19:12:08 +0000 Subject: dahdi_dynamic_eth: Move tx packet flushing to process context. The masterspan can be, and often is, called with interrupts disabled but dev_queue_xmit() needs to be called with interrupts enabled. This potentially fixes a deadlock. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10562 git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/branches/2.6@10570 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/dahdi_dynamic_eth.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/dahdi/dahdi_dynamic_eth.c b/drivers/dahdi/dahdi_dynamic_eth.c index 46699f5..0fc660f 100644 --- a/drivers/dahdi/dahdi_dynamic_eth.c +++ b/drivers/dahdi/dahdi_dynamic_eth.c @@ -191,15 +191,44 @@ static void ztdeth_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen) spin_unlock_irqrestore(&zlock, flags); } - -static int ztdeth_flush(void) +/** + * dahdi_dynamic_flush_work_fn - Flush all pending transactions. + * + * This function is run in a work queue since we can't guarantee interrupts + * will be enabled when we're called, and dev_queue_xmit() requires that + * interrupts be enabled. + * + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void dahdi_dynamic_flush_work_fn(void *data) +#else +static void dahdi_dynamic_flush_work_fn(struct work_struct *work) +#endif { struct sk_buff *skb; - /* Handle all transmissions now */ while ((skb = skb_dequeue(&skbs))) { dev_queue_xmit(skb); } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static DECLARE_WORK(dahdi_dynamic_eth_flush_work, + dahdi_dynamic_flush_work_fn, NULL); +#else +static DECLARE_WORK(dahdi_dynamic_eth_flush_work, + dahdi_dynamic_flush_work_fn); +#endif + +/** + * ztdeth_flush - Flush all pending transactions. + * + * This function is called in interrupt context while processing the master + * span. + */ +static int ztdeth_flush(void) +{ + schedule_work(&dahdi_dynamic_eth_flush_work); return 0; } @@ -422,6 +451,7 @@ static int __init ztdeth_init(void) static void __exit ztdeth_exit(void) { + cancel_work_sync(&dahdi_dynamic_eth_flush_work); dev_remove_pack(&ztdeth_ptype); unregister_netdevice_notifier(&ztdeth_nblock); dahdi_dynamic_unregister_driver(&ztd_eth); -- cgit v1.2.3