Home | History | Annotate | Line # | Download | only in src
      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