ia64/xen-unstable

changeset 13415:65a835dee3bc

[MINIOS] Implement a network frontend driver.
Signed-off-by: Jacob Gorm Hansen <jacobg@diku.dk>
author kfraser@localhost.localdomain
date Fri Jan 12 15:18:24 2007 +0000 (2007-01-12)
parents 2406531dae95
children c71fe03f086f
files extras/mini-os/include/netfront.h extras/mini-os/kernel.c extras/mini-os/netfront.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/extras/mini-os/include/netfront.h	Fri Jan 12 15:18:24 2007 +0000
     1.3 @@ -0,0 +1,2 @@
     1.4 +void init_netfront(void*);
     1.5 +void netfront_xmit(unsigned char* data,int len);
     2.1 --- a/extras/mini-os/kernel.c	Fri Jan 12 15:16:05 2007 +0000
     2.2 +++ b/extras/mini-os/kernel.c	Fri Jan 12 15:18:24 2007 +0000
     2.3 @@ -37,6 +37,7 @@
     2.4  #include <sched.h>
     2.5  #include <xenbus.h>
     2.6  #include <gnttab.h>
     2.7 +#include <netfront.h>
     2.8  #include <xen/features.h>
     2.9  #include <xen/version.h>
    2.10  
    2.11 @@ -61,13 +62,13 @@ void setup_xen_features(void)
    2.12  
    2.13  void test_xenbus(void);
    2.14  
    2.15 -void xenbus_tester(void *p)
    2.16 +static void xenbus_tester(void *p)
    2.17  {
    2.18      printk("Xenbus tests disabled, because of a Xend bug.\n");
    2.19      /* test_xenbus(); */
    2.20  }
    2.21  
    2.22 -void periodic_thread(void *p)
    2.23 +static void periodic_thread(void *p)
    2.24  {
    2.25      struct timeval tv;
    2.26      printk("Periodic thread started.\n");
    2.27 @@ -79,12 +80,18 @@ void periodic_thread(void *p)
    2.28      }
    2.29  }
    2.30  
    2.31 +static void netfront_thread(void *p)
    2.32 +{
    2.33 +    init_netfront(&start_info);
    2.34 +}
    2.35 +
    2.36  /* This should be overridden by the application we are linked against. */
    2.37  __attribute__((weak)) int app_main(start_info_t *si)
    2.38  {
    2.39      printk("Dummy main: start_info=%p\n", si);
    2.40      create_thread("xenbus_tester", xenbus_tester, si);
    2.41      create_thread("periodic_thread", periodic_thread, si);
    2.42 +    create_thread("netfront", netfront_thread, si);
    2.43      return 0;
    2.44  }
    2.45  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/extras/mini-os/netfront.c	Fri Jan 12 15:18:24 2007 +0000
     3.3 @@ -0,0 +1,455 @@
     3.4 +/* Minimal network driver for Mini-OS. 
     3.5 + * Copyright (c) 2006-2007 Jacob Gorm Hansen, University of Copenhagen.
     3.6 + * Based on netfront.c from Xen Linux.
     3.7 + *
     3.8 + * Does not handle fragments or extras.
     3.9 + */
    3.10 +
    3.11 +#include <os.h>
    3.12 +#include <xenbus.h>
    3.13 +#include <events.h>
    3.14 +#include <errno.h>
    3.15 +#include <xen/io/netif.h>
    3.16 +#include <gnttab.h>
    3.17 +#include <xmalloc.h>
    3.18 +#include <time.h>
    3.19 +
    3.20 +void init_rx_buffers(void);
    3.21 +
    3.22 +struct net_info {
    3.23 +    struct netif_tx_front_ring tx;
    3.24 +    struct netif_rx_front_ring rx;
    3.25 +    int tx_ring_ref;
    3.26 +    int rx_ring_ref;
    3.27 +    unsigned int evtchn, local_port;
    3.28 +
    3.29 +} net_info;
    3.30 +
    3.31 +
    3.32 +char* xenbus_printf(xenbus_transaction_t xbt,
    3.33 +        char* node,char* path,
    3.34 +        char* fmt,unsigned int arg)
    3.35 +{
    3.36 +    char fullpath[256];
    3.37 +    char val[256];
    3.38 +
    3.39 +    sprintf(fullpath,"%s/%s",node,path);
    3.40 +    sprintf(val,fmt,arg);
    3.41 +    xenbus_write(xbt,fullpath,val);
    3.42 +
    3.43 +    return NULL;
    3.44 +}
    3.45 +
    3.46 +
    3.47 +#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
    3.48 +#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
    3.49 +#define GRANT_INVALID_REF 0
    3.50 +
    3.51 +
    3.52 +unsigned short rx_freelist[NET_RX_RING_SIZE];
    3.53 +unsigned short tx_freelist[NET_TX_RING_SIZE];
    3.54 +
    3.55 +struct net_buffer {
    3.56 +    void* page;
    3.57 +    int gref;
    3.58 +};
    3.59 +struct net_buffer rx_buffers[NET_RX_RING_SIZE];
    3.60 +struct net_buffer tx_buffers[NET_TX_RING_SIZE];
    3.61 +
    3.62 +static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
    3.63 +{
    3.64 +    freelist[id] = freelist[0];
    3.65 +    freelist[0]  = id;
    3.66 +}
    3.67 +
    3.68 +static inline unsigned short get_id_from_freelist(unsigned short* freelist)
    3.69 +{
    3.70 +    unsigned int id = freelist[0];
    3.71 +    freelist[0] = freelist[id];
    3.72 +    return id;
    3.73 +}
    3.74 +
    3.75 +__attribute__((weak)) void netif_rx(unsigned char* data,int len)
    3.76 +{
    3.77 +    printk("%d bytes incoming at %p\n",len,data);
    3.78 +}
    3.79 +
    3.80 +__attribute__((weak)) void net_app_main(void*si,unsigned char*mac) {}
    3.81 +
    3.82 +static inline int xennet_rxidx(RING_IDX idx)
    3.83 +{
    3.84 +    return idx & (NET_RX_RING_SIZE - 1);
    3.85 +}
    3.86 +
    3.87 +void network_rx(void)
    3.88 +{
    3.89 +    struct net_info *np = &net_info;
    3.90 +    RING_IDX rp,cons;
    3.91 +    struct netif_rx_response *rx;
    3.92 +
    3.93 +
    3.94 +moretodo:
    3.95 +    rp = np->rx.sring->rsp_prod;
    3.96 +    rmb(); /* Ensure we see queued responses up to 'rp'. */
    3.97 +    cons = np->rx.rsp_cons;
    3.98 +
    3.99 +    int nr_consumed=0;
   3.100 +    while ((cons != rp))
   3.101 +    {
   3.102 +        struct net_buffer* buf;
   3.103 +        unsigned char* page;
   3.104 +
   3.105 +        rx = RING_GET_RESPONSE(&np->rx, cons);
   3.106 +
   3.107 +        if (rx->flags & NETRXF_extra_info)
   3.108 +        {
   3.109 +            printk("+++++++++++++++++++++ we have extras!\n");
   3.110 +            continue;
   3.111 +        }
   3.112 +
   3.113 +
   3.114 +        if (rx->status == NETIF_RSP_NULL) continue;
   3.115 +
   3.116 +        int id = rx->id;
   3.117 +
   3.118 +        buf = &rx_buffers[id];
   3.119 +        page = (unsigned char*)buf->page;
   3.120 +        gnttab_end_access(buf->gref);
   3.121 +
   3.122 +        if(rx->status>0)
   3.123 +        {
   3.124 +            netif_rx(page+rx->offset,rx->status);
   3.125 +        }
   3.126 +
   3.127 +        add_id_to_freelist(id,rx_freelist);
   3.128 +
   3.129 +        nr_consumed++;
   3.130 +
   3.131 +        ++cons;
   3.132 +    }
   3.133 +    np->rx.rsp_cons=rp;
   3.134 +
   3.135 +    int more;
   3.136 +    RING_FINAL_CHECK_FOR_RESPONSES(&np->rx,more);
   3.137 +    if(more) goto moretodo;
   3.138 +
   3.139 +    RING_IDX req_prod = np->rx.req_prod_pvt;
   3.140 +
   3.141 +    int i;
   3.142 +    netif_rx_request_t *req;
   3.143 +
   3.144 +    for(i=0; i<nr_consumed; i++)
   3.145 +    {
   3.146 +        int id = xennet_rxidx(req_prod + i);
   3.147 +        req = RING_GET_REQUEST(&np->rx, req_prod + i);
   3.148 +        struct net_buffer* buf = &rx_buffers[id];
   3.149 +        void* page = buf->page;
   3.150 +
   3.151 +        buf->gref = req->gref = 
   3.152 +            gnttab_grant_access(0,virt_to_mfn(page),0);
   3.153 +
   3.154 +        req->id = id;
   3.155 +    }
   3.156 +
   3.157 +    wmb();
   3.158 +
   3.159 +    np->rx.req_prod_pvt = req_prod + i;
   3.160 +    
   3.161 +    int notify;
   3.162 +    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
   3.163 +    if (notify)
   3.164 +        notify_remote_via_evtchn(np->evtchn);
   3.165 +
   3.166 +}
   3.167 +
   3.168 +void network_tx_buf_gc(void)
   3.169 +{
   3.170 +
   3.171 +
   3.172 +    RING_IDX cons, prod;
   3.173 +    unsigned short id;
   3.174 +    struct net_info *np = &net_info;
   3.175 +
   3.176 +    do {
   3.177 +        prod = np->tx.sring->rsp_prod;
   3.178 +        rmb(); /* Ensure we see responses up to 'rp'. */
   3.179 +
   3.180 +        for (cons = np->tx.rsp_cons; cons != prod; cons++) 
   3.181 +        {
   3.182 +            struct netif_tx_response *txrsp;
   3.183 +
   3.184 +            txrsp = RING_GET_RESPONSE(&np->tx, cons);
   3.185 +            if (txrsp->status == NETIF_RSP_NULL)
   3.186 +                continue;
   3.187 +
   3.188 +            id  = txrsp->id;
   3.189 +            struct net_buffer* buf = &tx_buffers[id];
   3.190 +            gnttab_end_access(buf->gref);
   3.191 +            buf->gref=GRANT_INVALID_REF;
   3.192 +
   3.193 +            add_id_to_freelist(id,tx_freelist);
   3.194 +        }
   3.195 +
   3.196 +        np->tx.rsp_cons = prod;
   3.197 +
   3.198 +        /*
   3.199 +         * Set a new event, then check for race with update of tx_cons.
   3.200 +         * Note that it is essential to schedule a callback, no matter
   3.201 +         * how few tx_buffers are pending. Even if there is space in the
   3.202 +         * transmit ring, higher layers may be blocked because too much
   3.203 +         * data is outstanding: in such cases notification from Xen is
   3.204 +         * likely to be the only kick that we'll get.
   3.205 +         */
   3.206 +        np->tx.sring->rsp_event =
   3.207 +            prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
   3.208 +        mb();
   3.209 +    } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
   3.210 +
   3.211 +
   3.212 +}
   3.213 +
   3.214 +void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
   3.215 +{
   3.216 +    int flags;
   3.217 +
   3.218 +    local_irq_save(flags);
   3.219 +
   3.220 +    network_tx_buf_gc();
   3.221 +    network_rx();
   3.222 +
   3.223 +    local_irq_restore(flags);
   3.224 +}
   3.225 +
   3.226 +char* backend;
   3.227 +
   3.228 +void init_netfront(void* si)
   3.229 +{
   3.230 +    xenbus_transaction_t xbt;
   3.231 +    struct net_info* info = &net_info;
   3.232 +    char* err;
   3.233 +    char* message=NULL;
   3.234 +    char nodename[] = "device/vif/0";
   3.235 +    struct netif_tx_sring *txs;
   3.236 +    struct netif_rx_sring *rxs;
   3.237 +    int retry=0;
   3.238 +    int i;
   3.239 +    char* mac;
   3.240 +    char* msg;
   3.241 +
   3.242 +    printk("************************ NETFRONT **********\n\n\n");
   3.243 +
   3.244 +    for(i=0;i<NET_TX_RING_SIZE;i++)
   3.245 +    {
   3.246 +        add_id_to_freelist(i,tx_freelist);
   3.247 +        tx_buffers[i].page = (char*)alloc_page();
   3.248 +    }
   3.249 +
   3.250 +    for(i=0;i<NET_RX_RING_SIZE;i++)
   3.251 +    {
   3.252 +        add_id_to_freelist(i,rx_freelist);
   3.253 +        rx_buffers[i].page = (char*)alloc_page();
   3.254 +    }
   3.255 +
   3.256 +    txs = (struct netif_tx_sring*) alloc_page();
   3.257 +    rxs = (struct netif_rx_sring *) alloc_page();
   3.258 +    memset(txs,0,PAGE_SIZE);
   3.259 +    memset(rxs,0,PAGE_SIZE);
   3.260 +
   3.261 +
   3.262 +    SHARED_RING_INIT(txs);
   3.263 +    SHARED_RING_INIT(rxs);
   3.264 +    FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
   3.265 +    FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
   3.266 +
   3.267 +    info->tx_ring_ref = gnttab_grant_access(0,virt_to_mfn(txs),0);
   3.268 +    info->rx_ring_ref = gnttab_grant_access(0,virt_to_mfn(rxs),0);
   3.269 +
   3.270 +    evtchn_alloc_unbound_t op;
   3.271 +    op.dom = DOMID_SELF;
   3.272 +    op.remote_dom = 0;
   3.273 +    HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
   3.274 +    clear_evtchn(op.port);        /* Without, handler gets invoked now! */
   3.275 +    info->local_port = bind_evtchn(op.port, netfront_handler, NULL);
   3.276 +    info->evtchn=op.port;
   3.277 +
   3.278 +again:
   3.279 +    err = xenbus_transaction_start(&xbt);
   3.280 +    if (err) {
   3.281 +        printk("starting transaction\n");
   3.282 +    }
   3.283 +
   3.284 +    err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
   3.285 +                info->tx_ring_ref);
   3.286 +    if (err) {
   3.287 +        message = "writing tx ring-ref";
   3.288 +        goto abort_transaction;
   3.289 +    }
   3.290 +    err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
   3.291 +                info->rx_ring_ref);
   3.292 +    if (err) {
   3.293 +        message = "writing rx ring-ref";
   3.294 +        goto abort_transaction;
   3.295 +    }
   3.296 +    err = xenbus_printf(xbt, nodename,
   3.297 +                "event-channel", "%u", info->evtchn);
   3.298 +    if (err) {
   3.299 +        message = "writing event-channel";
   3.300 +        goto abort_transaction;
   3.301 +    }
   3.302 +
   3.303 +    err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1);
   3.304 +
   3.305 +    if (err) {
   3.306 +        message = "writing request-rx-copy";
   3.307 +        goto abort_transaction;
   3.308 +    }
   3.309 +
   3.310 +    err = xenbus_printf(xbt, nodename, "state", "%u",
   3.311 +            4); /* connected */
   3.312 +
   3.313 +
   3.314 +    err = xenbus_transaction_end(xbt, 0, &retry);
   3.315 +    if (retry) {
   3.316 +            goto again;
   3.317 +        printk("completing transaction\n");
   3.318 +    }
   3.319 +
   3.320 +    goto done;
   3.321 +
   3.322 +abort_transaction:
   3.323 +    xenbus_transaction_end(xbt, 1, &retry);
   3.324 +
   3.325 +done:
   3.326 +
   3.327 +    msg = xenbus_read(XBT_NIL, "device/vif/0/backend", &backend);
   3.328 +    msg = xenbus_read(XBT_NIL, "device/vif/0/mac", &mac);
   3.329 +
   3.330 +    printk("backend at %s\n",backend);
   3.331 +    printk("mac is %s\n",mac);
   3.332 +
   3.333 +    char *res;
   3.334 +    char path[256];
   3.335 +    sprintf(path,"%s/state",backend);
   3.336 +
   3.337 +    xenbus_watch_path(XBT_NIL, path);
   3.338 +
   3.339 +    xenbus_wait_for_value(path,"4");
   3.340 +
   3.341 +    //free(backend);
   3.342 +    free(res);
   3.343 +
   3.344 +    printk("**************************\n");
   3.345 +
   3.346 +    init_rx_buffers();
   3.347 +
   3.348 +    unsigned char rawmac[6];
   3.349 +    sscanf(mac,"%x:%x:%x:%x:%x:%x",
   3.350 +            &rawmac[0],
   3.351 +            &rawmac[1],
   3.352 +            &rawmac[2],
   3.353 +            &rawmac[3],
   3.354 +            &rawmac[4],
   3.355 +            &rawmac[5]);
   3.356 +
   3.357 +    net_app_main(si,rawmac);
   3.358 +}
   3.359 +
   3.360 +void shutdown_netfront(void)
   3.361 +{
   3.362 +    //xenbus_transaction_t xbt;
   3.363 +    char* err;
   3.364 +    char nodename[] = "device/vif/0";
   3.365 +
   3.366 +    char path[256];
   3.367 +
   3.368 +    printk("close network: backend at %s\n",backend);
   3.369 +
   3.370 +    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6); /* closing */
   3.371 +    sprintf(path,"%s/state",backend);
   3.372 +
   3.373 +    xenbus_wait_for_value(path,"6");
   3.374 +
   3.375 +    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
   3.376 +
   3.377 +    xenbus_wait_for_value(path,"2");
   3.378 +
   3.379 +    unbind_all_ports();
   3.380 +
   3.381 +}
   3.382 +
   3.383 +
   3.384 +void init_rx_buffers(void)
   3.385 +{
   3.386 +    struct net_info* np = &net_info;
   3.387 +    int i, requeue_idx;
   3.388 +    netif_rx_request_t *req;
   3.389 +    int notify;
   3.390 +
   3.391 +    np->rx.req_prod_pvt = requeue_idx;
   3.392 +
   3.393 +
   3.394 +    /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
   3.395 +    for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) 
   3.396 +    {
   3.397 +        struct net_buffer* buf = &rx_buffers[requeue_idx];
   3.398 +        req = RING_GET_REQUEST(&np->rx, requeue_idx);
   3.399 +
   3.400 +        buf->gref = req->gref = 
   3.401 +            gnttab_grant_access(0,virt_to_mfn(buf->page),0);
   3.402 +
   3.403 +        req->id = requeue_idx;
   3.404 +
   3.405 +        requeue_idx++;
   3.406 +    }
   3.407 +
   3.408 +    np->rx.req_prod_pvt = requeue_idx;
   3.409 +
   3.410 +
   3.411 +
   3.412 +    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
   3.413 +
   3.414 +    if(notify) 
   3.415 +        notify_remote_via_evtchn(np->evtchn);
   3.416 +
   3.417 +    np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
   3.418 +
   3.419 +
   3.420 +}
   3.421 +
   3.422 +
   3.423 +void netfront_xmit(unsigned char* data,int len)
   3.424 +{
   3.425 +    int flags;
   3.426 +    local_irq_save(flags);
   3.427 +
   3.428 +    struct net_info* info = &net_info;
   3.429 +    struct netif_tx_request *tx;
   3.430 +    RING_IDX i = info->tx.req_prod_pvt;
   3.431 +    int notify;
   3.432 +    int id = get_id_from_freelist(tx_freelist);
   3.433 +    struct net_buffer* buf = &tx_buffers[id];
   3.434 +    void* page = buf->page;
   3.435 +
   3.436 +    tx = RING_GET_REQUEST(&info->tx, i);
   3.437 +
   3.438 +    memcpy(page,data,len);
   3.439 +
   3.440 +    buf->gref = 
   3.441 +        tx->gref = gnttab_grant_access(0,virt_to_mfn(page),0);
   3.442 +
   3.443 +    tx->offset=0;
   3.444 +    tx->size = len;
   3.445 +    tx->flags=0;
   3.446 +    tx->id = id;
   3.447 +    info->tx.req_prod_pvt = i + 1;
   3.448 +
   3.449 +    wmb();
   3.450 +
   3.451 +    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->tx, notify);
   3.452 +
   3.453 +    if(notify) notify_remote_via_evtchn(info->evtchn);
   3.454 +
   3.455 +    network_tx_buf_gc();
   3.456 +
   3.457 +    local_irq_restore(flags);
   3.458 +}