summaryrefslogtreecommitdiff
path: root/linux-core/r128_ioc32.c
blob: 64b167983360029566b09648fe3d258deac8c1d6 (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
/**
 * \file r128_ioc32.c
 *
 * 32-bit ioctl compatibility routines for the R128 DRM.
 *
 * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
 *
 * Copyright (C) Paul Mackerras 2005
 * Copyright (C) Egbert Eich 2003,2004
 * Copyright (C) Dave Airlie 2005
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
#include <linux/compat.h>

#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"

typedef struct drm_r128_init32 {
	int func;
	unsigned int sarea_priv_offset;
	int is_pci;
	int cce_mode;
	int cce_secure;
	int ring_size;
	int usec_timeout;

	unsigned int fb_bpp;
	unsigned int front_offset, front_pitch;
	unsigned int back_offset, back_pitch;
	unsigned int depth_bpp;
	unsigned int depth_offset, depth_pitch;
	unsigned int span_offset;

	unsigned int fb_offset;
	unsigned int mmio_offset;
	unsigned int ring_offset;
	unsigned int ring_rptr_offset;
	unsigned int buffers_offset;
	unsigned int agp_textures_offset;
} drm_r128_init32_t;

static int compat_r128_init(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
	drm_r128_init32_t init32;
	drm_r128_init_t __user *init;

	if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
		return -EFAULT;

	init = compat_alloc_user_space(sizeof(*init));
	if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
	    || __put_user(init32.func, &init->func)
	    || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
	    || __put_user(init32.is_pci, &init->is_pci)
	    || __put_user(init32.cce_mode, &init->cce_mode)
	    || __put_user(init32.cce_secure, &init->cce_secure)
	    || __put_user(init32.ring_size, &init->ring_size)
	    || __put_user(init32.usec_timeout, &init->usec_timeout)
	    || __put_user(init32.fb_bpp, &init->fb_bpp)
	    || __put_user(init32.front_offset, &init->front_offset)
	    || __put_user(init32.front_pitch, &init->front_pitch)
	    || __put_user(init32.back_offset, &init->back_offset)
	    || __put_user(init32.back_pitch, &init->back_pitch)
	    || __put_user(init32.depth_bpp, &init->depth_bpp)
	    || __put_user(init32.depth_offset, &init->depth_offset)
	    || __put_user(init32.depth_pitch, &init->depth_pitch)
	    || __put_user(init32.span_offset, &init->span_offset)
	    || __put_user(init32.fb_offset, &init->fb_offset)
	    || __put_user(init32.mmio_offset, &init->mmio_offset)
	    || __put_user(init32.ring_offset, &init->ring_offset)
	    || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
	    || __put_user(init32.buffers_offset, &init->buffers_offset)
	    || __put_user(init32.agp_textures_offset,
			  &init->agp_textures_offset))
		return -EFAULT;

	return drm_ioctl(file->f_dentry->d_inode, file,
			 DRM_IOCTL_R128_INIT, (unsigned long)init);
}


typedef struct drm_r128_depth32 {
	int func;
	int n;
	u32 x;
	u32 y;
	u32 buffer;
	u32 mask;
} drm_r128_depth32_t;

static int compat_r128_depth(struct file *file, unsigned int cmd,
			     unsigned long arg)
{
	drm_r128_depth32_t depth32;
	drm_r128_depth_t __user *depth;

	if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
		return -EFAULT;

	depth = compat_alloc_user_space(sizeof(*depth));
	if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth))
	    || __put_user(depth32.func, &depth->func)
	    || __put_user(depth32.n, &depth->n)
	    || __put_user((int __user *)(unsigned long)depth32.x, &depth->x)
	    || __put_user((int __user *)(unsigned long)depth32.y, &depth->y)
	    || __put_user((unsigned int __user *)(unsigned long)depth32.buffer,
			  &depth->buffer)
	    || __put_user((unsigned char __user *)(unsigned long)depth32.mask,
			  &depth->mask))
		return -EFAULT;

	return drm_ioctl(file->f_dentry->d_inode, file,
			 DRM_IOCTL_R128_DEPTH, (unsigned long)depth);

}

typedef struct drm_r128_stipple32 {
	u32 mask;
} drm_r128_stipple32_t;

static int compat_r128_stipple(struct file *file, unsigned int cmd,
			       unsigned long arg)
{
	drm_r128_stipple32_t stipple32;
	drm_r128_stipple_t __user *stipple;

	if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
		return -EFAULT;

	stipple = compat_alloc_user_space(sizeof(*stipple));
	if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
	    || __put_user((unsigned int __user *)(unsigned long)stipple32.mask,
			  &stipple->mask))
		return -EFAULT;

	return drm_ioctl(file->f_dentry->d_inode, file,
			 DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
}

typedef struct drm_r128_getparam32 {
	int param;
	u32 value;
} drm_r128_getparam32_t;

static int compat_r128_getparam(struct file *file, unsigned int cmd,
				unsigned long arg)
{
	drm_r128_getparam32_t getparam32;
	drm_r128_getparam_t __user *getparam;

	if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
		return -EFAULT;

	getparam = compat_alloc_user_space(sizeof(*getparam));
	if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
	    || __put_user(getparam32.param, &getparam->param)
	    || __put_user((void __user *)(unsigned long)getparam32.value,
			  &getparam->value))
		return -EFAULT;

	return drm_ioctl(file->f_dentry->d_inode, file,
			 DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
}

drm_ioctl_compat_t *r128_compat_ioctls[] = {
	[DRM_R128_INIT] = compat_r128_init,
	[DRM_R128_DEPTH] = compat_r128_depth,
	[DRM_R128_STIPPLE] = compat_r128_stipple,
	[DRM_R128_GETPARAM] = compat_r128_getparam,
};

/**
 * Called whenever a 32-bit process running under a 64-bit kernel
 * performs an ioctl on /dev/dri/card<n>.
 *
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument.
 * \return zero on success or negative number on failure.
 */
long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	unsigned int nr = DRM_IOCTL_NR(cmd);
	drm_ioctl_compat_t *fn = NULL;
	int ret;

	if (nr < DRM_COMMAND_BASE)
		return drm_compat_ioctl(filp, cmd, arg);

	if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
		fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];

	lock_kernel();		/* XXX for now */
	if (fn != NULL)
		ret = (*fn)(filp, cmd, arg);
	else
		ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
	unlock_kernel();

	return ret;
}
">int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); uint64_t (*read)(struct drm_device *dev); }; struct nouveau_fb_engine { int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); }; struct nouveau_fifo_engine { void *priv; int channels; int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); int (*channel_id)(struct drm_device *); int (*create_context)(struct nouveau_channel *); void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*save_context)(struct nouveau_channel *); }; struct nouveau_pgraph_engine { int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); int (*create_context)(struct nouveau_channel *); void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*save_context)(struct nouveau_channel *); }; struct nouveau_engine { struct nouveau_instmem_engine instmem; struct nouveau_mc_engine mc; struct nouveau_timer_engine timer; struct nouveau_fb_engine fb; struct nouveau_pgraph_engine graph; struct nouveau_fifo_engine fifo; }; #define NOUVEAU_MAX_CHANNEL_NR 128 struct drm_nouveau_private { enum { NOUVEAU_CARD_INIT_DOWN, NOUVEAU_CARD_INIT_DONE, NOUVEAU_CARD_INIT_FAILED } init_state; int ttm; /* the card type, takes NV_* as values */ int card_type; /* exact chipset, derived from NV_PMC_BOOT_0 */ int chipset; int flags; drm_local_map_t *mmio; drm_local_map_t *fb; drm_local_map_t *ramin; /* NV40 onwards */ int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; struct nouveau_engine Engine; struct nouveau_drm_channel channel; /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ struct nouveau_gpuobj *ramht; uint32_t ramin_rsvd_vram; uint32_t ramht_offset; uint32_t ramht_size; uint32_t ramht_bits; uint32_t ramfc_offset; uint32_t ramfc_size; uint32_t ramro_offset; uint32_t ramro_size; /* base physical adresses */ uint64_t fb_phys; uint64_t fb_available_size; struct { enum { NOUVEAU_GART_NONE = 0, NOUVEAU_GART_AGP, NOUVEAU_GART_SGDMA } type; uint64_t aper_base; uint64_t aper_size; struct nouveau_gpuobj *sg_ctxdma; struct page *sg_dummy_page; dma_addr_t sg_dummy_bus; /* nottm hack */ struct drm_ttm_backend *sg_be; unsigned long sg_handle; } gart_info; /* G8x global VRAM page table */ struct nouveau_gpuobj *vm_vram_pt; /* the mtrr covering the FB */ int fb_mtrr; struct mem_block *agp_heap; struct mem_block *fb_heap; struct mem_block *fb_nomap_heap; struct mem_block *ramin_heap; struct mem_block *pci_heap; /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */ uint32_t ctx_table_size; struct nouveau_gpuobj_ref *ctx_table; struct nouveau_config config; struct list_head gpuobj_list; }; #define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ struct drm_nouveau_private *nv = dev->dev_private; \ if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \ DRM_ERROR("called without init\n"); \ return -EINVAL; \ } \ } while(0) #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id,cl,ch) do { \ struct drm_nouveau_private *nv = dev->dev_private; \ if (!nouveau_fifo_owner(dev, (cl), (id))) { \ DRM_ERROR("pid %d doesn't own channel %d\n", \ DRM_CURRENTPID, (id)); \ return -EPERM; \ } \ (ch) = nv->fifos[(id)]; \ } while(0) /* nouveau_state.c */ extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); extern int nouveau_load(struct drm_device *, unsigned long flags); extern int nouveau_firstopen(struct drm_device *); extern void nouveau_lastclose(struct drm_device *); extern int nouveau_unload(struct drm_device *); extern int nouveau_ioctl_getparam(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_setparam(struct drm_device *, void *data, struct drm_file *); extern void nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); extern int nouveau_ioctl_card_init(struct drm_device *, void *data, struct drm_file *); /* nouveau_mem.c */ extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start, uint64_t size); extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, uint64_t size, int align2, struct drm_file *); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); extern uint64_t nouveau_mem_fb_amount(struct drm_device *); extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_mem_free(struct drm_device *, void *data, struct drm_file *); extern struct mem_block* nouveau_mem_alloc(struct drm_device *, int alignment, uint64_t size, int flags, struct drm_file *); extern void nouveau_mem_free(struct drm_device *dev, struct mem_block*); extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init_ttm(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); /* nouveau_notifier.c */ extern int nouveau_notifier_init_channel(struct nouveau_channel *); extern void nouveau_notifier_takedown_channel(struct nouveau_channel *); extern int nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int cout, uint32_t *offset); extern int nouveau_ioctl_notifier_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_notifier_free(struct drm_device *, void *data, struct drm_file *); /* nouveau_fifo.c */ extern int nouveau_fifo_init(struct drm_device *); extern int nouveau_fifo_ctx_size(struct drm_device *); extern void nouveau_fifo_cleanup(struct drm_device *, struct drm_file *); extern int nouveau_fifo_owner(struct drm_device *, struct drm_file *, int channel); extern int nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan, struct drm_file *file_priv, struct mem_block *pushbuf, uint32_t fb_ctxdma, uint32_t tt_ctxdma); extern void nouveau_fifo_free(struct nouveau_channel *); /* nouveau_object.c */ extern int nouveau_gpuobj_early_init(struct drm_device *); extern int nouveau_gpuobj_init(struct drm_device *); extern void nouveau_gpuobj_takedown(struct drm_device *); extern void nouveau_gpuobj_late_takedown(struct drm_device *); extern int nouveau_gpuobj_channel_init(struct nouveau_channel *, uint32_t vram_h, uint32_t tt_h); extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *, int size, int align, uint32_t flags, struct nouveau_gpuobj **); extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **); extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *, uint32_t handle, struct nouveau_gpuobj *, struct nouveau_gpuobj_ref **); extern int nouveau_gpuobj_ref_del(struct drm_device *, struct nouveau_gpuobj_ref **); extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle, struct nouveau_gpuobj_ref **ref_ret); extern int nouveau_gpuobj_new_ref(struct drm_device *, struct nouveau_channel *alloc_chan, struct nouveau_channel *ref_chan, uint32_t handle, int size, int align, uint32_t flags, struct nouveau_gpuobj_ref **); extern int nouveau_gpuobj_new_fake(struct drm_device *, uint32_t p_offset, uint32_t b_offset, uint32_t size, uint32_t flags, struct nouveau_gpuobj **, struct nouveau_gpuobj_ref**); extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, uint64_t offset, uint64_t size, int access, int target, struct nouveau_gpuobj **); extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, uint64_t offset, uint64_t size, int access, struct nouveau_gpuobj **, uint32_t *o_ret); extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, struct nouveau_gpuobj **); extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, struct drm_file *); /* nouveau_irq.c */ extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); extern void nouveau_irq_preinstall(struct drm_device *); extern int nouveau_irq_postinstall(struct drm_device *); extern void nouveau_irq_uninstall(struct drm_device *); /* nouveau_sgdma.c */ extern int nouveau_sgdma_init(struct drm_device *); extern void nouveau_sgdma_takedown(struct drm_device *); extern int nouveau_sgdma_get_page(struct drm_device *, uint32_t offset, uint32_t *page); extern struct drm_ttm_backend *nouveau_sgdma_init_ttm(struct drm_device *); extern int nouveau_sgdma_nottm_hack_init(struct drm_device *); extern void nouveau_sgdma_nottm_hack_takedown(struct drm_device *); /* nouveau_dma.c */ extern int nouveau_dma_channel_init(struct drm_device *); extern void nouveau_dma_channel_takedown(struct drm_device *); extern int nouveau_dma_wait(struct drm_device *, int size); /* nv04_fb.c */ extern int nv04_fb_init(struct drm_device *); extern void nv04_fb_takedown(struct drm_device *); /* nv10_fb.c */ extern int nv10_fb_init(struct drm_device *); extern void nv10_fb_takedown(struct drm_device *); /* nv40_fb.c */ extern int nv40_fb_init(struct drm_device *); extern void nv40_fb_takedown(struct drm_device *); /* nv04_fifo.c */ extern int nv04_fifo_channel_id(struct drm_device *); extern int nv04_fifo_create_context(struct nouveau_channel *); extern void nv04_fifo_destroy_context(struct nouveau_channel *); extern int nv04_fifo_load_context(struct nouveau_channel *); extern int nv04_fifo_save_context(struct nouveau_channel *); /* nv10_fifo.c */ extern int nv10_fifo_channel_id(struct drm_device *); extern int nv10_fifo_create_context(struct nouveau_channel *); extern void nv10_fifo_destroy_context(struct nouveau_channel *); extern int nv10_fifo_load_context(struct nouveau_channel *);