ia64/xen-unstable

view extras/mini-os/netfront.c @ 19557:226ef307cd2e

AMD IOMMU: Fix ioapic interrupt remapping

A few ioapic redirection entries are initialized by hypervisor before
enabling iommu hardware. This patch copies those entries from ioapic
redirection table into interrupt remapping table after interrupt
remapping table has been allocated.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Apr 17 13:16:39 2009 +0100 (2009-04-17)
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