diff -r 76eb6cc5bfd1 -r 33722a4d7abd drivers/xen/netback/netback.c --- a/drivers/xen/netback/netback.c Mon Sep 22 11:40:53 2008 +0100 +++ b/drivers/xen/netback/netback.c Mon Sep 22 11:40:55 2008 +0100 @@ -37,6 +37,7 @@ #include "common.h" #include #include +#include /*define NETBE_DEBUG_INTERRUPT*/ @@ -65,11 +66,9 @@ static netif_rx_response_t *make_rx_resp u16 size, u16 flags); -static void net_tx_action(unsigned long unused); -static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0); - -static void net_rx_action(unsigned long unused); -static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0); +static void net_rx_action(void); +static void net_tx_action(void); +static DECLARE_WAIT_QUEUE_HEAD(netbk_action_wq); void netback_dump_free_callpath(struct page *page); @@ -190,7 +189,7 @@ static inline void maybe_schedule_tx_act smp_mb(); if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && !list_empty(&net_schedule_list)) - tasklet_schedule(&net_tx_tasklet); + wake_up(&netbk_action_wq); } static struct sk_buff *netbk_copy_skb(struct sk_buff *skb) @@ -347,7 +346,7 @@ int netif_be_start_xmit(struct sk_buff * } skb_queue_tail(&rx_queue, skb); - tasklet_schedule(&net_rx_tasklet); + wake_up(&netbk_action_wq); return 0; @@ -645,7 +644,12 @@ struct skb_cb_overlay { int meta_slots_used; }; -static void net_rx_action(unsigned long unused) +static inline int net_rx_action_work_to_do(void) +{ + return !skb_queue_empty(&rx_queue); +} + +static void net_rx_action(void) { netif_t *netif = NULL; s8 status; @@ -854,9 +858,11 @@ static void net_rx_action(unsigned long notify_remote_via_irq(irq); } +#if 0 /* More work to do? */ if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer)) - tasklet_schedule(&net_rx_tasklet); + wake_up(&netbk_action_wq); +#endif #if 0 else xen_network_done_notify(); @@ -865,12 +871,12 @@ static void net_rx_action(unsigned long static void net_alarm(unsigned long unused) { - tasklet_schedule(&net_rx_tasklet); + wake_up(&netbk_action_wq); } static void netbk_tx_pending_timeout(unsigned long unused) { - tasklet_schedule(&net_tx_tasklet); + wake_up(&netbk_action_wq); } struct net_device_stats *netif_be_get_stats(struct net_device *dev) @@ -1295,8 +1301,20 @@ static int netbk_set_skb_gso(struct sk_b return 0; } +static inline int net_tx_action_work_to_do(void) +{ + if (dealloc_cons != dealloc_prod) + return 1; + + if (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) && + !list_empty(&net_schedule_list)) + return 1; + + return 0; +} + /* Called after netfront has transmitted */ -static void net_tx_action(unsigned long unused) +static void net_tx_action(void) { struct list_head *ent; struct sk_buff *skb; @@ -1528,7 +1546,7 @@ static void net_tx_action(unsigned long continue; } - netif_rx(skb); + netif_rx_ni(skb); netif->dev->last_rx = jiffies; } @@ -1554,7 +1572,7 @@ static void netif_idx_release(u16 pendin dealloc_prod++; spin_unlock_irqrestore(&_lock, flags); - tasklet_schedule(&net_tx_tasklet); + wake_up(&netbk_action_wq); } static void netif_page_release(struct page *page) @@ -1627,6 +1645,24 @@ static netif_rx_response_t *make_rx_resp return resp; } + +static int netbk_action_thread(void *unused) +{ + while (1) { + wait_event_interruptible(netbk_action_wq, + net_rx_action_work_to_do() || net_tx_action_work_to_do()); + cond_resched(); + + if (net_rx_action_work_to_do()) + net_rx_action(); + + if (net_tx_action_work_to_do()) + net_tx_action(); + } + + return 0; +} + #ifdef NETBE_DEBUG_INTERRUPT static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs) @@ -1666,6 +1702,7 @@ static int __init netback_init(void) { int i; struct page *page; + struct task_struct *task; if (!is_running_on_xen()) return -ENODEV; @@ -1717,6 +1754,10 @@ static int __init netback_init(void) netif_accel_init(); netif_xenbus_init(); + + task = kthread_run(netbk_action_thread, NULL, "netback"); + if (IS_ERR(task)) + return PTR_ERR(task); #ifdef NETBE_DEBUG_INTERRUPT (void)bind_virq_to_irqhandler(VIRQ_DEBUG,