ia64/xen-unstable

view extras/mini-os/netfront.c @ 18811:390ef36eb596

Remove Xen-private definitions from kexec public header.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 19 13:13:39 2008 +0000 (2008-11-19)
parents 433d1b26fd51
children 855e2f5ddb67
line source
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 */
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 #include <netfront.h>
17 #include <lib.h>
18 #include <semaphore.h>
20 DECLARE_WAIT_QUEUE_HEAD(netfront_queue);
22 #ifdef HAVE_LIBC
23 #define NETIF_SELECT_RX ((void*)-1)
24 #endif
28 #define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
29 #define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
30 #define GRANT_INVALID_REF 0
33 struct net_buffer {
34 void* page;
35 grant_ref_t gref;
36 };
38 struct netfront_dev {
39 domid_t dom;
41 unsigned short tx_freelist[NET_TX_RING_SIZE + 1];
42 struct semaphore tx_sem;
44 struct net_buffer rx_buffers[NET_RX_RING_SIZE];
45 struct net_buffer tx_buffers[NET_TX_RING_SIZE];
47 struct netif_tx_front_ring tx;
48 struct netif_rx_front_ring rx;
49 grant_ref_t tx_ring_ref;
50 grant_ref_t rx_ring_ref;
51 evtchn_port_t evtchn;
53 char *nodename;
54 char *backend;
55 char *mac;
57 xenbus_event_queue events;
59 #ifdef HAVE_LIBC
60 int fd;
61 unsigned char *data;
62 size_t len;
63 size_t rlen;
64 #endif
66 void (*netif_rx)(unsigned char* data, int len);
67 };
69 void init_rx_buffers(struct netfront_dev *dev);
71 static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
72 {
73 freelist[id + 1] = freelist[0];
74 freelist[0] = id;
75 }
77 static inline unsigned short get_id_from_freelist(unsigned short* freelist)
78 {
79 unsigned int id = freelist[0];
80 freelist[0] = freelist[id + 1];
81 return id;
82 }
84 __attribute__((weak)) void netif_rx(unsigned char* data,int len)
85 {
86 printk("%d bytes incoming at %p\n",len,data);
87 }
89 __attribute__((weak)) void net_app_main(void*si,unsigned char*mac) {}
91 static inline int xennet_rxidx(RING_IDX idx)
92 {
93 return idx & (NET_RX_RING_SIZE - 1);
94 }
96 void network_rx(struct netfront_dev *dev)
97 {
98 RING_IDX rp,cons,req_prod;
99 struct netif_rx_response *rx;
100 int nr_consumed, some, more, i, notify;
103 moretodo:
104 rp = dev->rx.sring->rsp_prod;
105 rmb(); /* Ensure we see queued responses up to 'rp'. */
106 cons = dev->rx.rsp_cons;
108 nr_consumed = 0;
109 some = 0;
110 while ((cons != rp) && !some)
111 {
112 struct net_buffer* buf;
113 unsigned char* page;
114 int id;
116 rx = RING_GET_RESPONSE(&dev->rx, cons);
118 if (rx->flags & NETRXF_extra_info)
119 {
120 printk("+++++++++++++++++++++ we have extras!\n");
121 continue;
122 }
125 if (rx->status == NETIF_RSP_NULL) continue;
127 id = rx->id;
128 BUG_ON(id >= NET_TX_RING_SIZE);
130 buf = &dev->rx_buffers[id];
131 page = (unsigned char*)buf->page;
132 gnttab_end_access(buf->gref);
134 if(rx->status>0)
135 {
136 #ifdef HAVE_LIBC
137 if (dev->netif_rx == NETIF_SELECT_RX) {
138 int len = rx->status;
139 ASSERT(current == main_thread);
140 if (len > dev->len)
141 len = dev->len;
142 memcpy(dev->data, page+rx->offset, len);
143 dev->rlen = len;
144 some = 1;
145 } else
146 #endif
147 dev->netif_rx(page+rx->offset,rx->status);
148 }
150 nr_consumed++;
152 ++cons;
153 }
154 dev->rx.rsp_cons=cons;
156 RING_FINAL_CHECK_FOR_RESPONSES(&dev->rx,more);
157 if(more && !some) goto moretodo;
159 req_prod = dev->rx.req_prod_pvt;
161 for(i=0; i<nr_consumed; i++)
162 {
163 int id = xennet_rxidx(req_prod + i);
164 netif_rx_request_t *req = RING_GET_REQUEST(&dev->rx, req_prod + i);
165 struct net_buffer* buf = &dev->rx_buffers[id];
166 void* page = buf->page;
168 /* We are sure to have free gnttab entries since they got released above */
169 buf->gref = req->gref =
170 gnttab_grant_access(dev->dom,virt_to_mfn(page),0);
172 req->id = id;
173 }
175 wmb();
177 dev->rx.req_prod_pvt = req_prod + i;
179 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
180 if (notify)
181 notify_remote_via_evtchn(dev->evtchn);
183 }
185 void network_tx_buf_gc(struct netfront_dev *dev)
186 {
189 RING_IDX cons, prod;
190 unsigned short id;
192 do {
193 prod = dev->tx.sring->rsp_prod;
194 rmb(); /* Ensure we see responses up to 'rp'. */
196 for (cons = dev->tx.rsp_cons; cons != prod; cons++)
197 {
198 struct netif_tx_response *txrsp;
199 struct net_buffer *buf;
201 txrsp = RING_GET_RESPONSE(&dev->tx, cons);
202 if (txrsp->status == NETIF_RSP_NULL)
203 continue;
205 if (txrsp->status == NETIF_RSP_ERROR)
206 printk("packet error\n");
208 id = txrsp->id;
209 BUG_ON(id >= NET_TX_RING_SIZE);
210 buf = &dev->tx_buffers[id];
211 gnttab_end_access(buf->gref);
212 buf->gref=GRANT_INVALID_REF;
214 add_id_to_freelist(id,dev->tx_freelist);
215 up(&dev->tx_sem);
216 }
218 dev->tx.rsp_cons = prod;
220 /*
221 * Set a new event, then check for race with update of tx_cons.
222 * Note that it is essential to schedule a callback, no matter
223 * how few tx_buffers are pending. Even if there is space in the
224 * transmit ring, higher layers may be blocked because too much
225 * data is outstanding: in such cases notification from Xen is
226 * likely to be the only kick that we'll get.
227 */
228 dev->tx.sring->rsp_event =
229 prod + ((dev->tx.sring->req_prod - prod) >> 1) + 1;
230 mb();
231 } while ((cons == prod) && (prod != dev->tx.sring->rsp_prod));
234 }
236 void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
237 {
238 int flags;
239 struct netfront_dev *dev = data;
241 local_irq_save(flags);
243 network_tx_buf_gc(dev);
244 network_rx(dev);
246 local_irq_restore(flags);
247 }
249 #ifdef HAVE_LIBC
250 void netfront_select_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
251 {
252 int flags;
253 struct netfront_dev *dev = data;
254 int fd = dev->fd;
256 local_irq_save(flags);
257 network_tx_buf_gc(dev);
258 local_irq_restore(flags);
260 if (fd != -1)
261 files[fd].read = 1;
262 wake_up(&netfront_queue);
263 }
264 #endif
266 static void free_netfront(struct netfront_dev *dev)
267 {
268 int i;
270 for(i=0;i<NET_TX_RING_SIZE;i++)
271 down(&dev->tx_sem);
273 mask_evtchn(dev->evtchn);
275 free(dev->mac);
276 free(dev->backend);
278 gnttab_end_access(dev->rx_ring_ref);
279 gnttab_end_access(dev->tx_ring_ref);
281 free_page(dev->rx.sring);
282 free_page(dev->tx.sring);
284 unbind_evtchn(dev->evtchn);
286 for(i=0;i<NET_RX_RING_SIZE;i++) {
287 gnttab_end_access(dev->rx_buffers[i].gref);
288 free_page(dev->rx_buffers[i].page);
289 }
291 for(i=0;i<NET_TX_RING_SIZE;i++)
292 if (dev->tx_buffers[i].page)
293 free_page(dev->tx_buffers[i].page);
295 free(dev->nodename);
296 free(dev);
297 }
299 struct netfront_dev *init_netfront(char *_nodename, void (*thenetif_rx)(unsigned char* data, int len), unsigned char rawmac[6], char **ip)
300 {
301 xenbus_transaction_t xbt;
302 char* err;
303 char* message=NULL;
304 struct netif_tx_sring *txs;
305 struct netif_rx_sring *rxs;
306 int retry=0;
307 int i;
308 char* msg;
309 char* nodename = _nodename ? _nodename : "device/vif/0";
311 struct netfront_dev *dev;
313 char path[strlen(nodename) + 1 + 10 + 1];
315 if (!thenetif_rx)
316 thenetif_rx = netif_rx;
318 printk("************************ NETFRONT for %s **********\n\n\n", nodename);
320 dev = malloc(sizeof(*dev));
321 memset(dev, 0, sizeof(*dev));
322 dev->nodename = strdup(nodename);
323 #ifdef HAVE_LIBC
324 dev->fd = -1;
325 #endif
327 printk("net TX ring size %d\n", NET_TX_RING_SIZE);
328 printk("net RX ring size %d\n", NET_RX_RING_SIZE);
329 init_SEMAPHORE(&dev->tx_sem, NET_TX_RING_SIZE);
330 for(i=0;i<NET_TX_RING_SIZE;i++)
331 {
332 add_id_to_freelist(i,dev->tx_freelist);
333 dev->tx_buffers[i].page = NULL;
334 }
336 for(i=0;i<NET_RX_RING_SIZE;i++)
337 {
338 /* TODO: that's a lot of memory */
339 dev->rx_buffers[i].page = (char*)alloc_page();
340 }
342 snprintf(path, sizeof(path), "%s/backend-id", nodename);
343 dev->dom = xenbus_read_integer(path);
344 #ifdef HAVE_LIBC
345 if (thenetif_rx == NETIF_SELECT_RX)
346 evtchn_alloc_unbound(dev->dom, netfront_select_handler, dev, &dev->evtchn);
347 else
348 #endif
349 evtchn_alloc_unbound(dev->dom, netfront_handler, dev, &dev->evtchn);
351 txs = (struct netif_tx_sring *) alloc_page();
352 rxs = (struct netif_rx_sring *) alloc_page();
353 memset(txs,0,PAGE_SIZE);
354 memset(rxs,0,PAGE_SIZE);
357 SHARED_RING_INIT(txs);
358 SHARED_RING_INIT(rxs);
359 FRONT_RING_INIT(&dev->tx, txs, PAGE_SIZE);
360 FRONT_RING_INIT(&dev->rx, rxs, PAGE_SIZE);
362 dev->tx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(txs),0);
363 dev->rx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(rxs),0);
365 init_rx_buffers(dev);
367 dev->netif_rx = thenetif_rx;
369 dev->events = NULL;
371 again:
372 err = xenbus_transaction_start(&xbt);
373 if (err) {
374 printk("starting transaction\n");
375 }
377 err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
378 dev->tx_ring_ref);
379 if (err) {
380 message = "writing tx ring-ref";
381 goto abort_transaction;
382 }
383 err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
384 dev->rx_ring_ref);
385 if (err) {
386 message = "writing rx ring-ref";
387 goto abort_transaction;
388 }
389 err = xenbus_printf(xbt, nodename,
390 "event-channel", "%u", dev->evtchn);
391 if (err) {
392 message = "writing event-channel";
393 goto abort_transaction;
394 }
396 err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1);
398 if (err) {
399 message = "writing request-rx-copy";
400 goto abort_transaction;
401 }
403 err = xenbus_printf(xbt, nodename, "state", "%u",
404 4); /* connected */
407 err = xenbus_transaction_end(xbt, 0, &retry);
408 if (retry) {
409 goto again;
410 printk("completing transaction\n");
411 }
413 goto done;
415 abort_transaction:
416 xenbus_transaction_end(xbt, 1, &retry);
417 goto error;
419 done:
421 snprintf(path, sizeof(path), "%s/backend", nodename);
422 msg = xenbus_read(XBT_NIL, path, &dev->backend);
423 snprintf(path, sizeof(path), "%s/mac", nodename);
424 msg = xenbus_read(XBT_NIL, path, &dev->mac);
426 if ((dev->backend == NULL) || (dev->mac == NULL)) {
427 printk("%s: backend/mac failed\n", __func__);
428 goto error;
429 }
431 printk("backend at %s\n",dev->backend);
432 printk("mac is %s\n",dev->mac);
434 {
435 char path[strlen(dev->backend) + 1 + 5 + 1];
436 snprintf(path, sizeof(path), "%s/state", dev->backend);
438 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
440 xenbus_wait_for_value(path, "4", &dev->events);
442 if (ip) {
443 snprintf(path, sizeof(path), "%s/ip", dev->backend);
444 xenbus_read(XBT_NIL, path, ip);
445 }
446 }
448 printk("**************************\n");
450 unmask_evtchn(dev->evtchn);
452 /* Special conversion specifier 'hh' needed for __ia64__. Without
453 this mini-os panics with 'Unaligned reference'. */
454 if (rawmac)
455 sscanf(dev->mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
456 &rawmac[0],
457 &rawmac[1],
458 &rawmac[2],
459 &rawmac[3],
460 &rawmac[4],
461 &rawmac[5]);
463 return dev;
464 error:
465 free_netfront(dev);
466 return NULL;
467 }
469 #ifdef HAVE_LIBC
470 int netfront_tap_open(char *nodename) {
471 struct netfront_dev *dev;
473 dev = init_netfront(nodename, NETIF_SELECT_RX, NULL, NULL);
474 if (!dev) {
475 printk("TAP open failed\n");
476 errno = EIO;
477 return -1;
478 }
479 dev->fd = alloc_fd(FTYPE_TAP);
480 printk("tap_open(%s) -> %d\n", nodename, dev->fd);
481 files[dev->fd].tap.dev = dev;
482 return dev->fd;
483 }
484 #endif
486 void shutdown_netfront(struct netfront_dev *dev)
487 {
488 char* err;
489 char *nodename = dev->nodename;
491 char path[strlen(dev->backend) + 1 + 5 + 1];
493 printk("close network: backend at %s\n",dev->backend);
495 snprintf(path, sizeof(path), "%s/state", dev->backend);
497 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
498 xenbus_wait_for_value(path, "5", &dev->events);
500 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
501 xenbus_wait_for_value(path, "6", &dev->events);
503 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
504 xenbus_wait_for_value(path, "2", &dev->events);
506 xenbus_unwatch_path(XBT_NIL, path);
508 snprintf(path, sizeof(path), "%s/tx-ring-ref", nodename);
509 xenbus_rm(XBT_NIL, path);
510 snprintf(path, sizeof(path), "%s/rx-ring-ref", nodename);
511 xenbus_rm(XBT_NIL, path);
512 snprintf(path, sizeof(path), "%s/event-channel", nodename);
513 xenbus_rm(XBT_NIL, path);
514 snprintf(path, sizeof(path), "%s/request-rx-copy", nodename);
515 xenbus_rm(XBT_NIL, path);
517 free_netfront(dev);
518 }
521 void init_rx_buffers(struct netfront_dev *dev)
522 {
523 int i, requeue_idx;
524 netif_rx_request_t *req;
525 int notify;
527 /* Rebuild the RX buffer freelist and the RX ring itself. */
528 for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++)
529 {
530 struct net_buffer* buf = &dev->rx_buffers[requeue_idx];
531 req = RING_GET_REQUEST(&dev->rx, requeue_idx);
533 buf->gref = req->gref =
534 gnttab_grant_access(dev->dom,virt_to_mfn(buf->page),0);
536 req->id = requeue_idx;
538 requeue_idx++;
539 }
541 dev->rx.req_prod_pvt = requeue_idx;
543 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
545 if (notify)
546 notify_remote_via_evtchn(dev->evtchn);
548 dev->rx.sring->rsp_event = dev->rx.rsp_cons + 1;
549 }
552 void netfront_xmit(struct netfront_dev *dev, unsigned char* data,int len)
553 {
554 int flags;
555 struct netif_tx_request *tx;
556 RING_IDX i;
557 int notify;
558 unsigned short id;
559 struct net_buffer* buf;
560 void* page;
562 BUG_ON(len > PAGE_SIZE);
564 down(&dev->tx_sem);
566 local_irq_save(flags);
567 id = get_id_from_freelist(dev->tx_freelist);
568 local_irq_restore(flags);
570 buf = &dev->tx_buffers[id];
571 page = buf->page;
572 if (!page)
573 page = buf->page = (char*) alloc_page();
575 i = dev->tx.req_prod_pvt;
576 tx = RING_GET_REQUEST(&dev->tx, i);
578 memcpy(page,data,len);
580 buf->gref =
581 tx->gref = gnttab_grant_access(dev->dom,virt_to_mfn(page),1);
583 tx->offset=0;
584 tx->size = len;
585 tx->flags=0;
586 tx->id = id;
587 dev->tx.req_prod_pvt = i + 1;
589 wmb();
591 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->tx, notify);
593 if(notify) notify_remote_via_evtchn(dev->evtchn);
595 local_irq_save(flags);
596 network_tx_buf_gc(dev);
597 local_irq_restore(flags);
598 }
600 #ifdef HAVE_LIBC
601 ssize_t netfront_receive(struct netfront_dev *dev, unsigned char *data, size_t len)
602 {
603 unsigned long flags;
604 int fd = dev->fd;
605 ASSERT(current == main_thread);
607 dev->rlen = 0;
608 dev->data = data;
609 dev->len = len;
611 local_irq_save(flags);
612 network_rx(dev);
613 if (!dev->rlen && fd != -1)
614 /* No data for us, make select stop returning */
615 files[fd].read = 0;
616 /* Before re-enabling the interrupts, in case a packet just arrived in the
617 * meanwhile. */
618 local_irq_restore(flags);
620 dev->data = NULL;
621 dev->len = 0;
623 return dev->rlen;
624 }
625 #endif