ia64/xen-unstable

changeset 667:6c29b3a63599

bitkeeper revision 1.382 (3f27e9e1QG4aZMHik9lRSaa177YIHg)

dev.c, skbuff.h, interrupt.h:
Fix network receive path to use a softirq to avoid deadlock situations.
author kaf24@scramble.cl.cam.ac.uk
date Wed Jul 30 15:53:05 2003 +0000 (2003-07-30)
parents b2b71842e45e
children e924f1dd98f3
files xen/include/xeno/interrupt.h xen/include/xeno/skbuff.h xen/net/dev.c
line diff
     1.1 --- a/xen/include/xeno/interrupt.h	Wed Jul 30 14:55:42 2003 +0000
     1.2 +++ b/xen/include/xeno/interrupt.h	Wed Jul 30 15:53:05 2003 +0000
     1.3 @@ -45,6 +45,7 @@ enum {
     1.4  enum
     1.5  {
     1.6  	HI_SOFTIRQ=0,
     1.7 +	NET_RX_SOFTIRQ,
     1.8  	AC_TIMER_SOFTIRQ,
     1.9  	TASKLET_SOFTIRQ
    1.10  };
     2.1 --- a/xen/include/xeno/skbuff.h	Wed Jul 30 14:55:42 2003 +0000
     2.2 +++ b/xen/include/xeno/skbuff.h	Wed Jul 30 15:53:05 2003 +0000
     2.3 @@ -236,6 +236,31 @@ static inline void __skb_queue_head(stru
     2.4  }
     2.5  
     2.6  /**
     2.7 + *      __skb_queue_tail - queue a buffer at the list tail
     2.8 + *      @list: list to use
     2.9 + *      @newsk: buffer to queue
    2.10 + *
    2.11 + *      Queue a buffer at the end of a list. This function takes no locks
    2.12 + *      and you must therefore hold required locks before calling it.
    2.13 + *
    2.14 + *      A buffer cannot be placed on two lists at the same time.
    2.15 + */ 
    2.16 +
    2.17 +static inline void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
    2.18 +{
    2.19 +        struct sk_buff *prev, *next;
    2.20 +
    2.21 +        newsk->list = list;
    2.22 +        list->qlen++;
    2.23 +        next = (struct sk_buff *)list;
    2.24 +        prev = next->prev;
    2.25 +        newsk->next = next;
    2.26 +        newsk->prev = prev;
    2.27 +        next->prev = newsk;
    2.28 +        prev->next = newsk;
    2.29 +}
    2.30 +
    2.31 +/**
    2.32   *	__skb_dequeue - remove from the head of the queue
    2.33   *	@list: list to dequeue from
    2.34   *
     3.1 --- a/xen/net/dev.c	Wed Jul 30 14:55:42 2003 +0000
     3.2 +++ b/xen/net/dev.c	Wed Jul 30 15:53:05 2003 +0000
     3.3 @@ -51,6 +51,8 @@
     3.4  #define TX_RING_ADD(_i,_j) (((_i)+(_j)) & (TX_RING_SIZE-1))
     3.5  #define RX_RING_ADD(_i,_j) (((_i)+(_j)) & (RX_RING_SIZE-1))
     3.6  
     3.7 +static struct sk_buff_head rx_skb_queue[NR_CPUS] __cacheline_aligned;
     3.8 +
     3.9  static void make_tx_response(net_vif_t *vif, 
    3.10                               unsigned short id, 
    3.11                               unsigned char  st);
    3.12 @@ -604,39 +606,68 @@ void deliver_packet(struct sk_buff *skb,
    3.13  
    3.14  int netif_rx(struct sk_buff *skb)
    3.15  {
    3.16 -    int offset, this_cpu = smp_processor_id();
    3.17 +    int this_cpu = smp_processor_id();
    3.18 +    struct sk_buff_head *q = &rx_skb_queue[this_cpu];
    3.19      unsigned long flags;
    3.20  
    3.21 +    /* This oughtn't to happen, really! */
    3.22 +    if ( unlikely(skb_queue_len(q) > 100) )
    3.23 +    {
    3.24 +        printk("Congestion -- packet dropped!!\n");
    3.25 +        return NET_RX_DROP;
    3.26 +    }
    3.27 +
    3.28      local_irq_save(flags);
    3.29 +    __skb_queue_tail(q, skb);
    3.30 +    local_irq_restore(flags);
    3.31  
    3.32 -    ASSERT(skb->skb_type == SKB_ZERO_COPY);
    3.33 +    __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
    3.34 +
    3.35 +    return NET_RX_SUCCESS;
    3.36 +}
    3.37  
    3.38 -    /*
    3.39 -     * Offset will include 16 bytes padding from dev_alloc_skb, 14 bytes for 
    3.40 -     * ethernet header, plus any other alignment padding added by the driver.
    3.41 -     */
    3.42 -    offset = (int)skb->data & ~PAGE_MASK; 
    3.43 -    skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << PAGE_SHIFT));
    3.44 -    skb->data = skb->nh.raw = skb->head + offset;
    3.45 -    skb->tail = skb->data + skb->len;
    3.46 -    skb_push(skb, ETH_HLEN);
    3.47 -    skb->mac.raw = skb->data;
    3.48 +static void net_rx_action(struct softirq_action *h)
    3.49 +{
    3.50 +    int offset, this_cpu = smp_processor_id();
    3.51 +    struct sk_buff_head *q = &rx_skb_queue[this_cpu];
    3.52 +    struct sk_buff *skb;
    3.53 +
    3.54 +    local_irq_disable();
    3.55 +    
    3.56 +    while ( (skb = __skb_dequeue(q)) != NULL )
    3.57 +    {
    3.58 +        ASSERT(skb->skb_type == SKB_ZERO_COPY);
    3.59  
    3.60 -    netdev_rx_stat[this_cpu].total++;
    3.61 -
    3.62 -    if ( skb->dst_vif == NULL )
    3.63 -        skb->dst_vif = net_get_target_vif(skb->data, skb->len, skb->src_vif);
    3.64 +        /*
    3.65 +         * Offset will include 16 bytes padding from dev_alloc_skb, 14 bytes
    3.66 +         * for ethernet header, plus any other alignment padding added by the
    3.67 +         * driver.
    3.68 +         */
    3.69 +        offset = (int)skb->data & ~PAGE_MASK; 
    3.70 +        skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << 
    3.71 +                                          PAGE_SHIFT));
    3.72 +        skb->data = skb->nh.raw = skb->head + offset;
    3.73 +        skb->tail = skb->data + skb->len;
    3.74 +        skb_push(skb, ETH_HLEN);
    3.75 +        skb->mac.raw = skb->data;
    3.76          
    3.77 -    if ( !VIF_LOCAL(skb->dst_vif) )
    3.78 -        skb->dst_vif = find_vif_by_id(0);
    3.79 +        netdev_rx_stat[this_cpu].total++;
    3.80 +        
    3.81 +        if ( skb->dst_vif == NULL )
    3.82 +            skb->dst_vif = net_get_target_vif(
    3.83 +                skb->data, skb->len, skb->src_vif);
    3.84 +        
    3.85 +        if ( !VIF_LOCAL(skb->dst_vif) )
    3.86 +            skb->dst_vif = find_vif_by_id(0);
    3.87 +        
    3.88 +        deliver_packet(skb, skb->dst_vif);
    3.89 +        put_vif(skb->dst_vif);
    3.90 +        
    3.91 +        unmap_domain_mem(skb->head);
    3.92 +        kfree_skb(skb);
    3.93 +    }
    3.94  
    3.95 -    deliver_packet(skb, skb->dst_vif);
    3.96 -    put_vif(skb->dst_vif);
    3.97 -
    3.98 -    unmap_domain_mem(skb->head);
    3.99 -    kfree_skb(skb);
   3.100 -    local_irq_restore(flags);
   3.101 -    return NET_RX_SUCCESS;
   3.102 +    local_irq_enable();
   3.103  }
   3.104  
   3.105  
   3.106 @@ -1770,7 +1801,7 @@ long do_net_update(void)
   3.107      net_vif_t *vif;
   3.108      net_idx_t *shared_idxs;
   3.109      unsigned int i, j, idx;
   3.110 -    struct sk_buff *skb, *interdom_skb = NULL;
   3.111 +    struct sk_buff *skb;
   3.112      tx_req_entry_t tx;
   3.113      rx_req_entry_t rx;
   3.114      unsigned long pte_pfn, buf_pfn;
   3.115 @@ -1874,11 +1905,7 @@ long do_net_update(void)
   3.116                  skb->len = tx.size - ETH_HLEN;
   3.117                  unmap_domain_mem(skb->head);
   3.118  
   3.119 -                /*
   3.120 -                 * We must defer netif_rx until we have released the current
   3.121 -                 * domain's page_lock, or we may deadlock on SMP.
   3.122 -                 */
   3.123 -                interdom_skb = skb;
   3.124 +                netif_rx(skb);
   3.125  
   3.126                  make_tx_response(vif, tx.id, RING_STATUS_OK);
   3.127              }
   3.128 @@ -1907,11 +1934,6 @@ long do_net_update(void)
   3.129          tx_unmap_and_continue:
   3.130              unmap_domain_mem(g_data);
   3.131              spin_unlock_irq(&current->page_lock);
   3.132 -            if ( interdom_skb != NULL )
   3.133 -            {
   3.134 -                (void)netif_rx(interdom_skb);
   3.135 -                interdom_skb = NULL;
   3.136 -            }
   3.137          }
   3.138  
   3.139          vif->tx_req_cons = i;
   3.140 @@ -2069,7 +2091,7 @@ static void make_rx_response(net_vif_t  
   3.141  
   3.142  int setup_network_devices(void)
   3.143  {
   3.144 -    int ret;
   3.145 +    int i, ret;
   3.146      extern char opt_ifname[];
   3.147      struct net_device *dev = dev_get_by_name(opt_ifname);
   3.148  
   3.149 @@ -2088,6 +2110,10 @@ int setup_network_devices(void)
   3.150      printk("Device %s opened and ready for use.\n", opt_ifname);
   3.151      the_dev = dev;
   3.152  
   3.153 +    for ( i = 0; i < smp_num_cpus; i++ )
   3.154 +        skb_queue_head_init(&rx_skb_queue[i]);
   3.155 +
   3.156 +    open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
   3.157      tasklet_enable(&net_tx_tasklet);
   3.158  
   3.159      return 1;