bitkeeper revision 1.891.2.1 (409a27ddyHHSEFrv4iElGUakv9riiw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 6 May 2004 11:56:13 +0000 (11:56 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 6 May 2004 11:56:13 +0000 (11:56 +0000)
First cut of new network backend. Net frontend is in progress.

tools/xend/lib/domain_controller.h
xen/common/memory.c
xen/include/hypervisor-ifs/hypervisor-if.h
xenolinux-2.4.26-sparse/arch/xen/defconfig-physdev
xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/common.h
xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/interface.c
xenolinux-2.4.26-sparse/arch/xen/drivers/netif/backend/main.c
xenolinux-2.4.26-sparse/arch/xen/drivers/netif/frontend/main.c
xenolinux-2.4.26-sparse/arch/xen/mm/hypervisor.c
xenolinux-2.4.26-sparse/include/asm-xen/hypervisor.h

index 8fe7353e944eb0ae6fab4be297c3d0755f65ad4b..d5c397fe96ef18ed040e1f029dbab34bb51a1cd6 100644 (file)
@@ -342,6 +342,7 @@ typedef struct {
     unsigned int handle;
     unsigned int status;
     unsigned int evtchn; /* status == NETIF_INTERFACE_STATUS_CONNECTED */
+    u8           mac[6]; /* status == NETIF_INTERFACE_STATUS_CONNECTED */
 } netif_fe_interface_status_changed_t;
 
 /*
@@ -373,7 +374,8 @@ typedef struct {
  */
 typedef struct {
     unsigned int  handle;
-    unsigned long shmem_frame;
+    unsigned long tx_shmem_frame;
+    unsigned long rx_shmem_frame;
 } netif_fe_interface_connect_t;
 
 /*
@@ -434,6 +436,7 @@ typedef struct {
     /* IN */
     domid_t        domid;             /* Domain attached to new interface.   */
     unsigned int   netif_handle;      /* Domain-specific interface handle.   */
+    u8             mac[6];
     /* OUT */
     unsigned int   status;
 } netif_be_create_t; 
@@ -463,7 +466,9 @@ typedef struct {
     domid_t        domid;             /* Domain attached to new interface.   */
     unsigned int   netif_handle;      /* Domain-specific interface handle.   */
     unsigned int   evtchn;            /* Event channel for notifications.    */
-    unsigned long  shmem_frame;       /* Page cont. shared comms window.     */
+    unsigned long  tx_shmem_frame;    /* Page cont. tx shared comms window.  */
+    unsigned long  rx_shmem_frame;    /* Page cont. rx shared comms window.  */
+    unsigned long  shmem_frame;       
     /* OUT */
     unsigned int   status;
 } netif_be_connect_t; 
index ed2e5b6e170df202f7ae34f92e4bdfade17d77df..8ff55e42ca3e2434175c882ba2ea517884169fd9 100644 (file)
@@ -910,7 +910,8 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         break;
 
     case MMUEXT_SET_SUBJECTDOM_H:
-        percpu_info[cpu].subject_id |= ((domid_t)((ptr&~0xFFFF)|(val>>16)))<<32;
+        percpu_info[cpu].subject_id |= 
+            ((domid_t)((ptr&~0xFFFF)|(val>>16)))<<32;
 
         if ( !IS_PRIV(current) )
         {
@@ -934,6 +935,25 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         }
         break;
 
+    case MMUEXT_REASSIGN_PAGE:
+        if ( !IS_PRIV(current) )
+        {
+            MEM_LOG("Dom %llu has no privilege to reassign page ownership",
+                    current->domain);
+            okay = 0;
+        }
+        else if ( percpu_info[cpu].gps != NULL )
+        {
+            page->u.domain = percpu_info[cpu].gps;
+        }
+        break;
+
+    case MMUEXT_RESET_SUBJECTDOM:
+        if ( percpu_info[cpu].gps != NULL )
+            put_task_struct(percpu_info[cpu].gps);
+        percpu_info[cpu].gps = percpu_info[cpu].pts = NULL;
+        break;
+
     default:
         MEM_LOG("Invalid extended pt command 0x%08lx", val & MMUEXT_CMD_MASK);
         okay = 0;
index 8660d86ed5990cfa2c03d88110ea61156445711b..5cde5d46e4d4e4b02524a5f6117f8ac6795cc7f4 100644 (file)
  *   (ptr[31:15],val[31:15]) -- dom[63:32]
  *   NB. This command must be immediately preceded by SET_SUBJECTDOM_L.
  * 
+ *   val[7:0] == MMUEXT_REASSIGN_PAGE:
+ *   ptr[:2]  -- machine address within page to be reassigned to the GPS.
+ * 
+ *   val[7:0] == MMUEXT_RESET_SUBJECTDOM:
+ *   Resets both the GPS and the PTS to their defaults (i.e., calling domain).
+ * 
  * Notes on constraints on the above arguments:
  *  [1] The page frame containing the machine address must belong to the PTS.
  *  [2] If the PTE is valid (i.e., bit 0 is set) then the specified page frame
 #define MMUEXT_SET_SUBJECTDOM_L  9 /* (ptr[31:15],val[31:15]) = dom[31:0]    */
 #define MMUEXT_SET_SUBJECTDOM_H 10 /* (ptr[31:15],val[31:15]) = dom[63:32]   */
 #define SET_PAGETABLE_SUBJECTDOM (1<<14) /* OR into 'val' arg of SUBJECTDOM_H*/
+#define MMUEXT_REASSIGN_PAGE    11
+#define MMUEXT_RESET_SUBJECTDOM 12
 #define MMUEXT_CMD_MASK        255
 #define MMUEXT_CMD_SHIFT         8
 
index 69aa6c085678c43b0a4b2f2e0d9deb39de48c85f..41b05aaaa7741d23ef6744ab64b8c8744d3155bc 100644 (file)
@@ -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
index 1e95d9f48009c9cb85d290180b3ea1c69969398f..88881cdf66882af46726d61ab3ed49f6a2c63a72 100644 (file)
@@ -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__ */
index d12ca3057d6171beda786cc8c08a0882c4bead2a..8623d8214ba9f9cb52494d8440ed9f76a8daceb0 100644 (file)
@@ -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);
 }
index eb233846629d9f28add00e240b5e51566f9e6997..5b84eba9bc77589c30dcaf4a3bb3ec66d05b8379 100644 (file)
  */
 
 #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);
index f2c36f1f88799c70bfacc4d86d9421500eb4ee8f..af8e660b7c95119f5a769837368437610cb9074b 100644 (file)
 #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();
 }
 
 
index c6dc7105766c56e5d613b8aaa66ef843b8dbf47a..e27616e4d4d9719d5128582791f032da051df8d6 100644 (file)
@@ -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 */
index c454728c0e65b240da89d7b01ff93aa46e1eb32c..c355ec538192ee2beaafdcc20592c41d4a9d31ed 100644 (file)
@@ -44,6 +44,7 @@ void queue_pgd_unpin(unsigned long ptr);
 void queue_pte_pin(unsigned long ptr);
 void queue_pte_unpin(unsigned long ptr);
 void queue_set_ldt(unsigned long ptr, unsigned long bytes);
+void queue_machphys_update(unsigned long mfn, unsigned long pfn);
 #define MMU_UPDATE_DEBUG 0
 
 #if MMU_UPDATE_DEBUG > 0
@@ -137,6 +138,12 @@ static inline int flush_page_update_queue(void)
 #define XEN_flush_page_update_queue() (_flush_page_update_queue())
 void MULTICALL_flush_page_update_queue(void);
 
+#ifdef CONFIG_XEN_PHYSDEV_ACCESS
+/* Allocate a contiguous empty region of low memory. Return virtual start. */
+unsigned long allocate_empty_lowmem_region(unsigned long pages);
+/* Deallocate a contiguous region of low memory. Return it to the allocator. */
+void deallocate_lowmem_region(unsigned long vstart, unsigned long pages);
+#endif
 
 /*
  * Assembler stubs for hyper-calls.