ia64/xen-unstable
changeset 1387:839302343688
bitkeeper revision 1.891.5.1 (40a4ee0eTiPczG5OYaAX2-NUVdmi1Q)
More batching and pipelining in network backend.
More batching and pipelining in network backend.
author | kaf24@scramble.cl.cam.ac.uk |
---|---|
date | Fri May 14 16:04:30 2004 +0000 (2004-05-14) |
parents | a693ae3c0f60 |
children | bf3fc7825f74 |
files | xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c |
line diff
1.1 --- a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c Fri May 14 14:21:38 2004 +0000 1.2 +++ b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c Fri May 14 16:04:30 2004 +0000 1.3 @@ -52,12 +52,24 @@ static unsigned long mmap_vstart; 1.4 static u16 pending_id[MAX_PENDING_REQS]; 1.5 static netif_t *pending_netif[MAX_PENDING_REQS]; 1.6 static u16 pending_ring[MAX_PENDING_REQS]; 1.7 -static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED; 1.8 typedef unsigned int PEND_RING_IDX; 1.9 #define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) 1.10 static PEND_RING_IDX pending_prod, pending_cons; 1.11 #define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) 1.12 1.13 +/* Freed TX SKBs get batched on this ring before return to pending_ring. */ 1.14 +static u16 dealloc_ring[MAX_PENDING_REQS]; 1.15 +static spinlock_t dealloc_lock = SPIN_LOCK_UNLOCKED; 1.16 +static PEND_RING_IDX dealloc_prod, dealloc_cons; 1.17 + 1.18 +typedef struct { 1.19 + u16 idx; 1.20 + netif_tx_request_t req; 1.21 + netif_t *netif; 1.22 +} tx_info_t; 1.23 +static struct sk_buff_head tx_queue; 1.24 +static multicall_entry_t tx_mcl[MAX_PENDING_REQS]; 1.25 + 1.26 static struct list_head net_schedule_list; 1.27 static spinlock_t net_schedule_list_lock; 1.28 1.29 @@ -215,7 +227,7 @@ static void net_rx_action(unsigned long 1.30 mcl[0].op = __HYPERVISOR_update_va_mapping; 1.31 mcl[0].args[0] = vdata >> PAGE_SHIFT; 1.32 mcl[0].args[1] = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL; 1.33 - mcl[0].args[2] = UVMF_INVLPG; 1.34 + mcl[0].args[2] = 0; 1.35 mcl[1].op = __HYPERVISOR_mmu_update; 1.36 mcl[1].args[0] = (unsigned long)mmu; 1.37 mcl[1].args[1] = 4; 1.38 @@ -232,9 +244,10 @@ static void net_rx_action(unsigned long 1.39 break; 1.40 } 1.41 1.42 - if ( (mcl - rx_mcl) == 0 ) 1.43 + if ( mcl == rx_mcl ) 1.44 return; 1.45 1.46 + mcl[-2].args[2] = UVMF_FLUSH_TLB; 1.47 (void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); 1.48 1.49 mcl = rx_mcl; 1.50 @@ -369,7 +382,51 @@ static void net_tx_action(unsigned long 1.51 u16 pending_idx; 1.52 NETIF_RING_IDX i; 1.53 struct page *page; 1.54 + multicall_entry_t *mcl; 1.55 1.56 + if ( (i = dealloc_cons) == dealloc_prod ) 1.57 + goto skip_dealloc; 1.58 + 1.59 + mcl = tx_mcl; 1.60 + while ( i != dealloc_prod ) 1.61 + { 1.62 + pending_idx = dealloc_ring[MASK_PEND_IDX(i++)]; 1.63 + mcl[0].op = __HYPERVISOR_update_va_mapping; 1.64 + mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT; 1.65 + mcl[0].args[1] = 0; 1.66 + mcl[0].args[2] = 0; 1.67 + mcl++; 1.68 + } 1.69 + 1.70 + mcl[-1].args[2] = UVMF_FLUSH_TLB; 1.71 + (void)HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl); 1.72 + 1.73 + while ( dealloc_cons != dealloc_prod ) 1.74 + { 1.75 + pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)]; 1.76 + 1.77 + netif = pending_netif[pending_idx]; 1.78 + 1.79 + spin_lock(&netif->tx_lock); 1.80 + make_tx_response(netif, pending_id[pending_idx], NETIF_RSP_OKAY); 1.81 + spin_unlock(&netif->tx_lock); 1.82 + 1.83 + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; 1.84 + 1.85 + /* 1.86 + * Scheduling checks must happen after the above response is posted. 1.87 + * This avoids a possible race with a guest OS on another CPU. 1.88 + */ 1.89 + mb(); 1.90 + if ( (netif->tx_req_cons != netif->tx->req_prod) && 1.91 + ((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE) ) 1.92 + add_to_net_schedule_list_tail(netif); 1.93 + 1.94 + netif_put(netif); 1.95 + } 1.96 + 1.97 + skip_dealloc: 1.98 + mcl = tx_mcl; 1.99 while ( (NR_PENDING_REQS < MAX_PENDING_REQS) && 1.100 !list_empty(&net_schedule_list) ) 1.101 { 1.102 @@ -440,29 +497,61 @@ static void net_tx_action(unsigned long 1.103 1.104 pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; 1.105 1.106 - if ( HYPERVISOR_update_va_mapping_otherdomain( 1.107 - MMAP_VADDR(pending_idx) >> PAGE_SHIFT, 1.108 - (pte_t) { (txreq.addr & PAGE_MASK) | __PAGE_KERNEL }, 1.109 - 0, netif->domid) != 0 ) 1.110 - { 1.111 - DPRINTK("Bad page frame\n"); 1.112 - make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); 1.113 - netif_put(netif); 1.114 - continue; 1.115 - } 1.116 - phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] = 1.117 - txreq.addr >> PAGE_SHIFT; 1.118 - 1.119 if ( unlikely((skb = alloc_skb(PKT_PROT_LEN, GFP_ATOMIC)) == NULL) ) 1.120 { 1.121 DPRINTK("Can't allocate a skb in start_xmit.\n"); 1.122 make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); 1.123 netif_put(netif); 1.124 - HYPERVISOR_update_va_mapping(MMAP_VADDR(pending_idx) >> PAGE_SHIFT, 1.125 - (pte_t) { 0 }, UVMF_INVLPG); 1.126 break; 1.127 } 1.128 + 1.129 + mcl[0].op = __HYPERVISOR_update_va_mapping_otherdomain; 1.130 + mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT; 1.131 + mcl[0].args[1] = (txreq.addr & PAGE_MASK) | __PAGE_KERNEL; 1.132 + mcl[0].args[2] = 0; 1.133 + mcl[0].args[3] = (unsigned long)netif->domid; 1.134 + mcl[0].args[4] = (unsigned long)(netif->domid>>32); 1.135 + mcl++; 1.136 1.137 + ((tx_info_t *)&skb->cb[0])->idx = pending_idx; 1.138 + ((tx_info_t *)&skb->cb[0])->netif = netif; 1.139 + memcpy(&((tx_info_t *)&skb->cb[0])->req, &txreq, sizeof(txreq)); 1.140 + __skb_queue_tail(&tx_queue, skb); 1.141 + 1.142 + pending_cons++; 1.143 + 1.144 + /* Filled the batch queue? */ 1.145 + if ( (mcl - tx_mcl) == ARRAY_SIZE(tx_mcl) ) 1.146 + break; 1.147 + } 1.148 + 1.149 + if ( mcl == tx_mcl ) 1.150 + return; 1.151 + 1.152 + (void)HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl); 1.153 + 1.154 + mcl = tx_mcl; 1.155 + while ( (skb = __skb_dequeue(&tx_queue)) != NULL ) 1.156 + { 1.157 + pending_idx = ((tx_info_t *)&skb->cb[0])->idx; 1.158 + netif = ((tx_info_t *)&skb->cb[0])->netif; 1.159 + memcpy(&txreq, &((tx_info_t *)&skb->cb[0])->req, sizeof(txreq)); 1.160 + 1.161 + /* Check the remap error code. */ 1.162 + if ( unlikely(mcl[0].args[5] != 0) ) 1.163 + { 1.164 + DPRINTK("Bad page frame\n"); 1.165 + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); 1.166 + netif_put(netif); 1.167 + kfree_skb(skb); 1.168 + mcl++; 1.169 + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; 1.170 + continue; 1.171 + } 1.172 + 1.173 + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] = 1.174 + txreq.addr >> PAGE_SHIFT; 1.175 + 1.176 __skb_put(skb, PKT_PROT_LEN); 1.177 memcpy(skb->data, 1.178 (void *)(MMAP_VADDR(pending_idx)|(txreq.addr&~PAGE_MASK)), 1.179 @@ -491,42 +580,23 @@ static void net_tx_action(unsigned long 1.180 netif->stats.tx_bytes += txreq.size; 1.181 netif->stats.tx_packets++; 1.182 1.183 - pending_cons++; 1.184 - 1.185 netif_rx(skb); 1.186 netif->dev->last_rx = jiffies; 1.187 + 1.188 + mcl++; 1.189 } 1.190 } 1.191 1.192 static void netif_page_release(struct page *page) 1.193 { 1.194 unsigned long flags; 1.195 - netif_t *netif; 1.196 - u16 pending_idx; 1.197 - 1.198 - pending_idx = page - virt_to_page(mmap_vstart); 1.199 - 1.200 - netif = pending_netif[pending_idx]; 1.201 + u16 pending_idx = page - virt_to_page(mmap_vstart); 1.202 1.203 - HYPERVISOR_update_va_mapping(MMAP_VADDR(pending_idx) >> PAGE_SHIFT, 1.204 - (pte_t) { 0 }, UVMF_INVLPG); 1.205 - 1.206 - spin_lock(&netif->tx_lock); 1.207 - make_tx_response(netif, pending_id[pending_idx], NETIF_RSP_OKAY); 1.208 - spin_unlock(&netif->tx_lock); 1.209 + spin_lock_irqsave(&dealloc_lock, flags); 1.210 + dealloc_ring[MASK_PEND_IDX(dealloc_prod++)] = pending_idx; 1.211 + spin_unlock_irqrestore(&dealloc_lock, flags); 1.212 1.213 - /* 1.214 - * Scheduling checks must happen after the above response is posted. 1.215 - * This avoids a possible race with a guest OS on another CPU. 1.216 - */ 1.217 - mb(); 1.218 - netif_schedule_work(netif); 1.219 - 1.220 - netif_put(netif); 1.221 - 1.222 - spin_lock_irqsave(&pend_prod_lock, flags); 1.223 - pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; 1.224 - spin_unlock_irqrestore(&pend_prod_lock, flags); 1.225 + tasklet_schedule(&net_tx_tasklet); 1.226 } 1.227 1.228 #if 0 1.229 @@ -627,6 +697,7 @@ static int __init init_module(void) 1.230 return 0; 1.231 1.232 skb_queue_head_init(&rx_queue); 1.233 + skb_queue_head_init(&tx_queue); 1.234 1.235 netif_interface_init(); 1.236