summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2008-09-18 15:10:58 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2008-09-18 15:10:58 +0000
commit80e73464cddea0a649b4991ab2b43d25504d8f4f (patch)
treeeed705232eb7437e2753f14de7acfe77c99eaac0 /sys/dev
parent8989d6a2d1f31dfcfb222541771afca08af8b8da (diff)
Rework the drm locking to be at least halfway sane. The freebsd code
held a lock over all driver ioctls in order to be ``mpsafe''. Stop lying to ourselves for a start. This code is not fully mpsafe, and should not pretend to be so. Put the locking around where it should, and rely on biglock for the rest. This will need to be fixed, but avoids some of the horrible that we have right now. Tested by many over a long time and several iterations.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/drm/drmP.h44
-rw-r--r--sys/dev/pci/drm/drm_agpsupport.c60
-rw-r--r--sys/dev/pci/drm/drm_auth.c2
-rw-r--r--sys/dev/pci/drm/drm_bufs.c56
-rw-r--r--sys/dev/pci/drm/drm_context.c10
-rw-r--r--sys/dev/pci/drm/drm_dma.c2
-rw-r--r--sys/dev/pci/drm/drm_drawable.c10
-rw-r--r--sys/dev/pci/drm/drm_drv.c127
-rw-r--r--sys/dev/pci/drm/drm_fops.c51
-rw-r--r--sys/dev/pci/drm/drm_irq.c74
-rw-r--r--sys/dev/pci/drm/drm_lock.c35
-rw-r--r--sys/dev/pci/drm/i915_dma.c2
-rw-r--r--sys/dev/pci/drm/radeon_cp.c3
13 files changed, 200 insertions, 276 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h
index 9dfd0941fdb..5afddd92726 100644
--- a/sys/dev/pci/drm/drmP.h
+++ b/sys/dev/pci/drm/drmP.h
@@ -113,7 +113,6 @@
#define wait_queue_head_t atomic_t
#define DRM_WAKEUP(w) wakeup((void *)w)
-#define DRM_WAKEUP_INT(w) wakeup(w)
#define DRM_INIT_WAITQUEUE(queue) do {(void)(queue);} while (0)
#define DRM_CURPROC curproc
@@ -130,8 +129,8 @@
} while (0)
#define DRM_SPINUNLOCK_IRQRESTORE(u, irqflags) DRM_SPINUNLOCK(u)
#define DRM_SPINLOCK_ASSERT(l) DRM_NOOP
-#define DRM_LOCK() DRM_SPINLOCK(&dev->dev_lock)
-#define DRM_UNLOCK() DRM_SPINUNLOCK(&dev->dev_lock)
+#define DRM_LOCK() rw_enter_write(&dev->dev_lock)
+#define DRM_UNLOCK() rw_exit_write(&dev->dev_lock)
#define DRM_MAXUNITS 8
extern struct drm_device *drm_units[];
@@ -239,20 +238,15 @@ do { \
} while (0)
/* Returns -errno to shared code */
-#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
-ret = 0; \
-while ( ret == 0 ) { \
- DRM_UNLOCK(); \
- DRM_SPINLOCK(&dev->irq_lock); \
- if (condition) { \
- DRM_SPINUNLOCK(&dev->irq_lock); \
- break; \
- } \
- ret = -msleep(&(queue), &dev->irq_lock, \
- PZERO | PCATCH, "drmwtq", (timeout)); \
- DRM_SPINUNLOCK(&dev->irq_lock); \
- DRM_LOCK(); \
-}
+#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
+DRM_SPINLOCK(&dev->irq_lock); \
+while ( ret == 0 ) { \
+ if (condition) \
+ break; \
+ ret = -msleep(&(queue), &dev->irq_lock, \
+ PZERO | PCATCH, "drmwtq", (timeout)); \
+} \
+DRM_SPINUNLOCK(&dev->irq_lock)
#define DRM_ERROR(fmt, arg...) \
printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt, \
@@ -344,8 +338,8 @@ struct drm_lock_data {
struct drm_hw_lock *hw_lock; /* Hardware lock */
/* Unique identifier of holding process (NULL is kernel) */
struct drm_file *file_priv;
- int lock_queue; /* Queue of blocked processes */
unsigned long lock_time; /* Time of last lock */
+ struct mutex spinlock;
};
/* This structure, in the struct drm_device, is always initialized while
@@ -428,7 +422,6 @@ typedef struct drm_local_map {
struct drm_vblank {
u_int32_t last_vblank; /* Last vblank we recieved */
atomic_t vbl_count; /* Number of interrupts */
- int vbl_queue; /* sleep on this when waiting */
atomic_t vbl_refcount; /* Number of users */
int vbl_enabled; /* Enabled? */
int vbl_inmodeset; /* is the DDX currently modesetting */
@@ -538,7 +531,7 @@ struct drm_device {
/* Locks */
DRM_SPINTYPE dma_lock; /* protects dev->dma */
DRM_SPINTYPE irq_lock; /* protects irq condition checks */
- DRM_SPINTYPE dev_lock; /* protects everything else */
+ struct rwlock dev_lock; /* protects everything else */
DRM_SPINTYPE drw_lock;
DRM_SPINTYPE tsk_lock;
@@ -616,8 +609,6 @@ dev_type_mmap(drmmmap);
extern drm_local_map_t *drm_getsarea(struct drm_device *);
/* File operations helpers (drm_fops.c) */
-int drm_open_helper(dev_t, int, int, struct proc *,
- struct drm_device *);
struct drm_file *drm_find_file_by_minor(struct drm_device *, int);
/* Memory management support (drm_memory.c) */
@@ -645,13 +636,13 @@ void drm_write32(drm_local_map_t *, unsigned long, u_int32_t);
/* Locking IOCTL support (drm_lock.c) */
int drm_lock_take(struct drm_lock_data *, unsigned int);
-int drm_lock_transfer(struct drm_lock_data *, unsigned int);
int drm_lock_free(struct drm_lock_data *, unsigned int);
/* Buffer management support (drm_bufs.c) */
unsigned long drm_get_resource_start(struct drm_device *, unsigned int);
unsigned long drm_get_resource_len(struct drm_device *, unsigned int);
void drm_rmmap(struct drm_device *, drm_local_map_t *);
+void drm_rmmap_locked(struct drm_device *, drm_local_map_t *);
int drm_order(unsigned long);
drm_local_map_t
*drm_find_matching_map(struct drm_device *, drm_local_map_t *);
@@ -797,12 +788,13 @@ static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev,
{
drm_local_map_t *map;
- DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+ DRM_LOCK();
TAILQ_FOREACH(map, &dev->maplist, link) {
if (offset == map->ext)
- return map;
+ break;
}
- return NULL;
+ DRM_UNLOCK();
+ return (map);
}
#endif /* __KERNEL__ */
diff --git a/sys/dev/pci/drm/drm_agpsupport.c b/sys/dev/pci/drm/drm_agpsupport.c
index be3f368c4c8..c8ea97384eb 100644
--- a/sys/dev/pci/drm/drm_agpsupport.c
+++ b/sys/dev/pci/drm/drm_agpsupport.c
@@ -186,10 +186,8 @@ drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
type = (u_int32_t)request->type;
- DRM_UNLOCK();
handle = agp_alloc_memory(dev->agp->agpdev, type,
pages << AGP_PAGE_SHIFT);
- DRM_LOCK();
if (handle == NULL) {
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
return (ENOMEM);
@@ -198,12 +196,14 @@ drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
entry->handle = handle;
entry->bound = 0;
entry->pages = pages;
- TAILQ_INSERT_HEAD(&dev->agp->memory, entry, link);
agp_memory_info(dev->agp->agpdev, entry->handle, &info);
request->handle = (unsigned long)entry->handle;
request->physical = info.ami_physical;
+ DRM_LOCK();
+ TAILQ_INSERT_HEAD(&dev->agp->memory, entry, link);
+ DRM_UNLOCK();
#endif
return (0);
@@ -214,14 +214,13 @@ drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_agp_buffer *request = data;
- int retcode;
- DRM_LOCK();
- retcode = drm_agp_alloc(dev, request);
- DRM_UNLOCK();
- return (retcode);
+ return (drm_agp_alloc(dev, request));
}
+/*
+ * find entry on agp list. Must be called with dev_lock locked.
+ */
struct drm_agp_mem *
drm_agp_lookup_entry(struct drm_device *dev, void *handle)
{
@@ -243,16 +242,18 @@ drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
if (dev->agp == NULL || !dev->agp->acquired)
return (EINVAL);
+ DRM_LOCK();
entry = drm_agp_lookup_entry(dev, (void *)request->handle);
- if (entry == NULL || !entry->bound)
+ if (entry == NULL || !entry->bound) {
+ DRM_UNLOCK();
return (EINVAL);
+ }
- DRM_UNLOCK();
retcode = agp_unbind_memory(dev->agp->agpdev, entry->handle);
- DRM_LOCK();
if (retcode == 0)
entry->bound = 0;
+ DRM_UNLOCK();
return (retcode);
}
@@ -262,13 +263,8 @@ drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_agp_binding *request = data;
- int retcode;
- DRM_LOCK();
- retcode = drm_agp_unbind(dev, request);
- DRM_UNLOCK();
-
- return (retcode);
+ return (drm_agp_unbind(dev, request));
}
int
@@ -282,18 +278,20 @@ drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
DRM_DEBUG("agp_bind, page_size=%x\n", PAGE_SIZE);
+ DRM_LOCK();
entry = drm_agp_lookup_entry(dev, (void *)request->handle);
- if (entry == NULL || entry->bound)
+ if (entry == NULL || entry->bound) {
+ DRM_UNLOCK();
return (EINVAL);
+ }
page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
- DRM_UNLOCK();
retcode = agp_bind_memory(dev->agp->agpdev, entry->handle,
page * PAGE_SIZE);
- DRM_LOCK();
if (retcode == 0)
entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+ DRM_UNLOCK();
return (retcode);
}
@@ -303,13 +301,8 @@ drm_agp_bind_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_agp_binding *request = data;
- int retcode;
- DRM_LOCK();
- retcode = drm_agp_bind(dev, request);
- DRM_UNLOCK();
-
- return (retcode);
+ return (drm_agp_bind(dev, request));
}
/*
@@ -320,12 +313,10 @@ drm_agp_remove_entry(struct drm_device *dev, struct drm_agp_mem *entry)
{
TAILQ_REMOVE(&dev->agp->memory, entry, link);
- DRM_UNLOCK();
if (entry->bound)
agp_unbind_memory(dev->agp->agpdev, entry->handle);
agp_free_memory(dev->agp->agpdev, entry->handle);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
- DRM_LOCK();
}
void
@@ -357,11 +348,15 @@ drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
if (dev->agp == NULL || !dev->agp->acquired)
return (EINVAL);
+ DRM_LOCK();
entry = drm_agp_lookup_entry(dev, (void*)request->handle);
- if (entry == NULL)
+ if (entry == NULL) {
+ DRM_UNLOCK();
return (EINVAL);
+ }
drm_agp_remove_entry(dev, entry);
+ DRM_UNLOCK();
return (0);
}
@@ -371,13 +366,8 @@ drm_agp_free_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_agp_buffer *request = data;
- int retcode;
- DRM_LOCK();
- retcode = drm_agp_free(dev, request);
- DRM_UNLOCK();
-
- return (retcode);
+ return (drm_agp_free(dev, request));
}
struct drm_agp_head *
diff --git a/sys/dev/pci/drm/drm_auth.c b/sys/dev/pci/drm/drm_auth.c
index 83f7bf64c1d..3a7e4af340e 100644
--- a/sys/dev/pci/drm/drm_auth.c
+++ b/sys/dev/pci/drm/drm_auth.c
@@ -61,8 +61,8 @@ drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
entry->priv = file_priv;
SPLAY_INSERT(drm_magic_tree, &dev->magiclist, entry);
- DRM_DEBUG("%d\n", auth->magic);
DRM_UNLOCK();
+ DRM_DEBUG("%d\n", auth->magic);
}
DRM_DEBUG("%u\n", auth->magic);
diff --git a/sys/dev/pci/drm/drm_bufs.c b/sys/dev/pci/drm/drm_bufs.c
index ce2987a3901..1ddb0efd5ef 100644
--- a/sys/dev/pci/drm/drm_bufs.c
+++ b/sys/dev/pci/drm/drm_bufs.c
@@ -72,14 +72,10 @@ drm_alloc_resource(struct drm_device *dev, int resource)
return 1;
}
- DRM_UNLOCK();
- if (dev->pcir[resource] != NULL) {
- DRM_LOCK();
+ if (dev->pcir[resource] != NULL)
return 0;
- }
dev->pcir[resource] = vga_pci_bar_info(dev->vga_softc, resource);
- DRM_LOCK();
if (dev->pcir[resource] == NULL) {
DRM_ERROR("Can't get bar info for resource 0x%x\n", resource);
return 1;
@@ -144,6 +140,7 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
* Check if this is just another version of a kernel-allocated map, and
* just hand that back if so.
*/
+ DRM_LOCK();
if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER ||
type == _DRM_SHM) {
TAILQ_FOREACH(map, &dev->maplist, link) {
@@ -179,18 +176,15 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
DRM_ERROR("can't find free offset\n");
DRM_UNLOCK();
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- DRM_LOCK();
- return ret;
+ return (ret);
}
DRM_UNLOCK();
switch (map->type) {
case _DRM_REGISTERS:
map->handle = drm_ioremap(dev, map);
- if (map->handle == NULL) {
- DRM_LOCK();
- return EINVAL;
- }
+ if (map->handle == NULL)
+ return (EINVAL);
if (!(map->flags & _DRM_WRITE_COMBINING))
break;
/* FALLTHROUGH */
@@ -217,6 +211,7 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
* If agp is in control of userspace (some intel drivers for
* example. In which case ignore this loop.
*/
+ DRM_LOCK();
TAILQ_FOREACH(entry, &dev->agp->memory, link) {
DRM_DEBUG("bound = %p, pages = %p, %p\n",
entry->bound, entry->pages,
@@ -229,18 +224,18 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
}
}
if (!TAILQ_EMPTY(&dev->agp->memory) && !valid) {
+ DRM_UNLOCK();
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- DRM_LOCK();
DRM_ERROR("invalid agp map requested\n");
- return EACCES;
+ return (EACCES);
}
+ DRM_UNLOCK();
#endif
break;
case _DRM_SCATTER_GATHER:
if (dev->sg == NULL) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- DRM_LOCK();
- return EINVAL;
+ return (EINVAL);
}
map->offset = map->offset + dev->sg->handle;
break;
@@ -258,8 +253,7 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful);
if (map->dmah == NULL) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- DRM_LOCK();
- return ENOMEM;
+ return (ENOMEM);
}
map->handle = map->dmah->vaddr;
map->offset = map->dmah->busaddr;
@@ -270,8 +264,7 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
DRM_UNLOCK();
drm_pci_free(dev, map->dmah);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- DRM_LOCK();
- return EBUSY;
+ return (EBUSY);
}
dev->lock.hw_lock = map->handle;
DRM_UNLOCK();
@@ -280,15 +273,13 @@ drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
default:
DRM_ERROR("Bad map type %d\n", map->type);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
- DRM_LOCK();
return EINVAL;
}
DRM_LOCK();
TAILQ_INSERT_TAIL(&dev->maplist, map, link);
-
done:
- /* Jumped to, with lock held, when a kernel map is found. */
+ DRM_UNLOCK();
DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset,
map->size);
@@ -308,10 +299,8 @@ drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
if (!(file_priv->flags & (FREAD|FWRITE)))
return EACCES; /* Require read/write */
- DRM_LOCK();
err = drm_addmap(dev, request->offset, request->size, request->type,
request->flags, &map);
- DRM_UNLOCK();
if (err != 0)
return err;
@@ -330,8 +319,15 @@ drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
void
drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
{
- DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+ DRM_LOCK();
+ drm_rmmap_locked(dev, map);
+ DRM_UNLOCK();
+}
+
+void
+drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
+{
TAILQ_REMOVE(&dev->maplist, map, link);
switch (map->type) {
@@ -362,7 +358,6 @@ drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
/* NOCOALESCE set, can't fail */
extent_free(dev->handle_ext, map->ext, map->size, EX_NOWAIT);
-
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
}
@@ -386,10 +381,10 @@ drm_rmmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
/* No match found. */
if (map == NULL) {
DRM_UNLOCK();
- return EINVAL;
+ return (EINVAL);
}
- drm_rmmap(dev, map);
+ drm_rmmap_locked(dev, map);
DRM_UNLOCK();
@@ -448,6 +443,7 @@ drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
*/
#if 0 /* disabled for now */
valid = 0;
+ DRM_LOCK();
TAILQ_FOREACH(agp_entry, &dev->agp->memory, link) {
if ((agp_offset >= agp_entry->bound) &&
(agp_offset + total * count <=
@@ -458,8 +454,10 @@ drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
}
if (!TAILQ_EMPTY(&dev->agp->memory) && !valid) {
DRM_DEBUG("zone invalid\n");
- return EINVAL;
+ DRM_UNLOCK();
+ return (EINVAL);
}
+ DRM_UNLOCK();
#endif
entry = &dma->bufs[order];
diff --git a/sys/dev/pci/drm/drm_context.c b/sys/dev/pci/drm/drm_context.c
index 3647f1f9c4a..70edfbdd6fe 100644
--- a/sys/dev/pci/drm/drm_context.c
+++ b/sys/dev/pci/drm/drm_context.c
@@ -147,11 +147,8 @@ drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
return ENOMEM;
}
- if (dev->driver.context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
- DRM_LOCK();
+ if (dev->driver.context_ctor && ctx->handle != DRM_KERNEL_CONTEXT)
dev->driver.context_ctor(dev, ctx->handle);
- DRM_UNLOCK();
- }
return 0;
}
@@ -174,11 +171,8 @@ drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
DRM_DEBUG("%d\n", ctx->handle);
if (ctx->handle != DRM_KERNEL_CONTEXT) {
- if (dev->driver.context_dtor) {
- DRM_LOCK();
+ if (dev->driver.context_dtor)
dev->driver.context_dtor(dev, ctx->handle);
- DRM_UNLOCK();
- }
drm_ctxbitmap_free(dev, ctx->handle);
}
diff --git a/sys/dev/pci/drm/drm_dma.c b/sys/dev/pci/drm/drm_dma.c
index 2059abcf7a6..c4012cc96c2 100644
--- a/sys/dev/pci/drm/drm_dma.c
+++ b/sys/dev/pci/drm/drm_dma.c
@@ -46,6 +46,8 @@ drm_dma_setup(struct drm_device *dev)
if (dev->dma == NULL)
return ENOMEM;
+ dev->buf_use = 0;
+
DRM_SPININIT(&dev->dma_lock, "drmdma");
return 0;
diff --git a/sys/dev/pci/drm/drm_drawable.c b/sys/dev/pci/drm/drm_drawable.c
index 563de03b064..4188c3190af 100644
--- a/sys/dev/pci/drm/drm_drawable.c
+++ b/sys/dev/pci/drm/drm_drawable.c
@@ -94,10 +94,9 @@ drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
if (info == NULL)
return (ENOMEM);
- info->handle = ++dev->drw_no;
DRM_SPINLOCK(&dev->drw_lock);
+ draw->handle = info->handle = ++dev->drw_no;
RB_INSERT(drawable_tree, &dev->drw_head, info);
- draw->handle = info->handle;
DRM_SPINUNLOCK(&dev->drw_lock);
DRM_DEBUG("%d\n", draw->handle);
@@ -197,13 +196,10 @@ drm_drawable_free(struct drm_device *dev, struct bsd_drm_drawable_info *draw)
void
drm_drawable_free_all(struct drm_device *dev)
{
- struct bsd_drm_drawable_info *draw, *nxt;
+ struct bsd_drm_drawable_info *draw;
DRM_SPINLOCK(&dev->drw_lock);
- for (draw = RB_MIN(drawable_tree, &dev->drw_head); draw != NULL;
- draw = nxt) {
- nxt = RB_NEXT(drawable_tree, &dev->drw_head, draw);
+ while ((draw = RB_ROOT(&dev->drw_head)) != NULL)
drm_drawable_free(dev, draw);
- }
DRM_SPINUNLOCK(&dev->drw_lock);
}
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index 7a39ee79b51..4b5755823fb 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -201,9 +201,10 @@ drm_attach(struct device *parent, struct device *kdev,
dev->pci_vendor = PCI_VENDOR(dev->pa.pa_id);
dev->pci_device = PCI_PRODUCT(dev->pa.pa_id);
- DRM_SPININIT(&dev->dev_lock, "drm device");
+ rw_init(&dev->dev_lock, "drmdevlk");
mtx_init(&dev->drw_lock, IPL_BIO);
mtx_init(&dev->tsk_lock, IPL_BIO);
+ mtx_init(&dev->lock.spinlock, IPL_NONE);
id_entry = drm_find_description(PCI_VENDOR(pa->pa_id),
PCI_PRODUCT(pa->pa_id), idlist);
@@ -230,11 +231,9 @@ drm_attach(struct device *parent, struct device *kdev,
if (dev->driver.load != NULL) {
int retcode;
- DRM_LOCK();
/* Shared code returns -errno. */
retcode = -dev->driver.load(dev,
dev->id_entry->driver_private);
- DRM_UNLOCK();
if (retcode != 0)
goto error;
}
@@ -263,10 +262,7 @@ drm_attach(struct device *parent, struct device *kdev,
return;
error:
- DRM_LOCK();
drm_lastclose(dev);
- DRM_UNLOCK();
- DRM_SPINUNINIT(&dev->dev_lock);
}
int
@@ -286,9 +282,7 @@ drm_detach(struct device *self, int flags)
DRM_DEBUG("mtrr_del = %d", retcode);
}
- DRM_LOCK();
drm_lastclose(dev);
- DRM_UNLOCK();
if (dev->agp != NULL) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
@@ -299,7 +293,6 @@ drm_detach(struct device *self, int flags)
dev->driver.unload(dev);
drm_mem_uninit();
- DRM_SPINUNINIT(&dev->dev_lock);
return 0;
}
@@ -337,8 +330,6 @@ drm_firstopen(struct drm_device *dev)
drm_local_map_t *map;
int i;
- DRM_SPINLOCK_ASSERT(&dev->dev_lock);
-
/* prebuild the SAREA */
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
_DRM_CONTAINS_LOCK, &map);
@@ -348,8 +339,6 @@ drm_firstopen(struct drm_device *dev)
if (dev->driver.firstopen)
dev->driver.firstopen(dev);
- dev->buf_use = 0;
-
if (dev->driver.use_dma) {
i = drm_dma_setup(dev);
if (i != 0)
@@ -359,7 +348,6 @@ drm_firstopen(struct drm_device *dev)
dev->magicid = 1;
SPLAY_INIT(&dev->magiclist);
- dev->lock.lock_queue = 0;
dev->irq_enabled = 0;
dev->if_version = 0;
@@ -376,8 +364,6 @@ drm_lastclose(struct drm_device *dev)
struct drm_magic_entry *pt;
drm_local_map_t *map, *mapsave;
- DRM_SPINLOCK_ASSERT(&dev->dev_lock);
-
DRM_DEBUG("\n");
if (dev->driver.lastclose != NULL)
@@ -386,6 +372,11 @@ drm_lastclose(struct drm_device *dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
+ drm_agp_takedown(dev);
+ drm_drawable_free_all(dev);
+ drm_dma_takedown(dev);
+
+ DRM_LOCK();
if (dev->unique != NULL) {
drm_free(dev->unique, dev->unique_len + 1, DRM_MEM_DRIVER);
dev->unique = NULL;
@@ -398,12 +389,6 @@ drm_lastclose(struct drm_device *dev)
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
}
- DRM_UNLOCK();
- drm_agp_takedown(dev);
- drm_drawable_free_all(dev);
- drm_dma_takedown(dev);
- DRM_LOCK();
-
if (dev->sg != NULL) {
drm_sg_mem_t *sg = dev->sg;
dev->sg = NULL;
@@ -417,14 +402,15 @@ drm_lastclose(struct drm_device *dev)
map = mapsave) {
mapsave = TAILQ_NEXT(map, link);
if (!(map->flags & _DRM_DRIVER))
- drm_rmmap(dev, map);
+ drm_rmmap_locked(dev, map);
}
if (dev->lock.hw_lock != NULL) {
dev->lock.hw_lock = NULL; /* SHM removed */
dev->lock.file_priv = NULL;
- DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
+ wakeup(&dev->lock); /* there should be nothing sleeping on it */
}
+ DRM_UNLOCK();
return 0;
}
@@ -458,8 +444,9 @@ drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
int
drmopen(dev_t kdev, int flags, int fmt, struct proc *p)
{
- struct drm_device *dev = NULL;
- int retcode = 0;
+ struct drm_device *dev = NULL;
+ struct drm_file *priv;
+ int ret = 0;
dev = drm_get_device_from_kdev(kdev);
if (dev == NULL)
@@ -467,16 +454,63 @@ drmopen(dev_t kdev, int flags, int fmt, struct proc *p)
DRM_DEBUG("open_count = %d\n", dev->open_count);
- retcode = drm_open_helper(kdev, flags, fmt, p, dev);
+ if (flags & O_EXCL)
+ return (EBUSY); /* No exclusive opens */
- if (retcode == 0) {
- DRM_LOCK();
- if (dev->open_count++ == 0)
- retcode = drm_firstopen(dev);
+ DRM_LOCK();
+ if (dev->open_count++ == 0) {
+ DRM_UNLOCK();
+ if ((ret = drm_firstopen(dev)) != 0)
+ goto err;
+ } else {
DRM_UNLOCK();
}
- return retcode;
+
+ priv = drm_calloc(1, sizeof(*priv), DRM_MEM_FILES);
+ if (priv == NULL) {
+ ret = ENOMEM;
+ goto err;
+ }
+
+ priv->kdev = kdev;
+ priv->flags = flags;
+ priv->minor = minor(kdev);
+ DRM_DEBUG("minor = %d\n", DRM_CURRENTPID, priv->minor);
+
+ /* for compatibility root is always authenticated */
+ priv->authenticated = DRM_SUSER(p);
+
+ if (dev->driver.open) {
+ /* shared code returns -errno */
+ ret = -dev->driver.open(dev, priv);
+ if (ret != 0) {
+ goto free_priv;
+ }
+ }
+
+ DRM_LOCK();
+ /* first opener automatically becomes master if root */
+ if (TAILQ_EMPTY(&dev->files) && !DRM_SUSER(p)) {
+ DRM_UNLOCK();
+ ret = EPERM;
+ goto free_priv;
+ }
+
+ priv->master = TAILQ_EMPTY(&dev->files);
+
+ TAILQ_INSERT_TAIL(&dev->files, priv, link);
+ DRM_UNLOCK();
+
+ return (0);
+
+free_priv:
+ drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+err:
+ DRM_LOCK();
+ --dev->open_count;
+ DRM_UNLOCK();
+ return (ret);
}
int
@@ -489,7 +523,6 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
DRM_DEBUG("open_count = %d\n", dev->open_count);
DRM_LOCK();
-
file_priv = drm_find_file_by_minor(dev, minor(kdev));
if (!file_priv) {
DRM_UNLOCK();
@@ -497,14 +530,11 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
retcode = EINVAL;
goto done;
}
+ DRM_UNLOCK();
if (dev->driver.preclose != NULL)
dev->driver.preclose(dev, file_priv);
- /* ========================================================
- * Begin inline drm_release
- */
-
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
DRM_CURRENTPID, (long)&dev->device, dev->open_count);
@@ -520,6 +550,7 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
} else if (dev->driver.reclaim_buffers_locked != NULL &&
dev->lock.hw_lock != NULL) {
+ mtx_enter(&dev->lock.spinlock);
/* The lock is required to reclaim buffers */
for (;;) {
if (dev->lock.hw_lock == NULL) {
@@ -533,11 +564,12 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
break; /* Got lock */
}
/* Contention */
- retcode = msleep((void *)&dev->lock.lock_queue,
- &dev->dev_lock, PZERO | PCATCH, "drmlk2", 0);
+ retcode = msleep(&dev->lock,
+ &dev->lock.spinlock, PZERO | PCATCH, "drmlk2", 0);
if (retcode)
break;
}
+ mtx_leave(&dev->lock.spinlock);
if (retcode == 0) {
dev->driver.reclaim_buffers_locked(dev, file_priv);
drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT);
@@ -551,15 +583,14 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
if (dev->driver.postclose != NULL)
dev->driver.postclose(dev, file_priv);
+
+ DRM_LOCK();
TAILQ_REMOVE(&dev->files, file_priv, link);
drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
- /* ========================================================
- * End inline drm_release
- */
-
done:
if (--dev->open_count == 0) {
+ DRM_UNLOCK();
retcode = drm_lastclose(dev);
}
@@ -647,10 +678,8 @@ drmioctl(dev_t kdev, u_long cmd, caddr_t data, int flags,
return EACCES;
if (is_driver_ioctl) {
- DRM_LOCK();
/* shared code returns -errno */
retcode = -func(dev, data, file_priv);
- DRM_UNLOCK();
} else {
retcode = func(dev, data, file_priv);
}
@@ -666,11 +695,11 @@ drm_getsarea(struct drm_device *dev)
{
drm_local_map_t *map;
- DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+ DRM_LOCK();
TAILQ_FOREACH(map, &dev->maplist, link) {
if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
- return map;
+ break;
}
-
- return NULL;
+ DRM_UNLOCK();
+ return (map);
}
diff --git a/sys/dev/pci/drm/drm_fops.c b/sys/dev/pci/drm/drm_fops.c
index 2f0b007def5..ebf4989bf25 100644
--- a/sys/dev/pci/drm/drm_fops.c
+++ b/sys/dev/pci/drm/drm_fops.c
@@ -49,57 +49,6 @@ drm_find_file_by_minor(struct drm_device *dev, int minor)
return (NULL);
}
-/* drm_open_helper is called whenever a process opens /dev/drm. */
-int
-drm_open_helper(dev_t kdev, int flags, int fmt, struct proc *p,
- struct drm_device *dev)
-{
- struct drm_file *priv;
- int m, retcode;
-
- m = minor(kdev);
- if (flags & O_EXCL)
- return (EBUSY); /* No exclusive opens */
-
- DRM_DEBUG("minor = %d\n", DRM_CURRENTPID, m);
-
- priv = drm_calloc(1, sizeof(*priv), DRM_MEM_FILES);
- if (priv == NULL)
- return (ENOMEM);
-
- priv->kdev = kdev;
- priv->flags = flags;
- priv->minor = m;
-
- /* for compatibility root is always authenticated */
- priv->authenticated = DRM_SUSER(p);
-
- DRM_LOCK();
- if (dev->driver.open) {
- /* shared code returns -errno */
- retcode = -dev->driver.open(dev, priv);
- if (retcode != 0) {
- DRM_UNLOCK();
- drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
- return (retcode);
- }
- }
-
- /* first opener automatically becomes master if root */
- if (TAILQ_EMPTY(&dev->files) && !DRM_SUSER(p)) {
- DRM_UNLOCK();
- drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
- return (EPERM);
- }
-
- priv->master = TAILQ_EMPTY(&dev->files);
-
- TAILQ_INSERT_TAIL(&dev->files, priv, link);
- DRM_UNLOCK();
- return (0);
-}
-
-
/* The drm_read and drm_poll are stubs to prevent spurious errors
* on older X Servers (4.3.0 and earlier) */
diff --git a/sys/dev/pci/drm/drm_irq.c b/sys/dev/pci/drm/drm_irq.c
index 866455ddc03..d3ab01c6df9 100644
--- a/sys/dev/pci/drm/drm_irq.c
+++ b/sys/dev/pci/drm/drm_irq.c
@@ -80,22 +80,22 @@ drm_irq_install(struct drm_device *dev)
const char *istr;
if (dev->irq == 0 || dev->dev_private == NULL)
- return EINVAL;
+ return (EINVAL);
DRM_DEBUG("irq=%d\n", dev->irq);
DRM_LOCK();
if (dev->irq_enabled) {
DRM_UNLOCK();
- return EBUSY;
+ return (EBUSY);
}
dev->irq_enabled = 1;
+ DRM_UNLOCK();
mtx_init(&dev->irq_lock, IPL_BIO);
/* Before installing handler */
dev->driver.irq_preinstall(dev);
- DRM_UNLOCK();
/* Install handler */
if (pci_intr_map(&dev->pa, &ih) != 0) {
@@ -112,9 +112,7 @@ drm_irq_install(struct drm_device *dev)
DRM_DEBUG("%s: interrupting at %s\n", dev->device.dv_xname, istr);
/* After installing handler */
- DRM_LOCK();
dev->driver.irq_postinstall(dev);
- DRM_UNLOCK();
return 0;
err:
@@ -129,10 +127,14 @@ int
drm_irq_uninstall(struct drm_device *dev)
{
- if (!dev->irq_enabled)
- return EINVAL;
+ DRM_LOCK();
+ if (!dev->irq_enabled) {
+ DRM_UNLOCK();
+ return (EINVAL);
+ }
dev->irq_enabled = 0;
+ DRM_UNLOCK();
DRM_DEBUG("irq=%d\n", dev->irq);
@@ -150,28 +152,21 @@ int
drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_control *ctl = data;
- int err;
+
+ /* Handle drivers who used to require IRQ setup no longer does. */
+ if (!dev->driver.use_irq)
+ return (0);
switch (ctl->func) {
case DRM_INST_HANDLER:
- /* Handle drivers whose DRM used to require IRQ setup but the
- * no longer does.
- */
- if (!dev->driver.use_irq)
- return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
ctl->irq != dev->irq)
- return EINVAL;
- return drm_irq_install(dev);
+ return (EINVAL);
+ return (drm_irq_install(dev));
case DRM_UNINST_HANDLER:
- if (!dev->driver.use_irq)
- return 0;
- DRM_LOCK();
- err = drm_irq_uninstall(dev);
- DRM_UNLOCK();
- return err;
+ return (drm_irq_uninstall(dev));
default:
- return EINVAL;
+ return (EINVAL);
}
}
@@ -181,11 +176,11 @@ vblank_disable(void *arg)
struct drm_device *dev = (struct drm_device*)arg;
int i;
+ DRM_SPINLOCK(&dev->vbl_lock);
if (!dev->vblank_disable_allowed)
- return;
+ goto out;
for (i=0; i < dev->num_crtcs; i++){
- DRM_SPINLOCK(&dev->vbl_lock);
if (atomic_read(&dev->vblank[i].vbl_refcount) == 0 &&
dev->vblank[i].vbl_enabled) {
dev->vblank[i].last_vblank =
@@ -193,8 +188,9 @@ vblank_disable(void *arg)
dev->driver.disable_vblank(dev, i);
dev->vblank[i].vbl_enabled = 0;
}
- DRM_SPINUNLOCK(&dev->vbl_lock);
}
+out:
+ DRM_SPINUNLOCK(&dev->vbl_lock);
}
void
@@ -375,18 +371,18 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
if (flags & _DRM_VBLANK_SIGNAL) {
ret = EINVAL;
} else {
+ DRM_SPINLOCK(&dev->vbl_lock);
while (ret == 0) {
- DRM_SPINLOCK(&dev->vbl_lock);
if ((drm_vblank_count(dev, crtc)
- vblwait->request.sequence) <= (1 << 23)) {
DRM_SPINUNLOCK(&dev->vbl_lock);
break;
}
- ret = msleep(&dev->vblank[crtc].vbl_queue,
+ ret = msleep(&dev->vblank[crtc],
&dev->vbl_lock, PZERO | PCATCH,
"drmvblq", 3 * DRM_HZ);
- DRM_SPINUNLOCK(&dev->vbl_lock);
}
+ DRM_SPINUNLOCK(&dev->vbl_lock);
if (ret != EINTR) {
struct timeval now;
@@ -406,36 +402,34 @@ void
drm_handle_vblank(struct drm_device *dev, int crtc)
{
atomic_inc(&dev->vblank[crtc].vbl_count);
- DRM_WAKEUP(&dev->vblank[crtc].vbl_queue);
+ wakeup(&dev->vblank[crtc]);
}
void
drm_locked_task(void *context, void *pending)
{
struct drm_device *dev = context;
+ void (*func)(struct drm_device *);
DRM_SPINLOCK(&dev->tsk_lock);
-
- DRM_LOCK(); /* XXX drm_lock_take() should do its own locking */
- if (dev->locked_task_call == NULL ||
+ mtx_enter(&dev->lock.spinlock);
+ func = dev->locked_task_call;
+ if (func == NULL ||
drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT) == 0) {
- DRM_UNLOCK();
+ mtx_leave(&dev->lock.spinlock);
DRM_SPINUNLOCK(&dev->tsk_lock);
return;
}
dev->lock.file_priv = NULL; /* kernel owned */
dev->lock.lock_time = jiffies;
+ mtx_leave(&dev->lock.spinlock);
+ dev->locked_task_call = NULL;
+ DRM_SPINUNLOCK(&dev->tsk_lock);
- DRM_UNLOCK();
-
- dev->locked_task_call(dev);
+ (*func)(dev);
drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT);
-
- dev->locked_task_call = NULL;
-
- DRM_SPINUNLOCK(&dev->tsk_lock);
}
void
diff --git a/sys/dev/pci/drm/drm_lock.c b/sys/dev/pci/drm/drm_lock.c
index e38316dc1ab..9519cb137eb 100644
--- a/sys/dev/pci/drm/drm_lock.c
+++ b/sys/dev/pci/drm/drm_lock.c
@@ -79,41 +79,26 @@ drm_lock_take(struct drm_lock_data *lock_data, unsigned int context)
return 0;
}
-/* This takes a lock forcibly and hands it to context. Should ONLY be used
- inside *_unlock to give lock to kernel before calling *_dma_schedule. */
-int
-drm_lock_transfer(struct drm_lock_data *lock_data, unsigned int context)
-{
- volatile unsigned int *lock = &lock_data->hw_lock->lock;
- unsigned int old, new;
-
- lock_data->file_priv = NULL;
- do {
- old = *lock;
- new = context | _DRM_LOCK_HELD;
- } while (!atomic_cmpset_int(lock, old, new));
-
- return 1;
-}
-
int
drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
{
volatile unsigned int *lock = &lock_data->hw_lock->lock;
unsigned int old, new;
+ mtx_enter(&lock_data->spinlock);
lock_data->file_priv = NULL;
do {
old = *lock;
new = 0;
} while (!atomic_cmpset_int(lock, old, new));
+ mtx_leave(&lock_data->spinlock);
if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
DRM_ERROR("%d freed heavyweight lock held by %d\n",
context, _DRM_LOCKING_CONTEXT(old));
return 1;
}
- DRM_WAKEUP_INT((void *)&lock_data->lock_queue);
+ wakeup(lock_data);
return 0;
}
@@ -136,7 +121,7 @@ drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
if (dev->driver.use_dma_queue && lock->context < 0)
return EINVAL;
- DRM_LOCK();
+ mtx_enter(&dev->lock.spinlock);
for (;;) {
if (drm_lock_take(&dev->lock, lock->context)) {
dev->lock.file_priv = file_priv;
@@ -145,12 +130,12 @@ drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
}
/* Contention */
- ret = msleep((void *)&dev->lock.lock_queue,
- &dev->dev_lock, PZERO | PCATCH, "drmlkq", 0);
+ ret = msleep(&dev->lock, &dev->lock.spinlock,
+ PZERO | PCATCH, "drmlkq", 0);
if (ret != 0)
break;
}
- DRM_UNLOCK();
+ mtx_leave(&dev->lock.spinlock);
DRM_DEBUG("%d %s\n", lock->context, ret ? "interrupted" : "has lock");
if (ret != 0)
@@ -189,13 +174,9 @@ drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
}
DRM_SPINUNLOCK(&dev->tsk_lock);
- DRM_LOCK();
- drm_lock_transfer(&dev->lock, DRM_KERNEL_CONTEXT);
-
- if (drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT)) {
+ if (drm_lock_free(&dev->lock, lock->context)) {
DRM_ERROR("\n");
}
- DRM_UNLOCK();
return 0;
}
diff --git a/sys/dev/pci/drm/i915_dma.c b/sys/dev/pci/drm/i915_dma.c
index b0c8d3b63ac..55ca786db74 100644
--- a/sys/dev/pci/drm/i915_dma.c
+++ b/sys/dev/pci/drm/i915_dma.c
@@ -65,7 +65,7 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
last_head = ring->head;
last_acthd = acthd;
- msleep(dev_priv, &dev->dev_lock, PZERO | PCATCH, "i915wt",
+ tsleep(dev_priv, PZERO | PCATCH, "i915wt",
hz / 100);
}
diff --git a/sys/dev/pci/drm/radeon_cp.c b/sys/dev/pci/drm/radeon_cp.c
index bb6fdb635e5..5c9da607c7c 100644
--- a/sys/dev/pci/drm/radeon_cp.c
+++ b/sys/dev/pci/drm/radeon_cp.c
@@ -1390,8 +1390,7 @@ void radeon_do_release(struct drm_device * dev)
mtx_sleep(&ret, &dev->dev_lock, PZERO, "rdnrel",
1);
#else
- msleep(&ret, &dev->dev_lock, PZERO,
- "rdnrel", 1);
+ tsleep(&ret, PZERO, "rdnrel", 1);
#endif
#endif
}