diff options
author | ach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk> | 2003-03-05 20:14:40 +0000 |
---|---|---|
committer | ach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk> | 2003-03-05 20:14:40 +0000 |
commit | f3c8dfc6270a0d4ac5f81d64b59a42623e45f82e (patch) | |
tree | 1f240422ead5b60bafe8126e850d92338ba6e40e /xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers | |
parent | a474d07ad6848eb61c591d57ff64400d66cd9007 (diff) | |
parent | dfca2c82d597482bab554fd1256cdb13154efba7 (diff) | |
download | xen-f3c8dfc6270a0d4ac5f81d64b59a42623e45f82e.tar.gz xen-f3c8dfc6270a0d4ac5f81d64b59a42623e45f82e.tar.bz2 xen-f3c8dfc6270a0d4ac5f81d64b59a42623e45f82e.zip |
bitkeeper revision 1.107 (3e665ab0XNZynD-498WHLN1g1IPRrw)
Merge labyrinth.cl.cam.ac.uk:/usr/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/anfs/scratch/boulderdash/ach61/xeno/xeno.bk
Diffstat (limited to 'xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers')
5 files changed, 352 insertions, 17 deletions
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/Makefile b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/Makefile new file mode 100644 index 0000000000..f780a515e0 --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/Makefile @@ -0,0 +1,3 @@ +O_TARGET := balloon_driver.o +obj-y := balloon.o +include $(TOPDIR)/Rules.make diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/balloon.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/balloon.c new file mode 100644 index 0000000000..abe5884800 --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/balloon.c @@ -0,0 +1,275 @@ +/****************************************************************************** + * balloon.c + * + * Xeno balloon driver - enables returning/claiming memory to/from xen + * + * Copyright (c) 2003, B Dragovic + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/proc_fs.h> + +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/smp_lock.h> +#include <linux/pagemap.h> + +#include <asm/hypervisor.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> +#include <asm/tlb.h> + +#include "dom_mem_ops.h" + +/* USER DEFINES -- THESE SHOULD BE COPIED TO USER-SPACE TOOLS */ +#define USER_INFLATE_BALLOON 1 /* return mem to hypervisor */ +#define USER_DEFLATE_BALLOON 2 /* claim mem from hypervisor */ +typedef struct user_balloon_op { + unsigned int op; + unsigned long size; +} user_balloon_op_t; +/* END OF USER DEFINE */ + +/* Dead entry written into ballon-owned entries in the PMT. */ +#define DEAD 0xdeadbeef + +#define BALLOON_ENTRY "balloon" +extern struct proc_dir_entry *xeno_base; + +static struct proc_dir_entry *balloon_pde; +unsigned long credit; + +static inline unsigned long get_ppte(unsigned long addr) +{ + unsigned long ppte; + pgd_t *pgd; pmd_t *pmd; pte_t *ptep; + pgd = pgd_offset_k(addr); + + if ( pgd_none(*pgd) || pgd_bad(*pgd) ) BUG(); + + pmd = pmd_offset(pgd, addr); + if ( pmd_none(*pmd) || pmd_bad(*pmd) ) BUG(); + + ptep = pte_offset(pmd, addr); + ppte = (unsigned long)__pa(ptep); + + return ppte; +} + +/* main function for relinquishing bit of memory */ +static unsigned long inflate_balloon(unsigned long num_pages) +{ + dom_mem_op_t dom_mem_op; + unsigned long *parray; + unsigned long *currp; + unsigned long ret = 0; + unsigned long vaddr; + unsigned long i, j; + + parray = (unsigned long *)kmalloc(num_pages * + sizeof(unsigned long), GFP_KERNEL); + currp = parray; + + for ( i = 0; i < num_pages; i++ ) + { + /* try to obtain a free page, has to be done with GFP_ATOMIC + * as we do not want to sleep indefinately. + */ + vaddr = __get_free_page(GFP_ATOMIC); + + /* if allocation fails, free all reserved pages */ + if(!vaddr){ + printk("Unable to inflate balloon by %ld, only %ld pages free.", + num_pages, i); + currp = parray; + for(j = 0; j < i; j++){ + free_page(*currp++); + } + goto cleanup; + } + + *currp++ = vaddr; + } + + + currp = parray; + for ( i = 0; i < num_pages; i++ ) + { + queue_l1_entry_update(get_ppte(*currp) | PGREQ_NORMAL, 0); + phys_to_machine_mapping[__pa(*currp) >> PAGE_SHIFT] = DEAD; + currp++; + } + + XENO_flush_page_update_queue(); + + dom_mem_op.op = BALLOON_INFLATE_OP; + dom_mem_op.u.balloon_inflate.size = num_pages; + dom_mem_op.u.balloon_inflate.pages = parray; + if ( (ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != num_pages ) + { + printk("Unable to deflate balloon, error %lx\n", ret); + goto cleanup; + } + + credit += num_pages; + ret = num_pages; + + cleanup: + kfree(parray); + + return ret; +} + +/* install new mem pages obtained by deflate_balloon. function walks + * phys->machine mapping table looking for DEAD entries and populates + * them. + */ +static unsigned long process_new_pages(unsigned long * parray, + unsigned long num) +{ + /* currently, this function is rather simplistic as + * it is assumed that domain reclaims only number of + * pages previously released. this is to change soon + * and the code to extend page tables etc. will be + * incorporated here. + */ + + unsigned long tot_pages = start_info.nr_pages; + unsigned long * curr = parray; + unsigned long num_installed; + unsigned long i; + + num_installed = 0; + for ( i = 0; i < tot_pages; i++ ) + { + if ( phys_to_machine_mapping[i] == DEAD ) + { + phys_to_machine_mapping[i] = *curr; + queue_l1_entry_update((i << PAGE_SHIFT) | PGREQ_MPT_UPDATE, i); + queue_l1_entry_update( + get_ppte((unsigned long)__va(i << PAGE_SHIFT)) | PGREQ_NORMAL, + ((*curr) << PAGE_SHIFT) | L1_PROT); + + *curr = (unsigned long)__va(i << PAGE_SHIFT); + curr++; + num_installed++; + } + } + + /* now, this is tricky (and will also change for machine addrs that + * are mapped to not previously released addresses). we free pages + * that were allocated by get_free_page (the mappings are different + * now, of course). + */ + curr = parray; + for ( i = 0; i < num_installed; i++ ) + { + free_page(*curr); + curr++; + } + + return num_installed; +} + +static unsigned long deflate_balloon(unsigned long num_pages) +{ + dom_mem_op_t dom_mem_op; + unsigned long ret; + unsigned long * parray; + + if ( num_pages > credit ) + { + printk("Can not allocate more pages than previously released.\n"); + return -EAGAIN; + } + + parray = (unsigned long *)kmalloc(num_pages * sizeof(unsigned long), + GFP_KERNEL); + + dom_mem_op.op = BALLOON_DEFLATE_OP; + dom_mem_op.u.balloon_deflate.size = num_pages; + dom_mem_op.u.balloon_deflate.pages = parray; + if((ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != num_pages){ + printk("Unable to deflate balloon, error %lx\n", ret); + goto cleanup; + } + + if((ret = process_new_pages(parray, num_pages)) < num_pages){ + printk("Unable to deflate balloon by specified %lx pages, only %lx.\n", + num_pages, ret); + goto cleanup; + } + + ret = num_pages; + + cleanup: + kfree(parray); + + return ret; +} + +static int balloon_write(struct file *file, const char *buffer, + u_long count, void *data) +{ + user_balloon_op_t bop; + + /* Only admin can play with the balloon :) */ + if ( !capable(CAP_SYS_ADMIN) ) + return -EPERM; + + if ( copy_from_user(&bop, buffer, sizeof(bop)) ) + return -EFAULT; + + switch ( bop.op ) + { + case USER_INFLATE_BALLOON: + if ( inflate_balloon(bop.size) < bop.size ) + return -EAGAIN; + break; + + case USER_DEFLATE_BALLOON: + deflate_balloon(bop.size); + break; + + default: + printk("Unknown command to balloon driver."); + return -EFAULT; + } + + return sizeof(bop); +} + +/* + * main balloon driver initialization function. + */ +static int __init init_module(void) +{ + printk(KERN_ALERT "Starting Xeno Balloon driver\n"); + + credit = 0; + + balloon_pde = create_proc_entry(BALLOON_ENTRY, 0600, xeno_base); + if ( balloon_pde == NULL ) + { + printk(KERN_ALERT "Unable to create balloon driver proc entry!"); + return -1; + } + + balloon_pde->write_proc = balloon_write; + + return 0; +} + +static void __exit cleanup_module(void) +{ +} + +module_init(init_module); +module_exit(cleanup_module); + + diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/dom_mem_ops.h b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/dom_mem_ops.h new file mode 100644 index 0000000000..c473f193e7 --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/balloon/dom_mem_ops.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * dom_mem_ops.h + * + * Header file supporting domain related memory operations. N.B. keep in sync + * with xen version. + * + * Copyright (c) 2003, B Dragovic + */ + +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED) +#define BALLOON_DEFLATE_OP 0 +#define BALLOON_INFLATE_OP 1 + +typedef struct balloon_deflate_op { + unsigned long size; + unsigned long * pages; +} balloon_def_op_t; + +typedef struct balloon_inflate_op { + unsigned long size; + unsigned long * pages; +} balloon_inf_op_t; + +typedef struct dom_mem_ops +{ + unsigned int op; + union + { + balloon_def_op_t balloon_deflate; + balloon_inf_op_t balloon_inflate; + }u; +} dom_mem_op_t; diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c index f8af85358b..c36ab02e96 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c @@ -53,7 +53,7 @@ typedef struct proc_mem_data { #define MAP_DISCONT 1 -static struct proc_dir_entry *xeno_base; +struct proc_dir_entry *xeno_base; static struct proc_dir_entry *dom0_cmd_intf; static struct proc_dir_entry *proc_ft; diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c index c9acaf43ee..7ef9ce4ef8 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c @@ -23,6 +23,7 @@ #include <asm/io.h> #include <net/sock.h> +#include <net/pkt_sched.h> #define NET_TX_IRQ _EVENT_NET_TX #define NET_RX_IRQ _EVENT_NET_RX @@ -65,7 +66,20 @@ struct net_private spinlock_t tx_lock; }; - + +static void dbg_network_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct net_private *np = dev->priv; + printk(KERN_ALERT "tx_full = %d, tx_entries = %d, tx_idx = %d," + " tx_cons = %d, tx_prod = %d, tx_event = %d, state=%d\n", + np->tx_full, atomic_read(&np->tx_entries), np->tx_idx, + np->net_ring->tx_cons, np->net_ring->tx_prod, + np->net_ring->tx_event, + test_bit(__LINK_STATE_XOFF, &dev->state)); +} + + static int network_open(struct net_device *dev) { struct net_private *np = dev->priv; @@ -123,6 +137,14 @@ static int network_open(struct net_device *dev) goto fail; } + error = request_irq(_EVENT_DEBUG, dbg_network_int, SA_SHIRQ, + "debug", dev); + if ( error ) + { + printk(KERN_WARNING "%s: Non-fatal error -- no debug interrupt\n", + dev->name); + } + printk("XenoLinux Virtual Network Driver installed as %s\n", dev->name); netif_start_queue(dev); @@ -147,17 +169,28 @@ static void network_tx_buf_gc(struct net_device *dev) struct net_private *np = dev->priv; struct sk_buff *skb; unsigned long flags; + unsigned int cons; spin_lock_irqsave(&np->tx_lock, flags); - for ( i = np->tx_idx; i != np->net_ring->tx_cons; i = TX_RING_INC(i) ) - { - skb = np->tx_skb_ring[i]; - dev_kfree_skb_any(skb); - atomic_dec(&np->tx_entries); - } + do { + cons = np->net_ring->tx_cons; - np->tx_idx = i; + for ( i = np->tx_idx; i != cons; i = TX_RING_INC(i) ) + { + skb = np->tx_skb_ring[i]; + dev_kfree_skb_any(skb); + atomic_dec(&np->tx_entries); + } + + np->tx_idx = i; + + /* Set a new event, then check for race with update of tx_cons. */ + np->net_ring->tx_event = + TX_RING_ADD(cons, (atomic_read(&np->tx_entries)>>1) + 1); + smp_mb(); + } + while ( cons != np->net_ring->tx_cons ); if ( np->tx_full && (atomic_read(&np->tx_entries) < TX_MAX_ENTRIES) ) { @@ -262,17 +295,9 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) { np->tx_full = 1; netif_stop_queue(dev); - np->net_ring->tx_event = - TX_RING_ADD(np->tx_idx, atomic_read(&np->tx_entries) >> 1); - } - else - { - /* Avoid unnecessary tx interrupts. */ - np->net_ring->tx_event = TX_RING_INC(np->net_ring->tx_prod); } spin_unlock_irq(&np->tx_lock); - /* Must do this after setting tx_event: race with updates of tx_cons. */ network_tx_buf_gc(dev); HYPERVISOR_net_update(); |