i915_dma.c revision 184373
1145132Sanholt/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
2145132Sanholt */
3152909Sanholt/*-
4145132Sanholt * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
5145132Sanholt * All Rights Reserved.
6182080Srnoland *
7152909Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
8152909Sanholt * copy of this software and associated documentation files (the
9152909Sanholt * "Software"), to deal in the Software without restriction, including
10152909Sanholt * without limitation the rights to use, copy, modify, merge, publish,
11152909Sanholt * distribute, sub license, and/or sell copies of the Software, and to
12152909Sanholt * permit persons to whom the Software is furnished to do so, subject to
13152909Sanholt * the following conditions:
14182080Srnoland *
15152909Sanholt * The above copyright notice and this permission notice (including the
16152909Sanholt * next paragraph) shall be included in all copies or substantial portions
17152909Sanholt * of the Software.
18182080Srnoland *
19152909Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20152909Sanholt * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21152909Sanholt * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22152909Sanholt * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23152909Sanholt * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24152909Sanholt * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25152909Sanholt * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26182080Srnoland *
27152909Sanholt */
28145132Sanholt
29152909Sanholt#include <sys/cdefs.h>
30152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/i915_dma.c 184373 2008-10-27 21:16:07Z rnoland $");
31145132Sanholt
32152909Sanholt#include "dev/drm/drmP.h"
33152909Sanholt#include "dev/drm/drm.h"
34152909Sanholt#include "dev/drm/i915_drm.h"
35152909Sanholt#include "dev/drm/i915_drv.h"
36152909Sanholt
37145132Sanholt/* Really want an OS-independent resettable timer.  Would like to have
38145132Sanholt * this loop run for (eg) 3 sec, but have the timer reset every time
39145132Sanholt * the head pointer changes, so that EBUSY only happens if the ring
40145132Sanholt * actually stalls for (eg) 3 seconds.
41145132Sanholt */
42182080Srnolandint i915_wait_ring(struct drm_device * dev, int n, const char *caller)
43145132Sanholt{
44145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
45145132Sanholt	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
46182080Srnoland	u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
47183573Srnoland	u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
48183573Srnoland	u32 last_acthd = I915_READ(acthd_reg);
49183573Srnoland	u32 acthd;
50145132Sanholt	int i;
51145132Sanholt
52183573Srnoland	for (i = 0; i < 100000; i++) {
53182080Srnoland		ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
54183573Srnoland		acthd = I915_READ(acthd_reg);
55145132Sanholt		ring->space = ring->head - (ring->tail + 8);
56145132Sanholt		if (ring->space < 0)
57145132Sanholt			ring->space += ring->Size;
58145132Sanholt		if (ring->space >= n)
59145132Sanholt			return 0;
60145132Sanholt
61145132Sanholt		if (ring->head != last_head)
62145132Sanholt			i = 0;
63145132Sanholt
64183573Srnoland		if (acthd != last_acthd)
65183573Srnoland			i = 0;
66183573Srnoland
67145132Sanholt		last_head = ring->head;
68183573Srnoland		last_acthd = acthd;
69183573Srnoland		DRM_UDELAY(10 * 1000);
70145132Sanholt	}
71145132Sanholt
72182080Srnoland	return -EBUSY;
73145132Sanholt}
74145132Sanholt
75183573Srnolandint i915_init_hardware_status(struct drm_device *dev)
76183573Srnoland{
77183573Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
78183573Srnoland	drm_dma_handle_t *dmah;
79183573Srnoland
80183573Srnoland	/* Program Hardware Status Page */
81183573Srnoland#ifdef __FreeBSD__
82183573Srnoland	DRM_UNLOCK();
83183573Srnoland#endif
84183573Srnoland	dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
85183573Srnoland#ifdef __FreeBSD__
86183573Srnoland	DRM_LOCK();
87183573Srnoland#endif
88183573Srnoland	if (!dmah) {
89183573Srnoland		DRM_ERROR("Can not allocate hardware status page\n");
90183573Srnoland		return -ENOMEM;
91183573Srnoland	}
92183573Srnoland
93183573Srnoland	dev_priv->status_page_dmah = dmah;
94183573Srnoland	dev_priv->hw_status_page = dmah->vaddr;
95183573Srnoland	dev_priv->dma_status_page = dmah->busaddr;
96183573Srnoland
97183573Srnoland	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
98183573Srnoland
99183573Srnoland	I915_WRITE(0x02080, dev_priv->dma_status_page);
100183573Srnoland	DRM_DEBUG("Enabled hardware status page\n");
101183573Srnoland	return 0;
102183573Srnoland}
103183573Srnoland
104183573Srnolandvoid i915_free_hardware_status(struct drm_device *dev)
105183573Srnoland{
106183573Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
107183573Srnoland	if (dev_priv->status_page_dmah) {
108183573Srnoland		drm_pci_free(dev, dev_priv->status_page_dmah);
109183573Srnoland		dev_priv->status_page_dmah = NULL;
110183573Srnoland		/* Need to rewrite hardware status page */
111183573Srnoland		I915_WRITE(0x02080, 0x1ffff000);
112183573Srnoland	}
113183573Srnoland
114183573Srnoland	if (dev_priv->status_gfx_addr) {
115183573Srnoland		dev_priv->status_gfx_addr = 0;
116183573Srnoland		drm_core_ioremapfree(&dev_priv->hws_map, dev);
117183573Srnoland		I915_WRITE(0x02080, 0x1ffff000);
118183573Srnoland	}
119183573Srnoland}
120183573Srnoland
121183573Srnoland#if I915_RING_VALIDATE
122183573Srnoland/**
123183573Srnoland * Validate the cached ring tail value
124183573Srnoland *
125183573Srnoland * If the X server writes to the ring and DRM doesn't
126183573Srnoland * reload the head and tail pointers, it will end up writing
127183573Srnoland * data to the wrong place in the ring, causing havoc.
128183573Srnoland */
129183573Srnolandvoid i915_ring_validate(struct drm_device *dev, const char *func, int line)
130183573Srnoland{
131183573Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
132183573Srnoland	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
133183573Srnoland	u32	tail = I915_READ(PRB0_TAIL) & HEAD_ADDR;
134183573Srnoland	u32	head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
135183573Srnoland
136183573Srnoland	if (tail != ring->tail) {
137183573Srnoland		DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n",
138183573Srnoland			  func, line,
139183573Srnoland			  ring->head, head, ring->tail, tail);
140183573Srnoland#ifdef __linux__
141183573Srnoland		BUG_ON(1);
142183573Srnoland#endif
143183573Srnoland	}
144183573Srnoland}
145183573Srnoland#endif
146183573Srnoland
147182080Srnolandvoid i915_kernel_lost_context(struct drm_device * dev)
148145132Sanholt{
149145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
150145132Sanholt	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
151145132Sanholt
152182080Srnoland	ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
153182080Srnoland	ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
154145132Sanholt	ring->space = ring->head - (ring->tail + 8);
155145132Sanholt	if (ring->space < 0)
156145132Sanholt		ring->space += ring->Size;
157145132Sanholt}
158145132Sanholt
159182080Srnolandstatic int i915_dma_cleanup(struct drm_device * dev)
160145132Sanholt{
161182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
162145132Sanholt	/* Make sure interrupts are disabled here because the uninstall ioctl
163145132Sanholt	 * may not have been called from userspace and after dev_private
164145132Sanholt	 * is freed, it's too late.
165145132Sanholt	 */
166183573Srnoland	if (dev->irq_enabled)
167145132Sanholt		drm_irq_uninstall(dev);
168145132Sanholt
169182080Srnoland	if (dev_priv->ring.virtual_start) {
170182080Srnoland		drm_core_ioremapfree(&dev_priv->ring.map, dev);
171182080Srnoland		dev_priv->ring.virtual_start = 0;
172182080Srnoland		dev_priv->ring.map.handle = 0;
173182080Srnoland		dev_priv->ring.map.size = 0;
174182080Srnoland	}
175145132Sanholt
176183573Srnoland	if (I915_NEED_GFX_HWS(dev))
177183573Srnoland		i915_free_hardware_status(dev);
178145132Sanholt
179145132Sanholt	return 0;
180145132Sanholt}
181145132Sanholt
182182080Srnoland#if defined(I915_HAVE_BUFFER)
183182080Srnoland#define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16)
184182080Srnoland#define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff)
185182080Srnoland#define DRI2_SAREA_BLOCK_NEXT(p)				\
186182080Srnoland	((void *) ((unsigned char *) (p) +			\
187182080Srnoland		   DRI2_SAREA_BLOCK_SIZE(*(unsigned int *) p)))
188182080Srnoland
189182080Srnoland#define DRI2_SAREA_BLOCK_END		0x0000
190182080Srnoland#define DRI2_SAREA_BLOCK_LOCK		0x0001
191182080Srnoland#define DRI2_SAREA_BLOCK_EVENT_BUFFER	0x0002
192182080Srnoland
193182080Srnolandstatic int
194182080Srnolandsetup_dri2_sarea(struct drm_device * dev,
195182080Srnoland		 struct drm_file *file_priv,
196182080Srnoland		 drm_i915_init_t * init)
197145132Sanholt{
198182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
199182080Srnoland	int ret;
200182080Srnoland	unsigned int *p, *end, *next;
201171394Skib
202182080Srnoland	mutex_lock(&dev->struct_mutex);
203182080Srnoland	dev_priv->sarea_bo =
204182080Srnoland		drm_lookup_buffer_object(file_priv,
205182080Srnoland					 init->sarea_handle, 1);
206182080Srnoland	mutex_unlock(&dev->struct_mutex);
207182080Srnoland
208182080Srnoland	if (!dev_priv->sarea_bo) {
209182080Srnoland		DRM_ERROR("did not find sarea bo\n");
210182080Srnoland		return -EINVAL;
211171394Skib	}
212171394Skib
213182080Srnoland	ret = drm_bo_kmap(dev_priv->sarea_bo, 0,
214182080Srnoland			  dev_priv->sarea_bo->num_pages,
215182080Srnoland			  &dev_priv->sarea_kmap);
216182080Srnoland	if (ret) {
217182080Srnoland		DRM_ERROR("could not map sarea bo\n");
218182080Srnoland		return ret;
219182080Srnoland	}
220145132Sanholt
221182080Srnoland	p = dev_priv->sarea_kmap.virtual;
222182080Srnoland	end = (void *) p + (dev_priv->sarea_bo->num_pages << PAGE_SHIFT);
223182080Srnoland	while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) {
224182080Srnoland		switch (DRI2_SAREA_BLOCK_TYPE(*p)) {
225182080Srnoland		case DRI2_SAREA_BLOCK_LOCK:
226182080Srnoland			dev->lock.hw_lock = (void *) (p + 1);
227182080Srnoland			dev->sigdata.lock = dev->lock.hw_lock;
228182080Srnoland			break;
229182080Srnoland		}
230182080Srnoland		next = DRI2_SAREA_BLOCK_NEXT(p);
231182080Srnoland		if (next <= p || end < next) {
232182080Srnoland			DRM_ERROR("malformed dri2 sarea: next is %p should be within %p-%p\n",
233182080Srnoland				  next, p, end);
234182080Srnoland			return -EINVAL;
235182080Srnoland		}
236182080Srnoland		p = next;
237182080Srnoland	}
238182080Srnoland
239182080Srnoland	return 0;
240182080Srnoland}
241182080Srnoland#endif
242182080Srnoland
243182080Srnolandstatic int i915_initialize(struct drm_device * dev,
244182080Srnoland			   struct drm_file *file_priv,
245182080Srnoland			   drm_i915_init_t * init)
246182080Srnoland{
247182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
248182080Srnoland#if defined(I915_HAVE_BUFFER)
249182080Srnoland	int ret;
250182080Srnoland#endif
251182080Srnoland	dev_priv->sarea = drm_getsarea(dev);
252145132Sanholt	if (!dev_priv->sarea) {
253145132Sanholt		DRM_ERROR("can not find sarea!\n");
254145132Sanholt		i915_dma_cleanup(dev);
255182080Srnoland		return -EINVAL;
256145132Sanholt	}
257145132Sanholt
258182080Srnoland#ifdef I915_HAVE_BUFFER
259182080Srnoland	dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS;
260182080Srnoland#endif
261145132Sanholt
262182080Srnoland	if (init->sarea_priv_offset)
263182080Srnoland		dev_priv->sarea_priv = (drm_i915_sarea_t *)
264182080Srnoland			((u8 *) dev_priv->sarea->handle +
265182080Srnoland			 init->sarea_priv_offset);
266182080Srnoland	else {
267182080Srnoland		/* No sarea_priv for you! */
268182080Srnoland		dev_priv->sarea_priv = NULL;
269182080Srnoland	}
270182080Srnoland
271183573Srnoland	if (init->ring_size != 0) {
272183573Srnoland		dev_priv->ring.Size = init->ring_size;
273183573Srnoland		dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
274145132Sanholt
275183573Srnoland		dev_priv->ring.map.offset = init->ring_start;
276183573Srnoland		dev_priv->ring.map.size = init->ring_size;
277183573Srnoland		dev_priv->ring.map.type = 0;
278183573Srnoland		dev_priv->ring.map.flags = 0;
279183573Srnoland		dev_priv->ring.map.mtrr = 0;
280145132Sanholt
281183573Srnoland		drm_core_ioremap(&dev_priv->ring.map, dev);
282145132Sanholt
283183573Srnoland		if (dev_priv->ring.map.handle == NULL) {
284183573Srnoland			i915_dma_cleanup(dev);
285183573Srnoland			DRM_ERROR("can not ioremap virtual address for"
286183573Srnoland				  " ring buffer\n");
287183573Srnoland			return -ENOMEM;
288183573Srnoland		}
289183573Srnoland
290183573Srnoland		dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
291145132Sanholt	}
292145132Sanholt
293182080Srnoland	dev_priv->cpp = init->cpp;
294145132Sanholt
295182080Srnoland	if (dev_priv->sarea_priv)
296182080Srnoland		dev_priv->sarea_priv->pf_current_page = 0;
297182080Srnoland
298145132Sanholt	/* We are using separate values as placeholders for mechanisms for
299145132Sanholt	 * private backbuffer/depthbuffer usage.
300145132Sanholt	 */
301145132Sanholt
302145132Sanholt	/* Allow hardware batchbuffers unless told otherwise.
303145132Sanholt	 */
304145132Sanholt	dev_priv->allow_batchbuffer = 1;
305145132Sanholt
306182080Srnoland	/* Enable vblank on pipe A for older X servers
307182080Srnoland	 */
308182080Srnoland	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
309182080Srnoland
310182080Srnoland#ifdef I915_HAVE_BUFFER
311182080Srnoland	mutex_init(&dev_priv->cmdbuf_mutex);
312182080Srnoland#endif
313182080Srnoland#if defined(I915_HAVE_BUFFER)
314182080Srnoland	if (init->func == I915_INIT_DMA2) {
315182080Srnoland		ret = setup_dri2_sarea(dev, file_priv, init);
316182080Srnoland		if (ret) {
317182080Srnoland			i915_dma_cleanup(dev);
318182080Srnoland			DRM_ERROR("could not set up dri2 sarea\n");
319182080Srnoland			return ret;
320182080Srnoland		}
321182080Srnoland	}
322182080Srnoland#endif
323145132Sanholt
324145132Sanholt	return 0;
325145132Sanholt}
326145132Sanholt
327182080Srnolandstatic int i915_dma_resume(struct drm_device * dev)
328145132Sanholt{
329145132Sanholt	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
330145132Sanholt
331182080Srnoland	DRM_DEBUG("\n");
332145132Sanholt
333145132Sanholt	if (!dev_priv->sarea) {
334145132Sanholt		DRM_ERROR("can not find sarea!\n");
335182080Srnoland		return -EINVAL;
336145132Sanholt	}
337145132Sanholt
338145132Sanholt	if (dev_priv->ring.map.handle == NULL) {
339145132Sanholt		DRM_ERROR("can not ioremap virtual address for"
340145132Sanholt			  " ring buffer\n");
341182080Srnoland		return -ENOMEM;
342145132Sanholt	}
343145132Sanholt
344145132Sanholt	/* Program Hardware Status Page */
345145132Sanholt	if (!dev_priv->hw_status_page) {
346145132Sanholt		DRM_ERROR("Can not find hardware status page\n");
347182080Srnoland		return -EINVAL;
348145132Sanholt	}
349145132Sanholt	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
350145132Sanholt
351182080Srnoland	if (dev_priv->status_gfx_addr != 0)
352182080Srnoland		I915_WRITE(0x02080, dev_priv->status_gfx_addr);
353182080Srnoland	else
354182080Srnoland		I915_WRITE(0x02080, dev_priv->dma_status_page);
355145132Sanholt	DRM_DEBUG("Enabled hardware status page\n");
356145132Sanholt
357145132Sanholt	return 0;
358145132Sanholt}
359145132Sanholt
360182080Srnolandstatic int i915_dma_init(struct drm_device *dev, void *data,
361182080Srnoland			 struct drm_file *file_priv)
362145132Sanholt{
363182080Srnoland	drm_i915_init_t *init = data;
364145132Sanholt	int retcode = 0;
365145132Sanholt
366182080Srnoland	switch (init->func) {
367145132Sanholt	case I915_INIT_DMA:
368182080Srnoland	case I915_INIT_DMA2:
369182080Srnoland		retcode = i915_initialize(dev, file_priv, init);
370145132Sanholt		break;
371145132Sanholt	case I915_CLEANUP_DMA:
372145132Sanholt		retcode = i915_dma_cleanup(dev);
373145132Sanholt		break;
374145132Sanholt	case I915_RESUME_DMA:
375145132Sanholt		retcode = i915_dma_resume(dev);
376145132Sanholt		break;
377145132Sanholt	default:
378145132Sanholt		retcode = -EINVAL;
379145132Sanholt		break;
380145132Sanholt	}
381145132Sanholt
382145132Sanholt	return retcode;
383145132Sanholt}
384145132Sanholt
385145132Sanholt/* Implement basically the same security restrictions as hardware does
386145132Sanholt * for MI_BATCH_NON_SECURE.  These can be made stricter at any time.
387145132Sanholt *
388145132Sanholt * Most of the calculations below involve calculating the size of a
389145132Sanholt * particular instruction.  It's important to get the size right as
390145132Sanholt * that tells us where the next instruction to check is.  Any illegal
391145132Sanholt * instruction detected will be given a size of zero, which is a
392145132Sanholt * signal to abort the rest of the buffer.
393145132Sanholt */
394145132Sanholtstatic int do_validate_cmd(int cmd)
395145132Sanholt{
396145132Sanholt	switch (((cmd >> 29) & 0x7)) {
397145132Sanholt	case 0x0:
398145132Sanholt		switch ((cmd >> 23) & 0x3f) {
399145132Sanholt		case 0x0:
400145132Sanholt			return 1;	/* MI_NOOP */
401145132Sanholt		case 0x4:
402145132Sanholt			return 1;	/* MI_FLUSH */
403145132Sanholt		default:
404145132Sanholt			return 0;	/* disallow everything else */
405145132Sanholt		}
406145132Sanholt		break;
407145132Sanholt	case 0x1:
408145132Sanholt		return 0;	/* reserved */
409145132Sanholt	case 0x2:
410145132Sanholt		return (cmd & 0xff) + 2;	/* 2d commands */
411145132Sanholt	case 0x3:
412145132Sanholt		if (((cmd >> 24) & 0x1f) <= 0x18)
413145132Sanholt			return 1;
414145132Sanholt
415145132Sanholt		switch ((cmd >> 24) & 0x1f) {
416145132Sanholt		case 0x1c:
417145132Sanholt			return 1;
418145132Sanholt		case 0x1d:
419145132Sanholt			switch ((cmd >> 16) & 0xff) {
420145132Sanholt			case 0x3:
421145132Sanholt				return (cmd & 0x1f) + 2;
422145132Sanholt			case 0x4:
423145132Sanholt				return (cmd & 0xf) + 2;
424145132Sanholt			default:
425145132Sanholt				return (cmd & 0xffff) + 2;
426145132Sanholt			}
427145132Sanholt		case 0x1e:
428145132Sanholt			if (cmd & (1 << 23))
429145132Sanholt				return (cmd & 0xffff) + 1;
430145132Sanholt			else
431145132Sanholt				return 1;
432145132Sanholt		case 0x1f:
433145132Sanholt			if ((cmd & (1 << 23)) == 0)	/* inline vertices */
434145132Sanholt				return (cmd & 0x1ffff) + 2;
435145132Sanholt			else if (cmd & (1 << 17))	/* indirect random */
436145132Sanholt				if ((cmd & 0xffff) == 0)
437145132Sanholt					return 0;	/* unknown length, too hard */
438145132Sanholt				else
439145132Sanholt					return (((cmd & 0xffff) + 1) / 2) + 1;
440145132Sanholt			else
441145132Sanholt				return 2;	/* indirect sequential */
442145132Sanholt		default:
443145132Sanholt			return 0;
444145132Sanholt		}
445145132Sanholt	default:
446145132Sanholt		return 0;
447145132Sanholt	}
448145132Sanholt
449145132Sanholt	return 0;
450145132Sanholt}
451145132Sanholt
452145132Sanholtstatic int validate_cmd(int cmd)
453145132Sanholt{
454145132Sanholt	int ret = do_validate_cmd(cmd);
455145132Sanholt
456182080Srnoland/*	printk("validate_cmd( %x ): %d\n", cmd, ret); */
457145132Sanholt
458145132Sanholt	return ret;
459145132Sanholt}
460145132Sanholt
461182080Srnolandstatic int i915_emit_cmds(struct drm_device *dev, int __user *buffer,
462182080Srnoland			  int dwords)
463145132Sanholt{
464145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
465145132Sanholt	int i;
466145132Sanholt	RING_LOCALS;
467145132Sanholt
468157617Sanholt	if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
469182080Srnoland		return -EINVAL;
470157617Sanholt
471162132Sanholt	BEGIN_LP_RING((dwords+1)&~1);
472157617Sanholt
473145132Sanholt	for (i = 0; i < dwords;) {
474145132Sanholt		int cmd, sz;
475145132Sanholt
476183573Srnoland		if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
477183573Srnoland			return -EINVAL;
478183573Srnoland
479145132Sanholt		if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
480182080Srnoland			return -EINVAL;
481145132Sanholt
482145132Sanholt		OUT_RING(cmd);
483145132Sanholt
484145132Sanholt		while (++i, --sz) {
485183573Srnoland			if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
486183573Srnoland							 sizeof(cmd))) {
487183573Srnoland				return -EINVAL;
488183573Srnoland			}
489145132Sanholt			OUT_RING(cmd);
490145132Sanholt		}
491145132Sanholt	}
492182080Srnoland
493157617Sanholt	if (dwords & 1)
494157617Sanholt		OUT_RING(0);
495145132Sanholt
496157617Sanholt	ADVANCE_LP_RING();
497182080Srnoland
498145132Sanholt	return 0;
499145132Sanholt}
500145132Sanholt
501183573Srnolandint i915_emit_box(struct drm_device * dev,
502183573Srnoland		  struct drm_clip_rect __user * boxes,
503183573Srnoland		  int i, int DR1, int DR4)
504145132Sanholt{
505145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
506182080Srnoland	struct drm_clip_rect box;
507145132Sanholt	RING_LOCALS;
508145132Sanholt
509183573Srnoland	if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
510183573Srnoland		return -EFAULT;
511183573Srnoland	}
512183573Srnoland
513145132Sanholt	if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
514145132Sanholt		DRM_ERROR("Bad box %d,%d..%d,%d\n",
515145132Sanholt			  box.x1, box.y1, box.x2, box.y2);
516182080Srnoland		return -EINVAL;
517145132Sanholt	}
518145132Sanholt
519162132Sanholt	if (IS_I965G(dev)) {
520162132Sanholt		BEGIN_LP_RING(4);
521162132Sanholt		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
522162132Sanholt		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
523162132Sanholt		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
524162132Sanholt		OUT_RING(DR4);
525162132Sanholt		ADVANCE_LP_RING();
526162132Sanholt	} else {
527162132Sanholt		BEGIN_LP_RING(6);
528162132Sanholt		OUT_RING(GFX_OP_DRAWRECT_INFO);
529162132Sanholt		OUT_RING(DR1);
530162132Sanholt		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
531162132Sanholt		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
532162132Sanholt		OUT_RING(DR4);
533162132Sanholt		OUT_RING(0);
534162132Sanholt		ADVANCE_LP_RING();
535162132Sanholt	}
536145132Sanholt
537145132Sanholt	return 0;
538145132Sanholt}
539145132Sanholt
540162132Sanholt/* XXX: Emitting the counter should really be moved to part of the IRQ
541182080Srnoland * emit. For now, do it in both places:
542162132Sanholt */
543157617Sanholt
544182080Srnolandvoid i915_emit_breadcrumb(struct drm_device *dev)
545157617Sanholt{
546157617Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
547157617Sanholt	RING_LOCALS;
548157617Sanholt
549182080Srnoland	if (++dev_priv->counter > BREADCRUMB_MASK) {
550182080Srnoland		 dev_priv->counter = 1;
551182080Srnoland		 DRM_DEBUG("Breadcrumb counter wrapped around\n");
552182080Srnoland	}
553157617Sanholt
554182080Srnoland	if (dev_priv->sarea_priv)
555182080Srnoland		dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
556162132Sanholt
557157617Sanholt	BEGIN_LP_RING(4);
558182080Srnoland	OUT_RING(MI_STORE_DWORD_INDEX);
559183573Srnoland	OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
560157617Sanholt	OUT_RING(dev_priv->counter);
561157617Sanholt	OUT_RING(0);
562157617Sanholt	ADVANCE_LP_RING();
563157617Sanholt}
564157617Sanholt
565182080Srnoland
566182080Srnolandint i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)
567182080Srnoland{
568182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
569182080Srnoland	uint32_t flush_cmd = MI_FLUSH;
570182080Srnoland	RING_LOCALS;
571182080Srnoland
572182080Srnoland	flush_cmd |= flush;
573182080Srnoland
574182080Srnoland	i915_kernel_lost_context(dev);
575182080Srnoland
576182080Srnoland	BEGIN_LP_RING(4);
577182080Srnoland	OUT_RING(flush_cmd);
578182080Srnoland	OUT_RING(0);
579182080Srnoland	OUT_RING(0);
580182080Srnoland	OUT_RING(0);
581182080Srnoland	ADVANCE_LP_RING();
582182080Srnoland
583182080Srnoland	return 0;
584182080Srnoland}
585182080Srnoland
586182080Srnoland
587182080Srnolandstatic int i915_dispatch_cmdbuffer(struct drm_device * dev,
588145132Sanholt				   drm_i915_cmdbuffer_t * cmd)
589145132Sanholt{
590182080Srnoland#ifdef I915_HAVE_FENCE
591182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
592182080Srnoland#endif
593145132Sanholt	int nbox = cmd->num_cliprects;
594145132Sanholt	int i = 0, count, ret;
595145132Sanholt
596145132Sanholt	if (cmd->sz & 0x3) {
597182080Srnoland		DRM_ERROR("alignment\n");
598182080Srnoland		return -EINVAL;
599145132Sanholt	}
600145132Sanholt
601145132Sanholt	i915_kernel_lost_context(dev);
602145132Sanholt
603145132Sanholt	count = nbox ? nbox : 1;
604145132Sanholt
605145132Sanholt	for (i = 0; i < count; i++) {
606145132Sanholt		if (i < nbox) {
607145132Sanholt			ret = i915_emit_box(dev, cmd->cliprects, i,
608145132Sanholt					    cmd->DR1, cmd->DR4);
609145132Sanholt			if (ret)
610145132Sanholt				return ret;
611145132Sanholt		}
612145132Sanholt
613145132Sanholt		ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4);
614145132Sanholt		if (ret)
615145132Sanholt			return ret;
616145132Sanholt	}
617145132Sanholt
618182080Srnoland	i915_emit_breadcrumb(dev);
619182080Srnoland#ifdef I915_HAVE_FENCE
620182080Srnoland	if (unlikely((dev_priv->counter & 0xFF) == 0))
621182080Srnoland		drm_fence_flush_old(dev, 0, dev_priv->counter);
622182080Srnoland#endif
623145132Sanholt	return 0;
624145132Sanholt}
625145132Sanholt
626182080Srnolandint i915_dispatch_batchbuffer(struct drm_device * dev,
627182080Srnoland			      drm_i915_batchbuffer_t * batch)
628145132Sanholt{
629145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
630182080Srnoland	struct drm_clip_rect __user *boxes = batch->cliprects;
631145132Sanholt	int nbox = batch->num_cliprects;
632145132Sanholt	int i = 0, count;
633145132Sanholt	RING_LOCALS;
634145132Sanholt
635145132Sanholt	if ((batch->start | batch->used) & 0x7) {
636182080Srnoland		DRM_ERROR("alignment\n");
637182080Srnoland		return -EINVAL;
638145132Sanholt	}
639145132Sanholt
640145132Sanholt	i915_kernel_lost_context(dev);
641145132Sanholt
642145132Sanholt	count = nbox ? nbox : 1;
643145132Sanholt
644145132Sanholt	for (i = 0; i < count; i++) {
645145132Sanholt		if (i < nbox) {
646145132Sanholt			int ret = i915_emit_box(dev, boxes, i,
647145132Sanholt						batch->DR1, batch->DR4);
648145132Sanholt			if (ret)
649145132Sanholt				return ret;
650145132Sanholt		}
651145132Sanholt
652183573Srnoland		if (IS_I830(dev) || IS_845G(dev)) {
653183573Srnoland			BEGIN_LP_RING(4);
654183573Srnoland			OUT_RING(MI_BATCH_BUFFER);
655183573Srnoland			OUT_RING(batch->start | MI_BATCH_NON_SECURE);
656183573Srnoland			OUT_RING(batch->start + batch->used - 4);
657183573Srnoland			OUT_RING(0);
658183573Srnoland			ADVANCE_LP_RING();
659183573Srnoland		} else {
660145132Sanholt			BEGIN_LP_RING(2);
661182080Srnoland			if (IS_I965G(dev)) {
662182080Srnoland				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
663182080Srnoland				OUT_RING(batch->start);
664182080Srnoland			} else {
665182080Srnoland				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
666182080Srnoland				OUT_RING(batch->start | MI_BATCH_NON_SECURE);
667182080Srnoland			}
668145132Sanholt			ADVANCE_LP_RING();
669145132Sanholt		}
670145132Sanholt	}
671145132Sanholt
672182080Srnoland	i915_emit_breadcrumb(dev);
673182080Srnoland#ifdef I915_HAVE_FENCE
674182080Srnoland	if (unlikely((dev_priv->counter & 0xFF) == 0))
675182080Srnoland		drm_fence_flush_old(dev, 0, dev_priv->counter);
676182080Srnoland#endif
677145132Sanholt	return 0;
678145132Sanholt}
679145132Sanholt
680182080Srnolandstatic void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
681145132Sanholt{
682145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
683182080Srnoland	u32 num_pages, current_page, next_page, dspbase;
684182080Srnoland	int shift = 2 * plane, x, y;
685145132Sanholt	RING_LOCALS;
686145132Sanholt
687182080Srnoland	/* Calculate display base offset */
688182080Srnoland	num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
689182080Srnoland	current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3;
690182080Srnoland	next_page = (current_page + 1) % num_pages;
691145132Sanholt
692182080Srnoland	switch (next_page) {
693182080Srnoland	default:
694182080Srnoland	case 0:
695182080Srnoland		dspbase = dev_priv->sarea_priv->front_offset;
696182080Srnoland		break;
697182080Srnoland	case 1:
698182080Srnoland		dspbase = dev_priv->sarea_priv->back_offset;
699182080Srnoland		break;
700182080Srnoland	case 2:
701182080Srnoland		dspbase = dev_priv->sarea_priv->third_offset;
702182080Srnoland		break;
703182080Srnoland	}
704145132Sanholt
705182080Srnoland	if (plane == 0) {
706182080Srnoland		x = dev_priv->sarea_priv->planeA_x;
707182080Srnoland		y = dev_priv->sarea_priv->planeA_y;
708145132Sanholt	} else {
709182080Srnoland		x = dev_priv->sarea_priv->planeB_x;
710182080Srnoland		y = dev_priv->sarea_priv->planeB_y;
711145132Sanholt	}
712145132Sanholt
713182080Srnoland	dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp;
714145132Sanholt
715182080Srnoland	DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page,
716182080Srnoland		  dspbase);
717145132Sanholt
718145132Sanholt	BEGIN_LP_RING(4);
719182080Srnoland	OUT_RING(sync ? 0 :
720182080Srnoland		 (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP :
721182080Srnoland				       MI_WAIT_FOR_PLANE_A_FLIP)));
722182080Srnoland	OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |
723182080Srnoland		 (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
724182080Srnoland	OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
725182080Srnoland	OUT_RING(dspbase);
726145132Sanholt	ADVANCE_LP_RING();
727145132Sanholt
728182080Srnoland	dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
729182080Srnoland	dev_priv->sarea_priv->pf_current_page |= next_page << shift;
730145132Sanholt}
731145132Sanholt
732182080Srnolandvoid i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
733145132Sanholt{
734145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
735182080Srnoland	int i;
736145132Sanholt
737182080Srnoland	DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
738182080Srnoland		  planes, dev_priv->sarea_priv->pf_current_page);
739182080Srnoland
740182080Srnoland	i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
741182080Srnoland
742182080Srnoland	for (i = 0; i < 2; i++)
743182080Srnoland		if (planes & (1 << i))
744182080Srnoland			i915_do_dispatch_flip(dev, i, sync);
745182080Srnoland
746182080Srnoland	i915_emit_breadcrumb(dev);
747182080Srnoland#ifdef I915_HAVE_FENCE
748182080Srnoland	if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0)))
749182080Srnoland		drm_fence_flush_old(dev, 0, dev_priv->counter);
750182080Srnoland#endif
751182080Srnoland}
752182080Srnoland
753182080Srnolandint i915_quiescent(struct drm_device *dev)
754182080Srnoland{
755182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
756183573Srnoland	int ret;
757182080Srnoland
758145132Sanholt	i915_kernel_lost_context(dev);
759183573Srnoland	ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
760183573Srnoland	if (ret)
761183573Srnoland	{
762183573Srnoland		i915_kernel_lost_context (dev);
763183573Srnoland		DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n",
764183573Srnoland			   dev_priv->ring.head,
765183573Srnoland			   dev_priv->ring.tail,
766183573Srnoland			   dev_priv->ring.space);
767183573Srnoland	}
768183573Srnoland	return ret;
769145132Sanholt}
770145132Sanholt
771182080Srnolandstatic int i915_flush_ioctl(struct drm_device *dev, void *data,
772182080Srnoland			    struct drm_file *file_priv)
773145132Sanholt{
774145132Sanholt
775182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
776145132Sanholt
777145132Sanholt	return i915_quiescent(dev);
778145132Sanholt}
779145132Sanholt
780182080Srnolandstatic int i915_batchbuffer(struct drm_device *dev, void *data,
781182080Srnoland			    struct drm_file *file_priv)
782145132Sanholt{
783145132Sanholt	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
784145132Sanholt	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
785145132Sanholt	    dev_priv->sarea_priv;
786182080Srnoland	drm_i915_batchbuffer_t *batch = data;
787145132Sanholt	int ret;
788145132Sanholt
789145132Sanholt	if (!dev_priv->allow_batchbuffer) {
790145132Sanholt		DRM_ERROR("Batchbuffer ioctl disabled\n");
791182080Srnoland		return -EINVAL;
792145132Sanholt	}
793145132Sanholt
794145132Sanholt	DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
795182080Srnoland		  batch->start, batch->used, batch->num_cliprects);
796145132Sanholt
797182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
798145132Sanholt
799182080Srnoland	if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
800183573Srnoland							batch->num_cliprects *
801183573Srnoland							sizeof(struct drm_clip_rect)))
802182080Srnoland		return -EFAULT;
803183573Srnoland
804182080Srnoland	ret = i915_dispatch_batchbuffer(dev, batch);
805145132Sanholt
806182080Srnoland	sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
807145132Sanholt	return ret;
808145132Sanholt}
809145132Sanholt
810182080Srnolandstatic int i915_cmdbuffer(struct drm_device *dev, void *data,
811182080Srnoland			  struct drm_file *file_priv)
812145132Sanholt{
813145132Sanholt	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
814145132Sanholt	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
815145132Sanholt	    dev_priv->sarea_priv;
816182080Srnoland	drm_i915_cmdbuffer_t *cmdbuf = data;
817145132Sanholt	int ret;
818145132Sanholt
819145132Sanholt	DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
820182080Srnoland		  cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
821145132Sanholt
822182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
823145132Sanholt
824182080Srnoland	if (cmdbuf->num_cliprects &&
825183573Srnoland	    DRM_VERIFYAREA_READ(cmdbuf->cliprects,
826183573Srnoland				cmdbuf->num_cliprects *
827183573Srnoland				sizeof(struct drm_clip_rect))) {
828145132Sanholt		DRM_ERROR("Fault accessing cliprects\n");
829182080Srnoland		return -EFAULT;
830145132Sanholt	}
831183573Srnoland
832182080Srnoland	ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
833183573Srnoland	if (ret) {
834145132Sanholt		DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
835183573Srnoland		return ret;
836145132Sanholt	}
837183573Srnoland
838183573Srnoland	sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
839183573Srnoland	return 0;
840145132Sanholt}
841145132Sanholt
842182080Srnoland#if defined(DRM_DEBUG_CODE)
843182080Srnoland#define DRM_DEBUG_RELOCATION	(drm_debug != 0)
844182080Srnoland#else
845182080Srnoland#define DRM_DEBUG_RELOCATION	0
846182080Srnoland#endif
847182080Srnoland
848182080Srnolandstatic int i915_do_cleanup_pageflip(struct drm_device * dev)
849145132Sanholt{
850145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
851182080Srnoland	int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
852145132Sanholt
853182080Srnoland	DRM_DEBUG("\n");
854145132Sanholt
855182080Srnoland	for (i = 0, planes = 0; i < 2; i++)
856182080Srnoland		if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
857182080Srnoland			dev_priv->sarea_priv->pf_current_page =
858182080Srnoland				(dev_priv->sarea_priv->pf_current_page &
859182080Srnoland				 ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
860182080Srnoland
861182080Srnoland			planes |= 1 << i;
862182080Srnoland		}
863182080Srnoland
864182080Srnoland	if (planes)
865182080Srnoland		i915_dispatch_flip(dev, planes, 0);
866182080Srnoland
867145132Sanholt	return 0;
868145132Sanholt}
869145132Sanholt
870182080Srnolandstatic int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
871145132Sanholt{
872182080Srnoland	drm_i915_flip_t *param = data;
873145132Sanholt
874182080Srnoland	DRM_DEBUG("\n");
875145132Sanholt
876182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
877145132Sanholt
878182080Srnoland	/* This is really planes */
879182080Srnoland	if (param->pipes & ~0x3) {
880182080Srnoland		DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n",
881182080Srnoland			  param->pipes);
882182080Srnoland		return -EINVAL;
883182080Srnoland	}
884182080Srnoland
885182080Srnoland	i915_dispatch_flip(dev, param->pipes, 0);
886182080Srnoland
887182080Srnoland	return 0;
888145132Sanholt}
889145132Sanholt
890182080Srnoland
891182080Srnolandstatic int i915_getparam(struct drm_device *dev, void *data,
892182080Srnoland			 struct drm_file *file_priv)
893145132Sanholt{
894145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
895182080Srnoland	drm_i915_getparam_t *param = data;
896145132Sanholt	int value;
897145132Sanholt
898145132Sanholt	if (!dev_priv) {
899182080Srnoland		DRM_ERROR("called with no initialization\n");
900182080Srnoland		return -EINVAL;
901145132Sanholt	}
902145132Sanholt
903182080Srnoland	switch (param->param) {
904145132Sanholt	case I915_PARAM_IRQ_ACTIVE:
905183573Srnoland		value = dev->irq_enabled ? 1 : 0;
906145132Sanholt		break;
907145132Sanholt	case I915_PARAM_ALLOW_BATCHBUFFER:
908145132Sanholt		value = dev_priv->allow_batchbuffer ? 1 : 0;
909145132Sanholt		break;
910157617Sanholt	case I915_PARAM_LAST_DISPATCH:
911157617Sanholt		value = READ_BREADCRUMB(dev_priv);
912157617Sanholt		break;
913182080Srnoland	case I915_PARAM_CHIPSET_ID:
914182080Srnoland		value = dev->pci_device;
915182080Srnoland		break;
916183573Srnoland	case I915_PARAM_HAS_GEM:
917184373Srnoland		/* We need to reset this to 1 once we have GEM */
918184373Srnoland		value = 0;
919183573Srnoland		break;
920145132Sanholt	default:
921182080Srnoland		DRM_ERROR("Unknown parameter %d\n", param->param);
922182080Srnoland		return -EINVAL;
923145132Sanholt	}
924145132Sanholt
925182080Srnoland	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
926145132Sanholt		DRM_ERROR("DRM_COPY_TO_USER failed\n");
927182080Srnoland		return -EFAULT;
928145132Sanholt	}
929145132Sanholt
930145132Sanholt	return 0;
931145132Sanholt}
932145132Sanholt
933182080Srnolandstatic int i915_setparam(struct drm_device *dev, void *data,
934182080Srnoland			 struct drm_file *file_priv)
935145132Sanholt{
936145132Sanholt	drm_i915_private_t *dev_priv = dev->dev_private;
937182080Srnoland	drm_i915_setparam_t *param = data;
938145132Sanholt
939145132Sanholt	if (!dev_priv) {
940182080Srnoland		DRM_ERROR("called with no initialization\n");
941182080Srnoland		return -EINVAL;
942145132Sanholt	}
943145132Sanholt
944182080Srnoland	switch (param->param) {
945145132Sanholt	case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
946145132Sanholt		break;
947145132Sanholt	case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
948182080Srnoland		dev_priv->tex_lru_log_granularity = param->value;
949145132Sanholt		break;
950145132Sanholt	case I915_SETPARAM_ALLOW_BATCHBUFFER:
951182080Srnoland		dev_priv->allow_batchbuffer = param->value;
952145132Sanholt		break;
953145132Sanholt	default:
954182080Srnoland		DRM_ERROR("unknown parameter %d\n", param->param);
955182080Srnoland		return -EINVAL;
956145132Sanholt	}
957145132Sanholt
958145132Sanholt	return 0;
959145132Sanholt}
960145132Sanholt
961182080Srnolanddrm_i915_mmio_entry_t mmio_table[] = {
962182080Srnoland	[MMIO_REGS_PS_DEPTH_COUNT] = {
963182080Srnoland		I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE,
964182080Srnoland		0x2350,
965182080Srnoland		8
966182080Srnoland	}
967182080Srnoland};
968182080Srnoland
969182080Srnolandstatic int mmio_table_size = sizeof(mmio_table)/sizeof(drm_i915_mmio_entry_t);
970182080Srnoland
971182080Srnolandstatic int i915_mmio(struct drm_device *dev, void *data,
972182080Srnoland		     struct drm_file *file_priv)
973145132Sanholt{
974182080Srnoland	uint32_t buf[8];
975182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
976182080Srnoland	drm_i915_mmio_entry_t *e;
977182080Srnoland	drm_i915_mmio_t *mmio = data;
978182080Srnoland	void __iomem *base;
979182080Srnoland	int i;
980182080Srnoland
981182080Srnoland	if (!dev_priv) {
982182080Srnoland		DRM_ERROR("called with no initialization\n");
983182080Srnoland		return -EINVAL;
984182080Srnoland	}
985182080Srnoland
986182080Srnoland	if (mmio->reg >= mmio_table_size)
987182080Srnoland		return -EINVAL;
988182080Srnoland
989182080Srnoland	e = &mmio_table[mmio->reg];
990182080Srnoland	base = (u8 *) dev_priv->mmio_map->handle + e->offset;
991182080Srnoland
992182080Srnoland	switch (mmio->read_write) {
993182080Srnoland	case I915_MMIO_READ:
994182080Srnoland		if (!(e->flag & I915_MMIO_MAY_READ))
995182080Srnoland			return -EINVAL;
996182080Srnoland		for (i = 0; i < e->size / 4; i++)
997182080Srnoland			buf[i] = I915_READ(e->offset + i * 4);
998182080Srnoland		if (DRM_COPY_TO_USER(mmio->data, buf, e->size)) {
999182080Srnoland			DRM_ERROR("DRM_COPY_TO_USER failed\n");
1000182080Srnoland			return -EFAULT;
1001182080Srnoland		}
1002182080Srnoland		break;
1003182080Srnoland
1004182080Srnoland	case I915_MMIO_WRITE:
1005182080Srnoland		if (!(e->flag & I915_MMIO_MAY_WRITE))
1006182080Srnoland			return -EINVAL;
1007182080Srnoland		if (DRM_COPY_FROM_USER(buf, mmio->data, e->size)) {
1008182080Srnoland			DRM_ERROR("DRM_COPY_TO_USER failed\n");
1009182080Srnoland			return -EFAULT;
1010182080Srnoland		}
1011182080Srnoland		for (i = 0; i < e->size / 4; i++)
1012182080Srnoland			I915_WRITE(e->offset + i * 4, buf[i]);
1013182080Srnoland		break;
1014182080Srnoland	}
1015182080Srnoland	return 0;
1016182080Srnoland}
1017182080Srnoland
1018182080Srnolandstatic int i915_set_status_page(struct drm_device *dev, void *data,
1019182080Srnoland				struct drm_file *file_priv)
1020182080Srnoland{
1021182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
1022182080Srnoland	drm_i915_hws_addr_t *hws = data;
1023182080Srnoland
1024182080Srnoland	if (!I915_NEED_GFX_HWS(dev))
1025182080Srnoland		return -EINVAL;
1026182080Srnoland
1027182080Srnoland	if (!dev_priv) {
1028182080Srnoland		DRM_ERROR("called with no initialization\n");
1029182080Srnoland		return -EINVAL;
1030182080Srnoland	}
1031182080Srnoland	DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
1032182080Srnoland
1033182080Srnoland	dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
1034182080Srnoland
1035182080Srnoland	dev_priv->hws_map.offset = dev->agp->base + hws->addr;
1036182080Srnoland	dev_priv->hws_map.size = 4*1024;
1037182080Srnoland	dev_priv->hws_map.type = 0;
1038182080Srnoland	dev_priv->hws_map.flags = 0;
1039182080Srnoland	dev_priv->hws_map.mtrr = 0;
1040182080Srnoland
1041182080Srnoland	drm_core_ioremap(&dev_priv->hws_map, dev);
1042182080Srnoland	if (dev_priv->hws_map.handle == NULL) {
1043182080Srnoland		i915_dma_cleanup(dev);
1044182080Srnoland		dev_priv->status_gfx_addr = 0;
1045182080Srnoland		DRM_ERROR("can not ioremap virtual address for"
1046182080Srnoland				" G33 hw status page\n");
1047182080Srnoland		return -ENOMEM;
1048182080Srnoland	}
1049182080Srnoland	dev_priv->hw_status_page = dev_priv->hws_map.handle;
1050182080Srnoland
1051182080Srnoland	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
1052182080Srnoland	I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
1053182080Srnoland	DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
1054182080Srnoland			dev_priv->status_gfx_addr);
1055182080Srnoland	DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
1056182080Srnoland	return 0;
1057182080Srnoland}
1058182080Srnoland
1059182080Srnolandint i915_driver_load(struct drm_device *dev, unsigned long flags)
1060182080Srnoland{
1061182080Srnoland	struct drm_i915_private *dev_priv;
1062182080Srnoland	unsigned long base, size;
1063182080Srnoland	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
1064182080Srnoland
1065152909Sanholt	/* i915 has 4 more counters */
1066152909Sanholt	dev->counters += 4;
1067152909Sanholt	dev->types[6] = _DRM_STAT_IRQ;
1068152909Sanholt	dev->types[7] = _DRM_STAT_PRIMARY;
1069152909Sanholt	dev->types[8] = _DRM_STAT_SECONDARY;
1070152909Sanholt	dev->types[9] = _DRM_STAT_DMA;
1071152909Sanholt
1072182080Srnoland	dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER);
1073182080Srnoland	if (dev_priv == NULL)
1074182080Srnoland		return -ENOMEM;
1075182080Srnoland
1076182080Srnoland	memset(dev_priv, 0, sizeof(drm_i915_private_t));
1077182080Srnoland
1078182080Srnoland	dev->dev_private = (void *)dev_priv;
1079183573Srnoland	dev_priv->dev = dev;
1080182080Srnoland
1081182080Srnoland	/* Add register map (needed for suspend/resume) */
1082182080Srnoland	base = drm_get_resource_start(dev, mmio_bar);
1083182080Srnoland	size = drm_get_resource_len(dev, mmio_bar);
1084182080Srnoland
1085182080Srnoland	ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
1086182080Srnoland		_DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map);
1087183573Srnoland#ifdef I915_HAVE_GEM
1088183573Srnoland	i915_gem_load(dev);
1089183573Srnoland#endif
1090182080Srnoland	DRM_SPININIT(&dev_priv->swaps_lock, "swap");
1091182080Srnoland	DRM_SPININIT(&dev_priv->user_irq_lock, "userirq");
1092182080Srnoland
1093182080Srnoland#ifdef __linux__
1094182080Srnoland#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
1095182080Srnoland	intel_init_chipset_flush_compat(dev);
1096182080Srnoland#endif
1097182080Srnoland#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
1098182080Srnoland	intel_opregion_init(dev);
1099182080Srnoland#endif
1100182080Srnoland#endif
1101182080Srnoland
1102183573Srnoland	/* Init HWS */
1103183573Srnoland	if (!I915_NEED_GFX_HWS(dev)) {
1104183573Srnoland		ret = i915_init_hardware_status(dev);
1105183573Srnoland		if(ret)
1106183573Srnoland			return ret;
1107183573Srnoland	}
1108183573Srnoland
1109182080Srnoland	return ret;
1110182080Srnoland}
1111182080Srnoland
1112182080Srnolandint i915_driver_unload(struct drm_device *dev)
1113182080Srnoland{
1114182080Srnoland	struct drm_i915_private *dev_priv = dev->dev_private;
1115182080Srnoland
1116183573Srnoland	i915_free_hardware_status(dev);
1117182080Srnoland
1118183573Srnoland    	drm_rmmap(dev, dev_priv->mmio_map);
1119183573Srnoland
1120182080Srnoland	DRM_SPINUNINIT(&dev_priv->swaps_lock);
1121182080Srnoland	DRM_SPINUNINIT(&dev_priv->user_irq_lock);
1122182080Srnoland
1123182080Srnoland#ifdef __linux__
1124182080Srnoland#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
1125182080Srnoland	intel_opregion_free(dev);
1126182080Srnoland#endif
1127182080Srnoland#endif
1128182080Srnoland
1129182080Srnoland	drm_free(dev->dev_private, sizeof(drm_i915_private_t),
1130182080Srnoland		 DRM_MEM_DRIVER);
1131182080Srnoland	dev->dev_private = NULL;
1132182080Srnoland
1133182080Srnoland#ifdef __linux__
1134182080Srnoland#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
1135182080Srnoland	intel_fini_chipset_flush_compat(dev);
1136182080Srnoland#endif
1137182080Srnoland#endif
1138152909Sanholt	return 0;
1139152909Sanholt}
1140152909Sanholt
1141182080Srnolandvoid i915_driver_lastclose(struct drm_device * dev)
1142152909Sanholt{
1143182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
1144182080Srnoland
1145182080Srnoland	/* agp off can use this to get called before dev_priv */
1146182080Srnoland	if (!dev_priv)
1147182080Srnoland		return;
1148182080Srnoland
1149182080Srnoland#ifdef I915_HAVE_BUFFER
1150182080Srnoland	if (dev_priv->val_bufs) {
1151182080Srnoland		vfree(dev_priv->val_bufs);
1152182080Srnoland		dev_priv->val_bufs = NULL;
1153182080Srnoland	}
1154182080Srnoland#endif
1155183573Srnoland#ifdef I915_HAVE_GEM
1156183573Srnoland	i915_gem_lastclose(dev);
1157183573Srnoland#endif
1158183573Srnoland	if (drm_getsarea(dev) && dev_priv->sarea_priv)
1159182080Srnoland		i915_do_cleanup_pageflip(dev);
1160183573Srnoland	if (dev_priv->sarea_priv)
1161182080Srnoland		dev_priv->sarea_priv = NULL;
1162182080Srnoland	if (dev_priv->agp_heap)
1163145132Sanholt		i915_mem_takedown(&(dev_priv->agp_heap));
1164182080Srnoland#if defined(I915_HAVE_BUFFER)
1165182080Srnoland	if (dev_priv->sarea_kmap.virtual) {
1166182080Srnoland		drm_bo_kunmap(&dev_priv->sarea_kmap);
1167182080Srnoland		dev_priv->sarea_kmap.virtual = NULL;
1168182080Srnoland		dev->lock.hw_lock = NULL;
1169182080Srnoland		dev->sigdata.lock = NULL;
1170145132Sanholt	}
1171182080Srnoland
1172182080Srnoland	if (dev_priv->sarea_bo) {
1173182080Srnoland		mutex_lock(&dev->struct_mutex);
1174182080Srnoland		drm_bo_usage_deref_locked(&dev_priv->sarea_bo);
1175182080Srnoland		mutex_unlock(&dev->struct_mutex);
1176182080Srnoland		dev_priv->sarea_bo = NULL;
1177182080Srnoland	}
1178182080Srnoland#endif
1179145132Sanholt	i915_dma_cleanup(dev);
1180145132Sanholt}
1181145132Sanholt
1182183573Srnolandint i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
1183183573Srnoland{
1184183573Srnoland	struct drm_i915_file_private *i915_file_priv;
1185183573Srnoland
1186183573Srnoland	DRM_DEBUG("\n");
1187183573Srnoland	i915_file_priv = (struct drm_i915_file_private *)
1188183573Srnoland	    drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
1189183573Srnoland
1190183573Srnoland	if (!i915_file_priv)
1191183573Srnoland		return -ENOMEM;
1192183573Srnoland
1193183573Srnoland	file_priv->driver_priv = i915_file_priv;
1194183573Srnoland
1195183573Srnoland	i915_file_priv->mm.last_gem_seqno = 0;
1196183573Srnoland	i915_file_priv->mm.last_gem_throttle_seqno = 0;
1197183573Srnoland
1198183573Srnoland	return 0;
1199183573Srnoland}
1200183573Srnoland
1201182080Srnolandvoid i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
1202145132Sanholt{
1203182080Srnoland	drm_i915_private_t *dev_priv = dev->dev_private;
1204182080Srnoland	i915_mem_release(dev, file_priv, dev_priv->agp_heap);
1205145132Sanholt}
1206145132Sanholt
1207183573Srnolandvoid i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
1208183573Srnoland{
1209183573Srnoland	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
1210183573Srnoland
1211183573Srnoland	drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES);
1212183573Srnoland}
1213183573Srnoland
1214182080Srnolandstruct drm_ioctl_desc i915_ioctls[] = {
1215182080Srnoland	DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1216182080Srnoland	DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
1217182080Srnoland	DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH),
1218182080Srnoland	DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH),
1219182080Srnoland	DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH),
1220182080Srnoland	DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
1221182080Srnoland	DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH),
1222182080Srnoland	DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1223182080Srnoland	DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH),
1224182080Srnoland	DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH),
1225182080Srnoland	DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1226182080Srnoland	DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
1227182080Srnoland	DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP,  i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
1228182080Srnoland	DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE,  i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
1229182080Srnoland	DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE,  i915_vblank_pipe_get, DRM_AUTH ),
1230182080Srnoland	DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
1231182080Srnoland	DRM_IOCTL_DEF(DRM_I915_MMIO, i915_mmio, DRM_AUTH),
1232184263Srnoland	DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1233182080Srnoland#ifdef I915_HAVE_BUFFER
1234182080Srnoland	DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH),
1235182080Srnoland#endif
1236183573Srnoland#ifdef I915_HAVE_GEM
1237183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH),
1238183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
1239183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
1240183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
1241183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH),
1242183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH),
1243183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH),
1244183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH),
1245183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0),
1246183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0),
1247183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0),
1248183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0),
1249183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0),
1250183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0),
1251183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
1252183573Srnoland	DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
1253183573Srnoland#endif
1254145132Sanholt};
1255145132Sanholt
1256145132Sanholtint i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
1257152909Sanholt
1258152909Sanholt/**
1259152909Sanholt * Determine if the device really is AGP or not.
1260152909Sanholt *
1261152909Sanholt * All Intel graphics chipsets are treated as AGP, even if they are really
1262152909Sanholt * PCI-e.
1263152909Sanholt *
1264152909Sanholt * \param dev   The device to be tested.
1265152909Sanholt *
1266152909Sanholt * \returns
1267152909Sanholt * A value of 1 is always retured to indictate every i9x5 is AGP.
1268152909Sanholt */
1269182080Srnolandint i915_driver_device_is_agp(struct drm_device * dev)
1270152909Sanholt{
1271152909Sanholt	return 1;
1272152909Sanholt}
1273182080Srnoland
1274182080Srnolandint i915_driver_firstopen(struct drm_device *dev)
1275182080Srnoland{
1276182080Srnoland#ifdef I915_HAVE_BUFFER
1277182080Srnoland	drm_bo_driver_init(dev);
1278182080Srnoland#endif
1279182080Srnoland	return 0;
1280182080Srnoland}
1281