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