Skip to content

Commit

Permalink
Merge branch 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/airlied/drm-2.6

* 'drm-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: Add 965GM pci id update
  drm: just use io_remap_pfn_range on all archs..
  drm: fix DRM_CONSISTENT mapping
  drm: fix up mmap locking in preparation for ttm changes
  drm: fix driver deadlock with AIGLX and reclaim_buffers_locked
  drm: fix warning in drm_fops.c
  drm: allow for more generic drm ioctls
  drm: fix alpha domain handling
  via: fix CX700 pci id
  drm: make drm_io_prot static.
  drm: remove via_mm.h
  drm: add missing NULL assignment
  drm/radeon: Fix u32 overflows when determining AGP base address in card space.
  drm: port over use_vmalloc code from git hashtab
  drm: fix crash with fops lock and fixup sarea/page size locking
  drm: bring bufs code from git tree.
  drm: move protection stuff into separate function
  drm: Use ARRAY_SIZE macro when appropriate
  drm: update README.drm (bugzilla #7933)
  drm: remove unused exports
  • Loading branch information
Linus Torvalds committed May 7, 2007
2 parents 9fa0853 + ce7dd06 commit 5f757f9
Show file tree
Hide file tree
Showing 20 changed files with 349 additions and 196 deletions.
16 changes: 7 additions & 9 deletions drivers/char/drm/README.drm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
************************************************************
* For the very latest on DRI development, please see: *
* http://dri.sourceforge.net/ *
* http://dri.freedesktop.org/ *
************************************************************

The Direct Rendering Manager (drm) is a device-independent kernel-level
Expand All @@ -26,21 +26,19 @@ ways:


Documentation on the DRI is available from:
http://precisioninsight.com/piinsights.html
http://dri.freedesktop.org/wiki/Documentation
http://sourceforge.net/project/showfiles.php?group_id=387
http://dri.sourceforge.net/doc/

For specific information about kernel-level support, see:

The Direct Rendering Manager, Kernel Support for the Direct Rendering
Infrastructure
http://precisioninsight.com/dr/drm.html
http://dri.sourceforge.net/doc/drm_low_level.html

Hardware Locking for the Direct Rendering Infrastructure
http://precisioninsight.com/dr/locking.html
http://dri.sourceforge.net/doc/hardware_locking_low_level.html

A Security Analysis of the Direct Rendering Infrastructure
http://precisioninsight.com/dr/security.html
http://dri.sourceforge.net/doc/security_low_level.html

************************************************************
* For the very latest on DRI development, please see: *
* http://dri.sourceforge.net/ *
************************************************************
4 changes: 3 additions & 1 deletion drivers/char/drm/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,11 +654,13 @@ typedef struct drm_set_version {

/**
* Device specific ioctls should only be in their respective headers
* The device specific ioctl range is from 0x40 to 0x79.
* The device specific ioctl range is from 0x40 to 0x99.
* Generic IOCTLS restart at 0xA0.
*
* \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
* drmCommandReadWrite().
*/
#define DRM_COMMAND_BASE 0x40
#define DRM_COMMAND_END 0xA0

#endif
23 changes: 19 additions & 4 deletions drivers/char/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@ typedef struct drm_lock_data {
struct file *filp; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
spinlock_t spinlock;
uint32_t kernel_waiters;
uint32_t user_waiters;
int idle_has_lock;
} drm_lock_data_t;

/**
Expand Down Expand Up @@ -590,6 +594,8 @@ struct drm_driver {
void (*reclaim_buffers) (struct drm_device * dev, struct file * filp);
void (*reclaim_buffers_locked) (struct drm_device *dev,
struct file *filp);
void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
struct file * filp);
unsigned long (*get_map_ofs) (drm_map_t * map);
unsigned long (*get_reg_ofs) (struct drm_device * dev);
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
Expand Down Expand Up @@ -764,7 +770,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
}

#ifdef __alpha__
#define drm_get_pci_domain(dev) dev->hose->bus->number
#define drm_get_pci_domain(dev) dev->hose->index
#else
#define drm_get_pci_domain(dev) 0
#endif
Expand Down Expand Up @@ -915,9 +921,18 @@ extern int drm_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context);
extern int drm_lock_free(drm_device_t * dev,
__volatile__ unsigned int *lock, unsigned int context);
extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context);
extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context);
extern void drm_idlelock_take(drm_lock_data_t *lock_data);
extern void drm_idlelock_release(drm_lock_data_t *lock_data);

/*
* These are exported to drivers so that they can implement fencing using
* DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
*/

extern int drm_i_have_hw_lock(struct file *filp);
extern int drm_kernel_take_hw_lock(struct file *filp);

/* Buffer management support (drm_bufs.h) */
extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
Expand Down
75 changes: 66 additions & 9 deletions drivers/char/drm/drm_bufs.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
list_for_each(list, &dev->maplist->head) {
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
if (entry->map && map->type == entry->map->type &&
entry->map->offset == map->offset) {
((entry->map->offset == map->offset) ||
(map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
return entry;
}
}
Expand Down Expand Up @@ -180,8 +181,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
if (map->type == _DRM_REGISTERS)
map->handle = ioremap(map->offset, map->size);
break;

case _DRM_SHM:
list = drm_find_matching_map(dev, map);
if (list != NULL) {
if(list->map->size != map->size) {
DRM_DEBUG("Matching maps of type %d with "
"mismatched sizes, (%ld vs %ld)\n",
map->type, map->size, list->map->size);
list->map->size = map->size;
}

drm_free(map, sizeof(*map), DRM_MEM_MAPS);
*maplist = list;
return 0;
}
map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
Expand All @@ -200,15 +213,45 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */
}
break;
case _DRM_AGP:
if (drm_core_has_AGP(dev)) {
case _DRM_AGP: {
drm_agp_mem_t *entry;
int valid = 0;

if (!drm_core_has_AGP(dev)) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
#ifdef __alpha__
map->offset += dev->hose->mem_space->start;
map->offset += dev->hose->mem_space->start;
#endif
map->offset += dev->agp->base;
map->mtrr = dev->agp->agp_mtrr; /* for getmap */
/* Note: dev->agp->base may actually be 0 when the DRM
* is not in control of AGP space. But if user space is
* it should already have added the AGP base itself.
*/
map->offset += dev->agp->base;
map->mtrr = dev->agp->agp_mtrr; /* for getmap */

/* This assumes the DRM is in total control of AGP space.
* It's not always the case as AGP can be in the control
* of user space (i.e. i810 driver). So this loop will get
* skipped and we double check that dev->agp->memory is
* actually set as well as being invalid before EPERM'ing
*/
for (entry = dev->agp->memory; entry; entry = entry->next) {
if ((map->offset >= entry->bound) &&
(map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
valid = 1;
break;
}
}
if (dev->agp->memory && !valid) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EPERM;
}
DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);

break;
}
case _DRM_SCATTER_GATHER:
if (!dev->sg) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
Expand Down Expand Up @@ -267,7 +310,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,

*maplist = list;
return 0;
}
}

int drm_addmap(drm_device_t * dev, unsigned int offset,
unsigned int size, drm_map_type_t type,
Expand Down Expand Up @@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
{
drm_device_dma_t *dma = dev->dma;
drm_buf_entry_t *entry;
drm_agp_mem_t *agp_entry;
drm_buf_t *buf;
unsigned long offset;
unsigned long agp_offset;
Expand All @@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
int page_order;
int total;
int byte_count;
int i;
int i, valid;
drm_buf_t **temp_buflist;

if (!dma)
Expand Down Expand Up @@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
if (dev->queue_count)
return -EBUSY; /* Not while in use */

/* Make sure buffers are located in AGP memory that we own */
valid = 0;
for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) {
if ((agp_offset >= agp_entry->bound) &&
(agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
valid = 1;
break;
}
}
if (dev->agp->memory && !valid) {
DRM_DEBUG("zone invalid\n");
return -EINVAL;
}
spin_lock(&dev->count_lock);
if (dev->buf_use) {
spin_unlock(&dev->count_lock);
Expand Down
9 changes: 6 additions & 3 deletions drivers/char/drm/drm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,11 +496,14 @@ int drm_ioctl(struct inode *inode, struct file *filp,
(long)old_encode_dev(priv->head->device),
priv->authenticated);

if (nr < DRIVER_IOCTL_COUNT)
ioctl = &drm_ioctls[nr];
else if ((nr >= DRM_COMMAND_BASE)
if ((nr >= DRIVER_IOCTL_COUNT) &&
((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
goto err_i1;
if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
&& (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
ioctl = &drm_ioctls[nr];
else
goto err_i1;

Expand Down
96 changes: 48 additions & 48 deletions drivers/char/drm/drm_fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static int drm_setup(drm_device_t * dev)
drm_local_map_t *map;
int i;
int ret;
u32 sareapage;

if (dev->driver->firstopen) {
ret = dev->driver->firstopen(dev);
Expand All @@ -56,7 +57,8 @@ static int drm_setup(drm_device_t * dev)
dev->magicfree.next = NULL;

/* prebuild the SAREA */
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
if (i != 0)
return i;

Expand Down Expand Up @@ -84,7 +86,7 @@ static int drm_setup(drm_device_t * dev)
INIT_LIST_HEAD(&dev->ctxlist->head);

dev->vmalist = NULL;
dev->sigdata.lock = dev->lock.hw_lock = NULL;
dev->sigdata.lock = NULL;
init_waitqueue_head(&dev->lock.lock_queue);
dev->queue_count = 0;
dev->queue_reserved = 0;
Expand Down Expand Up @@ -354,58 +356,56 @@ int drm_release(struct inode *inode, struct file *filp)
current->pid, (long)old_encode_dev(priv->head->device),
dev->open_count);

if (priv->lock_count && dev->lock.hw_lock &&
_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
dev->lock.filp == filp) {
DRM_DEBUG("File %p released, freeing lock for context %d\n",
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));

if (dev->driver->reclaim_buffers_locked)
if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
if (drm_i_have_hw_lock(filp)) {
dev->driver->reclaim_buffers_locked(dev, filp);

drm_lock_free(dev, &dev->lock.hw_lock->lock,
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));

/* FIXME: may require heavy-handed reset of
hardware at this point, possibly
processed via a callback to the X
server. */
} else if (dev->driver->reclaim_buffers_locked && priv->lock_count
&& dev->lock.hw_lock) {
/* The lock is required to reclaim buffers */
DECLARE_WAITQUEUE(entry, current);

add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
retcode = -EINTR;
break;
} else {
unsigned long _end=jiffies + 3*DRM_HZ;
int locked = 0;

drm_idlelock_take(&dev->lock);

/*
* Wait for a while.
*/

do{
spin_lock(&dev->lock.spinlock);
locked = dev->lock.idle_has_lock;
spin_unlock(&dev->lock.spinlock);
if (locked)
break;
schedule();
} while (!time_after_eq(jiffies, _end));

if (!locked) {
DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
"\tdriver to use reclaim_buffers_idlelocked() instead.\n"
"\tI will go on reclaiming the buffers anyway.\n");
}
if (drm_lock_take(&dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT)) {
dev->lock.filp = filp;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */
}
/* Contention */
schedule();
if (signal_pending(current)) {
retcode = -ERESTARTSYS;
break;
}
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
if (!retcode) {

dev->driver->reclaim_buffers_locked(dev, filp);
drm_lock_free(dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT);
drm_idlelock_release(&dev->lock);
}
}

if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {

drm_idlelock_take(&dev->lock);
dev->driver->reclaim_buffers_idlelocked(dev, filp);
drm_idlelock_release(&dev->lock);

}

if (drm_i_have_hw_lock(filp)) {
DRM_DEBUG("File %p released, freeing lock for context %d\n",
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));

drm_lock_free(&dev->lock,
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
}


if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
!dev->driver->reclaim_buffers_locked) {
dev->driver->reclaim_buffers(dev, filp);
Expand Down
Loading

0 comments on commit 5f757f9

Please sign in to comment.