1 /* 2 * Copyright 2009, 2010 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 /** \file qxl_ring.c 24 * \author Sren Sandmann <sandmann (at) redhat.com> 25 */ 26 #ifdef HAVE_CONFIG_H 27 #include "config.h" 28 #endif 29 30 #include <string.h> 31 #include <unistd.h> 32 #include <stdlib.h> 33 #include <sched.h> 34 #include "qxl.h" 35 36 struct ring 37 { 38 struct qxl_ring_header header; 39 uint8_t elements[0]; 40 }; 41 42 struct qxl_ring 43 { 44 volatile struct ring *ring; 45 int element_size; 46 int n_elements; 47 int io_port_prod_notify; 48 qxl_screen_t *qxl; 49 }; 50 51 struct qxl_ring * 52 qxl_ring_create (struct qxl_ring_header *header, 53 int element_size, 54 int n_elements, 55 int io_port_prod_notify, 56 qxl_screen_t *qxl) 57 { 58 struct qxl_ring *ring; 59 60 ring = malloc (sizeof *ring); 61 if (!ring) 62 return NULL; 63 64 ring->ring = (volatile struct ring *)header; 65 ring->element_size = element_size; 66 ring->n_elements = n_elements; 67 ring->io_port_prod_notify = io_port_prod_notify; 68 ring->qxl = qxl; 69 return ring; 70 } 71 72 void 73 qxl_ring_push (struct qxl_ring *ring, 74 const void *new_elt) 75 { 76 volatile struct qxl_ring_header *header = &(ring->ring->header); 77 volatile uint8_t *elt; 78 int idx; 79 80 while (header->prod - header->cons == header->num_items) 81 { 82 header->notify_on_cons = header->cons + 1; 83 #ifdef XSPICE 84 /* in gtkperf, circles, this is a major bottleneck. Can't be that good in a vm either 85 * Adding the yield reduces cpu usage, but doesn't improve throughput. */ 86 sched_yield(); 87 #endif 88 mem_barrier(); 89 } 90 91 idx = header->prod & (ring->n_elements - 1); 92 elt = ring->ring->elements + idx * ring->element_size; 93 94 /* TODO: We should use proper MMIO accessors; the use of 95 volatile leads to a gcc warning. See commit f7ba4bae */ 96 memcpy((void *)elt, new_elt, ring->element_size); 97 98 header->prod++; 99 100 mem_barrier(); 101 102 if (header->prod == header->notify_on_prod) { 103 ioport_write (ring->qxl, ring->io_port_prod_notify, 0); 104 } 105 } 106 107 Bool 108 qxl_ring_pop (struct qxl_ring *ring, 109 void *element) 110 { 111 volatile struct qxl_ring_header *header = &(ring->ring->header); 112 volatile uint8_t *ring_elt; 113 int idx; 114 115 if (header->cons == header->prod) 116 return FALSE; 117 118 idx = header->cons & (ring->n_elements - 1); 119 ring_elt = ring->ring->elements + idx * ring->element_size; 120 121 memcpy (element, (void *)ring_elt, ring->element_size); 122 123 header->cons++; 124 125 return TRUE; 126 } 127 128 void 129 qxl_ring_wait_idle (struct qxl_ring *ring) 130 { 131 while (ring->ring->header.cons != ring->ring->header.prod) 132 { 133 usleep (1000); 134 mem_barrier(); 135 } 136 } 137 138 void 139 qxl_ring_request_notify (struct qxl_ring *ring) 140 { 141 ring->ring->header.notify_on_prod = ring->ring->header.prod + 1; 142 ErrorF("%s: requesting notify on prod %d\n", __func__, 143 ring->ring->header.notify_on_prod); 144 } 145 146 int 147 qxl_ring_cons (struct qxl_ring *ring) 148 { 149 return ring->ring->header.cons; 150 } 151 152 int 153 qxl_ring_prod (struct qxl_ring *ring) 154 { 155 return ring->ring->header.prod; 156 } 157