r600g: move some queries into winsys/radeon
[mesa.git] / src / gallium / winsys / radeon / drm / radeon_drm_winsys.c
1 /*
2 * Copyright © 2009 Corbin Simpson
3 * Copyright © 2011 Marek Olšák <maraeo@gmail.com>
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27 /*
28 * Authors:
29 * Corbin Simpson <MostAwesomeDude@gmail.com>
30 * Joakim Sindholt <opensource@zhasha.com>
31 * Marek Olšák <maraeo@gmail.com>
32 */
33
34 #include "radeon_drm_bo.h"
35 #include "radeon_drm_cs.h"
36 #include "radeon_drm_public.h"
37
38 #include "pipebuffer/pb_bufmgr.h"
39 #include "util/u_memory.h"
40
41 #include <xf86drm.h>
42 #include <stdio.h>
43
44 #ifndef RADEON_INFO_TILING_CONFIG
45 #define RADEON_INFO_TILING_CONFIG 6
46 #endif
47
48 #ifndef RADEON_INFO_WANT_HYPERZ
49 #define RADEON_INFO_WANT_HYPERZ 7
50 #endif
51
52 #ifndef RADEON_INFO_WANT_CMASK
53 #define RADEON_INFO_WANT_CMASK 8
54 #endif
55
56 #ifndef RADEON_INFO_CLOCK_CRYSTAL_FREQ
57 #define RADEON_INFO_CLOCK_CRYSTAL_FREQ 9
58 #endif
59
60 #ifndef RADEON_INFO_NUM_BACKENDS
61 #define RADEON_INFO_NUM_BACKENDS 10
62 #endif
63
64 /* Enable/disable feature access for one command stream.
65 * If enable == TRUE, return TRUE on success.
66 * Otherwise, return FALSE.
67 *
68 * We basically do the same thing kernel does, because we have to deal
69 * with multiple contexts (here command streams) backed by one winsys. */
70 static boolean radeon_set_fd_access(struct radeon_drm_cs *applier,
71 struct radeon_drm_cs **owner,
72 pipe_mutex *mutex,
73 unsigned request, boolean enable)
74 {
75 struct drm_radeon_info info = {0};
76 unsigned value = enable ? 1 : 0;
77
78 pipe_mutex_lock(*mutex);
79
80 /* Early exit if we are sure the request will fail. */
81 if (enable) {
82 if (*owner) {
83 pipe_mutex_unlock(*mutex);
84 return FALSE;
85 }
86 } else {
87 if (*owner != applier) {
88 pipe_mutex_unlock(*mutex);
89 return FALSE;
90 }
91 }
92
93 /* Pass through the request to the kernel. */
94 info.value = (unsigned long)&value;
95 info.request = request;
96 if (drmCommandWriteRead(applier->ws->fd, DRM_RADEON_INFO,
97 &info, sizeof(info)) != 0) {
98 pipe_mutex_unlock(*mutex);
99 return FALSE;
100 }
101
102 /* Update the rights in the winsys. */
103 if (enable) {
104 if (value) {
105 *owner = applier;
106 fprintf(stderr, "radeon: Acquired Hyper-Z.\n");
107 pipe_mutex_unlock(*mutex);
108 return TRUE;
109 }
110 } else {
111 *owner = NULL;
112 fprintf(stderr, "radeon: Released Hyper-Z.\n");
113 }
114
115 pipe_mutex_unlock(*mutex);
116 return FALSE;
117 }
118
119 static boolean radeon_get_drm_value(int fd, unsigned request,
120 const char *errname, uint32_t *out)
121 {
122 struct drm_radeon_info info = {0};
123 int retval;
124
125 info.value = (unsigned long)out;
126 info.request = request;
127
128 retval = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info));
129 if (retval && errname) {
130 fprintf(stderr, "radeon: Failed to get %s, error number %d\n",
131 errname, retval);
132 return FALSE;
133 }
134 return TRUE;
135 }
136
137 /* Helper function to do the ioctls needed for setup and init. */
138 static boolean do_winsys_init(struct radeon_drm_winsys *ws)
139 {
140 struct drm_radeon_gem_info gem_info = {0};
141 int retval;
142 drmVersionPtr version;
143
144 /* We do things in a specific order here.
145 *
146 * DRM version first. We need to be sure we're running on a KMS chipset.
147 * This is also for some features.
148 *
149 * Then, the PCI ID. This is essential and should return usable numbers
150 * for all Radeons. If this fails, we probably got handed an FD for some
151 * non-Radeon card.
152 *
153 * The GEM info is actually bogus on the kernel side, as well as our side
154 * (see radeon_gem_info_ioctl in radeon_gem.c) but that's alright because
155 * we don't actually use the info for anything yet.
156 *
157 * The GB and Z pipe requests should always succeed, but they might not
158 * return sensical values for all chipsets, but that's alright because
159 * the pipe drivers already know that.
160 */
161
162 /* Get DRM version. */
163 version = drmGetVersion(ws->fd);
164 if (version->version_major != 2 ||
165 version->version_minor < 3) {
166 fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is "
167 "only compatible with 2.3.x (kernel 2.6.34) or later.\n",
168 __FUNCTION__,
169 version->version_major,
170 version->version_minor,
171 version->version_patchlevel);
172 drmFreeVersion(version);
173 return FALSE;
174 }
175
176 ws->info.drm_major = version->version_major;
177 ws->info.drm_minor = version->version_minor;
178 ws->info.drm_patchlevel = version->version_patchlevel;
179 drmFreeVersion(version);
180
181 /* Get PCI ID. */
182 if (!radeon_get_drm_value(ws->fd, RADEON_INFO_DEVICE_ID, "PCI ID",
183 &ws->info.pci_id))
184 return FALSE;
185
186 /* Check PCI ID. */
187 switch (ws->info.pci_id) {
188 #define CHIPSET(pci_id, name, family) case pci_id:
189 #include "pci_ids/r300_pci_ids.h"
190 #undef CHIPSET
191 ws->gen = R300;
192 break;
193
194 #define CHIPSET(pci_id, name, family) case pci_id:
195 #include "pci_ids/r600_pci_ids.h"
196 #undef CHIPSET
197 ws->gen = R600;
198 break;
199
200 default:
201 fprintf(stderr, "radeon: Invalid PCI ID.\n");
202 return FALSE;
203 }
204
205 /* Get GEM info. */
206 retval = drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_INFO,
207 &gem_info, sizeof(gem_info));
208 if (retval) {
209 fprintf(stderr, "radeon: Failed to get MM info, error number %d\n",
210 retval);
211 return FALSE;
212 }
213 ws->info.gart_size = gem_info.gart_size;
214 ws->info.vram_size = gem_info.vram_size;
215
216 ws->num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
217
218 /* Generation-specific queries. */
219 if (ws->gen == R300) {
220 if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_GB_PIPES,
221 "GB pipe count",
222 &ws->info.r300_num_gb_pipes))
223 return FALSE;
224
225 if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_Z_PIPES,
226 "Z pipe count",
227 &ws->info.r300_num_z_pipes))
228 return FALSE;
229 }
230 else if (ws->gen == R600) {
231 if (ws->info.drm_minor >= 9 &&
232 !radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_BACKENDS,
233 "num backends",
234 &ws->info.r600_num_backends))
235 return FALSE;
236
237 /* get the GPU counter frequency, failure is not fatal */
238 radeon_get_drm_value(ws->fd, RADEON_INFO_CLOCK_CRYSTAL_FREQ, NULL,
239 &ws->info.r600_clock_crystal_freq);
240
241 radeon_get_drm_value(ws->fd, RADEON_INFO_TILING_CONFIG, NULL,
242 &ws->info.r600_tiling_config);
243 }
244
245 return TRUE;
246 }
247
248 static void radeon_winsys_destroy(struct radeon_winsys *rws)
249 {
250 struct radeon_drm_winsys *ws = (struct radeon_drm_winsys*)rws;
251
252 pipe_mutex_destroy(ws->hyperz_owner_mutex);
253 pipe_mutex_destroy(ws->cmask_owner_mutex);
254
255 ws->cman->destroy(ws->cman);
256 ws->kman->destroy(ws->kman);
257 FREE(rws);
258 }
259
260 static void radeon_query_info(struct radeon_winsys *rws,
261 struct radeon_info *info)
262 {
263 *info = ((struct radeon_drm_winsys *)rws)->info;
264 }
265
266 static boolean radeon_cs_request_feature(struct radeon_winsys_cs *rcs,
267 enum radeon_feature_id fid,
268 boolean enable)
269 {
270 struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
271
272 switch (fid) {
273 case RADEON_FID_R300_HYPERZ_ACCESS:
274 if (debug_get_bool_option("RADEON_HYPERZ", FALSE)) {
275 return radeon_set_fd_access(cs, &cs->ws->hyperz_owner,
276 &cs->ws->hyperz_owner_mutex,
277 RADEON_INFO_WANT_HYPERZ, enable);
278 } else {
279 return FALSE;
280 }
281
282 case RADEON_FID_R300_CMASK_ACCESS:
283 if (debug_get_bool_option("RADEON_CMASK", FALSE)) {
284 return radeon_set_fd_access(cs, &cs->ws->cmask_owner,
285 &cs->ws->cmask_owner_mutex,
286 RADEON_INFO_WANT_CMASK, enable);
287 } else {
288 return FALSE;
289 }
290 }
291 return FALSE;
292 }
293
294 struct radeon_winsys *radeon_drm_winsys_create(int fd)
295 {
296 struct radeon_drm_winsys *ws = CALLOC_STRUCT(radeon_drm_winsys);
297 if (!ws) {
298 return NULL;
299 }
300
301 ws->fd = fd;
302 ws->info.fd = fd;
303
304 if (!do_winsys_init(ws))
305 goto fail;
306
307 /* Create managers. */
308 ws->kman = radeon_bomgr_create(ws);
309 if (!ws->kman)
310 goto fail;
311 ws->cman = pb_cache_manager_create(ws->kman, 1000000);
312 if (!ws->cman)
313 goto fail;
314
315 /* Set functions. */
316 ws->base.destroy = radeon_winsys_destroy;
317 ws->base.query_info = radeon_query_info;
318 ws->base.cs_request_feature = radeon_cs_request_feature;
319
320 radeon_bomgr_init_functions(ws);
321 radeon_drm_cs_init_functions(ws);
322
323 pipe_mutex_init(ws->hyperz_owner_mutex);
324 pipe_mutex_init(ws->cmask_owner_mutex);
325
326 return &ws->base;
327
328 fail:
329 if (ws->cman)
330 ws->cman->destroy(ws->cman);
331 if (ws->kman)
332 ws->kman->destroy(ws->kman);
333 FREE(ws);
334 return NULL;
335 }