diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-07-20 07:51:49 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-07-20 07:51:49 +0000 |
commit | acc53f09b2a8b8623ac41dab9cd5ac4ddd22c1f1 (patch) | |
tree | 7d62248f0d6b4d633d8cfa07bcca3630d4f90fb0 | |
parent | e17fa59f091dec17caa1b3a31625bd34aeef9ae4 (diff) | |
download | xen-acc53f09b2a8b8623ac41dab9cd5ac4ddd22c1f1.tar.gz xen-acc53f09b2a8b8623ac41dab9cd5ac4ddd22c1f1.tar.bz2 xen-acc53f09b2a8b8623ac41dab9cd5ac4ddd22c1f1.zip |
bitkeeper revision 1.1108.4.1 (40fccf15MMHXnf0_66am3vGFf6fVDA)
Merge net frontend drivers in 2.4 and 2.6.
Fix some bugs that would cause crashes in low-memory conditions.
There may well be some bugs still lurking, but better hidden than
before!
-rw-r--r-- | .rootkeys | 3 | ||||
-rw-r--r-- | linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/main.c | 5 | ||||
-rw-r--r-- | linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c | 867 | ||||
-rwxr-xr-x | linux-2.4.26-xen-sparse/mkbuildtree | 4 | ||||
-rw-r--r-- | linux-2.6.7-xen-sparse/drivers/xen/net/network.c | 32 |
5 files changed, 27 insertions, 884 deletions
@@ -72,7 +72,6 @@ 4097ba837h2tuiweIWp-voNVzCRI6g linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c 4087cf0d5dudKw_DecIJgOhLlBF_0Q linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/main.c 405853f2wg7JXZJNltspMwOZJklxgw linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/Makefile -405853f6nbeazrNyEWNHBuoSg2PiPA linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c 4097ba83Qy2eafeFUhGhm6_4iMIIDw linux-2.4.26-xen-sparse/arch/xen/drivers/netif/netif.h 3e5a4e65lWzkiPXsZdzPt2RNnJGG1g linux-2.4.26-xen-sparse/arch/xen/kernel/Makefile 4075806dE5mQwlVUf8-t3YXjiMMWDQ linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c @@ -199,7 +198,7 @@ 40f56239DoibTX6R-ZYd3QTXAB8_TA linux-2.6.7-xen-sparse/drivers/xen/evtchn/evtchn.c 40f56239lrg_Ob0BJ8WBFS1zeg2CYw linux-2.6.7-xen-sparse/drivers/xen/net/Kconfig 40f56239Wd4k_ycG_mFsSO1r5xKdtQ linux-2.6.7-xen-sparse/drivers/xen/net/Makefile -40f56239vUsbJCS9tGFfRVi1YZlGEg linux-2.6.7-xen-sparse/drivers/xen/net/network.c +405853f6nbeazrNyEWNHBuoSg2PiPA linux-2.6.7-xen-sparse/drivers/xen/net/network.c 40f56239YAjS52QG2FIAQpHDZAdGHg linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/desc.h 40f5623anSzpuEHgiNmQ56fIRfCoaQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/e820.h 40f5623akIoBsQ3KxSB2kufkbgONXQ linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/fixmap.h diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/main.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/main.c index 851cc30285..868f7d0a81 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/main.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/main.c @@ -495,7 +495,7 @@ static void net_tx_action(unsigned long unused) pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; - if ( unlikely((skb = dev_alloc_skb(PKT_PROT_LEN)) == NULL) ) + if ( unlikely((skb = alloc_skb(PKT_PROT_LEN+16, GFP_ATOMIC)) == NULL) ) { DPRINTK("Can't allocate a skb in start_xmit.\n"); make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); @@ -503,6 +503,9 @@ static void net_tx_action(unsigned long unused) break; } + /* Packets passed to netif_rx() must have some headroom. */ + skb_reserve(skb, 16); + mcl[0].op = __HYPERVISOR_update_va_mapping_otherdomain; mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT; mcl[0].args[1] = (txreq.addr & PAGE_MASK) | __PAGE_KERNEL; diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c deleted file mode 100644 index ff75096bd8..0000000000 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c +++ /dev/null @@ -1,867 +0,0 @@ -/****************************************************************************** - * arch/xen/drivers/netif/frontend/main.c - * - * Virtual network driver for conversing with remote driver backends. - * - * Copyright (c) 2002-2004, K A Fraser - */ - -#include <linux/config.h> -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> - -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <net/sock.h> -#include <net/pkt_sched.h> - -#include <asm/evtchn.h> -#include <asm/ctrl_if.h> - -#include <asm/page.h> - -#include "../netif.h" - -#define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */ - -static void network_tx_buf_gc(struct net_device *dev); -static void network_alloc_rx_buffers(struct net_device *dev); - -static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE]; -static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1]; -static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE]; - -static struct list_head dev_list; - -struct net_private -{ - struct list_head list; - struct net_device *dev; - - struct net_device_stats stats; - NETIF_RING_IDX rx_resp_cons, tx_resp_cons; - unsigned int tx_full; - - netif_tx_interface_t *tx; - netif_rx_interface_t *rx; - - spinlock_t tx_lock; - spinlock_t rx_lock; - - unsigned int handle; - unsigned int evtchn; - unsigned int irq; - - /* What is the status of our connection to the remote backend? */ -#define BEST_CLOSED 0 -#define BEST_DISCONNECTED 1 -#define BEST_CONNECTED 2 - unsigned int backend_state; - - /* Is this interface open or closed (down or up)? */ -#define UST_CLOSED 0 -#define UST_OPEN 1 - unsigned int user_state; - - /* - * {tx,rx}_skbs store outstanding skbuffs. The first entry in each - * array is an index into a chain of free entries. - */ - struct sk_buff *tx_skbs[NETIF_TX_RING_SIZE+1]; - struct sk_buff *rx_skbs[NETIF_RX_RING_SIZE+1]; -}; - -/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */ -#define ADD_ID_TO_FREELIST(_list, _id) \ - (_list)[(_id)] = (_list)[0]; \ - (_list)[0] = (void *)(unsigned long)(_id); -#define GET_ID_FROM_FREELIST(_list) \ - ({ unsigned long _id = (unsigned long)(_list)[0]; \ - (_list)[0] = (_list)[_id]; \ - (unsigned short)_id; }) - -static struct net_device *find_dev_by_handle(unsigned int handle) -{ - struct list_head *ent; - struct net_private *np; - list_for_each ( ent, &dev_list ) - { - np = list_entry(ent, struct net_private, list); - if ( np->handle == handle ) - return np->dev; - } - return NULL; -} - -/** Network interface info. */ -struct netif_ctrl { - /** Number of interfaces. */ - int interface_n; - /** Number of connected interfaces. */ - int connected_n; - /** Error code. */ - int err; -}; - -static struct netif_ctrl netctrl; - -static void netctrl_init(void) -{ - memset(&netctrl, 0, sizeof(netctrl)); - netctrl.interface_n = -1; -} - -/** Get or set a network interface error. - */ -static int netctrl_err(int err) -{ - if(err < 0 && !netctrl.err){ - netctrl.err = err; - printk(KERN_WARNING "%s> err=%d\n", __FUNCTION__, err); - } - return netctrl.err; -} - -/** Test if all network interfaces are connected. - * - * @return 1 if all connected, 0 if not, negative error code otherwise - */ -static int netctrl_connected(void) -{ - int ok = 0; - ok = (netctrl.err ? netctrl.err : - (netctrl.connected_n == netctrl.interface_n)); - return ok; -} - -/** Count the connected network interfaces. - * - * @return connected count - */ -static int netctrl_connected_count(void) -{ - - struct list_head *ent; - struct net_private *np; - unsigned int connected; - - connected = 0; - - list_for_each(ent, &dev_list) - { - np = list_entry(ent, struct net_private, list); - if ( np->backend_state == BEST_CONNECTED ) - connected++; - } - - netctrl.connected_n = connected; - return connected; -} - -static int network_open(struct net_device *dev) -{ - struct net_private *np = dev->priv; - - memset(&np->stats, 0, sizeof(np->stats)); - - np->user_state = UST_OPEN; - - network_alloc_rx_buffers(dev); - np->rx->event = np->rx_resp_cons + 1; - - netif_start_queue(dev); - - return 0; -} - - -static void network_tx_buf_gc(struct net_device *dev) -{ - NETIF_RING_IDX i, prod; - unsigned short id; - struct net_private *np = dev->priv; - struct sk_buff *skb; - - if ( np->backend_state != BEST_CONNECTED ) - return; - - do { - prod = np->tx->resp_prod; - - for ( i = np->tx_resp_cons; i != prod; i++ ) - { - id = np->tx->ring[MASK_NETIF_TX_IDX(i)].resp.id; - skb = np->tx_skbs[id]; - ADD_ID_TO_FREELIST(np->tx_skbs, id); - dev_kfree_skb_any(skb); - } - - np->tx_resp_cons = prod; - - /* - * Set a new event, then check for race with update of tx_cons. Note - * that it is essential to schedule a callback, no matter how few - * buffers are pending. Even if there is space in the transmit ring, - * higher layers may be blocked because too much data is outstanding: - * in such cases notification from Xen is likely to be the only kick - * that we'll get. - */ - np->tx->event = - prod + ((np->tx->req_prod - prod) >> 1) + 1; - mb(); - } - while ( prod != np->tx->resp_prod ); - - if ( np->tx_full && - ((np->tx->req_prod - prod) < NETIF_TX_RING_SIZE) ) - { - np->tx_full = 0; - if ( np->user_state == UST_OPEN ) - netif_wake_queue(dev); - } -} - - -static void network_alloc_rx_buffers(struct net_device *dev) -{ - unsigned short id; - struct net_private *np = dev->priv; - struct sk_buff *skb; - NETIF_RING_IDX i = np->rx->req_prod; - int nr_pfns = 0; - - /* Make sure the batch is large enough to be worthwhile (1/2 ring). */ - if ( unlikely((i - np->rx_resp_cons) > (NETIF_RX_RING_SIZE/2)) || - unlikely(np->backend_state != BEST_CONNECTED) ) - return; - - do { - skb = dev_alloc_skb(RX_BUF_SIZE); - if ( unlikely(skb == NULL) ) - break; - - skb->dev = dev; - - if ( unlikely(((unsigned long)skb->head & (PAGE_SIZE-1)) != 0) ) - panic("alloc_skb needs to provide us page-aligned buffers."); - - id = GET_ID_FROM_FREELIST(np->rx_skbs); - - np->rx_skbs[id] = skb; - - np->rx->ring[MASK_NETIF_RX_IDX(i)].req.id = id; - - rx_pfn_array[nr_pfns] = virt_to_machine(skb->head) >> PAGE_SHIFT; - - rx_mcl[nr_pfns].op = __HYPERVISOR_update_va_mapping; - rx_mcl[nr_pfns].args[0] = (unsigned long)skb->head >> PAGE_SHIFT; - rx_mcl[nr_pfns].args[1] = 0; - rx_mcl[nr_pfns].args[2] = 0; - - nr_pfns++; - } - while ( (++i - np->rx_resp_cons) != NETIF_RX_RING_SIZE ); - - /* - * We may have allocated buffers which have entries outstanding in the page - * update queue -- make sure we flush those first! - */ - flush_page_update_queue(); - - /* After all PTEs have been zapped we blow away stale TLB entries. */ - rx_mcl[nr_pfns-1].args[2] = UVMF_FLUSH_TLB; - - /* Give away a batch of pages. */ - rx_mcl[nr_pfns].op = __HYPERVISOR_dom_mem_op; - rx_mcl[nr_pfns].args[0] = MEMOP_decrease_reservation; - rx_mcl[nr_pfns].args[1] = (unsigned long)rx_pfn_array; - rx_mcl[nr_pfns].args[2] = (unsigned long)nr_pfns; - - /* Zap PTEs and give away pages in one big multicall. */ - (void)HYPERVISOR_multicall(rx_mcl, nr_pfns+1); - - /* Check return status of HYPERVISOR_dom_mem_op(). */ - if ( rx_mcl[nr_pfns].args[5] != nr_pfns ) - panic("Unable to reduce memory reservation\n"); - - np->rx->req_prod = i; -} - - -static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - unsigned short id; - struct net_private *np = (struct net_private *)dev->priv; - netif_tx_request_t *tx; - NETIF_RING_IDX i; - - if ( unlikely(np->tx_full) ) - { - printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name); - netif_stop_queue(dev); - return -ENOBUFS; - } - - if ( unlikely((((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >= - PAGE_SIZE) ) - { - struct sk_buff *new_skb = dev_alloc_skb(RX_BUF_SIZE); - if ( unlikely(new_skb == NULL) ) - return 1; - skb_put(new_skb, skb->len); - memcpy(new_skb->data, skb->data, skb->len); - dev_kfree_skb(skb); - skb = new_skb; - } - - spin_lock_irq(&np->tx_lock); - - if ( np->backend_state != BEST_CONNECTED ) - { - spin_unlock_irq(&np->tx_lock); - return 1; - } - - i = np->tx->req_prod; - - id = GET_ID_FROM_FREELIST(np->tx_skbs); - np->tx_skbs[id] = skb; - - tx = &np->tx->ring[MASK_NETIF_TX_IDX(i)].req; - - tx->id = id; - tx->addr = virt_to_machine(skb->data); - tx->size = skb->len; - - wmb(); - np->tx->req_prod = i + 1; - - network_tx_buf_gc(dev); - - if ( (i - np->tx_resp_cons) == (NETIF_TX_RING_SIZE - 1) ) - { - np->tx_full = 1; - netif_stop_queue(dev); - } - - spin_unlock_irq(&np->tx_lock); - - np->stats.tx_bytes += skb->len; - np->stats.tx_packets++; - - /* Only notify Xen if there are no outstanding responses. */ - mb(); - if ( np->tx->resp_prod == i ) - notify_via_evtchn(np->evtchn); - - return 0; -} - - -static void netif_int(int irq, void *dev_id, struct pt_regs *ptregs) -{ - struct net_device *dev = dev_id; - struct net_private *np = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&np->tx_lock, flags); - network_tx_buf_gc(dev); - spin_unlock_irqrestore(&np->tx_lock, flags); - - if ( (np->rx_resp_cons != np->rx->resp_prod) && - (np->user_state == UST_OPEN) ) - netif_rx_schedule(dev); -} - - -static int netif_poll(struct net_device *dev, int *pbudget) -{ - struct net_private *np = dev->priv; - struct sk_buff *skb; - netif_rx_response_t *rx; - NETIF_RING_IDX i; - mmu_update_t *mmu = rx_mmu; - multicall_entry_t *mcl = rx_mcl; - int work_done, budget, more_to_do = 1; - struct sk_buff_head rxq; - unsigned long flags; - - spin_lock(&np->rx_lock); - - if ( np->backend_state != BEST_CONNECTED ) - { - spin_unlock(&np->rx_lock); - return 0; - } - - skb_queue_head_init(&rxq); - - if ( (budget = *pbudget) > dev->quota ) - budget = dev->quota; - - for ( i = np->rx_resp_cons, work_done = 0; - (i != np->rx->resp_prod) && (work_done < budget); - i++, work_done++ ) - { - rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp; - - skb = np->rx_skbs[rx->id]; - ADD_ID_TO_FREELIST(np->rx_skbs, rx->id); - - if ( unlikely(rx->status <= 0) ) - { - /* Gate this error. We get a (valid) slew of them on suspend. */ - if ( np->user_state != UST_OPEN ) - printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status); - dev_kfree_skb(skb); - continue; - } - - skb->data = skb->tail = skb->head + (rx->addr & ~PAGE_MASK); - skb_put(skb, rx->status); - - np->stats.rx_packets++; - np->stats.rx_bytes += rx->status; - - /* Remap the page. */ - mmu->ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE; - mmu->val = __pa(skb->head) >> PAGE_SHIFT; - mmu++; - mcl->op = __HYPERVISOR_update_va_mapping; - mcl->args[0] = (unsigned long)skb->head >> PAGE_SHIFT; - mcl->args[1] = (rx->addr & PAGE_MASK) | __PAGE_KERNEL; - mcl->args[2] = 0; - mcl++; - - phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] = - rx->addr >> PAGE_SHIFT; - - __skb_queue_tail(&rxq, skb); - } - - /* Do all the remapping work, and M->P updates, in one big hypercall. */ - if ( likely((mcl - rx_mcl) != 0) ) - { - mcl->op = __HYPERVISOR_mmu_update; - mcl->args[0] = (unsigned long)rx_mmu; - mcl->args[1] = mmu - rx_mmu; - mcl->args[2] = 0; - mcl++; - (void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); - } - - while ( (skb = __skb_dequeue(&rxq)) != NULL ) - { - /* Set the shared-info area, which is hidden behind the real data. */ - atomic_set(&(skb_shinfo(skb)->dataref), 1); - skb_shinfo(skb)->nr_frags = 0; - skb_shinfo(skb)->frag_list = NULL; - - /* Ethernet-specific work. Delayed to here as it peeks the header. */ - skb->protocol = eth_type_trans(skb, dev); - - /* Pass it up. */ - netif_rx(skb); - dev->last_rx = jiffies; - } - - np->rx_resp_cons = i; - - network_alloc_rx_buffers(dev); - - *pbudget -= work_done; - dev->quota -= work_done; - - if ( work_done < budget ) - { - local_irq_save(flags); - - np->rx->event = i + 1; - - /* Deal with hypervisor racing our resetting of rx_event. */ - mb(); - if ( np->rx->resp_prod == i ) - { - __netif_rx_complete(dev); - more_to_do = 0; - } - - local_irq_restore(flags); - } - - spin_unlock(&np->rx_lock); - - return more_to_do; -} - - -static int network_close(struct net_device *dev) -{ - struct net_private *np = dev->priv; - np->user_state = UST_CLOSED; - netif_stop_queue(np->dev); - return 0; -} - - -static struct net_device_stats *network_get_stats(struct net_device *dev) -{ - struct net_private *np = (struct net_private *)dev->priv; - return &np->stats; -} - - -static void network_connect(struct net_device *dev, - netif_fe_interface_status_changed_t *status) -{ - struct net_private *np; - int i, requeue_idx; - netif_tx_request_t *tx; - - np = dev->priv; - spin_lock_irq(&np->rx_lock); - spin_lock(&np->tx_lock); - - /* Recovery procedure: */ - - /* Step 1: Reinitialise variables. */ - np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0; - np->rx->event = 1; - - /* Step 2: Rebuild the RX and TX ring contents. - * NB. We could just free the queued TX packets now but we hope - * that sending them out might do some good. We have to rebuild - * the RX ring because some of our pages are currently flipped out - * so we can't just free the RX skbs. - * NB2. Freelist index entries are always going to be less than - * __PAGE_OFFSET, whereas pointers to skbs will always be equal or - * greater than __PAGE_OFFSET: we use this property to distinguish - * them. - */ - - /* Rebuild the TX buffer freelist and the TX ring itself. - * NB. This reorders packets. We could keep more private state - * to avoid this but maybe it doesn't matter so much given the - * interface has been down. - */ - for ( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ ) - { - if ( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET ) - { - struct sk_buff *skb = np->tx_skbs[i]; - - tx = &np->tx->ring[requeue_idx++].req; - - tx->id = i; - tx->addr = virt_to_machine(skb->data); - tx->size = skb->len; - - np->stats.tx_bytes += skb->len; - np->stats.tx_packets++; - } - } - wmb(); - np->tx->req_prod = requeue_idx; - - /* Rebuild the RX buffer freelist and the RX ring itself. */ - for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ ) - if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET ) - np->rx->ring[requeue_idx++].req.id = i; - wmb(); - np->rx->req_prod = requeue_idx; - - /* Step 3: All public and private state should now be sane. Get - * ready to start sending and receiving packets and give the driver - * domain a kick because we've probably just requeued some - * packets. - */ - np->backend_state = BEST_CONNECTED; - notify_via_evtchn(status->evtchn); - network_tx_buf_gc(dev); - - if ( np->user_state == UST_OPEN ) - netif_start_queue(dev); - - spin_unlock(&np->tx_lock); - spin_unlock_irq(&np->rx_lock); -} - -static void netif_status_change(netif_fe_interface_status_changed_t *status) -{ - ctrl_msg_t cmsg; - netif_fe_interface_connect_t up; - struct net_device *dev; - struct net_private *np; - - if ( netctrl.interface_n <= 0 ) - { - printk(KERN_WARNING "Status change: no interfaces\n"); - return; - } - - dev = find_dev_by_handle(status->handle); - if(!dev){ - printk(KERN_WARNING "Status change: invalid netif handle %u\n", - status->handle); - return; - } - np = dev->priv; - - switch ( status->status ) - { - case NETIF_INTERFACE_STATUS_DESTROYED: - printk(KERN_WARNING "Unexpected netif-DESTROYED message in state %d\n", - np->backend_state); - break; - - case NETIF_INTERFACE_STATUS_DISCONNECTED: - if ( np->backend_state != BEST_CLOSED ) - { - printk(KERN_WARNING "Unexpected netif-DISCONNECTED message" - " in state %d\n", np->backend_state); - printk(KERN_INFO "Attempting to reconnect network interface\n"); - - /* Begin interface recovery. - * - * NB. Whilst we're recovering, we turn the carrier state off. We - * take measures to ensure that this device isn't used for - * anything. We also stop the queue for this device. Various - * different approaches (e.g. continuing to buffer packets) have - * been tested but don't appear to improve the overall impact on - * TCP connections. - * - * TODO: (MAW) Change the Xend<->Guest protocol so that a recovery - * is initiated by a special "RESET" message - disconnect could - * just mean we're not allowed to use this interface any more. - */ - - /* Stop old i/f to prevent errors whilst we rebuild the state. */ - spin_lock_irq(&np->tx_lock); - spin_lock(&np->rx_lock); - netif_stop_queue(dev); - np->backend_state = BEST_DISCONNECTED; - spin_unlock(&np->rx_lock); - spin_unlock_irq(&np->tx_lock); - - /* Free resources. */ - free_irq(np->irq, dev); - unbind_evtchn_from_irq(np->evtchn); - free_page((unsigned long)np->tx); - free_page((unsigned long)np->rx); - } - - /* Move from CLOSED to DISCONNECTED state. */ - np->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL); - np->rx = (netif_rx_interface_t *)__get_free_page(GFP_KERNEL); - memset(np->tx, 0, PAGE_SIZE); - memset(np->rx, 0, PAGE_SIZE); - np->backend_state = BEST_DISCONNECTED; - - /* Construct an interface-CONNECT message for the domain controller. */ - cmsg.type = CMSG_NETIF_FE; - cmsg.subtype = CMSG_NETIF_FE_INTERFACE_CONNECT; - cmsg.length = sizeof(netif_fe_interface_connect_t); - up.handle = status->handle; - up.tx_shmem_frame = virt_to_machine(np->tx) >> PAGE_SHIFT; - up.rx_shmem_frame = virt_to_machine(np->rx) >> PAGE_SHIFT; - memcpy(cmsg.msg, &up, sizeof(up)); - - /* Tell the controller to bring up the interface. */ - ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); - break; - - case NETIF_INTERFACE_STATUS_CONNECTED: - if ( np->backend_state == BEST_CLOSED ) - { - printk(KERN_WARNING "Unexpected netif-CONNECTED message" - " in state %d\n", np->backend_state); - break; - } - - memcpy(dev->dev_addr, status->mac, ETH_ALEN); - - network_connect(dev, status); - - np->evtchn = status->evtchn; - np->irq = bind_evtchn_to_irq(np->evtchn); - (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, - dev->name, dev); - - netctrl_connected_count(); - break; - - default: - printk(KERN_WARNING "Status change to unknown value %d\n", - status->status); - break; - } -} - -/** Create a network device. - * @param handle device handle - * @param val return parameter for created device - * @return 0 on success, error code otherwise - */ -static int create_netdev(int handle, struct net_device **val) -{ - int i, err = 0; - struct net_device *dev = NULL; - struct net_private *np = NULL; - - if ( (dev = alloc_etherdev(sizeof(struct net_private))) == NULL ) - { - printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__); - err = -ENOMEM; - goto exit; - } - - np = dev->priv; - np->backend_state = BEST_CLOSED; - np->user_state = UST_CLOSED; - np->handle = handle; - - spin_lock_init(&np->tx_lock); - spin_lock_init(&np->rx_lock); - - /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ - for ( i = 0; i <= NETIF_TX_RING_SIZE; i++ ) - np->tx_skbs[i] = (void *)(i+1); - for ( i = 0; i <= NETIF_RX_RING_SIZE; i++ ) - np->rx_skbs[i] = (void *)(i+1); - - dev->open = network_open; - dev->hard_start_xmit = network_start_xmit; - dev->stop = network_close; - dev->get_stats = network_get_stats; - dev->poll = netif_poll; - dev->weight = 64; - - if ( (err = register_netdev(dev)) != 0 ) - { - printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err); - goto exit; - } - np->dev = dev; - list_add(&np->list, &dev_list); - - exit: - if ( (err != 0) && (dev != NULL ) ) - kfree(dev); - else if ( val != NULL ) - *val = dev; - return err; -} - -/* - * Initialize the network control interface. Set the number of network devices - * and create them. - */ -static void netif_driver_status_change( - netif_fe_driver_status_changed_t *status) -{ - int err = 0; - int i; - - netctrl.interface_n = status->nr_interfaces; - netctrl.connected_n = 0; - - for ( i = 0; i < netctrl.interface_n; i++ ) - { - if ( (err = create_netdev(i, NULL)) != 0 ) - { - netctrl_err(err); - break; - } - } -} - -static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) -{ - int respond = 1; - - switch ( msg->subtype ) - { - case CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: - if ( msg->length != sizeof(netif_fe_interface_status_changed_t) ) - goto error; - netif_status_change((netif_fe_interface_status_changed_t *) - &msg->msg[0]); - break; - - case CMSG_NETIF_FE_DRIVER_STATUS_CHANGED: - if ( msg->length != sizeof(netif_fe_driver_status_changed_t) ) - goto error; - netif_driver_status_change((netif_fe_driver_status_changed_t *) - &msg->msg[0]); - /* Message is a response */ - respond = 0; - break; - - error: - default: - msg->length = 0; - break; - } - - if ( respond ) - ctrl_if_send_response(msg); -} - - -static int __init netif_init(void) -{ - ctrl_msg_t cmsg; - netif_fe_driver_status_changed_t st; - int err = 0, wait_i, wait_n = 20; - - if ( (start_info.flags & SIF_INITDOMAIN) || - (start_info.flags & SIF_NET_BE_DOMAIN) ) - return 0; - - printk("Initialising Xen virtual ethernet frontend driver"); - - INIT_LIST_HEAD(&dev_list); - - netctrl_init(); - - (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx, - CALLBACK_IN_BLOCKING_CONTEXT); - - /* Send a driver-UP notification to the domain controller. */ - cmsg.type = CMSG_NETIF_FE; - cmsg.subtype = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED; - cmsg.length = sizeof(netif_fe_driver_status_changed_t); - st.status = NETIF_DRIVER_STATUS_UP; - st.nr_interfaces = 0; - memcpy(cmsg.msg, &st, sizeof(st)); - ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); - - /* Wait for all interfaces to be connected. */ - for ( wait_i = 0; ; wait_i++) - { - if ( (err = (wait_i < wait_n) ? netctrl_connected() : -ENETDOWN) != 0 ) - { - err = (err > 0) ? 0 : err; - break; - } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } - - if ( err ) - ctrl_if_unregister_receiver(CMSG_NETIF_FE, netif_ctrlif_rx); - - return err; -} - -__initcall(netif_init); diff --git a/linux-2.4.26-xen-sparse/mkbuildtree b/linux-2.4.26-xen-sparse/mkbuildtree index 5dba6c03d5..7cdc0af60d 100755 --- a/linux-2.4.26-xen-sparse/mkbuildtree +++ b/linux-2.4.26-xen-sparse/mkbuildtree @@ -225,5 +225,5 @@ ln -sf ../../i386/mm/extable.c ln -sf ../../i386/mm/pageattr.c cd ../drivers/console ln -sf ../../../../${LINUX_26}/drivers/xen/console/console.c -#cd ../netif/frontend -#ln -sf ../../../../../${LINUX_26}/drivers/xen/net/network.c main.c +cd ../netif/frontend +ln -sf ../../../../../${LINUX_26}/drivers/xen/net/network.c main.c diff --git a/linux-2.6.7-xen-sparse/drivers/xen/net/network.c b/linux-2.6.7-xen-sparse/drivers/xen/net/network.c index d48192fd03..ea0fa45f03 100644 --- a/linux-2.6.7-xen-sparse/drivers/xen/net/network.c +++ b/linux-2.6.7-xen-sparse/drivers/xen/net/network.c @@ -1,6 +1,4 @@ /****************************************************************************** - * network.c - * * Virtual network driver for conversing with remote driver backends. * * Copyright (c) 2002-2004, K A Fraser @@ -8,13 +6,12 @@ #include <linux/config.h> #include <linux/module.h> - +#include <linux/version.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/errno.h> - #include <linux/netdevice.h> #include <linux/inetdevice.h> #include <linux/etherdevice.h> @@ -30,7 +27,13 @@ #include <asm/page.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #include <asm-xen/netif.h> +#else +#include "../netif.h" +#define irqreturn_t void +#define IRQ_HANDLED +#endif #define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */ @@ -368,7 +371,7 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) } -static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs) +static void netif_int(int irq, void *dev_id, struct pt_regs *ptregs) { struct net_device *dev = dev_id; struct net_private *np = dev->priv; @@ -381,8 +384,6 @@ static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs) if ( (np->rx_resp_cons != np->rx->resp_prod) && (np->user_state == UST_OPEN) ) netif_rx_schedule(dev); - - return IRQ_HANDLED; } @@ -417,18 +418,25 @@ static int netif_poll(struct net_device *dev, int *pbudget) { rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp; - skb = np->rx_skbs[rx->id]; - ADD_ID_TO_FREELIST(np->rx_skbs, rx->id); - + /* + * An error here is very odd. Usually indicates a backend bug, + * low-memory condition, or that we didn't have reservation headroom. + * Whatever - print an error and queue the id again straight away. + */ if ( unlikely(rx->status <= 0) ) { /* Gate this error. We get a (valid) slew of them on suspend. */ - if ( np->user_state != UST_OPEN ) + if ( np->user_state == UST_OPEN ) printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status); - dev_kfree_skb(skb); + np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)].req.id = rx->id; + wmb(); + np->rx->req_prod++; continue; } + skb = np->rx_skbs[rx->id]; + ADD_ID_TO_FREELIST(np->rx_skbs, rx->id); + skb->data = skb->tail = skb->head + (rx->addr & ~PAGE_MASK); skb_put(skb, rx->status); |