source: trunk/packages/xen-common/xen-common/extras/mini-os/netfront.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 10.5 KB
Line 
1/* Minimal network driver for Mini-OS.
2 * Copyright (c) 2006-2007 Jacob Gorm Hansen, University of Copenhagen.
3 * Based on netfront.c from Xen Linux.
4 *
5 * Does not handle fragments or extras.
6 */
7
8#include <os.h>
9#include <xenbus.h>
10#include <events.h>
11#include <errno.h>
12#include <xen/io/netif.h>
13#include <gnttab.h>
14#include <xmalloc.h>
15#include <time.h>
16
17void init_rx_buffers(void);
18
19struct net_info {
20    struct netif_tx_front_ring tx;
21    struct netif_rx_front_ring rx;
22    int tx_ring_ref;
23    int rx_ring_ref;
24    unsigned int evtchn, local_port;
25
26} net_info;
27
28
29char* xenbus_printf(xenbus_transaction_t xbt,
30        char* node,char* path,
31        char* fmt,unsigned int arg)
32{
33    char fullpath[256];
34    char val[256];
35
36    sprintf(fullpath,"%s/%s",node,path);
37    sprintf(val,fmt,arg);
38    xenbus_write(xbt,fullpath,val);
39
40    return NULL;
41}
42
43
44#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
45#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
46#define GRANT_INVALID_REF 0
47
48
49unsigned short rx_freelist[NET_RX_RING_SIZE];
50unsigned short tx_freelist[NET_TX_RING_SIZE];
51
52struct net_buffer {
53    void* page;
54    int gref;
55};
56struct net_buffer rx_buffers[NET_RX_RING_SIZE];
57struct net_buffer tx_buffers[NET_TX_RING_SIZE];
58
59static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
60{
61    freelist[id] = freelist[0];
62    freelist[0]  = id;
63}
64
65static inline unsigned short get_id_from_freelist(unsigned short* freelist)
66{
67    unsigned int id = freelist[0];
68    freelist[0] = freelist[id];
69    return id;
70}
71
72__attribute__((weak)) void netif_rx(unsigned char* data,int len)
73{
74    printk("%d bytes incoming at %p\n",len,data);
75}
76
77__attribute__((weak)) void net_app_main(void*si,unsigned char*mac) {}
78
79static inline int xennet_rxidx(RING_IDX idx)
80{
81    return idx & (NET_RX_RING_SIZE - 1);
82}
83
84void network_rx(void)
85{
86    struct net_info *np = &net_info;
87    RING_IDX rp,cons;
88    struct netif_rx_response *rx;
89
90
91moretodo:
92    rp = np->rx.sring->rsp_prod;
93    rmb(); /* Ensure we see queued responses up to 'rp'. */
94    cons = np->rx.rsp_cons;
95
96    int nr_consumed=0;
97    while ((cons != rp))
98    {
99        struct net_buffer* buf;
100        unsigned char* page;
101
102        rx = RING_GET_RESPONSE(&np->rx, cons);
103
104        if (rx->flags & NETRXF_extra_info)
105        {
106            printk("+++++++++++++++++++++ we have extras!\n");
107            continue;
108        }
109
110
111        if (rx->status == NETIF_RSP_NULL) continue;
112
113        int id = rx->id;
114
115        buf = &rx_buffers[id];
116        page = (unsigned char*)buf->page;
117        gnttab_end_access(buf->gref);
118
119        if(rx->status>0)
120        {
121            netif_rx(page+rx->offset,rx->status);
122        }
123
124        add_id_to_freelist(id,rx_freelist);
125
126        nr_consumed++;
127
128        ++cons;
129    }
130    np->rx.rsp_cons=rp;
131
132    int more;
133    RING_FINAL_CHECK_FOR_RESPONSES(&np->rx,more);
134    if(more) goto moretodo;
135
136    RING_IDX req_prod = np->rx.req_prod_pvt;
137
138    int i;
139    netif_rx_request_t *req;
140
141    for(i=0; i<nr_consumed; i++)
142    {
143        int id = xennet_rxidx(req_prod + i);
144        req = RING_GET_REQUEST(&np->rx, req_prod + i);
145        struct net_buffer* buf = &rx_buffers[id];
146        void* page = buf->page;
147
148        buf->gref = req->gref = 
149            gnttab_grant_access(0,virt_to_mfn(page),0);
150
151        req->id = id;
152    }
153
154    wmb();
155
156    np->rx.req_prod_pvt = req_prod + i;
157   
158    int notify;
159    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
160    if (notify)
161        notify_remote_via_evtchn(np->evtchn);
162
163}
164
165void network_tx_buf_gc(void)
166{
167
168
169    RING_IDX cons, prod;
170    unsigned short id;
171    struct net_info *np = &net_info;
172
173    do {
174        prod = np->tx.sring->rsp_prod;
175        rmb(); /* Ensure we see responses up to 'rp'. */
176
177        for (cons = np->tx.rsp_cons; cons != prod; cons++) 
178        {
179            struct netif_tx_response *txrsp;
180
181            txrsp = RING_GET_RESPONSE(&np->tx, cons);
182            if (txrsp->status == NETIF_RSP_NULL)
183                continue;
184
185            id  = txrsp->id;
186            struct net_buffer* buf = &tx_buffers[id];
187            gnttab_end_access(buf->gref);
188            buf->gref=GRANT_INVALID_REF;
189
190            add_id_to_freelist(id,tx_freelist);
191        }
192
193        np->tx.rsp_cons = prod;
194
195        /*
196         * Set a new event, then check for race with update of tx_cons.
197         * Note that it is essential to schedule a callback, no matter
198         * how few tx_buffers are pending. Even if there is space in the
199         * transmit ring, higher layers may be blocked because too much
200         * data is outstanding: in such cases notification from Xen is
201         * likely to be the only kick that we'll get.
202         */
203        np->tx.sring->rsp_event =
204            prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
205        mb();
206    } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
207
208
209}
210
211void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
212{
213    int flags;
214
215    local_irq_save(flags);
216
217    network_tx_buf_gc();
218    network_rx();
219
220    local_irq_restore(flags);
221}
222
223char* backend;
224
225void init_netfront(void* si)
226{
227    xenbus_transaction_t xbt;
228    struct net_info* info = &net_info;
229    char* err;
230    char* message=NULL;
231    char nodename[] = "device/vif/0";
232    struct netif_tx_sring *txs;
233    struct netif_rx_sring *rxs;
234    int retry=0;
235    int i;
236    char* mac;
237    char* msg;
238
239    printk("************************ NETFRONT **********\n\n\n");
240
241    for(i=0;i<NET_TX_RING_SIZE;i++)
242    {
243        add_id_to_freelist(i,tx_freelist);
244        tx_buffers[i].page = (char*)alloc_page();
245    }
246
247    for(i=0;i<NET_RX_RING_SIZE;i++)
248    {
249        add_id_to_freelist(i,rx_freelist);
250        rx_buffers[i].page = (char*)alloc_page();
251    }
252
253    txs = (struct netif_tx_sring*) alloc_page();
254    rxs = (struct netif_rx_sring *) alloc_page();
255    memset(txs,0,PAGE_SIZE);
256    memset(rxs,0,PAGE_SIZE);
257
258
259    SHARED_RING_INIT(txs);
260    SHARED_RING_INIT(rxs);
261    FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
262    FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
263
264    info->tx_ring_ref = gnttab_grant_access(0,virt_to_mfn(txs),0);
265    info->rx_ring_ref = gnttab_grant_access(0,virt_to_mfn(rxs),0);
266
267    evtchn_alloc_unbound_t op;
268    op.dom = DOMID_SELF;
269    op.remote_dom = 0;
270    HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
271    clear_evtchn(op.port);        /* Without, handler gets invoked now! */
272    info->local_port = bind_evtchn(op.port, netfront_handler, NULL);
273    info->evtchn=op.port;
274
275again:
276    err = xenbus_transaction_start(&xbt);
277    if (err) {
278        printk("starting transaction\n");
279    }
280
281    err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
282                info->tx_ring_ref);
283    if (err) {
284        message = "writing tx ring-ref";
285        goto abort_transaction;
286    }
287    err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
288                info->rx_ring_ref);
289    if (err) {
290        message = "writing rx ring-ref";
291        goto abort_transaction;
292    }
293    err = xenbus_printf(xbt, nodename,
294                "event-channel", "%u", info->evtchn);
295    if (err) {
296        message = "writing event-channel";
297        goto abort_transaction;
298    }
299
300    err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1);
301
302    if (err) {
303        message = "writing request-rx-copy";
304        goto abort_transaction;
305    }
306
307    err = xenbus_printf(xbt, nodename, "state", "%u",
308            4); /* connected */
309
310
311    err = xenbus_transaction_end(xbt, 0, &retry);
312    if (retry) {
313            goto again;
314        printk("completing transaction\n");
315    }
316
317    goto done;
318
319abort_transaction:
320    xenbus_transaction_end(xbt, 1, &retry);
321
322done:
323
324    msg = xenbus_read(XBT_NIL, "device/vif/0/backend", &backend);
325    msg = xenbus_read(XBT_NIL, "device/vif/0/mac", &mac);
326
327    if ((backend == NULL) || (mac == NULL)) {
328        struct evtchn_close op = { info->local_port };
329        printk("%s: backend/mac failed\n", __func__);
330        unbind_evtchn(info->local_port);
331        HYPERVISOR_event_channel_op(EVTCHNOP_close, &op);
332        return;
333    }
334
335    printk("backend at %s\n",backend);
336    printk("mac is %s\n",mac);
337
338    char path[256];
339    sprintf(path,"%s/state",backend);
340
341    xenbus_watch_path(XBT_NIL, path);
342
343    xenbus_wait_for_value(path,"4");
344
345    //free(backend);
346
347    printk("**************************\n");
348
349    init_rx_buffers();
350
351    unsigned char rawmac[6];
352        /* Special conversion specifier 'hh' needed for __ia64__. Without
353           this mini-os panics with 'Unaligned reference'. */
354    sscanf(mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
355            &rawmac[0],
356            &rawmac[1],
357            &rawmac[2],
358            &rawmac[3],
359            &rawmac[4],
360            &rawmac[5]);
361
362    net_app_main(si,rawmac);
363}
364
365void shutdown_netfront(void)
366{
367    //xenbus_transaction_t xbt;
368    char* err;
369    char nodename[] = "device/vif/0";
370
371    char path[256];
372
373    printk("close network: backend at %s\n",backend);
374
375    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6); /* closing */
376    sprintf(path,"%s/state",backend);
377
378    xenbus_wait_for_value(path,"6");
379
380    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
381
382    xenbus_wait_for_value(path,"2");
383
384    unbind_all_ports();
385
386}
387
388
389void init_rx_buffers(void)
390{
391    struct net_info* np = &net_info;
392    int i, requeue_idx;
393    netif_rx_request_t *req;
394    int notify;
395
396    /* Rebuild the RX buffer freelist and the RX ring itself. */
397    for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) 
398    {
399        struct net_buffer* buf = &rx_buffers[requeue_idx];
400        req = RING_GET_REQUEST(&np->rx, requeue_idx);
401
402        buf->gref = req->gref = 
403            gnttab_grant_access(0,virt_to_mfn(buf->page),0);
404
405        req->id = requeue_idx;
406
407        requeue_idx++;
408    }
409
410    np->rx.req_prod_pvt = requeue_idx;
411
412    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
413
414    if (notify) 
415        notify_remote_via_evtchn(np->evtchn);
416
417    np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
418}
419
420
421void netfront_xmit(unsigned char* data,int len)
422{
423    int flags;
424    local_irq_save(flags);
425
426    struct net_info* info = &net_info;
427    struct netif_tx_request *tx;
428    RING_IDX i = info->tx.req_prod_pvt;
429    int notify;
430    int id = get_id_from_freelist(tx_freelist);
431    struct net_buffer* buf = &tx_buffers[id];
432    void* page = buf->page;
433
434    tx = RING_GET_REQUEST(&info->tx, i);
435
436    memcpy(page,data,len);
437
438    buf->gref = 
439        tx->gref = gnttab_grant_access(0,virt_to_mfn(page),0);
440
441    tx->offset=0;
442    tx->size = len;
443    tx->flags=0;
444    tx->id = id;
445    info->tx.req_prod_pvt = i + 1;
446
447    wmb();
448
449    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->tx, notify);
450
451    if(notify) notify_remote_via_evtchn(info->evtchn);
452
453    network_tx_buf_gc();
454
455    local_irq_restore(flags);
456}
Note: See TracBrowser for help on using the repository browser.