diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-05-06 11:56:13 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-05-06 11:56:13 +0000 |
commit | 3b5b2188aa19c0f284b5289cd97acfdd81fa131c (patch) | |
tree | 15077840b604d04f01fb2860334ac402a1516ef7 /xenolinux-2.4.26-sparse/arch | |
parent | 9687f61b49c7864fe60468036ec6da8620e36426 (diff) | |
download | xen-3b5b2188aa19c0f284b5289cd97acfdd81fa131c.tar.gz xen-3b5b2188aa19c0f284b5289cd97acfdd81fa131c.tar.bz2 xen-3b5b2188aa19c0f284b5289cd97acfdd81fa131c.zip |
bitkeeper revision 1.891.2.1 (409a27ddyHHSEFrv4iElGUakv9riiw)
First cut of new network backend. Net frontend is in progress.
Diffstat (limited to 'xenolinux-2.4.26-sparse/arch')
6 files changed, 557 insertions, 565 deletions
diff --git a/xenolinux-2.4.26-sparse/arch/xen/defconfig-physdev b/xenolinux-2.4.26-sparse/arch/xen/defconfig-physdev index 69aa6c0856..41b05aaaa7 100644 --- a/xenolinux-2.4.26-sparse/arch/xen/defconfig-physdev +++ b/xenolinux-2.4.26-sparse/arch/xen/defconfig-physdev @@ -89,19 +89,7 @@ CONFIG_BINFMT_ELF=y # # Parallel port support # -CONFIG_PARPORT=y -CONFIG_PARPORT_PC=y -# CONFIG_PARPORT_PC_FIFO is not set -# CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_PC_PCMCIA is not set -# CONFIG_PARPORT_AMIGA is not set -# CONFIG_PARPORT_MFC3 is not set -# CONFIG_PARPORT_ATARI is not set -# CONFIG_PARPORT_GSC is not set -# CONFIG_PARPORT_SUNBPP is not set -# CONFIG_PARPORT_IP22 is not set -# CONFIG_PARPORT_OTHER is not set -CONFIG_PARPORT_1284=y +# CONFIG_PARPORT is not set # # Plug and Play configuration @@ -112,7 +100,7 @@ CONFIG_PNP=y # # Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set @@ -131,14 +119,14 @@ CONFIG_BLK_DEV_INITRD=y # # Multi-device support (RAID and LVM) # -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_RAID0=y -CONFIG_MD_RAID1=y -CONFIG_MD_RAID5=y -CONFIG_MD_MULTIPATH=y -CONFIG_BLK_DEV_LVM=y +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -234,7 +222,7 @@ CONFIG_IP_NF_TARGET_ULOG=y # # CONFIG_DEV_APPLETALK is not set # CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set +CONFIG_BRIDGE=y # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set @@ -380,14 +368,7 @@ CONFIG_CHR_DEV_SG=y # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AACRAID=y # CONFIG_SCSI_AIC7XXX is not set -CONFIG_SCSI_AIC79XX=y -CONFIG_AIC79XX_CMDS_PER_DEVICE=32 -CONFIG_AIC79XX_RESET_DELAY_MS=15000 -# CONFIG_AIC79XX_BUILD_FIRMWARE is not set -# CONFIG_AIC79XX_ENABLE_RD_STRM is not set -CONFIG_AIC79XX_DEBUG_ENABLE=y -CONFIG_AIC79XX_DEBUG_MASK=0 -# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set @@ -397,9 +378,9 @@ CONFIG_SCSI_MEGARAID=y # CONFIG_SCSI_MEGARAID2 is not set CONFIG_SCSI_BUSLOGIC=y # CONFIG_SCSI_OMIT_FLASHPOINT is not set -CONFIG_SCSI_CPQFCTS=y +# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set -CONFIG_SCSI_DTC3280=y +# CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set # CONFIG_SCSI_EATA_PIO is not set @@ -409,15 +390,11 @@ CONFIG_SCSI_DTC3280=y # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_SYM53C8XX_2=y -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -510,9 +487,7 @@ CONFIG_PCNET32=y # CONFIG_APRICOT is not set # CONFIG_B44 is not set # CONFIG_CS89x0 is not set -CONFIG_TULIP=y -# CONFIG_TULIP_MWI is not set -# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set @@ -545,8 +520,7 @@ CONFIG_TULIP=y # # Ethernet (1000 Mbit) # -CONFIG_ACENIC=y -# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_ACENIC is not set # CONFIG_DL2K is not set CONFIG_E1000=y # CONFIG_E1000_NAPI is not set @@ -621,9 +595,6 @@ CONFIG_VT_CONSOLE=y # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set -# CONFIG_TIPAR is not set # # I2C support @@ -869,107 +840,7 @@ CONFIG_DUMMY_CONSOLE=y # # USB support # -CONFIG_USB=y -CONFIG_USB_DEBUG=y - -# -# Miscellaneous USB options -# -# CONFIG_USB_DEVICEFS is not set -# CONFIG_USB_BANDWIDTH is not set - -# -# USB Host Controller Drivers -# -# CONFIG_USB_EHCI_HCD is not set -CONFIG_USB_UHCI=y -# CONFIG_USB_UHCI_ALT is not set -CONFIG_USB_OHCI=y -# CONFIG_USB_SL811HS_ALT is not set -# CONFIG_USB_SL811HS is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_EMI26 is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_MIDI is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_SDDR55 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set - -# -# USB Human Interface Devices (HID) -# -# CONFIG_USB_HID is not set - -# -# Input core support is needed for USB HID input layer or HIDBP support -# -# CONFIG_USB_HIDINPUT is not set -# CONFIG_USB_HIDDEV is not set -# CONFIG_USB_KBD is not set -# CONFIG_USB_MOUSE is not set -# CONFIG_USB_AIPTEK is not set -# CONFIG_USB_WACOM is not set -# CONFIG_USB_KBTAB is not set -# CONFIG_USB_POWERMATE is not set - -# -# USB Imaging devices -# -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_RTL8150 is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set - -# -# USB port drivers -# -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_AUERSWALD is not set -# CONFIG_USB_TIGL is not set -# CONFIG_USB_BRLVGER is not set -# CONFIG_USB_LCD is not set +# CONFIG_USB is not set # # Support for USB gadgets diff --git a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/common.h b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/common.h index 1e95d9f480..88881cdf66 100644 --- a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/common.h +++ b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/common.h @@ -16,6 +16,7 @@ #include <asm/ctrl_if.h> #include <asm/io.h> #include "../netif.h" +#include "../../../../../net/bridge/br_private.h" #ifndef NDEBUG #define ASSERT(_p) \ @@ -28,7 +29,7 @@ #define DPRINTK(_f, _a...) ((void)0) #endif -typedef struct { +typedef struct netif_st { /* Unique identifier for this interface. */ domid_t domid; unsigned int handle; @@ -49,13 +50,7 @@ typedef struct { NETIF_RING_IDX tx_req_cons; NETIF_RING_IDX tx_resp_prod; /* private version of shared variable */ - /* Usage accounting */ - long long total_bytes_sent; - long long total_bytes_received; - long long total_packets_sent; - long long total_packets_received; - - /* Trasnmit shaping: allow 'credit_bytes' every 'credit_usec'. */ + /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */ unsigned long credit_bytes; unsigned long credit_usec; unsigned long remaining_credit; @@ -72,7 +67,8 @@ typedef struct { struct list_head list; /* scheduling list */ atomic_t refcnt; spinlock_t rx_lock, tx_lock; - unsigned char vmac[ETH_ALEN]; + struct net_device *dev; + struct net_device_stats stats; } netif_t; void netif_create(netif_be_create_t *create); @@ -93,6 +89,8 @@ void netif_ctrlif_init(void); void netif_deschedule(netif_t *netif); +int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev); +struct net_device_stats *netif_be_get_stats(struct net_device *dev); void netif_be_int(int irq, void *dev_id, struct pt_regs *regs); #endif /* __NETIF__BACKEND__COMMON_H__ */ diff --git a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/interface.c b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/interface.c index d12ca3057d..8623d8214b 100644 --- a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/interface.c +++ b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/interface.c @@ -12,8 +12,8 @@ #define NETIF_HASH(_d,_h) \ (((int)(_d)^(int)((_d)>>32)^(int)(_h))&(NETIF_HASHSZ-1)) -static kmem_cache_t *netif_cachep; -static netif_t *netif_hash[NETIF_HASHSZ]; +static netif_t *netif_hash[NETIF_HASHSZ]; +static struct net_device *bridge_dev; netif_t *netif_find_by_handle(domid_t domid, unsigned int handle) { @@ -35,7 +35,9 @@ void __netif_disconnect_complete(netif_t *netif) * must still be notified to the remote driver. */ unbind_evtchn_from_irq(netif->evtchn); - vfree(netif->net_ring_base); + vfree(netif->tx); /* Frees netif->rx as well. */ + (void)br_del_if((struct net_bridge *)bridge_dev->priv, netif->dev); + (void)dev_close(netif->dev); /* Construct the deferred response message. */ cmsg.type = CMSG_NETIF_BE; @@ -66,24 +68,32 @@ void __netif_disconnect_complete(netif_t *netif) void netif_create(netif_be_create_t *create) { - domid_t domid = create->domid; - unsigned int handle = create->netif_handle; - netif_t **pnetif, *netif; + domid_t domid = create->domid; + unsigned int handle = create->netif_handle; + struct net_device *dev; + netif_t **pnetif, *netif; - if ( (netif = kmem_cache_alloc(netif_cachep, GFP_ATOMIC)) == NULL ) + dev = alloc_netdev(sizeof(netif_t), "netif-be-%d", ether_setup); + if ( dev == NULL ) { DPRINTK("Could not create netif: out of memory\n"); create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; return; } + netif = dev->priv; memset(netif, 0, sizeof(*netif)); netif->domid = domid; netif->handle = handle; netif->status = DISCONNECTED; - spin_lock_init(&netif->vbd_lock); - spin_lock_init(&netif->net_ring_lock); + spin_lock_init(&netif->rx_lock); + spin_lock_init(&netif->tx_lock); atomic_set(&netif->refcnt, 0); + netif->dev = dev; + + netif->credit_bytes = netif->remaining_credit = ~0UL; + netif->credit_usec = 0UL; + /*init_ac_timer(&new_vif->credit_timeout);*/ pnetif = &netif_hash[NETIF_HASH(domid, handle)]; while ( *pnetif != NULL ) @@ -92,12 +102,24 @@ void netif_create(netif_be_create_t *create) { DPRINTK("Could not create netif: already exists\n"); create->status = NETIF_BE_STATUS_INTERFACE_EXISTS; - kmem_cache_free(netif_cachep, netif); + kfree(dev); return; } pnetif = &(*pnetif)->hash_next; } + dev->hard_start_xmit = netif_be_start_xmit; + dev->get_stats = netif_be_get_stats; + memcpy(dev->dev_addr, create->mac, ETH_ALEN); + + if ( register_netdev(dev) != 0 ) + { + DPRINTK("Could not register new net device\n"); + create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; + kfree(dev); + return; + } + netif->hash_next = *pnetif; *pnetif = netif; @@ -132,8 +154,8 @@ void netif_destroy(netif_be_destroy_t *destroy) destroy: *pnetif = netif->hash_next; - destroy_all_vbds(netif); - kmem_cache_free(netif_cachep, netif); + unregister_netdev(netif->dev); + kfree(netif->dev); destroy->status = NETIF_BE_STATUS_OKAY; } @@ -142,11 +164,13 @@ void netif_connect(netif_be_connect_t *connect) domid_t domid = connect->domid; unsigned int handle = connect->netif_handle; unsigned int evtchn = connect->evtchn; - unsigned long shmem_frame = connect->shmem_frame; + unsigned long tx_shmem_frame = connect->tx_shmem_frame; + unsigned long rx_shmem_frame = connect->rx_shmem_frame; struct vm_struct *vma; pgprot_t prot; int error; netif_t *netif; + struct net_device *eth0_dev; netif = netif_find_by_handle(domid, handle); if ( unlikely(netif == NULL) ) @@ -157,16 +181,27 @@ void netif_connect(netif_be_connect_t *connect) return; } - if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL ) + if ( netif->status != DISCONNECTED ) + { + connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED; + return; + } + + if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL ) { connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY; return; } prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED); - error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr), - shmem_frame<<PAGE_SHIFT, PAGE_SIZE, - prot, domid); + error = direct_remap_area_pages(&init_mm, + VMALLOC_VMADDR(vma->addr), + tx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE, + prot, domid); + error |= direct_remap_area_pages(&init_mm, + VMALLOC_VMADDR(vma->addr) + PAGE_SIZE, + rx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE, + prot, domid); if ( error != 0 ) { if ( error == -ENOMEM ) @@ -179,21 +214,27 @@ void netif_connect(netif_be_connect_t *connect) return; } - if ( netif->status != DISCONNECTED ) - { - connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED; - vfree(vma->addr); - return; - } - - netif->evtchn = evtchn; - netif->irq = bind_evtchn_to_irq(evtchn); - netif->shmem_frame = shmem_frame; - netif->net_ring_base = (netif_ring_t *)vma->addr; - netif->status = CONNECTED; + netif->evtchn = evtchn; + netif->irq = bind_evtchn_to_irq(evtchn); + netif->tx_shmem_frame = tx_shmem_frame; + netif->rx_shmem_frame = rx_shmem_frame; + netif->tx = + (netif_tx_interface_t *)vma->addr; + netif->rx = + (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE); + netif->status = CONNECTED; netif_get(netif); - request_irq(netif->irq, netif_be_int, 0, "netif-backend", netif); + (void)dev_open(netif->dev); + (void)br_add_if((struct net_bridge *)bridge_dev->priv, netif->dev); + /* At this point we try to ensure that eth0 is attached to the bridge. */ + if ( (eth0_dev = __dev_get_by_name("eth0")) != NULL ) + { + (void)dev_open(eth0_dev); + (void)br_add_if((struct net_bridge *)bridge_dev->priv, eth0_dev); + } + (void)request_irq(netif->irq, netif_be_int, 0, "netif-backend", netif); + netif_start_queue(netif->dev); connect->status = NETIF_BE_STATUS_OKAY; } @@ -218,6 +259,7 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) netif->status = DISCONNECTING; netif->disconnect_rspid = rsp_id; wmb(); /* Let other CPUs see the status change. */ + netif_stop_queue(netif->dev); free_irq(netif->irq, NULL); netif_deschedule(netif); netif_put(netif); @@ -226,105 +268,11 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) return 0; /* Caller should not send response message. */ } -net_vif_t *create_net_vif(domid_t dom) -{ - unsigned int idx; - net_vif_t *new_vif = NULL; - net_ring_t *new_ring = NULL; - struct task_struct *p = NULL; - unsigned long flags, vmac_hash; - unsigned char vmac_key[ETH_ALEN + 2 + MAX_DOMAIN_NAME]; - - if ( (p = find_domain_by_id(dom)) == NULL ) - return NULL; - - write_lock_irqsave(&tasklist_lock, flags); - - for ( idx = 0; idx < MAX_DOMAIN_VIFS; idx++ ) - if ( p->net_vif_list[idx] == NULL ) - break; - if ( idx == MAX_DOMAIN_VIFS ) - goto fail; - - if ( (new_vif = kmem_cache_alloc(net_vif_cache, GFP_KERNEL)) == NULL ) - goto fail; - - memset(new_vif, 0, sizeof(*new_vif)); - - if ( sizeof(net_ring_t) > PAGE_SIZE ) - BUG(); - new_ring = (net_ring_t *)get_free_page(GFP_KERNEL); - clear_page(new_ring); - SHARE_PFN_WITH_DOMAIN(virt_to_page(new_ring), p); - - /* - * Fill in the new vif struct. Note that, while the vif's refcnt is - * non-zero, we hold a reference to the task structure. - */ - atomic_set(&new_vif->refcnt, 1); - new_vif->shared_rings = new_ring; - new_vif->shared_idxs = &p->shared_info->net_idx[idx]; - new_vif->domain = p; - new_vif->idx = idx; - new_vif->list.next = NULL; - spin_lock_init(&new_vif->rx_lock); - spin_lock_init(&new_vif->tx_lock); - - new_vif->credit_bytes = new_vif->remaining_credit = ~0UL; - new_vif->credit_usec = 0UL; - init_ac_timer(&new_vif->credit_timeout); - - if ( (p->domain == 0) && (idx == 0) ) - { - /* - * DOM0/VIF0 gets the real physical MAC address, so that users can - * easily get a Xen-based machine up and running by using an existing - * DHCP entry. - */ - memcpy(new_vif->vmac, the_dev->dev_addr, ETH_ALEN); - } - else - { - /* - * Most VIFs get a random MAC address with a "special" vendor id. - * We try to get MAC addresses to be unique across multiple servers - * by including the physical MAC address in the hash. The hash also - * includes the vif index and the domain's name. - * - * NB. The vendor is currently an "obsolete" one that used to belong - * to DEC (AA-00-00). Using it is probably a bit rude :-) - * - * NB2. The first bit of the first random octet is set to zero for - * all dynamic MAC addresses. This may allow us to manually specify - * MAC addresses for some VIFs with no fear of clashes. - */ - memcpy(&vmac_key[0], the_dev->dev_addr, ETH_ALEN); - *(__u16 *)(&vmac_key[ETH_ALEN]) = htons(idx); - strcpy(&vmac_key[ETH_ALEN+2], p->name); - vmac_hash = hash(vmac_key, ETH_ALEN + 2 + strlen(p->name)); - memcpy(new_vif->vmac, "\xaa\x00\x00", 3); - new_vif->vmac[3] = (vmac_hash >> 16) & 0xef; /* First bit is zero. */ - new_vif->vmac[4] = (vmac_hash >> 8) & 0xff; - new_vif->vmac[5] = (vmac_hash >> 0) & 0xff; - } - - p->net_vif_list[idx] = new_vif; - - write_unlock_irqrestore(&tasklist_lock, flags); - return new_vif; - - fail: - write_unlock_irqrestore(&tasklist_lock, flags); - if ( new_vif != NULL ) - kmem_cache_free(net_vif_cache, new_vif); - if ( p != NULL ) - put_task_struct(p); - return NULL; -} - void netif_interface_init(void) { - netif_cachep = kmem_cache_create("netif_cache", sizeof(netif_t), - 0, 0, NULL, NULL); memset(netif_hash, 0, sizeof(netif_hash)); + if ( br_add_bridge("netif-backend") != 0 ) + BUG(); + bridge_dev = __dev_get_by_name("netif-be-bridge"); + (void)dev_open(bridge_dev); } diff --git a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c index eb23384662..5b84eba9bc 100644 --- a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c +++ b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c @@ -11,7 +11,10 @@ */ #include "common.h" +#include <asm/hypervisor-ifs/dom_mem_ops.h> +static void net_tx_action(unsigned long unused); +static void tx_skb_release(struct sk_buff *skb); static void make_tx_response(netif_t *netif, u16 id, s8 st); @@ -21,38 +24,125 @@ static void make_rx_response(netif_t *netif, netif_addr_t addr, u16 size); +static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0); + /* Don't currently gate addition of an interface to the tx scheduling list. */ #define tx_work_exists(_if) (1) #define MAX_PENDING_REQS 256 -static struct vm_struct *mmap_vma; -#define MMAP_VADDR(_req) ((unsigned long)mmap_vma->addr + ((_req) * PAGE_SIZE)) +unsigned long mmap_vstart; +#define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE)) + +#define PKT_PROT_LEN (ETH_HLEN + 20) /*static pending_req_t pending_reqs[MAX_PENDING_REQS];*/ +static u16 pending_id[MAX_PENDING_REQS]; static u16 pending_ring[MAX_PENDING_REQS]; static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED; -/* NB. We use a different index type to differentiate from shared blk rings. */ typedef unsigned int PEND_RING_IDX; #define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) static PEND_RING_IDX pending_prod, pending_cons; #define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) +static struct list_head net_schedule_list; +static spinlock_t net_schedule_list_lock; + +#define MAX_MFN_ALLOC 64 +static unsigned long mfn_list[MAX_MFN_ALLOC]; +static unsigned int alloc_index = 0; +static spinlock_t mfn_lock = SPIN_LOCK_UNLOCKED; +static void __refresh_mfn_list(void) +{ + int ret; + dom_mem_op_t op; + op.op = MEMOP_RESERVATION_INCREASE; + op.u.increase.size = MAX_MFN_ALLOC; + op.u.increase.pages = mfn_list; + if ( (ret = HYPERVISOR_dom_mem_op(&op)) != MAX_MFN_ALLOC ) + { + printk(KERN_WARNING "Unable to increase memory reservation (%d)\n", + ret); + BUG(); + } + alloc_index = MAX_MFN_ALLOC; +} +static unsigned long get_new_mfn(void) +{ + unsigned long mfn, flags; + spin_lock_irqsave(&mfn_lock, flags); + if ( alloc_index == 0 ) + __refresh_mfn_list(); + mfn = mfn_list[--alloc_index]; + spin_unlock_irqrestore(&mfn_lock, flags); + return mfn; +} +static void dealloc_mfn(unsigned long mfn) +{ + unsigned long flags; + spin_lock_irqsave(&mfn_lock, flags); + mfn_list[alloc_index++] = mfn; + spin_unlock_irqrestore(&mfn_lock, flags); +} + +static inline void maybe_schedule_tx_action(void) +{ + smp_mb(); + if ( (NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && + !list_empty(&net_schedule_list) ) + tasklet_schedule(&net_tx_tasklet); +} + /* * This is the primary RECEIVE function for a network interface. * Note that, from the p.o.v. of /this/ OS it looks like a transmit. */ -static void netif_start_xmit(struct sk_buff *skb, struct net_device *dev) +int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_t *netif = (netif_t *)dev->priv; - s8 status = BLKIF_RSP_OKAY; - u16 size; - mmu_update_t mmu[4]; + s8 status = NETIF_RSP_OKAY; + u16 size, id; + mmu_update_t mmu[6]; + pgd_t *pgd; pmd_t *pmd; pte_t *pte; + unsigned long vdata, new_mfn; + + /* Drop the packet if the target domain has no receive buffers. */ + if ( (netif->rx_req_cons == netif->rx->req_prod) || + ((netif->rx_req_cons-netif->rx_resp_prod) == NETIF_RX_RING_SIZE) ) + { + dev_kfree_skb(skb); + return 0; + } - memcpy(skb->mac.ethernet->h_dest, netif->vmac, ETH_ALEN); - if ( ntohs(skb->mac.ethernet->h_proto) == ETH_P_ARP ) - memcpy(skb->nh.raw + 18, netif->vmac, ETH_ALEN); + id = netif->rx->ring[MASK_NETIF_RX_IDX(netif->rx_req_cons++)].req.id; + + /* + * We do not copy the packet unless: + * 1. It is fragmented; or + * 2. It spans a page boundary; or + * 3. We cannot be sure the whole data page is allocated. + * The copying method is taken from skb_copy(). + */ + if ( (skb_shinfo(skb)->nr_frags != 0) || + (((unsigned long)skb->end ^ (unsigned long)skb->head) & PAGE_MASK) || + ((skb->end - skb->head) < (PAGE_SIZE/2)) ) + { + struct sk_buff *nskb = dev_alloc_skb(PAGE_SIZE-1024); + int hlen = skb->data - skb->head; + skb_reserve(nskb, hlen); + skb_put(nskb, skb->len); + (void)skb_copy_bits(skb, -hlen, nskb->head, hlen + skb->len); + dev_kfree_skb(skb); + skb = nskb; + } - spin_lock(&netif->rx_lock); + vdata = (unsigned long)skb->data; + size = skb->tail - skb->data; + + new_mfn = get_new_mfn(); + + pgd = pgd_offset_k( (vdata & PAGE_MASK)); + pmd = pmd_offset(pgd, (vdata & PAGE_MASK)); + pte = pte_offset(pmd, (vdata & PAGE_MASK)); mmu[0].val = (unsigned long)(netif->domid<<16) & ~0xFFFFUL; mmu[0].ptr = (unsigned long)(netif->domid<< 0) & ~0xFFFFUL; @@ -63,49 +153,43 @@ static void netif_start_xmit(struct sk_buff *skb, struct net_device *dev) mmu[1].ptr |= MMU_EXTENDED_COMMAND; mmu[1].val |= MMUEXT_SET_SUBJECTDOM_H; - mmu[2].ptr = ptr | MMU_EXTENDED_COMMAND; + mmu[2].ptr = virt_to_machine(vdata & PAGE_MASK) | MMU_EXTENDED_COMMAND; mmu[2].val = MMUEXT_REASSIGN_PAGE; - mmu[3].ptr = ppte; - mmu[3].val = newpage; + mmu[3].ptr = MMU_EXTENDED_COMMAND; + mmu[3].val = MMUEXT_RESET_SUBJECTDOM; - if ( unlikely(HYPERVISOR_mmu_update(mmu, 4) < 0) ) + mmu[4].ptr = virt_to_machine(pte); + mmu[4].val = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL; + + mmu[5].ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; + mmu[5].val = __pa(vdata) >> PAGE_SHIFT; + + if ( unlikely(HYPERVISOR_mmu_update(mmu, 6) < 0) ) { - status = BLKIF_RSP_ERROR; + dealloc_mfn(new_mfn); + status = NETIF_RSP_ERROR; goto out; } - /* Record this so they can be billed. */ - netif->total_packets_received++; - netif->total_bytes_received += size; + phys_to_machine_mapping[__pa(vdata) >> PAGE_SHIFT] = new_mfn; + + netif->stats.tx_bytes += size; + netif->stats.tx_packets++; out: - make_rx_response(netif, rx->id, status, addr, size); + spin_lock(&netif->rx_lock); + make_rx_response(netif, id, status, virt_to_machine(vdata), size); spin_unlock(&netif->rx_lock); dev_kfree_skb(skb); + return 0; } - -/************************************************************* - * NEW TRANSMIT SCHEDULER - * - * NB. We ought also to only send a limited number of bytes to the NIC - * for transmission at any one time (to avoid head-of-line blocking). - * However, driver rings are small enough that they provide a reasonable - * limit. - * - * eg. 3c905 has 16 descriptors == 8 packets, at 100Mbps - * e1000 has 256 descriptors == 128 packets, at 1000Mbps - * tg3 has 512 descriptors == 256 packets, at 1000Mbps - * - * So, worst case is tg3 with 256 1500-bytes packets == 375kB. - * This would take 3ms, and represents our worst-case HoL blocking cost. - * - * We think this is reasonable. - */ - -struct list_head net_schedule_list; -spinlock_t net_schedule_list_lock; +struct net_device_stats *netif_be_get_stats(struct net_device *dev) +{ + netif_t *netif = dev->priv; + return &netif->stats; +} static int __on_net_schedule_list(netif_t *netif) { @@ -128,7 +212,7 @@ static void add_to_net_schedule_list_tail(netif_t *netif) return; spin_lock(&net_schedule_list_lock); - if ( likely(!__on_net_schedule_list(netif)) ) + if ( !__on_net_schedule_list(netif) && (netif->status == CONNECTED) ) { list_add_tail(&netif->list, &net_schedule_list); netif_get(netif); @@ -136,34 +220,12 @@ static void add_to_net_schedule_list_tail(netif_t *netif) spin_unlock(&net_schedule_list_lock); } - -static void tx_skb_release(struct sk_buff *skb); - -static inline int init_tx_header(netif_t *netif, u8 *data, - unsigned int len, struct net_device *dev) +void netif_deschedule(netif_t *netif) { - int proto = ntohs(*(unsigned short *)(data + 12)); - - memcpy(data + ETH_ALEN, dev->dev_addr, ETH_ALEN); - - switch ( proto ) - { - case ETH_P_ARP: - if ( len < 42 ) break; - memcpy(data + 22, dev->dev_addr, ETH_ALEN); - break; - case ETH_P_IP: - break; - default: - /* Unsupported protocols are onyl allowed to/from NETIF0/0. */ - if ( (netif->domain->domain != 0) || (netif->idx != 0) ) - proto = 0; - break; - } - return proto; + remove_from_net_schedule_list(netif); } - +#if 0 static void tx_credit_callback(unsigned long data) { netif_t *netif = (netif_t *)data; @@ -176,6 +238,7 @@ static void tx_credit_callback(unsigned long data) maybe_schedule_tx_action(); } } +#endif static void net_tx_action(unsigned long unused) { @@ -184,6 +247,7 @@ static void net_tx_action(unsigned long unused) netif_t *netif; netif_tx_request_t txreq; u16 pending_idx; + NETIF_RING_IDX i; pgprot_t prot = __pgprot(_PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED); while ( (NR_PENDING_REQS < MAX_PENDING_REQS) && @@ -197,7 +261,7 @@ static void net_tx_action(unsigned long unused) /* Work to do? */ i = netif->tx_req_cons; - if ( (i == shared_idxs->tx_req_prod) && + if ( (i == netif->tx->req_prod) && ((i-netif->tx_resp_prod) == NETIF_TX_RING_SIZE) ) { netif_put(netif); @@ -246,7 +310,7 @@ static void net_tx_action(unsigned long unused) /* No crossing a page boundary as the payload mustn't fragment. */ if ( unlikely(((txreq.addr & ~PAGE_MASK) + txreq.size) >= PAGE_SIZE) ) { - DPRINTK("tx.addr: %lx, size: %u, end: %lu\n", + DPRINTK("txreq.addr: %lx, size: %u, end: %lu\n", txreq.addr, txreq.size, (txreq.addr &~PAGE_MASK) + txreq.size); make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); @@ -262,42 +326,38 @@ static void net_tx_action(unsigned long unused) PAGE_SIZE, prot, netif->domid) != 0 ) { DPRINTK("Bad page frame\n"); - make_tx_response(netif, tx.id, NETIF_RSP_ERROR); + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); netif_put(netif); continue; } - + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] = + txreq.addr >> PAGE_SHIFT; + if ( unlikely((skb = alloc_skb(PKT_PROT_LEN, GFP_ATOMIC)) == NULL) ) { - make_tx_response(netif, tx.id, BLKIF_RSP_ERROR); + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); netif_put(netif); vmfree_area_pages(MMAP_VADDR(pending_idx), PAGE_SIZE); break; } - __skb_put(PKT_PROT_LEN); - memcpy(skb->data, src, PKT_PROT_LEN); - protocol = __constant_htons( - init_tx_header(netif, g_data, tx.size, the_dev)); - if ( protocol == 0 ) - { - make_tx_response(netif, tx.id, NETIF_RSP_ERROR); - netif_put(netif); - dev_kfree_skb(skb); - goto cleanup_and_continue; - } + __skb_put(skb, PKT_PROT_LEN); + memcpy(skb->data, + (void *)(MMAP_VADDR(pending_idx)|(txreq.addr&~PAGE_MASK)), + PKT_PROT_LEN); skb->dev = netif->dev; skb->protocol = eth_type_trans(skb, skb->dev); /* Append the packet payload as a fragment. */ skb_shinfo(skb)->frags[0].page = - &mem_map[txreq.addr >> PAGE_SHIFT]; - skb_shinfo(skb)->frags[0].size = txreq.size - PKT_PROT_LEN; + virt_to_page(MMAP_VADDR(pending_idx)); + skb_shinfo(skb)->frags[0].size = + txreq.size - PKT_PROT_LEN; skb_shinfo(skb)->frags[0].page_offset = (txreq.addr + PKT_PROT_LEN) & ~PAGE_MASK; skb_shinfo(skb)->nr_frags = 1; - skb->data_len = tx->size - PKT_PROT_LEN; + skb->data_len = txreq.size - PKT_PROT_LEN; skb->len += skb->data_len; /* Destructor information. */ @@ -305,33 +365,22 @@ static void net_tx_action(unsigned long unused) skb_shinfo(skb)->frags[MAX_SKB_FRAGS-1].page = (struct page *)netif; skb_shinfo(skb)->frags[MAX_SKB_FRAGS-1].size = pending_idx; - /* Record the transmission so they can be billed. */ - netif->total_packets_sent++; - netif->total_bytes_sent += tx->size; + netif->stats.rx_bytes += txreq.size; + netif->stats.rx_packets++; + pending_id[pending_idx] = txreq.id; pending_cons++; + netif_rx(skb); netif->dev->last_rx = jiffies; } } -DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0); - - -static inline void maybe_schedule_tx_action(void) -{ - smp_mb(); - if ( !netif_queue_stopped(the_dev) && - !list_empty(&net_schedule_list) ) - tasklet_schedule(&net_tx_tasklet); -} - - /* Destructor function for tx skbs. */ static void tx_skb_release(struct sk_buff *skb) { - int i; - netif_t *netif = (netif_t)skb_shinfo(skb)->frags[MAX_SKB_FRAGS-1].page; + unsigned long flags; + netif_t *netif = (netif_t *)skb_shinfo(skb)->frags[MAX_SKB_FRAGS-1].page; u16 pending_idx = skb_shinfo(skb)->frags[MAX_SKB_FRAGS-1].size; vmfree_area_pages(MMAP_VADDR(pending_idx), PAGE_SIZE); @@ -339,25 +388,19 @@ static void tx_skb_release(struct sk_buff *skb) skb_shinfo(skb)->nr_frags = 0; spin_lock(&netif->tx_lock); - make_tx_response(netif, skb->guest_id, NETIF_RSP_OKAY); + make_tx_response(netif, pending_id[pending_idx], NETIF_RSP_OKAY); spin_unlock(&netif->tx_lock); - /* - * Checks below must happen after the above response is posted. This avoids - * a possible race with a guest OS on another CPU. - */ - mb(); - - if ( tx_work_exists(netif) ) - { - add_to_net_schedule_list_tail(netif); - maybe_schedule_tx_action(); - } - netif_put(netif); + + spin_lock_irqsave(&pend_prod_lock, flags); + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; + spin_unlock_irqrestore(&pend_prod_lock, flags); + + maybe_schedule_tx_action(); } - +#if 0 long flush_bufs_for_netif(netif_t *netif) { NET_RING_IDX i; @@ -395,6 +438,7 @@ long flush_bufs_for_netif(netif_t *netif) return 0; } +#endif void netif_be_int(int irq, void *dev_id, struct pt_regs *regs) { @@ -424,7 +468,6 @@ static void make_tx_response(netif_t *netif, notify_via_evtchn(netif->evtchn); } - static void make_rx_response(netif_t *netif, u16 id, s8 st, @@ -448,28 +491,18 @@ static void make_rx_response(netif_t *netif, notify_via_evtchn(netif->evtchn); } - static int __init init_module(void) { netif_interface_init(); - - if ( (mmap_vma = get_vm_area(MAX_PENDING_REQS * PAGE_SIZE, - VM_IOREMAP)) == NULL ) - { - printk(KERN_WARNING "Could not allocate VMA for netif backend.\n"); - return -ENOMEM; - } - + mmap_vstart = allocate_empty_lowmem_region(MAX_PENDING_REQS); netif_ctrlif_init(); - return 0; } - static void cleanup_module(void) { + BUG(); } - module_init(init_module); module_exit(cleanup_module); diff --git a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/frontend/main.c b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/frontend/main.c index f2c36f1f88..af8e660b7c 100644 --- a/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/frontend/main.c +++ b/xenolinux-2.4.26-sparse/arch/xen/drivers/netif/frontend/main.c @@ -25,6 +25,10 @@ #include <net/sock.h> #include <net/pkt_sched.h> +#include "../netif.h" + +static struct tq_struct netif_statechange_tq; + #define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */ static void network_interrupt(int irq, void *dev_id, struct pt_regs *ptregs); @@ -44,17 +48,21 @@ struct net_private struct net_device_stats stats; NET_RING_IDX rx_resp_cons, tx_resp_cons; - unsigned int net_ring_fixmap_idx, tx_full; - net_ring_t *net_ring; - net_idx_t *net_idx; + unsigned int tx_full; + + netif_tx_interface_t *tx; + netif_rx_interface_t *rx; + spinlock_t tx_lock; - unsigned int idx; /* Domain-specific index of this VIF. */ - unsigned int rx_bufs_to_notify; + unsigned int handle; + unsigned int evtchn; + unsigned int irq; -#define STATE_ACTIVE 0 -#define STATE_SUSPENDED 1 -#define STATE_CLOSED 2 +#define NETIF_STATE_CLOSED 0 +#define NETIF_STATE_DISCONNECTED 1 +#define NETIF_STATE_CONNECTED 2 +#define NETIF_STATE_ACTIVE 3 unsigned int state; /* @@ -75,36 +83,17 @@ struct net_private (unsigned short)_id; }) -static void _dbg_network_int(struct net_device *dev) -{ - struct net_private *np = dev->priv; - - if ( np->state == STATE_CLOSED ) - return; - - printk(KERN_ALERT "net: tx_full=%d, tx_resp_cons=0x%08x," - " tx_req_prod=0x%08x\nnet: tx_resp_prod=0x%08x," - " tx_event=0x%08x, state=%d\n", - np->tx_full, np->tx_resp_cons, - np->net_idx->tx_req_prod, np->net_idx->tx_resp_prod, - np->net_idx->tx_event, - test_bit(__LINK_STATE_XOFF, &dev->state)); - printk(KERN_ALERT "net: rx_resp_cons=0x%08x," - " rx_req_prod=0x%08x\nnet: rx_resp_prod=0x%08x, rx_event=0x%08x\n", - np->rx_resp_cons, np->net_idx->rx_req_prod, - np->net_idx->rx_resp_prod, np->net_idx->rx_event); -} - - -static void dbg_network_int(int irq, void *unused, struct pt_regs *ptregs) +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); - _dbg_network_int(np->dev); + if ( np->handle == handle ) + return np; } + return NULL; } @@ -114,36 +103,12 @@ static int network_open(struct net_device *dev) netop_t netop; int i, ret; - netop.cmd = NETOP_RESET_RINGS; - netop.vif = np->idx; - if ( (ret = HYPERVISOR_net_io_op(&netop)) != 0 ) - { - printk(KERN_ALERT "Possible net trouble: couldn't reset ring idxs\n"); - return ret; - } - - netop.cmd = NETOP_GET_VIF_INFO; - netop.vif = np->idx; - if ( (ret = HYPERVISOR_net_io_op(&netop)) != 0 ) - { - printk(KERN_ALERT "Couldn't get info for vif %d\n", np->idx); - return ret; - } - - memcpy(dev->dev_addr, netop.u.get_vif_info.vmac, ETH_ALEN); + if ( np->state != NETIF_STATE_CONNECTED ) + return -EINVAL; - set_fixmap(FIX_NETRING0_BASE + np->net_ring_fixmap_idx, - netop.u.get_vif_info.ring_mfn << PAGE_SHIFT); - np->net_ring = (net_ring_t *)fix_to_virt( - FIX_NETRING0_BASE + np->net_ring_fixmap_idx); - np->net_idx = &HYPERVISOR_shared_info->net_idx[np->idx]; - - np->rx_bufs_to_notify = 0; np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0; memset(&np->stats, 0, sizeof(np->stats)); spin_lock_init(&np->tx_lock); - memset(np->net_ring, 0, sizeof(*np->net_ring)); - memset(np->net_idx, 0, sizeof(*np->net_idx)); /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ for ( i = 0; i <= XENNET_TX_RING_SIZE; i++ ) @@ -152,7 +117,7 @@ static int network_open(struct net_device *dev) np->rx_skbs[i] = (void *)(i+1); wmb(); - np->state = STATE_ACTIVE; + np->state = NETIF_STATE_ACTIVE; network_alloc_rx_buffers(dev); @@ -203,7 +168,7 @@ static void network_tx_buf_gc(struct net_device *dev) ((np->net_idx->tx_req_prod - prod) < XENNET_TX_RING_SIZE) ) { np->tx_full = 0; - if ( np->state == STATE_ACTIVE ) + if ( np->state == NETIF_STATE_ACTIVE ) netif_wake_queue(dev); } } @@ -228,7 +193,7 @@ static void network_alloc_rx_buffers(struct net_device *dev) NET_RING_IDX i = np->net_idx->rx_req_prod; if ( unlikely((i - np->rx_resp_cons) == XENNET_RX_RING_SIZE) || - unlikely(np->state != STATE_ACTIVE) ) + unlikely(np->state != NETIF_STATE_ACTIVE) ) return; do { @@ -341,17 +306,15 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) } -static inline void _network_interrupt(struct net_device *dev) +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; struct sk_buff *skb; rx_resp_entry_t *rx; NET_RING_IDX i; - if ( unlikely(np->state == STATE_CLOSED) ) - return; - spin_lock_irqsave(&np->tx_lock, flags); network_tx_buf_gc(dev); spin_unlock_irqrestore(&np->tx_lock, flags); @@ -367,7 +330,7 @@ static inline void _network_interrupt(struct net_device *dev) if ( unlikely(rx->status != RING_STATUS_OK) ) { /* Gate this error. We get a (valid) slew of them on suspend. */ - if ( np->state == STATE_ACTIVE ) + if ( np->state == NETIF_STATE_ACTIVE ) printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status); dev_kfree_skb_any(skb); continue; @@ -407,26 +370,11 @@ static inline void _network_interrupt(struct net_device *dev) } -static void network_interrupt(int irq, void *unused, struct pt_regs *ptregs) -{ - struct list_head *ent; - struct net_private *np; - list_for_each ( ent, &dev_list ) - { - np = list_entry(ent, struct net_private, list); - _network_interrupt(np->dev); - } -} - - static int network_close(struct net_device *dev) { struct net_private *np = dev->priv; netop_t netop; - np->state = STATE_SUSPENDED; - wmb(); - netif_stop_queue(np->dev); netop.cmd = NETOP_FLUSH_BUFFERS; @@ -442,12 +390,9 @@ static int network_close(struct net_device *dev) } wmb(); - np->state = STATE_CLOSED; + np->state = NETIF_STATE_CONNECTED; wmb(); - /* Now no longer safe to take interrupts for this device. */ - clear_fixmap(FIX_NETRING0_BASE + np->net_ring_fixmap_idx); - MOD_DEC_USE_COUNT; return 0; @@ -461,72 +406,181 @@ static struct net_device_stats *network_get_stats(struct net_device *dev) } -static int __init init_module(void) +static void netif_bringup_phase1(void *unused) { -#if 0 - int i, fixmap_idx=-1, err; + ctrl_msg_t cmsg; + netif_fe_interface_connect_t up; struct net_device *dev; struct net_private *np; - netop_t netop; - INIT_LIST_HEAD(&dev_list); + dev = find_dev_by_handle(0); + np = dev->priv; + + /* 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->state = NETIF_STATE_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 = 0; + 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); +} - network_irq = bind_virq_to_irq(VIRQ_NET); - debug_irq = bind_virq_to_irq(VIRQ_DEBUG); +static void netif_bringup_phase2(void *unused) +{ + struct net_device *dev; + struct net_private *np; + + dev = find_dev_by_handle(0); + np = dev->priv; + + np->irq = bind_evtchn_to_irq(np->evtchn); + (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, + "netif", dev); - err = request_irq(network_irq, network_interrupt, - SA_SAMPLE_RANDOM, "network", NULL); - if ( err ) + np->state = NETIF_STATE_CONNECTED; +} + +static void netif_status_change(netif_fe_interface_status_changed_t *status) +{ + struct net_device *dev; + struct net_private *np; + + if ( status->handle != 0 ) { - printk(KERN_WARNING "Could not allocate network interrupt\n"); - goto fail; + printk(KERN_WARNING "Status change on unsupported netif %d\n", + status->handle); + return; } - - err = request_irq(debug_irq, dbg_network_int, - SA_SHIRQ, "net_dbg", &dbg_network_int); - if ( err ) - printk(KERN_WARNING "Non-fatal error -- no debug interrupt\n"); - for ( i = 0; i < MAX_DOMAIN_VIFS; i++ ) + dev = find_dev_by_handle(0); + np = dev->priv; + + switch ( status->status ) { - /* If the VIF is invalid then the query hypercall will fail. */ - netop.cmd = NETOP_GET_VIF_INFO; - netop.vif = i; - if ( HYPERVISOR_net_io_op(&netop) != 0 ) - continue; + case NETIF_INTERFACE_STATUS_DESTROYED: + printk(KERN_WARNING "Unexpected netif-DESTROYED message in state %d\n", + netif_state); + break; - /* We actually only support up to 4 vifs right now. */ - if ( ++fixmap_idx == 4 ) + case NETIF_INTERFACE_STATUS_DISCONNECTED: + if ( np->state != NETIF_STATE_CLOSED ) + { + printk(KERN_WARNING "Unexpected netif-DISCONNECTED message" + " in state %d\n", netif_state); break; + } + netif_statechange_tq.routine = netif_bringup_phase1; + schedule_task(&netif_statechange_tq); + break; - dev = alloc_etherdev(sizeof(struct net_private)); - if ( dev == NULL ) + case NETIF_INTERFACE_STATUS_CONNECTED: + if ( np->state == NETIF_STATE_CLOSED ) { - err = -ENOMEM; - goto fail; + printk(KERN_WARNING "Unexpected netif-CONNECTED message" + " in state %d\n", netif_state); + break; } + np->evtchn = status->evtchn; + memcpy(dev->dev_addr, status->mac, ETH_ALEN); + netif_statechange_tq.routine = netif_bringup_phase2; + schedule_task(&netif_statechange_tq); + break; + + default: + printk(KERN_WARNING "Status change to unknown value %d\n", + status->status); + break; + } +} + + +static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) +{ + switch ( msg->subtype ) + { + case CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED: + if ( msg->length != sizeof(netif_fe_interface_status_changed_t) ) + goto parse_error; + netif_status_change((netif_fe_interface_status_changed_t *) + &msg->msg[0]); + break; + default: + goto parse_error; + } - np = dev->priv; - np->state = STATE_CLOSED; - np->net_ring_fixmap_idx = fixmap_idx; - np->idx = i; + ctrl_if_send_response(msg); + return; - SET_MODULE_OWNER(dev); - dev->open = network_open; - dev->hard_start_xmit = network_start_xmit; - dev->stop = network_close; - dev->get_stats = network_get_stats; + parse_error: + msg->length = 0; + ctrl_if_send_response(msg); +} - memcpy(dev->dev_addr, netop.u.get_vif_info.vmac, ETH_ALEN); - if ( (err = register_netdev(dev)) != 0 ) - { - kfree(dev); - goto fail; - } +static int __init init_module(void) +{ + ctrl_msg_t cmsg; + netif_fe_driver_status_changed_t st; + int i, err; + struct net_device *dev; + struct net_private *np; + + INIT_LIST_HEAD(&dev_list); - np->dev = dev; - list_add(&np->list, &dev_list); + if ( (dev = alloc_etherdev(sizeof(struct net_private))) == NULL ) + { + err = -ENOMEM; + goto fail; + } + + np = dev->priv; + np->state = NETIF_STATE_CLOSED; + np->handle = 0; + + dev->open = network_open; + dev->hard_start_xmit = network_start_xmit; + dev->stop = network_close; + dev->get_stats = network_get_stats; + + if ( (err = register_netdev(dev)) != 0 ) + { + kfree(dev); + goto fail; + } + + np->dev = dev; + list_add(&np->list, &dev_list); + + (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx); + + /* 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; + memcpy(cmsg.msg, &st, sizeof(st)); + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); + + /* + * We should read 'nr_interfaces' from response message and wait + * for notifications before proceeding. For now we assume that we + * will be notified of exactly one interface. + */ + while ( np->state != NETIF_STATE_CONNECTED ) + { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); } return 0; @@ -534,30 +588,13 @@ static int __init init_module(void) fail: cleanup_module(); return err; -#endif - return 0; } static void cleanup_module(void) { - struct net_private *np; - struct net_device *dev; - - while ( !list_empty(&dev_list) ) - { - np = list_entry(dev_list.next, struct net_private, list); - list_del(&np->list); - dev = np->dev; - unregister_netdev(dev); - kfree(dev); - } - - free_irq(network_irq, NULL); - free_irq(debug_irq, NULL); - - unbind_virq_from_irq(VIRQ_NET); - unbind_virq_from_irq(VIRQ_DEBUG); + /* XXX FIXME */ + BUG(); } diff --git a/xenolinux-2.4.26-sparse/arch/xen/mm/hypervisor.c b/xenolinux-2.4.26-sparse/arch/xen/mm/hypervisor.c index c6dc710576..e27616e4d4 100644 --- a/xenolinux-2.4.26-sparse/arch/xen/mm/hypervisor.c +++ b/xenolinux-2.4.26-sparse/arch/xen/mm/hypervisor.c @@ -8,7 +8,10 @@ #include <linux/config.h> #include <linux/sched.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> #include <asm/hypervisor.h> +#include <asm/hypervisor-ifs/dom_mem_ops.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/multicall.h> @@ -242,3 +245,105 @@ void queue_set_ldt(unsigned long ptr, unsigned long len) increment_index(); spin_unlock_irqrestore(&update_lock, flags); } + +void queue_machphys_update(unsigned long mfn, unsigned long pfn) +{ + unsigned long flags; + spin_lock_irqsave(&update_lock, flags); + update_queue[idx].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; + update_queue[idx].val = pfn; + increment_index(); + spin_unlock_irqrestore(&update_lock, flags); +} + +#ifdef CONFIG_XEN_PHYSDEV_ACCESS + +unsigned long allocate_empty_lowmem_region(unsigned long pages) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long *pfn_array; + unsigned long vstart; + unsigned long i; + int ret; + unsigned int order = get_order(pages*PAGE_SIZE); + dom_mem_op_t dom_mem_op; + + vstart = __get_free_pages(GFP_KERNEL, order); + if ( vstart == 0 ) + return 0UL; + + pfn_array = vmalloc((1<<order) * sizeof(*pfn_array)); + if ( pfn_array == NULL ) + BUG(); + + for ( i = 0; i < (1<<order); i++ ) + { + pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE))); + pmd = pmd_offset(pgd, (vstart + (i*PAGE_SIZE))); + pte = pte_offset(pmd, (vstart + (i*PAGE_SIZE))); + pfn_array[i] = pte->pte_low >> PAGE_SHIFT; + queue_l1_entry_update(pte, 0); + phys_to_machine_mapping[__pa(vstart)>>PAGE_SHIFT] = 0xdeadbeef; + } + + flush_page_update_queue(); + + dom_mem_op.op = MEMOP_RESERVATION_DECREASE; + dom_mem_op.u.decrease.size = 1<<order; + dom_mem_op.u.decrease.pages = pfn_array; + if ( (ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != (1<<order) ) + { + printk(KERN_WARNING "Unable to reduce memory reservation (%d)\n", ret); + BUG(); + } + + vfree(pfn_array); + + return vstart; +} + +void deallocate_lowmem_region(unsigned long vstart, unsigned long pages) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long *pfn_array; + unsigned long i; + int ret; + unsigned int order = get_order(pages*PAGE_SIZE); + dom_mem_op_t dom_mem_op; + + pfn_array = vmalloc((1<<order) * sizeof(*pfn_array)); + if ( pfn_array == NULL ) + BUG(); + + dom_mem_op.op = MEMOP_RESERVATION_INCREASE; + dom_mem_op.u.increase.size = 1<<order; + dom_mem_op.u.increase.pages = pfn_array; + if ( (ret = HYPERVISOR_dom_mem_op(&dom_mem_op)) != (1<<order) ) + { + printk(KERN_WARNING "Unable to increase memory reservation (%d)\n", + ret); + BUG(); + } + + for ( i = 0; i < (1<<order); i++ ) + { + pgd = pgd_offset_k( (vstart + (i*PAGE_SIZE))); + pmd = pmd_offset(pgd, (vstart + (i*PAGE_SIZE))); + pte = pte_offset(pmd, (vstart + (i*PAGE_SIZE))); + queue_l1_entry_update(pte, (pfn_array[i]<<PAGE_SHIFT)|__PAGE_KERNEL); + queue_machphys_update(pfn_array[i], __pa(vstart)>>PAGE_SHIFT); + phys_to_machine_mapping[__pa(vstart)>>PAGE_SHIFT] = pfn_array[i]; + } + + flush_page_update_queue(); + + vfree(pfn_array); + + free_pages(vstart, order); +} + +#endif /* CONFIG_XEN_PHYSDEV_ACCESS */ |