ia64/xen-unstable

changeset 16746:95558b4a6714

minios: support several netfronts

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 17 15:50:48 2008 +0000 (2008-01-17)
parents 6fdb108db46c
children bf828db8d017
files extras/mini-os/include/netfront.h extras/mini-os/kernel.c extras/mini-os/netfront.c
line diff
     1.1 --- a/extras/mini-os/include/netfront.h	Thu Jan 17 15:23:47 2008 +0000
     1.2 +++ b/extras/mini-os/include/netfront.h	Thu Jan 17 15:50:48 2008 +0000
     1.3 @@ -1,2 +1,7 @@
     1.4 -void init_netfront(void*);
     1.5 -void netfront_xmit(unsigned char* data,int len);
     1.6 +#include <wait.h>
     1.7 +struct netfront_dev;
     1.8 +struct netfront_dev *init_netfront(char *nodename, void (*netif_rx)(unsigned char *data, int len), unsigned char rawmac[6]);
     1.9 +void netfront_xmit(struct netfront_dev *dev, unsigned char* data,int len);
    1.10 +void shutdown_netfront(struct netfront_dev *dev);
    1.11 +
    1.12 +extern struct wait_queue_head netfront_queue;
     2.1 --- a/extras/mini-os/kernel.c	Thu Jan 17 15:23:47 2008 +0000
     2.2 +++ b/extras/mini-os/kernel.c	Thu Jan 17 15:50:48 2008 +0000
     2.3 @@ -82,7 +82,7 @@ static void periodic_thread(void *p)
     2.4  
     2.5  static void netfront_thread(void *p)
     2.6  {
     2.7 -    init_netfront(&start_info);
     2.8 +    init_netfront(NULL, NULL, NULL);
     2.9  }
    2.10  
    2.11  /* This should be overridden by the application we are linked against. */
     3.1 --- a/extras/mini-os/netfront.c	Thu Jan 17 15:23:47 2008 +0000
     3.2 +++ b/extras/mini-os/netfront.c	Thu Jan 17 15:50:48 2008 +0000
     3.3 @@ -13,19 +13,13 @@
     3.4  #include <gnttab.h>
     3.5  #include <xmalloc.h>
     3.6  #include <time.h>
     3.7 +#include <netfront.h>
     3.8 +#include <lib.h>
     3.9  #include <semaphore.h>
    3.10  
    3.11 -void init_rx_buffers(void);
    3.12 +DECLARE_WAIT_QUEUE_HEAD(netfront_queue);
    3.13  
    3.14 -struct net_info {
    3.15 -    struct netif_tx_front_ring tx;
    3.16 -    struct netif_rx_front_ring rx;
    3.17 -    int tx_ring_ref;
    3.18 -    int rx_ring_ref;
    3.19 -    unsigned int evtchn, local_port;
    3.20 -
    3.21 -} net_info;
    3.22 -
    3.23 +#define NETIF_SELECT_RX ((void*)-1)
    3.24  
    3.25  
    3.26  #define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
    3.27 @@ -33,16 +27,31 @@ struct net_info {
    3.28  #define GRANT_INVALID_REF 0
    3.29  
    3.30  
    3.31 -unsigned short rx_freelist[NET_RX_RING_SIZE];
    3.32 -unsigned short tx_freelist[NET_TX_RING_SIZE];
    3.33 -__DECLARE_SEMAPHORE_GENERIC(tx_sem, NET_TX_RING_SIZE);
    3.34 -
    3.35  struct net_buffer {
    3.36      void* page;
    3.37 -    int gref;
    3.38 +    grant_ref_t gref;
    3.39  };
    3.40 -struct net_buffer rx_buffers[NET_RX_RING_SIZE];
    3.41 -struct net_buffer tx_buffers[NET_TX_RING_SIZE];
    3.42 +
    3.43 +struct netfront_dev {
    3.44 +    unsigned short tx_freelist[NET_TX_RING_SIZE];
    3.45 +    struct semaphore tx_sem;
    3.46 +
    3.47 +    struct net_buffer rx_buffers[NET_RX_RING_SIZE];
    3.48 +    struct net_buffer tx_buffers[NET_TX_RING_SIZE];
    3.49 +
    3.50 +    struct netif_tx_front_ring tx;
    3.51 +    struct netif_rx_front_ring rx;
    3.52 +    grant_ref_t tx_ring_ref;
    3.53 +    grant_ref_t rx_ring_ref;
    3.54 +    evtchn_port_t evtchn, local_port;
    3.55 +
    3.56 +    char *nodename;
    3.57 +    char *backend;
    3.58 +
    3.59 +    void (*netif_rx)(unsigned char* data, int len);
    3.60 +};
    3.61 +
    3.62 +void init_rx_buffers(struct netfront_dev *dev);
    3.63  
    3.64  static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
    3.65  {
    3.66 @@ -69,17 +78,16 @@ static inline int xennet_rxidx(RING_IDX 
    3.67      return idx & (NET_RX_RING_SIZE - 1);
    3.68  }
    3.69  
    3.70 -void network_rx(void)
    3.71 +void network_rx(struct netfront_dev *dev)
    3.72  {
    3.73 -    struct net_info *np = &net_info;
    3.74      RING_IDX rp,cons;
    3.75      struct netif_rx_response *rx;
    3.76  
    3.77  
    3.78  moretodo:
    3.79 -    rp = np->rx.sring->rsp_prod;
    3.80 +    rp = dev->rx.sring->rsp_prod;
    3.81      rmb(); /* Ensure we see queued responses up to 'rp'. */
    3.82 -    cons = np->rx.rsp_cons;
    3.83 +    cons = dev->rx.rsp_cons;
    3.84  
    3.85      int nr_consumed=0;
    3.86      while ((cons != rp))
    3.87 @@ -87,7 +95,7 @@ moretodo:
    3.88          struct net_buffer* buf;
    3.89          unsigned char* page;
    3.90  
    3.91 -        rx = RING_GET_RESPONSE(&np->rx, cons);
    3.92 +        rx = RING_GET_RESPONSE(&dev->rx, cons);
    3.93  
    3.94          if (rx->flags & NETRXF_extra_info)
    3.95          {
    3.96 @@ -100,28 +108,26 @@ moretodo:
    3.97  
    3.98          int id = rx->id;
    3.99  
   3.100 -        buf = &rx_buffers[id];
   3.101 +        buf = &dev->rx_buffers[id];
   3.102          page = (unsigned char*)buf->page;
   3.103          gnttab_end_access(buf->gref);
   3.104  
   3.105          if(rx->status>0)
   3.106          {
   3.107 -            netif_rx(page+rx->offset,rx->status);
   3.108 +            dev->netif_rx(page+rx->offset,rx->status);
   3.109          }
   3.110  
   3.111 -        add_id_to_freelist(id,rx_freelist);
   3.112 -
   3.113          nr_consumed++;
   3.114  
   3.115          ++cons;
   3.116      }
   3.117 -    np->rx.rsp_cons=rp;
   3.118 +    dev->rx.rsp_cons=cons;
   3.119  
   3.120      int more;
   3.121 -    RING_FINAL_CHECK_FOR_RESPONSES(&np->rx,more);
   3.122 +    RING_FINAL_CHECK_FOR_RESPONSES(&dev->rx,more);
   3.123      if(more) goto moretodo;
   3.124  
   3.125 -    RING_IDX req_prod = np->rx.req_prod_pvt;
   3.126 +    RING_IDX req_prod = dev->rx.req_prod_pvt;
   3.127  
   3.128      int i;
   3.129      netif_rx_request_t *req;
   3.130 @@ -129,8 +135,8 @@ moretodo:
   3.131      for(i=0; i<nr_consumed; i++)
   3.132      {
   3.133          int id = xennet_rxidx(req_prod + i);
   3.134 -        req = RING_GET_REQUEST(&np->rx, req_prod + i);
   3.135 -        struct net_buffer* buf = &rx_buffers[id];
   3.136 +        req = RING_GET_REQUEST(&dev->rx, req_prod + i);
   3.137 +        struct net_buffer* buf = &dev->rx_buffers[id];
   3.138          void* page = buf->page;
   3.139  
   3.140          /* We are sure to have free gnttab entries since they got released above */
   3.141 @@ -142,45 +148,44 @@ moretodo:
   3.142  
   3.143      wmb();
   3.144  
   3.145 -    np->rx.req_prod_pvt = req_prod + i;
   3.146 +    dev->rx.req_prod_pvt = req_prod + i;
   3.147      
   3.148      int notify;
   3.149 -    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
   3.150 +    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
   3.151      if (notify)
   3.152 -        notify_remote_via_evtchn(np->evtchn);
   3.153 +        notify_remote_via_evtchn(dev->evtchn);
   3.154  
   3.155  }
   3.156  
   3.157 -void network_tx_buf_gc(void)
   3.158 +void network_tx_buf_gc(struct netfront_dev *dev)
   3.159  {
   3.160  
   3.161  
   3.162      RING_IDX cons, prod;
   3.163      unsigned short id;
   3.164 -    struct net_info *np = &net_info;
   3.165  
   3.166      do {
   3.167 -        prod = np->tx.sring->rsp_prod;
   3.168 +        prod = dev->tx.sring->rsp_prod;
   3.169          rmb(); /* Ensure we see responses up to 'rp'. */
   3.170  
   3.171 -        for (cons = np->tx.rsp_cons; cons != prod; cons++) 
   3.172 +        for (cons = dev->tx.rsp_cons; cons != prod; cons++) 
   3.173          {
   3.174              struct netif_tx_response *txrsp;
   3.175  
   3.176 -            txrsp = RING_GET_RESPONSE(&np->tx, cons);
   3.177 +            txrsp = RING_GET_RESPONSE(&dev->tx, cons);
   3.178              if (txrsp->status == NETIF_RSP_NULL)
   3.179                  continue;
   3.180  
   3.181              id  = txrsp->id;
   3.182 -            struct net_buffer* buf = &tx_buffers[id];
   3.183 +            struct net_buffer* buf = &dev->tx_buffers[id];
   3.184              gnttab_end_access(buf->gref);
   3.185              buf->gref=GRANT_INVALID_REF;
   3.186  
   3.187 -            add_id_to_freelist(id,tx_freelist);
   3.188 -            up(&tx_sem);
   3.189 +	    add_id_to_freelist(id,dev->tx_freelist);
   3.190 +	    up(&dev->tx_sem);
   3.191          }
   3.192  
   3.193 -        np->tx.rsp_cons = prod;
   3.194 +        dev->tx.rsp_cons = prod;
   3.195  
   3.196          /*
   3.197           * Set a new event, then check for race with update of tx_cons.
   3.198 @@ -190,10 +195,10 @@ void network_tx_buf_gc(void)
   3.199           * data is outstanding: in such cases notification from Xen is
   3.200           * likely to be the only kick that we'll get.
   3.201           */
   3.202 -        np->tx.sring->rsp_event =
   3.203 -            prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
   3.204 +        dev->tx.sring->rsp_event =
   3.205 +            prod + ((dev->tx.sring->req_prod - prod) >> 1) + 1;
   3.206          mb();
   3.207 -    } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
   3.208 +    } while ((cons == prod) && (prod != dev->tx.sring->rsp_prod));
   3.209  
   3.210  
   3.211  }
   3.212 @@ -201,24 +206,21 @@ void network_tx_buf_gc(void)
   3.213  void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
   3.214  {
   3.215      int flags;
   3.216 +    struct netfront_dev *dev = data;
   3.217  
   3.218      local_irq_save(flags);
   3.219  
   3.220 -    network_tx_buf_gc();
   3.221 -    network_rx();
   3.222 +    network_tx_buf_gc(dev);
   3.223 +    network_rx(dev);
   3.224  
   3.225      local_irq_restore(flags);
   3.226  }
   3.227  
   3.228 -char* backend;
   3.229 -
   3.230 -void init_netfront(void* si)
   3.231 +struct netfront_dev *init_netfront(char *nodename, void (*thenetif_rx)(unsigned char* data, int len), unsigned char rawmac[6])
   3.232  {
   3.233      xenbus_transaction_t xbt;
   3.234 -    struct net_info* info = &net_info;
   3.235      char* err;
   3.236      char* message=NULL;
   3.237 -    char nodename[] = "device/vif/0";
   3.238      struct netif_tx_sring *txs;
   3.239      struct netif_rx_sring *rxs;
   3.240      int retry=0;
   3.241 @@ -226,18 +228,34 @@ void init_netfront(void* si)
   3.242      char* mac;
   3.243      char* msg;
   3.244  
   3.245 -    printk("************************ NETFRONT **********\n\n\n");
   3.246 +    struct netfront_dev *dev;
   3.247  
   3.248 +    if (!nodename)
   3.249 +	nodename = "device/vif/0";
   3.250 +
   3.251 +    char path[strlen(nodename) + 1 + 10 + 1];
   3.252 +
   3.253 +    if (!thenetif_rx)
   3.254 +	thenetif_rx = netif_rx;
   3.255 +
   3.256 +    printk("************************ NETFRONT for %s **********\n\n\n", nodename);
   3.257 +
   3.258 +    dev = malloc(sizeof(*dev));
   3.259 +    dev->nodename = strdup(nodename);
   3.260 +
   3.261 +    printk("net TX ring size %d\n", NET_TX_RING_SIZE);
   3.262 +    printk("net RX ring size %d\n", NET_RX_RING_SIZE);
   3.263 +    init_SEMAPHORE(&dev->tx_sem, NET_TX_RING_SIZE);
   3.264      for(i=0;i<NET_TX_RING_SIZE;i++)
   3.265      {
   3.266 -        add_id_to_freelist(i,tx_freelist);
   3.267 -        tx_buffers[i].page = (char*)alloc_page();
   3.268 +	add_id_to_freelist(i,dev->tx_freelist);
   3.269 +        dev->tx_buffers[i].page = NULL;
   3.270      }
   3.271  
   3.272      for(i=0;i<NET_RX_RING_SIZE;i++)
   3.273      {
   3.274 -        add_id_to_freelist(i,rx_freelist);
   3.275 -        rx_buffers[i].page = (char*)alloc_page();
   3.276 +	/* TODO: that's a lot of memory */
   3.277 +        dev->rx_buffers[i].page = (char*)alloc_page();
   3.278      }
   3.279  
   3.280      txs = (struct netif_tx_sring*) alloc_page();
   3.281 @@ -248,20 +266,24 @@ void init_netfront(void* si)
   3.282  
   3.283      SHARED_RING_INIT(txs);
   3.284      SHARED_RING_INIT(rxs);
   3.285 -    FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
   3.286 -    FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
   3.287 +    FRONT_RING_INIT(&dev->tx, txs, PAGE_SIZE);
   3.288 +    FRONT_RING_INIT(&dev->rx, rxs, PAGE_SIZE);
   3.289  
   3.290 -    info->tx_ring_ref = gnttab_grant_access(0,virt_to_mfn(txs),0);
   3.291 -    info->rx_ring_ref = gnttab_grant_access(0,virt_to_mfn(rxs),0);
   3.292 +    dev->tx_ring_ref = gnttab_grant_access(0,virt_to_mfn(txs),0);
   3.293 +    dev->rx_ring_ref = gnttab_grant_access(0,virt_to_mfn(rxs),0);
   3.294  
   3.295      evtchn_alloc_unbound_t op;
   3.296      op.dom = DOMID_SELF;
   3.297 -    op.remote_dom = 0;
   3.298 +    snprintf(path, sizeof(path), "%s/backend-id", nodename);
   3.299 +    op.remote_dom = xenbus_read_integer(path);
   3.300      HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
   3.301      clear_evtchn(op.port);        /* Without, handler gets invoked now! */
   3.302 -    info->local_port = bind_evtchn(op.port, netfront_handler, NULL);
   3.303 -    info->evtchn=op.port;
   3.304 +    dev->local_port = bind_evtchn(op.port, netfront_handler, dev);
   3.305 +    dev->evtchn=op.port;
   3.306  
   3.307 +    dev->netif_rx = thenetif_rx;
   3.308 +
   3.309 +    // FIXME: proper frees on failures
   3.310  again:
   3.311      err = xenbus_transaction_start(&xbt);
   3.312      if (err) {
   3.313 @@ -269,19 +291,19 @@ again:
   3.314      }
   3.315  
   3.316      err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
   3.317 -                info->tx_ring_ref);
   3.318 +                dev->tx_ring_ref);
   3.319      if (err) {
   3.320          message = "writing tx ring-ref";
   3.321          goto abort_transaction;
   3.322      }
   3.323      err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
   3.324 -                info->rx_ring_ref);
   3.325 +                dev->rx_ring_ref);
   3.326      if (err) {
   3.327          message = "writing rx ring-ref";
   3.328          goto abort_transaction;
   3.329      }
   3.330      err = xenbus_printf(xbt, nodename,
   3.331 -                "event-channel", "%u", info->evtchn);
   3.332 +                "event-channel", "%u", dev->evtchn);
   3.333      if (err) {
   3.334          message = "writing event-channel";
   3.335          goto abort_transaction;
   3.336 @@ -308,40 +330,45 @@ again:
   3.337  
   3.338  abort_transaction:
   3.339      xenbus_transaction_end(xbt, 1, &retry);
   3.340 +    return NULL;
   3.341  
   3.342  done:
   3.343  
   3.344 -    msg = xenbus_read(XBT_NIL, "device/vif/0/backend", &backend);
   3.345 -    msg = xenbus_read(XBT_NIL, "device/vif/0/mac", &mac);
   3.346 +    snprintf(path, sizeof(path), "%s/backend", nodename);
   3.347 +    msg = xenbus_read(XBT_NIL, path, &dev->backend);
   3.348 +    snprintf(path, sizeof(path), "%s/mac", nodename);
   3.349 +    msg = xenbus_read(XBT_NIL, path, &mac);
   3.350  
   3.351 -    if ((backend == NULL) || (mac == NULL)) {
   3.352 -        struct evtchn_close op = { info->local_port };
   3.353 +    if ((dev->backend == NULL) || (mac == NULL)) {
   3.354 +        struct evtchn_close op = { dev->local_port };
   3.355          printk("%s: backend/mac failed\n", __func__);
   3.356 -        unbind_evtchn(info->local_port);
   3.357 +        unbind_evtchn(dev->local_port);
   3.358          HYPERVISOR_event_channel_op(EVTCHNOP_close, &op);
   3.359 -        return;
   3.360 +        return NULL;
   3.361      }
   3.362  
   3.363 -    printk("backend at %s\n",backend);
   3.364 +    printk("backend at %s\n",dev->backend);
   3.365      printk("mac is %s\n",mac);
   3.366  
   3.367 -    char path[256];
   3.368 -    sprintf(path,"%s/state",backend);
   3.369 +    {
   3.370 +        char path[strlen(dev->backend) + 1 + 5 + 1];
   3.371 +        snprintf(path, sizeof(path), "%s/state", dev->backend);
   3.372  
   3.373 -    xenbus_watch_path(XBT_NIL, path);
   3.374 +        xenbus_watch_path(XBT_NIL, path);
   3.375  
   3.376 -    xenbus_wait_for_value(path,"4");
   3.377 +        xenbus_wait_for_value(path,"4");
   3.378  
   3.379 -    //free(backend);
   3.380 +        xenbus_unwatch_path(XBT_NIL, path);
   3.381 +    }
   3.382  
   3.383      printk("**************************\n");
   3.384  
   3.385 -    init_rx_buffers();
   3.386 +    init_rx_buffers(dev);
   3.387  
   3.388 -    unsigned char rawmac[6];
   3.389          /* Special conversion specifier 'hh' needed for __ia64__. Without
   3.390             this mini-os panics with 'Unaligned reference'. */
   3.391 -    sscanf(mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
   3.392 +    if (rawmac)
   3.393 +	sscanf(mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
   3.394              &rawmac[0],
   3.395              &rawmac[1],
   3.396              &rawmac[2],
   3.397 @@ -349,37 +376,35 @@ done:
   3.398              &rawmac[4],
   3.399              &rawmac[5]);
   3.400  
   3.401 -    net_app_main(si,rawmac);
   3.402 +    return dev;
   3.403  }
   3.404  
   3.405 -void shutdown_netfront(void)
   3.406 +void shutdown_netfront(struct netfront_dev *dev)
   3.407  {
   3.408 -    //xenbus_transaction_t xbt;
   3.409      char* err;
   3.410 -    char nodename[] = "device/vif/0";
   3.411 +    char *nodename = dev->nodename;
   3.412  
   3.413 -    char path[256];
   3.414 +    char path[strlen(dev->backend) + 1 + 5 + 1];
   3.415  
   3.416 -    printk("close network: backend at %s\n",backend);
   3.417 +    printk("close network: backend at %s\n",dev->backend);
   3.418  
   3.419 -    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6); /* closing */
   3.420 -    sprintf(path,"%s/state",backend);
   3.421 +    snprintf(path, sizeof(path), "%s/state", dev->backend);
   3.422 +    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
   3.423 +    xenbus_wait_for_value(path,"5");
   3.424  
   3.425 +    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
   3.426      xenbus_wait_for_value(path,"6");
   3.427  
   3.428 -    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
   3.429 +    unbind_evtchn(dev->local_port);
   3.430  
   3.431 -    xenbus_wait_for_value(path,"2");
   3.432 -
   3.433 -    unbind_all_ports();
   3.434 -
   3.435 -    free(backend);
   3.436 +    free(nodename);
   3.437 +    free(dev->backend);
   3.438 +    free(dev);
   3.439  }
   3.440  
   3.441  
   3.442 -void init_rx_buffers(void)
   3.443 +void init_rx_buffers(struct netfront_dev *dev)
   3.444  {
   3.445 -    struct net_info* np = &net_info;
   3.446      int i, requeue_idx;
   3.447      netif_rx_request_t *req;
   3.448      int notify;
   3.449 @@ -387,8 +412,8 @@ void init_rx_buffers(void)
   3.450      /* Rebuild the RX buffer freelist and the RX ring itself. */
   3.451      for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) 
   3.452      {
   3.453 -        struct net_buffer* buf = &rx_buffers[requeue_idx];
   3.454 -        req = RING_GET_REQUEST(&np->rx, requeue_idx);
   3.455 +        struct net_buffer* buf = &dev->rx_buffers[requeue_idx];
   3.456 +        req = RING_GET_REQUEST(&dev->rx, requeue_idx);
   3.457  
   3.458          buf->gref = req->gref = 
   3.459              gnttab_grant_access(0,virt_to_mfn(buf->page),0);
   3.460 @@ -398,39 +423,40 @@ void init_rx_buffers(void)
   3.461          requeue_idx++;
   3.462      }
   3.463  
   3.464 -    np->rx.req_prod_pvt = requeue_idx;
   3.465 +    dev->rx.req_prod_pvt = requeue_idx;
   3.466  
   3.467 -    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
   3.468 +    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
   3.469  
   3.470      if (notify) 
   3.471 -        notify_remote_via_evtchn(np->evtchn);
   3.472 +        notify_remote_via_evtchn(dev->evtchn);
   3.473  
   3.474 -    np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
   3.475 +    dev->rx.sring->rsp_event = dev->rx.rsp_cons + 1;
   3.476  }
   3.477  
   3.478  
   3.479 -void netfront_xmit(unsigned char* data,int len)
   3.480 +void netfront_xmit(struct netfront_dev *dev, unsigned char* data,int len)
   3.481  {
   3.482      int flags;
   3.483 -    struct net_info* info = &net_info;
   3.484      struct netif_tx_request *tx;
   3.485      RING_IDX i;
   3.486      int notify;
   3.487 -    int id;
   3.488 +    unsigned short id;
   3.489      struct net_buffer* buf;
   3.490      void* page;
   3.491  
   3.492 -    down(&tx_sem);
   3.493 +    down(&dev->tx_sem);
   3.494  
   3.495      local_irq_save(flags);
   3.496 -    id = get_id_from_freelist(tx_freelist);
   3.497 +    id = get_id_from_freelist(dev->tx_freelist);
   3.498      local_irq_restore(flags);
   3.499  
   3.500 -    buf = &tx_buffers[id];
   3.501 +    buf = &dev->tx_buffers[id];
   3.502      page = buf->page;
   3.503 +    if (!page)
   3.504 +	page = buf->page = (char*) alloc_page();
   3.505  
   3.506 -    i = info->tx.req_prod_pvt;
   3.507 -    tx = RING_GET_REQUEST(&info->tx, i);
   3.508 +    i = dev->tx.req_prod_pvt;
   3.509 +    tx = RING_GET_REQUEST(&dev->tx, i);
   3.510  
   3.511      memcpy(page,data,len);
   3.512  
   3.513 @@ -441,15 +467,15 @@ void netfront_xmit(unsigned char* data,i
   3.514      tx->size = len;
   3.515      tx->flags=0;
   3.516      tx->id = id;
   3.517 -    info->tx.req_prod_pvt = i + 1;
   3.518 +    dev->tx.req_prod_pvt = i + 1;
   3.519  
   3.520      wmb();
   3.521  
   3.522 -    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->tx, notify);
   3.523 +    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->tx, notify);
   3.524  
   3.525 -    if(notify) notify_remote_via_evtchn(info->evtchn);
   3.526 +    if(notify) notify_remote_via_evtchn(dev->evtchn);
   3.527  
   3.528      local_irq_save(flags);
   3.529 -    network_tx_buf_gc();
   3.530 +    network_tx_buf_gc(dev);
   3.531      local_irq_restore(flags);
   3.532  }