aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/drm
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@insightbb.com>2007-02-10 01:26:32 -0500
committerDmitry Torokhov <dtor@insightbb.com>2007-02-10 01:26:32 -0500
commitb22364c8eec89e6b0c081a237f3b6348df87796f (patch)
tree233a923281fb640106465d076997ff511efb6edf /drivers/char/drm
parent2c8dc071517ec2843869024dc82be2e246f41064 (diff)
parent66efc5a7e3061c3597ac43a8bb1026488d57e66b (diff)
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/char/drm')
-rw-r--r--drivers/char/drm/drm.h33
-rw-r--r--drivers/char/drm/drmP.h66
-rw-r--r--drivers/char/drm/drm_bufs.c29
-rw-r--r--drivers/char/drm/drm_core.h8
-rw-r--r--drivers/char/drm/drm_drawable.c294
-rw-r--r--drivers/char/drm/drm_drv.c14
-rw-r--r--drivers/char/drm/drm_ioc32.c56
-rw-r--r--drivers/char/drm/drm_irq.c155
-rw-r--r--drivers/char/drm/drm_lock.c13
-rw-r--r--drivers/char/drm/drm_memory.c94
-rw-r--r--drivers/char/drm/drm_memory.h20
-rw-r--r--drivers/char/drm/drm_memory_debug.h70
-rw-r--r--drivers/char/drm/drm_mm.c183
-rw-r--r--drivers/char/drm/drm_pciids.h4
-rw-r--r--drivers/char/drm/drm_proc.c4
-rw-r--r--drivers/char/drm/drm_sman.c3
-rw-r--r--drivers/char/drm/drm_stub.c14
-rw-r--r--drivers/char/drm/drm_sysfs.c8
-rw-r--r--drivers/char/drm/drm_vm.c32
-rw-r--r--drivers/char/drm/i810_dma.c34
-rw-r--r--drivers/char/drm/i810_drv.h2
-rw-r--r--drivers/char/drm/i830_dma.c32
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/i915_dma.c2
-rw-r--r--drivers/char/drm/i915_drm.h19
-rw-r--r--drivers/char/drm/i915_drv.c4
-rw-r--r--drivers/char/drm/i915_drv.h22
-rw-r--r--drivers/char/drm/i915_ioc32.c12
-rw-r--r--drivers/char/drm/i915_irq.c344
-rw-r--r--drivers/char/drm/mga_ioc32.c8
-rw-r--r--drivers/char/drm/r128_drm.h3
-rw-r--r--drivers/char/drm/r128_drv.h3
-rw-r--r--drivers/char/drm/r128_ioc32.c10
-rw-r--r--drivers/char/drm/r128_state.c3
-rw-r--r--drivers/char/drm/r300_cmdbuf.c32
-rw-r--r--drivers/char/drm/radeon_drv.h15
-rw-r--r--drivers/char/drm/radeon_ioc32.c20
-rw-r--r--drivers/char/drm/radeon_irq.c4
-rw-r--r--drivers/char/drm/radeon_mem.c4
-rw-r--r--drivers/char/drm/radeon_state.c13
-rw-r--r--drivers/char/drm/savage_bci.c4
-rw-r--r--drivers/char/drm/via_dma.c9
-rw-r--r--drivers/char/drm/via_dmablit.c2
-rw-r--r--drivers/char/drm/via_drv.h11
-rw-r--r--drivers/char/drm/via_irq.c16
-rw-r--r--drivers/char/drm/via_map.c3
-rw-r--r--drivers/char/drm/via_verifier.c50
-rw-r--r--drivers/char/drm/via_verifier.h1
48 files changed, 1308 insertions, 476 deletions
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 5642ac43e0f..8db9041e306 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -117,6 +117,14 @@ typedef struct drm_clip_rect {
} drm_clip_rect_t;
/**
+ * Drawable information.
+ */
+typedef struct drm_drawable_info {
+ unsigned int num_rects;
+ drm_clip_rect_t *rects;
+} drm_drawable_info_t;
+
+/**
* Texture region,
*/
typedef struct drm_tex_region {
@@ -348,7 +356,8 @@ typedef struct drm_buf_desc {
_DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
_DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
_DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */
- _DRM_FB_BUFFER = 0x08 /**< Buffer is in frame buffer */
+ _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */
+ _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */
} flags;
unsigned long agp_start; /**<
* Start address of where the AGP buffers are
@@ -444,6 +453,20 @@ typedef struct drm_draw {
} drm_draw_t;
/**
+ * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
+ */
+typedef enum {
+ DRM_DRAWABLE_CLIPRECTS,
+} drm_drawable_info_type_t;
+
+typedef struct drm_update_draw {
+ drm_drawable_t handle;
+ unsigned int type;
+ unsigned int num;
+ unsigned long long data;
+} drm_update_draw_t;
+
+/**
* DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
*/
typedef struct drm_auth {
@@ -465,10 +488,14 @@ typedef struct drm_irq_busid {
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
+ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
+ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
} drm_vblank_seq_type_t;
-#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
+#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
+ _DRM_VBLANK_NEXTONMISS)
struct drm_wait_vblank_request {
drm_vblank_seq_type_t type;
@@ -623,6 +650,8 @@ typedef struct drm_set_version {
#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t)
+
/**
* Device specific ioctls should only be in their respective headers
* The device specific ioctl range is from 0x40 to 0x79.
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 7690a59ace0..85d99e21e18 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -97,6 +97,7 @@
#define DRIVER_IRQ_VBL 0x100
#define DRIVER_DMA_QUEUE 0x200
#define DRIVER_FB_DMA 0x400
+#define DRIVER_IRQ_VBL2 0x800
/***********************************************************************/
/** \name Begin the DRM... */
@@ -430,7 +431,8 @@ typedef struct drm_device_dma {
enum {
_DRM_DMA_USE_AGP = 0x01,
_DRM_DMA_USE_SG = 0x02,
- _DRM_DMA_USE_FB = 0x04
+ _DRM_DMA_USE_FB = 0x04,
+ _DRM_DMA_USE_PCI_RO = 0x08
} flags;
} drm_device_dma_t;
@@ -530,11 +532,13 @@ typedef struct drm_mm_node {
int free;
unsigned long start;
unsigned long size;
+ struct drm_mm *mm;
void *private;
} drm_mm_node_t;
typedef struct drm_mm {
- drm_mm_node_t root_node;
+ struct list_head fl_entry;
+ struct list_head ml_entry;
} drm_mm_t;
/**
@@ -559,9 +563,9 @@ struct drm_driver {
int (*context_dtor) (struct drm_device * dev, int context);
int (*kernel_context_switch) (struct drm_device * dev, int old,
int new);
- void (*kernel_context_switch_unlock) (struct drm_device * dev,
- drm_lock_t *lock);
+ void (*kernel_context_switch_unlock) (struct drm_device * dev);
int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence);
+ int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence);
int (*dri_library_name) (struct drm_device *dev, char *buf);
/**
@@ -708,9 +712,13 @@ typedef struct drm_device {
wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
atomic_t vbl_received;
+ atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
spinlock_t vbl_lock;
drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */
+ drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */
unsigned int vbl_pending;
+ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
+ void (*locked_tasklet_func)(struct drm_device *dev);
/*@} */
cycles_t ctx_start;
@@ -738,6 +746,15 @@ typedef struct drm_device {
drm_local_map_t *agp_buffer_map;
unsigned int agp_buffer_token;
drm_head_t primary; /**< primary screen head */
+
+ /** \name Drawable information */
+ /*@{ */
+ spinlock_t drw_lock;
+ unsigned int drw_bitfield_length;
+ u32 *drw_bitfield;
+ unsigned int drw_info_length;
+ drm_drawable_info_t **drw_info;
+ /*@} */
} drm_device_t;
static __inline__ int drm_core_check_feature(struct drm_device *dev,
@@ -828,9 +845,6 @@ extern void drm_mem_init(void);
extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev);
extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
@@ -885,6 +899,10 @@ extern int drm_adddraw(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_rmdraw(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
+ drm_drawable_t id);
/* Authentication IOCTL support (drm_auth.h) */
extern int drm_getmagic(struct inode *inode, struct file *filp,
@@ -949,6 +967,7 @@ extern int drm_wait_vblank(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq);
extern void drm_vbl_send_signals(drm_device_t * dev);
+extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*));
/* AGP/GART support (drm_agpsupport.h) */
extern drm_agp_head_t *drm_agp_init(drm_device_t * dev);
@@ -1033,33 +1052,18 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev);
extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size,
unsigned alignment);
-extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+void drm_mm_put_block(drm_mm_node_t * cur);
extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
unsigned alignment, int best_match);
extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
extern void drm_mm_takedown(drm_mm_t *mm);
+extern int drm_mm_clean(drm_mm_t *mm);
+extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
+extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
-/* Inline replacements for DRM_IOREMAP macros */
-static __inline__ void drm_core_ioremap(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap(map->offset, map->size, dev);
-}
-
-#if 0
-static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
-}
-#endif /* 0 */
-
-static __inline__ void drm_core_ioremapfree(struct drm_map *map,
- struct drm_device *dev)
-{
- if (map->handle && map->size)
- drm_ioremapfree(map->handle, map->size, dev);
-}
+extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
unsigned int token)
@@ -1122,9 +1126,5 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area);
extern unsigned long drm_core_get_map_ofs(drm_map_t * map);
extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
-#ifndef pci_pretty_name
-#define pci_pretty_name(dev) ""
-#endif
-
#endif /* __KERNEL__ */
#endif
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 6eafff13dab..a6828cc14e5 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -79,14 +79,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
if (!use_hashed_handle) {
int ret;
- hash->key = user_token;
+ hash->key = user_token >> PAGE_SHIFT;
ret = drm_ht_insert_item(&dev->map_hash, hash);
if (ret != -EINVAL)
return ret;
}
return drm_ht_just_insert_please(&dev->map_hash, hash,
user_token, 32 - PAGE_SHIFT - 3,
- PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+ 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
}
/**
@@ -178,11 +178,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
}
}
if (map->type == _DRM_REGISTERS)
- map->handle = drm_ioremap(map->offset, map->size, dev);
+ map->handle = ioremap(map->offset, map->size);
break;
case _DRM_SHM:
- map->handle = vmalloc_32(map->size);
+ map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
if (!map->handle) {
@@ -238,7 +238,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
mutex_unlock(&dev->struct_mutex);
return ret;
}
- list->user_token = list->hash.key;
+ list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex);
*maplist = list;
@@ -347,7 +347,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
if (r_list->map == map) {
list_del(list);
- drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+ drm_ht_remove_key(&dev->map_hash,
+ r_list->user_token >> PAGE_SHIFT);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
break;
}
@@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
switch (map->type) {
case _DRM_REGISTERS:
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
/* FALLTHROUGH */
case _DRM_FRAME_BUFFER:
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
@@ -887,6 +888,9 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
request->count = entry->buf_count;
request->size = size;
+ if (request->flags & _DRM_PCI_BUFFER_RO)
+ dma->flags = _DRM_DMA_USE_PCI_RO;
+
atomic_dec(&dev->buf_alloc);
return 0;
@@ -1471,9 +1475,10 @@ int drm_freebufs(struct inode *inode, struct file *filp,
* \param arg pointer to a drm_buf_map structure.
* \return zero on success or a negative number on failure.
*
- * Maps the AGP or SG buffer region with do_mmap(), and copies information
- * about each buffer into user space. The PCI buffers are already mapped on the
- * addbufs_pci() call.
+ * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information
+ * about each buffer into user space. For PCI buffers, it calls do_mmap() with
+ * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
+ * drm_mmap_dma().
*/
int drm_mapbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h
index f4f9db6c7ed..31673903607 100644
--- a/drivers/char/drm/drm_core.h
+++ b/drivers/char/drm/drm_core.h
@@ -24,11 +24,11 @@
#define CORE_NAME "drm"
#define CORE_DESC "DRM shared core routines"
-#define CORE_DATE "20051102"
+#define CORE_DATE "20060810"
#define DRM_IF_MAJOR 1
-#define DRM_IF_MINOR 2
+#define DRM_IF_MINOR 3
#define CORE_MAJOR 1
-#define CORE_MINOR 0
-#define CORE_PATCHLEVEL 1
+#define CORE_MINOR 1
+#define CORE_PATCHLEVEL 0
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c
index 7857453c4f4..de37d5f7456 100644
--- a/drivers/char/drm/drm_drawable.c
+++ b/drivers/char/drm/drm_drawable.c
@@ -4,6 +4,7 @@
*
* \author Rickard E. (Rik) Faith <faith@valinux.com>
* \author Gareth Hughes <gareth@valinux.com>
+ * \author Michel Dänzer <michel@tungstengraphics.com>
*/
/*
@@ -11,6 +12,7 @@
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -35,22 +37,294 @@
#include "drmP.h"
-/** No-op. */
-int drm_adddraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+/**
+ * Allocate drawable ID and memory to store information about it.
+ */
+int drm_adddraw(DRM_IOCTL_ARGS)
{
+ DRM_DEVICE;
+ unsigned long irqflags;
+ int i, j;
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned int bitfield_length = dev->drw_bitfield_length;
+ drm_drawable_info_t **info = dev->drw_info;
+ unsigned int info_length = dev->drw_info_length;
drm_draw_t draw;
- draw.handle = 0; /* NOOP */
+ for (i = 0, j = 0; i < bitfield_length; i++) {
+ if (bitfield[i] == ~0)
+ continue;
+
+ for (; j < 8 * sizeof(*bitfield); j++)
+ if (!(bitfield[i] & (1 << j)))
+ goto done;
+ }
+done:
+
+ if (i == bitfield_length) {
+ bitfield_length++;
+
+ bitfield = drm_alloc(bitfield_length * sizeof(*bitfield),
+ DRM_MEM_BUFS);
+
+ if (!bitfield) {
+ DRM_ERROR("Failed to allocate new drawable bitfield\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ if (8 * sizeof(*bitfield) * bitfield_length > info_length) {
+ info_length += 8 * sizeof(*bitfield);
+
+ info = drm_alloc(info_length * sizeof(*info),
+ DRM_MEM_BUFS);
+
+ if (!info) {
+ DRM_ERROR("Failed to allocate new drawable info"
+ " array\n");
+
+ drm_free(bitfield,
+ bitfield_length * sizeof(*bitfield),
+ DRM_MEM_BUFS);
+ return DRM_ERR(ENOMEM);
+ }
+ }
+
+ bitfield[i] = 0;
+ }
+
+ draw.handle = i * 8 * sizeof(*bitfield) + j + 1;
DRM_DEBUG("%d\n", draw.handle);
- if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw)))
- return -EFAULT;
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ bitfield[i] |= 1 << j;
+ info[draw.handle - 1] = NULL;
+
+ if (bitfield != dev->drw_bitfield) {
+ memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
+ sizeof(*bitfield));
+ drm_free(dev->drw_bitfield, sizeof(*bitfield) *
+ dev->drw_bitfield_length, DRM_MEM_BUFS);
+ dev->drw_bitfield = bitfield;
+ dev->drw_bitfield_length = bitfield_length;
+ }
+
+ if (info != dev->drw_info) {
+ memcpy(info, dev->drw_info, dev->drw_info_length *
+ sizeof(*info));
+ drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length,
+ DRM_MEM_BUFS);
+ dev->drw_info = info;
+ dev->drw_info_length = info_length;
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
+
return 0;
}
-/** No-op. */
-int drm_rmdraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+/**
+ * Free drawable ID and memory to store information about it.
+ */
+int drm_rmdraw(DRM_IOCTL_ARGS)
{
- return 0; /* NOOP */
+ DRM_DEVICE;
+ drm_draw_t draw;
+ int id, idx;
+ unsigned int shift;
+ unsigned long irqflags;
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned int bitfield_length = dev->drw_bitfield_length;
+ drm_drawable_info_t **info = dev->drw_info;
+ unsigned int info_length = dev->drw_info_length;
+
+ DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
+ sizeof(draw));
+
+ id = draw.handle - 1;
+ idx = id / (8 * sizeof(*bitfield));
+ shift = id % (8 * sizeof(*bitfield));
+
+ if (idx < 0 || idx >= bitfield_length ||
+ !(bitfield[idx] & (1 << shift))) {
+ DRM_DEBUG("No such drawable %d\n", draw.handle);
+ return 0;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ bitfield[idx] &= ~(1 << shift);
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ if (info[id]) {
+ drm_free(info[id]->rects, info[id]->num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ drm_free(info[id], sizeof(**info), DRM_MEM_BUFS);
+ }
+
+ /* Can we shrink the arrays? */
+ if (idx == bitfield_length - 1) {
+ while (idx >= 0 && !bitfield[idx])
+ --idx;
+
+ bitfield_length = idx + 1;
+
+ if (idx != id / (8 * sizeof(*bitfield)))
+ bitfield = drm_alloc(bitfield_length *
+ sizeof(*bitfield), DRM_MEM_BUFS);
+
+ if (!bitfield && bitfield_length) {
+ bitfield = dev->drw_bitfield;
+ bitfield_length = dev->drw_bitfield_length;
+ }
+ }
+
+ if (bitfield != dev->drw_bitfield) {
+ info_length = 8 * sizeof(*bitfield) * bitfield_length;
+
+ info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS);
+
+ if (!info && info_length) {
+ info = dev->drw_info;
+ info_length = dev->drw_info_length;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ memcpy(bitfield, dev->drw_bitfield, bitfield_length *
+ sizeof(*bitfield));
+ drm_free(dev->drw_bitfield, sizeof(*bitfield) *
+ dev->drw_bitfield_length, DRM_MEM_BUFS);
+ dev->drw_bitfield = bitfield;
+ dev->drw_bitfield_length = bitfield_length;
+
+ if (info != dev->drw_info) {
+ memcpy(info, dev->drw_info, info_length *
+ sizeof(*info));
+ drm_free(dev->drw_info, sizeof(*info) *
+ dev->drw_info_length, DRM_MEM_BUFS);
+ dev->drw_info = info;
+ dev->drw_info_length = info_length;
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ }
+
+ DRM_DEBUG("%d\n", draw.handle);
+ return 0;
+}
+
+int drm_update_drawable_info(DRM_IOCTL_ARGS) {
+ DRM_DEVICE;
+ drm_update_draw_t update;
+ unsigned int id, idx, shift;
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned long irqflags, bitfield_length = dev->drw_bitfield_length;
+ drm_drawable_info_t *info;
+ drm_clip_rect_t *rects;
+ int err;
+
+ DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
+ sizeof(update));
+
+ id = update.handle - 1;
+ idx = id / (8 * sizeof(*bitfield));
+ shift = id % (8 * sizeof(*bitfield));
+
+ if (idx < 0 || idx >= bitfield_length ||
+ !(bitfield[idx] & (1 << shift))) {
+ DRM_ERROR("No such drawable %d\n", update.handle);
+ return DRM_ERR(EINVAL);
+ }
+
+ info = dev->drw_info[id];
+
+ if (!info) {
+ info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS);
+
+ if (!info) {
+ DRM_ERROR("Failed to allocate drawable info memory\n");
+ return DRM_ERR(ENOMEM);
+ }
+ }
+
+ switch (update.type) {
+ case DRM_DRAWABLE_CLIPRECTS:
+ if (update.num != info->num_rects) {
+ rects = drm_alloc(update.num * sizeof(drm_clip_rect_t),
+ DRM_MEM_BUFS);
+ } else
+ rects = info->rects;
+
+ if (update.num && !rects) {
+ DRM_ERROR("Failed to allocate cliprect memory\n");
+ err = DRM_ERR(ENOMEM);
+ goto error;
+ }
+
+ if (update.num && DRM_COPY_FROM_USER(rects,
+ (drm_clip_rect_t __user *)
+ (unsigned long)update.data,
+ update.num *
+ sizeof(*rects))) {
+ DRM_ERROR("Failed to copy cliprects from userspace\n");
+ err = DRM_ERR(EFAULT);
+ goto error;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ if (rects != info->rects) {
+ drm_free(info->rects, info->num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ }
+
+ info->rects = rects;
+ info->num_rects = update.num;
+ dev->drw_info[id] = info;
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ DRM_DEBUG("Updated %d cliprects for drawable %d\n",
+ info->num_rects, id);
+ break;
+ default:
+ DRM_ERROR("Invalid update type %d\n", update.type);
+ return DRM_ERR(EINVAL);
+ }
+
+ return 0;
+
+error:
+ if (!dev->drw_info[id])
+ drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+ else if (rects != dev->drw_info[id]->rects)
+ drm_free(rects, update.num *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+
+ return err;
+}
+
+/**
+ * Caller must hold the drawable spinlock!
+ */
+drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned int idx, shift;
+
+ id--;
+ idx = id / (8 * sizeof(*bitfield));
+ shift = id % (8 * sizeof(*bitfield));
+
+ if (idx < 0 || idx >= dev->drw_bitfield_length ||
+ !(bitfield[idx] & (1 << shift))) {
+ DRM_DEBUG("No such drawable %d\n", id);
+ return NULL;
+ }
+
+ return dev->drw_info[id];
}
+EXPORT_SYMBOL(drm_get_drawable_info);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index b366c5b1bd1..a70af0de445 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -116,6 +116,8 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+
+ [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@@ -151,6 +153,18 @@ int drm_lastclose(drm_device_t * dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
+ /* Free drawable information memory */
+ for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
+ i++) {
+ drm_drawable_info_t *info = drm_get_drawable_info(dev, i);
+
+ if (info) {
+ drm_free(info->rects, info->num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+ }
+ }
+
mutex_lock(&dev->struct_mutex);
del_timer(&dev->timer);
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index d4f87452008..fafeb34f89d 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -102,7 +102,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
&version->desc))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_VERSION, (unsigned long)version);
if (err)
return err;
@@ -143,7 +143,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd,
&u->unique))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
if (err)
return err;
@@ -172,7 +172,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd,
&u->unique))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
}
@@ -203,7 +203,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd,
if (__put_user(idx, &map->offset))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_MAP, (unsigned long)map);
if (err)
return err;
@@ -244,7 +244,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
|| __put_user(m32.flags, &map->flags))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_ADD_MAP, (unsigned long)map);
if (err)
return err;
@@ -282,7 +282,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd,
if (__put_user((void *)(unsigned long)handle, &map->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RM_MAP, (unsigned long)map);
}
@@ -312,7 +312,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd,
if (__put_user(idx, &client->idx))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_CLIENT, (unsigned long)client);
if (err)
return err;
@@ -349,7 +349,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_STATS, (unsigned long)stats);
if (err)
return err;
@@ -393,7 +393,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd,
|| __put_user(agp_start, &buf->agp_start))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
if (err)
return err;
@@ -425,7 +425,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd,
|| __put_user(b32.high_mark, &buf->high_mark))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
}
@@ -467,7 +467,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_INFO_BUFS, (unsigned long)request);
if (err)
return err;
@@ -529,7 +529,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MAP_BUFS, (unsigned long)request);
if (err)
return err;
@@ -576,7 +576,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd,
&request->list))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_FREE_BUFS, (unsigned long)request);
}
@@ -603,7 +603,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
&request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
}
@@ -626,7 +626,7 @@ static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
if (__put_user(ctx_id, &request->ctx_id))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
if (err)
return err;
@@ -662,7 +662,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd,
&res->contexts))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RES_CTX, (unsigned long)res);
if (err)
return err;
@@ -716,7 +716,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd,
&d->request_sizes))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_DMA, (unsigned long)d);
if (err)
return err;
@@ -749,7 +749,7 @@ static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
if (put_user(m32.mode, &mode->mode))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
}
@@ -779,7 +779,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_INFO, (unsigned long)info);
if (err)
return err;
@@ -825,7 +825,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
|| __put_user(req32.type, &request->type))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
if (err)
return err;
@@ -833,7 +833,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
if (__get_user(req32.handle, &request->handle)
|| __get_user(req32.physical, &request->physical)
|| copy_to_user(argp, &req32, sizeof(req32))) {
- drm_ioctl(file->f_dentry->d_inode, file,
+ drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_FREE, (unsigned long)request);
return -EFAULT;
}
@@ -854,7 +854,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd,
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_FREE, (unsigned long)request);
}
@@ -879,7 +879,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
|| __put_user(req32.offset, &request->offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_BIND, (unsigned long)request);
}
@@ -896,7 +896,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
}
#endif /* __OS_HAS_AGP */
@@ -921,7 +921,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
|| __put_user(x, &request->size))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SG_ALLOC, (unsigned long)request);
if (err)
return err;
@@ -948,7 +948,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
|| __put_user(x << PAGE_SHIFT, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SG_FREE, (unsigned long)request);
}
@@ -988,7 +988,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
|| __put_user(req32.request.signal, &request->request.signal))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
if (err)
return err;
@@ -1060,7 +1060,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 4553a3a1e49..9d00c51fe2c 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev)
spin_lock_init(&dev->vbl_lock);
INIT_LIST_HEAD(&dev->vbl_sigs.head);
+ INIT_LIST_HEAD(&dev->vbl_sigs2.head);
dev->vbl_pending = 0;
}
@@ -175,6 +176,8 @@ int drm_irq_uninstall(drm_device_t * dev)
free_irq(dev->irq, dev);
+ dev->locked_tasklet_func = NULL;
+
return 0;
}
@@ -247,10 +250,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
drm_wait_vblank_t vblwait;
struct timeval now;
int ret = 0;
- unsigned int flags;
-
- if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
- return -EINVAL;
+ unsigned int flags, seq;
if (!dev->irq)
return -EINVAL;
@@ -258,9 +258,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
return -EFAULT;
- switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
+ if (vblwait.request.type &
+ ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
+ DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
+ vblwait.request.type,
+ (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
+ return -EINVAL;
+ }
+
+ flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+
+ if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
+ DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+ return -EINVAL;
+
+ seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
+ : &dev->vbl_received);
+
+ switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
- vblwait.request.sequence += atomic_read(&dev->vbl_received);
+ vblwait.request.sequence += seq;
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
case _DRM_VBLANK_ABSOLUTE:
break;
@@ -268,26 +285,30 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
return -EINVAL;
}
- flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+ if ((flags & _DRM_VBLANK_NEXTONMISS) &&
+ (seq - vblwait.request.sequence) <= (1<<23)) {
+ vblwait.request.sequence = seq + 1;
+ }
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
+ drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
+ ? &dev->vbl_sigs2 : &dev->vbl_sigs;
drm_vbl_sig_t *vbl_sig;
- vblwait.reply.sequence = atomic_read(&dev->vbl_received);
-
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Check if this task has already scheduled the same signal
* for the same vblank sequence number; nothing to be done in
* that case
*/
- list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) {
+ list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
if (vbl_sig->sequence == vblwait.request.sequence
&& vbl_sig->info.si_signo == vblwait.request.signal
&& vbl_sig->task == current) {
spin_unlock_irqrestore(&dev->vbl_lock,
irqflags);
+ vblwait.reply.sequence = seq;
goto done;
}
}
@@ -315,11 +336,16 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head);
+ list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+ vblwait.reply.sequence = seq;
} else {
- if (dev->driver->vblank_wait)
+ if (flags & _DRM_VBLANK_SECONDARY) {
+ if (dev->driver->vblank_wait2)
+ ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
+ } else if (dev->driver->vblank_wait)
ret =
dev->driver->vblank_wait(dev,
&vblwait.request.sequence);
@@ -347,25 +373,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
*/
void drm_vbl_send_signals(drm_device_t * dev)
{
- struct list_head *list, *tmp;
- drm_vbl_sig_t *vbl_sig;
- unsigned int vbl_seq = atomic_read(&dev->vbl_received);
unsigned long flags;
+ int i;
spin_lock_irqsave(&dev->vbl_lock, flags);
- list_for_each_safe(list, tmp, &dev->vbl_sigs.head) {
- vbl_sig = list_entry(list, drm_vbl_sig_t, head);
- if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
- vbl_sig->info.si_code = vbl_seq;
- send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info,
- vbl_sig->task);
+ for (i = 0; i < 2; i++) {
+ struct list_head *list, *tmp;
+ drm_vbl_sig_t *vbl_sig;
+ drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+ unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
+ &dev->vbl_received);
+
+ list_for_each_safe(list, tmp, &vbl_sigs->head) {
+ vbl_sig = list_entry(list, drm_vbl_sig_t, head);
+ if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+ vbl_sig->info.si_code = vbl_seq;
+ send_sig_info(vbl_sig->info.si_signo,
+ &vbl_sig->info, vbl_sig->task);
- list_del(list);
+ list_del(list);
- drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER);
+ drm_free(vbl_sig, sizeof(*vbl_sig),
+ DRM_MEM_DRIVER);
- dev->vbl_pending--;
+ dev->vbl_pending--;
+ }
}
}
@@ -373,3 +406,77 @@ void drm_vbl_send_signals(drm_device_t * dev)
}
EXPORT_SYMBOL(drm_vbl_send_signals);
+
+/**
+ * Tasklet wrapper function.
+ *
+ * \param data DRM device in disguise.
+ *
+ * Attempts to grab the HW lock and calls the driver callback on success. On
+ * failure, leave the lock marked as contended so the callback can be called
+ * from drm_unlock().
+ */
+static void drm_locked_tasklet_func(unsigned long data)
+{
+ drm_device_t *dev = (drm_device_t*)data;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+ if (!dev->locked_tasklet_func ||
+ !drm_lock_take(&dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+ return;
+ }
+
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
+
+ dev->locked_tasklet_func(dev);
+
+ drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT);
+
+ dev->locked_tasklet_func = NULL;
+
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+}
+
+/**
+ * Schedule a tasklet to call back a driver hook with the HW lock held.
+ *
+ * \param dev DRM device.
+ * \param func Driver callback.
+ *
+ * This is intended for triggering actions that require the HW lock from an
+ * interrupt handler. The lock will be grabbed ASAP after the interrupt handler
+ * completes. Note that the callback may be called from interrupt or process
+ * context, it must not make any assumptions about this. Also, the HW lock will
+ * be held with the kernel context or any client context.
+ */
+void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*))
+{
+ unsigned long irqflags;
+ static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
+
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) ||
+ test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state))
+ return;
+
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+ if (dev->locked_tasklet_func) {
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+ return;
+ }
+
+ dev->locked_tasklet_func = func;
+
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
+ drm_tasklet.data = (unsigned long)dev;
+
+ tasklet_hi_schedule(&drm_tasklet);
+}
+EXPORT_SYMBOL(drm_locked_tasklet);
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index f9e45303498..e9993ba461a 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
drm_lock_t lock;
+ unsigned long irqflags;
if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
return -EFAULT;
@@ -165,13 +166,23 @@ int drm_unlock(struct inode *inode, struct file *filp,
return -EINVAL;
}
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+ if (dev->locked_tasklet_func) {
+ dev->locked_tasklet_func(dev);
+
+ dev->locked_tasklet_func = NULL;
+ }
+
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
/* kernel_context_switch isn't used by any of the x86 drm
* modules but is required by the Sparc driver.
*/
if (dev->driver->kernel_context_switch_unlock)
- dev->driver->kernel_context_switch_unlock(dev, &lock);
+ dev->driver->kernel_context_switch_unlock(dev);
else {
drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT);
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 5681cae1d40..92a86708237 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
}
#if __OS_HAS_AGP
-/*
- * Find the drm_map that covers the range [offset, offset+size).
- */
-static drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- struct list_head *list;
- drm_map_list_t *r_list;
- drm_map_t *map;
-
- list_for_each(list, &dev->maplist->head) {
- r_list = (drm_map_list_t *) list;
- map = r_list->map;
- if (!map)
- continue;
- if (map->offset <= offset
- && (offset + size) <= (map->offset + map->size))
- return map;
- }
- return NULL;
-}
-
static void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
}
#else /* __OS_HAS_AGP */
-
-static inline drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- return NULL;
-}
-
static inline void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
#endif /* agp */
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev)
-{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap(offset, size);
-}
-EXPORT_SYMBOL(drm_ioremap);
+#endif /* debug_memory */
-#if 0
-void *drm_ioremap_nocache(unsigned long offset,
- unsigned long size, drm_device_t * dev)
+void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap_nocache(offset, size);
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ map->handle = agp_remap(map->offset, map->size, dev);
+ else
+ map->handle = ioremap(map->offset, map->size);
}
-#endif /* 0 */
+EXPORT_SYMBOL(drm_core_ioremap);
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev)
+void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
{
- /*
- * This is a bit ugly. It would be much cleaner if the DRM API would use separate
- * routines for handling mappings in the AGP space. Hopefully this can be done in
- * a future revision of the interface...
- */
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
- && ((unsigned long)pt >= VMALLOC_START
- && (unsigned long)pt < VMALLOC_END)) {
- unsigned long offset;
- drm_map_t *map;
-
- offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
- map = drm_lookup_map(offset, size, dev);
- if (map && map->type == _DRM_AGP) {
- vunmap(pt);
- return;
- }
- }
-
- iounmap(pt);
+ if (!map->handle || !map->size)
+ return;
+
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ vunmap(map->handle);
+ else
+ iounmap(map->handle);
}
-EXPORT_SYMBOL(drm_ioremapfree);
+EXPORT_SYMBOL(drm_core_ioremapfree);
-#endif /* debug_memory */
diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h
index f1b97aff10c..63e425b5ea8 100644
--- a/drivers/char/drm/drm_memory.h
+++ b/drivers/char/drm/drm_memory.h
@@ -56,26 +56,6 @@
# endif
#endif
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)vaddr);
- pud_t *pud = pud_offset(pgd, (unsigned long)vaddr);
- pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr);
- pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr);
- return pte_pfn(*ptep) << PAGE_SHIFT;
-}
-
#else /* __OS_HAS_AGP */
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- return 0;
-}
-
#endif
-
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev);
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index 74581af806e..6463271deea 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, int area) {
}
}
-void *drm_ioremap (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-
-#if 0
-void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-#endif /* 0 */
-
-void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
- int alloc_count;
- int free_count;
-
- if (!pt)
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Attempt to free NULL pointer\n");
- else
- drm_ioremapfree(pt, size, dev);
-
- spin_lock(&drm_mem_lock);
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
- free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
- alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- spin_unlock(&drm_mem_lock);
- if (free_count > alloc_count) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Excess frees: %d frees, %d allocs\n",
- free_count, alloc_count);
- }
-}
-
#if __OS_HAS_AGP
DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 617526bd5b0..9b46b85027d 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -42,36 +42,131 @@
*/
#include "drmP.h"
+#include <linux/slab.h>
+
+unsigned long drm_mm_tail_space(drm_mm_t *mm)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return 0;
+
+ return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return -ENOMEM;
+
+ if (entry->size <= size)
+ return -ENOMEM;
+
+ entry->size -= size;
+ return 0;
+}
+
+
+static int drm_mm_create_tail_node(drm_mm_t *mm,
+ unsigned long start,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return -ENOMEM;
+
+ child->free = 1;
+ child->size = size;
+ child->start = start;
+ child->mm = mm;
+
+ list_add_tail(&child->ml_entry, &mm->ml_entry);
+ list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+ return 0;
+}
+
+
+int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free) {
+ return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+ }
+ entry->size += size;
+ return 0;
+}
+
+static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return NULL;
+
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ child->free = 0;
+ child->size = size;
+ child->start = parent->start;
+ child->mm = parent->mm;
+
+ list_add_tail(&child->ml_entry, &parent->ml_entry);
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ parent->size -= size;
+ parent->start += size;
+ return child;
+}
+
+
drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size, unsigned alignment)
{
+ drm_mm_node_t *align_splitoff = NULL;
drm_mm_node_t *child;
+ unsigned tmp = 0;
if (alignment)
- size += alignment - 1;
+ tmp = parent->start % alignment;
+
+ if (tmp) {
+ align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
+ if (!align_splitoff)
+ return NULL;
+ }
if (parent->size == size) {
list_del_init(&parent->fl_entry);
parent->free = 0;
return parent;
} else {
- child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
- if (!child)
- return NULL;
-
- INIT_LIST_HEAD(&child->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ child = drm_mm_split_at_start(parent, size);
+ }
- child->free = 0;
- child->size = size;
- child->start = parent->start;
+ if (align_splitoff)
+ drm_mm_put_block(align_splitoff);
- list_add_tail(&child->ml_entry, &parent->ml_entry);
- parent->size -= size;
- parent->start += size;
- }
return child;
}
@@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
* Otherwise add to the free stack.
*/
-void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+void drm_mm_put_block(drm_mm_node_t * cur)
{
- drm_mm_node_t *list_root = &mm->root_node;
+ drm_mm_t *mm = cur->mm;
struct list_head *cur_head = &cur->ml_entry;
- struct list_head *root_head = &list_root->ml_entry;
+ struct list_head *root_head = &mm->ml_entry;
drm_mm_node_t *prev_node = NULL;
drm_mm_node_t *next_node;
@@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
}
if (!merged) {
cur->free = 1;
- list_add(&cur->fl_entry, &list_root->fl_entry);
+ list_add(&cur->fl_entry, &mm->fl_entry);
} else {
list_del(&cur->ml_entry);
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
@@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
unsigned alignment, int best_match)
{
struct list_head *list;
- const struct list_head *free_stack = &mm->root_node.fl_entry;
+ const struct list_head *free_stack = &mm->fl_entry;
drm_mm_node_t *entry;
drm_mm_node_t *best;
unsigned long best_size;
+ unsigned wasted;
best = NULL;
best_size = ~0UL;
- if (alignment)
- size += alignment - 1;
-
list_for_each(list, free_stack) {
entry = list_entry(list, drm_mm_node_t, fl_entry);
- if (entry->size >= size) {
+ wasted = 0;
+
+ if (entry->size < size)
+ continue;
+
+ if (alignment) {
+ register unsigned tmp = entry->start % alignment;
+ if (tmp)
+ wasted += alignment - tmp;
+ }
+
+
+ if (entry->size >= size + wasted) {
if (!best_match)
return entry;
if (size < best_size) {
@@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
return best;
}
-int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+int drm_mm_clean(drm_mm_t * mm)
{
- drm_mm_node_t *child;
-
- INIT_LIST_HEAD(&mm->root_node.ml_entry);
- INIT_LIST_HEAD(&mm->root_node.fl_entry);
- child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
- if (!child)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&child->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ struct list_head *head = &mm->ml_entry;
- child->start = start;
- child->size = size;
- child->free = 1;
+ return (head->next->next == head);
+}
- list_add(&child->fl_entry, &mm->root_node.fl_entry);
- list_add(&child->ml_entry, &mm->root_node.ml_entry);
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+ INIT_LIST_HEAD(&mm->ml_entry);
+ INIT_LIST_HEAD(&mm->fl_entry);
- return 0;
+ return drm_mm_create_tail_node(mm, start, size);
}
EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm)
{
- struct list_head *bnode = mm->root_node.fl_entry.next;
+ struct list_head *bnode = mm->fl_entry.next;
drm_mm_node_t *entry;
entry = list_entry(bnode, drm_mm_node_t, fl_entry);
- if (entry->ml_entry.next != &mm->root_node.ml_entry ||
- entry->fl_entry.next != &mm->root_node.fl_entry) {
+ if (entry->ml_entry.next != &mm->ml_entry ||
+ entry->fl_entry.next != &mm->fl_entry) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 09398d5fbd3..ad54b845978 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -226,12 +226,14 @@
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
{0, 0, 0}
#define i810_PCI_IDS \
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 62d5fe15f04..7fd0da71214 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -500,7 +500,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
for (pt = dev->vmalist; pt; pt = pt->next) {
if (!(vma = pt->vma))
continue;
- DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
pt->pid,
vma->vm_start,
vma->vm_end,
@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
vma->vm_flags & VM_LOCKED ? 'l' : '-',
vma->vm_flags & VM_IO ? 'i' : '-',
- vma->vm_pgoff << PAGE_SHIFT);
+ vma->vm_pgoff);
#if defined(__i386__)
pgprot = pgprot_val(vma->vm_page_prot);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
index 19c81d2e13d..e15db6d6bea 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size,
static void drm_sman_mm_free(void *private, void *ref)
{
- drm_mm_t *mm = (drm_mm_t *) private;
drm_mm_node_t *node = (drm_mm_node_t *) ref;
- drm_mm_put_block(mm, node);
+ drm_mm_put_block(node);
}
static void drm_sman_mm_destroy(void *private)
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 7b1d4e8659b..120d10256fe 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -60,6 +60,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
int retcode;
spin_lock_init(&dev->count_lock);
+ spin_lock_init(&dev->drw_lock);
+ spin_lock_init(&dev->tasklet_lock);
init_timer(&dev->timer);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex);
@@ -209,14 +211,16 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
if (!dev)
return -ENOMEM;
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_g1;
if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
- goto err_g1;
+ goto err_g2;
}
if ((ret = drm_get_head(dev, &dev->primary)))
- goto err_g1;
+ goto err_g2;
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
@@ -224,7 +228,9 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
return 0;
- err_g1:
+err_g2:
+ pci_disable_device(pdev);
+err_g1:
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return ret;
}
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index ba4b8de83cf..cc8e2ebe128 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -45,8 +45,8 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
int err;
class = class_create(owner, name);
- if (!class) {
- err = -ENOMEM;
+ if (IS_ERR(class)) {
+ err = PTR_ERR(class);
goto err_out;
}
@@ -113,8 +113,8 @@ struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head)
MKDEV(DRM_MAJOR, head->minor),
&(head->dev->pdev)->dev,
"card%d", head->minor);
- if (!class_dev) {
- err = -ENOMEM;
+ if (IS_ERR(class_dev)) {
+ err = PTR_ERR(class_dev);
goto err_out;
}
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index ae2691942dd..54a63284895 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -70,7 +70,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
if (!dev->agp || !dev->agp->cant_use_aperture)
goto vm_nopage_error;
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
goto vm_nopage_error;
r_list = drm_hash_entry(hash, drm_map_list_t, hash);
@@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map->size);
DRM_DEBUG("mtrr_del = %d\n", retcode);
}
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
break;
case _DRM_SHM:
vfree(map->handle);
@@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
lock_kernel();
dev = priv->head->dev;
dma = dev->dma;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -473,6 +473,22 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
}
unlock_kernel();
+ if (!capable(CAP_SYS_ADMIN) &&
+ (dma->flags & _DRM_DMA_USE_PCI_RO)) {
+ vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
+#if defined(__i386__) || defined(__x86_64__)
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+#else
+ /* Ye gads this is ugly. With more thought
+ we could move this up higher and use
+ `protection_map' instead. */
+ vma->vm_page_prot =
+ __pgprot(pte_val
+ (pte_wrprotect
+ (__pte(pgprot_val(vma->vm_page_prot)))));
+#endif
+ }
+
vma->vm_ops = &drm_vm_dma_ops;
vma->vm_flags |= VM_RESERVED; /* Don't swap */
@@ -521,8 +537,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
unsigned long offset = 0;
drm_hash_item_t *hash;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
if (!priv->authenticated)
return -EACCES;
@@ -531,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
* the AGP mapped at physical address 0
* --BenH.
*/
- if (!(vma->vm_pgoff << PAGE_SHIFT)
+ if (!vma->vm_pgoff
#if __OS_HAS_AGP
&& (!dev->agp
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -539,7 +555,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
)
return drm_mmap_dma(filp, vma);
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
DRM_ERROR("Could not find map\n");
return -EINVAL;
}
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index fa2de70f740..60cb4e45a75 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
(drm_i810_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t * dev)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
*buf_priv->in_use = I810_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
+
}
return 0;
}
@@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
- if (dev_priv->ring.virtual_start == NULL) {
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index e8cf3ff606f..e6df49f4928 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv {
int currently_mapped;
void *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i810_buf_priv_t;
typedef struct _drm_i810_ring_buffer {
@@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i810_ring_buffer_t;
typedef struct drm_i810_private {
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 4f0e5746ab3..95224455ec0 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
(drm_i830_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
drm_buf_t *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
*buf_priv->in_use = I830_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
}
return 0;
}
@@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap(&dev_priv->ring.map, dev);
- if (dev_priv->ring.virtual_start == NULL) {
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i830_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 85bc5be6f91..e91f94afb4b 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv {
int currently_mapped;
void __user *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i830_buf_priv_t;
typedef struct _drm_i830_ring_buffer {
@@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index fb7913ff528..9354ce3b009 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -162,6 +162,7 @@ static int i915_initialize(drm_device_t * dev,
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;
@@ -782,6 +783,7 @@ drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
+ [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH},
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 6af83e613f2..96a468886a7 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea {
unsigned int depth_tiled;
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
+
+ int pipeA_x;
+ int pipeA_y;
+ int pipeA_w;
+ int pipeA_h;
+ int pipeB_x;
+ int pipeB_y;
+ int pipeB_w;
+ int pipeB_h;
} drm_i915_sarea_t;
/* Flags for perf_boxes
@@ -132,6 +141,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_DESTROY_HEAP 0x0c
#define DRM_I915_SET_VBLANK_PIPE 0x0d
#define DRM_I915_GET_VBLANK_PIPE 0x0e
+#define DRM_I915_VBLANK_SWAP 0x0f
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -148,6 +158,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -243,4 +254,12 @@ typedef struct drm_i915_vblank_pipe {
int pipe;
} drm_i915_vblank_pipe_t;
+/* Schedule buffer swap at given vertical blank:
+ */
+typedef struct drm_i915_vblank_swap {
+ drm_drawable_t drawable;
+ drm_vblank_seq_type_t seqtype;
+ unsigned int sequence;
+} drm_i915_vblank_swap_t;
+
#endif /* _I915_DRM_H_ */
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index 8e2e6095c4b..85bcc276f80 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -44,12 +44,14 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
+ DRIVER_IRQ_VBL2,
.load = i915_driver_load,
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.device_is_agp = i915_driver_device_is_agp,
.vblank_wait = i915_driver_vblank_wait,
+ .vblank_wait2 = i915_driver_vblank_wait2,
.irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index fdc2bf19271..93cdcfe6aa8 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -46,9 +46,11 @@
* 1.3: Add vblank support
* 1.4: Fix cmdbuffer path, add heap destroy
* 1.5: Add vblank pipe configuration
+ * 1.6: - New ioctl for scheduling buffer swaps on vertical blank
+ * - Support vertical blank on secondary display pipe
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 5
+#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
@@ -71,6 +73,13 @@ struct mem_block {
DRMFILE filp; /* 0: free, -1: heap, other: real files */
};
+typedef struct _drm_i915_vbl_swap {
+ struct list_head head;
+ drm_drawable_t drw_id;
+ unsigned int pipe;
+ unsigned int sequence;
+} drm_i915_vbl_swap_t;
+
typedef struct drm_i915_private {
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
@@ -83,6 +92,7 @@ typedef struct drm_i915_private {
dma_addr_t dma_status_page;
unsigned long counter;
+ unsigned int cpp;
int back_offset;
int front_offset;
int current_page;
@@ -98,6 +108,10 @@ typedef struct drm_i915_private {
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
+
+ spinlock_t swaps_lock;
+ drm_i915_vbl_swap_t vbl_swaps;
+ unsigned int swaps_pending;
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
@@ -117,12 +131,14 @@ extern int i915_irq_emit(DRM_IOCTL_ARGS);
extern int i915_irq_wait(DRM_IOCTL_ARGS);
extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
+extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
+extern int i915_vblank_swap(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
@@ -256,6 +272,10 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
+#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
diff --git a/drivers/char/drm/i915_ioc32.c b/drivers/char/drm/i915_ioc32.c
index 296248cdc76..1fe68a251b7 100644
--- a/drivers/char/drm/i915_ioc32.c
+++ b/drivers/char/drm/i915_ioc32.c
@@ -66,7 +66,7 @@ static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
&batchbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_BATCHBUFFER,
(unsigned long)batchbuffer);
}
@@ -102,7 +102,7 @@ static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
&cmdbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_CMDBUFFER, (unsigned long)cmdbuffer);
}
@@ -125,7 +125,7 @@ static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_IRQ_EMIT, (unsigned long)request);
}
typedef struct drm_i915_getparam32 {
@@ -149,7 +149,7 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_GETPARAM, (unsigned long)request);
}
@@ -178,7 +178,7 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd,
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_ALLOC, (unsigned long)request);
}
@@ -215,7 +215,7 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index 0d4a162aa38..78c1ae28f17 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -37,6 +37,178 @@
#define MAX_NOPID ((u32)~0)
+/**
+ * Emit blits for scheduled buffer swaps.
+ *
+ * This function will be called with the HW lock held.
+ */
+static void i915_vblank_tasklet(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+ struct list_head *list, *tmp, hits, *hit;
+ int nhits, nrects, slice[2], upper[2], lower[2], i;
+ unsigned counter[2] = { atomic_read(&dev->vbl_received),
+ atomic_read(&dev->vbl_received2) };
+ drm_drawable_info_t *drw;
+ drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ u32 cpp = dev_priv->cpp;
+ u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB)
+ : XY_SRC_COPY_BLT_CMD;
+ u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
+ (cpp << 23) | (1 << 24);
+ RING_LOCALS;
+
+ DRM_DEBUG("\n");
+
+ INIT_LIST_HEAD(&hits);
+
+ nhits = nrects = 0;
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ /* Find buffer swaps scheduled for this vertical blank */
+ list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
+ drm_i915_vbl_swap_t *vbl_swap =
+ list_entry(list, drm_i915_vbl_swap_t, head);
+
+ if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+ continue;
+
+ list_del(list);
+ dev_priv->swaps_pending--;
+
+ spin_unlock(&dev_priv->swaps_lock);
+ spin_lock(&dev->drw_lock);
+
+ drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
+
+ if (!drw) {
+ spin_unlock(&dev->drw_lock);
+ drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+ spin_lock(&dev_priv->swaps_lock);
+ continue;
+ }
+
+ list_for_each(hit, &hits) {
+ drm_i915_vbl_swap_t *swap_cmp =
+ list_entry(hit, drm_i915_vbl_swap_t, head);
+ drm_drawable_info_t *drw_cmp =
+ drm_get_drawable_info(dev, swap_cmp->drw_id);
+
+ if (drw_cmp &&
+ drw_cmp->rects[0].y1 > drw->rects[0].y1) {
+ list_add_tail(list, hit);
+ break;
+ }
+ }
+
+ spin_unlock(&dev->drw_lock);
+
+ /* List of hits was empty, or we reached the end of it */
+ if (hit == &hits)
+ list_add_tail(list, hits.prev);
+
+ nhits++;
+
+ spin_lock(&dev_priv->swaps_lock);
+ }
+
+ if (nhits == 0) {
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ return;
+ }
+
+ spin_unlock(&dev_priv->swaps_lock);
+
+ i915_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(6);
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(sarea_priv->width | sarea_priv->height << 16);
+ OUT_RING(sarea_priv->width | sarea_priv->height << 16);
+ OUT_RING(0);
+
+ ADVANCE_LP_RING();
+
+ sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+ upper[0] = upper[1] = 0;
+ slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
+ slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
+ lower[0] = sarea_priv->pipeA_y + slice[0];
+ lower[1] = sarea_priv->pipeB_y + slice[0];
+
+ spin_lock(&dev->drw_lock);
+
+ /* Emit blits for buffer swaps, partitioning both outputs into as many
+ * slices as there are buffer swaps scheduled in order to avoid tearing
+ * (based on the assumption that a single buffer swap would always
+ * complete before scanout starts).
+ */
+ for (i = 0; i++ < nhits;
+ upper[0] = lower[0], lower[0] += slice[0],
+ upper[1] = lower[1], lower[1] += slice[1]) {
+ if (i == nhits)
+ lower[0] = lower[1] = sarea_priv->height;
+
+ list_for_each(hit, &hits) {
+ drm_i915_vbl_swap_t *swap_hit =
+ list_entry(hit, drm_i915_vbl_swap_t, head);
+ drm_clip_rect_t *rect;
+ int num_rects, pipe;
+ unsigned short top, bottom;
+
+ drw = drm_get_drawable_info(dev, swap_hit->drw_id);
+
+ if (!drw)
+ continue;
+
+ rect = drw->rects;
+ pipe = swap_hit->pipe;
+ top = upper[pipe];
+ bottom = lower[pipe];
+
+ for (num_rects = drw->num_rects; num_rects--; rect++) {
+ int y1 = max(rect->y1, top);
+ int y2 = min(rect->y2, bottom);
+
+ if (y1 >= y2)
+ continue;
+
+ BEGIN_LP_RING(8);
+
+ OUT_RING(cmd);
+ OUT_RING(pitchropcpp);
+ OUT_RING((y1 << 16) | rect->x1);
+ OUT_RING((y2 << 16) | rect->x2);
+ OUT_RING(sarea_priv->front_offset);
+ OUT_RING((y1 << 16) | rect->x1);
+ OUT_RING(pitchropcpp & 0xffff);
+ OUT_RING(sarea_priv->back_offset);
+
+ ADVANCE_LP_RING();
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ list_for_each_safe(hit, tmp, &hits) {
+ drm_i915_vbl_swap_t *swap_hit =
+ list_entry(hit, drm_i915_vbl_swap_t, head);
+
+ list_del(hit);
+
+ drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
+ }
+}
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
@@ -60,9 +232,26 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
DRM_WAKEUP(&dev_priv->irq_queue);
if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- atomic_inc(&dev->vbl_received);
+ int vblank_pipe = dev_priv->vblank_pipe;
+
+ if ((vblank_pipe &
+ (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
+ == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
+ if (temp & VSYNC_PIPEA_FLAG)
+ atomic_inc(&dev->vbl_received);
+ if (temp & VSYNC_PIPEB_FLAG)
+ atomic_inc(&dev->vbl_received2);
+ } else if (((temp & VSYNC_PIPEA_FLAG) &&
+ (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
+ ((temp & VSYNC_PIPEB_FLAG) &&
+ (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
+ atomic_inc(&dev->vbl_received);
+
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
+
+ if (dev_priv->swaps_pending > 0)
+ drm_locked_tasklet(dev, i915_vblank_tasklet);
}
return IRQ_HANDLED;
@@ -120,7 +309,8 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
return ret;
}
-int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
+ atomic_t *counter)
{
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned int cur_vblank;
@@ -132,7 +322,7 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
}
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
+ (((cur_vblank = atomic_read(counter))
- *sequence) <= (1<<23)));
*sequence = cur_vblank;
@@ -141,6 +331,16 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
}
+int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+{
+ return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
+}
+
+int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
+{
+ return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
+}
+
/* Needs the lock as it touches the ring.
*/
int i915_irq_emit(DRM_IOCTL_ARGS)
@@ -189,7 +389,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
-static int i915_enable_interrupt (drm_device_t *dev)
+static void i915_enable_interrupt (drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 flag;
@@ -199,13 +399,8 @@ static int i915_enable_interrupt (drm_device_t *dev)
flag |= VSYNC_PIPEA_FLAG;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
flag |= VSYNC_PIPEB_FLAG;
- if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
- DRM_ERROR("%s called with invalid pipe 0x%x\n",
- __FUNCTION__, dev_priv->vblank_pipe);
- return DRM_ERR(EINVAL);
- }
+
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
- return 0;
}
/* Set the vblank monitor pipe
@@ -224,8 +419,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
sizeof(pipe));
+ if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+ DRM_ERROR("%s called with invalid pipe 0x%x\n",
+ __FUNCTION__, pipe.pipe);
+ return DRM_ERR(EINVAL);
+ }
+
dev_priv->vblank_pipe = pipe.pipe;
- return i915_enable_interrupt (dev);
+
+ i915_enable_interrupt (dev);
+
+ return 0;
}
int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
@@ -251,6 +455,118 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
return 0;
}
+/**
+ * Schedule buffer swap at given vertical blank.
+ */
+int i915_vblank_swap(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_swap_t swap;
+ drm_i915_vbl_swap_t *vbl_swap;
+ unsigned int pipe, seqtype, curseq;
+ unsigned long irqflags;
+ struct list_head *list;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __func__);
+ return DRM_ERR(EINVAL);
+ }
+
+ if (dev_priv->sarea_priv->rotation) {
+ DRM_DEBUG("Rotation not supported\n");
+ return DRM_ERR(EINVAL);
+ }
+
+ DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
+ sizeof(swap));
+
+ if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
+ return DRM_ERR(EINVAL);
+ }
+
+ pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+
+ seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+
+ if (!(dev_priv->vblank_pipe & (1 << pipe))) {
+ DRM_ERROR("Invalid pipe %d\n", pipe);
+ return DRM_ERR(EINVAL);
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ if (!drm_get_drawable_info(dev, swap.drawable)) {
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
+ return DRM_ERR(EINVAL);
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+
+ if (seqtype == _DRM_VBLANK_RELATIVE)
+ swap.sequence += curseq;
+
+ if ((curseq - swap.sequence) <= (1<<23)) {
+ if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
+ swap.sequence = curseq + 1;
+ } else {
+ DRM_DEBUG("Missed target sequence\n");
+ return DRM_ERR(EINVAL);
+ }
+ }
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_for_each(list, &dev_priv->vbl_swaps.head) {
+ vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+
+ if (vbl_swap->drw_id == swap.drawable &&
+ vbl_swap->pipe == pipe &&
+ vbl_swap->sequence == swap.sequence) {
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ DRM_DEBUG("Already scheduled\n");
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ if (dev_priv->swaps_pending >= 100) {
+ DRM_DEBUG("Too many swaps queued\n");
+ return DRM_ERR(EBUSY);
+ }
+
+ vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+
+ if (!vbl_swap) {
+ DRM_ERROR("Failed to allocate memory to queue swap\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ DRM_DEBUG("\n");
+
+ vbl_swap->drw_id = swap.drawable;
+ vbl_swap->pipe = pipe;
+ vbl_swap->sequence = swap.sequence;
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
+ dev_priv->swaps_pending++;
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
+ sizeof(swap));
+
+ return 0;
+}
+
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
@@ -266,6 +582,12 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
+ dev_priv->swaps_pending = 0;
+
+ if (!dev_priv->vblank_pipe)
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c
index 54a18eb2fc0..30d00478dde 100644
--- a/drivers/char/drm/mga_ioc32.c
+++ b/drivers/char/drm/mga_ioc32.c
@@ -100,7 +100,7 @@ static int compat_mga_init(struct file *file, unsigned int cmd,
if (err)
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_INIT, (unsigned long)init);
}
@@ -125,7 +125,7 @@ static int compat_mga_getparam(struct file *file, unsigned int cmd,
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
}
@@ -166,7 +166,7 @@ static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
|| __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_DMA_BOOTSTRAP,
(unsigned long)dma_bootstrap);
if (err)
@@ -224,7 +224,7 @@ long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
index 5d835b006f5..6e8af313f2b 100644
--- a/drivers/char/drm/r128_drm.h
+++ b/drivers/char/drm/r128_drm.h
@@ -1,7 +1,8 @@
/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*-
* Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com
*/
-/* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+/*
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All rights reserved.
*
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 94abffb2cca..f1efb49de8d 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -1,7 +1,8 @@
/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
* Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
*/
-/* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All rights reserved.
*
diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c
index 9dd6d4116e4..d3cb676eee8 100644
--- a/drivers/char/drm/r128_ioc32.c
+++ b/drivers/char/drm/r128_ioc32.c
@@ -95,7 +95,7 @@ static int compat_r128_init(struct file *file, unsigned int cmd,
&init->agp_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_INIT, (unsigned long)init);
}
@@ -129,7 +129,7 @@ static int compat_r128_depth(struct file *file, unsigned int cmd,
&depth->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
}
@@ -153,7 +153,7 @@ static int compat_r128_stipple(struct file *file, unsigned int cmd,
&stipple->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
}
@@ -178,7 +178,7 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd,
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
}
@@ -214,7 +214,7 @@ long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index a080cdd6081..17b11e7d8f3 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -1,7 +1,8 @@
/* r128_state.c -- State support for r128 -*- linux-c -*-
* Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com
*/
-/* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+/*
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index d14477ba367..032a022ec6a 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -242,26 +242,6 @@ static __inline__ int r300_check_range(unsigned reg, int count)
return 0;
}
-/*
- * we expect offsets passed to the framebuffer to be either within video
- * memory or within AGP space
- */
-static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
- u32 offset)
-{
- /* we realy want to check against end of video aperture
- but this value is not being kept.
- This code is correct for now (does the same thing as the
- code that sets MC_FB_LOCATION) in radeon_cp.c */
- if (offset >= dev_priv->fb_location &&
- offset < (dev_priv->fb_location + dev_priv->fb_size))
- return 0;
- if (offset >= dev_priv->gart_vm_start &&
- offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
- return 0;
- return 1;
-}
-
static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
dev_priv,
drm_radeon_kcmd_buffer_t
@@ -290,7 +270,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
case MARK_SAFE:
break;
case MARK_CHECK_OFFSET:
- if (r300_check_offset(dev_priv, (u32) values[i])) {
+ if (!radeon_check_offset(dev_priv, (u32) values[i])) {
DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz);
@@ -452,7 +432,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
i = 1;
while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */
- if (r300_check_offset(dev_priv, payload[i])) {
+ if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -463,7 +443,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if (k == narrays)
break;
/* have one more to process, they come in pairs */
- if (r300_check_offset(dev_priv, payload[i])) {
+ if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -508,7 +488,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
- ret = r300_check_offset(dev_priv, offset);
+ ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
return DRM_ERR(EINVAL);
@@ -518,7 +498,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10;
- ret = r300_check_offset(dev_priv, offset);
+ ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
return DRM_ERR(EINVAL);
@@ -551,7 +531,7 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return DRM_ERR(EINVAL);
}
- ret = r300_check_offset(dev_priv, cmd[2]);
+ ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return DRM_ERR(EINVAL);
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index f45cd7f147a..8b105f1460a 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -303,6 +303,21 @@ extern int radeon_no_wb;
extern drm_ioctl_desc_t radeon_ioctls[];
extern int radeon_max_ioctl;
+/* Check whether the given hardware address is inside the framebuffer or the
+ * GART area.
+ */
+static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
+ u64 off)
+{
+ u32 fb_start = dev_priv->fb_location;
+ u32 fb_end = fb_start + dev_priv->fb_size - 1;
+ u32 gart_start = dev_priv->gart_vm_start;
+ u32 gart_end = gart_start + dev_priv->gart_size - 1;
+
+ return ((off >= fb_start && off <= fb_end) ||
+ (off >= gart_start && off <= gart_end));
+}
+
/* radeon_cp.c */
extern int radeon_cp_init(DRM_IOCTL_ARGS);
extern int radeon_cp_start(DRM_IOCTL_ARGS);
diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
index 0ccfd3618ff..1f1f9cc055a 100644
--- a/drivers/char/drm/radeon_ioc32.c
+++ b/drivers/char/drm/radeon_ioc32.c
@@ -92,7 +92,7 @@ static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
&init->gart_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
}
@@ -125,7 +125,7 @@ static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
&clr->depth_boxes))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
}
@@ -149,7 +149,7 @@ static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
&request->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
}
@@ -204,7 +204,7 @@ static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
&image->data))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
}
@@ -238,7 +238,7 @@ static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
&request->prim))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
}
@@ -268,7 +268,7 @@ static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
&request->boxes))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
}
@@ -293,7 +293,7 @@ static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
}
@@ -322,7 +322,7 @@ static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
}
@@ -345,7 +345,7 @@ static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
}
@@ -386,7 +386,7 @@ long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index d60519de887..3ff0baa2fbf 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -1,5 +1,5 @@
-/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-
- *
+/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */
+/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c
index 030a6fad0d8..517cad8b6e3 100644
--- a/drivers/char/drm/radeon_mem.c
+++ b/drivers/char/drm/radeon_mem.c
@@ -1,5 +1,5 @@
-/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*-
- *
+/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */
+/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 6e04fdd732a..938eccb78cc 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -43,10 +43,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
u32 *offset)
{
u64 off = *offset;
- u32 fb_start = dev_priv->fb_location;
- u32 fb_end = fb_start + dev_priv->fb_size - 1;
- u32 gart_start = dev_priv->gart_vm_start;
- u32 gart_end = gart_start + dev_priv->gart_size - 1;
+ u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
struct drm_radeon_driver_file_fields *radeon_priv;
/* Hrm ... the story of the offset ... So this function converts
@@ -66,8 +63,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
/* First, the best case, the offset already lands in either the
* framebuffer or the GART mapped space
*/
- if ((off >= fb_start && off <= fb_end) ||
- (off >= gart_start && off <= gart_end))
+ if (radeon_check_offset(dev_priv, off))
return 0;
/* Ok, that didn't happen... now check if we have a zero based
@@ -81,11 +77,10 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
/* Finally, assume we aimed at a GART offset if beyond the fb */
if (off > fb_end)
- off = off - fb_end - 1 + gart_start;
+ off = off - fb_end - 1 + dev_priv->gart_vm_start;
/* Now recheck and fail if out of bounds */
- if ((off >= fb_start && off <= fb_end) ||
- (off >= gart_start && off <= gart_end)) {
+ if (radeon_check_offset(dev_priv, off)) {
DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
*offset = off;
return 0;
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
index a9a84f88df5..b94fab55680 100644
--- a/drivers/char/drm/savage_bci.c
+++ b/drivers/char/drm/savage_bci.c
@@ -963,8 +963,8 @@ static int savage_bci_event_emit(DRM_IOCTL_ARGS)
event.count = savage_bci_emit_event(dev_priv, event.flags);
event.count |= dev_priv->event_wrap << 16;
- DRM_COPY_TO_USER_IOCTL(&((drm_savage_event_emit_t __user *) data)->
- count, event.count, sizeof(event.count));
+ DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data,
+ event, sizeof(event));
return 0;
}
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index a691ae74129..c0539c6299c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * dev,
return DRM_ERR(EFAULT);
}
+ if (dev_priv->chipset == VIA_DX9_0) {
+ DRM_ERROR("AGP DMA is not supported on this chip\n");
+ return DRM_ERR(EINVAL);
+ }
+
dev_priv->ring.map.offset = dev->agp->base + init->offset;
dev_priv->ring.map.size = init->size;
dev_priv->ring.map.type = 0;
@@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+ VIA_READ(VIA_REG_TRANSPACE);
}
}
return paused;
@@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+ VIA_READ(VIA_REG_TRANSPACE);
}
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 806f9ce5f47..2054d577371 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
+ VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
}
/*
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index d21b5b75da0..8b8778d4a42 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,10 +29,10 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20060529"
+#define DRIVER_DATE "20061227"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 10
+#define DRIVER_MINOR 11
#define DRIVER_PATCHLEVEL 0
#include "via_verifier.h"
@@ -79,7 +79,7 @@ typedef struct drm_via_private {
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
uint32_t num_fire_offsets;
- int pro_group_a;
+ int chipset;
drm_via_irq_t via_irqs[VIA_NUM_IRQS];
unsigned num_irqs;
maskarray_t *irq_masks;
@@ -96,8 +96,9 @@ typedef struct drm_via_private {
} drm_via_private_t;
enum via_family {
- VIA_OTHER = 0,
- VIA_PRO_GROUP_A,
+ VIA_OTHER = 0, /* Baseline */
+ VIA_PRO_GROUP_A, /* Another video engine and DMA commands */
+ VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */
};
/* VIA MMIO register access */
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index c33d068cde1..1ac5941ad23 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_device_t * dev)
dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
- dev_priv->irq_masks = (dev_priv->pro_group_a) ?
- via_pro_group_a_irqs : via_unichrome_irqs;
- dev_priv->num_irqs = (dev_priv->pro_group_a) ?
- via_num_pro_group_a : via_num_unichrome;
- dev_priv->irq_map = (dev_priv->pro_group_a) ?
- via_irqmap_pro_group_a : via_irqmap_unichrome;
+ if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0) {
+ dev_priv->irq_masks = via_pro_group_a_irqs;
+ dev_priv->num_irqs = via_num_pro_group_a;
+ dev_priv->irq_map = via_irqmap_pro_group_a;
+ } else {
+ dev_priv->irq_masks = via_unichrome_irqs;
+ dev_priv->num_irqs = via_num_unichrome;
+ dev_priv->irq_map = via_irqmap_unichrome;
+ }
for (i = 0; i < dev_priv->num_irqs; ++i) {
atomic_set(&cur_irq->irq_received, 0);
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 782011e0a58..4e3fc072aa3 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
dev->dev_private = (void *)dev_priv;
- if (chipset == VIA_PRO_GROUP_A)
- dev_priv->pro_group_a = 1;
+ dev_priv->chipset = chipset;
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
if (ret) {
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 70c897c8876..2e7e0807828 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -306,6 +306,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
unsigned long lo = ~0, hi = 0, tmp;
uint32_t *addr, *pitch, *height, tex;
unsigned i;
+ int npot;
if (end > 9)
end = 9;
@@ -316,12 +317,15 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
&(cur_seq->t_addr[tex = cur_seq->texture][start]);
pitch = &(cur_seq->pitch[tex][start]);
height = &(cur_seq->height[tex][start]);
-
+ npot = cur_seq->tex_npot[tex];
for (i = start; i <= end; ++i) {
tmp = *addr++;
if (tmp < lo)
lo = tmp;
- tmp += (*height++ << *pitch++);
+ if (i == 0 && npot)
+ tmp += (*height++ * *pitch++);
+ else
+ tmp += (*height++ << *pitch++);
if (tmp > hi)
hi = tmp;
}
@@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
return 0;
case check_texture_addr3:
cur_seq->unfinished = tex_address;
- tmp = ((cmd >> 24) - 0x2B);
- cur_seq->pitch[cur_seq->texture][tmp] =
- (cmd & 0x00F00000) >> 20;
- if (!tmp && (cmd & 0x000FFFFF)) {
- DRM_ERROR
- ("Unimplemented texture level 0 pitch mode.\n");
- return 2;
+ tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
+ if (tmp == 0 &&
+ (cmd & HC_HTXnEnPit_MASK)) {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPit_MASK);
+ cur_seq->tex_npot[cur_seq->texture] = 1;
+ } else {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
+ cur_seq->tex_npot[cur_seq->texture] = 0;
+ if (cmd & 0x000FFFFF) {
+ DRM_ERROR
+ ("Unimplemented texture level 0 pitch mode.\n");
+ return 2;
+ }
}
return 0;
case check_texture_addr4:
@@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
uint32_t cmd;
const uint32_t *buf_end = buf + (size >> 2);
verifier_state_t state = state_command;
- int pro_group_a = dev_priv->pro_group_a;
+ int cme_video;
+ int supported_3d;
+
+ cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0);
+
+ supported_3d = dev_priv->chipset != VIA_DX9_0;
hc_state->dev = dev;
hc_state->unfinished = no_sequence;
@@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
state = via_check_vheader6(&buf, buf_end);
break;
case state_command:
- if (HALCYON_HEADER2 == (cmd = *buf))
+ if ((HALCYON_HEADER2 == (cmd = *buf)) &&
+ supported_3d)
state = state_header2;
else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
state = state_header1;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
state = state_vheader5;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
state = state_vheader6;
- else {
+ else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
+ DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
+ state = state_error;
+ } else {
DRM_ERROR
("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
cmd);
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index 256590fcc22..b77f59df027 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -43,6 +43,7 @@ typedef struct {
uint32_t tex_level_lo[2];
uint32_t tex_level_hi[2];
uint32_t tex_palette_size[2];
+ uint32_t tex_npot[2];
drm_via_sequence_t unfinished;
int agp_texture;
int multitex;