summaryrefslogtreecommitdiff
path: root/sys/dev/pci/drm/drm_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/drm/drm_linux.c')
-rw-r--r--sys/dev/pci/drm/drm_linux.c282
1 files changed, 274 insertions, 8 deletions
diff --git a/sys/dev/pci/drm/drm_linux.c b/sys/dev/pci/drm/drm_linux.c
index 110e18dbe24..b68d2c98ef4 100644
--- a/sys/dev/pci/drm/drm_linux.c
+++ b/sys/dev/pci/drm/drm_linux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_linux.c,v 1.58 2020/03/15 10:14:49 claudio Exp $ */
+/* $OpenBSD: drm_linux.c,v 1.59 2020/06/08 04:47:58 jsg Exp $ */
/*
* Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
* Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org>
@@ -16,18 +16,38 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <drm/drmP.h>
-#include <dev/pci/ppbreg.h>
+#include <sys/types.h>
+#include <sys/param.h>
#include <sys/event.h>
#include <sys/filedesc.h>
#include <sys/kthread.h>
#include <sys/stat.h>
#include <sys/unistd.h>
+#include <sys/proc.h>
+#include <sys/pool.h>
+#include <sys/fcntl.h>
+
+#include <dev/pci/ppbreg.h>
+
#include <linux/dma-buf.h>
#include <linux/mod_devicetable.h>
#include <linux/acpi.h>
#include <linux/pagevec.h>
#include <linux/dma-fence-array.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/scatterlist.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/notifier.h>
+#include <linux/backlight.h>
+#include <linux/shrinker.h>
+#include <linux/fb.h>
+#include <linux/xarray.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_print.h>
#if defined(__amd64__) || defined(__i386__)
#include "bios.h"
@@ -113,6 +133,13 @@ schedule_timeout(long timeout)
return timeout > 0 ? timeout : 0;
}
+long
+schedule_timeout_uninterruptible(long timeout)
+{
+ tsleep(curproc, PWAIT, "schtou", timeout);
+ return 0;
+}
+
int
wake_up_process(struct proc *p)
{
@@ -816,6 +843,113 @@ ida_simple_remove(struct ida *ida, int id)
}
int
+xarray_cmp(struct xarray_entry *a, struct xarray_entry *b)
+{
+ return (a->id < b->id ? -1 : a->id > b->id);
+}
+
+SPLAY_PROTOTYPE(xarray_tree, xarray_entry, entry, xarray_cmp);
+struct pool xa_pool;
+SPLAY_GENERATE(xarray_tree, xarray_entry, entry, xarray_cmp);
+
+void
+xa_init_flags(struct xarray *xa, gfp_t flags)
+{
+ static int initialized;
+
+ if (!initialized) {
+ pool_init(&xa_pool, sizeof(struct xarray_entry), 0, IPL_TTY, 0,
+ "xapl", NULL);
+ initialized = 1;
+ }
+ SPLAY_INIT(&xa->xa_tree);
+}
+
+void
+xa_destroy(struct xarray *xa)
+{
+ struct xarray_entry *id;
+
+ while ((id = SPLAY_MIN(xarray_tree, &xa->xa_tree))) {
+ SPLAY_REMOVE(xarray_tree, &xa->xa_tree, id);
+ pool_put(&xa_pool, id);
+ }
+}
+
+int
+xa_alloc(struct xarray *xa, u32 *id, void *entry, int limit, gfp_t gfp)
+{
+ struct xarray_entry *xid;
+ int flags = (gfp & GFP_NOWAIT) ? PR_NOWAIT : PR_WAITOK;
+ int start = (xa->xa_flags & XA_FLAGS_ALLOC1) ? 1 : 0;
+ int begin;
+
+ xid = pool_get(&xa_pool, flags);
+ if (xid == NULL)
+ return -ENOMEM;
+
+ if (limit <= 0)
+ limit = INT_MAX;
+
+ xid->id = begin = start;
+
+ while (SPLAY_INSERT(xarray_tree, &xa->xa_tree, xid)) {
+ if (++xid->id == limit)
+ xid->id = start;
+ if (xid->id == begin) {
+ pool_put(&xa_pool, xid);
+ return -EBUSY;
+ }
+ }
+ xid->ptr = entry;
+ *id = xid->id;
+ return 0;
+}
+
+void *
+xa_erase(struct xarray *xa, unsigned long index)
+{
+ struct xarray_entry find, *res;
+ void *ptr = NULL;
+
+ find.id = index;
+ res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
+ if (res) {
+ SPLAY_REMOVE(xarray_tree, &xa->xa_tree, res);
+ ptr = res->ptr;
+ pool_put(&xa_pool, res);
+ }
+ return ptr;
+}
+
+void *
+xa_load(struct xarray *xa, unsigned long index)
+{
+ struct xarray_entry find, *res;
+
+ find.id = index;
+ res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
+ if (res == NULL)
+ return NULL;
+ return res->ptr;
+}
+
+void *
+xa_get_next(struct xarray *xa, unsigned long *index)
+{
+ struct xarray_entry *res;
+
+ SPLAY_FOREACH(res, xarray_tree, &xa->xa_tree) {
+ if (res->id >= *index) {
+ *index = res->id;
+ return res->ptr;
+ }
+ }
+
+ return NULL;
+}
+
+int
sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
{
table->sgl = mallocarray(nents, sizeof(struct scatterlist),
@@ -891,10 +1025,20 @@ fail:
int
i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
+ int ret;
+
+ if (adap->lock_ops)
+ adap->lock_ops->lock_bus(adap, 0);
+
if (adap->algo)
- return adap->algo->master_xfer(adap, msgs, num);
+ ret = adap->algo->master_xfer(adap, msgs, num);
+ else
+ ret = i2c_master_xfer(adap, msgs, num);
- return i2c_master_xfer(adap, msgs, num);
+ if (adap->lock_ops)
+ adap->lock_ops->unlock_bus(adap, 0);
+
+ return ret;
}
int
@@ -1199,18 +1343,40 @@ backlight_schedule_update_status(struct backlight_device *bd)
task_add(systq, &bd->task);
}
+inline int
+backlight_enable(struct backlight_device *bd)
+{
+ if (bd == NULL)
+ return 0;
+
+ bd->props.power = FB_BLANK_UNBLANK;
+
+ return bd->ops->update_status(bd);
+}
+
+inline int
+backlight_disable(struct backlight_device *bd)
+{
+ if (bd == NULL)
+ return 0;
+
+ bd->props.power = FB_BLANK_POWERDOWN;
+
+ return bd->ops->update_status(bd);
+}
+
void
drm_sysfs_hotplug_event(struct drm_device *dev)
{
KNOTE(&dev->note, NOTE_CHANGE);
}
-unsigned int drm_fence_count;
+static atomic64_t drm_fence_context_count = ATOMIC64_INIT(1);
-unsigned int
+uint64_t
dma_fence_context_alloc(unsigned int num)
{
- return __sync_add_and_fetch(&drm_fence_count, num) - num;
+ return atomic64_add_return(num, &drm_fence_context_count) - num;
}
struct default_wait_cb {
@@ -1354,6 +1520,34 @@ cb_cleanup:
return ret;
}
+static struct dma_fence dma_fence_stub;
+static struct mutex dma_fence_stub_mtx = MUTEX_INITIALIZER(IPL_TTY);
+
+static const char *
+dma_fence_stub_get_name(struct dma_fence *fence)
+{
+ return "stub";
+}
+
+static const struct dma_fence_ops dma_fence_stub_ops = {
+ .get_driver_name = dma_fence_stub_get_name,
+ .get_timeline_name = dma_fence_stub_get_name,
+};
+
+struct dma_fence *
+dma_fence_get_stub(void)
+{
+ mtx_enter(&dma_fence_stub_mtx);
+ if (dma_fence_stub.ops == NULL) {
+ dma_fence_init(&dma_fence_stub, &dma_fence_stub_ops,
+ &dma_fence_stub_mtx, 0, 0);
+ dma_fence_signal_locked(&dma_fence_stub);
+ }
+ mtx_leave(&dma_fence_stub_mtx);
+
+ return dma_fence_get(&dma_fence_stub);
+}
+
static const char *
dma_fence_array_get_driver_name(struct dma_fence *fence)
{
@@ -1567,6 +1761,7 @@ dma_buf_export(const struct dma_buf_export_info *info)
dmabuf->size = info->size;
dmabuf->file = fp;
fp->f_data = dmabuf;
+ INIT_LIST_HEAD(&dmabuf->attachments);
return dmabuf;
}
@@ -1729,6 +1924,8 @@ autoremove_wake_function(struct wait_queue_entry *wqe, unsigned int mode,
return 0;
}
+static wait_queue_head_t bit_waitq;
+wait_queue_head_t var_waitq;
struct mutex wait_bit_mtx = MUTEX_INITIALIZER(IPL_TTY);
int
@@ -1780,7 +1977,22 @@ wake_up_bit(void *word, int bit)
mtx_leave(&wait_bit_mtx);
}
+void
+clear_and_wake_up_bit(int bit, void *word)
+{
+ clear_bit(bit, word);
+ wake_up_bit(word, bit);
+}
+
+wait_queue_head_t *
+bit_waitqueue(void *word, int bit)
+{
+ /* XXX hash table of wait queues? */
+ return &bit_waitq;
+}
+
struct workqueue_struct *system_wq;
+struct workqueue_struct *system_highpri_wq;
struct workqueue_struct *system_unbound_wq;
struct workqueue_struct *system_long_wq;
struct taskq *taskletq;
@@ -1792,6 +2004,10 @@ drm_linux_init(void)
system_wq = (struct workqueue_struct *)
taskq_create("drmwq", 4, IPL_HIGH, 0);
}
+ if (system_highpri_wq == NULL) {
+ system_highpri_wq = (struct workqueue_struct *)
+ taskq_create("drmhpwq", 4, IPL_HIGH, 0);
+ }
if (system_unbound_wq == NULL) {
system_unbound_wq = (struct workqueue_struct *)
taskq_create("drmubwq", 4, IPL_HIGH, 0);
@@ -1803,6 +2019,9 @@ drm_linux_init(void)
if (taskletq == NULL)
taskletq = taskq_create("drmtskl", 1, IPL_HIGH, 0);
+
+ init_waitqueue_head(&bit_waitq);
+ init_waitqueue_head(&var_waitq);
}
#define PCIE_ECAP_RESIZE_BAR 0x15
@@ -1888,3 +2107,50 @@ drmbackoff(long npages)
shrinker = TAILQ_NEXT(shrinker, next);
}
}
+
+void *
+bitmap_zalloc(u_int n, gfp_t flags)
+{
+ return kcalloc(BITS_TO_LONGS(n), sizeof(long), flags);
+}
+
+void
+bitmap_free(void *p)
+{
+ kfree(p);
+}
+
+int
+atomic_dec_and_mutex_lock(volatile int *v, struct rwlock *lock)
+{
+ if (atomic_add_unless(v, -1, 1))
+ return 0;
+
+ rw_enter_write(lock);
+ if (atomic_dec_return(v) == 0)
+ return 1;
+ rw_exit_write(lock);
+ return 0;
+}
+
+int
+printk(const char *fmt, ...)
+{
+ int ret, level;
+ va_list ap;
+
+ if (fmt != NULL && *fmt == '\001') {
+ level = fmt[1];
+#ifndef DRMDEBUG
+ if (level >= KERN_INFO[1] && level <= '9')
+ return 0;
+#endif
+ fmt += 2;
+ }
+
+ va_start(ap, fmt);
+ ret = vprintf(fmt, ap);
+ va_end(ap);
+
+ return ret;
+}