ia64/xen-unstable

view extras/mini-os/fbfront.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 18c8270da77c
line source
1 /*
2 * Frame Buffer + Keyboard driver for Mini-OS.
3 * Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008
4 * Based on blkfront.c.
5 */
7 #include <os.h>
8 #include <xenbus.h>
9 #include <events.h>
10 #include <xen/io/kbdif.h>
11 #include <xen/io/fbif.h>
12 #include <xen/io/protocols.h>
13 #include <gnttab.h>
14 #include <xmalloc.h>
15 #include <fbfront.h>
16 #include <lib.h>
18 DECLARE_WAIT_QUEUE_HEAD(kbdfront_queue);
25 struct kbdfront_dev {
26 domid_t dom;
28 struct xenkbd_page *page;
29 evtchn_port_t evtchn;
31 char *nodename;
32 char *backend;
34 xenbus_event_queue events;
36 #ifdef HAVE_LIBC
37 int fd;
38 #endif
39 };
41 void kbdfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
42 {
43 #ifdef HAVE_LIBC
44 struct kbdfront_dev *dev = data;
45 int fd = dev->fd;
47 if (fd != -1)
48 files[fd].read = 1;
49 #endif
50 wake_up(&kbdfront_queue);
51 }
53 static void free_kbdfront(struct kbdfront_dev *dev)
54 {
55 mask_evtchn(dev->evtchn);
57 free(dev->backend);
59 free_page(dev->page);
61 unbind_evtchn(dev->evtchn);
63 free(dev->nodename);
64 free(dev);
65 }
67 struct kbdfront_dev *init_kbdfront(char *_nodename, int abs_pointer)
68 {
69 xenbus_transaction_t xbt;
70 char* err;
71 char* message=NULL;
72 struct xenkbd_page *s;
73 int retry=0;
74 char* msg;
75 char* nodename = _nodename ? _nodename : "device/vkbd/0";
76 struct kbdfront_dev *dev;
78 char path[strlen(nodename) + 1 + 10 + 1];
80 printk("******************* KBDFRONT for %s **********\n\n\n", nodename);
82 dev = malloc(sizeof(*dev));
83 dev->nodename = strdup(nodename);
84 #ifdef HAVE_LIBC
85 dev->fd = -1;
86 #endif
88 snprintf(path, sizeof(path), "%s/backend-id", nodename);
89 dev->dom = xenbus_read_integer(path);
90 evtchn_alloc_unbound(dev->dom, kbdfront_handler, dev, &dev->evtchn);
92 dev->page = s = (struct xenkbd_page*) alloc_page();
93 memset(s,0,PAGE_SIZE);
95 dev->events = NULL;
97 s->in_cons = s->in_prod = 0;
98 s->out_cons = s->out_prod = 0;
100 again:
101 err = xenbus_transaction_start(&xbt);
102 if (err) {
103 printk("starting transaction\n");
104 }
106 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
107 if (err) {
108 message = "writing page-ref";
109 goto abort_transaction;
110 }
111 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
112 if (err) {
113 message = "writing event-channel";
114 goto abort_transaction;
115 }
116 if (abs_pointer) {
117 err = xenbus_printf(xbt, nodename, "request-abs-pointer", "1");
118 if (err) {
119 message = "writing event-channel";
120 goto abort_transaction;
121 }
122 }
124 err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
125 if (err)
126 printk("error writing initialized: %s\n", err);
129 err = xenbus_transaction_end(xbt, 0, &retry);
130 if (retry) {
131 goto again;
132 printk("completing transaction\n");
133 }
135 goto done;
137 abort_transaction:
138 xenbus_transaction_end(xbt, 1, &retry);
139 goto error;
141 done:
143 snprintf(path, sizeof(path), "%s/backend", nodename);
144 msg = xenbus_read(XBT_NIL, path, &dev->backend);
145 if (msg) {
146 printk("Error %s when reading the backend path %s\n", msg, path);
147 goto error;
148 }
150 printk("backend at %s\n", dev->backend);
152 {
153 char path[strlen(dev->backend) + 1 + 6 + 1];
155 snprintf(path, sizeof(path), "%s/state", dev->backend);
157 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
159 xenbus_wait_for_value(path, "4", &dev->events);
161 printk("%s connected\n", dev->backend);
163 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
164 }
165 unmask_evtchn(dev->evtchn);
167 printk("************************** KBDFRONT\n");
169 return dev;
170 error:
171 free_kbdfront(dev);
172 return NULL;
173 }
175 int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n)
176 {
177 struct xenkbd_page *page = dev->page;
178 uint32_t prod, cons;
179 int i;
181 #ifdef HAVE_LIBC
182 if (dev->fd != -1) {
183 files[dev->fd].read = 0;
184 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
185 }
186 #endif
188 prod = page->in_prod;
190 if (prod == page->in_cons)
191 return 0;
193 rmb(); /* ensure we see ring contents up to prod */
195 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
196 memcpy(buf + i, &XENKBD_IN_RING_REF(page, cons), sizeof(*buf));
198 mb(); /* ensure we got ring contents */
199 page->in_cons = cons;
200 notify_remote_via_evtchn(dev->evtchn);
202 #ifdef HAVE_LIBC
203 if (cons != prod && dev->fd != -1)
204 /* still some events to read */
205 files[dev->fd].read = 1;
206 #endif
208 return i;
209 }
212 void shutdown_kbdfront(struct kbdfront_dev *dev)
213 {
214 char* err;
215 char *nodename = dev->nodename;
217 char path[strlen(dev->backend) + 1 + 5 + 1];
219 printk("close kbd: backend at %s\n",dev->backend);
221 snprintf(path, sizeof(path), "%s/state", dev->backend);
222 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
223 xenbus_wait_for_value(path, "5", &dev->events);
225 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
226 xenbus_wait_for_value(path, "6", &dev->events);
228 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
229 // does not work yet.
230 //xenbus_wait_for_value(path, "2", &dev->events);
232 xenbus_unwatch_path(XBT_NIL, path);
234 snprintf(path, sizeof(path), "%s/page-ref", nodename);
235 xenbus_rm(XBT_NIL, path);
236 snprintf(path, sizeof(path), "%s/event-channel", nodename);
237 xenbus_rm(XBT_NIL, path);
238 snprintf(path, sizeof(path), "%s/request-abs-pointer", nodename);
239 xenbus_rm(XBT_NIL, path);
241 free_kbdfront(dev);
242 }
244 #ifdef HAVE_LIBC
245 int kbdfront_open(struct kbdfront_dev *dev)
246 {
247 dev->fd = alloc_fd(FTYPE_KBD);
248 printk("kbd_open(%s) -> %d\n", dev->nodename, dev->fd);
249 files[dev->fd].kbd.dev = dev;
250 return dev->fd;
251 }
252 #endif
258 DECLARE_WAIT_QUEUE_HEAD(fbfront_queue);
265 struct fbfront_dev {
266 domid_t dom;
268 struct xenfb_page *page;
269 evtchn_port_t evtchn;
271 char *nodename;
272 char *backend;
273 int request_update;
275 int width;
276 int height;
277 int depth;
278 int stride;
279 int mem_length;
280 int offset;
282 xenbus_event_queue events;
284 #ifdef HAVE_LIBC
285 int fd;
286 #endif
287 };
289 void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
290 {
291 #ifdef HAVE_LIBC
292 struct fbfront_dev *dev = data;
293 int fd = dev->fd;
295 if (fd != -1)
296 files[fd].read = 1;
297 #endif
298 wake_up(&fbfront_queue);
299 }
301 static void free_fbfront(struct fbfront_dev *dev)
302 {
303 mask_evtchn(dev->evtchn);
305 free(dev->backend);
307 free_page(dev->page);
309 unbind_evtchn(dev->evtchn);
311 free(dev->nodename);
312 free(dev);
313 }
315 int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
316 {
317 struct xenfb_page *page = dev->page;
318 uint32_t prod, cons;
319 int i;
321 #ifdef HAVE_LIBC
322 if (dev->fd != -1) {
323 files[dev->fd].read = 0;
324 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
325 }
326 #endif
328 prod = page->in_prod;
330 if (prod == page->in_cons)
331 return 0;
333 rmb(); /* ensure we see ring contents up to prod */
335 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
336 memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
338 mb(); /* ensure we got ring contents */
339 page->in_cons = cons;
340 notify_remote_via_evtchn(dev->evtchn);
342 #ifdef HAVE_LIBC
343 if (cons != prod && dev->fd != -1)
344 /* still some events to read */
345 files[dev->fd].read = 1;
346 #endif
348 return i;
349 }
351 struct fbfront_dev *init_fbfront(char *_nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
352 {
353 xenbus_transaction_t xbt;
354 char* err;
355 char* message=NULL;
356 struct xenfb_page *s;
357 int retry=0;
358 char* msg;
359 int i, j;
360 struct fbfront_dev *dev;
361 int max_pd;
362 unsigned long mapped;
363 char* nodename = _nodename ? _nodename : "device/vfb/0";
365 char path[strlen(nodename) + 1 + 10 + 1];
367 printk("******************* FBFRONT for %s **********\n\n\n", nodename);
369 dev = malloc(sizeof(*dev));
370 dev->nodename = strdup(nodename);
371 #ifdef HAVE_LIBC
372 dev->fd = -1;
373 #endif
375 snprintf(path, sizeof(path), "%s/backend-id", nodename);
376 dev->dom = xenbus_read_integer(path);
377 evtchn_alloc_unbound(dev->dom, fbfront_handler, dev, &dev->evtchn);
379 dev->page = s = (struct xenfb_page*) alloc_page();
380 memset(s,0,PAGE_SIZE);
382 s->in_cons = s->in_prod = 0;
383 s->out_cons = s->out_prod = 0;
384 dev->width = s->width = width;
385 dev->height = s->height = height;
386 dev->depth = s->depth = depth;
387 dev->stride = s->line_length = stride;
388 dev->mem_length = s->mem_length = n * PAGE_SIZE;
389 dev->offset = 0;
390 dev->events = NULL;
392 max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
393 mapped = 0;
395 for (i = 0; mapped < n && i < max_pd; i++) {
396 unsigned long *pd = (unsigned long *) alloc_page();
397 for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++)
398 pd[j] = mfns[mapped++];
399 for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
400 pd[j] = 0;
401 s->pd[i] = virt_to_mfn(pd);
402 }
403 for ( ; i < max_pd; i++)
404 s->pd[i] = 0;
407 again:
408 err = xenbus_transaction_start(&xbt);
409 if (err) {
410 printk("starting transaction\n");
411 }
413 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
414 if (err) {
415 message = "writing page-ref";
416 goto abort_transaction;
417 }
418 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
419 if (err) {
420 message = "writing event-channel";
421 goto abort_transaction;
422 }
423 err = xenbus_printf(xbt, nodename, "protocol", "%s",
424 XEN_IO_PROTO_ABI_NATIVE);
425 if (err) {
426 message = "writing event-channel";
427 goto abort_transaction;
428 }
429 err = xenbus_printf(xbt, nodename, "feature-update", "1");
430 if (err) {
431 message = "writing event-channel";
432 goto abort_transaction;
433 }
435 err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
438 err = xenbus_transaction_end(xbt, 0, &retry);
439 if (retry) {
440 goto again;
441 printk("completing transaction\n");
442 }
444 goto done;
446 abort_transaction:
447 xenbus_transaction_end(xbt, 1, &retry);
448 goto error;
450 done:
452 snprintf(path, sizeof(path), "%s/backend", nodename);
453 msg = xenbus_read(XBT_NIL, path, &dev->backend);
454 if (msg) {
455 printk("Error %s when reading the backend path %s\n", msg, path);
456 goto error;
457 }
459 printk("backend at %s\n", dev->backend);
461 {
462 char path[strlen(dev->backend) + 1 + 14 + 1];
464 snprintf(path, sizeof(path), "%s/state", dev->backend);
466 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
468 xenbus_wait_for_value(path, "4", &dev->events);
470 printk("%s connected\n", dev->backend);
472 snprintf(path, sizeof(path), "%s/request-update", dev->backend);
473 dev->request_update = xenbus_read_integer(path);
475 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
476 }
477 unmask_evtchn(dev->evtchn);
479 printk("************************** FBFRONT\n");
481 return dev;
483 error:
484 free_fbfront(dev);
485 return NULL;
486 }
488 static void fbfront_out_event(struct fbfront_dev *dev, union xenfb_out_event *event)
489 {
490 struct xenfb_page *page = dev->page;
491 uint32_t prod;
492 DEFINE_WAIT(w);
494 add_waiter(w, fbfront_queue);
495 while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
496 schedule();
497 remove_waiter(w);
499 prod = page->out_prod;
500 mb(); /* ensure ring space available */
501 XENFB_OUT_RING_REF(page, prod) = *event;
502 wmb(); /* ensure ring contents visible */
503 page->out_prod = prod + 1;
504 notify_remote_via_evtchn(dev->evtchn);
505 }
507 void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
508 {
509 struct xenfb_update update;
511 if (dev->request_update <= 0)
512 return;
514 if (x < 0) {
515 width += x;
516 x = 0;
517 }
518 if (x + width > dev->width)
519 width = dev->width - x;
521 if (y < 0) {
522 height += y;
523 y = 0;
524 }
525 if (y + height > dev->height)
526 height = dev->height - y;
528 if (width <= 0 || height <= 0)
529 return;
531 update.type = XENFB_TYPE_UPDATE;
532 update.x = x;
533 update.y = y;
534 update.width = width;
535 update.height = height;
536 fbfront_out_event(dev, (union xenfb_out_event *) &update);
537 }
539 void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset)
540 {
541 struct xenfb_resize resize;
543 resize.type = XENFB_TYPE_RESIZE;
544 dev->width = resize.width = width;
545 dev->height = resize.height = height;
546 dev->stride = resize.stride = stride;
547 dev->depth = resize.depth = depth;
548 dev->offset = resize.offset = offset;
549 fbfront_out_event(dev, (union xenfb_out_event *) &resize);
550 }
552 void shutdown_fbfront(struct fbfront_dev *dev)
553 {
554 char* err;
555 char *nodename = dev->nodename;
557 char path[strlen(dev->backend) + 1 + 5 + 1];
559 printk("close fb: backend at %s\n",dev->backend);
561 snprintf(path, sizeof(path), "%s/state", dev->backend);
562 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
563 xenbus_wait_for_value(path, "5", &dev->events);
565 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
566 xenbus_wait_for_value(path, "6", &dev->events);
568 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
569 // does not work yet
570 //xenbus_wait_for_value(path, "2", &dev->events);
572 xenbus_unwatch_path(XBT_NIL, path);
574 snprintf(path, sizeof(path), "%s/page-ref", nodename);
575 xenbus_rm(XBT_NIL, path);
576 snprintf(path, sizeof(path), "%s/event-channel", nodename);
577 xenbus_rm(XBT_NIL, path);
578 snprintf(path, sizeof(path), "%s/protocol", nodename);
579 xenbus_rm(XBT_NIL, path);
580 snprintf(path, sizeof(path), "%s/feature-update", nodename);
581 xenbus_rm(XBT_NIL, path);
583 unbind_evtchn(dev->evtchn);
585 free_fbfront(dev);
586 }
588 #ifdef HAVE_LIBC
589 int fbfront_open(struct fbfront_dev *dev)
590 {
591 dev->fd = alloc_fd(FTYPE_FB);
592 printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
593 files[dev->fd].fb.dev = dev;
594 return dev->fd;
595 }
596 #endif