Add dry-coded DRM drawable private information storage for FreeBSD.

With this, all modules build again.
main
Eric Anholt 2007-07-18 14:22:40 -07:00
parent 3f04fe7890
commit 33a50412c2
9 changed files with 248 additions and 52 deletions

View File

@ -59,6 +59,8 @@ typedef struct drm_file drm_file_t;
#include <sys/bus.h>
#include <sys/signalvar.h>
#include <sys/poll.h>
#include <sys/tree.h>
#include <sys/taskqueue.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
@ -152,6 +154,7 @@ typedef struct drm_file drm_file_t;
#define DRM_MEM_CTXBITMAP 17
#define DRM_MEM_STUB 18
#define DRM_MEM_SGLISTS 19
#define DRM_MEM_DRAWABLE 20
#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
@ -184,10 +187,15 @@ MALLOC_DECLARE(M_DRM);
#define DRM_CURPROC curthread
#define DRM_STRUCTPROC struct thread
#define DRM_SPINTYPE struct mtx
#define DRM_SPININIT(l,name) mtx_init(&l, name, NULL, MTX_DEF)
#define DRM_SPINUNINIT(l) mtx_destroy(&l)
#define DRM_SPININIT(l,name) mtx_init(l, name, NULL, MTX_DEF)
#define DRM_SPINUNINIT(l) mtx_destroy(l)
#define DRM_SPINLOCK(l) mtx_lock(l)
#define DRM_SPINUNLOCK(u) mtx_unlock(u);
#define DRM_SPINUNLOCK(u) mtx_unlock(u)
#define DRM_SPINLOCK_IRQSAVE(l, irqflags) do { \
mtx_lock(l); \
(void)irqflags; \
} while (0)
#define DRM_SPINUNLOCK_IRQRESTORE(u, irqflags) mtx_unlock(u)
#define DRM_SPINLOCK_ASSERT(l) mtx_assert(l, MA_OWNED)
#define DRM_CURRENTPID curthread->td_proc->p_pid
#define DRM_LOCK() mtx_lock(&dev->dev_lock)
@ -732,6 +740,8 @@ struct drm_device {
struct mtx irq_lock; /* protects irq condition checks */
struct mtx dev_lock; /* protects everything else */
#endif
DRM_SPINTYPE drw_lock;
/* Usage Counters */
int open_count; /* Outstanding files open */
int buf_use; /* Buffers in use -- cannot alloc */
@ -797,6 +807,13 @@ struct drm_device {
void *dev_private;
unsigned int agp_buffer_token;
drm_local_map_t *agp_buffer_map;
struct unrhdr *drw_unrhdr;
/* RB tree of drawable infos */
RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head;
struct task locked_task;
void (*locked_task_call)(drm_device_t *dev);
};
extern int drm_debug_flag;
@ -959,6 +976,8 @@ int drm_getsareactx(DRM_IOCTL_ARGS);
/* Drawable IOCTL support (drm_drawable.c) */
int drm_adddraw(DRM_IOCTL_ARGS);
int drm_rmdraw(DRM_IOCTL_ARGS);
int drm_update_draw(DRM_IOCTL_ARGS);
struct drm_drawable_info *drm_get_drawable_info(drm_device_t *dev, int handle);
/* Authentication IOCTL support (drm_auth.c) */
int drm_getmagic(DRM_IOCTL_ARGS);

View File

@ -40,7 +40,7 @@ int drm_dma_setup(drm_device_t *dev)
if (dev->dma == NULL)
return DRM_ERR(ENOMEM);
DRM_SPININIT(dev->dma_lock, "drmdma");
DRM_SPININIT(&dev->dma_lock, "drmdma");
return 0;
}
@ -80,7 +80,7 @@ void drm_dma_takedown(drm_device_t *dev)
free(dma->pagelist, M_DRM);
free(dev->dma, M_DRM);
dev->dma = NULL;
DRM_SPINUNINIT(dev->dma_lock);
DRM_SPINUNINIT(&dev->dma_lock);
}

View File

@ -33,19 +33,130 @@
#include "drmP.h"
struct bsd_drm_drawable_info {
struct drm_drawable_info info;
int handle;
RB_ENTRY(bsd_drm_drawable_info) tree;
};
static int
drm_drawable_compare(struct bsd_drm_drawable_info *a,
struct bsd_drm_drawable_info *b)
{
if (a->handle > b->handle)
return 1;
if (a->handle > b->handle)
return -1;
return 0;
}
RB_GENERATE_STATIC(drawable_tree, bsd_drm_drawable_info, tree,
drm_drawable_compare);
struct drm_drawable_info *
drm_get_drawable_info(drm_device_t *dev, int handle)
{
struct bsd_drm_drawable_info find, *result;
find.handle = handle;
result = RB_FIND(drawable_tree, &dev->drw_head, &find);
return &result->info;
}
static struct drm_drawable_info *
drm_drawable_info_alloc(drm_device_t *dev, int handle)
{
struct bsd_drm_drawable_info *info;
info = drm_calloc(1, sizeof(struct bsd_drm_drawable_info),
DRM_MEM_DRAWABLE);
if (info == NULL)
return NULL;
info->handle = handle;
RB_INSERT(drawable_tree, &dev->drw_head, info);
return &info->info;
}
static void
drm_drawable_info_free(drm_device_t *dev, struct drm_drawable_info *info)
{
RB_REMOVE(drawable_tree, &dev->drw_head,
(struct bsd_drm_drawable_info *)info);
drm_free(info, sizeof(struct bsd_drm_drawable_info), DRM_MEM_DRAWABLE);
}
int drm_adddraw(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_draw_t draw;
draw.handle = 0; /* NOOP */
draw.handle = alloc_unr(dev->drw_unrhdr);
DRM_DEBUG("%d\n", draw.handle);
DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) );
DRM_COPY_TO_USER_IOCTL((drm_draw_t *)data, draw, sizeof(draw));
return 0;
}
int drm_rmdraw(DRM_IOCTL_ARGS)
{
return 0; /* NOOP */
DRM_DEVICE;
drm_draw_t *draw = (drm_draw_t *)data;
struct drm_drawable_info *info;
free_unr(dev->drw_unrhdr, draw->handle);
info = drm_get_drawable_info(dev, draw->handle);
if (info != NULL) {
drm_drawable_info_free(dev, info);
}
return 0;
}
int drm_update_draw(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
struct drm_drawable_info *info;
struct drm_update_draw *update = (struct drm_update_draw *)data;
info = drm_get_drawable_info(dev, update->handle);
if (info == NULL) {
info = drm_drawable_info_alloc(dev, update->handle);
if (info == NULL)
return ENOMEM;
}
switch (update->type) {
case DRM_DRAWABLE_CLIPRECTS:
DRM_SPINLOCK(&dev->drw_lock);
if (update->num != info->num_rects) {
drm_free(info->rects,
sizeof(*info->rects) * info->num_rects,
DRM_MEM_DRAWABLE);
info->rects = NULL;
info->num_rects = 0;
}
if (update->num == 0) {
DRM_SPINUNLOCK(&dev->drw_lock);
return 0;
}
if (info->rects == NULL) {
info->rects = drm_alloc(sizeof(*info->rects) *
update->num, DRM_MEM_DRAWABLE);
if (info->rects == NULL)
return ENOMEM;
info->num_rects = update->num;
}
/* For some reason the pointer arg is unsigned long long. */
copyin((void *)(intptr_t)update->data, info->rects,
sizeof(*info->rects) * info->num_rects);
DRM_SPINUNLOCK(&dev->drw_lock);
return 0;
default:
return EINVAL;
}
}

View File

@ -31,6 +31,7 @@
*
*/
#include <sys/limits.h>
#include "drmP.h"
#include "drm.h"
#include "drm_sarea.h"
@ -121,6 +122,7 @@ static drm_ioctl_desc_t drm_ioctls[256] = {
[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_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
};
#ifdef __FreeBSD__
@ -557,6 +559,12 @@ static int drm_load(drm_device_t *dev)
goto error;
}
dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL);
if (dev->drw_unrhdr == NULL) {
DRM_ERROR("Couldn't allocate drawable number allocator\n");
goto error;
}
DRM_INFO("Initialized %s %d.%d.%d %s\n",
dev->driver.name,
dev->driver.major,
@ -628,6 +636,8 @@ static void drm_unload(drm_device_t *dev)
if (dev->driver.unload != NULL)
dev->driver.unload(dev);
delete_unrhdr(dev->drw_unrhdr);
drm_mem_uninit();
#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
mtx_destroy(&dev->dev_lock);

View File

@ -31,6 +31,8 @@
#include "drmP.h"
#include "drm.h"
static void drm_locked_task(void *context, int pending __unused);
int drm_irq_by_busid(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
@ -87,7 +89,7 @@ int drm_irq_install(drm_device_t *dev)
dev->context_flag = 0;
DRM_SPININIT(dev->irq_lock, "DRM IRQ lock");
DRM_SPININIT(&dev->irq_lock, "DRM IRQ lock");
/* Before installing handler */
dev->driver.irq_preinstall(dev);
@ -131,6 +133,7 @@ int drm_irq_install(drm_device_t *dev)
dev->driver.irq_postinstall(dev);
DRM_UNLOCK();
TASK_INIT(&dev->locked_task, 0, drm_locked_task, dev);
return 0;
err:
DRM_LOCK();
@ -142,7 +145,7 @@ err:
dev->irqrid = 0;
}
#endif
DRM_SPINUNINIT(dev->irq_lock);
DRM_SPINUNINIT(&dev->irq_lock);
DRM_UNLOCK();
return retcode;
}
@ -174,7 +177,7 @@ int drm_irq_uninstall(drm_device_t *dev)
#elif defined(__NetBSD__) || defined(__OpenBSD__)
pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
#endif
DRM_SPINUNINIT(dev->irq_lock);
DRM_SPINUNINIT(&dev->irq_lock);
return 0;
}
@ -291,3 +294,45 @@ void drm_vbl_send_signals( drm_device_t *dev )
}
}
#endif
static void drm_locked_task(void *context, int pending __unused)
{
drm_device_t *dev = context;
DRM_LOCK();
for (;;) {
int ret;
if (drm_lock_take(&dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT))
{
dev->lock.filp = (void *)(uintptr_t)DRM_CURRENTPID;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */
}
/* Contention */
#if defined(__FreeBSD__) && __FreeBSD_version > 500000
ret = msleep((void *)&dev->lock.lock_queue, &dev->dev_lock,
PZERO | PCATCH, "drmlk2", 0);
#else
ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH,
"drmlk2", 0);
#endif
if (ret != 0)
return;
}
DRM_UNLOCK();
dev->locked_task_call(dev);
drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
}
void
drm_locked_tasklet(drm_device_t *dev, void (*tasklet)(drm_device_t *dev))
{
dev->locked_task_call = tasklet;
taskqueue_enqueue(taskqueue_swi, &dev->locked_task);
}

View File

@ -90,6 +90,7 @@ int drm_sg_alloc(drm_device_t * dev, drm_scatter_gather_t * request)
dev->sg = entry;
DRM_UNLOCK();
return 0;
}
int drm_sg_alloc_ioctl(DRM_IOCTL_ARGS)

View File

@ -1264,5 +1264,19 @@ static inline void drm_ctl_free(void *pt, size_t size, int area)
/*@}*/
/** Type for the OS's non-sleepable mutex lock */
#define DRM_SPINTYPE spinlock_t
/**
* Initialize the lock for use. name is an optional string describing the
* lock
*/
#define DRM_SPININIT(l,name) spin_lock_init(l);
#define DRM_SPINUNINIT(l)
#define DRM_SPINLOCK(l) spin_lock(l);
#define DRM_SPINUNLOCK(u) spin_unlock(l);
#define DRM_SPINLOCK_IRQSAVE(l, flags) spin_lock_irqflags(l, _flags);
#define DRM_SPINUNLOCK_IRQRESTORE(u, flags) spin_unlock_irqrestore(l, _flags);
#define DRM_SPINLOCK_ASSERT(l) do {} while (0)
#endif /* __KERNEL__ */
#endif

View File

@ -118,7 +118,7 @@ typedef struct drm_i915_private {
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
spinlock_t user_irq_lock;
DRM_SPINTYPE user_irq_lock;
int user_irq_refcount;
int fence_irq_on;
uint32_t irq_enable_reg;
@ -133,7 +133,7 @@ typedef struct drm_i915_private {
#ifdef I915_HAVE_BUFFER
void *agp_iomap;
#endif
spinlock_t swaps_lock;
DRM_SPINTYPE swaps_lock;
drm_i915_vbl_swap_t vbl_swaps;
unsigned int swaps_pending;
} drm_i915_private_t;

View File

@ -50,6 +50,8 @@ i915_dispatch_vsync_flip(drm_device_t *dev, drm_drawable_info_t *drw, int pipe)
u16 x1, y1, x2, y2;
int pf_pipes = 1 << pipe;
DRM_SPINLOCK_ASSERT(&dev->drw_lock);
/* If the window is visible on the other pipe, we have to flip on that
* pipe as well.
*/
@ -89,7 +91,6 @@ i915_dispatch_vsync_flip(drm_device_t *dev, drm_drawable_info_t *drw, int pipe)
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, num_pages;
unsigned counter[2] = { atomic_read(&dev->vbl_received),
@ -111,7 +112,12 @@ static void i915_vblank_tasklet(drm_device_t *dev)
nhits = nrects = 0;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
/* No irqsave/restore necessary. This tasklet may be run in an
* interrupt context or normal context, but we don't have to worry
* about getting interrupted by something acquiring the lock, because
* we are the interrupt context thing that acquires the lock.
*/
DRM_SPINLOCK(&dev_priv->swaps_lock);
/* Find buffer swaps scheduled for this vertical blank */
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
@ -124,15 +130,15 @@ static void i915_vblank_tasklet(drm_device_t *dev)
list_del(list);
dev_priv->swaps_pending--;
spin_unlock(&dev_priv->swaps_lock);
spin_lock(&dev->drw_lock);
DRM_SPINUNLOCK(&dev_priv->swaps_lock);
DRM_SPINLOCK(&dev->drw_lock);
drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
if (!drw) {
spin_unlock(&dev->drw_lock);
DRM_SPINUNLOCK(&dev->drw_lock);
drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
spin_lock(&dev_priv->swaps_lock);
DRM_SPINLOCK(&dev_priv->swaps_lock);
continue;
}
@ -149,7 +155,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
}
}
spin_unlock(&dev->drw_lock);
DRM_SPINUNLOCK(&dev->drw_lock);
/* List of hits was empty, or we reached the end of it */
if (hit == &hits)
@ -157,16 +163,15 @@ static void i915_vblank_tasklet(drm_device_t *dev)
nhits++;
spin_lock(&dev_priv->swaps_lock);
DRM_SPINLOCK(&dev_priv->swaps_lock);
}
DRM_SPINUNLOCK(&dev->drw_lock);
if (nhits == 0) {
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
return;
}
spin_unlock(&dev_priv->swaps_lock);
i915_kernel_lost_context(dev);
upper[0] = upper[1] = 0;
@ -180,7 +185,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
offsets[2] = sarea_priv->third_offset;
num_pages = sarea_priv->third_handle ? 3 : 2;
spin_lock(&dev->drw_lock);
DRM_SPINLOCK(&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
@ -262,7 +267,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
}
}
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_SPINUNLOCK(&dev->drw_lock);
list_for_each_safe(hit, tmp, &hits) {
drm_i915_vbl_swap_t *swap_hit =
@ -362,23 +367,23 @@ int i915_emit_irq(drm_device_t * dev)
void i915_user_irq_on(drm_i915_private_t *dev_priv)
{
spin_lock(&dev_priv->user_irq_lock);
DRM_SPINLOCK(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
dev_priv->irq_enable_reg |= USER_INT_FLAG;
I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
}
spin_unlock(&dev_priv->user_irq_lock);
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}
void i915_user_irq_off(drm_i915_private_t *dev_priv)
{
spin_lock(&dev_priv->user_irq_lock);
DRM_SPINLOCK(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
// dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
// I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
}
spin_unlock(&dev_priv->user_irq_lock);
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}
@ -597,16 +602,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
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)
@ -629,12 +624,13 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
LOCK_TEST_WITH_RETURN(dev, filp);
spin_lock_irqsave(&dev->drw_lock, irqflags);
DRM_SPINLOCK_IRQSAVE(&dev->drw_lock, irqflags);
drw = drm_get_drawable_info(dev, swap.drawable);
if (!drw) {
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock,
irqflags);
DRM_DEBUG("Invalid drawable ID %d\n",
swap.drawable);
return DRM_ERR(EINVAL);
@ -642,13 +638,13 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
i915_dispatch_vsync_flip(dev, drw, pipe);
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);
return 0;
}
}
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
DRM_SPINLOCK_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);
@ -657,13 +653,13 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
vbl_swap->pipe == pipe &&
vbl_swap->sequence == swap.sequence) {
vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP);
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags);
DRM_DEBUG("Already scheduled\n");
return 0;
}
}
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags);
if (dev_priv->swaps_pending >= 100) {
DRM_DEBUG("Too many swaps queued\n");
@ -687,12 +683,12 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
if (vbl_swap->flip)
swap.sequence++;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
DRM_SPINLOCK_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_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags);
DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
sizeof(swap));
@ -715,11 +711,11 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
spin_lock_init(&dev_priv->swaps_lock);
DRM_SPININIT(&dev_priv->swaps_lock, "swap");
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
spin_lock_init(&dev_priv->user_irq_lock);
DRM_SPININIT(&dev_priv->user_irq_lock, "userirq");
dev_priv->user_irq_refcount = 0;
i915_enable_interrupt(dev);