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