aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i830
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-05-28 20:09:59 -0400
committerDave Airlie <airlied@redhat.com>2008-07-13 20:45:01 -0400
commitc0e09200dc0813972442e550a5905a132768e56c (patch)
treed38e635a30ff8b0a2b98b9d7f97cab1501f8209e /drivers/gpu/drm/i830
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
drm: reorganise drm tree to be more future proof.
With the coming of kernel based modesetting and the memory manager stuff, the everything in one directory approach was getting very ugly and starting to be unmanageable. This restructures the drm along the lines of other kernel components. It creates a drivers/gpu/drm directory and moves the hw drivers into subdirectores. It moves the includes into an include/drm, and sets up the unifdef for the userspace headers we should be exporting. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/i830')
-rw-r--r--drivers/gpu/drm/i830/Makefile8
-rw-r--r--drivers/gpu/drm/i830/i830_dma.c1553
-rw-r--r--drivers/gpu/drm/i830/i830_drv.c108
-rw-r--r--drivers/gpu/drm/i830/i830_drv.h292
-rw-r--r--drivers/gpu/drm/i830/i830_irq.c186
5 files changed, 2147 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i830/Makefile b/drivers/gpu/drm/i830/Makefile
new file mode 100644
index 000000000000..c642ee0b238c
--- /dev/null
+++ b/drivers/gpu/drm/i830/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the drm device driver. This driver provides support for the
3# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
4
5ccflags-y := -Iinclude/drm
6i830-y := i830_drv.o i830_dma.o i830_irq.o
7
8obj-$(CONFIG_DRM_I830) += i830.o
diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c
new file mode 100644
index 000000000000..a86ab30b4620
--- /dev/null
+++ b/drivers/gpu/drm/i830/i830_dma.c
@@ -0,0 +1,1553 @@
1/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
2 * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
28 * Jeff Hartmann <jhartmann@valinux.com>
29 * Keith Whitwell <keith@tungstengraphics.com>
30 * Abraham vd Merwe <abraham@2d3d.co.za>
31 *
32 */
33
34#include "drmP.h"
35#include "drm.h"
36#include "i830_drm.h"
37#include "i830_drv.h"
38#include <linux/interrupt.h> /* For task queue support */
39#include <linux/pagemap.h>
40#include <linux/delay.h>
41#include <asm/uaccess.h>
42
43#define I830_BUF_FREE 2
44#define I830_BUF_CLIENT 1
45#define I830_BUF_HARDWARE 0
46
47#define I830_BUF_UNMAPPED 0
48#define I830_BUF_MAPPED 1
49
50static struct drm_buf *i830_freelist_get(struct drm_device * dev)
51{
52 struct drm_device_dma *dma = dev->dma;
53 int i;
54 int used;
55
56 /* Linear search might not be the best solution */
57
58 for (i = 0; i < dma->buf_count; i++) {
59 struct drm_buf *buf = dma->buflist[i];
60 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
61 /* In use is already a pointer */
62 used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
63 I830_BUF_CLIENT);
64 if (used == I830_BUF_FREE) {
65 return buf;
66 }
67 }
68 return NULL;
69}
70
71/* This should only be called if the buffer is not sent to the hardware
72 * yet, the hardware updates in use for us once its on the ring buffer.
73 */
74
75static int i830_freelist_put(struct drm_device * dev, struct drm_buf * buf)
76{
77 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
78 int used;
79
80 /* In use is already a pointer */
81 used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
82 if (used != I830_BUF_CLIENT) {
83 DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
84 return -EINVAL;
85 }
86
87 return 0;
88}
89
90static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
91{
92 struct drm_file *priv = filp->private_data;
93 struct drm_device *dev;
94 drm_i830_private_t *dev_priv;
95 struct drm_buf *buf;
96 drm_i830_buf_priv_t *buf_priv;
97
98 lock_kernel();
99 dev = priv->minor->dev;
100 dev_priv = dev->dev_private;
101 buf = dev_priv->mmap_buffer;
102 buf_priv = buf->dev_private;
103
104 vma->vm_flags |= (VM_IO | VM_DONTCOPY);
105 vma->vm_file = filp;
106
107 buf_priv->currently_mapped = I830_BUF_MAPPED;
108 unlock_kernel();
109
110 if (io_remap_pfn_range(vma, vma->vm_start,
111 vma->vm_pgoff,
112 vma->vm_end - vma->vm_start, vma->vm_page_prot))
113 return -EAGAIN;
114 return 0;
115}
116
117static const struct file_operations i830_buffer_fops = {
118 .open = drm_open,
119 .release = drm_release,
120 .ioctl = drm_ioctl,
121 .mmap = i830_mmap_buffers,
122 .fasync = drm_fasync,
123};
124
125static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
126{
127 struct drm_device *dev = file_priv->minor->dev;
128 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
129 drm_i830_private_t *dev_priv = dev->dev_private;
130 const struct file_operations *old_fops;
131 unsigned long virtual;
132 int retcode = 0;
133
134 if (buf_priv->currently_mapped == I830_BUF_MAPPED)
135 return -EINVAL;
136
137 down_write(&current->mm->mmap_sem);
138 old_fops = file_priv->filp->f_op;
139 file_priv->filp->f_op = &i830_buffer_fops;
140 dev_priv->mmap_buffer = buf;
141 virtual = do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE,
142 MAP_SHARED, buf->bus_address);
143 dev_priv->mmap_buffer = NULL;
144 file_priv->filp->f_op = old_fops;
145 if (IS_ERR((void *)virtual)) { /* ugh */
146 /* Real error */
147 DRM_ERROR("mmap error\n");
148 retcode = PTR_ERR((void *)virtual);
149 buf_priv->virtual = NULL;
150 } else {
151 buf_priv->virtual = (void __user *)virtual;
152 }
153 up_write(&current->mm->mmap_sem);
154
155 return retcode;
156}
157
158static int i830_unmap_buffer(struct drm_buf * buf)
159{
160 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
161 int retcode = 0;
162
163 if (buf_priv->currently_mapped != I830_BUF_MAPPED)
164 return -EINVAL;
165
166 down_write(&current->mm->mmap_sem);
167 retcode = do_munmap(current->mm,
168 (unsigned long)buf_priv->virtual,
169 (size_t) buf->total);
170 up_write(&current->mm->mmap_sem);
171
172 buf_priv->currently_mapped = I830_BUF_UNMAPPED;
173 buf_priv->virtual = NULL;
174
175 return retcode;
176}
177
178static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
179 struct drm_file *file_priv)
180{
181 struct drm_buf *buf;
182 drm_i830_buf_priv_t *buf_priv;
183 int retcode = 0;
184
185 buf = i830_freelist_get(dev);
186 if (!buf) {
187 retcode = -ENOMEM;
188 DRM_DEBUG("retcode=%d\n", retcode);
189 return retcode;
190 }
191
192 retcode = i830_map_buffer(buf, file_priv);
193 if (retcode) {
194 i830_freelist_put(dev, buf);
195 DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
196 return retcode;
197 }
198 buf->file_priv = file_priv;
199 buf_priv = buf->dev_private;
200 d->granted = 1;
201 d->request_idx = buf->idx;
202 d->request_size = buf->total;
203 d->virtual = buf_priv->virtual;
204
205 return retcode;
206}
207
208static int i830_dma_cleanup(struct drm_device * dev)
209{
210 struct drm_device_dma *dma = dev->dma;
211
212 /* Make sure interrupts are disabled here because the uninstall ioctl
213 * may not have been called from userspace and after dev_private
214 * is freed, it's too late.
215 */
216 if (dev->irq_enabled)
217 drm_irq_uninstall(dev);
218
219 if (dev->dev_private) {
220 int i;
221 drm_i830_private_t *dev_priv =
222 (drm_i830_private_t *) dev->dev_private;
223
224 if (dev_priv->ring.virtual_start) {
225 drm_core_ioremapfree(&dev_priv->ring.map, dev);
226 }
227 if (dev_priv->hw_status_page) {
228 pci_free_consistent(dev->pdev, PAGE_SIZE,
229 dev_priv->hw_status_page,
230 dev_priv->dma_status_page);
231 /* Need to rewrite hardware status page */
232 I830_WRITE(0x02080, 0x1ffff000);
233 }
234
235 drm_free(dev->dev_private, sizeof(drm_i830_private_t),
236 DRM_MEM_DRIVER);
237 dev->dev_private = NULL;
238
239 for (i = 0; i < dma->buf_count; i++) {
240 struct drm_buf *buf = dma->buflist[i];
241 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
242 if (buf_priv->kernel_virtual && buf->total)
243 drm_core_ioremapfree(&buf_priv->map, dev);
244 }
245 }
246 return 0;
247}
248
249int i830_wait_ring(struct drm_device * dev, int n, const char *caller)
250{
251 drm_i830_private_t *dev_priv = dev->dev_private;
252 drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
253 int iters = 0;
254 unsigned long end;
255 unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
256
257 end = jiffies + (HZ * 3);
258 while (ring->space < n) {
259 ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
260 ring->space = ring->head - (ring->tail + 8);
261 if (ring->space < 0)
262 ring->space += ring->Size;
263
264 if (ring->head != last_head) {
265 end = jiffies + (HZ * 3);
266 last_head = ring->head;
267 }
268
269 iters++;
270 if (time_before(end, jiffies)) {
271 DRM_ERROR("space: %d wanted %d\n", ring->space, n);
272 DRM_ERROR("lockup\n");
273 goto out_wait_ring;
274 }
275 udelay(1);
276 dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
277 }
278
279 out_wait_ring:
280 return iters;
281}
282
283static void i830_kernel_lost_context(struct drm_device * dev)
284{
285 drm_i830_private_t *dev_priv = dev->dev_private;
286 drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
287
288 ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
289 ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
290 ring->space = ring->head - (ring->tail + 8);
291 if (ring->space < 0)
292 ring->space += ring->Size;
293
294 if (ring->head == ring->tail)
295 dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
296}
297
298static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_priv)
299{
300 struct drm_device_dma *dma = dev->dma;
301 int my_idx = 36;
302 u32 *hw_status = (u32 *) (dev_priv->hw_status_page + my_idx);
303 int i;
304
305 if (dma->buf_count > 1019) {
306 /* Not enough space in the status page for the freelist */
307 return -EINVAL;
308 }
309
310 for (i = 0; i < dma->buf_count; i++) {
311 struct drm_buf *buf = dma->buflist[i];
312 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
313
314 buf_priv->in_use = hw_status++;
315 buf_priv->my_use_idx = my_idx;
316 my_idx += 4;
317
318 *buf_priv->in_use = I830_BUF_FREE;
319
320 buf_priv->map.offset = buf->bus_address;
321 buf_priv->map.size = buf->total;
322 buf_priv->map.type = _DRM_AGP;
323 buf_priv->map.flags = 0;
324 buf_priv->map.mtrr = 0;
325
326 drm_core_ioremap(&buf_priv->map, dev);
327 buf_priv->kernel_virtual = buf_priv->map.handle;
328 }
329 return 0;
330}
331
332static int i830_dma_initialize(struct drm_device * dev,
333 drm_i830_private_t * dev_priv,
334 drm_i830_init_t * init)
335{
336 struct drm_map_list *r_list;
337
338 memset(dev_priv, 0, sizeof(drm_i830_private_t));
339
340 list_for_each_entry(r_list, &dev->maplist, head) {
341 if (r_list->map &&
342 r_list->map->type == _DRM_SHM &&
343 r_list->map->flags & _DRM_CONTAINS_LOCK) {
344 dev_priv->sarea_map = r_list->map;
345 break;
346 }
347 }
348
349 if (!dev_priv->sarea_map) {
350 dev->dev_private = (void *)dev_priv;
351 i830_dma_cleanup(dev);
352 DRM_ERROR("can not find sarea!\n");
353 return -EINVAL;
354 }
355 dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
356 if (!dev_priv->mmio_map) {
357 dev->dev_private = (void *)dev_priv;
358 i830_dma_cleanup(dev);
359 DRM_ERROR("can not find mmio map!\n");
360 return -EINVAL;
361 }
362 dev->agp_buffer_token = init->buffers_offset;
363 dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
364 if (!dev->agp_buffer_map) {
365 dev->dev_private = (void *)dev_priv;
366 i830_dma_cleanup(dev);
367 DRM_ERROR("can not find dma buffer map!\n");
368 return -EINVAL;
369 }
370
371 dev_priv->sarea_priv = (drm_i830_sarea_t *)
372 ((u8 *) dev_priv->sarea_map->handle + init->sarea_priv_offset);
373
374 dev_priv->ring.Start = init->ring_start;
375 dev_priv->ring.End = init->ring_end;
376 dev_priv->ring.Size = init->ring_size;
377
378 dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
379 dev_priv->ring.map.size = init->ring_size;
380 dev_priv->ring.map.type = _DRM_AGP;
381 dev_priv->ring.map.flags = 0;
382 dev_priv->ring.map.mtrr = 0;
383
384 drm_core_ioremap(&dev_priv->ring.map, dev);
385
386 if (dev_priv->ring.map.handle == NULL) {
387 dev->dev_private = (void *)dev_priv;
388 i830_dma_cleanup(dev);
389 DRM_ERROR("can not ioremap virtual address for"
390 " ring buffer\n");
391 return -ENOMEM;
392 }
393
394 dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
395
396 dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
397
398 dev_priv->w = init->w;
399 dev_priv->h = init->h;
400 dev_priv->pitch = init->pitch;
401 dev_priv->back_offset = init->back_offset;
402 dev_priv->depth_offset = init->depth_offset;
403 dev_priv->front_offset = init->front_offset;
404
405 dev_priv->front_di1 = init->front_offset | init->pitch_bits;
406 dev_priv->back_di1 = init->back_offset | init->pitch_bits;
407 dev_priv->zi1 = init->depth_offset | init->pitch_bits;
408
409 DRM_DEBUG("front_di1 %x\n", dev_priv->front_di1);
410 DRM_DEBUG("back_offset %x\n", dev_priv->back_offset);
411 DRM_DEBUG("back_di1 %x\n", dev_priv->back_di1);
412 DRM_DEBUG("pitch_bits %x\n", init->pitch_bits);
413
414 dev_priv->cpp = init->cpp;
415 /* We are using separate values as placeholders for mechanisms for
416 * private backbuffer/depthbuffer usage.
417 */
418
419 dev_priv->back_pitch = init->back_pitch;
420 dev_priv->depth_pitch = init->depth_pitch;
421 dev_priv->do_boxes = 0;
422 dev_priv->use_mi_batchbuffer_start = 0;
423
424 /* Program Hardware Status Page */
425 dev_priv->hw_status_page =
426 pci_alloc_consistent(dev->pdev, PAGE_SIZE,
427 &dev_priv->dma_status_page);
428 if (!dev_priv->hw_status_page) {
429 dev->dev_private = (void *)dev_priv;
430 i830_dma_cleanup(dev);
431 DRM_ERROR("Can not allocate hardware status page\n");
432 return -ENOMEM;
433 }
434 memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
435 DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
436
437 I830_WRITE(0x02080, dev_priv->dma_status_page);
438 DRM_DEBUG("Enabled hardware status page\n");
439
440 /* Now we need to init our freelist */
441 if (i830_freelist_init(dev, dev_priv) != 0) {
442 dev->dev_private = (void *)dev_priv;
443 i830_dma_cleanup(dev);
444 DRM_ERROR("Not enough space in the status page for"
445 " the freelist\n");
446 return -ENOMEM;
447 }
448 dev->dev_private = (void *)dev_priv;
449
450 return 0;
451}
452
453static int i830_dma_init(struct drm_device *dev, void *data,
454 struct drm_file *file_priv)
455{
456 drm_i830_private_t *dev_priv;
457 drm_i830_init_t *init = data;
458 int retcode = 0;
459
460 switch (init->func) {
461 case I830_INIT_DMA:
462 dev_priv = drm_alloc(sizeof(drm_i830_private_t),
463 DRM_MEM_DRIVER);
464 if (dev_priv == NULL)
465 return -ENOMEM;
466 retcode = i830_dma_initialize(dev, dev_priv, init);
467 break;
468 case I830_CLEANUP_DMA:
469 retcode = i830_dma_cleanup(dev);
470 break;
471 default:
472 retcode = -EINVAL;
473 break;
474 }
475
476 return retcode;
477}
478
479#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
480#define ST1_ENABLE (1<<16)
481#define ST1_MASK (0xffff)
482
483/* Most efficient way to verify state for the i830 is as it is
484 * emitted. Non-conformant state is silently dropped.
485 */
486static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code)
487{
488 drm_i830_private_t *dev_priv = dev->dev_private;
489 int i, j = 0;
490 unsigned int tmp;
491 RING_LOCALS;
492
493 BEGIN_LP_RING(I830_CTX_SETUP_SIZE + 4);
494
495 for (i = 0; i < I830_CTXREG_BLENDCOLR0; i++) {
496 tmp = code[i];
497 if ((tmp & (7 << 29)) == CMD_3D &&
498 (tmp & (0x1f << 24)) < (0x1d << 24)) {
499 OUT_RING(tmp);
500 j++;
501 } else {
502 DRM_ERROR("Skipping %d\n", i);
503 }
504 }
505
506 OUT_RING(STATE3D_CONST_BLEND_COLOR_CMD);
507 OUT_RING(code[I830_CTXREG_BLENDCOLR]);
508 j += 2;
509
510 for (i = I830_CTXREG_VF; i < I830_CTXREG_MCSB0; i++) {
511 tmp = code[i];
512 if ((tmp & (7 << 29)) == CMD_3D &&
513 (tmp & (0x1f << 24)) < (0x1d << 24)) {
514 OUT_RING(tmp);
515 j++;
516 } else {
517 DRM_ERROR("Skipping %d\n", i);
518 }
519 }
520
521 OUT_RING(STATE3D_MAP_COORD_SETBIND_CMD);
522 OUT_RING(code[I830_CTXREG_MCSB1]);
523 j += 2;
524
525 if (j & 1)
526 OUT_RING(0);
527
528 ADVANCE_LP_RING();
529}
530
531static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code)
532{
533 drm_i830_private_t *dev_priv = dev->dev_private;
534 int i, j = 0;
535 unsigned int tmp;
536 RING_LOCALS;
537
538 if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
539 (code[I830_TEXREG_MI0] & ~(0xf * LOAD_TEXTURE_MAP0)) ==
540 (STATE3D_LOAD_STATE_IMMEDIATE_2 | 4)) {
541
542 BEGIN_LP_RING(I830_TEX_SETUP_SIZE);
543
544 OUT_RING(code[I830_TEXREG_MI0]); /* TM0LI */
545 OUT_RING(code[I830_TEXREG_MI1]); /* TM0S0 */
546 OUT_RING(code[I830_TEXREG_MI2]); /* TM0S1 */
547 OUT_RING(code[I830_TEXREG_MI3]); /* TM0S2 */
548 OUT_RING(code[I830_TEXREG_MI4]); /* TM0S3 */
549 OUT_RING(code[I830_TEXREG_MI5]); /* TM0S4 */
550
551 for (i = 6; i < I830_TEX_SETUP_SIZE; i++) {
552 tmp = code[i];
553 OUT_RING(tmp);
554 j++;
555 }
556
557 if (j & 1)
558 OUT_RING(0);
559
560 ADVANCE_LP_RING();
561 } else
562 printk("rejected packet %x\n", code[0]);
563}
564
565static void i830EmitTexBlendVerified(struct drm_device * dev,
566 unsigned int *code, unsigned int num)
567{
568 drm_i830_private_t *dev_priv = dev->dev_private;
569 int i, j = 0;
570 unsigned int tmp;
571 RING_LOCALS;
572
573 if (!num)
574 return;
575
576 BEGIN_LP_RING(num + 1);
577
578 for (i = 0; i < num; i++) {
579 tmp = code[i];
580 OUT_RING(tmp);
581 j++;
582 }
583
584 if (j & 1)
585 OUT_RING(0);
586
587 ADVANCE_LP_RING();
588}
589
590static void i830EmitTexPalette(struct drm_device * dev,
591 unsigned int *palette, int number, int is_shared)
592{
593 drm_i830_private_t *dev_priv = dev->dev_private;
594 int i;
595 RING_LOCALS;
596
597 return;
598
599 BEGIN_LP_RING(258);
600
601 if (is_shared == 1) {
602 OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
603 MAP_PALETTE_NUM(0) | MAP_PALETTE_BOTH);
604 } else {
605 OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
606 }
607 for (i = 0; i < 256; i++) {
608 OUT_RING(palette[i]);
609 }
610 OUT_RING(0);
611 /* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop!
612 */
613}
614
615/* Need to do some additional checking when setting the dest buffer.
616 */
617static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code)
618{
619 drm_i830_private_t *dev_priv = dev->dev_private;
620 unsigned int tmp;
621 RING_LOCALS;
622
623 BEGIN_LP_RING(I830_DEST_SETUP_SIZE + 10);
624
625 tmp = code[I830_DESTREG_CBUFADDR];
626 if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
627 if (((int)outring) & 8) {
628 OUT_RING(0);
629 OUT_RING(0);
630 }
631
632 OUT_RING(CMD_OP_DESTBUFFER_INFO);
633 OUT_RING(BUF_3D_ID_COLOR_BACK |
634 BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
635 BUF_3D_USE_FENCE);
636 OUT_RING(tmp);
637 OUT_RING(0);
638
639 OUT_RING(CMD_OP_DESTBUFFER_INFO);
640 OUT_RING(BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE |
641 BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
642 OUT_RING(dev_priv->zi1);
643 OUT_RING(0);
644 } else {
645 DRM_ERROR("bad di1 %x (allow %x or %x)\n",
646 tmp, dev_priv->front_di1, dev_priv->back_di1);
647 }
648
649 /* invarient:
650 */
651
652 OUT_RING(GFX_OP_DESTBUFFER_VARS);
653 OUT_RING(code[I830_DESTREG_DV1]);
654
655 OUT_RING(GFX_OP_DRAWRECT_INFO);
656 OUT_RING(code[I830_DESTREG_DR1]);
657 OUT_RING(code[I830_DESTREG_DR2]);
658 OUT_RING(code[I830_DESTREG_DR3]);
659 OUT_RING(code[I830_DESTREG_DR4]);
660
661 /* Need to verify this */
662 tmp = code[I830_DESTREG_SENABLE];
663 if ((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
664 OUT_RING(tmp);
665 } else {
666 DRM_ERROR("bad scissor enable\n");
667 OUT_RING(0);
668 }
669
670 OUT_RING(GFX_OP_SCISSOR_RECT);
671 OUT_RING(code[I830_DESTREG_SR1]);
672 OUT_RING(code[I830_DESTREG_SR2]);
673 OUT_RING(0);
674
675 ADVANCE_LP_RING();
676}
677
678static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code)
679{
680 drm_i830_private_t *dev_priv = dev->dev_private;
681 RING_LOCALS;
682
683 BEGIN_LP_RING(2);
684 OUT_RING(GFX_OP_STIPPLE);
685 OUT_RING(code[1]);
686 ADVANCE_LP_RING();
687}
688
689static void i830EmitState(struct drm_device * dev)
690{
691 drm_i830_private_t *dev_priv = dev->dev_private;
692 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
693 unsigned int dirty = sarea_priv->dirty;
694
695 DRM_DEBUG("%s %x\n", __func__, dirty);
696
697 if (dirty & I830_UPLOAD_BUFFERS) {
698 i830EmitDestVerified(dev, sarea_priv->BufferState);
699 sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
700 }
701
702 if (dirty & I830_UPLOAD_CTX) {
703 i830EmitContextVerified(dev, sarea_priv->ContextState);
704 sarea_priv->dirty &= ~I830_UPLOAD_CTX;
705 }
706
707 if (dirty & I830_UPLOAD_TEX0) {
708 i830EmitTexVerified(dev, sarea_priv->TexState[0]);
709 sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
710 }
711
712 if (dirty & I830_UPLOAD_TEX1) {
713 i830EmitTexVerified(dev, sarea_priv->TexState[1]);
714 sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
715 }
716
717 if (dirty & I830_UPLOAD_TEXBLEND0) {
718 i830EmitTexBlendVerified(dev, sarea_priv->TexBlendState[0],
719 sarea_priv->TexBlendStateWordsUsed[0]);
720 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
721 }
722
723 if (dirty & I830_UPLOAD_TEXBLEND1) {
724 i830EmitTexBlendVerified(dev, sarea_priv->TexBlendState[1],
725 sarea_priv->TexBlendStateWordsUsed[1]);
726 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
727 }
728
729 if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
730 i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
731 } else {
732 if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
733 i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
734 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
735 }
736 if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
737 i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
738 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
739 }
740
741 /* 1.3:
742 */
743#if 0
744 if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) {
745 i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0);
746 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
747 }
748 if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) {
749 i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0);
750 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
751 }
752#endif
753 }
754
755 /* 1.3:
756 */
757 if (dirty & I830_UPLOAD_STIPPLE) {
758 i830EmitStippleVerified(dev, sarea_priv->StippleState);
759 sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
760 }
761
762 if (dirty & I830_UPLOAD_TEX2) {
763 i830EmitTexVerified(dev, sarea_priv->TexState2);
764 sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
765 }
766
767 if (dirty & I830_UPLOAD_TEX3) {
768 i830EmitTexVerified(dev, sarea_priv->TexState3);
769 sarea_priv->dirty &= ~I830_UPLOAD_TEX3;
770 }
771
772 if (dirty & I830_UPLOAD_TEXBLEND2) {
773 i830EmitTexBlendVerified(dev,
774 sarea_priv->TexBlendState2,
775 sarea_priv->TexBlendStateWordsUsed2);
776
777 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
778 }
779
780 if (dirty & I830_UPLOAD_TEXBLEND3) {
781 i830EmitTexBlendVerified(dev,
782 sarea_priv->TexBlendState3,
783 sarea_priv->TexBlendStateWordsUsed3);
784 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3;
785 }
786}
787
788/* ================================================================
789 * Performance monitoring functions
790 */
791
792static void i830_fill_box(struct drm_device * dev,
793 int x, int y, int w, int h, int r, int g, int b)
794{
795 drm_i830_private_t *dev_priv = dev->dev_private;
796 u32 color;
797 unsigned int BR13, CMD;
798 RING_LOCALS;
799
800 BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1 << 24);
801 CMD = XY_COLOR_BLT_CMD;
802 x += dev_priv->sarea_priv->boxes[0].x1;
803 y += dev_priv->sarea_priv->boxes[0].y1;
804
805 if (dev_priv->cpp == 4) {
806 BR13 |= (1 << 25);
807 CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
808 color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
809 } else {
810 color = (((r & 0xf8) << 8) |
811 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
812 }
813
814 BEGIN_LP_RING(6);
815 OUT_RING(CMD);
816 OUT_RING(BR13);
817 OUT_RING((y << 16) | x);
818 OUT_RING(((y + h) << 16) | (x + w));
819
820 if (dev_priv->current_page == 1) {
821 OUT_RING(dev_priv->front_offset);
822 } else {
823 OUT_RING(dev_priv->back_offset);
824 }
825
826 OUT_RING(color);
827 ADVANCE_LP_RING();
828}
829
830static void i830_cp_performance_boxes(struct drm_device * dev)
831{
832 drm_i830_private_t *dev_priv = dev->dev_private;
833
834 /* Purple box for page flipping
835 */
836 if (dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP)
837 i830_fill_box(dev, 4, 4, 8, 8, 255, 0, 255);
838
839 /* Red box if we have to wait for idle at any point
840 */
841 if (dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT)
842 i830_fill_box(dev, 16, 4, 8, 8, 255, 0, 0);
843
844 /* Blue box: lost context?
845 */
846 if (dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT)
847 i830_fill_box(dev, 28, 4, 8, 8, 0, 0, 255);
848
849 /* Yellow box for texture swaps
850 */
851 if (dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD)
852 i830_fill_box(dev, 40, 4, 8, 8, 255, 255, 0);
853
854 /* Green box if hardware never idles (as far as we can tell)
855 */
856 if (!(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY))
857 i830_fill_box(dev, 64, 4, 8, 8, 0, 255, 0);
858
859 /* Draw bars indicating number of buffers allocated
860 * (not a great measure, easily confused)
861 */
862 if (dev_priv->dma_used) {
863 int bar = dev_priv->dma_used / 10240;
864 if (bar > 100)
865 bar = 100;
866 if (bar < 1)
867 bar = 1;
868 i830_fill_box(dev, 4, 16, bar, 4, 196, 128, 128);
869 dev_priv->dma_used = 0;
870 }
871
872 dev_priv->sarea_priv->perf_boxes = 0;
873}
874
875static void i830_dma_dispatch_clear(struct drm_device * dev, int flags,
876 unsigned int clear_color,
877 unsigned int clear_zval,
878 unsigned int clear_depthmask)
879{
880 drm_i830_private_t *dev_priv = dev->dev_private;
881 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
882 int nbox = sarea_priv->nbox;
883 struct drm_clip_rect *pbox = sarea_priv->boxes;
884 int pitch = dev_priv->pitch;
885 int cpp = dev_priv->cpp;
886 int i;
887 unsigned int BR13, CMD, D_CMD;
888 RING_LOCALS;
889
890 if (dev_priv->current_page == 1) {
891 unsigned int tmp = flags;
892
893 flags &= ~(I830_FRONT | I830_BACK);
894 if (tmp & I830_FRONT)
895 flags |= I830_BACK;
896 if (tmp & I830_BACK)
897 flags |= I830_FRONT;
898 }
899
900 i830_kernel_lost_context(dev);
901
902 switch (cpp) {
903 case 2:
904 BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24);
905 D_CMD = CMD = XY_COLOR_BLT_CMD;
906 break;
907 case 4:
908 BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24) | (1 << 25);
909 CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
910 XY_COLOR_BLT_WRITE_RGB);
911 D_CMD = XY_COLOR_BLT_CMD;
912 if (clear_depthmask & 0x00ffffff)
913 D_CMD |= XY_COLOR_BLT_WRITE_RGB;
914 if (clear_depthmask & 0xff000000)
915 D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
916 break;
917 default:
918 BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24);
919 D_CMD = CMD = XY_COLOR_BLT_CMD;
920 break;
921 }
922
923 if (nbox > I830_NR_SAREA_CLIPRECTS)
924 nbox = I830_NR_SAREA_CLIPRECTS;
925
926 for (i = 0; i < nbox; i++, pbox++) {
927 if (pbox->x1 > pbox->x2 ||
928 pbox->y1 > pbox->y2 ||
929 pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
930 continue;
931
932 if (flags & I830_FRONT) {
933 DRM_DEBUG("clear front\n");
934 BEGIN_LP_RING(6);
935 OUT_RING(CMD);
936 OUT_RING(BR13);
937 OUT_RING((pbox->y1 << 16) | pbox->x1);
938 OUT_RING((pbox->y2 << 16) | pbox->x2);
939 OUT_RING(dev_priv->front_offset);
940 OUT_RING(clear_color);
941 ADVANCE_LP_RING();
942 }
943
944 if (flags & I830_BACK) {
945 DRM_DEBUG("clear back\n");
946 BEGIN_LP_RING(6);
947 OUT_RING(CMD);
948 OUT_RING(BR13);
949 OUT_RING((pbox->y1 << 16) | pbox->x1);
950 OUT_RING((pbox->y2 << 16) | pbox->x2);
951 OUT_RING(dev_priv->back_offset);
952 OUT_RING(clear_color);
953 ADVANCE_LP_RING();
954 }
955
956 if (flags & I830_DEPTH) {
957 DRM_DEBUG("clear depth\n");
958 BEGIN_LP_RING(6);
959 OUT_RING(D_CMD);
960 OUT_RING(BR13);
961 OUT_RING((pbox->y1 << 16) | pbox->x1);
962 OUT_RING((pbox->y2 << 16) | pbox->x2);
963 OUT_RING(dev_priv->depth_offset);
964 OUT_RING(clear_zval);
965 ADVANCE_LP_RING();
966 }
967 }
968}
969
970static void i830_dma_dispatch_swap(struct drm_device * dev)
971{
972 drm_i830_private_t *dev_priv = dev->dev_private;
973 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
974 int nbox = sarea_priv->nbox;
975 struct drm_clip_rect *pbox = sarea_priv->boxes;
976 int pitch = dev_priv->pitch;
977 int cpp = dev_priv->cpp;
978 int i;
979 unsigned int CMD, BR13;
980 RING_LOCALS;
981
982 DRM_DEBUG("swapbuffers\n");
983
984 i830_kernel_lost_context(dev);
985
986 if (dev_priv->do_boxes)
987 i830_cp_performance_boxes(dev);
988
989 switch (cpp) {
990 case 2:
991 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
992 CMD = XY_SRC_COPY_BLT_CMD;
993 break;
994 case 4:
995 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
996 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
997 XY_SRC_COPY_BLT_WRITE_RGB);
998 break;
999 default:
1000 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
1001 CMD = XY_SRC_COPY_BLT_CMD;
1002 break;
1003 }
1004
1005 if (nbox > I830_NR_SAREA_CLIPRECTS)
1006 nbox = I830_NR_SAREA_CLIPRECTS;
1007
1008 for (i = 0; i < nbox; i++, pbox++) {
1009 if (pbox->x1 > pbox->x2 ||
1010 pbox->y1 > pbox->y2 ||
1011 pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
1012 continue;
1013
1014 DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
1015 pbox->x1, pbox->y1, pbox->x2, pbox->y2);
1016
1017 BEGIN_LP_RING(8);
1018 OUT_RING(CMD);
1019 OUT_RING(BR13);
1020 OUT_RING((pbox->y1 << 16) | pbox->x1);
1021 OUT_RING((pbox->y2 << 16) | pbox->x2);
1022
1023 if (dev_priv->current_page == 0)
1024 OUT_RING(dev_priv->front_offset);
1025 else
1026 OUT_RING(dev_priv->back_offset);
1027
1028 OUT_RING((pbox->y1 << 16) | pbox->x1);
1029 OUT_RING(BR13 & 0xffff);
1030
1031 if (dev_priv->current_page == 0)
1032 OUT_RING(dev_priv->back_offset);
1033 else
1034 OUT_RING(dev_priv->front_offset);
1035
1036 ADVANCE_LP_RING();
1037 }
1038}
1039
1040static void i830_dma_dispatch_flip(struct drm_device * dev)
1041{
1042 drm_i830_private_t *dev_priv = dev->dev_private;
1043 RING_LOCALS;
1044
1045 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1046 __func__,
1047 dev_priv->current_page,
1048 dev_priv->sarea_priv->pf_current_page);
1049
1050 i830_kernel_lost_context(dev);
1051
1052 if (dev_priv->do_boxes) {
1053 dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP;
1054 i830_cp_performance_boxes(dev);
1055 }
1056
1057 BEGIN_LP_RING(2);
1058 OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
1059 OUT_RING(0);
1060 ADVANCE_LP_RING();
1061
1062 BEGIN_LP_RING(6);
1063 OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
1064 OUT_RING(0);
1065 if (dev_priv->current_page == 0) {
1066 OUT_RING(dev_priv->back_offset);
1067 dev_priv->current_page = 1;
1068 } else {
1069 OUT_RING(dev_priv->front_offset);
1070 dev_priv->current_page = 0;
1071 }
1072 OUT_RING(0);
1073 ADVANCE_LP_RING();
1074
1075 BEGIN_LP_RING(2);
1076 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
1077 OUT_RING(0);
1078 ADVANCE_LP_RING();
1079
1080 dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1081}
1082
1083static void i830_dma_dispatch_vertex(struct drm_device * dev,
1084 struct drm_buf * buf, int discard, int used)
1085{
1086 drm_i830_private_t *dev_priv = dev->dev_private;
1087 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1088 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
1089 struct drm_clip_rect *box = sarea_priv->boxes;
1090 int nbox = sarea_priv->nbox;
1091 unsigned long address = (unsigned long)buf->bus_address;
1092 unsigned long start = address - dev->agp->base;
1093 int i = 0, u;
1094 RING_LOCALS;
1095
1096 i830_kernel_lost_context(dev);
1097
1098 if (nbox > I830_NR_SAREA_CLIPRECTS)
1099 nbox = I830_NR_SAREA_CLIPRECTS;
1100
1101 if (discard) {
1102 u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1103 I830_BUF_HARDWARE);
1104 if (u != I830_BUF_CLIENT) {
1105 DRM_DEBUG("xxxx 2\n");
1106 }
1107 }
1108
1109 if (used > 4 * 1023)
1110 used = 0;
1111
1112 if (sarea_priv->dirty)
1113 i830EmitState(dev);
1114
1115 DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
1116 address, used, nbox);
1117
1118 dev_priv->counter++;
1119 DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
1120 DRM_DEBUG("i830_dma_dispatch\n");
1121 DRM_DEBUG("start : %lx\n", start);
1122 DRM_DEBUG("used : %d\n", used);
1123 DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
1124
1125 if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
1126 u32 *vp = buf_priv->kernel_virtual;
1127
1128 vp[0] = (GFX_OP_PRIMITIVE |
1129 sarea_priv->vertex_prim | ((used / 4) - 2));
1130
1131 if (dev_priv->use_mi_batchbuffer_start) {
1132 vp[used / 4] = MI_BATCH_BUFFER_END;
1133 used += 4;
1134 }
1135
1136 if (used & 4) {
1137 vp[used / 4] = 0;
1138 used += 4;
1139 }
1140
1141 i830_unmap_buffer(buf);
1142 }
1143
1144 if (used) {
1145 do {
1146 if (i < nbox) {
1147 BEGIN_LP_RING(6);
1148 OUT_RING(GFX_OP_DRAWRECT_INFO);
1149 OUT_RING(sarea_priv->
1150 BufferState[I830_DESTREG_DR1]);
1151 OUT_RING(box[i].x1 | (box[i].y1 << 16));
1152 OUT_RING(box[i].x2 | (box[i].y2 << 16));
1153 OUT_RING(sarea_priv->
1154 BufferState[I830_DESTREG_DR4]);
1155 OUT_RING(0);
1156 ADVANCE_LP_RING();
1157 }
1158
1159 if (dev_priv->use_mi_batchbuffer_start) {
1160 BEGIN_LP_RING(2);
1161 OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
1162 OUT_RING(start | MI_BATCH_NON_SECURE);
1163 ADVANCE_LP_RING();
1164 } else {
1165 BEGIN_LP_RING(4);
1166 OUT_RING(MI_BATCH_BUFFER);
1167 OUT_RING(start | MI_BATCH_NON_SECURE);
1168 OUT_RING(start + used - 4);
1169 OUT_RING(0);
1170 ADVANCE_LP_RING();
1171 }
1172
1173 } while (++i < nbox);
1174 }
1175
1176 if (discard) {
1177 dev_priv->counter++;
1178
1179 (void)cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1180 I830_BUF_HARDWARE);
1181
1182 BEGIN_LP_RING(8);
1183 OUT_RING(CMD_STORE_DWORD_IDX);
1184 OUT_RING(20);
1185 OUT_RING(dev_priv->counter);
1186 OUT_RING(CMD_STORE_DWORD_IDX);
1187 OUT_RING(buf_priv->my_use_idx);
1188 OUT_RING(I830_BUF_FREE);
1189 OUT_RING(CMD_REPORT_HEAD);
1190 OUT_RING(0);
1191 ADVANCE_LP_RING();
1192 }
1193}
1194
1195static void i830_dma_quiescent(struct drm_device * dev)
1196{
1197 drm_i830_private_t *dev_priv = dev->dev_private;
1198 RING_LOCALS;
1199
1200 i830_kernel_lost_context(dev);
1201
1202 BEGIN_LP_RING(4);
1203 OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
1204 OUT_RING(CMD_REPORT_HEAD);
1205 OUT_RING(0);
1206 OUT_RING(0);
1207 ADVANCE_LP_RING();
1208
1209 i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
1210}
1211
1212static int i830_flush_queue(struct drm_device * dev)
1213{
1214 drm_i830_private_t *dev_priv = dev->dev_private;
1215 struct drm_device_dma *dma = dev->dma;
1216 int i, ret = 0;
1217 RING_LOCALS;
1218
1219 i830_kernel_lost_context(dev);
1220
1221 BEGIN_LP_RING(2);
1222 OUT_RING(CMD_REPORT_HEAD);
1223 OUT_RING(0);
1224 ADVANCE_LP_RING();
1225
1226 i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
1227
1228 for (i = 0; i < dma->buf_count; i++) {
1229 struct drm_buf *buf = dma->buflist[i];
1230 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1231
1232 int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE,
1233 I830_BUF_FREE);
1234
1235 if (used == I830_BUF_HARDWARE)
1236 DRM_DEBUG("reclaimed from HARDWARE\n");
1237 if (used == I830_BUF_CLIENT)
1238 DRM_DEBUG("still on client\n");
1239 }
1240
1241 return ret;
1242}
1243
1244/* Must be called with the lock held */
1245static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv)
1246{
1247 struct drm_device_dma *dma = dev->dma;
1248 int i;
1249
1250 if (!dma)
1251 return;
1252 if (!dev->dev_private)
1253 return;
1254 if (!dma->buflist)
1255 return;
1256
1257 i830_flush_queue(dev);
1258
1259 for (i = 0; i < dma->buf_count; i++) {
1260 struct drm_buf *buf = dma->buflist[i];
1261 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1262
1263 if (buf->file_priv == file_priv && buf_priv) {
1264 int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1265 I830_BUF_FREE);
1266
1267 if (used == I830_BUF_CLIENT)
1268 DRM_DEBUG("reclaimed from client\n");
1269 if (buf_priv->currently_mapped == I830_BUF_MAPPED)
1270 buf_priv->currently_mapped = I830_BUF_UNMAPPED;
1271 }
1272 }
1273}
1274
1275static int i830_flush_ioctl(struct drm_device *dev, void *data,
1276 struct drm_file *file_priv)
1277{
1278 LOCK_TEST_WITH_RETURN(dev, file_priv);
1279
1280 i830_flush_queue(dev);
1281 return 0;
1282}
1283
1284static int i830_dma_vertex(struct drm_device *dev, void *data,
1285 struct drm_file *file_priv)
1286{
1287 struct drm_device_dma *dma = dev->dma;
1288 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
1289 u32 *hw_status = dev_priv->hw_status_page;
1290 drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
1291 dev_priv->sarea_priv;
1292 drm_i830_vertex_t *vertex = data;
1293
1294 LOCK_TEST_WITH_RETURN(dev, file_priv);
1295
1296 DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
1297 vertex->idx, vertex->used, vertex->discard);
1298
1299 if (vertex->idx < 0 || vertex->idx > dma->buf_count)
1300 return -EINVAL;
1301
1302 i830_dma_dispatch_vertex(dev,
1303 dma->buflist[vertex->idx],
1304 vertex->discard, vertex->used);
1305
1306 sarea_priv->last_enqueue = dev_priv->counter - 1;
1307 sarea_priv->last_dispatch = (int)hw_status[5];
1308
1309 return 0;
1310}
1311
1312static int i830_clear_bufs(struct drm_device *dev, void *data,
1313 struct drm_file *file_priv)
1314{
1315 drm_i830_clear_t *clear = data;
1316
1317 LOCK_TEST_WITH_RETURN(dev, file_priv);
1318
1319 /* GH: Someone's doing nasty things... */
1320 if (!dev->dev_private) {
1321 return -EINVAL;
1322 }
1323
1324 i830_dma_dispatch_clear(dev, clear->flags,
1325 clear->clear_color,
1326 clear->clear_depth, clear->clear_depthmask);
1327 return 0;
1328}
1329
1330static int i830_swap_bufs(struct drm_device *dev, void *data,
1331 struct drm_file *file_priv)
1332{
1333 DRM_DEBUG("i830_swap_bufs\n");
1334
1335 LOCK_TEST_WITH_RETURN(dev, file_priv);
1336
1337 i830_dma_dispatch_swap(dev);
1338 return 0;
1339}
1340
1341/* Not sure why this isn't set all the time:
1342 */
1343static void i830_do_init_pageflip(struct drm_device * dev)
1344{
1345 drm_i830_private_t *dev_priv = dev->dev_private;
1346
1347 DRM_DEBUG("%s\n", __func__);
1348 dev_priv->page_flipping = 1;
1349 dev_priv->current_page = 0;
1350 dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1351}
1352
1353static int i830_do_cleanup_pageflip(struct drm_device * dev)
1354{
1355 drm_i830_private_t *dev_priv = dev->dev_private;
1356
1357 DRM_DEBUG("%s\n", __func__);
1358 if (dev_priv->current_page != 0)
1359 i830_dma_dispatch_flip(dev);
1360
1361 dev_priv->page_flipping = 0;
1362 return 0;
1363}
1364
1365static int i830_flip_bufs(struct drm_device *dev, void *data,
1366 struct drm_file *file_priv)
1367{
1368 drm_i830_private_t *dev_priv = dev->dev_private;
1369
1370 DRM_DEBUG("%s\n", __func__);
1371
1372 LOCK_TEST_WITH_RETURN(dev, file_priv);
1373
1374 if (!dev_priv->page_flipping)
1375 i830_do_init_pageflip(dev);
1376
1377 i830_dma_dispatch_flip(dev);
1378 return 0;
1379}
1380
1381static int i830_getage(struct drm_device *dev, void *data,
1382 struct drm_file *file_priv)
1383{
1384 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
1385 u32 *hw_status = dev_priv->hw_status_page;
1386 drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
1387 dev_priv->sarea_priv;
1388
1389 sarea_priv->last_dispatch = (int)hw_status[5];
1390 return 0;
1391}
1392
1393static int i830_getbuf(struct drm_device *dev, void *data,
1394 struct drm_file *file_priv)
1395{
1396 int retcode = 0;
1397 drm_i830_dma_t *d = data;
1398 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
1399 u32 *hw_status = dev_priv->hw_status_page;
1400 drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
1401 dev_priv->sarea_priv;
1402
1403 DRM_DEBUG("getbuf\n");
1404
1405 LOCK_TEST_WITH_RETURN(dev, file_priv);
1406
1407 d->granted = 0;
1408
1409 retcode = i830_dma_get_buffer(dev, d, file_priv);
1410
1411 DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
1412 task_pid_nr(current), retcode, d->granted);
1413
1414 sarea_priv->last_dispatch = (int)hw_status[5];
1415
1416 return retcode;
1417}
1418
1419static int i830_copybuf(struct drm_device *dev, void *data,
1420 struct drm_file *file_priv)
1421{
1422 /* Never copy - 2.4.x doesn't need it */
1423 return 0;
1424}
1425
1426static int i830_docopy(struct drm_device *dev, void *data,
1427 struct drm_file *file_priv)
1428{
1429 return 0;
1430}
1431
1432static int i830_getparam(struct drm_device *dev, void *data,
1433 struct drm_file *file_priv)
1434{
1435 drm_i830_private_t *dev_priv = dev->dev_private;
1436 drm_i830_getparam_t *param = data;
1437 int value;
1438
1439 if (!dev_priv) {
1440 DRM_ERROR("%s called with no initialization\n", __func__);
1441 return -EINVAL;
1442 }
1443
1444 switch (param->param) {
1445 case I830_PARAM_IRQ_ACTIVE:
1446 value = dev->irq_enabled;
1447 break;
1448 default:
1449 return -EINVAL;
1450 }
1451
1452 if (copy_to_user(param->value, &value, sizeof(int))) {
1453 DRM_ERROR("copy_to_user\n");
1454 return -EFAULT;
1455 }
1456
1457 return 0;
1458}
1459
1460static int i830_setparam(struct drm_device *dev, void *data,
1461 struct drm_file *file_priv)
1462{
1463 drm_i830_private_t *dev_priv = dev->dev_private;
1464 drm_i830_setparam_t *param = data;
1465
1466 if (!dev_priv) {
1467 DRM_ERROR("%s called with no initialization\n", __func__);
1468 return -EINVAL;
1469 }
1470
1471 switch (param->param) {
1472 case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
1473 dev_priv->use_mi_batchbuffer_start = param->value;
1474 break;
1475 default:
1476 return -EINVAL;
1477 }
1478
1479 return 0;
1480}
1481
1482int i830_driver_load(struct drm_device *dev, unsigned long flags)
1483{
1484 /* i830 has 4 more counters */
1485 dev->counters += 4;
1486 dev->types[6] = _DRM_STAT_IRQ;
1487 dev->types[7] = _DRM_STAT_PRIMARY;
1488 dev->types[8] = _DRM_STAT_SECONDARY;
1489 dev->types[9] = _DRM_STAT_DMA;
1490
1491 return 0;
1492}
1493
1494void i830_driver_lastclose(struct drm_device * dev)
1495{
1496 i830_dma_cleanup(dev);
1497}
1498
1499void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
1500{
1501 if (dev->dev_private) {
1502 drm_i830_private_t *dev_priv = dev->dev_private;
1503 if (dev_priv->page_flipping) {
1504 i830_do_cleanup_pageflip(dev);
1505 }
1506 }
1507}
1508
1509void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv)
1510{
1511 i830_reclaim_buffers(dev, file_priv);
1512}
1513
1514int i830_driver_dma_quiescent(struct drm_device * dev)
1515{
1516 i830_dma_quiescent(dev);
1517 return 0;
1518}
1519
1520struct drm_ioctl_desc i830_ioctls[] = {
1521 DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1522 DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
1523 DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
1524 DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
1525 DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
1526 DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
1527 DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
1528 DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
1529 DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
1530 DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
1531 DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
1532 DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
1533 DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
1534 DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
1535};
1536
1537int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
1538
1539/**
1540 * Determine if the device really is AGP or not.
1541 *
1542 * All Intel graphics chipsets are treated as AGP, even if they are really
1543 * PCI-e.
1544 *
1545 * \param dev The device to be tested.
1546 *
1547 * \returns
1548 * A value of 1 is always retured to indictate every i8xx is AGP.
1549 */
1550int i830_driver_device_is_agp(struct drm_device * dev)
1551{
1552 return 1;
1553}
diff --git a/drivers/gpu/drm/i830/i830_drv.c b/drivers/gpu/drm/i830/i830_drv.c
new file mode 100644
index 000000000000..389597e4a623
--- /dev/null
+++ b/drivers/gpu/drm/i830/i830_drv.c
@@ -0,0 +1,108 @@
1/* i830_drv.c -- I810 driver -*- linux-c -*-
2 * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 * Rickard E. (Rik) Faith <faith@valinux.com>
29 * Jeff Hartmann <jhartmann@valinux.com>
30 * Gareth Hughes <gareth@valinux.com>
31 * Abraham vd Merwe <abraham@2d3d.co.za>
32 * Keith Whitwell <keith@tungstengraphics.com>
33 */
34
35#include "drmP.h"
36#include "drm.h"
37#include "i830_drm.h"
38#include "i830_drv.h"
39
40#include "drm_pciids.h"
41
42static struct pci_device_id pciidlist[] = {
43 i830_PCI_IDS
44};
45
46static struct drm_driver driver = {
47 .driver_features =
48 DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR |
49 DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE,
50#if USE_IRQS
51 .driver_features |= DRIVER_HAVE_IRQ | DRIVER_SHARED_IRQ,
52#endif
53 .dev_priv_size = sizeof(drm_i830_buf_priv_t),
54 .load = i830_driver_load,
55 .lastclose = i830_driver_lastclose,
56 .preclose = i830_driver_preclose,
57 .device_is_agp = i830_driver_device_is_agp,
58 .reclaim_buffers_locked = i830_driver_reclaim_buffers_locked,
59 .dma_quiescent = i830_driver_dma_quiescent,
60 .get_map_ofs = drm_core_get_map_ofs,
61 .get_reg_ofs = drm_core_get_reg_ofs,
62#if USE_IRQS
63 .irq_preinstall = i830_driver_irq_preinstall,
64 .irq_postinstall = i830_driver_irq_postinstall,
65 .irq_uninstall = i830_driver_irq_uninstall,
66 .irq_handler = i830_driver_irq_handler,
67#endif
68 .ioctls = i830_ioctls,
69 .fops = {
70 .owner = THIS_MODULE,
71 .open = drm_open,
72 .release = drm_release,
73 .ioctl = drm_ioctl,
74 .mmap = drm_mmap,
75 .poll = drm_poll,
76 .fasync = drm_fasync,
77 },
78
79 .pci_driver = {
80 .name = DRIVER_NAME,
81 .id_table = pciidlist,
82 },
83
84 .name = DRIVER_NAME,
85 .desc = DRIVER_DESC,
86 .date = DRIVER_DATE,
87 .major = DRIVER_MAJOR,
88 .minor = DRIVER_MINOR,
89 .patchlevel = DRIVER_PATCHLEVEL,
90};
91
92static int __init i830_init(void)
93{
94 driver.num_ioctls = i830_max_ioctl;
95 return drm_init(&driver);
96}
97
98static void __exit i830_exit(void)
99{
100 drm_exit(&driver);
101}
102
103module_init(i830_init);
104module_exit(i830_exit);
105
106MODULE_AUTHOR(DRIVER_AUTHOR);
107MODULE_DESCRIPTION(DRIVER_DESC);
108MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/i830/i830_drv.h b/drivers/gpu/drm/i830/i830_drv.h
new file mode 100644
index 000000000000..b5bf8cc0fdaa
--- /dev/null
+++ b/drivers/gpu/drm/i830/i830_drv.h
@@ -0,0 +1,292 @@
1/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*-
2 * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All rights reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
28 * Jeff Hartmann <jhartmann@valinux.com>
29 *
30 */
31
32#ifndef _I830_DRV_H_
33#define _I830_DRV_H_
34
35/* General customization:
36 */
37
38#define DRIVER_AUTHOR "VA Linux Systems Inc."
39
40#define DRIVER_NAME "i830"
41#define DRIVER_DESC "Intel 830M"
42#define DRIVER_DATE "20021108"
43
44/* Interface history:
45 *
46 * 1.1: Original.
47 * 1.2: ?
48 * 1.3: New irq emit/wait ioctls.
49 * New pageflip ioctl.
50 * New getparam ioctl.
51 * State for texunits 3&4 in sarea.
52 * New (alternative) layout for texture state.
53 */
54#define DRIVER_MAJOR 1
55#define DRIVER_MINOR 3
56#define DRIVER_PATCHLEVEL 2
57
58/* Driver will work either way: IRQ's save cpu time when waiting for
59 * the card, but are subject to subtle interactions between bios,
60 * hardware and the driver.
61 */
62/* XXX: Add vblank support? */
63#define USE_IRQS 0
64
65typedef struct drm_i830_buf_priv {
66 u32 *in_use;
67 int my_use_idx;
68 int currently_mapped;
69 void __user *virtual;
70 void *kernel_virtual;
71 drm_local_map_t map;
72} drm_i830_buf_priv_t;
73
74typedef struct _drm_i830_ring_buffer {
75 int tail_mask;
76 unsigned long Start;
77 unsigned long End;
78 unsigned long Size;
79 u8 *virtual_start;
80 int head;
81 int tail;
82 int space;
83 drm_local_map_t map;
84} drm_i830_ring_buffer_t;
85
86typedef struct drm_i830_private {
87 struct drm_map *sarea_map;
88 struct drm_map *mmio_map;
89
90 drm_i830_sarea_t *sarea_priv;
91 drm_i830_ring_buffer_t ring;
92
93 void *hw_status_page;
94 unsigned long counter;
95
96 dma_addr_t dma_status_page;
97
98 struct drm_buf *mmap_buffer;
99
100 u32 front_di1, back_di1, zi1;
101
102 int back_offset;
103 int depth_offset;
104 int front_offset;
105 int w, h;
106 int pitch;
107 int back_pitch;
108 int depth_pitch;
109 unsigned int cpp;
110
111 int do_boxes;
112 int dma_used;
113
114 int current_page;
115 int page_flipping;
116
117 wait_queue_head_t irq_queue;
118 atomic_t irq_received;
119 atomic_t irq_emitted;
120
121 int use_mi_batchbuffer_start;
122
123} drm_i830_private_t;
124
125extern struct drm_ioctl_desc i830_ioctls[];
126extern int i830_max_ioctl;
127
128/* i830_irq.c */
129extern int i830_irq_emit(struct drm_device *dev, void *data,
130 struct drm_file *file_priv);
131extern int i830_irq_wait(struct drm_device *dev, void *data,
132 struct drm_file *file_priv);
133
134extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
135extern void i830_driver_irq_preinstall(struct drm_device * dev);
136extern void i830_driver_irq_postinstall(struct drm_device * dev);
137extern void i830_driver_irq_uninstall(struct drm_device * dev);
138extern int i830_driver_load(struct drm_device *, unsigned long flags);
139extern void i830_driver_preclose(struct drm_device * dev,
140 struct drm_file *file_priv);
141extern void i830_driver_lastclose(struct drm_device * dev);
142extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev,
143 struct drm_file *file_priv);
144extern int i830_driver_dma_quiescent(struct drm_device * dev);
145extern int i830_driver_device_is_agp(struct drm_device * dev);
146
147#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg)
148#define I830_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val)
149#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg)
150#define I830_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val)
151
152#define I830_VERBOSE 0
153
154#define RING_LOCALS unsigned int outring, ringmask, outcount; \
155 volatile char *virt;
156
157#define BEGIN_LP_RING(n) do { \
158 if (I830_VERBOSE) \
159 printk("BEGIN_LP_RING(%d)\n", (n)); \
160 if (dev_priv->ring.space < n*4) \
161 i830_wait_ring(dev, n*4, __func__); \
162 outcount = 0; \
163 outring = dev_priv->ring.tail; \
164 ringmask = dev_priv->ring.tail_mask; \
165 virt = dev_priv->ring.virtual_start; \
166} while (0)
167
168#define OUT_RING(n) do { \
169 if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \
170 *(volatile unsigned int *)(virt + outring) = n; \
171 outcount++; \
172 outring += 4; \
173 outring &= ringmask; \
174} while (0)
175
176#define ADVANCE_LP_RING() do { \
177 if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \
178 dev_priv->ring.tail = outring; \
179 dev_priv->ring.space -= outcount * 4; \
180 I830_WRITE(LP_RING + RING_TAIL, outring); \
181} while(0)
182
183extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller);
184
185#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
186#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
187#define CMD_REPORT_HEAD (7<<23)
188#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
189#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
190
191#define STATE3D_LOAD_STATE_IMMEDIATE_2 ((0x3<<29)|(0x1d<<24)|(0x03<<16))
192#define LOAD_TEXTURE_MAP0 (1<<11)
193
194#define INST_PARSER_CLIENT 0x00000000
195#define INST_OP_FLUSH 0x02000000
196#define INST_FLUSH_MAP_CACHE 0x00000001
197
198#define BB1_START_ADDR_MASK (~0x7)
199#define BB1_PROTECTED (1<<0)
200#define BB1_UNPROTECTED (0<<0)
201#define BB2_END_ADDR_MASK (~0x7)
202
203#define I830REG_HWSTAM 0x02098
204#define I830REG_INT_IDENTITY_R 0x020a4
205#define I830REG_INT_MASK_R 0x020a8
206#define I830REG_INT_ENABLE_R 0x020a0
207
208#define I830_IRQ_RESERVED ((1<<13)|(3<<2))
209
210#define LP_RING 0x2030
211#define HP_RING 0x2040
212#define RING_TAIL 0x00
213#define TAIL_ADDR 0x001FFFF8
214#define RING_HEAD 0x04
215#define HEAD_WRAP_COUNT 0xFFE00000
216#define HEAD_WRAP_ONE 0x00200000
217#define HEAD_ADDR 0x001FFFFC
218#define RING_START 0x08
219#define START_ADDR 0x0xFFFFF000
220#define RING_LEN 0x0C
221#define RING_NR_PAGES 0x001FF000
222#define RING_REPORT_MASK 0x00000006
223#define RING_REPORT_64K 0x00000002
224#define RING_REPORT_128K 0x00000004
225#define RING_NO_REPORT 0x00000000
226#define RING_VALID_MASK 0x00000001
227#define RING_VALID 0x00000001
228#define RING_INVALID 0x00000000
229
230#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
231#define SC_UPDATE_SCISSOR (0x1<<1)
232#define SC_ENABLE_MASK (0x1<<0)
233#define SC_ENABLE (0x1<<0)
234
235#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
236#define SCI_YMIN_MASK (0xffff<<16)
237#define SCI_XMIN_MASK (0xffff<<0)
238#define SCI_YMAX_MASK (0xffff<<16)
239#define SCI_XMAX_MASK (0xffff<<0)
240
241#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19))
242#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
243#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
244#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
245#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4)
246#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
247#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
248#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24))
249
250#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
251
252#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
253#define ASYNC_FLIP (1<<22)
254
255#define CMD_3D (0x3<<29)
256#define STATE3D_CONST_BLEND_COLOR_CMD (CMD_3D|(0x1d<<24)|(0x88<<16))
257#define STATE3D_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16))
258
259#define BR00_BITBLT_CLIENT 0x40000000
260#define BR00_OP_COLOR_BLT 0x10000000
261#define BR00_OP_SRC_COPY_BLT 0x10C00000
262#define BR13_SOLID_PATTERN 0x80000000
263
264#define BUF_3D_ID_COLOR_BACK (0x3<<24)
265#define BUF_3D_ID_DEPTH (0x7<<24)
266#define BUF_3D_USE_FENCE (1<<23)
267#define BUF_3D_PITCH(x) (((x)/4)<<2)
268
269#define CMD_OP_MAP_PALETTE_LOAD ((3<<29)|(0x1d<<24)|(0x82<<16)|255)
270#define MAP_PALETTE_NUM(x) ((x<<8) & (1<<8))
271#define MAP_PALETTE_BOTH (1<<11)
272
273#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4)
274#define XY_COLOR_BLT_WRITE_ALPHA (1<<21)
275#define XY_COLOR_BLT_WRITE_RGB (1<<20)
276
277#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
278#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
279#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
280
281#define MI_BATCH_BUFFER ((0x30<<23)|1)
282#define MI_BATCH_BUFFER_START (0x31<<23)
283#define MI_BATCH_BUFFER_END (0xA<<23)
284#define MI_BATCH_NON_SECURE (1)
285
286#define MI_WAIT_FOR_EVENT ((0x3<<23))
287#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
288#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
289
290#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23))
291
292#endif
diff --git a/drivers/gpu/drm/i830/i830_irq.c b/drivers/gpu/drm/i830/i830_irq.c
new file mode 100644
index 000000000000..91ec2bb497e9
--- /dev/null
+++ b/drivers/gpu/drm/i830/i830_irq.c
@@ -0,0 +1,186 @@
1/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
2 *
3 * Copyright 2002 Tungsten Graphics, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors: Keith Whitwell <keith@tungstengraphics.com>
26 *
27 */
28
29#include "drmP.h"
30#include "drm.h"
31#include "i830_drm.h"
32#include "i830_drv.h"
33#include <linux/interrupt.h> /* For task queue support */
34#include <linux/delay.h>
35
36irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
37{
38 struct drm_device *dev = (struct drm_device *) arg;
39 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
40 u16 temp;
41
42 temp = I830_READ16(I830REG_INT_IDENTITY_R);
43 DRM_DEBUG("%x\n", temp);
44
45 if (!(temp & 2))
46 return IRQ_NONE;
47
48 I830_WRITE16(I830REG_INT_IDENTITY_R, temp);
49
50 atomic_inc(&dev_priv->irq_received);
51 wake_up_interruptible(&dev_priv->irq_queue);
52
53 return IRQ_HANDLED;
54}
55
56static int i830_emit_irq(struct drm_device * dev)
57{
58 drm_i830_private_t *dev_priv = dev->dev_private;
59 RING_LOCALS;
60
61 DRM_DEBUG("%s\n", __func__);
62
63 atomic_inc(&dev_priv->irq_emitted);
64
65 BEGIN_LP_RING(2);
66 OUT_RING(0);
67 OUT_RING(GFX_OP_USER_INTERRUPT);
68 ADVANCE_LP_RING();
69
70 return atomic_read(&dev_priv->irq_emitted);
71}
72
73static int i830_wait_irq(struct drm_device * dev, int irq_nr)
74{
75 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
76 DECLARE_WAITQUEUE(entry, current);
77 unsigned long end = jiffies + HZ * 3;
78 int ret = 0;
79
80 DRM_DEBUG("%s\n", __func__);
81
82 if (atomic_read(&dev_priv->irq_received) >= irq_nr)
83 return 0;
84
85 dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
86
87 add_wait_queue(&dev_priv->irq_queue, &entry);
88
89 for (;;) {
90 __set_current_state(TASK_INTERRUPTIBLE);
91 if (atomic_read(&dev_priv->irq_received) >= irq_nr)
92 break;
93 if ((signed)(end - jiffies) <= 0) {
94 DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
95 I830_READ16(I830REG_INT_IDENTITY_R),
96 I830_READ16(I830REG_INT_MASK_R),
97 I830_READ16(I830REG_INT_ENABLE_R),
98 I830_READ16(I830REG_HWSTAM));
99
100 ret = -EBUSY; /* Lockup? Missed irq? */
101 break;
102 }
103 schedule_timeout(HZ * 3);
104 if (signal_pending(current)) {
105 ret = -EINTR;
106 break;
107 }
108 }
109
110 __set_current_state(TASK_RUNNING);
111 remove_wait_queue(&dev_priv->irq_queue, &entry);
112 return ret;
113}
114
115/* Needs the lock as it touches the ring.
116 */
117int i830_irq_emit(struct drm_device *dev, void *data,
118 struct drm_file *file_priv)
119{
120 drm_i830_private_t *dev_priv = dev->dev_private;
121 drm_i830_irq_emit_t *emit = data;
122 int result;
123
124 LOCK_TEST_WITH_RETURN(dev, file_priv);
125
126 if (!dev_priv) {
127 DRM_ERROR("%s called with no initialization\n", __func__);
128 return -EINVAL;
129 }
130
131 result = i830_emit_irq(dev);
132
133 if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
134 DRM_ERROR("copy_to_user\n");
135 return -EFAULT;
136 }
137
138 return 0;
139}
140
141/* Doesn't need the hardware lock.
142 */
143int i830_irq_wait(struct drm_device *dev, void *data,
144 struct drm_file *file_priv)
145{
146 drm_i830_private_t *dev_priv = dev->dev_private;
147 drm_i830_irq_wait_t *irqwait = data;
148
149 if (!dev_priv) {
150 DRM_ERROR("%s called with no initialization\n", __func__);
151 return -EINVAL;
152 }
153
154 return i830_wait_irq(dev, irqwait->irq_seq);
155}
156
157/* drm_dma.h hooks
158*/
159void i830_driver_irq_preinstall(struct drm_device * dev)
160{
161 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
162
163 I830_WRITE16(I830REG_HWSTAM, 0xffff);
164 I830_WRITE16(I830REG_INT_MASK_R, 0x0);
165 I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
166 atomic_set(&dev_priv->irq_received, 0);
167 atomic_set(&dev_priv->irq_emitted, 0);
168 init_waitqueue_head(&dev_priv->irq_queue);
169}
170
171void i830_driver_irq_postinstall(struct drm_device * dev)
172{
173 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
174
175 I830_WRITE16(I830REG_INT_ENABLE_R, 0x2);
176}
177
178void i830_driver_irq_uninstall(struct drm_device * dev)
179{
180 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
181 if (!dev_priv)
182 return;
183
184 I830_WRITE16(I830REG_INT_MASK_R, 0xffff);
185 I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
186}