aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/qxl/qxl_image.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2013-02-24 23:47:55 -0500
committerDave Airlie <airlied@redhat.com>2013-04-11 23:51:07 -0400
commitf64122c1f6ade301585569863b4b3b18f6e4e332 (patch)
tree1eb6629931604584f6fff28c0b9a1c9a3d9024f3 /drivers/gpu/drm/qxl/qxl_image.c
parentafe6804c045fbd69a1b75c681107b5d6df9190de (diff)
drm: add new QXL driver. (v1.4)
QXL is a paravirtual graphics device used by the Spice virtual desktop interface. The drivers uses GEM and TTM to manage memory, the qxl hw fencing however is quite different than normal TTM expects, we have to keep track of a number of non-linear fence ids per bo that we need to have released by the hardware. The releases are freed from a workqueue that wakes up and processes the release ring. releases are suballocated from a BO, there are 3 release categories, drawables, surfaces and cursor cmds. The hw also has 3 rings for commands, cursor and release handling. The hardware also have a surface id tracking mechnaism and the driver encapsulates it completely inside the kernel, userspace never sees the actual hw surface ids. This requires a newer version of the QXL userspace driver, so shouldn't be enabled until that has been placed into your distro of choice. Authors: Dave Airlie, Alon Levy v1.1: fixup some issues in the ioctl interface with padding v1.2: add module device table v1.3: fix nomodeset, fbcon leak, dumb bo create, release ring irq, don't try flush release ring (broken hw), fix -modesetting. v1.4: fbcon cpu usage reduction + suitable accel flags. Signed-off-by: Alon Levy <alevy@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/qxl/qxl_image.c')
-rw-r--r--drivers/gpu/drm/qxl/qxl_image.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_image.c b/drivers/gpu/drm/qxl/qxl_image.c
new file mode 100644
index 000000000000..cf856206996b
--- /dev/null
+++ b/drivers/gpu/drm/qxl/qxl_image.c
@@ -0,0 +1,176 @@
1/*
2 * Copyright 2013 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Dave Airlie
23 * Alon Levy
24 */
25
26#include <linux/gfp.h>
27#include <linux/slab.h>
28
29#include "qxl_drv.h"
30#include "qxl_object.h"
31
32static int
33qxl_image_create_helper(struct qxl_device *qdev,
34 struct qxl_release *release,
35 struct qxl_bo **image_bo,
36 const uint8_t *data,
37 int width, int height,
38 int depth, unsigned int hash,
39 int stride)
40{
41 struct qxl_image *image;
42 struct qxl_data_chunk *chunk;
43 int i;
44 int chunk_stride;
45 int linesize = width * depth / 8;
46 struct qxl_bo *chunk_bo;
47 int ret;
48 void *ptr;
49 /* Chunk */
50 /* FIXME: Check integer overflow */
51 /* TODO: variable number of chunks */
52 chunk_stride = stride; /* TODO: should use linesize, but it renders
53 wrong (check the bitmaps are sent correctly
54 first) */
55 ret = qxl_alloc_bo_reserved(qdev, sizeof(*chunk) + height * chunk_stride,
56 &chunk_bo);
57
58 ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, 0);
59 chunk = ptr;
60 chunk->data_size = height * chunk_stride;
61 chunk->prev_chunk = 0;
62 chunk->next_chunk = 0;
63 qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
64
65 {
66 void *k_data, *i_data;
67 int remain;
68 int page;
69 int size;
70 if (stride == linesize && chunk_stride == stride) {
71 remain = linesize * height;
72 page = 0;
73 i_data = (void *)data;
74
75 while (remain > 0) {
76 ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page << PAGE_SHIFT);
77
78 if (page == 0) {
79 chunk = ptr;
80 k_data = chunk->data;
81 size = PAGE_SIZE - offsetof(struct qxl_data_chunk, data);
82 } else {
83 k_data = ptr;
84 size = PAGE_SIZE;
85 }
86 size = min(size, remain);
87
88 memcpy(k_data, i_data, size);
89
90 qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
91 i_data += size;
92 remain -= size;
93 page++;
94 }
95 } else {
96 unsigned page_base, page_offset, out_offset;
97 for (i = 0 ; i < height ; ++i) {
98 i_data = (void *)data + i * stride;
99 remain = linesize;
100 out_offset = offsetof(struct qxl_data_chunk, data) + i * chunk_stride;
101
102 while (remain > 0) {
103 page_base = out_offset & PAGE_MASK;
104 page_offset = offset_in_page(out_offset);
105
106 size = min((int)(PAGE_SIZE - page_offset), remain);
107
108 ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page_base);
109 k_data = ptr + page_offset;
110 memcpy(k_data, i_data, size);
111 qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
112 remain -= size;
113 i_data += size;
114 out_offset += size;
115 }
116 }
117 }
118 }
119
120
121 qxl_bo_kunmap(chunk_bo);
122
123 /* Image */
124 ret = qxl_alloc_bo_reserved(qdev, sizeof(*image), image_bo);
125
126 ptr = qxl_bo_kmap_atomic_page(qdev, *image_bo, 0);
127 image = ptr;
128
129 image->descriptor.id = 0;
130 image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
131
132 image->descriptor.flags = 0;
133 image->descriptor.width = width;
134 image->descriptor.height = height;
135
136 switch (depth) {
137 case 1:
138 /* TODO: BE? check by arch? */
139 image->u.bitmap.format = SPICE_BITMAP_FMT_1BIT_BE;
140 break;
141 case 24:
142 image->u.bitmap.format = SPICE_BITMAP_FMT_24BIT;
143 break;
144 case 32:
145 image->u.bitmap.format = SPICE_BITMAP_FMT_32BIT;
146 break;
147 default:
148 DRM_ERROR("unsupported image bit depth\n");
149 return -EINVAL; /* TODO: cleanup */
150 }
151 image->u.bitmap.flags = QXL_BITMAP_TOP_DOWN;
152 image->u.bitmap.x = width;
153 image->u.bitmap.y = height;
154 image->u.bitmap.stride = chunk_stride;
155 image->u.bitmap.palette = 0;
156 image->u.bitmap.data = qxl_bo_physical_address(qdev, chunk_bo, 0);
157 qxl_release_add_res(qdev, release, chunk_bo);
158 qxl_bo_unreserve(chunk_bo);
159 qxl_bo_unref(&chunk_bo);
160
161 qxl_bo_kunmap_atomic_page(qdev, *image_bo, ptr);
162
163 return 0;
164}
165
166int qxl_image_create(struct qxl_device *qdev,
167 struct qxl_release *release,
168 struct qxl_bo **image_bo,
169 const uint8_t *data,
170 int x, int y, int width, int height,
171 int depth, int stride)
172{
173 data += y * stride + x * (depth / 8);
174 return qxl_image_create_helper(qdev, release, image_bo, data,
175 width, height, depth, 0, stride);
176}