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 Søren Sandmann <sandmann@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 36struct ring 37{ 38 struct qxl_ring_header header; 39 uint8_t elements[0]; 40}; 41 42struct 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 51struct qxl_ring * 52qxl_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 72void 73qxl_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 107Bool 108qxl_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 128void 129qxl_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 138void 139qxl_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 146int 147qxl_ring_cons (struct qxl_ring *ring) 148{ 149 return ring->ring->header.cons; 150} 151 152int 153qxl_ring_prod (struct qxl_ring *ring) 154{ 155 return ring->ring->header.prod; 156} 157