Commit | Line | Data |
---|---|---|
bc5f4523 | 1 | /* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*- |
1da177e4 | 2 | * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com |
f26c473c DA |
3 | */ |
4 | /* | |
1da177e4 LT |
5 | * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. |
6 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | |
7 | * All Rights Reserved. | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | |
10 | * copy of this software and associated documentation files (the "Software"), | |
11 | * to deal in the Software without restriction, including without limitation | |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | * and/or sell copies of the Software, and to permit persons to whom the | |
14 | * Software is furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice (including the next | |
17 | * paragraph) shall be included in all copies or substantial portions of the | |
18 | * Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
23 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
24 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
26 | * DEALINGS IN THE SOFTWARE. | |
27 | * | |
28 | * Authors: | |
29 | * Gareth Hughes <gareth@valinux.com> | |
30 | */ | |
31 | ||
52f97df5 BH |
32 | #include <linux/firmware.h> |
33 | #include <linux/platform_device.h> | |
5a0e3ad6 | 34 | #include <linux/slab.h> |
52f97df5 | 35 | |
1da177e4 LT |
36 | #include "drmP.h" |
37 | #include "drm.h" | |
38 | #include "r128_drm.h" | |
39 | #include "r128_drv.h" | |
40 | ||
41 | #define R128_FIFO_DEBUG 0 | |
42 | ||
52f97df5 BH |
43 | #define FIRMWARE_NAME "r128/r128_cce.bin" |
44 | ||
45 | MODULE_FIRMWARE(FIRMWARE_NAME); | |
1da177e4 | 46 | |
eddca551 | 47 | static int R128_READ_PLL(struct drm_device * dev, int addr) |
1da177e4 LT |
48 | { |
49 | drm_r128_private_t *dev_priv = dev->dev_private; | |
50 | ||
51 | R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); | |
52 | return R128_READ(R128_CLOCK_CNTL_DATA); | |
53 | } | |
54 | ||
55 | #if R128_FIFO_DEBUG | |
b5e89ed5 | 56 | static void r128_status(drm_r128_private_t * dev_priv) |
1da177e4 | 57 | { |
b5e89ed5 DA |
58 | printk("GUI_STAT = 0x%08x\n", |
59 | (unsigned int)R128_READ(R128_GUI_STAT)); | |
60 | printk("PM4_STAT = 0x%08x\n", | |
61 | (unsigned int)R128_READ(R128_PM4_STAT)); | |
62 | printk("PM4_BUFFER_DL_WPTR = 0x%08x\n", | |
63 | (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR)); | |
64 | printk("PM4_BUFFER_DL_RPTR = 0x%08x\n", | |
65 | (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR)); | |
66 | printk("PM4_MICRO_CNTL = 0x%08x\n", | |
67 | (unsigned int)R128_READ(R128_PM4_MICRO_CNTL)); | |
68 | printk("PM4_BUFFER_CNTL = 0x%08x\n", | |
69 | (unsigned int)R128_READ(R128_PM4_BUFFER_CNTL)); | |
1da177e4 LT |
70 | } |
71 | #endif | |
72 | ||
1da177e4 LT |
73 | /* ================================================================ |
74 | * Engine, FIFO control | |
75 | */ | |
76 | ||
b5e89ed5 | 77 | static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv) |
1da177e4 LT |
78 | { |
79 | u32 tmp; | |
80 | int i; | |
81 | ||
b5e89ed5 DA |
82 | tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL; |
83 | R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp); | |
1da177e4 | 84 | |
b5e89ed5 DA |
85 | for (i = 0; i < dev_priv->usec_timeout; i++) { |
86 | if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) { | |
1da177e4 LT |
87 | return 0; |
88 | } | |
b5e89ed5 | 89 | DRM_UDELAY(1); |
1da177e4 LT |
90 | } |
91 | ||
92 | #if R128_FIFO_DEBUG | |
b5e89ed5 | 93 | DRM_ERROR("failed!\n"); |
1da177e4 | 94 | #endif |
20caafa6 | 95 | return -EBUSY; |
1da177e4 LT |
96 | } |
97 | ||
b5e89ed5 | 98 | static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries) |
1da177e4 LT |
99 | { |
100 | int i; | |
101 | ||
b5e89ed5 DA |
102 | for (i = 0; i < dev_priv->usec_timeout; i++) { |
103 | int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; | |
104 | if (slots >= entries) | |
105 | return 0; | |
106 | DRM_UDELAY(1); | |
1da177e4 LT |
107 | } |
108 | ||
109 | #if R128_FIFO_DEBUG | |
b5e89ed5 | 110 | DRM_ERROR("failed!\n"); |
1da177e4 | 111 | #endif |
20caafa6 | 112 | return -EBUSY; |
1da177e4 LT |
113 | } |
114 | ||
b5e89ed5 | 115 | static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv) |
1da177e4 LT |
116 | { |
117 | int i, ret; | |
118 | ||
b5e89ed5 DA |
119 | ret = r128_do_wait_for_fifo(dev_priv, 64); |
120 | if (ret) | |
121 | return ret; | |
1da177e4 | 122 | |
b5e89ed5 DA |
123 | for (i = 0; i < dev_priv->usec_timeout; i++) { |
124 | if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) { | |
125 | r128_do_pixcache_flush(dev_priv); | |
1da177e4 LT |
126 | return 0; |
127 | } | |
b5e89ed5 | 128 | DRM_UDELAY(1); |
1da177e4 LT |
129 | } |
130 | ||
131 | #if R128_FIFO_DEBUG | |
b5e89ed5 | 132 | DRM_ERROR("failed!\n"); |
1da177e4 | 133 | #endif |
20caafa6 | 134 | return -EBUSY; |
1da177e4 LT |
135 | } |
136 | ||
1da177e4 LT |
137 | /* ================================================================ |
138 | * CCE control, initialization | |
139 | */ | |
140 | ||
141 | /* Load the microcode for the CCE */ | |
52f97df5 | 142 | static int r128_cce_load_microcode(drm_r128_private_t *dev_priv) |
1da177e4 | 143 | { |
52f97df5 BH |
144 | struct platform_device *pdev; |
145 | const struct firmware *fw; | |
146 | const __be32 *fw_data; | |
147 | int rc, i; | |
1da177e4 | 148 | |
b5e89ed5 | 149 | DRM_DEBUG("\n"); |
1da177e4 | 150 | |
52f97df5 BH |
151 | pdev = platform_device_register_simple("r128_cce", 0, NULL, 0); |
152 | if (IS_ERR(pdev)) { | |
153 | printk(KERN_ERR "r128_cce: Failed to register firmware\n"); | |
154 | return PTR_ERR(pdev); | |
155 | } | |
156 | rc = request_firmware(&fw, FIRMWARE_NAME, &pdev->dev); | |
157 | platform_device_unregister(pdev); | |
158 | if (rc) { | |
159 | printk(KERN_ERR "r128_cce: Failed to load firmware \"%s\"\n", | |
160 | FIRMWARE_NAME); | |
161 | return rc; | |
162 | } | |
163 | ||
164 | if (fw->size != 256 * 8) { | |
165 | printk(KERN_ERR | |
166 | "r128_cce: Bogus length %zu in firmware \"%s\"\n", | |
167 | fw->size, FIRMWARE_NAME); | |
168 | rc = -EINVAL; | |
169 | goto out_release; | |
170 | } | |
171 | ||
b5e89ed5 | 172 | r128_do_wait_for_idle(dev_priv); |
1da177e4 | 173 | |
52f97df5 | 174 | fw_data = (const __be32 *)fw->data; |
b5e89ed5 DA |
175 | R128_WRITE(R128_PM4_MICROCODE_ADDR, 0); |
176 | for (i = 0; i < 256; i++) { | |
52f97df5 BH |
177 | R128_WRITE(R128_PM4_MICROCODE_DATAH, |
178 | be32_to_cpup(&fw_data[i * 2])); | |
b5e89ed5 | 179 | R128_WRITE(R128_PM4_MICROCODE_DATAL, |
52f97df5 | 180 | be32_to_cpup(&fw_data[i * 2 + 1])); |
1da177e4 | 181 | } |
52f97df5 BH |
182 | |
183 | out_release: | |
184 | release_firmware(fw); | |
185 | return rc; | |
1da177e4 LT |
186 | } |
187 | ||
188 | /* Flush any pending commands to the CCE. This should only be used just | |
189 | * prior to a wait for idle, as it informs the engine that the command | |
190 | * stream is ending. | |
191 | */ | |
b5e89ed5 | 192 | static void r128_do_cce_flush(drm_r128_private_t * dev_priv) |
1da177e4 LT |
193 | { |
194 | u32 tmp; | |
195 | ||
b5e89ed5 DA |
196 | tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE; |
197 | R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp); | |
1da177e4 LT |
198 | } |
199 | ||
200 | /* Wait for the CCE to go idle. | |
201 | */ | |
b5e89ed5 | 202 | int r128_do_cce_idle(drm_r128_private_t * dev_priv) |
1da177e4 LT |
203 | { |
204 | int i; | |
205 | ||
b5e89ed5 DA |
206 | for (i = 0; i < dev_priv->usec_timeout; i++) { |
207 | if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) { | |
208 | int pm4stat = R128_READ(R128_PM4_STAT); | |
209 | if (((pm4stat & R128_PM4_FIFOCNT_MASK) >= | |
210 | dev_priv->cce_fifo_size) && | |
211 | !(pm4stat & (R128_PM4_BUSY | | |
212 | R128_PM4_GUI_ACTIVE))) { | |
213 | return r128_do_pixcache_flush(dev_priv); | |
1da177e4 LT |
214 | } |
215 | } | |
b5e89ed5 | 216 | DRM_UDELAY(1); |
1da177e4 LT |
217 | } |
218 | ||
219 | #if R128_FIFO_DEBUG | |
b5e89ed5 DA |
220 | DRM_ERROR("failed!\n"); |
221 | r128_status(dev_priv); | |
1da177e4 | 222 | #endif |
20caafa6 | 223 | return -EBUSY; |
1da177e4 LT |
224 | } |
225 | ||
226 | /* Start the Concurrent Command Engine. | |
227 | */ | |
b5e89ed5 | 228 | static void r128_do_cce_start(drm_r128_private_t * dev_priv) |
1da177e4 | 229 | { |
b5e89ed5 | 230 | r128_do_wait_for_idle(dev_priv); |
1da177e4 | 231 | |
b5e89ed5 DA |
232 | R128_WRITE(R128_PM4_BUFFER_CNTL, |
233 | dev_priv->cce_mode | dev_priv->ring.size_l2qw | |
234 | | R128_PM4_BUFFER_CNTL_NOUPDATE); | |
235 | R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */ | |
236 | R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN); | |
1da177e4 LT |
237 | |
238 | dev_priv->cce_running = 1; | |
239 | } | |
240 | ||
241 | /* Reset the Concurrent Command Engine. This will not flush any pending | |
242 | * commands, so you must wait for the CCE command stream to complete | |
243 | * before calling this routine. | |
244 | */ | |
b5e89ed5 | 245 | static void r128_do_cce_reset(drm_r128_private_t * dev_priv) |
1da177e4 | 246 | { |
b5e89ed5 DA |
247 | R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); |
248 | R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); | |
1da177e4 LT |
249 | dev_priv->ring.tail = 0; |
250 | } | |
251 | ||
252 | /* Stop the Concurrent Command Engine. This will not flush any pending | |
253 | * commands, so you must flush the command stream and wait for the CCE | |
254 | * to go idle before calling this routine. | |
255 | */ | |
b5e89ed5 | 256 | static void r128_do_cce_stop(drm_r128_private_t * dev_priv) |
1da177e4 | 257 | { |
b5e89ed5 DA |
258 | R128_WRITE(R128_PM4_MICRO_CNTL, 0); |
259 | R128_WRITE(R128_PM4_BUFFER_CNTL, | |
260 | R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE); | |
1da177e4 LT |
261 | |
262 | dev_priv->cce_running = 0; | |
263 | } | |
264 | ||
265 | /* Reset the engine. This will stop the CCE if it is running. | |
266 | */ | |
eddca551 | 267 | static int r128_do_engine_reset(struct drm_device * dev) |
1da177e4 LT |
268 | { |
269 | drm_r128_private_t *dev_priv = dev->dev_private; | |
270 | u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; | |
271 | ||
b5e89ed5 | 272 | r128_do_pixcache_flush(dev_priv); |
1da177e4 | 273 | |
b5e89ed5 DA |
274 | clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX); |
275 | mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL); | |
1da177e4 | 276 | |
b5e89ed5 DA |
277 | R128_WRITE_PLL(R128_MCLK_CNTL, |
278 | mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP); | |
1da177e4 | 279 | |
b5e89ed5 | 280 | gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL); |
1da177e4 LT |
281 | |
282 | /* Taken from the sample code - do not change */ | |
b5e89ed5 DA |
283 | R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); |
284 | R128_READ(R128_GEN_RESET_CNTL); | |
285 | R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI); | |
286 | R128_READ(R128_GEN_RESET_CNTL); | |
1da177e4 | 287 | |
b5e89ed5 DA |
288 | R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl); |
289 | R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index); | |
290 | R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl); | |
1da177e4 LT |
291 | |
292 | /* Reset the CCE ring */ | |
b5e89ed5 | 293 | r128_do_cce_reset(dev_priv); |
1da177e4 LT |
294 | |
295 | /* The CCE is no longer running after an engine reset */ | |
296 | dev_priv->cce_running = 0; | |
297 | ||
298 | /* Reset any pending vertex, indirect buffers */ | |
b5e89ed5 | 299 | r128_freelist_reset(dev); |
1da177e4 LT |
300 | |
301 | return 0; | |
302 | } | |
303 | ||
eddca551 | 304 | static void r128_cce_init_ring_buffer(struct drm_device * dev, |
b5e89ed5 | 305 | drm_r128_private_t * dev_priv) |
1da177e4 LT |
306 | { |
307 | u32 ring_start; | |
308 | u32 tmp; | |
309 | ||
b5e89ed5 | 310 | DRM_DEBUG("\n"); |
1da177e4 LT |
311 | |
312 | /* The manual (p. 2) says this address is in "VM space". This | |
313 | * means it's an offset from the start of AGP space. | |
314 | */ | |
315 | #if __OS_HAS_AGP | |
b5e89ed5 | 316 | if (!dev_priv->is_pci) |
1da177e4 LT |
317 | ring_start = dev_priv->cce_ring->offset - dev->agp->base; |
318 | else | |
319 | #endif | |
b5e89ed5 DA |
320 | ring_start = dev_priv->cce_ring->offset - |
321 | (unsigned long)dev->sg->virtual; | |
1da177e4 | 322 | |
b5e89ed5 | 323 | R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET); |
1da177e4 | 324 | |
b5e89ed5 DA |
325 | R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); |
326 | R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); | |
1da177e4 LT |
327 | |
328 | /* Set watermark control */ | |
b5e89ed5 DA |
329 | R128_WRITE(R128_PM4_BUFFER_WM_CNTL, |
330 | ((R128_WATERMARK_L / 4) << R128_WMA_SHIFT) | |
331 | | ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT) | |
332 | | ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT) | |
333 | | ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT)); | |
1da177e4 LT |
334 | |
335 | /* Force read. Why? Because it's in the examples... */ | |
b5e89ed5 | 336 | R128_READ(R128_PM4_BUFFER_ADDR); |
1da177e4 LT |
337 | |
338 | /* Turn on bus mastering */ | |
b5e89ed5 DA |
339 | tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS; |
340 | R128_WRITE(R128_BUS_CNTL, tmp); | |
1da177e4 LT |
341 | } |
342 | ||
eddca551 | 343 | static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) |
1da177e4 LT |
344 | { |
345 | drm_r128_private_t *dev_priv; | |
52f97df5 | 346 | int rc; |
1da177e4 | 347 | |
b5e89ed5 | 348 | DRM_DEBUG("\n"); |
1da177e4 | 349 | |
7dc482df BH |
350 | if (dev->dev_private) { |
351 | DRM_DEBUG("called when already initialized\n"); | |
352 | return -EINVAL; | |
353 | } | |
354 | ||
9a298b2a | 355 | dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL); |
b5e89ed5 | 356 | if (dev_priv == NULL) |
20caafa6 | 357 | return -ENOMEM; |
1da177e4 | 358 | |
1da177e4 LT |
359 | dev_priv->is_pci = init->is_pci; |
360 | ||
b5e89ed5 DA |
361 | if (dev_priv->is_pci && !dev->sg) { |
362 | DRM_ERROR("PCI GART memory not allocated!\n"); | |
1da177e4 | 363 | dev->dev_private = (void *)dev_priv; |
b5e89ed5 | 364 | r128_do_cleanup_cce(dev); |
20caafa6 | 365 | return -EINVAL; |
1da177e4 LT |
366 | } |
367 | ||
368 | dev_priv->usec_timeout = init->usec_timeout; | |
b5e89ed5 DA |
369 | if (dev_priv->usec_timeout < 1 || |
370 | dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) { | |
371 | DRM_DEBUG("TIMEOUT problem!\n"); | |
1da177e4 | 372 | dev->dev_private = (void *)dev_priv; |
b5e89ed5 | 373 | r128_do_cleanup_cce(dev); |
20caafa6 | 374 | return -EINVAL; |
1da177e4 LT |
375 | } |
376 | ||
377 | dev_priv->cce_mode = init->cce_mode; | |
378 | ||
379 | /* GH: Simple idle check. | |
380 | */ | |
b5e89ed5 | 381 | atomic_set(&dev_priv->idle_count, 0); |
1da177e4 LT |
382 | |
383 | /* We don't support anything other than bus-mastering ring mode, | |
384 | * but the ring can be in either AGP or PCI space for the ring | |
385 | * read pointer. | |
386 | */ | |
b5e89ed5 DA |
387 | if ((init->cce_mode != R128_PM4_192BM) && |
388 | (init->cce_mode != R128_PM4_128BM_64INDBM) && | |
389 | (init->cce_mode != R128_PM4_64BM_128INDBM) && | |
390 | (init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) { | |
391 | DRM_DEBUG("Bad cce_mode!\n"); | |
1da177e4 | 392 | dev->dev_private = (void *)dev_priv; |
b5e89ed5 | 393 | r128_do_cleanup_cce(dev); |
20caafa6 | 394 | return -EINVAL; |
1da177e4 LT |
395 | } |
396 | ||
b5e89ed5 | 397 | switch (init->cce_mode) { |
1da177e4 LT |
398 | case R128_PM4_NONPM4: |
399 | dev_priv->cce_fifo_size = 0; | |
400 | break; | |
401 | case R128_PM4_192PIO: | |
402 | case R128_PM4_192BM: | |
403 | dev_priv->cce_fifo_size = 192; | |
404 | break; | |
405 | case R128_PM4_128PIO_64INDBM: | |
406 | case R128_PM4_128BM_64INDBM: | |
407 | dev_priv->cce_fifo_size = 128; | |
408 | break; | |
409 | case R128_PM4_64PIO_128INDBM: | |
410 | case R128_PM4_64BM_128INDBM: | |
411 | case R128_PM4_64PIO_64VCBM_64INDBM: | |
412 | case R128_PM4_64BM_64VCBM_64INDBM: | |
413 | case R128_PM4_64PIO_64VCPIO_64INDPIO: | |
414 | dev_priv->cce_fifo_size = 64; | |
415 | break; | |
416 | } | |
417 | ||
b5e89ed5 | 418 | switch (init->fb_bpp) { |
1da177e4 LT |
419 | case 16: |
420 | dev_priv->color_fmt = R128_DATATYPE_RGB565; | |
421 | break; | |
422 | case 32: | |
423 | default: | |
424 | dev_priv->color_fmt = R128_DATATYPE_ARGB8888; | |
425 | break; | |
426 | } | |
b5e89ed5 DA |
427 | dev_priv->front_offset = init->front_offset; |
428 | dev_priv->front_pitch = init->front_pitch; | |
429 | dev_priv->back_offset = init->back_offset; | |
430 | dev_priv->back_pitch = init->back_pitch; | |
1da177e4 | 431 | |
b5e89ed5 | 432 | switch (init->depth_bpp) { |
1da177e4 LT |
433 | case 16: |
434 | dev_priv->depth_fmt = R128_DATATYPE_RGB565; | |
435 | break; | |
436 | case 24: | |
437 | case 32: | |
438 | default: | |
439 | dev_priv->depth_fmt = R128_DATATYPE_ARGB8888; | |
440 | break; | |
441 | } | |
b5e89ed5 DA |
442 | dev_priv->depth_offset = init->depth_offset; |
443 | dev_priv->depth_pitch = init->depth_pitch; | |
444 | dev_priv->span_offset = init->span_offset; | |
1da177e4 | 445 | |
b5e89ed5 | 446 | dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) | |
1da177e4 | 447 | (dev_priv->front_offset >> 5)); |
b5e89ed5 | 448 | dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) | |
1da177e4 | 449 | (dev_priv->back_offset >> 5)); |
b5e89ed5 | 450 | dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) | |
1da177e4 LT |
451 | (dev_priv->depth_offset >> 5) | |
452 | R128_DST_TILE); | |
b5e89ed5 | 453 | dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) | |
1da177e4 LT |
454 | (dev_priv->span_offset >> 5)); |
455 | ||
da509d7a | 456 | dev_priv->sarea = drm_getsarea(dev); |
b5e89ed5 | 457 | if (!dev_priv->sarea) { |
1da177e4 LT |
458 | DRM_ERROR("could not find sarea!\n"); |
459 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 460 | r128_do_cleanup_cce(dev); |
20caafa6 | 461 | return -EINVAL; |
1da177e4 LT |
462 | } |
463 | ||
464 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); | |
b5e89ed5 | 465 | if (!dev_priv->mmio) { |
1da177e4 LT |
466 | DRM_ERROR("could not find mmio region!\n"); |
467 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 468 | r128_do_cleanup_cce(dev); |
20caafa6 | 469 | return -EINVAL; |
1da177e4 LT |
470 | } |
471 | dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset); | |
b5e89ed5 | 472 | if (!dev_priv->cce_ring) { |
1da177e4 LT |
473 | DRM_ERROR("could not find cce ring region!\n"); |
474 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 475 | r128_do_cleanup_cce(dev); |
20caafa6 | 476 | return -EINVAL; |
1da177e4 LT |
477 | } |
478 | dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); | |
b5e89ed5 | 479 | if (!dev_priv->ring_rptr) { |
1da177e4 LT |
480 | DRM_ERROR("could not find ring read pointer!\n"); |
481 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 482 | r128_do_cleanup_cce(dev); |
20caafa6 | 483 | return -EINVAL; |
1da177e4 | 484 | } |
d1f2b55a | 485 | dev->agp_buffer_token = init->buffers_offset; |
1da177e4 | 486 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); |
b5e89ed5 | 487 | if (!dev->agp_buffer_map) { |
1da177e4 LT |
488 | DRM_ERROR("could not find dma buffer region!\n"); |
489 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 490 | r128_do_cleanup_cce(dev); |
20caafa6 | 491 | return -EINVAL; |
1da177e4 LT |
492 | } |
493 | ||
b5e89ed5 DA |
494 | if (!dev_priv->is_pci) { |
495 | dev_priv->agp_textures = | |
496 | drm_core_findmap(dev, init->agp_textures_offset); | |
497 | if (!dev_priv->agp_textures) { | |
1da177e4 LT |
498 | DRM_ERROR("could not find agp texture region!\n"); |
499 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 500 | r128_do_cleanup_cce(dev); |
20caafa6 | 501 | return -EINVAL; |
1da177e4 LT |
502 | } |
503 | } | |
504 | ||
505 | dev_priv->sarea_priv = | |
b5e89ed5 DA |
506 | (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle + |
507 | init->sarea_priv_offset); | |
1da177e4 LT |
508 | |
509 | #if __OS_HAS_AGP | |
b5e89ed5 | 510 | if (!dev_priv->is_pci) { |
42beefc0 DA |
511 | drm_core_ioremap_wc(dev_priv->cce_ring, dev); |
512 | drm_core_ioremap_wc(dev_priv->ring_rptr, dev); | |
513 | drm_core_ioremap_wc(dev->agp_buffer_map, dev); | |
b5e89ed5 DA |
514 | if (!dev_priv->cce_ring->handle || |
515 | !dev_priv->ring_rptr->handle || | |
516 | !dev->agp_buffer_map->handle) { | |
1da177e4 LT |
517 | DRM_ERROR("Could not ioremap agp regions!\n"); |
518 | dev->dev_private = (void *)dev_priv; | |
b5e89ed5 | 519 | r128_do_cleanup_cce(dev); |
20caafa6 | 520 | return -ENOMEM; |
1da177e4 LT |
521 | } |
522 | } else | |
523 | #endif | |
524 | { | |
41c2e75e BH |
525 | dev_priv->cce_ring->handle = |
526 | (void *)(unsigned long)dev_priv->cce_ring->offset; | |
1da177e4 | 527 | dev_priv->ring_rptr->handle = |
41c2e75e | 528 | (void *)(unsigned long)dev_priv->ring_rptr->offset; |
b5e89ed5 | 529 | dev->agp_buffer_map->handle = |
41c2e75e | 530 | (void *)(unsigned long)dev->agp_buffer_map->offset; |
1da177e4 LT |
531 | } |
532 | ||
533 | #if __OS_HAS_AGP | |
b5e89ed5 | 534 | if (!dev_priv->is_pci) |
1da177e4 LT |
535 | dev_priv->cce_buffers_offset = dev->agp->base; |
536 | else | |
537 | #endif | |
d1f2b55a | 538 | dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual; |
1da177e4 | 539 | |
b5e89ed5 DA |
540 | dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle; |
541 | dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle | |
1da177e4 LT |
542 | + init->ring_size / sizeof(u32)); |
543 | dev_priv->ring.size = init->ring_size; | |
b5e89ed5 | 544 | dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8); |
1da177e4 | 545 | |
b5e89ed5 | 546 | dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; |
1da177e4 LT |
547 | |
548 | dev_priv->ring.high_mark = 128; | |
549 | ||
550 | dev_priv->sarea_priv->last_frame = 0; | |
b5e89ed5 | 551 | R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); |
1da177e4 LT |
552 | |
553 | dev_priv->sarea_priv->last_dispatch = 0; | |
b5e89ed5 | 554 | R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch); |
1da177e4 LT |
555 | |
556 | #if __OS_HAS_AGP | |
b5e89ed5 | 557 | if (dev_priv->is_pci) { |
1da177e4 | 558 | #endif |
b05c2385 | 559 | dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); |
ea98a92f | 560 | dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; |
f2b04cd2 | 561 | dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE; |
f26c473c DA |
562 | dev_priv->gart_info.addr = NULL; |
563 | dev_priv->gart_info.bus_addr = 0; | |
f2b04cd2 | 564 | dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; |
ea98a92f | 565 | if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { |
b5e89ed5 | 566 | DRM_ERROR("failed to init PCI GART!\n"); |
1da177e4 | 567 | dev->dev_private = (void *)dev_priv; |
b5e89ed5 | 568 | r128_do_cleanup_cce(dev); |
20caafa6 | 569 | return -ENOMEM; |
1da177e4 | 570 | } |
ea98a92f | 571 | R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr); |
1da177e4 LT |
572 | #if __OS_HAS_AGP |
573 | } | |
574 | #endif | |
575 | ||
b5e89ed5 | 576 | r128_cce_init_ring_buffer(dev, dev_priv); |
52f97df5 | 577 | rc = r128_cce_load_microcode(dev_priv); |
1da177e4 LT |
578 | |
579 | dev->dev_private = (void *)dev_priv; | |
580 | ||
b5e89ed5 | 581 | r128_do_engine_reset(dev); |
1da177e4 | 582 | |
52f97df5 BH |
583 | if (rc) { |
584 | DRM_ERROR("Failed to load firmware!\n"); | |
585 | r128_do_cleanup_cce(dev); | |
586 | } | |
587 | ||
588 | return rc; | |
1da177e4 LT |
589 | } |
590 | ||
eddca551 | 591 | int r128_do_cleanup_cce(struct drm_device * dev) |
1da177e4 LT |
592 | { |
593 | ||
594 | /* Make sure interrupts are disabled here because the uninstall ioctl | |
595 | * may not have been called from userspace and after dev_private | |
596 | * is freed, it's too late. | |
597 | */ | |
b5e89ed5 DA |
598 | if (dev->irq_enabled) |
599 | drm_irq_uninstall(dev); | |
1da177e4 | 600 | |
b5e89ed5 | 601 | if (dev->dev_private) { |
1da177e4 LT |
602 | drm_r128_private_t *dev_priv = dev->dev_private; |
603 | ||
604 | #if __OS_HAS_AGP | |
b5e89ed5 DA |
605 | if (!dev_priv->is_pci) { |
606 | if (dev_priv->cce_ring != NULL) | |
607 | drm_core_ioremapfree(dev_priv->cce_ring, dev); | |
608 | if (dev_priv->ring_rptr != NULL) | |
609 | drm_core_ioremapfree(dev_priv->ring_rptr, dev); | |
f26c473c | 610 | if (dev->agp_buffer_map != NULL) { |
b5e89ed5 | 611 | drm_core_ioremapfree(dev->agp_buffer_map, dev); |
f26c473c DA |
612 | dev->agp_buffer_map = NULL; |
613 | } | |
1da177e4 LT |
614 | } else |
615 | #endif | |
616 | { | |
b5e89ed5 DA |
617 | if (dev_priv->gart_info.bus_addr) |
618 | if (!drm_ati_pcigart_cleanup(dev, | |
f26c473c | 619 | &dev_priv->gart_info)) |
b5e89ed5 DA |
620 | DRM_ERROR |
621 | ("failed to cleanup PCI GART!\n"); | |
1da177e4 LT |
622 | } |
623 | ||
9a298b2a | 624 | kfree(dev->dev_private); |
1da177e4 LT |
625 | dev->dev_private = NULL; |
626 | } | |
627 | ||
628 | return 0; | |
629 | } | |
630 | ||
c153f45f | 631 | int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 632 | { |
c153f45f | 633 | drm_r128_init_t *init = data; |
1da177e4 | 634 | |
b5e89ed5 | 635 | DRM_DEBUG("\n"); |
1da177e4 | 636 | |
6c340eac | 637 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 638 | |
c153f45f | 639 | switch (init->func) { |
1da177e4 | 640 | case R128_INIT_CCE: |
c153f45f | 641 | return r128_do_init_cce(dev, init); |
1da177e4 | 642 | case R128_CLEANUP_CCE: |
b5e89ed5 | 643 | return r128_do_cleanup_cce(dev); |
1da177e4 LT |
644 | } |
645 | ||
20caafa6 | 646 | return -EINVAL; |
1da177e4 LT |
647 | } |
648 | ||
c153f45f | 649 | int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 650 | { |
1da177e4 | 651 | drm_r128_private_t *dev_priv = dev->dev_private; |
b5e89ed5 | 652 | DRM_DEBUG("\n"); |
1da177e4 | 653 | |
6c340eac | 654 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 655 | |
7dc482df BH |
656 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
657 | ||
b5e89ed5 | 658 | if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) { |
3e684eae | 659 | DRM_DEBUG("while CCE running\n"); |
1da177e4 LT |
660 | return 0; |
661 | } | |
662 | ||
b5e89ed5 | 663 | r128_do_cce_start(dev_priv); |
1da177e4 LT |
664 | |
665 | return 0; | |
666 | } | |
667 | ||
668 | /* Stop the CCE. The engine must have been idled before calling this | |
669 | * routine. | |
670 | */ | |
c153f45f | 671 | int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 672 | { |
1da177e4 | 673 | drm_r128_private_t *dev_priv = dev->dev_private; |
c153f45f | 674 | drm_r128_cce_stop_t *stop = data; |
1da177e4 | 675 | int ret; |
b5e89ed5 | 676 | DRM_DEBUG("\n"); |
1da177e4 | 677 | |
6c340eac | 678 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 679 | |
7dc482df BH |
680 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
681 | ||
1da177e4 LT |
682 | /* Flush any pending CCE commands. This ensures any outstanding |
683 | * commands are exectuted by the engine before we turn it off. | |
684 | */ | |
c153f45f | 685 | if (stop->flush) { |
b5e89ed5 | 686 | r128_do_cce_flush(dev_priv); |
1da177e4 LT |
687 | } |
688 | ||
689 | /* If we fail to make the engine go idle, we return an error | |
690 | * code so that the DRM ioctl wrapper can try again. | |
691 | */ | |
c153f45f | 692 | if (stop->idle) { |
b5e89ed5 DA |
693 | ret = r128_do_cce_idle(dev_priv); |
694 | if (ret) | |
695 | return ret; | |
1da177e4 LT |
696 | } |
697 | ||
698 | /* Finally, we can turn off the CCE. If the engine isn't idle, | |
699 | * we will get some dropped triangles as they won't be fully | |
700 | * rendered before the CCE is shut down. | |
701 | */ | |
b5e89ed5 | 702 | r128_do_cce_stop(dev_priv); |
1da177e4 LT |
703 | |
704 | /* Reset the engine */ | |
b5e89ed5 | 705 | r128_do_engine_reset(dev); |
1da177e4 LT |
706 | |
707 | return 0; | |
708 | } | |
709 | ||
710 | /* Just reset the CCE ring. Called as part of an X Server engine reset. | |
711 | */ | |
c153f45f | 712 | int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 713 | { |
1da177e4 | 714 | drm_r128_private_t *dev_priv = dev->dev_private; |
b5e89ed5 | 715 | DRM_DEBUG("\n"); |
1da177e4 | 716 | |
6c340eac | 717 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 718 | |
7dc482df | 719 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
1da177e4 | 720 | |
b5e89ed5 | 721 | r128_do_cce_reset(dev_priv); |
1da177e4 LT |
722 | |
723 | /* The CCE is no longer running after an engine reset */ | |
724 | dev_priv->cce_running = 0; | |
725 | ||
726 | return 0; | |
727 | } | |
728 | ||
c153f45f | 729 | int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 730 | { |
1da177e4 | 731 | drm_r128_private_t *dev_priv = dev->dev_private; |
b5e89ed5 | 732 | DRM_DEBUG("\n"); |
1da177e4 | 733 | |
6c340eac | 734 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 735 | |
7dc482df BH |
736 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
737 | ||
b5e89ed5 DA |
738 | if (dev_priv->cce_running) { |
739 | r128_do_cce_flush(dev_priv); | |
1da177e4 LT |
740 | } |
741 | ||
b5e89ed5 | 742 | return r128_do_cce_idle(dev_priv); |
1da177e4 LT |
743 | } |
744 | ||
c153f45f | 745 | int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 746 | { |
b5e89ed5 | 747 | DRM_DEBUG("\n"); |
1da177e4 | 748 | |
6c340eac | 749 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 750 | |
7dc482df BH |
751 | DEV_INIT_TEST_WITH_RETURN(dev->dev_private); |
752 | ||
b5e89ed5 | 753 | return r128_do_engine_reset(dev); |
1da177e4 LT |
754 | } |
755 | ||
c153f45f | 756 | int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 757 | { |
20caafa6 | 758 | return -EINVAL; |
1da177e4 LT |
759 | } |
760 | ||
1da177e4 LT |
761 | /* ================================================================ |
762 | * Freelist management | |
763 | */ | |
764 | #define R128_BUFFER_USED 0xffffffff | |
765 | #define R128_BUFFER_FREE 0 | |
766 | ||
767 | #if 0 | |
eddca551 | 768 | static int r128_freelist_init(struct drm_device * dev) |
1da177e4 | 769 | { |
cdd55a29 | 770 | struct drm_device_dma *dma = dev->dma; |
1da177e4 | 771 | drm_r128_private_t *dev_priv = dev->dev_private; |
056219e2 | 772 | struct drm_buf *buf; |
1da177e4 LT |
773 | drm_r128_buf_priv_t *buf_priv; |
774 | drm_r128_freelist_t *entry; | |
775 | int i; | |
776 | ||
9a298b2a | 777 | dev_priv->head = kzalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL); |
b5e89ed5 | 778 | if (dev_priv->head == NULL) |
20caafa6 | 779 | return -ENOMEM; |
1da177e4 | 780 | |
1da177e4 LT |
781 | dev_priv->head->age = R128_BUFFER_USED; |
782 | ||
b5e89ed5 | 783 | for (i = 0; i < dma->buf_count; i++) { |
1da177e4 LT |
784 | buf = dma->buflist[i]; |
785 | buf_priv = buf->dev_private; | |
786 | ||
9a298b2a | 787 | entry = kmalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL); |
b5e89ed5 | 788 | if (!entry) |
20caafa6 | 789 | return -ENOMEM; |
1da177e4 LT |
790 | |
791 | entry->age = R128_BUFFER_FREE; | |
792 | entry->buf = buf; | |
793 | entry->prev = dev_priv->head; | |
794 | entry->next = dev_priv->head->next; | |
b5e89ed5 | 795 | if (!entry->next) |
1da177e4 LT |
796 | dev_priv->tail = entry; |
797 | ||
798 | buf_priv->discard = 0; | |
799 | buf_priv->dispatched = 0; | |
800 | buf_priv->list_entry = entry; | |
801 | ||
802 | dev_priv->head->next = entry; | |
803 | ||
b5e89ed5 | 804 | if (dev_priv->head->next) |
1da177e4 LT |
805 | dev_priv->head->next->prev = entry; |
806 | } | |
807 | ||
808 | return 0; | |
809 | ||
810 | } | |
811 | #endif | |
812 | ||
056219e2 | 813 | static struct drm_buf *r128_freelist_get(struct drm_device * dev) |
1da177e4 | 814 | { |
cdd55a29 | 815 | struct drm_device_dma *dma = dev->dma; |
1da177e4 LT |
816 | drm_r128_private_t *dev_priv = dev->dev_private; |
817 | drm_r128_buf_priv_t *buf_priv; | |
056219e2 | 818 | struct drm_buf *buf; |
1da177e4 LT |
819 | int i, t; |
820 | ||
821 | /* FIXME: Optimize -- use freelist code */ | |
822 | ||
b5e89ed5 | 823 | for (i = 0; i < dma->buf_count; i++) { |
1da177e4 LT |
824 | buf = dma->buflist[i]; |
825 | buf_priv = buf->dev_private; | |
8da56309 | 826 | if (!buf->file_priv) |
1da177e4 LT |
827 | return buf; |
828 | } | |
829 | ||
b5e89ed5 DA |
830 | for (t = 0; t < dev_priv->usec_timeout; t++) { |
831 | u32 done_age = R128_READ(R128_LAST_DISPATCH_REG); | |
1da177e4 | 832 | |
b5e89ed5 | 833 | for (i = 0; i < dma->buf_count; i++) { |
1da177e4 LT |
834 | buf = dma->buflist[i]; |
835 | buf_priv = buf->dev_private; | |
b5e89ed5 | 836 | if (buf->pending && buf_priv->age <= done_age) { |
1da177e4 LT |
837 | /* The buffer has been processed, so it |
838 | * can now be used. | |
839 | */ | |
840 | buf->pending = 0; | |
841 | return buf; | |
842 | } | |
843 | } | |
b5e89ed5 | 844 | DRM_UDELAY(1); |
1da177e4 LT |
845 | } |
846 | ||
b5e89ed5 | 847 | DRM_DEBUG("returning NULL!\n"); |
1da177e4 LT |
848 | return NULL; |
849 | } | |
850 | ||
eddca551 | 851 | void r128_freelist_reset(struct drm_device * dev) |
1da177e4 | 852 | { |
cdd55a29 | 853 | struct drm_device_dma *dma = dev->dma; |
1da177e4 LT |
854 | int i; |
855 | ||
b5e89ed5 | 856 | for (i = 0; i < dma->buf_count; i++) { |
056219e2 | 857 | struct drm_buf *buf = dma->buflist[i]; |
1da177e4 LT |
858 | drm_r128_buf_priv_t *buf_priv = buf->dev_private; |
859 | buf_priv->age = 0; | |
860 | } | |
861 | } | |
862 | ||
1da177e4 LT |
863 | /* ================================================================ |
864 | * CCE command submission | |
865 | */ | |
866 | ||
b5e89ed5 | 867 | int r128_wait_ring(drm_r128_private_t * dev_priv, int n) |
1da177e4 LT |
868 | { |
869 | drm_r128_ring_buffer_t *ring = &dev_priv->ring; | |
870 | int i; | |
871 | ||
b5e89ed5 DA |
872 | for (i = 0; i < dev_priv->usec_timeout; i++) { |
873 | r128_update_ring_snapshot(dev_priv); | |
874 | if (ring->space >= n) | |
1da177e4 | 875 | return 0; |
b5e89ed5 | 876 | DRM_UDELAY(1); |
1da177e4 LT |
877 | } |
878 | ||
879 | /* FIXME: This is being ignored... */ | |
b5e89ed5 | 880 | DRM_ERROR("failed!\n"); |
20caafa6 | 881 | return -EBUSY; |
1da177e4 LT |
882 | } |
883 | ||
6c340eac EA |
884 | static int r128_cce_get_buffers(struct drm_device * dev, |
885 | struct drm_file *file_priv, | |
886 | struct drm_dma * d) | |
1da177e4 LT |
887 | { |
888 | int i; | |
056219e2 | 889 | struct drm_buf *buf; |
1da177e4 | 890 | |
b5e89ed5 DA |
891 | for (i = d->granted_count; i < d->request_count; i++) { |
892 | buf = r128_freelist_get(dev); | |
893 | if (!buf) | |
20caafa6 | 894 | return -EAGAIN; |
1da177e4 | 895 | |
6c340eac | 896 | buf->file_priv = file_priv; |
1da177e4 | 897 | |
b5e89ed5 DA |
898 | if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, |
899 | sizeof(buf->idx))) | |
20caafa6 | 900 | return -EFAULT; |
b5e89ed5 DA |
901 | if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, |
902 | sizeof(buf->total))) | |
20caafa6 | 903 | return -EFAULT; |
1da177e4 LT |
904 | |
905 | d->granted_count++; | |
906 | } | |
907 | return 0; | |
908 | } | |
909 | ||
c153f45f | 910 | int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 911 | { |
cdd55a29 | 912 | struct drm_device_dma *dma = dev->dma; |
1da177e4 | 913 | int ret = 0; |
c153f45f | 914 | struct drm_dma *d = data; |
1da177e4 | 915 | |
6c340eac | 916 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 917 | |
1da177e4 LT |
918 | /* Please don't send us buffers. |
919 | */ | |
c153f45f | 920 | if (d->send_count != 0) { |
b5e89ed5 | 921 | DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", |
c153f45f | 922 | DRM_CURRENTPID, d->send_count); |
20caafa6 | 923 | return -EINVAL; |
1da177e4 LT |
924 | } |
925 | ||
926 | /* We'll send you buffers. | |
927 | */ | |
c153f45f | 928 | if (d->request_count < 0 || d->request_count > dma->buf_count) { |
b5e89ed5 | 929 | DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", |
c153f45f | 930 | DRM_CURRENTPID, d->request_count, dma->buf_count); |
20caafa6 | 931 | return -EINVAL; |
1da177e4 LT |
932 | } |
933 | ||
c153f45f | 934 | d->granted_count = 0; |
1da177e4 | 935 | |
c153f45f EA |
936 | if (d->request_count) { |
937 | ret = r128_cce_get_buffers(dev, file_priv, d); | |
1da177e4 LT |
938 | } |
939 | ||
1da177e4 LT |
940 | return ret; |
941 | } |