summaryrefslogtreecommitdiff
path: root/include
AgeCommit message (Expand)Author
2010-03-17Install headers to $(includedir)/libdrmJulien Cristau
2010-03-02libdrm/intel: execbuf2 supportJesse Barnes
2010-02-18vmwgfx: Update kernel headerJakob Bornecrantz
2010-02-18radeon: add square-tiling flagMarek Olšák
2010-02-16nouveau: bump MAX_PUSH to 512Ben Skeggs
2010-02-16nouveau: interface changes for 0.0.16 DRMLuca Barbieri
2010-01-27nouveau: Update nouveau_drm.hMarcin Kościelnicki
2010-01-05vmwgfx: Add experimental vmwgfx kernel headerJakob Bornecrantz
2009-12-02Merge branch 'modesetting-dirty-libdrm'Jakob Bornecrantz
2009-12-03Merge branch 'pageflip' of git://people.freedesktop.org/~jbarnes/drmJesse Barnes
2009-12-02Change the number on the dirty ioctl to match upstreamJakob Bornecrantz
2009-11-30Change the dirty ioctl a bit and comment itJakob Bornecrantz
2009-11-26Bring dirty code from old branchJakob Bornecrantz
2009-11-24More fixups to allow mesa to buildRobert Noland
2009-11-24Finish fixing the build on FreeBSDRobert Noland
2009-11-23Fix build on *BSDKristian Høgsberg
2009-11-23Drop duplicated radeon_*.h files in include/drmKristian Høgsberg
2009-11-20Put mach64_drm.h back in to avoid breaking mesa buildKristian Høgsberg
2009-11-20Install kernel headers in ${includedir}/drmKristian Høgsberg
2009-11-21nouveau: fix DRM headersPekka Paalanen
2009-11-17Fix typo in i915 pipe_from_crtc_id ioctl struct nameKristian Høgsberg
2009-11-17Copy headers from kernel v2.6.32-rc6-130-g5b8f0beKristian Høgsberg
/a> 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 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*-
 * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
 * Revised: Fri Aug 20 11:32:09 1999 by faith@precisioninsight.com
 *
 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 * 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
 * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
 * 
 * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/context.c,v 1.2 2000/02/23 04:47:26 martin Exp $
 *
 */

#define __NO_VERSION__
#include "drmP.h"

static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
{
	DRM_DEBUG("\n");
	
	if (atomic_read(&q->use_count) != 1
	    || atomic_read(&q->finalization)
	    || atomic_read(&q->block_count)) {
		DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
			  atomic_read(&q->use_count),
			  atomic_read(&q->finalization),
			  atomic_read(&q->block_count));
	}
		  
	atomic_set(&q->finalization,  0);
	atomic_set(&q->block_count,   0);
	atomic_set(&q->block_read,    0);
	atomic_set(&q->block_write,   0);
	atomic_set(&q->total_queued,  0);
	atomic_set(&q->total_flushed, 0);
	atomic_set(&q->total_locks,   0);

	init_waitqueue_head(&q->write_queue);
	init_waitqueue_head(&q->read_queue);
	init_waitqueue_head(&q->flush_queue);

	q->flags = ctx->flags;

	drm_waitlist_create(&q->waitlist, dev->dma->buf_count);

	return 0;
}


/* drm_alloc_queue:
PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
	disappear (so all deallocation must be done after IOCTLs are off)
     2) dev->queue_count < dev->queue_slots
     3) dev->queuelist[i].use_count == 0 and
	dev->queuelist[i].finalization == 0 if i not in use 
POST: 1) dev->queuelist[i].use_count == 1
      2) dev->queue_count < dev->queue_slots */
		
static int drm_alloc_queue(drm_device_t *dev)
{
	int	    i;
	drm_queue_t *queue;
	int	    oldslots;
	int	    newslots;
				/* Check for a free queue */
	for (i = 0; i < dev->queue_count; i++) {
		atomic_inc(&dev->queuelist[i]->use_count);
		if (atomic_read(&dev->queuelist[i]->use_count) == 1
		    && !atomic_read(&dev->queuelist[i]->finalization)) {
			DRM_DEBUG("%d (free)\n", i);
			return i;
		}
		atomic_dec(&dev->queuelist[i]->use_count);
	}
				/* Allocate a new queue */
	down(&dev->struct_sem);
	
	queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
	memset(queue, 0, sizeof(*queue));
	atomic_set(&queue->use_count, 1);
	
	++dev->queue_count;
	if (dev->queue_count >= dev->queue_slots) {
		oldslots = dev->queue_slots * sizeof(*dev->queuelist);
		if (!dev->queue_slots) dev->queue_slots = 1;
		dev->queue_slots *= 2;
		newslots = dev->queue_slots * sizeof(*dev->queuelist);

		dev->queuelist = drm_realloc(dev->queuelist,
					     oldslots,
					     newslots,
					     DRM_MEM_QUEUES);
		if (!dev->queuelist) {
			up(&dev->struct_sem);
			DRM_DEBUG("out of memory\n");
			return -ENOMEM;
		}
	}
	dev->queuelist[dev->queue_count-1] = queue;
	
	up(&dev->struct_sem);
	DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
	return dev->queue_count - 1;
}

int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
	       unsigned long arg)
{
	drm_ctx_res_t	res;
	drm_ctx_t	ctx;
	int		i;

	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
	if (res.count >= DRM_RESERVED_CONTEXTS) {
		memset(&ctx, 0, sizeof(ctx));
		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
			ctx.handle = i;
			copy_to_user_ret(&res.contexts[i],
					 &i,
					 sizeof(i),
					 -EFAULT);
		}
	}
	res.count = DRM_RESERVED_CONTEXTS;
	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
	return 0;
}


int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
	       unsigned long arg)
{
	drm_file_t	*priv	= filp->private_data;
	drm_device_t	*dev	= priv->dev;
	drm_ctx_t	ctx;

	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
	if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
				/* Init kernel's context and get a new one. */
		drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
		ctx.handle = drm_alloc_queue(dev);
	}
	drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
	DRM_DEBUG("%d\n", ctx.handle);
	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
	return 0;
}

int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
	       unsigned long arg)
{
	drm_file_t	*priv	= filp->private_data;
	drm_device_t	*dev	= priv->dev;
	drm_ctx_t	ctx;
	drm_queue_t	*q;
		
	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
	
	DRM_DEBUG("%d\n", ctx.handle);
	
	if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
	q = dev->queuelist[ctx.handle];
	
	atomic_inc(&q->use_count);
	if (atomic_read(&q->use_count) == 1) {
				/* No longer in use */
		atomic_dec(&q->use_count);
		return -EINVAL;
	}

	if (DRM_BUFCOUNT(&q->waitlist)) {
		atomic_dec(&q->use_count);
		return -EBUSY;
	}
	
	q->flags = ctx.flags;
	
	atomic_dec(&q->use_count);
	return 0;
}

int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
	       unsigned long arg)
{
	drm_file_t	*priv	= filp->private_data;
	drm_device_t	*dev	= priv->dev;
	drm_ctx_t	ctx;
	drm_queue_t	*q;
		
	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
	
	DRM_DEBUG("%d\n", ctx.handle);
	
	if (ctx.handle >= dev->queue_count) return -EINVAL;
	q = dev->queuelist[ctx.handle];
	
	atomic_inc(&q->use_count);
	if (atomic_read(&q->use_count) == 1) {
				/* No longer in use */
		atomic_dec(&q->use_count);
		return -EINVAL;
	}
	
	ctx.flags = q->flags;
	atomic_dec(&q->use_count);
	
	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
	
	return 0;
}

int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
		  unsigned long arg)
{
	drm_file_t	*priv	= filp->private_data;
	drm_device_t	*dev	= priv->dev;
	drm_ctx_t	ctx;

	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
	DRM_DEBUG("%d\n", ctx.handle);
	return drm_context_switch(dev, dev->last_context, ctx.handle);
}

int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
	       unsigned long arg)
{
	drm_file_t	*priv	= filp->private_data;
	drm_device_t	*dev	= priv->dev;
	drm_ctx_t	ctx;

	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
	DRM_DEBUG("%d\n", ctx.handle);
	drm_context_switch_complete(dev, ctx.handle);

	return 0;
}

int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
	      unsigned long arg)
{
	drm_file_t	*priv	= filp->private_data;
	drm_device_t	*dev	= priv->dev;
	drm_ctx_t	ctx;
	drm_queue_t	*q;
	drm_buf_t	*buf;

	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
	DRM_DEBUG("%d\n", ctx.handle);
	
	if (ctx.handle >= dev->queue_count) return -EINVAL;
	q = dev->queuelist[ctx.handle];
	
	atomic_inc(&q->use_count);
	if (atomic_read(&q->use_count) == 1) {
				/* No longer in use */
		atomic_dec(&q->use_count);
		return -EINVAL;
	}
	
	atomic_inc(&q->finalization); /* Mark queue in finalization state */
	atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
					 finalization) */

	while (test_and_set_bit(0, &dev->interrupt_flag)) {
		schedule();
		if (signal_pending(current)) {
			clear_bit(0, &dev->interrupt_flag);
			return -EINTR;
		}
	}
				/* Remove queued buffers */
	while ((buf = drm_waitlist_get(&q->waitlist))) {
		drm_free_buffer(dev, buf);
	}
	clear_bit(0, &dev->interrupt_flag);
	
				/* Wakeup blocked processes */
	wake_up_interruptible(&q->read_queue);
	wake_up_interruptible(&q->write_queue);
	wake_up_interruptible(&q->flush_queue);
	
				/* Finalization over.  Queue is made
				   available when both use_count and
				   finalization become 0, which won't
				   happen until all the waiting processes
				   stop waiting. */
	atomic_dec(&q->finalization);
	return 0;
}