summaryrefslogtreecommitdiff
path: root/scripts/drm-scripts-gentree.pl
blob: cbc101751fd55ca60518aa27fb820c9abe29ebf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/usr/bin/perl
#
# Original version were part of Gerd Knorr's v4l scripts.
#
# Several improvements by (c) 2005-2007 Mauro Carvalho Chehab
#
# Largely re-written (C) 2007 Trent Piepho <xyzzy@speakeasy.org>
# Stolen for DRM usage by airlied
#
# Theory of Operation
#
# This acts as a sort of mini version of cpp, which will process
# #if/#elif/#ifdef/etc directives to strip out code used to support
# multiple kernel versions or otherwise not wanted to be sent upstream to
# git.
#
# Conditional compilation directives fall into two catagories,
# "processed" and "other".  The "other" directives are ignored and simply
# output as they come in without changes (see 'keep' exception).  The
# "processed" variaty are evaluated and only the lines in the 'true' part
# are kept, like cpp would do.
#
# If gentree knows the result of an expression, that directive will be
# "processed", otherwise it will be an "other".  gentree knows the value
# of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z)
# macro, numeric constants like 0 and 1, and a few defines like MM_KERNEL
# and STV0297_CS2.
#
# An exception is if the comment "/*KEEP*/" appears after the expression,
# in which case that directive will be considered an "other" and not
# processed, other than to remove the keep comment.
#
# Known bugs:
# don't specify the root directory e.g. '/' or even '////'
# directives continued with a back-slash will always be ignored
# you can't modify a source tree in-place, i.e. source dir == dest dir

use strict;
use File::Find;
use Fcntl ':mode';

my $VERSION = shift;
my $SRC = shift;
my $DESTDIR = shift;

if (!defined($DESTDIR)) {
	print "Usage:\ngentree.pl\t<version> <source dir> <dest dir>\n\n";
	exit;
}

my $BTTVCODE = KERNEL_VERSION(0,9,17);
my ($LINUXCODE, $extra) = kernel_version($VERSION);
my $DEBUG = 0;

my %defs = (
	'LINUX_VERSION_CODE' => $LINUXCODE,
	'MM_KERNEL' => ($extra =~ /-mm/)?1:0,
	'DRM_ODD_MM_COMPAT' => 0,
	'I915_HAVE_FENCE' => 1,
	'I915_HAVE_BUFFER' => 1,
	'VIA_HAVE_DMABLIT' => 1,
	'VIA_HAVE_CORE_MM' => 1,
	'VIA_HAVE_FENCE' => 1,
        'VIA_HAVE_BUFFER' => 1,
	'SIS_HAVE_CORE_MM' => 1,
        'DRM_FULL_MM_COMPAT' => 1,   
	'__linux__' => 1,
);

#################################################################
# helpers

sub kernel_version($) {
	$_[0] =~ m/(\d+)\.(\d+)\.(\d+)(.*)/;
	return ($1*65536 + $2*256 + $3, $4);
}

# used in eval()
sub KERNEL_VERSION($$$) { return $_[0]*65536 + $_[1]*256 + $_[2]; }

sub evalexp($) {
	local $_ = shift;
	s|/\*.*?\*/||go;	# delete /* */ comments
	s|//.*$||o;		# delete // comments
	s/\bdefined\s*\(/(/go;	# defined(foo) to (foo)
	while (/\b([_A-Za-z]\w*)\b/go) {
		if (exists $defs{$1}) {
			my $id = $1; my $pos = $-[0];
			s/$id/$defs{$id}/;
			pos = $-[0];
		} elsif ($1 ne 'KERNEL_VERSION') {
			return(undef);
		}
	}
	return(eval($_) ? 1 : 0);
}

#################################################################
# filter out version-specific code

sub filter_source ($$) {
	my ($in,$out) = @_;
	my $line;
	my $level=0;
	my %if = ();
	my %state = ();

	my @dbgargs = \($level, %state, %if, $line);
	sub dbgline($\@) {
		my $level = ${$_[1][0]};
		printf STDERR ("/* BP %4d $_[0] state=$_[1][1]->{$level} if=$_[1][2]->{$level} level=$level (${$_[1][3]}) */\n", $.) if $DEBUG;
	}

	open IN, '<', $in or die "Error opening $in: $!\n";
	open OUT, '>', $out or die "Error opening $out: $!\n";

	print STDERR "File: $in, for kernel $VERSION($LINUXCODE)/\n" if $DEBUG;

	while ($line = <IN>) {
		chomp $line;
		next if ($line =~ m/^#include \"compat.h\"/o);
#		next if ($line =~ m/[\$]Id:/);

		# For "#if 0 /*KEEP*/;" the ; should be dropped too
		if ($line =~ m@^\s*#\s*if(n?def)?\s.*?(\s*/\*\s*(?i)keep\s*\*/;?)@) {
			$state{$level} = "ifother";
			$if{$level} = 1;
			dbgline "#if$1 (keep)", @dbgargs;
			$line =~ s/\Q$2\E//;
			$level++;
		}
		# handle all ifdef/ifndef lines
		elsif ($line =~ /^\s*#\s*if(n?)def\s*(\w+)/o) {
			if (exists $defs{$2}) {
				$state{$level} = 'if';
				$if{$level} = ($1 eq 'n') ? !$defs{$2} : $defs{$2};
				dbgline "#if$1def $2", @dbgargs;
				$level++;
				next;
			}
			$state{$level} = "ifother";
			$if{$level} = 1;
			dbgline "#if$1def (other)", @dbgargs;
			$level++;
		}
		# handle all ifs
		elsif ($line =~ /^\s*#\s*if\s+(.*)$/o) {
			my $res = evalexp($1);
			if (defined $res) {
				$state{$level} = 'if';
				$if{$level} = $res;
				dbgline '#if '.($res?'(yes)':'(no)'), @dbgargs;
				$level++;
				next;
			} else {
				$state{$level} = 'ifother';
				$if{$level} = 1;
				dbgline '#if (other)', @dbgargs;
				$level++;
			}
		}
		# handle all elifs
		elsif ($line =~ /^\s*#\s*elif\s+(.*)$/o) {
			my $exp = $1;
			$level--;
			$level < 0 and die "more elifs than ifs";
			$state{$level} =~ /if/ or die "unmatched elif";

			if ($state{$level} eq 'if' && !$if{$level}) {
				my $res = evalexp($exp);
				defined $res or die 'moving from if to ifother';
				$state{$level} = 'if';
				$if{$level} = $res;
				dbgline '#elif1 '.($res?'(yes)':'(no)'), @dbgargs;
				$level++;
				next;
			} elsif ($state{$level} ne 'ifother') {
				$if{$level} = 0;
				$state{$level} = 'elif';
				dbgline '#elif0', @dbgargs;
				$level++;
				next;
			}
			$level++;
		}
		elsif ($line =~ /^\s*#\s*else/o) {
			$level--;
			$level < 0 and die "more elses than ifs";
			$state{$level} =~ /if/ or die "unmatched else";
			$if{$level} = !$if{$level} if ($state{$level} eq 'if');
			$state{$level} =~ s/^if/else/o; # if -> else, ifother -> elseother, elif -> elif
			dbgline '#else', @dbgargs;
			$level++;
			next if $state{$level-1} !~ /other$/o;
		}
		elsif ($line =~ /^\s*#\s*endif/o) {
			$level--;
			$level < 0 and die "more endifs than ifs";
			dbgline '#endif', @dbgargs;
			next if $state{$level} !~ /other$/o;
		}

		my $print = 1;
		for (my $i=0;$i<$level;$i++) {
			next if $state{$i} =~ /other$/o;	# keep code in ifother/elseother blocks
			if (!$if{$i}) {
				$print = 0;
				dbgline 'DEL', @{[\$i, \%state, \%if, \$line]};
				last;
			}
		}
		print OUT "$line\n" if $print;
	}
	close IN;
	close OUT;
}

#################################################################

sub parse_dir {
	my $file = $File::Find::name;

	return if ($file =~ /CVS/);
	return if ($file =~ /~$/);

	my $f2 = $file;
	$f2 =~ s/^\Q$SRC\E/$DESTDIR/;

	my $mode = (stat($file))[2];
	if ($mode & S_IFDIR) {
		print("mkdir -p '$f2'\n");
		system("mkdir -p '$f2'");  # should check for error
		return;
	}
	print "from $file to $f2\n";

	if ($file =~ m/.*\.[ch]$/) {
		filter_source($file, $f2);
	} else {
		system("cp $file $f2");
	}
}


# main

printf "kernel is %s (0x%x)\n",$VERSION,$LINUXCODE;

# remove any trailing slashes from dir names.  don't pass in just '/'
$SRC =~ s|/*$||; $DESTDIR =~ s|/*$||;

print "finding files at $SRC\n";

find({wanted => \&parse_dir, no_chdir => 1}, $SRC);
s="hl opt">= drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); return DRM_ERR(EINVAL); } dev_priv->sarea_priv = (drm_i915_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); dev_priv->ring.Start = init->ring_start; dev_priv->ring.End = init->ring_end; dev_priv->ring.Size = init->ring_size; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->ring.map.offset = init->ring_start; dev_priv->ring.map.size = init->ring_size; dev_priv->ring.map.type = 0; dev_priv->ring.map.flags = 0; dev_priv->ring.map.mtrr = 0; drm_core_ioremap(&dev_priv->ring.map, dev); if (dev_priv->ring.map.handle == NULL) { dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return DRM_ERR(ENOMEM); } dev_priv->ring.virtual_start = dev_priv->ring.map.handle; dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. */ dev_priv->use_mi_batchbuffer_start = 0; /* Allow hardware batchbuffers unless told otherwise. */ dev_priv->allow_batchbuffer = 1; /* Program Hardware Status Page */ dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); if (!dev_priv->status_page_dmah) { dev->dev_private = (void *)dev_priv; i915_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); return DRM_ERR(ENOMEM); } dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); dev->dev_private = (void *)dev_priv; #ifdef I915_HAVE_BUFFER drm_bo_driver_init(dev); #endif return 0; } static int i915_dma_resume(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); if (!dev_priv->sarea) { DRM_ERROR("can not find sarea!\n"); return DRM_ERR(EINVAL); } if (!dev_priv->mmio_map) { DRM_ERROR("can not find mmio map!\n"); return DRM_ERR(EINVAL); } if (dev_priv->ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return DRM_ERR(ENOMEM); } /* Program Hardware Status Page */ if (!dev_priv->hw_status_page) { DRM_ERROR("Can not find hardware status page\n"); return DRM_ERR(EINVAL); } DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); return 0; } static int i915_dma_init(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv; drm_i915_init_t init; int retcode = 0; DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data, sizeof(init)); switch (init.func) { case I915_INIT_DMA: dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) return DRM_ERR(ENOMEM); retcode = i915_initialize(dev, dev_priv, &init); break; case I915_CLEANUP_DMA: retcode = i915_dma_cleanup(dev); break; case I915_RESUME_DMA: retcode = i915_dma_resume(dev); break; default: retcode = DRM_ERR(EINVAL); break; } return retcode; } /* Implement basically the same security restrictions as hardware does * for MI_BATCH_NON_SECURE. These can be made stricter at any time. * * Most of the calculations below involve calculating the size of a * particular instruction. It's important to get the size right as * that tells us where the next instruction to check is. Any illegal * instruction detected will be given a size of zero, which is a * signal to abort the rest of the buffer. */ static int do_validate_cmd(int cmd) { switch (((cmd >> 29) & 0x7)) { case 0x0: switch ((cmd >> 23) & 0x3f) { case 0x0: return 1; /* MI_NOOP */ case 0x4: return 1; /* MI_FLUSH */ default: return 0; /* disallow everything else */ } break; case 0x1: return 0; /* reserved */ case 0x2: return (cmd & 0xff) + 2; /* 2d commands */ case 0x3: if (((cmd >> 24) & 0x1f) <= 0x18) return 1; switch ((cmd >> 24) & 0x1f) { case 0x1c: return 1; case 0x1d: switch ((cmd >> 16) & 0xff) { case 0x3: return (cmd & 0x1f) + 2; case 0x4: return (cmd & 0xf) + 2; default: return (cmd & 0xffff) + 2; } case 0x1e: if (cmd & (1 << 23)) return (cmd & 0xffff) + 1; else return 1; case 0x1f: if ((cmd & (1 << 23)) == 0) /* inline vertices */ return (cmd & 0x1ffff) + 2; else if (cmd & (1 << 17)) /* indirect random */ if ((cmd & 0xffff) == 0) return 0; /* unknown length, too hard */ else return (((cmd & 0xffff) + 1) / 2) + 1; else return 2; /* indirect sequential */ default: return 0; } default: return 0; } return 0; } static int validate_cmd(int cmd) { int ret = do_validate_cmd(cmd); /* printk("validate_cmd( %x ): %d\n", cmd, ret); */ return ret; } static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords) { drm_i915_private_t *dev_priv = dev->dev_private; int i; RING_LOCALS; if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) return DRM_ERR(EINVAL); BEGIN_LP_RING((dwords+1)&~1); for (i = 0; i < dwords;) { int cmd, sz; if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) return DRM_ERR(EINVAL); if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) return DRM_ERR(EINVAL); OUT_RING(cmd); while (++i, --sz) { if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) { return DRM_ERR(EINVAL); } OUT_RING(cmd); } } if (dwords & 1) OUT_RING(0); ADVANCE_LP_RING(); return 0; } static int i915_emit_box(drm_device_t * dev, drm_clip_rect_t __user * boxes, int i, int DR1, int DR4) { drm_i915_private_t *dev_priv = dev->dev_private; drm_clip_rect_t box; RING_LOCALS; if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { return DRM_ERR(EFAULT); } if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { DRM_ERROR("Bad box %d,%d..%d,%d\n", box.x1, box.y1, box.x2, box.y2); return DRM_ERR(EINVAL); } if (IS_I965G(dev)) { BEGIN_LP_RING(4); OUT_RING(GFX_OP_DRAWRECT_INFO_I965); OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); OUT_RING(DR4); ADVANCE_LP_RING(); } else { BEGIN_LP_RING(6); OUT_RING(GFX_OP_DRAWRECT_INFO); OUT_RING(DR1); OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); OUT_RING(DR4); OUT_RING(0); ADVANCE_LP_RING(); } return 0; } /* XXX: Emitting the counter should really be moved to part of the IRQ * emit. For now, do it in both places: */ static void i915_emit_breadcrumb(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; RING_LOCALS; dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); #ifdef I915_HAVE_FENCE drm_fence_flush_old(dev, dev_priv->counter); #endif } int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush) { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t flush_cmd = CMD_MI_FLUSH; RING_LOCALS; flush_cmd |= flush; i915_kernel_lost_context(dev); BEGIN_LP_RING(4); OUT_RING(flush_cmd); OUT_RING(0); OUT_RING(0); OUT_RING(0); ADVANCE_LP_RING(); return 0; } static int i915_dispatch_cmdbuffer(drm_device_t * dev, drm_i915_cmdbuffer_t * cmd) { int nbox = cmd->num_cliprects; int i = 0, count, ret; if (cmd->sz & 0x3) { DRM_ERROR("alignment"); return DRM_ERR(EINVAL); } i915_kernel_lost_context(dev); count = nbox ? nbox : 1; for (i = 0; i < count; i++) { if (i < nbox) { ret = i915_emit_box(dev, cmd->cliprects, i, cmd->DR1, cmd->DR4); if (ret) return ret; } ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); if (ret) return ret; } i915_emit_breadcrumb( dev ); return 0; } static int i915_dispatch_batchbuffer(drm_device_t * dev, drm_i915_batchbuffer_t * batch) { drm_i915_private_t *dev_priv = dev->dev_private; drm_clip_rect_t __user *boxes = batch->cliprects; int nbox = batch->num_cliprects; int i = 0, count; RING_LOCALS; if ((batch->start | batch->used) & 0x7) { DRM_ERROR("alignment"); return DRM_ERR(EINVAL); } i915_kernel_lost_context(dev); count = nbox ? nbox : 1; for (i = 0; i < count; i++) { if (i < nbox) { int ret = i915_emit_box(dev, boxes, i, batch->DR1, batch->DR4); if (ret) return ret; } if (dev_priv->use_mi_batchbuffer_start) { BEGIN_LP_RING(2); OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); OUT_RING(batch->start | MI_BATCH_NON_SECURE); ADVANCE_LP_RING(); } else { BEGIN_LP_RING(4); OUT_RING(MI_BATCH_BUFFER); OUT_RING(batch->start | MI_BATCH_NON_SECURE); OUT_RING(batch->start + batch->used - 4); OUT_RING(0); ADVANCE_LP_RING(); } } i915_emit_breadcrumb( dev ); return 0; } static int i915_dispatch_flip(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; RING_LOCALS; DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", __FUNCTION__, dev_priv->current_page, dev_priv->sarea_priv->pf_current_page); i915_kernel_lost_context(dev); BEGIN_LP_RING(2); OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); OUT_RING(0); ADVANCE_LP_RING(); BEGIN_LP_RING(6); OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); OUT_RING(0); if (dev_priv->current_page == 0) { OUT_RING(dev_priv->back_offset); dev_priv->current_page = 1; } else { OUT_RING(dev_priv->front_offset); dev_priv->current_page = 0; } OUT_RING(0); ADVANCE_LP_RING(); BEGIN_LP_RING(2); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); OUT_RING(0); ADVANCE_LP_RING(); dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); #ifdef I915_HAVE_FENCE drm_fence_flush_old(dev, dev_priv->counter); #endif dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; return 0; } static int i915_quiescent(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); } static int i915_flush_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; LOCK_TEST_WITH_RETURN(dev, filp); return i915_quiescent(dev); } static int i915_batchbuffer(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) dev_priv->sarea_priv; drm_i915_batchbuffer_t batch; int ret; if (!dev_priv->allow_batchbuffer) { DRM_ERROR("Batchbuffer ioctl disabled\n"); return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data, sizeof(batch)); DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", batch.start, batch.used, batch.num_cliprects); LOCK_TEST_WITH_RETURN(dev, filp); if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects, batch.num_cliprects * sizeof(drm_clip_rect_t))) return DRM_ERR(EFAULT); ret = i915_dispatch_batchbuffer(dev, &batch); sarea_priv->last_dispatch = (int)hw_status[5]; return ret; } static int i915_cmdbuffer(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) dev_priv->sarea_priv; drm_i915_cmdbuffer_t cmdbuf; int ret; DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data, sizeof(cmdbuf)); DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects); LOCK_TEST_WITH_RETURN(dev, filp); if (cmdbuf.num_cliprects && DRM_VERIFYAREA_READ(cmdbuf.cliprects, cmdbuf.num_cliprects * sizeof(drm_clip_rect_t))) { DRM_ERROR("Fault accessing cliprects\n"); return DRM_ERR(EFAULT); } ret = i915_dispatch_cmdbuffer(dev, &cmdbuf); if (ret) { DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); return ret; } sarea_priv->last_dispatch = (int)hw_status[5]; return 0; } static int i915_do_cleanup_pageflip(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); if (dev_priv->current_page != 0) i915_dispatch_flip(dev); return 0; } static int i915_flip_bufs(DRM_IOCTL_ARGS) { DRM_DEVICE; DRM_DEBUG("%s\n", __FUNCTION__); LOCK_TEST_WITH_RETURN(dev, filp); return i915_dispatch_flip(dev); } static int i915_getparam(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_getparam_t param; int value; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data, sizeof(param)); switch (param.param) { case I915_PARAM_IRQ_ACTIVE: value = dev->irq ? 1 : 0; break; case I915_PARAM_ALLOW_BATCHBUFFER: value = dev_priv->allow_batchbuffer ? 1 : 0; break; case I915_PARAM_LAST_DISPATCH: value = READ_BREADCRUMB(dev_priv); break; default: DRM_ERROR("Unknown parameter %d\n", param.param); return DRM_ERR(EINVAL); } if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { DRM_ERROR("DRM_COPY_TO_USER failed\n"); return DRM_ERR(EFAULT); } return 0; } static int i915_setparam(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_setparam_t param; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __FUNCTION__); return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data, sizeof(param)); switch (param.param) { case I915_SETPARAM_USE_MI_BATCHBUFFER_START: dev_priv->use_mi_batchbuffer_start = param.value; break; case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: dev_priv->tex_lru_log_granularity = param.value; break; case I915_SETPARAM_ALLOW_BATCHBUFFER: dev_priv->allow_batchbuffer = param.value; break;