xref: /openbsd/sys/dev/pci/drm/drm_linux.c (revision e1edc428)
1*e1edc428Smpi /*	$OpenBSD: drm_linux.c,v 1.112 2024/03/30 13:33:20 mpi Exp $	*/
2652bbc39Skettenis /*
3652bbc39Skettenis  * Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
4d71700c3Skettenis  * Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org>
5652bbc39Skettenis  *
6652bbc39Skettenis  * Permission to use, copy, modify, and distribute this software for any
7652bbc39Skettenis  * purpose with or without fee is hereby granted, provided that the above
8652bbc39Skettenis  * copyright notice and this permission notice appear in all copies.
9652bbc39Skettenis  *
10652bbc39Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11652bbc39Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12652bbc39Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13652bbc39Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14652bbc39Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15652bbc39Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16652bbc39Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17652bbc39Skettenis  */
18652bbc39Skettenis 
19c349dbc7Sjsg #include <sys/types.h>
2085fcfc35Svisa #include <sys/systm.h>
21c349dbc7Sjsg #include <sys/param.h>
22b8584f42Srobert #include <sys/event.h>
23a9ee023bSkettenis #include <sys/filedesc.h>
2463b8f014Skettenis #include <sys/kthread.h>
25a9ee023bSkettenis #include <sys/stat.h>
26f3455eb0Skettenis #include <sys/unistd.h>
27c349dbc7Sjsg #include <sys/proc.h>
28c349dbc7Sjsg #include <sys/pool.h>
29c349dbc7Sjsg #include <sys/fcntl.h>
30c349dbc7Sjsg 
31c349dbc7Sjsg #include <dev/pci/ppbreg.h>
32c349dbc7Sjsg 
337f4dd379Sjsg #include <linux/dma-buf.h>
347f4dd379Sjsg #include <linux/mod_devicetable.h>
357f4dd379Sjsg #include <linux/acpi.h>
367f4dd379Sjsg #include <linux/pagevec.h>
3795f00a37Sjsg #include <linux/dma-fence-array.h>
38ad8b1aafSjsg #include <linux/dma-fence-chain.h>
39c349dbc7Sjsg #include <linux/interrupt.h>
40c349dbc7Sjsg #include <linux/err.h>
41c349dbc7Sjsg #include <linux/idr.h>
42c349dbc7Sjsg #include <linux/scatterlist.h>
43c349dbc7Sjsg #include <linux/i2c.h>
44c349dbc7Sjsg #include <linux/pci.h>
45c349dbc7Sjsg #include <linux/notifier.h>
46c349dbc7Sjsg #include <linux/backlight.h>
47c349dbc7Sjsg #include <linux/shrinker.h>
48c349dbc7Sjsg #include <linux/fb.h>
49c349dbc7Sjsg #include <linux/xarray.h>
50cfaa6efeSjsg #include <linux/interval_tree.h>
51ad8b1aafSjsg #include <linux/kthread.h>
525ca02815Sjsg #include <linux/processor.h>
5361c1bba6Sjsg #include <linux/sync_file.h>
54c349dbc7Sjsg 
55c349dbc7Sjsg #include <drm/drm_device.h>
561bb76ff1Sjsg #include <drm/drm_connector.h>
57c349dbc7Sjsg #include <drm/drm_print.h>
587f4dd379Sjsg 
597ef4208bSjsg #if defined(__amd64__) || defined(__i386__)
607ef4208bSjsg #include "bios.h"
617ef4208bSjsg #endif
627ef4208bSjsg 
635ca02815Sjsg /* allowed to sleep */
645ca02815Sjsg void
tasklet_unlock_wait(struct tasklet_struct * ts)655ca02815Sjsg tasklet_unlock_wait(struct tasklet_struct *ts)
665ca02815Sjsg {
675ca02815Sjsg 	while (test_bit(TASKLET_STATE_RUN, &ts->state))
685ca02815Sjsg 		cpu_relax();
695ca02815Sjsg }
705ca02815Sjsg 
715ca02815Sjsg /* must not sleep */
725ca02815Sjsg void
tasklet_unlock_spin_wait(struct tasklet_struct * ts)735ca02815Sjsg tasklet_unlock_spin_wait(struct tasklet_struct *ts)
745ca02815Sjsg {
755ca02815Sjsg 	while (test_bit(TASKLET_STATE_RUN, &ts->state))
765ca02815Sjsg 		cpu_relax();
775ca02815Sjsg }
785ca02815Sjsg 
797f4dd379Sjsg void
tasklet_run(void * arg)807f4dd379Sjsg tasklet_run(void *arg)
817f4dd379Sjsg {
827f4dd379Sjsg 	struct tasklet_struct *ts = arg;
837f4dd379Sjsg 
847f4dd379Sjsg 	clear_bit(TASKLET_STATE_SCHED, &ts->state);
857f4dd379Sjsg 	if (tasklet_trylock(ts)) {
865ca02815Sjsg 		if (!atomic_read(&ts->count)) {
875ca02815Sjsg 			if (ts->use_callback)
885ca02815Sjsg 				ts->callback(ts);
895ca02815Sjsg 			else
907f4dd379Sjsg 				ts->func(ts->data);
915ca02815Sjsg 		}
927f4dd379Sjsg 		tasklet_unlock(ts);
937f4dd379Sjsg 	}
947f4dd379Sjsg }
95652bbc39Skettenis 
96ec70c0c7Sjsg /* 32 bit powerpc lacks 64 bit atomics */
97ec70c0c7Sjsg #if defined(__powerpc__) && !defined(__powerpc64__)
98ec70c0c7Sjsg struct mutex atomic64_mtx = MUTEX_INITIALIZER(IPL_HIGH);
99ec70c0c7Sjsg #endif
100ec70c0c7Sjsg 
1013253c27bSkettenis void
set_current_state(int state)1027f4dd379Sjsg set_current_state(int state)
1033253c27bSkettenis {
104c0be31d8Sclaudio 	int prio = state;
105c0be31d8Sclaudio 
106c0be31d8Sclaudio 	KASSERT(state != TASK_RUNNING);
107c0be31d8Sclaudio 	/* check if already on the sleep list */
108c0be31d8Sclaudio 	if (curproc->p_wchan != NULL)
109c0be31d8Sclaudio 		return;
110c0be31d8Sclaudio 	sleep_setup(curproc, prio, "schto");
1117f4dd379Sjsg }
1123253c27bSkettenis 
1137f4dd379Sjsg void
__set_current_state(int state)1147f4dd379Sjsg __set_current_state(int state)
1157f4dd379Sjsg {
116c0be31d8Sclaudio 	struct proc *p = curproc;
117c0be31d8Sclaudio 	int s;
118c0be31d8Sclaudio 
1197f4dd379Sjsg 	KASSERT(state == TASK_RUNNING);
120c0be31d8Sclaudio 	SCHED_LOCK(s);
121c0be31d8Sclaudio 	unsleep(p);
122c0be31d8Sclaudio 	p->p_stat = SONPROC;
123c0be31d8Sclaudio 	atomic_clearbits_int(&p->p_flag, P_WSLEEP);
124c0be31d8Sclaudio 	SCHED_UNLOCK(s);
1257f4dd379Sjsg }
1267f4dd379Sjsg 
1277f4dd379Sjsg void
schedule(void)1287f4dd379Sjsg schedule(void)
1297f4dd379Sjsg {
1307f4dd379Sjsg 	schedule_timeout(MAX_SCHEDULE_TIMEOUT);
1317f4dd379Sjsg }
1327f4dd379Sjsg 
1337f4dd379Sjsg long
schedule_timeout(long timeout)1347f4dd379Sjsg schedule_timeout(long timeout)
1357f4dd379Sjsg {
136c2a61337Sjsg 	unsigned long deadline;
137c0be31d8Sclaudio 	int timo = 0;
1387f4dd379Sjsg 
1397f4dd379Sjsg 	KASSERT(!cold);
1407f4dd379Sjsg 
1417f4dd379Sjsg 	if (timeout != MAX_SCHEDULE_TIMEOUT)
142436960cfSmpi 		timo = timeout;
1437f4dd379Sjsg 	if (timeout != MAX_SCHEDULE_TIMEOUT)
144c2a61337Sjsg 		deadline = jiffies + timeout;
145c0be31d8Sclaudio 	sleep_finish(timo, timeout > 0);
1467f4dd379Sjsg 	if (timeout != MAX_SCHEDULE_TIMEOUT)
147c2a61337Sjsg 		timeout = deadline - jiffies;
1487f4dd379Sjsg 
1497f4dd379Sjsg 	return timeout > 0 ? timeout : 0;
1507f4dd379Sjsg }
1517f4dd379Sjsg 
152c349dbc7Sjsg long
schedule_timeout_uninterruptible(long timeout)153c349dbc7Sjsg schedule_timeout_uninterruptible(long timeout)
154c349dbc7Sjsg {
155c349dbc7Sjsg 	tsleep(curproc, PWAIT, "schtou", timeout);
156c349dbc7Sjsg 	return 0;
157c349dbc7Sjsg }
158c349dbc7Sjsg 
1597f4dd379Sjsg int
wake_up_process(struct proc * p)1607f4dd379Sjsg wake_up_process(struct proc *p)
1617f4dd379Sjsg {
162e1b95daaSclaudio 	int s, rv;
163e1b95daaSclaudio 
164e1b95daaSclaudio 	SCHED_LOCK(s);
165*e1edc428Smpi 	rv = wakeup_proc(p, 0);
166e1b95daaSclaudio 	SCHED_UNLOCK(s);
167e1b95daaSclaudio 	return rv;
1683253c27bSkettenis }
1693253c27bSkettenis 
170c0be31d8Sclaudio int
autoremove_wake_function(struct wait_queue_entry * wqe,unsigned int mode,int sync,void * key)171c0be31d8Sclaudio autoremove_wake_function(struct wait_queue_entry *wqe, unsigned int mode,
172c0be31d8Sclaudio     int sync, void *key)
173c0be31d8Sclaudio {
174c0be31d8Sclaudio 	if (wqe->private)
175c0be31d8Sclaudio 		wake_up_process(wqe->private);
176c0be31d8Sclaudio 	list_del_init(&wqe->entry);
177c0be31d8Sclaudio 	return 0;
178c0be31d8Sclaudio }
179c0be31d8Sclaudio 
180c0be31d8Sclaudio void
prepare_to_wait(wait_queue_head_t * wqh,wait_queue_entry_t * wqe,int state)181c0be31d8Sclaudio prepare_to_wait(wait_queue_head_t *wqh, wait_queue_entry_t *wqe, int state)
182c0be31d8Sclaudio {
183c0be31d8Sclaudio 	mtx_enter(&wqh->lock);
184c0be31d8Sclaudio 	if (list_empty(&wqe->entry))
185c0be31d8Sclaudio 		__add_wait_queue(wqh, wqe);
186c0be31d8Sclaudio 	mtx_leave(&wqh->lock);
187c0be31d8Sclaudio 
188c0be31d8Sclaudio 	set_current_state(state);
189c0be31d8Sclaudio }
190c0be31d8Sclaudio 
191c0be31d8Sclaudio void
finish_wait(wait_queue_head_t * wqh,wait_queue_entry_t * wqe)192c0be31d8Sclaudio finish_wait(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
193c0be31d8Sclaudio {
194c0be31d8Sclaudio 	__set_current_state(TASK_RUNNING);
195c0be31d8Sclaudio 
196c0be31d8Sclaudio 	mtx_enter(&wqh->lock);
197c0be31d8Sclaudio 	if (!list_empty(&wqe->entry))
198c0be31d8Sclaudio 		list_del_init(&wqe->entry);
199c0be31d8Sclaudio 	mtx_leave(&wqh->lock);
200c0be31d8Sclaudio }
201c0be31d8Sclaudio 
2023253c27bSkettenis void
flush_workqueue(struct workqueue_struct * wq)2033253c27bSkettenis flush_workqueue(struct workqueue_struct *wq)
2043253c27bSkettenis {
2053253c27bSkettenis 	if (cold)
2063253c27bSkettenis 		return;
2073253c27bSkettenis 
20815e28df9Sjsg 	if (wq)
2097f4dd379Sjsg 		taskq_barrier((struct taskq *)wq);
2103253c27bSkettenis }
2113253c27bSkettenis 
2127f4dd379Sjsg bool
flush_work(struct work_struct * work)2133253c27bSkettenis flush_work(struct work_struct *work)
2143253c27bSkettenis {
2153253c27bSkettenis 	if (cold)
2167f4dd379Sjsg 		return false;
2173253c27bSkettenis 
21815e28df9Sjsg 	if (work->tq)
219b11a6e7fSsthen 		taskq_barrier(work->tq);
2207f4dd379Sjsg 	return false;
2213253c27bSkettenis }
2223253c27bSkettenis 
2237f4dd379Sjsg bool
flush_delayed_work(struct delayed_work * dwork)2243253c27bSkettenis flush_delayed_work(struct delayed_work *dwork)
2253253c27bSkettenis {
2267f4dd379Sjsg 	bool ret = false;
2273253c27bSkettenis 
2283253c27bSkettenis 	if (cold)
2297f4dd379Sjsg 		return false;
2303253c27bSkettenis 
2317f4dd379Sjsg 	while (timeout_pending(&dwork->to)) {
2327f4dd379Sjsg 		tsleep(dwork, PWAIT, "fldwto", 1);
2337f4dd379Sjsg 		ret = true;
2343253c27bSkettenis 	}
2357f4dd379Sjsg 
23615e28df9Sjsg 	if (dwork->tq)
237b11a6e7fSsthen 		taskq_barrier(dwork->tq);
2387f4dd379Sjsg 	return ret;
2393253c27bSkettenis }
2403253c27bSkettenis 
24163b8f014Skettenis struct kthread {
24263b8f014Skettenis 	int (*func)(void *);
24363b8f014Skettenis 	void *data;
24463b8f014Skettenis 	struct proc *proc;
24563b8f014Skettenis 	volatile u_int flags;
24663b8f014Skettenis #define KTHREAD_SHOULDSTOP	0x0000001
24763b8f014Skettenis #define KTHREAD_STOPPED		0x0000002
24863b8f014Skettenis #define KTHREAD_SHOULDPARK	0x0000004
24963b8f014Skettenis #define KTHREAD_PARKED		0x0000008
25063b8f014Skettenis 	LIST_ENTRY(kthread) next;
25163b8f014Skettenis };
25263b8f014Skettenis 
25363b8f014Skettenis LIST_HEAD(, kthread) kthread_list = LIST_HEAD_INITIALIZER(kthread_list);
25463b8f014Skettenis 
25563b8f014Skettenis void
kthread_func(void * arg)25663b8f014Skettenis kthread_func(void *arg)
25763b8f014Skettenis {
25863b8f014Skettenis 	struct kthread *thread = arg;
25963b8f014Skettenis 	int ret;
26063b8f014Skettenis 
26163b8f014Skettenis 	ret = thread->func(thread->data);
26263b8f014Skettenis 	thread->flags |= KTHREAD_STOPPED;
2638224282cSsemarie 	wakeup(thread);
26463b8f014Skettenis 	kthread_exit(ret);
26563b8f014Skettenis }
26663b8f014Skettenis 
26763b8f014Skettenis struct proc *
kthread_run(int (* func)(void *),void * data,const char * name)26863b8f014Skettenis kthread_run(int (*func)(void *), void *data, const char *name)
26963b8f014Skettenis {
27063b8f014Skettenis 	struct kthread *thread;
27163b8f014Skettenis 
27263b8f014Skettenis 	thread = malloc(sizeof(*thread), M_DRM, M_WAITOK);
27363b8f014Skettenis 	thread->func = func;
27463b8f014Skettenis 	thread->data = data;
27563b8f014Skettenis 	thread->flags = 0;
27663b8f014Skettenis 
27763b8f014Skettenis 	if (kthread_create(kthread_func, thread, &thread->proc, name)) {
27863b8f014Skettenis 		free(thread, M_DRM, sizeof(*thread));
27963b8f014Skettenis 		return ERR_PTR(-ENOMEM);
28063b8f014Skettenis 	}
28163b8f014Skettenis 
28263b8f014Skettenis 	LIST_INSERT_HEAD(&kthread_list, thread, next);
28363b8f014Skettenis 	return thread->proc;
28463b8f014Skettenis }
28563b8f014Skettenis 
286ad8b1aafSjsg struct kthread_worker *
kthread_create_worker(unsigned int flags,const char * fmt,...)287ad8b1aafSjsg kthread_create_worker(unsigned int flags, const char *fmt, ...)
288ad8b1aafSjsg {
289ad8b1aafSjsg 	char name[MAXCOMLEN+1];
290ad8b1aafSjsg 	va_list ap;
291ad8b1aafSjsg 
292ad8b1aafSjsg 	struct kthread_worker *w = malloc(sizeof(*w), M_DRM, M_WAITOK);
293ad8b1aafSjsg 	va_start(ap, fmt);
294ad8b1aafSjsg 	vsnprintf(name, sizeof(name), fmt, ap);
295ad8b1aafSjsg 	va_end(ap);
296ad8b1aafSjsg 	w->tq = taskq_create(name, 1, IPL_HIGH, 0);
297ad8b1aafSjsg 
298ad8b1aafSjsg 	return w;
299ad8b1aafSjsg }
300ad8b1aafSjsg 
301ad8b1aafSjsg void
kthread_destroy_worker(struct kthread_worker * worker)302ad8b1aafSjsg kthread_destroy_worker(struct kthread_worker *worker)
303ad8b1aafSjsg {
304ad8b1aafSjsg 	taskq_destroy(worker->tq);
305ad8b1aafSjsg 	free(worker, M_DRM, sizeof(*worker));
306ad8b1aafSjsg 
307ad8b1aafSjsg }
308ad8b1aafSjsg 
309ad8b1aafSjsg void
kthread_init_work(struct kthread_work * work,void (* func)(struct kthread_work *))310ad8b1aafSjsg kthread_init_work(struct kthread_work *work, void (*func)(struct kthread_work *))
311ad8b1aafSjsg {
312ad8b1aafSjsg 	work->tq = NULL;
313ad8b1aafSjsg 	task_set(&work->task, (void (*)(void *))func, work);
314ad8b1aafSjsg }
315ad8b1aafSjsg 
316ad8b1aafSjsg bool
kthread_queue_work(struct kthread_worker * worker,struct kthread_work * work)317ad8b1aafSjsg kthread_queue_work(struct kthread_worker *worker, struct kthread_work *work)
318ad8b1aafSjsg {
319ad8b1aafSjsg 	work->tq = worker->tq;
320ad8b1aafSjsg 	return task_add(work->tq, &work->task);
321ad8b1aafSjsg }
322ad8b1aafSjsg 
323ad8b1aafSjsg bool
kthread_cancel_work_sync(struct kthread_work * work)324ad8b1aafSjsg kthread_cancel_work_sync(struct kthread_work *work)
325ad8b1aafSjsg {
326ad8b1aafSjsg 	return task_del(work->tq, &work->task);
327ad8b1aafSjsg }
328ad8b1aafSjsg 
329ad8b1aafSjsg void
kthread_flush_work(struct kthread_work * work)330ad8b1aafSjsg kthread_flush_work(struct kthread_work *work)
331ad8b1aafSjsg {
332ad8b1aafSjsg 	if (cold)
333ad8b1aafSjsg 		return;
334ad8b1aafSjsg 
335ad8b1aafSjsg 	if (work->tq)
336b11a6e7fSsthen 		taskq_barrier(work->tq);
337ad8b1aafSjsg }
338ad8b1aafSjsg 
339ad8b1aafSjsg void
kthread_flush_worker(struct kthread_worker * worker)340ad8b1aafSjsg kthread_flush_worker(struct kthread_worker *worker)
341ad8b1aafSjsg {
342ad8b1aafSjsg 	if (cold)
343ad8b1aafSjsg 		return;
344ad8b1aafSjsg 
345ad8b1aafSjsg 	if (worker->tq)
346ad8b1aafSjsg 		taskq_barrier(worker->tq);
347ad8b1aafSjsg }
348ad8b1aafSjsg 
34963b8f014Skettenis struct kthread *
kthread_lookup(struct proc * p)35063b8f014Skettenis kthread_lookup(struct proc *p)
35163b8f014Skettenis {
35263b8f014Skettenis 	struct kthread *thread;
35363b8f014Skettenis 
35463b8f014Skettenis 	LIST_FOREACH(thread, &kthread_list, next) {
35563b8f014Skettenis 		if (thread->proc == p)
35663b8f014Skettenis 			break;
35763b8f014Skettenis 	}
35863b8f014Skettenis 	KASSERT(thread);
35963b8f014Skettenis 
36063b8f014Skettenis 	return thread;
36163b8f014Skettenis }
36263b8f014Skettenis 
36363b8f014Skettenis int
kthread_should_park(void)36463b8f014Skettenis kthread_should_park(void)
36563b8f014Skettenis {
36663b8f014Skettenis 	struct kthread *thread = kthread_lookup(curproc);
36763b8f014Skettenis 	return (thread->flags & KTHREAD_SHOULDPARK);
36863b8f014Skettenis }
36963b8f014Skettenis 
37063b8f014Skettenis void
kthread_parkme(void)37163b8f014Skettenis kthread_parkme(void)
37263b8f014Skettenis {
37363b8f014Skettenis 	struct kthread *thread = kthread_lookup(curproc);
37463b8f014Skettenis 
37563b8f014Skettenis 	while (thread->flags & KTHREAD_SHOULDPARK) {
37663b8f014Skettenis 		thread->flags |= KTHREAD_PARKED;
37763b8f014Skettenis 		wakeup(thread);
3781ccb306fSclaudio 		tsleep_nsec(thread, PPAUSE, "parkme", INFSLP);
37963b8f014Skettenis 		thread->flags &= ~KTHREAD_PARKED;
38063b8f014Skettenis 	}
38163b8f014Skettenis }
38263b8f014Skettenis 
38363b8f014Skettenis void
kthread_park(struct proc * p)38463b8f014Skettenis kthread_park(struct proc *p)
38563b8f014Skettenis {
38663b8f014Skettenis 	struct kthread *thread = kthread_lookup(p);
38763b8f014Skettenis 
38863b8f014Skettenis 	while ((thread->flags & KTHREAD_PARKED) == 0) {
38963b8f014Skettenis 		thread->flags |= KTHREAD_SHOULDPARK;
39063b8f014Skettenis 		wake_up_process(thread->proc);
3911ccb306fSclaudio 		tsleep_nsec(thread, PPAUSE, "park", INFSLP);
39263b8f014Skettenis 	}
39363b8f014Skettenis }
39463b8f014Skettenis 
39563b8f014Skettenis void
kthread_unpark(struct proc * p)39663b8f014Skettenis kthread_unpark(struct proc *p)
39763b8f014Skettenis {
39863b8f014Skettenis 	struct kthread *thread = kthread_lookup(p);
39963b8f014Skettenis 
40063b8f014Skettenis 	thread->flags &= ~KTHREAD_SHOULDPARK;
40163b8f014Skettenis 	wakeup(thread);
40263b8f014Skettenis }
40363b8f014Skettenis 
40463b8f014Skettenis int
kthread_should_stop(void)40563b8f014Skettenis kthread_should_stop(void)
40663b8f014Skettenis {
40763b8f014Skettenis 	struct kthread *thread = kthread_lookup(curproc);
40863b8f014Skettenis 	return (thread->flags & KTHREAD_SHOULDSTOP);
40963b8f014Skettenis }
41063b8f014Skettenis 
41163b8f014Skettenis void
kthread_stop(struct proc * p)41263b8f014Skettenis kthread_stop(struct proc *p)
41363b8f014Skettenis {
41463b8f014Skettenis 	struct kthread *thread = kthread_lookup(p);
41563b8f014Skettenis 
41663b8f014Skettenis 	while ((thread->flags & KTHREAD_STOPPED) == 0) {
41763b8f014Skettenis 		thread->flags |= KTHREAD_SHOULDSTOP;
4188224282cSsemarie 		kthread_unpark(p);
41963b8f014Skettenis 		wake_up_process(thread->proc);
4201ccb306fSclaudio 		tsleep_nsec(thread, PPAUSE, "stop", INFSLP);
42163b8f014Skettenis 	}
42263b8f014Skettenis 	LIST_REMOVE(thread, next);
42363b8f014Skettenis 	free(thread, M_DRM, sizeof(*thread));
42463b8f014Skettenis }
42563b8f014Skettenis 
426a3f8ffedSjsg #if NBIOS > 0
427a3f8ffedSjsg extern char smbios_board_vendor[];
428a3f8ffedSjsg extern char smbios_board_prod[];
429a3f8ffedSjsg extern char smbios_board_serial[];
430a3f8ffedSjsg #endif
431a3f8ffedSjsg 
432807828a6Sjsg bool
dmi_match(int slot,const char * str)433807828a6Sjsg dmi_match(int slot, const char *str)
434807828a6Sjsg {
435807828a6Sjsg 	switch (slot) {
436807828a6Sjsg 	case DMI_SYS_VENDOR:
437807828a6Sjsg 		if (hw_vendor != NULL &&
438807828a6Sjsg 		    !strcmp(hw_vendor, str))
439807828a6Sjsg 			return true;
440807828a6Sjsg 		break;
441807828a6Sjsg 	case DMI_PRODUCT_NAME:
442807828a6Sjsg 		if (hw_prod != NULL &&
443807828a6Sjsg 		    !strcmp(hw_prod, str))
444807828a6Sjsg 			return true;
445807828a6Sjsg 		break;
446807828a6Sjsg 	case DMI_PRODUCT_VERSION:
447807828a6Sjsg 		if (hw_ver != NULL &&
448807828a6Sjsg 		    !strcmp(hw_ver, str))
449807828a6Sjsg 			return true;
450807828a6Sjsg 		break;
451a3f8ffedSjsg #if NBIOS > 0
452a3f8ffedSjsg 	case DMI_BOARD_VENDOR:
453a3f8ffedSjsg 		if (strcmp(smbios_board_vendor, str) == 0)
454a3f8ffedSjsg 			return true;
455a3f8ffedSjsg 		break;
456a3f8ffedSjsg 	case DMI_BOARD_NAME:
457a3f8ffedSjsg 		if (strcmp(smbios_board_prod, str) == 0)
458a3f8ffedSjsg 			return true;
459a3f8ffedSjsg 		break;
460a3f8ffedSjsg 	case DMI_BOARD_SERIAL:
461a3f8ffedSjsg 		if (strcmp(smbios_board_serial, str) == 0)
462a3f8ffedSjsg 			return true;
463a3f8ffedSjsg 		break;
464a3f8ffedSjsg #else
465a3f8ffedSjsg 	case DMI_BOARD_VENDOR:
466a3f8ffedSjsg 		if (hw_vendor != NULL &&
467a3f8ffedSjsg 		    !strcmp(hw_vendor, str))
468a3f8ffedSjsg 			return true;
469a3f8ffedSjsg 		break;
470a3f8ffedSjsg 	case DMI_BOARD_NAME:
471a3f8ffedSjsg 		if (hw_prod != NULL &&
472a3f8ffedSjsg 		    !strcmp(hw_prod, str))
473a3f8ffedSjsg 			return true;
474a3f8ffedSjsg 		break;
475a3f8ffedSjsg #endif
476807828a6Sjsg 	case DMI_NONE:
477807828a6Sjsg 	default:
478807828a6Sjsg 		return false;
479807828a6Sjsg 	}
480807828a6Sjsg 
481807828a6Sjsg 	return false;
482807828a6Sjsg }
4830046ae84Sjsg 
4840046ae84Sjsg static bool
dmi_found(const struct dmi_system_id * dsi)4850046ae84Sjsg dmi_found(const struct dmi_system_id *dsi)
4860046ae84Sjsg {
4870046ae84Sjsg 	int i, slot;
4880046ae84Sjsg 
4890046ae84Sjsg 	for (i = 0; i < nitems(dsi->matches); i++) {
4900046ae84Sjsg 		slot = dsi->matches[i].slot;
491807828a6Sjsg 		if (slot == DMI_NONE)
4920046ae84Sjsg 			break;
493807828a6Sjsg 		if (!dmi_match(slot, dsi->matches[i].substr))
4940046ae84Sjsg 			return false;
4950046ae84Sjsg 	}
4960046ae84Sjsg 
4970046ae84Sjsg 	return true;
4980046ae84Sjsg }
4990046ae84Sjsg 
500b1c2f9d1Sjsg const struct dmi_system_id *
dmi_first_match(const struct dmi_system_id * sysid)501b1c2f9d1Sjsg dmi_first_match(const struct dmi_system_id *sysid)
502b1c2f9d1Sjsg {
503b1c2f9d1Sjsg 	const struct dmi_system_id *dsi;
504b1c2f9d1Sjsg 
505b1c2f9d1Sjsg 	for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) {
506b1c2f9d1Sjsg 		if (dmi_found(dsi))
507b1c2f9d1Sjsg 			return dsi;
508b1c2f9d1Sjsg 	}
509b1c2f9d1Sjsg 
510b1c2f9d1Sjsg 	return NULL;
511b1c2f9d1Sjsg }
512b1c2f9d1Sjsg 
5137ef4208bSjsg #if NBIOS > 0
514b1c2f9d1Sjsg extern char smbios_bios_date[];
515d5650ceeSjsg extern char smbios_bios_version[];
516b1c2f9d1Sjsg #endif
517b1c2f9d1Sjsg 
518b1c2f9d1Sjsg const char *
dmi_get_system_info(int slot)519b1c2f9d1Sjsg dmi_get_system_info(int slot)
520b1c2f9d1Sjsg {
5217ef4208bSjsg #if NBIOS > 0
522d5650ceeSjsg 	switch (slot) {
523d5650ceeSjsg 	case DMI_BIOS_DATE:
524b1c2f9d1Sjsg 		return smbios_bios_date;
525d5650ceeSjsg 	case DMI_BIOS_VERSION:
526d5650ceeSjsg 		return smbios_bios_version;
527d5650ceeSjsg 	default:
528d5650ceeSjsg 		printf("%s slot %d not handled\n", __func__, slot);
529d5650ceeSjsg 	}
530b1c2f9d1Sjsg #endif
531b1c2f9d1Sjsg 	return NULL;
532b1c2f9d1Sjsg }
533b1c2f9d1Sjsg 
5340046ae84Sjsg int
dmi_check_system(const struct dmi_system_id * sysid)5350046ae84Sjsg dmi_check_system(const struct dmi_system_id *sysid)
5360046ae84Sjsg {
5370046ae84Sjsg 	const struct dmi_system_id *dsi;
5380046ae84Sjsg 	int num = 0;
5390046ae84Sjsg 
5400046ae84Sjsg 	for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) {
5410046ae84Sjsg 		if (dmi_found(dsi)) {
5420046ae84Sjsg 			num++;
5430046ae84Sjsg 			if (dsi->callback && dsi->callback(dsi))
5440046ae84Sjsg 				break;
5450046ae84Sjsg 		}
5460046ae84Sjsg 	}
5470046ae84Sjsg 	return (num);
5480046ae84Sjsg }
549332cefa1Sjsg 
550c260f068Skettenis struct vm_page *
alloc_pages(unsigned int gfp_mask,unsigned int order)551c260f068Skettenis alloc_pages(unsigned int gfp_mask, unsigned int order)
552c260f068Skettenis {
553c260f068Skettenis 	int flags = (gfp_mask & M_NOWAIT) ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK;
554804f6649Skettenis 	struct uvm_constraint_range *constraint = &no_constraint;
555c260f068Skettenis 	struct pglist mlist;
556c260f068Skettenis 
557c260f068Skettenis 	if (gfp_mask & M_CANFAIL)
558c260f068Skettenis 		flags |= UVM_PLA_FAILOK;
5593253c27bSkettenis 	if (gfp_mask & M_ZERO)
5603253c27bSkettenis 		flags |= UVM_PLA_ZERO;
561804f6649Skettenis 	if (gfp_mask & __GFP_DMA32)
562804f6649Skettenis 		constraint = &dma_constraint;
563c260f068Skettenis 
564c260f068Skettenis 	TAILQ_INIT(&mlist);
565804f6649Skettenis 	if (uvm_pglistalloc(PAGE_SIZE << order, constraint->ucr_low,
566804f6649Skettenis 	    constraint->ucr_high, PAGE_SIZE, 0, &mlist, 1, flags))
567c260f068Skettenis 		return NULL;
568c260f068Skettenis 	return TAILQ_FIRST(&mlist);
569c260f068Skettenis }
570c260f068Skettenis 
571c260f068Skettenis void
__free_pages(struct vm_page * page,unsigned int order)572c260f068Skettenis __free_pages(struct vm_page *page, unsigned int order)
573c260f068Skettenis {
574c260f068Skettenis 	struct pglist mlist;
575c260f068Skettenis 	int i;
576c260f068Skettenis 
577c260f068Skettenis 	TAILQ_INIT(&mlist);
578c260f068Skettenis 	for (i = 0; i < (1 << order); i++)
579c260f068Skettenis 		TAILQ_INSERT_TAIL(&mlist, &page[i], pageq);
580c260f068Skettenis 	uvm_pglistfree(&mlist);
581c260f068Skettenis }
582c260f068Skettenis 
5837f4dd379Sjsg void
__pagevec_release(struct pagevec * pvec)5847f4dd379Sjsg __pagevec_release(struct pagevec *pvec)
5857f4dd379Sjsg {
5867f4dd379Sjsg 	struct pglist mlist;
5877f4dd379Sjsg 	int i;
5887f4dd379Sjsg 
5897f4dd379Sjsg 	TAILQ_INIT(&mlist);
5907f4dd379Sjsg 	for (i = 0; i < pvec->nr; i++)
5917f4dd379Sjsg 		TAILQ_INSERT_TAIL(&mlist, pvec->pages[i], pageq);
5927f4dd379Sjsg 	uvm_pglistfree(&mlist);
5937f4dd379Sjsg 	pagevec_reinit(pvec);
5947f4dd379Sjsg }
5957f4dd379Sjsg 
59674cebfa8Skettenis static struct kmem_va_mode kv_physwait = {
59774cebfa8Skettenis 	.kv_map = &phys_map,
59874cebfa8Skettenis 	.kv_wait = 1,
59974cebfa8Skettenis };
60074cebfa8Skettenis 
601332cefa1Sjsg void *
kmap(struct vm_page * pg)602332cefa1Sjsg kmap(struct vm_page *pg)
603332cefa1Sjsg {
604332cefa1Sjsg 	vaddr_t va;
605332cefa1Sjsg 
606332cefa1Sjsg #if defined (__HAVE_PMAP_DIRECT)
607332cefa1Sjsg 	va = pmap_map_direct(pg);
608332cefa1Sjsg #else
60974cebfa8Skettenis 	va = (vaddr_t)km_alloc(PAGE_SIZE, &kv_physwait, &kp_none, &kd_waitok);
610332cefa1Sjsg 	pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), PROT_READ | PROT_WRITE);
611332cefa1Sjsg 	pmap_update(pmap_kernel());
612332cefa1Sjsg #endif
613332cefa1Sjsg 	return (void *)va;
614332cefa1Sjsg }
615332cefa1Sjsg 
616332cefa1Sjsg void
kunmap_va(void * addr)6176942ea66Sjsg kunmap_va(void *addr)
618332cefa1Sjsg {
619332cefa1Sjsg 	vaddr_t va = (vaddr_t)addr;
620332cefa1Sjsg 
621332cefa1Sjsg #if defined (__HAVE_PMAP_DIRECT)
622332cefa1Sjsg 	pmap_unmap_direct(va);
623332cefa1Sjsg #else
624332cefa1Sjsg 	pmap_kremove(va, PAGE_SIZE);
625332cefa1Sjsg 	pmap_update(pmap_kernel());
62674cebfa8Skettenis 	km_free((void *)va, PAGE_SIZE, &kv_physwait, &kp_none);
627332cefa1Sjsg #endif
628332cefa1Sjsg }
629332cefa1Sjsg 
63049a189d2Skettenis vaddr_t kmap_atomic_va;
63149a189d2Skettenis int kmap_atomic_inuse;
63249a189d2Skettenis 
63349a189d2Skettenis void *
kmap_atomic_prot(struct vm_page * pg,pgprot_t prot)63449a189d2Skettenis kmap_atomic_prot(struct vm_page *pg, pgprot_t prot)
63549a189d2Skettenis {
63649a189d2Skettenis 	KASSERT(!kmap_atomic_inuse);
63749a189d2Skettenis 
63849a189d2Skettenis 	kmap_atomic_inuse = 1;
63949a189d2Skettenis 	pmap_kenter_pa(kmap_atomic_va, VM_PAGE_TO_PHYS(pg) | prot,
64049a189d2Skettenis 	    PROT_READ | PROT_WRITE);
64149a189d2Skettenis 	return (void *)kmap_atomic_va;
64249a189d2Skettenis }
64349a189d2Skettenis 
64449a189d2Skettenis void
kunmap_atomic(void * addr)64549a189d2Skettenis kunmap_atomic(void *addr)
64649a189d2Skettenis {
64749a189d2Skettenis 	KASSERT(kmap_atomic_inuse);
64849a189d2Skettenis 
64949a189d2Skettenis 	pmap_kremove(kmap_atomic_va, PAGE_SIZE);
65049a189d2Skettenis 	kmap_atomic_inuse = 0;
65149a189d2Skettenis }
65249a189d2Skettenis 
653332cefa1Sjsg void *
vmap(struct vm_page ** pages,unsigned int npages,unsigned long flags,pgprot_t prot)654332cefa1Sjsg vmap(struct vm_page **pages, unsigned int npages, unsigned long flags,
655332cefa1Sjsg      pgprot_t prot)
656332cefa1Sjsg {
657332cefa1Sjsg 	vaddr_t va;
658332cefa1Sjsg 	paddr_t pa;
659332cefa1Sjsg 	int i;
660332cefa1Sjsg 
66174cebfa8Skettenis 	va = (vaddr_t)km_alloc(PAGE_SIZE * npages, &kv_any, &kp_none,
66274cebfa8Skettenis 	    &kd_nowait);
663332cefa1Sjsg 	if (va == 0)
664332cefa1Sjsg 		return NULL;
665332cefa1Sjsg 	for (i = 0; i < npages; i++) {
666332cefa1Sjsg 		pa = VM_PAGE_TO_PHYS(pages[i]) | prot;
667332cefa1Sjsg 		pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa,
668332cefa1Sjsg 		    PROT_READ | PROT_WRITE,
669332cefa1Sjsg 		    PROT_READ | PROT_WRITE | PMAP_WIRED);
670332cefa1Sjsg 		pmap_update(pmap_kernel());
671332cefa1Sjsg 	}
672332cefa1Sjsg 
673332cefa1Sjsg 	return (void *)va;
674332cefa1Sjsg }
675332cefa1Sjsg 
676c036ab16Sjsg void *
vmap_pfn(unsigned long * pfns,unsigned int npfn,pgprot_t prot)677c036ab16Sjsg vmap_pfn(unsigned long *pfns, unsigned int npfn, pgprot_t prot)
678c036ab16Sjsg {
679c036ab16Sjsg 	vaddr_t va;
680c036ab16Sjsg 	paddr_t pa;
681c036ab16Sjsg 	int i;
682c036ab16Sjsg 
683c036ab16Sjsg 	va = (vaddr_t)km_alloc(PAGE_SIZE * npfn, &kv_any, &kp_none,
684c036ab16Sjsg 	    &kd_nowait);
685c036ab16Sjsg 	if (va == 0)
686c036ab16Sjsg 		return NULL;
687c036ab16Sjsg 	for (i = 0; i < npfn; i++) {
688c036ab16Sjsg 		pa = round_page(pfns[i]) | prot;
689c036ab16Sjsg 		pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa,
690c036ab16Sjsg 		    PROT_READ | PROT_WRITE,
691c036ab16Sjsg 		    PROT_READ | PROT_WRITE | PMAP_WIRED);
692c036ab16Sjsg 		pmap_update(pmap_kernel());
693c036ab16Sjsg 	}
694c036ab16Sjsg 
695c036ab16Sjsg 	return (void *)va;
696c036ab16Sjsg }
697c036ab16Sjsg 
698332cefa1Sjsg void
vunmap(void * addr,size_t size)699332cefa1Sjsg vunmap(void *addr, size_t size)
700332cefa1Sjsg {
701332cefa1Sjsg 	vaddr_t va = (vaddr_t)addr;
702332cefa1Sjsg 
703332cefa1Sjsg 	pmap_remove(pmap_kernel(), va, va + size);
704332cefa1Sjsg 	pmap_update(pmap_kernel());
70574cebfa8Skettenis 	km_free((void *)va, size, &kv_any, &kp_none);
706332cefa1Sjsg }
707332cefa1Sjsg 
708ad8b1aafSjsg bool
is_vmalloc_addr(const void * p)709ad8b1aafSjsg is_vmalloc_addr(const void *p)
710ad8b1aafSjsg {
711ad8b1aafSjsg 	vaddr_t min, max, addr;
712ad8b1aafSjsg 
713ad8b1aafSjsg 	min = vm_map_min(kernel_map);
714ad8b1aafSjsg 	max = vm_map_max(kernel_map);
715ad8b1aafSjsg 	addr = (vaddr_t)p;
716ad8b1aafSjsg 
717ad8b1aafSjsg 	if (addr >= min && addr <= max)
718ad8b1aafSjsg 		return true;
719ad8b1aafSjsg 	else
720ad8b1aafSjsg 		return false;
721ad8b1aafSjsg }
722ad8b1aafSjsg 
7233253c27bSkettenis void
print_hex_dump(const char * level,const char * prefix_str,int prefix_type,int rowsize,int groupsize,const void * buf,size_t len,bool ascii)7243253c27bSkettenis print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
7253253c27bSkettenis     int rowsize, int groupsize, const void *buf, size_t len, bool ascii)
7263253c27bSkettenis {
7273253c27bSkettenis 	const uint8_t *cbuf = buf;
7283253c27bSkettenis 	int i;
7293253c27bSkettenis 
7303253c27bSkettenis 	for (i = 0; i < len; i++) {
7313253c27bSkettenis 		if ((i % rowsize) == 0)
7323253c27bSkettenis 			printf("%s", prefix_str);
7333253c27bSkettenis 		printf("%02x", cbuf[i]);
7343253c27bSkettenis 		if ((i % rowsize) == (rowsize - 1))
7353253c27bSkettenis 			printf("\n");
7363253c27bSkettenis 		else
7373253c27bSkettenis 			printf(" ");
7383253c27bSkettenis 	}
7393253c27bSkettenis }
7403253c27bSkettenis 
7413253c27bSkettenis void *
memchr_inv(const void * s,int c,size_t n)7423253c27bSkettenis memchr_inv(const void *s, int c, size_t n)
7433253c27bSkettenis {
7443253c27bSkettenis 	if (n != 0) {
7453253c27bSkettenis 		const unsigned char *p = s;
7463253c27bSkettenis 
7473253c27bSkettenis 		do {
7483253c27bSkettenis 			if (*p++ != (unsigned char)c)
7493253c27bSkettenis 				return ((void *)(p - 1));
7503253c27bSkettenis 		} while (--n != 0);
7513253c27bSkettenis 	}
7523253c27bSkettenis 	return (NULL);
7533253c27bSkettenis }
7543253c27bSkettenis 
75589859f0fSkettenis int
panic_cmp(struct rb_node * a,struct rb_node * b)75689859f0fSkettenis panic_cmp(struct rb_node *a, struct rb_node *b)
75789859f0fSkettenis {
75889859f0fSkettenis 	panic(__func__);
75989859f0fSkettenis }
76089859f0fSkettenis 
76189859f0fSkettenis #undef RB_ROOT
76289859f0fSkettenis #define RB_ROOT(head)	(head)->rbh_root
76389859f0fSkettenis 
76489859f0fSkettenis RB_GENERATE(linux_root, rb_node, __entry, panic_cmp);
76589859f0fSkettenis 
766d71700c3Skettenis /*
767d71700c3Skettenis  * This is a fairly minimal implementation of the Linux "idr" API.  It
7685ca02815Sjsg  * probably isn't very efficient, and definitely isn't RCU safe.  The
769d71700c3Skettenis  * pre-load buffer is global instead of per-cpu; we rely on the kernel
770d71700c3Skettenis  * lock to make this work.  We do randomize our IDs in order to make
771d71700c3Skettenis  * them harder to guess.
772d71700c3Skettenis  */
773d71700c3Skettenis 
774d71700c3Skettenis int idr_cmp(struct idr_entry *, struct idr_entry *);
775d71700c3Skettenis SPLAY_PROTOTYPE(idr_tree, idr_entry, entry, idr_cmp);
776d71700c3Skettenis 
777d71700c3Skettenis struct pool idr_pool;
778d71700c3Skettenis struct idr_entry *idr_entry_cache;
779d71700c3Skettenis 
780d71700c3Skettenis void
idr_init(struct idr * idr)781d71700c3Skettenis idr_init(struct idr *idr)
782d71700c3Skettenis {
783d71700c3Skettenis 	SPLAY_INIT(&idr->tree);
784d71700c3Skettenis }
785d71700c3Skettenis 
786d71700c3Skettenis void
idr_destroy(struct idr * idr)787d71700c3Skettenis idr_destroy(struct idr *idr)
788d71700c3Skettenis {
789d71700c3Skettenis 	struct idr_entry *id;
790d71700c3Skettenis 
791d71700c3Skettenis 	while ((id = SPLAY_MIN(idr_tree, &idr->tree))) {
792d71700c3Skettenis 		SPLAY_REMOVE(idr_tree, &idr->tree, id);
793d71700c3Skettenis 		pool_put(&idr_pool, id);
794d71700c3Skettenis 	}
795d71700c3Skettenis }
796d71700c3Skettenis 
797d71700c3Skettenis void
idr_preload(unsigned int gfp_mask)798d71700c3Skettenis idr_preload(unsigned int gfp_mask)
799d71700c3Skettenis {
800d71700c3Skettenis 	int flags = (gfp_mask & GFP_NOWAIT) ? PR_NOWAIT : PR_WAITOK;
801d71700c3Skettenis 
802d71700c3Skettenis 	KERNEL_ASSERT_LOCKED();
803d71700c3Skettenis 
804d71700c3Skettenis 	if (idr_entry_cache == NULL)
805d71700c3Skettenis 		idr_entry_cache = pool_get(&idr_pool, flags);
806d71700c3Skettenis }
807d71700c3Skettenis 
808d71700c3Skettenis int
idr_alloc(struct idr * idr,void * ptr,int start,int end,gfp_t gfp_mask)809d9e6dc4fSkettenis idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
810d71700c3Skettenis {
811d71700c3Skettenis 	int flags = (gfp_mask & GFP_NOWAIT) ? PR_NOWAIT : PR_WAITOK;
812d71700c3Skettenis 	struct idr_entry *id;
8138c3d1b55Skettenis 	int begin;
814d71700c3Skettenis 
815d71700c3Skettenis 	KERNEL_ASSERT_LOCKED();
816d71700c3Skettenis 
817d71700c3Skettenis 	if (idr_entry_cache) {
818d71700c3Skettenis 		id = idr_entry_cache;
819d71700c3Skettenis 		idr_entry_cache = NULL;
820d71700c3Skettenis 	} else {
821d71700c3Skettenis 		id = pool_get(&idr_pool, flags);
822d71700c3Skettenis 		if (id == NULL)
823d71700c3Skettenis 			return -ENOMEM;
824d71700c3Skettenis 	}
825d71700c3Skettenis 
826d71700c3Skettenis 	if (end <= 0)
827d71700c3Skettenis 		end = INT_MAX;
828d71700c3Skettenis 
8293253c27bSkettenis #ifdef notyet
8308c3d1b55Skettenis 	id->id = begin = start + arc4random_uniform(end - start);
8313253c27bSkettenis #else
8323253c27bSkettenis 	id->id = begin = start;
8333253c27bSkettenis #endif
834d71700c3Skettenis 	while (SPLAY_INSERT(idr_tree, &idr->tree, id)) {
8354ce37e7fSjsg 		if (id->id == end)
836d71700c3Skettenis 			id->id = start;
8374ce37e7fSjsg 		else
8384ce37e7fSjsg 			id->id++;
8398c3d1b55Skettenis 		if (id->id == begin) {
8408c3d1b55Skettenis 			pool_put(&idr_pool, id);
8418c3d1b55Skettenis 			return -ENOSPC;
8428c3d1b55Skettenis 		}
843d71700c3Skettenis 	}
844d71700c3Skettenis 	id->ptr = ptr;
845d71700c3Skettenis 	return id->id;
846d71700c3Skettenis }
847d71700c3Skettenis 
8483253c27bSkettenis void *
idr_replace(struct idr * idr,void * ptr,unsigned long id)849d9e6dc4fSkettenis idr_replace(struct idr *idr, void *ptr, unsigned long id)
8503253c27bSkettenis {
8513253c27bSkettenis 	struct idr_entry find, *res;
8523253c27bSkettenis 	void *old;
8533253c27bSkettenis 
8543253c27bSkettenis 	find.id = id;
8553253c27bSkettenis 	res = SPLAY_FIND(idr_tree, &idr->tree, &find);
8563253c27bSkettenis 	if (res == NULL)
8573253c27bSkettenis 		return ERR_PTR(-ENOENT);
8583253c27bSkettenis 	old = res->ptr;
8593253c27bSkettenis 	res->ptr = ptr;
8603253c27bSkettenis 	return old;
8613253c27bSkettenis }
8623253c27bSkettenis 
8637f4dd379Sjsg void *
idr_remove(struct idr * idr,unsigned long id)864d9e6dc4fSkettenis idr_remove(struct idr *idr, unsigned long id)
865d71700c3Skettenis {
866d71700c3Skettenis 	struct idr_entry find, *res;
8677f4dd379Sjsg 	void *ptr = NULL;
868d71700c3Skettenis 
869d71700c3Skettenis 	find.id = id;
870d71700c3Skettenis 	res = SPLAY_FIND(idr_tree, &idr->tree, &find);
871d71700c3Skettenis 	if (res) {
872d71700c3Skettenis 		SPLAY_REMOVE(idr_tree, &idr->tree, res);
8737f4dd379Sjsg 		ptr = res->ptr;
874d71700c3Skettenis 		pool_put(&idr_pool, res);
875d71700c3Skettenis 	}
8767f4dd379Sjsg 	return ptr;
877d71700c3Skettenis }
878d71700c3Skettenis 
879d71700c3Skettenis void *
idr_find(struct idr * idr,unsigned long id)880d9e6dc4fSkettenis idr_find(struct idr *idr, unsigned long id)
881d71700c3Skettenis {
882d71700c3Skettenis 	struct idr_entry find, *res;
883d71700c3Skettenis 
884d71700c3Skettenis 	find.id = id;
885d71700c3Skettenis 	res = SPLAY_FIND(idr_tree, &idr->tree, &find);
886d71700c3Skettenis 	if (res == NULL)
887d71700c3Skettenis 		return NULL;
888d71700c3Skettenis 	return res->ptr;
889d71700c3Skettenis }
890d71700c3Skettenis 
8913253c27bSkettenis void *
idr_get_next(struct idr * idr,int * id)8923253c27bSkettenis idr_get_next(struct idr *idr, int *id)
8933253c27bSkettenis {
8943253c27bSkettenis 	struct idr_entry *res;
8953253c27bSkettenis 
89623c0d2a5Skettenis 	SPLAY_FOREACH(res, idr_tree, &idr->tree) {
89723c0d2a5Skettenis 		if (res->id >= *id) {
8983253c27bSkettenis 			*id = res->id;
8993253c27bSkettenis 			return res->ptr;
9003253c27bSkettenis 		}
90123c0d2a5Skettenis 	}
90223c0d2a5Skettenis 
90323c0d2a5Skettenis 	return NULL;
90423c0d2a5Skettenis }
9053253c27bSkettenis 
906d71700c3Skettenis int
idr_for_each(struct idr * idr,int (* func)(int,void *,void *),void * data)907d71700c3Skettenis idr_for_each(struct idr *idr, int (*func)(int, void *, void *), void *data)
908d71700c3Skettenis {
909d71700c3Skettenis 	struct idr_entry *id;
910d71700c3Skettenis 	int ret;
911d71700c3Skettenis 
912d71700c3Skettenis 	SPLAY_FOREACH(id, idr_tree, &idr->tree) {
913d71700c3Skettenis 		ret = func(id->id, id->ptr, data);
914d71700c3Skettenis 		if (ret)
915d71700c3Skettenis 			return ret;
916d71700c3Skettenis 	}
917d71700c3Skettenis 
918d71700c3Skettenis 	return 0;
919d71700c3Skettenis }
920d71700c3Skettenis 
921d71700c3Skettenis int
idr_cmp(struct idr_entry * a,struct idr_entry * b)922d71700c3Skettenis idr_cmp(struct idr_entry *a, struct idr_entry *b)
923d71700c3Skettenis {
924d71700c3Skettenis 	return (a->id < b->id ? -1 : a->id > b->id);
925d71700c3Skettenis }
926d71700c3Skettenis 
927d71700c3Skettenis SPLAY_GENERATE(idr_tree, idr_entry, entry, idr_cmp);
928d71700c3Skettenis 
9293253c27bSkettenis void
ida_init(struct ida * ida)9303253c27bSkettenis ida_init(struct ida *ida)
9313253c27bSkettenis {
932d9e6dc4fSkettenis 	idr_init(&ida->idr);
9333253c27bSkettenis }
9343253c27bSkettenis 
9353253c27bSkettenis void
ida_destroy(struct ida * ida)9363253c27bSkettenis ida_destroy(struct ida *ida)
9373253c27bSkettenis {
938d9e6dc4fSkettenis 	idr_destroy(&ida->idr);
9393253c27bSkettenis }
9403253c27bSkettenis 
9413253c27bSkettenis int
ida_simple_get(struct ida * ida,unsigned int start,unsigned int end,gfp_t gfp_mask)9423253c27bSkettenis ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
943d9e6dc4fSkettenis     gfp_t gfp_mask)
9443253c27bSkettenis {
945d9e6dc4fSkettenis 	return idr_alloc(&ida->idr, NULL, start, end, gfp_mask);
9463253c27bSkettenis }
9473253c27bSkettenis 
9487f4dd379Sjsg void
ida_simple_remove(struct ida * ida,unsigned int id)949d9e6dc4fSkettenis ida_simple_remove(struct ida *ida, unsigned int id)
9507f4dd379Sjsg {
951d9e6dc4fSkettenis 	idr_remove(&ida->idr, id);
9527f4dd379Sjsg }
9537f4dd379Sjsg 
9543253c27bSkettenis int
ida_alloc_min(struct ida * ida,unsigned int min,gfp_t gfp)9551bb76ff1Sjsg ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp)
9561bb76ff1Sjsg {
9571bb76ff1Sjsg 	return idr_alloc(&ida->idr, NULL, min, INT_MAX, gfp);
9581bb76ff1Sjsg }
9591bb76ff1Sjsg 
9601bb76ff1Sjsg int
ida_alloc_max(struct ida * ida,unsigned int max,gfp_t gfp)9611bb76ff1Sjsg ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp)
9621bb76ff1Sjsg {
9631bb76ff1Sjsg 	return idr_alloc(&ida->idr, NULL, 0, max - 1, gfp);
9641bb76ff1Sjsg }
9651bb76ff1Sjsg 
9661bb76ff1Sjsg void
ida_free(struct ida * ida,unsigned int id)9671bb76ff1Sjsg ida_free(struct ida *ida, unsigned int id)
9681bb76ff1Sjsg {
9691bb76ff1Sjsg 	idr_remove(&ida->idr, id);
9701bb76ff1Sjsg }
9711bb76ff1Sjsg 
9721bb76ff1Sjsg int
xarray_cmp(struct xarray_entry * a,struct xarray_entry * b)973c349dbc7Sjsg xarray_cmp(struct xarray_entry *a, struct xarray_entry *b)
974c349dbc7Sjsg {
975c349dbc7Sjsg 	return (a->id < b->id ? -1 : a->id > b->id);
976c349dbc7Sjsg }
977c349dbc7Sjsg 
978c349dbc7Sjsg SPLAY_PROTOTYPE(xarray_tree, xarray_entry, entry, xarray_cmp);
979c349dbc7Sjsg struct pool xa_pool;
980c349dbc7Sjsg SPLAY_GENERATE(xarray_tree, xarray_entry, entry, xarray_cmp);
981c349dbc7Sjsg 
982c349dbc7Sjsg void
xa_init_flags(struct xarray * xa,gfp_t flags)983c349dbc7Sjsg xa_init_flags(struct xarray *xa, gfp_t flags)
984c349dbc7Sjsg {
985c349dbc7Sjsg 	static int initialized;
986c349dbc7Sjsg 
987c349dbc7Sjsg 	if (!initialized) {
988373fecfbSjsg 		pool_init(&xa_pool, sizeof(struct xarray_entry), 0, IPL_NONE, 0,
989c349dbc7Sjsg 		    "xapl", NULL);
990c349dbc7Sjsg 		initialized = 1;
991c349dbc7Sjsg 	}
992c349dbc7Sjsg 	SPLAY_INIT(&xa->xa_tree);
9935ca02815Sjsg 	if (flags & XA_FLAGS_LOCK_IRQ)
9945ca02815Sjsg 		mtx_init(&xa->xa_lock, IPL_TTY);
9955ca02815Sjsg 	else
9965ca02815Sjsg 		mtx_init(&xa->xa_lock, IPL_NONE);
997c349dbc7Sjsg }
998c349dbc7Sjsg 
999c349dbc7Sjsg void
xa_destroy(struct xarray * xa)1000c349dbc7Sjsg xa_destroy(struct xarray *xa)
1001c349dbc7Sjsg {
1002c349dbc7Sjsg 	struct xarray_entry *id;
1003c349dbc7Sjsg 
1004c349dbc7Sjsg 	while ((id = SPLAY_MIN(xarray_tree, &xa->xa_tree))) {
1005c349dbc7Sjsg 		SPLAY_REMOVE(xarray_tree, &xa->xa_tree, id);
1006c349dbc7Sjsg 		pool_put(&xa_pool, id);
1007c349dbc7Sjsg 	}
1008c349dbc7Sjsg }
1009c349dbc7Sjsg 
10101bb76ff1Sjsg /* Don't wrap ids. */
1011c349dbc7Sjsg int
__xa_alloc(struct xarray * xa,u32 * id,void * entry,int limit,gfp_t gfp)10125ca02815Sjsg __xa_alloc(struct xarray *xa, u32 *id, void *entry, int limit, gfp_t gfp)
1013c349dbc7Sjsg {
1014c349dbc7Sjsg 	struct xarray_entry *xid;
1015c349dbc7Sjsg 	int start = (xa->xa_flags & XA_FLAGS_ALLOC1) ? 1 : 0;
1016c349dbc7Sjsg 	int begin;
1017c349dbc7Sjsg 
1018be42cb11Sjsg 	if (gfp & GFP_NOWAIT) {
1019be42cb11Sjsg 		xid = pool_get(&xa_pool, PR_NOWAIT);
1020be42cb11Sjsg 	} else {
1021be42cb11Sjsg 		mtx_leave(&xa->xa_lock);
1022be42cb11Sjsg 		xid = pool_get(&xa_pool, PR_WAITOK);
1023be42cb11Sjsg 		mtx_enter(&xa->xa_lock);
1024be42cb11Sjsg 	}
1025be42cb11Sjsg 
1026c349dbc7Sjsg 	if (xid == NULL)
1027c349dbc7Sjsg 		return -ENOMEM;
1028c349dbc7Sjsg 
1029c349dbc7Sjsg 	if (limit <= 0)
1030c349dbc7Sjsg 		limit = INT_MAX;
1031c349dbc7Sjsg 
1032c349dbc7Sjsg 	xid->id = begin = start;
1033c349dbc7Sjsg 
1034c349dbc7Sjsg 	while (SPLAY_INSERT(xarray_tree, &xa->xa_tree, xid)) {
10354ce37e7fSjsg 		if (xid->id == limit)
1036c349dbc7Sjsg 			xid->id = start;
10374ce37e7fSjsg 		else
10384ce37e7fSjsg 			xid->id++;
1039c349dbc7Sjsg 		if (xid->id == begin) {
1040c349dbc7Sjsg 			pool_put(&xa_pool, xid);
1041c349dbc7Sjsg 			return -EBUSY;
1042c349dbc7Sjsg 		}
1043c349dbc7Sjsg 	}
1044c349dbc7Sjsg 	xid->ptr = entry;
1045c349dbc7Sjsg 	*id = xid->id;
1046c349dbc7Sjsg 	return 0;
1047c349dbc7Sjsg }
1048c349dbc7Sjsg 
10491bb76ff1Sjsg /*
10501bb76ff1Sjsg  * Wrap ids and store next id.
10511bb76ff1Sjsg  * We walk the entire tree so don't special case wrapping.
10521bb76ff1Sjsg  * The only caller of this (i915_drm_client.c) doesn't use next id.
10531bb76ff1Sjsg  */
10541bb76ff1Sjsg int
__xa_alloc_cyclic(struct xarray * xa,u32 * id,void * entry,int limit,u32 * next,gfp_t gfp)10551bb76ff1Sjsg __xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry, int limit, u32 *next,
10561bb76ff1Sjsg     gfp_t gfp)
10571bb76ff1Sjsg {
10581bb76ff1Sjsg 	int r = __xa_alloc(xa, id, entry, limit, gfp);
10591bb76ff1Sjsg 	*next = *id + 1;
10601bb76ff1Sjsg 	return r;
10611bb76ff1Sjsg }
10621bb76ff1Sjsg 
1063c349dbc7Sjsg void *
__xa_erase(struct xarray * xa,unsigned long index)10645ca02815Sjsg __xa_erase(struct xarray *xa, unsigned long index)
1065c349dbc7Sjsg {
1066c349dbc7Sjsg 	struct xarray_entry find, *res;
1067c349dbc7Sjsg 	void *ptr = NULL;
1068c349dbc7Sjsg 
1069c349dbc7Sjsg 	find.id = index;
1070c349dbc7Sjsg 	res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
1071c349dbc7Sjsg 	if (res) {
1072c349dbc7Sjsg 		SPLAY_REMOVE(xarray_tree, &xa->xa_tree, res);
1073c349dbc7Sjsg 		ptr = res->ptr;
1074c349dbc7Sjsg 		pool_put(&xa_pool, res);
1075c349dbc7Sjsg 	}
1076c349dbc7Sjsg 	return ptr;
1077c349dbc7Sjsg }
1078c349dbc7Sjsg 
1079c349dbc7Sjsg void *
__xa_load(struct xarray * xa,unsigned long index)10805ca02815Sjsg __xa_load(struct xarray *xa, unsigned long index)
1081c349dbc7Sjsg {
1082c349dbc7Sjsg 	struct xarray_entry find, *res;
1083c349dbc7Sjsg 
1084c349dbc7Sjsg 	find.id = index;
1085c349dbc7Sjsg 	res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
1086c349dbc7Sjsg 	if (res == NULL)
1087c349dbc7Sjsg 		return NULL;
1088c349dbc7Sjsg 	return res->ptr;
1089c349dbc7Sjsg }
1090c349dbc7Sjsg 
1091c349dbc7Sjsg void *
__xa_store(struct xarray * xa,unsigned long index,void * entry,gfp_t gfp)10925ca02815Sjsg __xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
10935ca02815Sjsg {
10945ca02815Sjsg 	struct xarray_entry find, *res;
10955ca02815Sjsg 	void *prev;
10965ca02815Sjsg 
10975ca02815Sjsg 	if (entry == NULL)
10985ca02815Sjsg 		return __xa_erase(xa, index);
10995ca02815Sjsg 
11005ca02815Sjsg 	find.id = index;
11015ca02815Sjsg 	res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
11025ca02815Sjsg 	if (res != NULL) {
11035ca02815Sjsg 		/* index exists */
11045ca02815Sjsg 		/* XXX Multislot entries updates not implemented yet */
11055ca02815Sjsg 		prev = res->ptr;
11065ca02815Sjsg 		res->ptr = entry;
11075ca02815Sjsg 		return prev;
11085ca02815Sjsg 	}
11095ca02815Sjsg 
11105ca02815Sjsg 	/* index not found, add new */
1111be42cb11Sjsg 	if (gfp & GFP_NOWAIT) {
1112be42cb11Sjsg 		res = pool_get(&xa_pool, PR_NOWAIT);
1113be42cb11Sjsg 	} else {
1114be42cb11Sjsg 		mtx_leave(&xa->xa_lock);
1115be42cb11Sjsg 		res = pool_get(&xa_pool, PR_WAITOK);
1116be42cb11Sjsg 		mtx_enter(&xa->xa_lock);
1117be42cb11Sjsg 	}
11185ca02815Sjsg 	if (res == NULL)
11195ca02815Sjsg 		return XA_ERROR(-ENOMEM);
11205ca02815Sjsg 	res->id = index;
11215ca02815Sjsg 	res->ptr = entry;
11225ca02815Sjsg 	if (SPLAY_INSERT(xarray_tree, &xa->xa_tree, res) != NULL)
11235ca02815Sjsg 		return XA_ERROR(-EINVAL);
11245ca02815Sjsg 	return NULL; /* no prev entry at index */
11255ca02815Sjsg }
11265ca02815Sjsg 
11275ca02815Sjsg void *
xa_get_next(struct xarray * xa,unsigned long * index)1128c349dbc7Sjsg xa_get_next(struct xarray *xa, unsigned long *index)
1129c349dbc7Sjsg {
1130c349dbc7Sjsg 	struct xarray_entry *res;
1131c349dbc7Sjsg 
1132c349dbc7Sjsg 	SPLAY_FOREACH(res, xarray_tree, &xa->xa_tree) {
1133c349dbc7Sjsg 		if (res->id >= *index) {
1134c349dbc7Sjsg 			*index = res->id;
1135c349dbc7Sjsg 			return res->ptr;
1136c349dbc7Sjsg 		}
1137c349dbc7Sjsg 	}
1138c349dbc7Sjsg 
1139c349dbc7Sjsg 	return NULL;
1140c349dbc7Sjsg }
1141c349dbc7Sjsg 
1142c349dbc7Sjsg int
sg_alloc_table(struct sg_table * table,unsigned int nents,gfp_t gfp_mask)11433253c27bSkettenis sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
11443253c27bSkettenis {
11453253c27bSkettenis 	table->sgl = mallocarray(nents, sizeof(struct scatterlist),
1146ad8b1aafSjsg 	    M_DRM, gfp_mask | M_ZERO);
11473253c27bSkettenis 	if (table->sgl == NULL)
11483253c27bSkettenis 		return -ENOMEM;
11493253c27bSkettenis 	table->nents = table->orig_nents = nents;
1150ad8b1aafSjsg 	sg_mark_end(&table->sgl[nents - 1]);
11513253c27bSkettenis 	return 0;
11523253c27bSkettenis }
11533253c27bSkettenis 
11543253c27bSkettenis void
sg_free_table(struct sg_table * table)11553253c27bSkettenis sg_free_table(struct sg_table *table)
11563253c27bSkettenis {
11573253c27bSkettenis 	free(table->sgl, M_DRM,
11583253c27bSkettenis 	    table->orig_nents * sizeof(struct scatterlist));
1159ad8b1aafSjsg 	table->orig_nents = 0;
1160ee152407Sjsg 	table->sgl = NULL;
11613253c27bSkettenis }
11623253c27bSkettenis 
11633253c27bSkettenis size_t
sg_copy_from_buffer(struct scatterlist * sgl,unsigned int nents,const void * buf,size_t buflen)11643253c27bSkettenis sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
11653253c27bSkettenis     const void *buf, size_t buflen)
11663253c27bSkettenis {
11673253c27bSkettenis 	panic("%s", __func__);
11683253c27bSkettenis }
11693253c27bSkettenis 
11703253c27bSkettenis int
i2c_master_xfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)1171142c034fSkettenis i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
11723253c27bSkettenis {
11733253c27bSkettenis 	void *cmd = NULL;
11743253c27bSkettenis 	int cmdlen = 0;
11753253c27bSkettenis 	int err, ret = 0;
11763253c27bSkettenis 	int op;
11773253c27bSkettenis 
11783253c27bSkettenis 	iic_acquire_bus(&adap->ic, 0);
11793253c27bSkettenis 
11803253c27bSkettenis 	while (num > 2) {
11813253c27bSkettenis 		op = (msgs->flags & I2C_M_RD) ? I2C_OP_READ : I2C_OP_WRITE;
11823253c27bSkettenis 		err = iic_exec(&adap->ic, op, msgs->addr, NULL, 0,
11833253c27bSkettenis 		    msgs->buf, msgs->len, 0);
11843253c27bSkettenis 		if (err) {
11853253c27bSkettenis 			ret = -err;
11863253c27bSkettenis 			goto fail;
11873253c27bSkettenis 		}
11883253c27bSkettenis 		msgs++;
11893253c27bSkettenis 		num--;
11903253c27bSkettenis 		ret++;
11913253c27bSkettenis 	}
11923253c27bSkettenis 
11933253c27bSkettenis 	if (num > 1) {
11943253c27bSkettenis 		cmd = msgs->buf;
11953253c27bSkettenis 		cmdlen = msgs->len;
11963253c27bSkettenis 		msgs++;
11973253c27bSkettenis 		num--;
11983253c27bSkettenis 		ret++;
11993253c27bSkettenis 	}
12003253c27bSkettenis 
1201142c034fSkettenis 	op = (msgs->flags & I2C_M_RD) ?
1202142c034fSkettenis 	    I2C_OP_READ_WITH_STOP : I2C_OP_WRITE_WITH_STOP;
1203142c034fSkettenis 	err = iic_exec(&adap->ic, op, msgs->addr, cmd, cmdlen,
1204142c034fSkettenis 	    msgs->buf, msgs->len, 0);
12053253c27bSkettenis 	if (err) {
12063253c27bSkettenis 		ret = -err;
12073253c27bSkettenis 		goto fail;
12083253c27bSkettenis 	}
12093253c27bSkettenis 	msgs++;
12103253c27bSkettenis 	ret++;
12113253c27bSkettenis 
12123253c27bSkettenis fail:
12133253c27bSkettenis 	iic_release_bus(&adap->ic, 0);
12143253c27bSkettenis 
12153253c27bSkettenis 	return ret;
12163253c27bSkettenis }
12173253c27bSkettenis 
1218142c034fSkettenis int
__i2c_transfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)121965bb161bSjsg __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1220142c034fSkettenis {
12212156c0eeSjsg 	int ret, retries;
1222142c034fSkettenis 
12232156c0eeSjsg 	retries = adap->retries;
12242156c0eeSjsg retry:
1225c349dbc7Sjsg 	if (adap->algo)
1226c349dbc7Sjsg 		ret = adap->algo->master_xfer(adap, msgs, num);
1227c349dbc7Sjsg 	else
1228c349dbc7Sjsg 		ret = i2c_master_xfer(adap, msgs, num);
12292156c0eeSjsg 	if (ret == -EAGAIN && retries > 0) {
12302156c0eeSjsg 		retries--;
12312156c0eeSjsg 		goto retry;
12322156c0eeSjsg 	}
1233c349dbc7Sjsg 
123465bb161bSjsg 	return ret;
123565bb161bSjsg }
123665bb161bSjsg 
123765bb161bSjsg int
i2c_transfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)123865bb161bSjsg i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
123965bb161bSjsg {
124065bb161bSjsg 	int ret;
124165bb161bSjsg 
124265bb161bSjsg 	if (adap->lock_ops)
124365bb161bSjsg 		adap->lock_ops->lock_bus(adap, 0);
124465bb161bSjsg 
124565bb161bSjsg 	ret = __i2c_transfer(adap, msgs, num);
124665bb161bSjsg 
1247c349dbc7Sjsg 	if (adap->lock_ops)
1248c349dbc7Sjsg 		adap->lock_ops->unlock_bus(adap, 0);
1249c349dbc7Sjsg 
1250c349dbc7Sjsg 	return ret;
1251142c034fSkettenis }
1252142c034fSkettenis 
1253142c034fSkettenis int
i2c_bb_master_xfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)1254142c034fSkettenis i2c_bb_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1255142c034fSkettenis {
1256142c034fSkettenis 	struct i2c_algo_bit_data *algo = adap->algo_data;
1257142c034fSkettenis 	struct i2c_adapter bb;
1258142c034fSkettenis 
1259142c034fSkettenis 	memset(&bb, 0, sizeof(bb));
1260142c034fSkettenis 	bb.ic = algo->ic;
1261142c034fSkettenis 	bb.retries = adap->retries;
1262142c034fSkettenis 	return i2c_master_xfer(&bb, msgs, num);
1263142c034fSkettenis }
1264142c034fSkettenis 
1265142c034fSkettenis uint32_t
i2c_bb_functionality(struct i2c_adapter * adap)1266142c034fSkettenis i2c_bb_functionality(struct i2c_adapter *adap)
1267142c034fSkettenis {
1268142c034fSkettenis 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
1269142c034fSkettenis }
1270142c034fSkettenis 
1271142c034fSkettenis struct i2c_algorithm i2c_bit_algo = {
1272142c034fSkettenis 	.master_xfer = i2c_bb_master_xfer,
1273142c034fSkettenis 	.functionality = i2c_bb_functionality
1274142c034fSkettenis };
1275142c034fSkettenis 
1276d8a2843fSjsg int
i2c_bit_add_bus(struct i2c_adapter * adap)1277d8a2843fSjsg i2c_bit_add_bus(struct i2c_adapter *adap)
1278d8a2843fSjsg {
1279d8a2843fSjsg 	adap->algo = &i2c_bit_algo;
1280d8a2843fSjsg 	adap->retries = 3;
1281d8a2843fSjsg 
1282d8a2843fSjsg 	return 0;
1283d8a2843fSjsg }
1284d8a2843fSjsg 
1285adfb93f8Skettenis #if defined(__amd64__) || defined(__i386__)
1286adfb93f8Skettenis 
1287adfb93f8Skettenis /*
1288adfb93f8Skettenis  * This is a minimal implementation of the Linux vga_get/vga_put
12895ca02815Sjsg  * interface.  In all likelihood, it will only work for inteldrm(4) as
1290adfb93f8Skettenis  * it assumes that if there is another active VGA device in the
1291adfb93f8Skettenis  * system, it is sitting behind a PCI bridge.
1292adfb93f8Skettenis  */
1293adfb93f8Skettenis 
1294adfb93f8Skettenis extern int pci_enumerate_bus(struct pci_softc *,
1295adfb93f8Skettenis     int (*)(struct pci_attach_args *), struct pci_attach_args *);
1296adfb93f8Skettenis 
1297adfb93f8Skettenis pcitag_t vga_bridge_tag;
1298adfb93f8Skettenis int vga_bridge_disabled;
1299adfb93f8Skettenis 
1300adfb93f8Skettenis int
vga_disable_bridge(struct pci_attach_args * pa)1301adfb93f8Skettenis vga_disable_bridge(struct pci_attach_args *pa)
1302adfb93f8Skettenis {
1303adfb93f8Skettenis 	pcireg_t bhlc, bc;
1304adfb93f8Skettenis 
1305adfb93f8Skettenis 	if (pa->pa_domain != 0)
1306adfb93f8Skettenis 		return 0;
1307adfb93f8Skettenis 
1308adfb93f8Skettenis 	bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
1309adfb93f8Skettenis 	if (PCI_HDRTYPE_TYPE(bhlc) != 1)
1310adfb93f8Skettenis 		return 0;
1311adfb93f8Skettenis 
1312adfb93f8Skettenis 	bc = pci_conf_read(pa->pa_pc, pa->pa_tag, PPB_REG_BRIDGECONTROL);
1313adfb93f8Skettenis 	if ((bc & PPB_BC_VGA_ENABLE) == 0)
1314adfb93f8Skettenis 		return 0;
1315adfb93f8Skettenis 	bc &= ~PPB_BC_VGA_ENABLE;
1316adfb93f8Skettenis 	pci_conf_write(pa->pa_pc, pa->pa_tag, PPB_REG_BRIDGECONTROL, bc);
1317adfb93f8Skettenis 
1318adfb93f8Skettenis 	vga_bridge_tag = pa->pa_tag;
1319adfb93f8Skettenis 	vga_bridge_disabled = 1;
1320adfb93f8Skettenis 
1321adfb93f8Skettenis 	return 1;
1322adfb93f8Skettenis }
1323adfb93f8Skettenis 
1324adfb93f8Skettenis void
vga_get_uninterruptible(struct pci_dev * pdev,int rsrc)1325adfb93f8Skettenis vga_get_uninterruptible(struct pci_dev *pdev, int rsrc)
1326adfb93f8Skettenis {
132703c13a2aSjsg 	if (pdev->pci->sc_bridgetag != NULL)
132803c13a2aSjsg 		return;
1329adfb93f8Skettenis 	pci_enumerate_bus(pdev->pci, vga_disable_bridge, NULL);
1330adfb93f8Skettenis }
1331adfb93f8Skettenis 
1332adfb93f8Skettenis void
vga_put(struct pci_dev * pdev,int rsrc)1333adfb93f8Skettenis vga_put(struct pci_dev *pdev, int rsrc)
1334adfb93f8Skettenis {
1335ec031e48Skettenis 	pcireg_t bc;
1336ec031e48Skettenis 
1337ec031e48Skettenis 	if (!vga_bridge_disabled)
1338ec031e48Skettenis 		return;
1339ec031e48Skettenis 
1340ec031e48Skettenis 	bc = pci_conf_read(pdev->pc, vga_bridge_tag, PPB_REG_BRIDGECONTROL);
1341ec031e48Skettenis 	bc |= PPB_BC_VGA_ENABLE;
1342ec031e48Skettenis 	pci_conf_write(pdev->pc, vga_bridge_tag, PPB_REG_BRIDGECONTROL, bc);
1343ec031e48Skettenis 
1344ec031e48Skettenis 	vga_bridge_disabled = 0;
1345adfb93f8Skettenis }
1346adfb93f8Skettenis 
1347adfb93f8Skettenis #endif
134827f2381eSkettenis 
134927f2381eSkettenis /*
135027f2381eSkettenis  * ACPI types and interfaces.
135127f2381eSkettenis  */
135227f2381eSkettenis 
13539943d3dfSkettenis #ifdef __HAVE_ACPI
135427f2381eSkettenis #include "acpi.h"
135527f2381eSkettenis #endif
135627f2381eSkettenis 
135727f2381eSkettenis #if NACPI > 0
135827f2381eSkettenis 
135927f2381eSkettenis #include <dev/acpi/acpireg.h>
136027f2381eSkettenis #include <dev/acpi/acpivar.h>
13616a77e6adSkettenis #include <dev/acpi/amltypes.h>
13626a77e6adSkettenis #include <dev/acpi/dsdt.h>
136327f2381eSkettenis 
136427f2381eSkettenis acpi_status
acpi_get_table(const char * sig,int instance,struct acpi_table_header ** hdr)13657f4dd379Sjsg acpi_get_table(const char *sig, int instance,
13667f4dd379Sjsg     struct acpi_table_header **hdr)
136727f2381eSkettenis {
136827f2381eSkettenis 	struct acpi_softc *sc = acpi_softc;
136927f2381eSkettenis 	struct acpi_q *entry;
137027f2381eSkettenis 
137127f2381eSkettenis 	KASSERT(instance == 1);
137227f2381eSkettenis 
13735d868007Skettenis 	if (sc == NULL)
13745d868007Skettenis 		return AE_NOT_FOUND;
13755d868007Skettenis 
137627f2381eSkettenis 	SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) {
137727f2381eSkettenis 		if (memcmp(entry->q_table, sig, strlen(sig)) == 0) {
137827f2381eSkettenis 			*hdr = entry->q_table;
137927f2381eSkettenis 			return 0;
138027f2381eSkettenis 		}
138127f2381eSkettenis 	}
138227f2381eSkettenis 
138327f2381eSkettenis 	return AE_NOT_FOUND;
138427f2381eSkettenis }
138527f2381eSkettenis 
13861bb76ff1Sjsg void
acpi_put_table(struct acpi_table_header * hdr)13871bb76ff1Sjsg acpi_put_table(struct acpi_table_header *hdr)
13881bb76ff1Sjsg {
13891bb76ff1Sjsg }
13901bb76ff1Sjsg 
13916a77e6adSkettenis acpi_status
acpi_get_handle(acpi_handle node,const char * name,acpi_handle * rnode)13926a77e6adSkettenis acpi_get_handle(acpi_handle node, const char *name, acpi_handle *rnode)
13936a77e6adSkettenis {
13946a77e6adSkettenis 	node = aml_searchname(node, name);
13956a77e6adSkettenis 	if (node == NULL)
13966a77e6adSkettenis 		return AE_NOT_FOUND;
13976a77e6adSkettenis 
13986a77e6adSkettenis 	*rnode = node;
13996a77e6adSkettenis 	return 0;
14006a77e6adSkettenis }
14016a77e6adSkettenis 
14026a77e6adSkettenis acpi_status
acpi_get_name(acpi_handle node,int type,struct acpi_buffer * buffer)14036a77e6adSkettenis acpi_get_name(acpi_handle node, int type,  struct acpi_buffer *buffer)
14046a77e6adSkettenis {
14056a77e6adSkettenis 	KASSERT(buffer->length != ACPI_ALLOCATE_BUFFER);
14066a77e6adSkettenis 	KASSERT(type == ACPI_FULL_PATHNAME);
14076a77e6adSkettenis 	strlcpy(buffer->pointer, aml_nodename(node), buffer->length);
14086a77e6adSkettenis 	return 0;
14096a77e6adSkettenis }
14106a77e6adSkettenis 
14116a77e6adSkettenis acpi_status
acpi_evaluate_object(acpi_handle node,const char * name,struct acpi_object_list * params,struct acpi_buffer * result)14126a77e6adSkettenis acpi_evaluate_object(acpi_handle node, const char *name,
14136a77e6adSkettenis     struct acpi_object_list *params, struct acpi_buffer *result)
14146a77e6adSkettenis {
14156a77e6adSkettenis 	struct aml_value args[4], res;
14166a77e6adSkettenis 	union acpi_object *obj;
14176a77e6adSkettenis 	uint8_t *data;
14186a77e6adSkettenis 	int i;
14196a77e6adSkettenis 
14206a77e6adSkettenis 	KASSERT(params->count <= nitems(args));
14216a77e6adSkettenis 
14226a77e6adSkettenis 	for (i = 0; i < params->count; i++) {
14236a77e6adSkettenis 		args[i].type = params->pointer[i].type;
14246a77e6adSkettenis 		switch (args[i].type) {
14256a77e6adSkettenis 		case AML_OBJTYPE_INTEGER:
14266a77e6adSkettenis 			args[i].v_integer = params->pointer[i].integer.value;
14276a77e6adSkettenis 			break;
14286a77e6adSkettenis 		case AML_OBJTYPE_BUFFER:
14296a77e6adSkettenis 			args[i].length = params->pointer[i].buffer.length;
14306a77e6adSkettenis 			args[i].v_buffer = params->pointer[i].buffer.pointer;
14316a77e6adSkettenis 			break;
14326a77e6adSkettenis 		default:
14336a77e6adSkettenis 			printf("%s: arg type 0x%02x", __func__, args[i].type);
14346a77e6adSkettenis 			return AE_BAD_PARAMETER;
14356a77e6adSkettenis 		}
14366a77e6adSkettenis 	}
14376a77e6adSkettenis 
14386a77e6adSkettenis 	if (name) {
14396a77e6adSkettenis 		node = aml_searchname(node, name);
14406a77e6adSkettenis 		if (node == NULL)
14416a77e6adSkettenis 			return AE_NOT_FOUND;
14426a77e6adSkettenis 	}
14436a77e6adSkettenis 	if (aml_evalnode(acpi_softc, node, params->count, args, &res)) {
14446a77e6adSkettenis 		aml_freevalue(&res);
14456a77e6adSkettenis 		return AE_ERROR;
14466a77e6adSkettenis 	}
14476a77e6adSkettenis 
14486a77e6adSkettenis 	KASSERT(result->length == ACPI_ALLOCATE_BUFFER);
14496a77e6adSkettenis 
14506a77e6adSkettenis 	result->length = sizeof(union acpi_object);
14516a77e6adSkettenis 	switch (res.type) {
14526a77e6adSkettenis 	case AML_OBJTYPE_BUFFER:
14536a77e6adSkettenis 		result->length += res.length;
14546a77e6adSkettenis 		result->pointer = malloc(result->length, M_DRM, M_WAITOK);
14556a77e6adSkettenis 		obj = (union acpi_object *)result->pointer;
14566a77e6adSkettenis 		data = (uint8_t *)(obj + 1);
14576a77e6adSkettenis 		obj->type = res.type;
14586a77e6adSkettenis 		obj->buffer.length = res.length;
14596a77e6adSkettenis 		obj->buffer.pointer = data;
14606a77e6adSkettenis 		memcpy(data, res.v_buffer, res.length);
14616a77e6adSkettenis 		break;
14626a77e6adSkettenis 	default:
14636a77e6adSkettenis 		printf("%s: return type 0x%02x", __func__, res.type);
14646a77e6adSkettenis 		aml_freevalue(&res);
14656a77e6adSkettenis 		return AE_ERROR;
14666a77e6adSkettenis 	}
14676a77e6adSkettenis 
14686a77e6adSkettenis 	aml_freevalue(&res);
14696a77e6adSkettenis 	return 0;
14706a77e6adSkettenis }
14716a77e6adSkettenis 
14726a77e6adSkettenis SLIST_HEAD(, notifier_block) drm_linux_acpi_notify_list =
14736a77e6adSkettenis 	SLIST_HEAD_INITIALIZER(drm_linux_acpi_notify_list);
14746a77e6adSkettenis 
14756a77e6adSkettenis int
drm_linux_acpi_notify(struct aml_node * node,int notify,void * arg)14766a77e6adSkettenis drm_linux_acpi_notify(struct aml_node *node, int notify, void *arg)
14776a77e6adSkettenis {
14786a77e6adSkettenis 	struct acpi_bus_event event;
14796a77e6adSkettenis 	struct notifier_block *nb;
14806a77e6adSkettenis 
14816a77e6adSkettenis 	event.device_class = ACPI_VIDEO_CLASS;
14826a77e6adSkettenis 	event.type = notify;
14836a77e6adSkettenis 
14846a77e6adSkettenis 	SLIST_FOREACH(nb, &drm_linux_acpi_notify_list, link)
14856a77e6adSkettenis 		nb->notifier_call(nb, 0, &event);
14866a77e6adSkettenis 	return 0;
14876a77e6adSkettenis }
14886a77e6adSkettenis 
14896a77e6adSkettenis int
register_acpi_notifier(struct notifier_block * nb)14906a77e6adSkettenis register_acpi_notifier(struct notifier_block *nb)
14916a77e6adSkettenis {
14926a77e6adSkettenis 	SLIST_INSERT_HEAD(&drm_linux_acpi_notify_list, nb, link);
14936a77e6adSkettenis 	return 0;
14946a77e6adSkettenis }
14956a77e6adSkettenis 
14966a77e6adSkettenis int
unregister_acpi_notifier(struct notifier_block * nb)14976a77e6adSkettenis unregister_acpi_notifier(struct notifier_block *nb)
14986a77e6adSkettenis {
14994d3f7975Skettenis 	struct notifier_block *tmp;
15004d3f7975Skettenis 
15014d3f7975Skettenis 	SLIST_FOREACH(tmp, &drm_linux_acpi_notify_list, link) {
15024d3f7975Skettenis 		if (tmp == nb) {
15034d3f7975Skettenis 			SLIST_REMOVE(&drm_linux_acpi_notify_list, nb,
15044d3f7975Skettenis 			    notifier_block, link);
15056a77e6adSkettenis 			return 0;
15066a77e6adSkettenis 		}
15074d3f7975Skettenis 	}
15084d3f7975Skettenis 
15094d3f7975Skettenis 	return -ENOENT;
15104d3f7975Skettenis }
15116a77e6adSkettenis 
15126a77e6adSkettenis const char *
acpi_format_exception(acpi_status status)15136a77e6adSkettenis acpi_format_exception(acpi_status status)
15146a77e6adSkettenis {
15156a77e6adSkettenis 	switch (status) {
15166a77e6adSkettenis 	case AE_NOT_FOUND:
15176a77e6adSkettenis 		return "not found";
15186a77e6adSkettenis 	case AE_BAD_PARAMETER:
15196a77e6adSkettenis 		return "bad parameter";
15206a77e6adSkettenis 	default:
15216a77e6adSkettenis 		return "unknown";
15226a77e6adSkettenis 	}
15236a77e6adSkettenis }
15246a77e6adSkettenis 
152527f2381eSkettenis #endif
1526e12511f5Skettenis 
15279342ba5eSkettenis SLIST_HEAD(,backlight_device) backlight_device_list =
15289342ba5eSkettenis     SLIST_HEAD_INITIALIZER(backlight_device_list);
15299342ba5eSkettenis 
1530f88c7015Skettenis void
backlight_do_update_status(void * arg)1531f88c7015Skettenis backlight_do_update_status(void *arg)
1532f88c7015Skettenis {
1533f88c7015Skettenis 	backlight_update_status(arg);
1534f88c7015Skettenis }
1535f88c7015Skettenis 
1536e12511f5Skettenis struct backlight_device *
backlight_device_register(const char * name,void * kdev,void * data,const struct backlight_ops * ops,const struct backlight_properties * props)1537e12511f5Skettenis backlight_device_register(const char *name, void *kdev, void *data,
15389342ba5eSkettenis     const struct backlight_ops *ops, const struct backlight_properties *props)
1539e12511f5Skettenis {
1540e12511f5Skettenis 	struct backlight_device *bd;
1541e12511f5Skettenis 
1542e12511f5Skettenis 	bd = malloc(sizeof(*bd), M_DRM, M_WAITOK);
1543e12511f5Skettenis 	bd->ops = ops;
1544e12511f5Skettenis 	bd->props = *props;
1545e12511f5Skettenis 	bd->data = data;
1546e12511f5Skettenis 
1547f88c7015Skettenis 	task_set(&bd->task, backlight_do_update_status, bd);
1548f88c7015Skettenis 
15499342ba5eSkettenis 	SLIST_INSERT_HEAD(&backlight_device_list, bd, next);
15509342ba5eSkettenis 	bd->name = name;
15519342ba5eSkettenis 
1552e12511f5Skettenis 	return bd;
1553e12511f5Skettenis }
1554e12511f5Skettenis 
1555e12511f5Skettenis void
backlight_device_unregister(struct backlight_device * bd)1556e12511f5Skettenis backlight_device_unregister(struct backlight_device *bd)
1557e12511f5Skettenis {
15589342ba5eSkettenis 	SLIST_REMOVE(&backlight_device_list, bd, backlight_device, next);
1559e12511f5Skettenis 	free(bd, M_DRM, sizeof(*bd));
1560e12511f5Skettenis }
1561f88c7015Skettenis 
1562f88c7015Skettenis void
backlight_schedule_update_status(struct backlight_device * bd)1563f88c7015Skettenis backlight_schedule_update_status(struct backlight_device *bd)
1564f88c7015Skettenis {
1565f88c7015Skettenis 	task_add(systq, &bd->task);
1566f88c7015Skettenis }
1567b8584f42Srobert 
15689342ba5eSkettenis int
backlight_enable(struct backlight_device * bd)1569c349dbc7Sjsg backlight_enable(struct backlight_device *bd)
1570c349dbc7Sjsg {
1571c349dbc7Sjsg 	if (bd == NULL)
1572c349dbc7Sjsg 		return 0;
1573c349dbc7Sjsg 
1574c349dbc7Sjsg 	bd->props.power = FB_BLANK_UNBLANK;
1575c349dbc7Sjsg 
1576c349dbc7Sjsg 	return bd->ops->update_status(bd);
1577c349dbc7Sjsg }
1578c349dbc7Sjsg 
15799342ba5eSkettenis int
backlight_disable(struct backlight_device * bd)1580c349dbc7Sjsg backlight_disable(struct backlight_device *bd)
1581c349dbc7Sjsg {
1582c349dbc7Sjsg 	if (bd == NULL)
1583c349dbc7Sjsg 		return 0;
1584c349dbc7Sjsg 
1585c349dbc7Sjsg 	bd->props.power = FB_BLANK_POWERDOWN;
1586c349dbc7Sjsg 
1587c349dbc7Sjsg 	return bd->ops->update_status(bd);
1588c349dbc7Sjsg }
1589c349dbc7Sjsg 
15909342ba5eSkettenis struct backlight_device *
backlight_device_get_by_name(const char * name)15919342ba5eSkettenis backlight_device_get_by_name(const char *name)
15929342ba5eSkettenis {
15939342ba5eSkettenis 	struct backlight_device *bd;
15949342ba5eSkettenis 
15959342ba5eSkettenis 	SLIST_FOREACH(bd, &backlight_device_list, next) {
15969342ba5eSkettenis 		if (strcmp(name, bd->name) == 0)
15979342ba5eSkettenis 			return bd;
15989342ba5eSkettenis 	}
15999342ba5eSkettenis 
16009342ba5eSkettenis 	return NULL;
16019342ba5eSkettenis }
16029342ba5eSkettenis 
16039342ba5eSkettenis struct drvdata {
16049342ba5eSkettenis 	struct device *dev;
16059342ba5eSkettenis 	void *data;
16069342ba5eSkettenis 	SLIST_ENTRY(drvdata) next;
16079342ba5eSkettenis };
16089342ba5eSkettenis 
16099342ba5eSkettenis SLIST_HEAD(,drvdata) drvdata_list = SLIST_HEAD_INITIALIZER(drvdata_list);
16109342ba5eSkettenis 
16119342ba5eSkettenis void
dev_set_drvdata(struct device * dev,void * data)16129342ba5eSkettenis dev_set_drvdata(struct device *dev, void *data)
16139342ba5eSkettenis {
16149342ba5eSkettenis 	struct drvdata *drvdata;
16159342ba5eSkettenis 
16169342ba5eSkettenis 	SLIST_FOREACH(drvdata, &drvdata_list, next) {
16179342ba5eSkettenis 		if (drvdata->dev == dev) {
16189342ba5eSkettenis 			drvdata->data = data;
16199342ba5eSkettenis 			return;
16209342ba5eSkettenis 		}
16219342ba5eSkettenis 	}
16229342ba5eSkettenis 
16239342ba5eSkettenis 	if (data == NULL)
16249342ba5eSkettenis 		return;
16259342ba5eSkettenis 
16269342ba5eSkettenis 	drvdata = malloc(sizeof(*drvdata), M_DRM, M_WAITOK);
16279342ba5eSkettenis 	drvdata->dev = dev;
16289342ba5eSkettenis 	drvdata->data = data;
16299342ba5eSkettenis 
16309342ba5eSkettenis 	SLIST_INSERT_HEAD(&drvdata_list, drvdata, next);
16319342ba5eSkettenis }
16329342ba5eSkettenis 
16339342ba5eSkettenis void *
dev_get_drvdata(struct device * dev)16349342ba5eSkettenis dev_get_drvdata(struct device *dev)
16359342ba5eSkettenis {
16369342ba5eSkettenis 	struct drvdata *drvdata;
16379342ba5eSkettenis 
16389342ba5eSkettenis 	SLIST_FOREACH(drvdata, &drvdata_list, next) {
16399342ba5eSkettenis 		if (drvdata->dev == dev)
16409342ba5eSkettenis 			return drvdata->data;
16419342ba5eSkettenis 	}
16429342ba5eSkettenis 
16439342ba5eSkettenis 	return NULL;
16449342ba5eSkettenis }
16459342ba5eSkettenis 
1646b8584f42Srobert void
drm_sysfs_hotplug_event(struct drm_device * dev)1647b8584f42Srobert drm_sysfs_hotplug_event(struct drm_device *dev)
1648b8584f42Srobert {
1649c78098b6Svisa 	knote_locked(&dev->note, NOTE_CHANGE);
1650b8584f42Srobert }
16517ccd5a2cSjsg 
16521bb76ff1Sjsg void
drm_sysfs_connector_hotplug_event(struct drm_connector * connector)16531bb76ff1Sjsg drm_sysfs_connector_hotplug_event(struct drm_connector *connector)
16541bb76ff1Sjsg {
1655c78098b6Svisa 	knote_locked(&connector->dev->note, NOTE_CHANGE);
16561bb76ff1Sjsg }
16571bb76ff1Sjsg 
16581bb76ff1Sjsg void
drm_sysfs_connector_status_event(struct drm_connector * connector,struct drm_property * property)16591bb76ff1Sjsg drm_sysfs_connector_status_event(struct drm_connector *connector,
16601bb76ff1Sjsg     struct drm_property *property)
16611bb76ff1Sjsg {
16621bb76ff1Sjsg 	STUB();
16631bb76ff1Sjsg }
16641bb76ff1Sjsg 
1665f005ef32Sjsg void
drm_sysfs_connector_property_event(struct drm_connector * connector,struct drm_property * property)1666f005ef32Sjsg drm_sysfs_connector_property_event(struct drm_connector *connector,
1667f005ef32Sjsg     struct drm_property *property)
1668f005ef32Sjsg {
1669f005ef32Sjsg 	STUB();
1670f005ef32Sjsg }
1671f005ef32Sjsg 
1672ad8b1aafSjsg struct dma_fence *
dma_fence_get(struct dma_fence * fence)1673ad8b1aafSjsg dma_fence_get(struct dma_fence *fence)
1674ad8b1aafSjsg {
1675ad8b1aafSjsg 	if (fence)
1676ad8b1aafSjsg 		kref_get(&fence->refcount);
1677ad8b1aafSjsg 	return fence;
1678ad8b1aafSjsg }
1679ad8b1aafSjsg 
1680ad8b1aafSjsg struct dma_fence *
dma_fence_get_rcu(struct dma_fence * fence)1681ad8b1aafSjsg dma_fence_get_rcu(struct dma_fence *fence)
1682ad8b1aafSjsg {
1683ad8b1aafSjsg 	if (fence)
1684ad8b1aafSjsg 		kref_get(&fence->refcount);
1685ad8b1aafSjsg 	return fence;
1686ad8b1aafSjsg }
1687ad8b1aafSjsg 
1688ad8b1aafSjsg struct dma_fence *
dma_fence_get_rcu_safe(struct dma_fence ** dfp)1689ad8b1aafSjsg dma_fence_get_rcu_safe(struct dma_fence **dfp)
1690ad8b1aafSjsg {
1691ad8b1aafSjsg 	struct dma_fence *fence;
1692ad8b1aafSjsg 	if (dfp == NULL)
1693ad8b1aafSjsg 		return NULL;
1694ad8b1aafSjsg 	fence = *dfp;
1695ad8b1aafSjsg 	if (fence)
1696ad8b1aafSjsg 		kref_get(&fence->refcount);
1697ad8b1aafSjsg 	return fence;
1698ad8b1aafSjsg }
1699ad8b1aafSjsg 
1700ad8b1aafSjsg void
dma_fence_release(struct kref * ref)1701ad8b1aafSjsg dma_fence_release(struct kref *ref)
1702ad8b1aafSjsg {
1703ad8b1aafSjsg 	struct dma_fence *fence = container_of(ref, struct dma_fence, refcount);
1704ad8b1aafSjsg 	if (fence->ops && fence->ops->release)
1705ad8b1aafSjsg 		fence->ops->release(fence);
1706ad8b1aafSjsg 	else
1707ad8b1aafSjsg 		free(fence, M_DRM, 0);
1708ad8b1aafSjsg }
1709ad8b1aafSjsg 
1710ad8b1aafSjsg void
dma_fence_put(struct dma_fence * fence)1711ad8b1aafSjsg dma_fence_put(struct dma_fence *fence)
1712ad8b1aafSjsg {
1713ad8b1aafSjsg 	if (fence)
1714ad8b1aafSjsg 		kref_put(&fence->refcount, dma_fence_release);
1715ad8b1aafSjsg }
1716ad8b1aafSjsg 
1717ad8b1aafSjsg int
dma_fence_signal_timestamp_locked(struct dma_fence * fence,ktime_t timestamp)17185ca02815Sjsg dma_fence_signal_timestamp_locked(struct dma_fence *fence, ktime_t timestamp)
1719ad8b1aafSjsg {
1720ad8b1aafSjsg 	struct dma_fence_cb *cur, *tmp;
1721ad8b1aafSjsg 	struct list_head cb_list;
1722ad8b1aafSjsg 
1723ad8b1aafSjsg 	if (fence == NULL)
1724ad8b1aafSjsg 		return -EINVAL;
1725ad8b1aafSjsg 
1726ad8b1aafSjsg 	if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1727ad8b1aafSjsg 		return -EINVAL;
1728ad8b1aafSjsg 
1729ad8b1aafSjsg 	list_replace(&fence->cb_list, &cb_list);
1730ad8b1aafSjsg 
17315ca02815Sjsg 	fence->timestamp = timestamp;
1732ad8b1aafSjsg 	set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
1733ad8b1aafSjsg 
1734ad8b1aafSjsg 	list_for_each_entry_safe(cur, tmp, &cb_list, node) {
1735ad8b1aafSjsg 		INIT_LIST_HEAD(&cur->node);
1736ad8b1aafSjsg 		cur->func(fence, cur);
1737ad8b1aafSjsg 	}
1738ad8b1aafSjsg 
1739ad8b1aafSjsg 	return 0;
1740ad8b1aafSjsg }
1741ad8b1aafSjsg 
1742ad8b1aafSjsg int
dma_fence_signal(struct dma_fence * fence)1743ad8b1aafSjsg dma_fence_signal(struct dma_fence *fence)
1744ad8b1aafSjsg {
1745ad8b1aafSjsg 	int r;
1746ad8b1aafSjsg 
1747ad8b1aafSjsg 	if (fence == NULL)
1748ad8b1aafSjsg 		return -EINVAL;
1749ad8b1aafSjsg 
1750ad8b1aafSjsg 	mtx_enter(fence->lock);
17515ca02815Sjsg 	r = dma_fence_signal_timestamp_locked(fence, ktime_get());
17525ca02815Sjsg 	mtx_leave(fence->lock);
17535ca02815Sjsg 
17545ca02815Sjsg 	return r;
17555ca02815Sjsg }
17565ca02815Sjsg 
17575ca02815Sjsg int
dma_fence_signal_locked(struct dma_fence * fence)17585ca02815Sjsg dma_fence_signal_locked(struct dma_fence *fence)
17595ca02815Sjsg {
17605ca02815Sjsg 	if (fence == NULL)
17615ca02815Sjsg 		return -EINVAL;
17625ca02815Sjsg 
17635ca02815Sjsg 	return dma_fence_signal_timestamp_locked(fence, ktime_get());
17645ca02815Sjsg }
17655ca02815Sjsg 
17665ca02815Sjsg int
dma_fence_signal_timestamp(struct dma_fence * fence,ktime_t timestamp)17675ca02815Sjsg dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp)
17685ca02815Sjsg {
17695ca02815Sjsg 	int r;
17705ca02815Sjsg 
17715ca02815Sjsg 	if (fence == NULL)
17725ca02815Sjsg 		return -EINVAL;
17735ca02815Sjsg 
17745ca02815Sjsg 	mtx_enter(fence->lock);
17755ca02815Sjsg 	r = dma_fence_signal_timestamp_locked(fence, timestamp);
1776ad8b1aafSjsg 	mtx_leave(fence->lock);
1777ad8b1aafSjsg 
1778ad8b1aafSjsg 	return r;
1779ad8b1aafSjsg }
1780ad8b1aafSjsg 
1781ad8b1aafSjsg bool
dma_fence_is_signaled(struct dma_fence * fence)1782ad8b1aafSjsg dma_fence_is_signaled(struct dma_fence *fence)
1783ad8b1aafSjsg {
1784ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1785ad8b1aafSjsg 		return true;
1786ad8b1aafSjsg 
1787ad8b1aafSjsg 	if (fence->ops->signaled && fence->ops->signaled(fence)) {
1788ad8b1aafSjsg 		dma_fence_signal(fence);
1789ad8b1aafSjsg 		return true;
1790ad8b1aafSjsg 	}
1791ad8b1aafSjsg 
1792ad8b1aafSjsg 	return false;
1793ad8b1aafSjsg }
1794ad8b1aafSjsg 
1795ad8b1aafSjsg bool
dma_fence_is_signaled_locked(struct dma_fence * fence)1796ad8b1aafSjsg dma_fence_is_signaled_locked(struct dma_fence *fence)
1797ad8b1aafSjsg {
1798ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1799ad8b1aafSjsg 		return true;
1800ad8b1aafSjsg 
1801ad8b1aafSjsg 	if (fence->ops->signaled && fence->ops->signaled(fence)) {
1802ad8b1aafSjsg 		dma_fence_signal_locked(fence);
1803ad8b1aafSjsg 		return true;
1804ad8b1aafSjsg 	}
1805ad8b1aafSjsg 
1806ad8b1aafSjsg 	return false;
1807ad8b1aafSjsg }
1808ad8b1aafSjsg 
18095158102cSjsg ktime_t
dma_fence_timestamp(struct dma_fence * fence)18105158102cSjsg dma_fence_timestamp(struct dma_fence *fence)
18115158102cSjsg {
18125158102cSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
18135158102cSjsg 		while (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
18145158102cSjsg 			CPU_BUSY_CYCLE();
18155158102cSjsg 		return fence->timestamp;
18165158102cSjsg 	} else {
18175158102cSjsg 		return ktime_get();
18185158102cSjsg 	}
18195158102cSjsg }
18205158102cSjsg 
1821ad8b1aafSjsg long
dma_fence_wait_timeout(struct dma_fence * fence,bool intr,long timeout)1822ad8b1aafSjsg dma_fence_wait_timeout(struct dma_fence *fence, bool intr, long timeout)
1823ad8b1aafSjsg {
1824ad8b1aafSjsg 	if (timeout < 0)
1825ad8b1aafSjsg 		return -EINVAL;
1826ad8b1aafSjsg 
1827ad8b1aafSjsg 	if (fence->ops->wait)
1828ad8b1aafSjsg 		return fence->ops->wait(fence, intr, timeout);
1829ad8b1aafSjsg 	else
1830ad8b1aafSjsg 		return dma_fence_default_wait(fence, intr, timeout);
1831ad8b1aafSjsg }
1832ad8b1aafSjsg 
1833ad8b1aafSjsg long
dma_fence_wait(struct dma_fence * fence,bool intr)1834ad8b1aafSjsg dma_fence_wait(struct dma_fence *fence, bool intr)
1835ad8b1aafSjsg {
1836ad8b1aafSjsg 	long ret;
1837ad8b1aafSjsg 
1838ad8b1aafSjsg 	ret = dma_fence_wait_timeout(fence, intr, MAX_SCHEDULE_TIMEOUT);
1839ad8b1aafSjsg 	if (ret < 0)
1840ad8b1aafSjsg 		return ret;
1841ad8b1aafSjsg 
1842ad8b1aafSjsg 	return 0;
1843ad8b1aafSjsg }
1844ad8b1aafSjsg 
1845ad8b1aafSjsg void
dma_fence_enable_sw_signaling(struct dma_fence * fence)1846ad8b1aafSjsg dma_fence_enable_sw_signaling(struct dma_fence *fence)
1847ad8b1aafSjsg {
1848ad8b1aafSjsg 	if (!test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags) &&
1849ad8b1aafSjsg 	    !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
1850ad8b1aafSjsg 	    fence->ops->enable_signaling) {
1851ad8b1aafSjsg 		mtx_enter(fence->lock);
1852ad8b1aafSjsg 		if (!fence->ops->enable_signaling(fence))
1853ad8b1aafSjsg 			dma_fence_signal_locked(fence);
1854ad8b1aafSjsg 		mtx_leave(fence->lock);
1855ad8b1aafSjsg 	}
1856ad8b1aafSjsg }
1857ad8b1aafSjsg 
1858ad8b1aafSjsg void
dma_fence_init(struct dma_fence * fence,const struct dma_fence_ops * ops,struct mutex * lock,uint64_t context,uint64_t seqno)1859ad8b1aafSjsg dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
1860ad8b1aafSjsg     struct mutex *lock, uint64_t context, uint64_t seqno)
1861ad8b1aafSjsg {
1862ad8b1aafSjsg 	fence->ops = ops;
1863ad8b1aafSjsg 	fence->lock = lock;
1864ad8b1aafSjsg 	fence->context = context;
1865ad8b1aafSjsg 	fence->seqno = seqno;
1866ad8b1aafSjsg 	fence->flags = 0;
1867ad8b1aafSjsg 	fence->error = 0;
1868ad8b1aafSjsg 	kref_init(&fence->refcount);
1869ad8b1aafSjsg 	INIT_LIST_HEAD(&fence->cb_list);
1870ad8b1aafSjsg }
1871ad8b1aafSjsg 
1872ad8b1aafSjsg int
dma_fence_add_callback(struct dma_fence * fence,struct dma_fence_cb * cb,dma_fence_func_t func)1873ad8b1aafSjsg dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
1874ad8b1aafSjsg     dma_fence_func_t func)
1875ad8b1aafSjsg {
1876ad8b1aafSjsg 	int ret = 0;
1877ad8b1aafSjsg 	bool was_set;
1878ad8b1aafSjsg 
1879ad8b1aafSjsg 	if (WARN_ON(!fence || !func))
1880ad8b1aafSjsg 		return -EINVAL;
1881ad8b1aafSjsg 
1882ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
1883ad8b1aafSjsg 		INIT_LIST_HEAD(&cb->node);
1884ad8b1aafSjsg 		return -ENOENT;
1885ad8b1aafSjsg 	}
1886ad8b1aafSjsg 
1887ad8b1aafSjsg 	mtx_enter(fence->lock);
1888ad8b1aafSjsg 
1889ad8b1aafSjsg 	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags);
1890ad8b1aafSjsg 
1891ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1892ad8b1aafSjsg 		ret = -ENOENT;
1893ad8b1aafSjsg 	else if (!was_set && fence->ops->enable_signaling) {
1894ad8b1aafSjsg 		if (!fence->ops->enable_signaling(fence)) {
1895ad8b1aafSjsg 			dma_fence_signal_locked(fence);
1896ad8b1aafSjsg 			ret = -ENOENT;
1897ad8b1aafSjsg 		}
1898ad8b1aafSjsg 	}
1899ad8b1aafSjsg 
1900ad8b1aafSjsg 	if (!ret) {
1901ad8b1aafSjsg 		cb->func = func;
1902ad8b1aafSjsg 		list_add_tail(&cb->node, &fence->cb_list);
1903ad8b1aafSjsg 	} else
1904ad8b1aafSjsg 		INIT_LIST_HEAD(&cb->node);
1905ad8b1aafSjsg 	mtx_leave(fence->lock);
1906ad8b1aafSjsg 
1907ad8b1aafSjsg 	return ret;
1908ad8b1aafSjsg }
1909ad8b1aafSjsg 
1910ad8b1aafSjsg bool
dma_fence_remove_callback(struct dma_fence * fence,struct dma_fence_cb * cb)1911ad8b1aafSjsg dma_fence_remove_callback(struct dma_fence *fence, struct dma_fence_cb *cb)
1912ad8b1aafSjsg {
1913ad8b1aafSjsg 	bool ret;
1914ad8b1aafSjsg 
1915ad8b1aafSjsg 	mtx_enter(fence->lock);
1916ad8b1aafSjsg 
1917ad8b1aafSjsg 	ret = !list_empty(&cb->node);
1918ad8b1aafSjsg 	if (ret)
1919ad8b1aafSjsg 		list_del_init(&cb->node);
1920ad8b1aafSjsg 
1921ad8b1aafSjsg 	mtx_leave(fence->lock);
1922ad8b1aafSjsg 
1923ad8b1aafSjsg 	return ret;
1924ad8b1aafSjsg }
1925ad8b1aafSjsg 
1926c349dbc7Sjsg static atomic64_t drm_fence_context_count = ATOMIC64_INIT(1);
19277ccd5a2cSjsg 
1928c349dbc7Sjsg uint64_t
dma_fence_context_alloc(unsigned int num)19297f4dd379Sjsg dma_fence_context_alloc(unsigned int num)
19307ccd5a2cSjsg {
1931c349dbc7Sjsg   return atomic64_add_return(num, &drm_fence_context_count) - num;
19327ccd5a2cSjsg }
1933a9ee023bSkettenis 
1934537ee4c6Sjsg struct default_wait_cb {
1935537ee4c6Sjsg 	struct dma_fence_cb base;
1936537ee4c6Sjsg 	struct proc *proc;
1937537ee4c6Sjsg };
1938537ee4c6Sjsg 
193913e5339cSjsg static void
dma_fence_default_wait_cb(struct dma_fence * fence,struct dma_fence_cb * cb)194013e5339cSjsg dma_fence_default_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
194113e5339cSjsg {
1942537ee4c6Sjsg 	struct default_wait_cb *wait =
1943537ee4c6Sjsg 	    container_of(cb, struct default_wait_cb, base);
194456a2da50Sjsg 	wake_up_process(wait->proc);
194513e5339cSjsg }
194613e5339cSjsg 
194713e5339cSjsg long
dma_fence_default_wait(struct dma_fence * fence,bool intr,signed long timeout)194813e5339cSjsg dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
194913e5339cSjsg {
195013e5339cSjsg 	long ret = timeout ? timeout : 1;
195119fc7f4fSjsg 	unsigned long end;
195213e5339cSjsg 	int err;
1953537ee4c6Sjsg 	struct default_wait_cb cb;
195413e5339cSjsg 	bool was_set;
195513e5339cSjsg 
195619fc7f4fSjsg 	KASSERT(timeout <= INT_MAX);
195719fc7f4fSjsg 
195813e5339cSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
195913e5339cSjsg 		return ret;
196013e5339cSjsg 
196113e5339cSjsg 	mtx_enter(fence->lock);
196213e5339cSjsg 
196313e5339cSjsg 	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
196413e5339cSjsg 	    &fence->flags);
196513e5339cSjsg 
196613e5339cSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
196713e5339cSjsg 		goto out;
196813e5339cSjsg 
196913e5339cSjsg 	if (!was_set && fence->ops->enable_signaling) {
197013e5339cSjsg 		if (!fence->ops->enable_signaling(fence)) {
197113e5339cSjsg 			dma_fence_signal_locked(fence);
197213e5339cSjsg 			goto out;
197313e5339cSjsg 		}
197413e5339cSjsg 	}
197513e5339cSjsg 
197613e5339cSjsg 	if (timeout == 0) {
197713e5339cSjsg 		ret = 0;
197813e5339cSjsg 		goto out;
197913e5339cSjsg 	}
198013e5339cSjsg 
1981537ee4c6Sjsg 	cb.base.func = dma_fence_default_wait_cb;
1982537ee4c6Sjsg 	cb.proc = curproc;
1983537ee4c6Sjsg 	list_add(&cb.base.node, &fence->cb_list);
198413e5339cSjsg 
198519fc7f4fSjsg 	end = jiffies + timeout;
198619fc7f4fSjsg 	for (ret = timeout; ret > 0; ret = MAX(0, end - jiffies)) {
198719fc7f4fSjsg 		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
198819fc7f4fSjsg 			break;
198919fc7f4fSjsg 		err = msleep(curproc, fence->lock, intr ? PCATCH : 0,
199019fc7f4fSjsg 		    "dmafence", ret);
199113e5339cSjsg 		if (err == EINTR || err == ERESTART) {
199213e5339cSjsg 			ret = -ERESTARTSYS;
199313e5339cSjsg 			break;
199413e5339cSjsg 		}
199513e5339cSjsg 	}
199613e5339cSjsg 
1997537ee4c6Sjsg 	if (!list_empty(&cb.base.node))
1998537ee4c6Sjsg 		list_del(&cb.base.node);
199913e5339cSjsg out:
200013e5339cSjsg 	mtx_leave(fence->lock);
200113e5339cSjsg 
200213e5339cSjsg 	return ret;
200313e5339cSjsg }
200413e5339cSjsg 
2005537ee4c6Sjsg static bool
dma_fence_test_signaled_any(struct dma_fence ** fences,uint32_t count,uint32_t * idx)2006537ee4c6Sjsg dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count,
2007537ee4c6Sjsg     uint32_t *idx)
2008537ee4c6Sjsg {
2009537ee4c6Sjsg 	int i;
2010537ee4c6Sjsg 
2011537ee4c6Sjsg 	for (i = 0; i < count; ++i) {
2012537ee4c6Sjsg 		struct dma_fence *fence = fences[i];
2013537ee4c6Sjsg 		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
2014537ee4c6Sjsg 			if (idx)
2015537ee4c6Sjsg 				*idx = i;
2016537ee4c6Sjsg 			return true;
2017537ee4c6Sjsg 		}
2018537ee4c6Sjsg 	}
2019537ee4c6Sjsg 	return false;
2020537ee4c6Sjsg }
2021537ee4c6Sjsg 
2022537ee4c6Sjsg long
dma_fence_wait_any_timeout(struct dma_fence ** fences,uint32_t count,bool intr,long timeout,uint32_t * idx)2023537ee4c6Sjsg dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count,
2024537ee4c6Sjsg     bool intr, long timeout, uint32_t *idx)
2025537ee4c6Sjsg {
2026537ee4c6Sjsg 	struct default_wait_cb *cb;
202719fc7f4fSjsg 	long ret = timeout;
202819fc7f4fSjsg 	unsigned long end;
2029537ee4c6Sjsg 	int i, err;
203019fc7f4fSjsg 
203119fc7f4fSjsg 	KASSERT(timeout <= INT_MAX);
2032537ee4c6Sjsg 
2033537ee4c6Sjsg 	if (timeout == 0) {
2034537ee4c6Sjsg 		for (i = 0; i < count; i++) {
2035537ee4c6Sjsg 			if (dma_fence_is_signaled(fences[i])) {
2036537ee4c6Sjsg 				if (idx)
2037537ee4c6Sjsg 					*idx = i;
2038537ee4c6Sjsg 				return 1;
2039537ee4c6Sjsg 			}
2040537ee4c6Sjsg 		}
2041537ee4c6Sjsg 		return 0;
2042537ee4c6Sjsg 	}
2043537ee4c6Sjsg 
2044537ee4c6Sjsg 	cb = mallocarray(count, sizeof(*cb), M_DRM, M_WAITOK|M_CANFAIL|M_ZERO);
2045537ee4c6Sjsg 	if (cb == NULL)
2046537ee4c6Sjsg 		return -ENOMEM;
2047537ee4c6Sjsg 
2048537ee4c6Sjsg 	for (i = 0; i < count; i++) {
2049537ee4c6Sjsg 		struct dma_fence *fence = fences[i];
2050537ee4c6Sjsg 		cb[i].proc = curproc;
2051537ee4c6Sjsg 		if (dma_fence_add_callback(fence, &cb[i].base,
2052537ee4c6Sjsg 		    dma_fence_default_wait_cb)) {
2053537ee4c6Sjsg 			if (idx)
2054537ee4c6Sjsg 				*idx = i;
2055537ee4c6Sjsg 			goto cb_cleanup;
2056537ee4c6Sjsg 		}
2057537ee4c6Sjsg 	}
2058537ee4c6Sjsg 
205919fc7f4fSjsg 	end = jiffies + timeout;
206019fc7f4fSjsg 	for (ret = timeout; ret > 0; ret = MAX(0, end - jiffies)) {
2061537ee4c6Sjsg 		if (dma_fence_test_signaled_any(fences, count, idx))
2062537ee4c6Sjsg 			break;
206319fc7f4fSjsg 		err = tsleep(curproc, intr ? PCATCH : 0, "dfwat", ret);
2064537ee4c6Sjsg 		if (err == EINTR || err == ERESTART) {
2065537ee4c6Sjsg 			ret = -ERESTARTSYS;
2066537ee4c6Sjsg 			break;
2067537ee4c6Sjsg 		}
2068537ee4c6Sjsg 	}
2069537ee4c6Sjsg 
2070537ee4c6Sjsg cb_cleanup:
2071537ee4c6Sjsg 	while (i-- > 0)
2072537ee4c6Sjsg 		dma_fence_remove_callback(fences[i], &cb[i].base);
2073537ee4c6Sjsg 	free(cb, M_DRM, count * sizeof(*cb));
2074537ee4c6Sjsg 	return ret;
2075537ee4c6Sjsg }
2076537ee4c6Sjsg 
2077f005ef32Sjsg void
dma_fence_set_deadline(struct dma_fence * f,ktime_t t)2078f005ef32Sjsg dma_fence_set_deadline(struct dma_fence *f, ktime_t t)
2079f005ef32Sjsg {
2080f005ef32Sjsg 	if (f->ops->set_deadline == NULL)
2081f005ef32Sjsg 		return;
2082f005ef32Sjsg 	if (dma_fence_is_signaled(f) == false)
2083f005ef32Sjsg 		f->ops->set_deadline(f, t);
2084f005ef32Sjsg }
2085f005ef32Sjsg 
2086c349dbc7Sjsg static struct dma_fence dma_fence_stub;
2087c349dbc7Sjsg static struct mutex dma_fence_stub_mtx = MUTEX_INITIALIZER(IPL_TTY);
2088c349dbc7Sjsg 
2089c349dbc7Sjsg static const char *
dma_fence_stub_get_name(struct dma_fence * fence)2090c349dbc7Sjsg dma_fence_stub_get_name(struct dma_fence *fence)
2091c349dbc7Sjsg {
2092c349dbc7Sjsg 	return "stub";
2093c349dbc7Sjsg }
2094c349dbc7Sjsg 
2095c349dbc7Sjsg static const struct dma_fence_ops dma_fence_stub_ops = {
2096c349dbc7Sjsg 	.get_driver_name = dma_fence_stub_get_name,
2097c349dbc7Sjsg 	.get_timeline_name = dma_fence_stub_get_name,
2098c349dbc7Sjsg };
2099c349dbc7Sjsg 
2100c349dbc7Sjsg struct dma_fence *
dma_fence_get_stub(void)2101c349dbc7Sjsg dma_fence_get_stub(void)
2102c349dbc7Sjsg {
2103c349dbc7Sjsg 	mtx_enter(&dma_fence_stub_mtx);
2104c349dbc7Sjsg 	if (dma_fence_stub.ops == NULL) {
2105c349dbc7Sjsg 		dma_fence_init(&dma_fence_stub, &dma_fence_stub_ops,
2106c349dbc7Sjsg 		    &dma_fence_stub_mtx, 0, 0);
2107c349dbc7Sjsg 		dma_fence_signal_locked(&dma_fence_stub);
2108c349dbc7Sjsg 	}
2109c349dbc7Sjsg 	mtx_leave(&dma_fence_stub_mtx);
2110c349dbc7Sjsg 
2111c349dbc7Sjsg 	return dma_fence_get(&dma_fence_stub);
2112c349dbc7Sjsg }
2113c349dbc7Sjsg 
21145ca02815Sjsg struct dma_fence *
dma_fence_allocate_private_stub(ktime_t ts)2115e80177aeSjsg dma_fence_allocate_private_stub(ktime_t ts)
21165ca02815Sjsg {
21175ca02815Sjsg 	struct dma_fence *f = malloc(sizeof(*f), M_DRM,
21185ca02815Sjsg 	    M_ZERO | M_WAITOK | M_CANFAIL);
21195ca02815Sjsg 	if (f == NULL)
2120f69d21f3Sjsg 		return NULL;
21215ca02815Sjsg 	dma_fence_init(f, &dma_fence_stub_ops, &dma_fence_stub_mtx, 0, 0);
2122e80177aeSjsg 	dma_fence_signal_timestamp(f, ts);
21235ca02815Sjsg 	return f;
21245ca02815Sjsg }
21255ca02815Sjsg 
212695f00a37Sjsg static const char *
dma_fence_array_get_driver_name(struct dma_fence * fence)212795f00a37Sjsg dma_fence_array_get_driver_name(struct dma_fence *fence)
212895f00a37Sjsg {
212995f00a37Sjsg 	return "dma_fence_array";
213095f00a37Sjsg }
213195f00a37Sjsg 
213295f00a37Sjsg static const char *
dma_fence_array_get_timeline_name(struct dma_fence * fence)213395f00a37Sjsg dma_fence_array_get_timeline_name(struct dma_fence *fence)
213495f00a37Sjsg {
213595f00a37Sjsg 	return "unbound";
213695f00a37Sjsg }
213795f00a37Sjsg 
213895f00a37Sjsg static void
irq_dma_fence_array_work(void * arg)21395ca02815Sjsg irq_dma_fence_array_work(void *arg)
214095f00a37Sjsg {
21415ca02815Sjsg 	struct dma_fence_array *dfa = (struct dma_fence_array *)arg;
214295f00a37Sjsg 	dma_fence_signal(&dfa->base);
214395f00a37Sjsg 	dma_fence_put(&dfa->base);
214495f00a37Sjsg }
214595f00a37Sjsg 
214695f00a37Sjsg static void
dma_fence_array_cb_func(struct dma_fence * f,struct dma_fence_cb * cb)214795f00a37Sjsg dma_fence_array_cb_func(struct dma_fence *f, struct dma_fence_cb *cb)
214895f00a37Sjsg {
214995f00a37Sjsg 	struct dma_fence_array_cb *array_cb =
215095f00a37Sjsg 	    container_of(cb, struct dma_fence_array_cb, cb);
215195f00a37Sjsg 	struct dma_fence_array *dfa = array_cb->array;
215295f00a37Sjsg 
215395f00a37Sjsg 	if (atomic_dec_and_test(&dfa->num_pending))
21545ca02815Sjsg 		timeout_add(&dfa->to, 1);
215595f00a37Sjsg 	else
215695f00a37Sjsg 		dma_fence_put(&dfa->base);
215795f00a37Sjsg }
215895f00a37Sjsg 
215995f00a37Sjsg static bool
dma_fence_array_enable_signaling(struct dma_fence * fence)216095f00a37Sjsg dma_fence_array_enable_signaling(struct dma_fence *fence)
216195f00a37Sjsg {
216295f00a37Sjsg 	struct dma_fence_array *dfa = to_dma_fence_array(fence);
216395f00a37Sjsg 	struct dma_fence_array_cb *cb = (void *)(&dfa[1]);
216495f00a37Sjsg 	int i;
216595f00a37Sjsg 
216695f00a37Sjsg 	for (i = 0; i < dfa->num_fences; ++i) {
216795f00a37Sjsg 		cb[i].array = dfa;
216895f00a37Sjsg 		dma_fence_get(&dfa->base);
216995f00a37Sjsg 		if (dma_fence_add_callback(dfa->fences[i], &cb[i].cb,
217095f00a37Sjsg 		    dma_fence_array_cb_func)) {
217195f00a37Sjsg 			dma_fence_put(&dfa->base);
217295f00a37Sjsg 			if (atomic_dec_and_test(&dfa->num_pending))
217395f00a37Sjsg 				return false;
217495f00a37Sjsg 		}
217595f00a37Sjsg 	}
217695f00a37Sjsg 
217795f00a37Sjsg 	return true;
217895f00a37Sjsg }
217995f00a37Sjsg 
2180ad8b1aafSjsg static bool
dma_fence_array_signaled(struct dma_fence * fence)2181ad8b1aafSjsg dma_fence_array_signaled(struct dma_fence *fence)
218295f00a37Sjsg {
218395f00a37Sjsg 	struct dma_fence_array *dfa = to_dma_fence_array(fence);
218495f00a37Sjsg 
218595f00a37Sjsg 	return atomic_read(&dfa->num_pending) <= 0;
218695f00a37Sjsg }
218795f00a37Sjsg 
2188ad8b1aafSjsg static void
dma_fence_array_release(struct dma_fence * fence)2189ad8b1aafSjsg dma_fence_array_release(struct dma_fence *fence)
219095f00a37Sjsg {
219195f00a37Sjsg 	struct dma_fence_array *dfa = to_dma_fence_array(fence);
219295f00a37Sjsg 	int i;
219395f00a37Sjsg 
219495f00a37Sjsg 	for (i = 0; i < dfa->num_fences; ++i)
219595f00a37Sjsg 		dma_fence_put(dfa->fences[i]);
219695f00a37Sjsg 
219795f00a37Sjsg 	free(dfa->fences, M_DRM, 0);
219895f00a37Sjsg 	dma_fence_free(fence);
219995f00a37Sjsg }
220095f00a37Sjsg 
220195f00a37Sjsg struct dma_fence_array *
dma_fence_array_create(int num_fences,struct dma_fence ** fences,u64 context,unsigned seqno,bool signal_on_any)220295f00a37Sjsg dma_fence_array_create(int num_fences, struct dma_fence **fences, u64 context,
220395f00a37Sjsg     unsigned seqno, bool signal_on_any)
220495f00a37Sjsg {
220595f00a37Sjsg 	struct dma_fence_array *dfa = malloc(sizeof(*dfa) +
220695f00a37Sjsg 	    (num_fences * sizeof(struct dma_fence_array_cb)),
220795f00a37Sjsg 	    M_DRM, M_WAITOK|M_CANFAIL|M_ZERO);
220895f00a37Sjsg 	if (dfa == NULL)
220995f00a37Sjsg 		return NULL;
221095f00a37Sjsg 
221195f00a37Sjsg 	mtx_init(&dfa->lock, IPL_TTY);
221295f00a37Sjsg 	dma_fence_init(&dfa->base, &dma_fence_array_ops, &dfa->lock,
221395f00a37Sjsg 	    context, seqno);
22145ca02815Sjsg 	timeout_set(&dfa->to, irq_dma_fence_array_work, dfa);
221595f00a37Sjsg 
221695f00a37Sjsg 	dfa->num_fences = num_fences;
221795f00a37Sjsg 	atomic_set(&dfa->num_pending, signal_on_any ? 1 : num_fences);
221895f00a37Sjsg 	dfa->fences = fences;
221995f00a37Sjsg 
222095f00a37Sjsg 	return dfa;
222195f00a37Sjsg }
222295f00a37Sjsg 
22231bb76ff1Sjsg struct dma_fence *
dma_fence_array_first(struct dma_fence * f)22241bb76ff1Sjsg dma_fence_array_first(struct dma_fence *f)
22251bb76ff1Sjsg {
22261bb76ff1Sjsg 	struct dma_fence_array *dfa;
22271bb76ff1Sjsg 
22281bb76ff1Sjsg 	if (f == NULL)
22291bb76ff1Sjsg 		return NULL;
22301bb76ff1Sjsg 
22311bb76ff1Sjsg 	if ((dfa = to_dma_fence_array(f)) == NULL)
22321bb76ff1Sjsg 		return f;
22331bb76ff1Sjsg 
22341bb76ff1Sjsg 	if (dfa->num_fences > 0)
22351bb76ff1Sjsg 		return dfa->fences[0];
22361bb76ff1Sjsg 
22371bb76ff1Sjsg 	return NULL;
22381bb76ff1Sjsg }
22391bb76ff1Sjsg 
22401bb76ff1Sjsg struct dma_fence *
dma_fence_array_next(struct dma_fence * f,unsigned int i)22411bb76ff1Sjsg dma_fence_array_next(struct dma_fence *f, unsigned int i)
22421bb76ff1Sjsg {
22431bb76ff1Sjsg 	struct dma_fence_array *dfa;
22441bb76ff1Sjsg 
22451bb76ff1Sjsg 	if (f == NULL)
22461bb76ff1Sjsg 		return NULL;
22471bb76ff1Sjsg 
22481bb76ff1Sjsg 	if ((dfa = to_dma_fence_array(f)) == NULL)
22491bb76ff1Sjsg 		return NULL;
22501bb76ff1Sjsg 
22511bb76ff1Sjsg 	if (i < dfa->num_fences)
22521bb76ff1Sjsg 		return dfa->fences[i];
22531bb76ff1Sjsg 
22541bb76ff1Sjsg 	return NULL;
22551bb76ff1Sjsg }
22561bb76ff1Sjsg 
225795f00a37Sjsg const struct dma_fence_ops dma_fence_array_ops = {
225895f00a37Sjsg 	.get_driver_name = dma_fence_array_get_driver_name,
225995f00a37Sjsg 	.get_timeline_name = dma_fence_array_get_timeline_name,
226095f00a37Sjsg 	.enable_signaling = dma_fence_array_enable_signaling,
226195f00a37Sjsg 	.signaled = dma_fence_array_signaled,
226295f00a37Sjsg 	.release = dma_fence_array_release,
226395f00a37Sjsg };
226495f00a37Sjsg 
2265a9ee023bSkettenis int
dma_fence_chain_find_seqno(struct dma_fence ** df,uint64_t seqno)2266ad8b1aafSjsg dma_fence_chain_find_seqno(struct dma_fence **df, uint64_t seqno)
2267ad8b1aafSjsg {
2268f56254deSjsg 	struct dma_fence_chain *chain;
2269f56254deSjsg 	struct dma_fence *fence;
2270f56254deSjsg 
2271ad8b1aafSjsg 	if (seqno == 0)
2272ad8b1aafSjsg 		return 0;
2273f56254deSjsg 
2274f56254deSjsg 	if ((chain = to_dma_fence_chain(*df)) == NULL)
2275f56254deSjsg 		return -EINVAL;
2276f56254deSjsg 
2277f56254deSjsg 	fence = &chain->base;
2278f56254deSjsg 	if (fence->seqno < seqno)
2279f56254deSjsg 		return -EINVAL;
2280f56254deSjsg 
2281f56254deSjsg 	dma_fence_chain_for_each(*df, fence) {
2282f56254deSjsg 		if ((*df)->context != fence->context)
2283f56254deSjsg 			break;
2284f56254deSjsg 
2285f56254deSjsg 		chain = to_dma_fence_chain(*df);
2286f56254deSjsg 		if (chain->prev_seqno < seqno)
2287f56254deSjsg 			break;
2288f56254deSjsg 	}
2289f56254deSjsg 	dma_fence_put(fence);
2290f56254deSjsg 
2291f56254deSjsg 	return 0;
2292ad8b1aafSjsg }
2293ad8b1aafSjsg 
2294ad8b1aafSjsg void
dma_fence_chain_init(struct dma_fence_chain * chain,struct dma_fence * prev,struct dma_fence * fence,uint64_t seqno)2295ad8b1aafSjsg dma_fence_chain_init(struct dma_fence_chain *chain, struct dma_fence *prev,
2296ad8b1aafSjsg     struct dma_fence *fence, uint64_t seqno)
2297ad8b1aafSjsg {
2298ad8b1aafSjsg 	uint64_t context;
2299ad8b1aafSjsg 
2300ad8b1aafSjsg 	chain->fence = fence;
2301ad8b1aafSjsg 	chain->prev = prev;
2302ad8b1aafSjsg 	mtx_init(&chain->lock, IPL_TTY);
2303ad8b1aafSjsg 
23045ca02815Sjsg 	/* if prev is a chain */
23055ca02815Sjsg 	if (to_dma_fence_chain(prev) != NULL) {
2306bcd4d0b5Sjsg 		if (__dma_fence_is_later(seqno, prev->seqno, prev->ops)) {
2307ad8b1aafSjsg 			chain->prev_seqno = prev->seqno;
2308ad8b1aafSjsg 			context = prev->context;
2309ad8b1aafSjsg 		} else {
2310ad8b1aafSjsg 			chain->prev_seqno = 0;
2311ad8b1aafSjsg 			context = dma_fence_context_alloc(1);
23125ca02815Sjsg 			seqno = prev->seqno;
23135ca02815Sjsg 		}
23145ca02815Sjsg 	} else {
23155ca02815Sjsg 		chain->prev_seqno = 0;
23165ca02815Sjsg 		context = dma_fence_context_alloc(1);
2317ad8b1aafSjsg 	}
2318ad8b1aafSjsg 
2319ad8b1aafSjsg 	dma_fence_init(&chain->base, &dma_fence_chain_ops, &chain->lock,
2320ad8b1aafSjsg 	    context, seqno);
2321ad8b1aafSjsg }
2322ad8b1aafSjsg 
2323ad8b1aafSjsg static const char *
dma_fence_chain_get_driver_name(struct dma_fence * fence)2324ad8b1aafSjsg dma_fence_chain_get_driver_name(struct dma_fence *fence)
2325ad8b1aafSjsg {
2326ad8b1aafSjsg 	return "dma_fence_chain";
2327ad8b1aafSjsg }
2328ad8b1aafSjsg 
2329ad8b1aafSjsg static const char *
dma_fence_chain_get_timeline_name(struct dma_fence * fence)2330ad8b1aafSjsg dma_fence_chain_get_timeline_name(struct dma_fence *fence)
2331ad8b1aafSjsg {
2332ad8b1aafSjsg 	return "unbound";
2333ad8b1aafSjsg }
2334ad8b1aafSjsg 
23355ca02815Sjsg static bool dma_fence_chain_enable_signaling(struct dma_fence *);
23365ca02815Sjsg 
23375ca02815Sjsg static void
dma_fence_chain_timo(void * arg)23385ca02815Sjsg dma_fence_chain_timo(void *arg)
23395ca02815Sjsg {
23405ca02815Sjsg 	struct dma_fence_chain *chain = (struct dma_fence_chain *)arg;
23415ca02815Sjsg 
23425ca02815Sjsg 	if (dma_fence_chain_enable_signaling(&chain->base) == false)
23435ca02815Sjsg 		dma_fence_signal(&chain->base);
23445ca02815Sjsg 	dma_fence_put(&chain->base);
23455ca02815Sjsg }
23465ca02815Sjsg 
23475ca02815Sjsg static void
dma_fence_chain_cb(struct dma_fence * f,struct dma_fence_cb * cb)23485ca02815Sjsg dma_fence_chain_cb(struct dma_fence *f, struct dma_fence_cb *cb)
23495ca02815Sjsg {
23505ca02815Sjsg 	struct dma_fence_chain *chain =
23515ca02815Sjsg 	    container_of(cb, struct dma_fence_chain, cb);
23525ca02815Sjsg 	timeout_set(&chain->to, dma_fence_chain_timo, chain);
23535ca02815Sjsg 	timeout_add(&chain->to, 1);
23545ca02815Sjsg 	dma_fence_put(f);
23555ca02815Sjsg }
23565ca02815Sjsg 
2357ad8b1aafSjsg static bool
dma_fence_chain_enable_signaling(struct dma_fence * fence)2358ad8b1aafSjsg dma_fence_chain_enable_signaling(struct dma_fence *fence)
2359ad8b1aafSjsg {
23605ca02815Sjsg 	struct dma_fence_chain *chain, *h;
23615ca02815Sjsg 	struct dma_fence *f;
23625ca02815Sjsg 
23635ca02815Sjsg 	h = to_dma_fence_chain(fence);
23645ca02815Sjsg 	dma_fence_get(&h->base);
23655ca02815Sjsg 	dma_fence_chain_for_each(fence, &h->base) {
23665ca02815Sjsg 		chain = to_dma_fence_chain(fence);
23675ca02815Sjsg 		if (chain == NULL)
23685ca02815Sjsg 			f = fence;
23695ca02815Sjsg 		else
23705ca02815Sjsg 			f = chain->fence;
23715ca02815Sjsg 
23725ca02815Sjsg 		dma_fence_get(f);
23735ca02815Sjsg 		if (!dma_fence_add_callback(f, &h->cb, dma_fence_chain_cb)) {
23745ca02815Sjsg 			dma_fence_put(fence);
23755ca02815Sjsg 			return true;
23765ca02815Sjsg 		}
23775ca02815Sjsg 		dma_fence_put(f);
23785ca02815Sjsg 	}
23795ca02815Sjsg 	dma_fence_put(&h->base);
2380ad8b1aafSjsg 	return false;
2381ad8b1aafSjsg }
2382ad8b1aafSjsg 
2383ad8b1aafSjsg static bool
dma_fence_chain_signaled(struct dma_fence * fence)2384ad8b1aafSjsg dma_fence_chain_signaled(struct dma_fence *fence)
2385ad8b1aafSjsg {
23865ca02815Sjsg 	struct dma_fence_chain *chain;
23875ca02815Sjsg 	struct dma_fence *f;
23885ca02815Sjsg 
23895ca02815Sjsg 	dma_fence_chain_for_each(fence, fence) {
23905ca02815Sjsg 		chain = to_dma_fence_chain(fence);
23915ca02815Sjsg 		if (chain == NULL)
23925ca02815Sjsg 			f = fence;
23935ca02815Sjsg 		else
23945ca02815Sjsg 			f = chain->fence;
23955ca02815Sjsg 
23965ca02815Sjsg 		if (dma_fence_is_signaled(f) == false) {
23975ca02815Sjsg 			dma_fence_put(fence);
2398ad8b1aafSjsg 			return false;
2399ad8b1aafSjsg 		}
24005ca02815Sjsg 	}
24015ca02815Sjsg 	return true;
24025ca02815Sjsg }
2403ad8b1aafSjsg 
2404ad8b1aafSjsg static void
dma_fence_chain_release(struct dma_fence * fence)2405ad8b1aafSjsg dma_fence_chain_release(struct dma_fence *fence)
2406ad8b1aafSjsg {
24075ca02815Sjsg 	struct dma_fence_chain *chain = to_dma_fence_chain(fence);
24085ca02815Sjsg 	struct dma_fence_chain *prev_chain;
24095ca02815Sjsg 	struct dma_fence *prev;
24105ca02815Sjsg 
24115ca02815Sjsg 	for (prev = chain->prev; prev != NULL; prev = chain->prev) {
24125ca02815Sjsg 		if (kref_read(&prev->refcount) > 1)
24135ca02815Sjsg 			break;
24145ca02815Sjsg 		if ((prev_chain = to_dma_fence_chain(prev)) == NULL)
24155ca02815Sjsg 			break;
24165ca02815Sjsg 		chain->prev = prev_chain->prev;
24175ca02815Sjsg 		prev_chain->prev = NULL;
24185ca02815Sjsg 		dma_fence_put(prev);
24195ca02815Sjsg 	}
24205ca02815Sjsg 	dma_fence_put(prev);
24215ca02815Sjsg 	dma_fence_put(chain->fence);
24225ca02815Sjsg 	dma_fence_free(fence);
2423ad8b1aafSjsg }
2424ad8b1aafSjsg 
2425ad8b1aafSjsg struct dma_fence *
dma_fence_chain_walk(struct dma_fence * fence)24265ca02815Sjsg dma_fence_chain_walk(struct dma_fence *fence)
2427ad8b1aafSjsg {
24285ca02815Sjsg 	struct dma_fence_chain *chain = to_dma_fence_chain(fence), *prev_chain;
24295ca02815Sjsg 	struct dma_fence *prev, *new_prev, *tmp;
2430ad8b1aafSjsg 
2431ad8b1aafSjsg 	if (chain == NULL) {
2432ad8b1aafSjsg 		dma_fence_put(fence);
2433ad8b1aafSjsg 		return NULL;
2434ad8b1aafSjsg 	}
2435ad8b1aafSjsg 
24365ca02815Sjsg 	while ((prev = dma_fence_get(chain->prev)) != NULL) {
24375ca02815Sjsg 		prev_chain = to_dma_fence_chain(prev);
24385ca02815Sjsg 		if (prev_chain != NULL) {
24395ca02815Sjsg 			if (!dma_fence_is_signaled(prev_chain->fence))
24405ca02815Sjsg 				break;
24415ca02815Sjsg 			new_prev = dma_fence_get(prev_chain->prev);
24425ca02815Sjsg 		} else {
24435ca02815Sjsg 			if (!dma_fence_is_signaled(prev))
24445ca02815Sjsg 				break;
24455ca02815Sjsg 			new_prev = NULL;
24465ca02815Sjsg 		}
24475ca02815Sjsg 		tmp = atomic_cas_ptr(&chain->prev, prev, new_prev);
24485ca02815Sjsg 		dma_fence_put(tmp == prev ? prev : new_prev);
24495ca02815Sjsg 		dma_fence_put(prev);
24505ca02815Sjsg 	}
24515ca02815Sjsg 
2452ad8b1aafSjsg 	dma_fence_put(fence);
24535ca02815Sjsg 	return prev;
2454ad8b1aafSjsg }
2455ad8b1aafSjsg 
2456ad8b1aafSjsg const struct dma_fence_ops dma_fence_chain_ops = {
2457ad8b1aafSjsg 	.get_driver_name = dma_fence_chain_get_driver_name,
2458ad8b1aafSjsg 	.get_timeline_name = dma_fence_chain_get_timeline_name,
2459ad8b1aafSjsg 	.enable_signaling = dma_fence_chain_enable_signaling,
2460ad8b1aafSjsg 	.signaled = dma_fence_chain_signaled,
2461ad8b1aafSjsg 	.release = dma_fence_chain_release,
2462bcd4d0b5Sjsg 	.use_64bit_seqno = true,
2463ad8b1aafSjsg };
2464ad8b1aafSjsg 
24651bb76ff1Sjsg bool
dma_fence_is_container(struct dma_fence * fence)24661bb76ff1Sjsg dma_fence_is_container(struct dma_fence *fence)
24671bb76ff1Sjsg {
24681bb76ff1Sjsg 	return (fence->ops == &dma_fence_chain_ops) ||
24691bb76ff1Sjsg 	    (fence->ops == &dma_fence_array_ops);
24701bb76ff1Sjsg }
24711bb76ff1Sjsg 
2472ad8b1aafSjsg int
dmabuf_read(struct file * fp,struct uio * uio,int fflags)24732bd648c0Smpi dmabuf_read(struct file *fp, struct uio *uio, int fflags)
2474a9ee023bSkettenis {
2475a9ee023bSkettenis 	return (ENXIO);
2476a9ee023bSkettenis }
2477a9ee023bSkettenis 
2478a9ee023bSkettenis int
dmabuf_write(struct file * fp,struct uio * uio,int fflags)24792bd648c0Smpi dmabuf_write(struct file *fp, struct uio *uio, int fflags)
2480a9ee023bSkettenis {
2481a9ee023bSkettenis 	return (ENXIO);
2482a9ee023bSkettenis }
2483a9ee023bSkettenis 
2484a9ee023bSkettenis int
dmabuf_ioctl(struct file * fp,u_long com,caddr_t data,struct proc * p)2485a9ee023bSkettenis dmabuf_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
2486a9ee023bSkettenis {
2487a9ee023bSkettenis 	return (ENOTTY);
2488a9ee023bSkettenis }
2489a9ee023bSkettenis 
2490a9ee023bSkettenis int
dmabuf_kqfilter(struct file * fp,struct knote * kn)2491a9ee023bSkettenis dmabuf_kqfilter(struct file *fp, struct knote *kn)
2492a9ee023bSkettenis {
2493a9ee023bSkettenis 	return (EINVAL);
2494a9ee023bSkettenis }
2495a9ee023bSkettenis 
2496a9ee023bSkettenis int
dmabuf_stat(struct file * fp,struct stat * st,struct proc * p)2497a9ee023bSkettenis dmabuf_stat(struct file *fp, struct stat *st, struct proc *p)
2498a9ee023bSkettenis {
2499a9ee023bSkettenis 	struct dma_buf *dmabuf = fp->f_data;
2500a9ee023bSkettenis 
2501a9ee023bSkettenis 	memset(st, 0, sizeof(*st));
2502a9ee023bSkettenis 	st->st_size = dmabuf->size;
2503a9ee023bSkettenis 	st->st_mode = S_IFIFO;	/* XXX */
2504a9ee023bSkettenis 	return (0);
2505a9ee023bSkettenis }
2506a9ee023bSkettenis 
2507a9ee023bSkettenis int
dmabuf_close(struct file * fp,struct proc * p)2508a9ee023bSkettenis dmabuf_close(struct file *fp, struct proc *p)
2509a9ee023bSkettenis {
2510a9ee023bSkettenis 	struct dma_buf *dmabuf = fp->f_data;
2511a9ee023bSkettenis 
2512a9ee023bSkettenis 	fp->f_data = NULL;
2513fcba5756Svisa 	KERNEL_LOCK();
2514a9ee023bSkettenis 	dmabuf->ops->release(dmabuf);
2515fcba5756Svisa 	KERNEL_UNLOCK();
2516a9ee023bSkettenis 	free(dmabuf, M_DRM, sizeof(struct dma_buf));
2517a9ee023bSkettenis 	return (0);
2518a9ee023bSkettenis }
2519a9ee023bSkettenis 
2520f3455eb0Skettenis int
dmabuf_seek(struct file * fp,off_t * offset,int whence,struct proc * p)2521f3455eb0Skettenis dmabuf_seek(struct file *fp, off_t *offset, int whence, struct proc *p)
2522f3455eb0Skettenis {
2523f3455eb0Skettenis 	struct dma_buf *dmabuf = fp->f_data;
2524f3455eb0Skettenis 	off_t newoff;
2525f3455eb0Skettenis 
2526f3455eb0Skettenis 	if (*offset != 0)
2527f3455eb0Skettenis 		return (EINVAL);
2528f3455eb0Skettenis 
2529f3455eb0Skettenis 	switch (whence) {
2530f3455eb0Skettenis 	case SEEK_SET:
2531f3455eb0Skettenis 		newoff = 0;
2532f3455eb0Skettenis 		break;
2533f3455eb0Skettenis 	case SEEK_END:
2534f3455eb0Skettenis 		newoff = dmabuf->size;
2535f3455eb0Skettenis 		break;
2536f3455eb0Skettenis 	default:
2537f3455eb0Skettenis 		return (EINVAL);
2538f3455eb0Skettenis 	}
2539836f297bSanton 	mtx_enter(&fp->f_mtx);
2540836f297bSanton 	fp->f_offset = newoff;
2541836f297bSanton 	mtx_leave(&fp->f_mtx);
2542836f297bSanton 	*offset = newoff;
2543f3455eb0Skettenis 	return (0);
2544f3455eb0Skettenis }
2545f3455eb0Skettenis 
2546c02bfb27Svisa const struct fileops dmabufops = {
2547a9ee023bSkettenis 	.fo_read	= dmabuf_read,
2548a9ee023bSkettenis 	.fo_write	= dmabuf_write,
2549a9ee023bSkettenis 	.fo_ioctl	= dmabuf_ioctl,
2550a9ee023bSkettenis 	.fo_kqfilter	= dmabuf_kqfilter,
2551a9ee023bSkettenis 	.fo_stat	= dmabuf_stat,
2552f3455eb0Skettenis 	.fo_close	= dmabuf_close,
2553f3455eb0Skettenis 	.fo_seek	= dmabuf_seek,
2554a9ee023bSkettenis };
2555a9ee023bSkettenis 
2556a9ee023bSkettenis struct dma_buf *
dma_buf_export(const struct dma_buf_export_info * info)2557a9ee023bSkettenis dma_buf_export(const struct dma_buf_export_info *info)
2558a9ee023bSkettenis {
2559a9ee023bSkettenis 	struct proc *p = curproc;
2560a9ee023bSkettenis 	struct dma_buf *dmabuf;
2561a9ee023bSkettenis 	struct file *fp;
2562a9ee023bSkettenis 
2563d90ebdd6Skettenis 	fp = fnew(p);
2564d90ebdd6Skettenis 	if (fp == NULL)
2565d90ebdd6Skettenis 		return ERR_PTR(-ENFILE);
2566a9ee023bSkettenis 	fp->f_type = DTYPE_DMABUF;
2567a9ee023bSkettenis 	fp->f_ops = &dmabufops;
2568a9ee023bSkettenis 	dmabuf = malloc(sizeof(struct dma_buf), M_DRM, M_WAITOK | M_ZERO);
2569a9ee023bSkettenis 	dmabuf->priv = info->priv;
2570a9ee023bSkettenis 	dmabuf->ops = info->ops;
2571a9ee023bSkettenis 	dmabuf->size = info->size;
2572a9ee023bSkettenis 	dmabuf->file = fp;
2573a9ee023bSkettenis 	fp->f_data = dmabuf;
2574c349dbc7Sjsg 	INIT_LIST_HEAD(&dmabuf->attachments);
2575a9ee023bSkettenis 	return dmabuf;
2576a9ee023bSkettenis }
2577a9ee023bSkettenis 
2578a9ee023bSkettenis struct dma_buf *
dma_buf_get(int fd)2579a9ee023bSkettenis dma_buf_get(int fd)
2580a9ee023bSkettenis {
2581a9ee023bSkettenis 	struct proc *p = curproc;
2582a9ee023bSkettenis 	struct filedesc *fdp = p->p_fd;
2583a9ee023bSkettenis 	struct file *fp;
2584a9ee023bSkettenis 
2585a9ee023bSkettenis 	if ((fp = fd_getfile(fdp, fd)) == NULL)
2586a9ee023bSkettenis 		return ERR_PTR(-EBADF);
2587a9ee023bSkettenis 
2588a9ee023bSkettenis 	if (fp->f_type != DTYPE_DMABUF) {
2589a9ee023bSkettenis 		FRELE(fp, p);
2590a9ee023bSkettenis 		return ERR_PTR(-EINVAL);
2591a9ee023bSkettenis 	}
2592a9ee023bSkettenis 
2593a9ee023bSkettenis 	return fp->f_data;
2594a9ee023bSkettenis }
2595a9ee023bSkettenis 
2596a9ee023bSkettenis void
dma_buf_put(struct dma_buf * dmabuf)2597a9ee023bSkettenis dma_buf_put(struct dma_buf *dmabuf)
2598a9ee023bSkettenis {
2599a9ee023bSkettenis 	KASSERT(dmabuf);
2600a9ee023bSkettenis 	KASSERT(dmabuf->file);
2601a9ee023bSkettenis 
2602a9ee023bSkettenis 	FRELE(dmabuf->file, curproc);
2603a9ee023bSkettenis }
2604a9ee023bSkettenis 
2605a9ee023bSkettenis int
dma_buf_fd(struct dma_buf * dmabuf,int flags)2606a9ee023bSkettenis dma_buf_fd(struct dma_buf *dmabuf, int flags)
2607a9ee023bSkettenis {
2608a9ee023bSkettenis 	struct proc *p = curproc;
2609a9ee023bSkettenis 	struct filedesc *fdp = p->p_fd;
2610a9ee023bSkettenis 	struct file *fp = dmabuf->file;
2611a9ee023bSkettenis 	int fd, cloexec, error;
2612a9ee023bSkettenis 
2613a9ee023bSkettenis 	cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0;
2614a9ee023bSkettenis 
2615a9ee023bSkettenis 	fdplock(fdp);
2616a9ee023bSkettenis restart:
2617a9ee023bSkettenis 	if ((error = fdalloc(p, 0, &fd)) != 0) {
2618a9ee023bSkettenis 		if (error == ENOSPC) {
2619a9ee023bSkettenis 			fdexpand(p);
2620a9ee023bSkettenis 			goto restart;
2621a9ee023bSkettenis 		}
2622a9ee023bSkettenis 		fdpunlock(fdp);
2623a9ee023bSkettenis 		return -error;
2624a9ee023bSkettenis 	}
2625a9ee023bSkettenis 
2626a9ee023bSkettenis 	fdinsert(fdp, fd, cloexec, fp);
2627a9ee023bSkettenis 	fdpunlock(fdp);
2628a9ee023bSkettenis 
2629a9ee023bSkettenis 	return fd;
2630a9ee023bSkettenis }
2631a9ee023bSkettenis 
2632a9ee023bSkettenis void
get_dma_buf(struct dma_buf * dmabuf)2633a9ee023bSkettenis get_dma_buf(struct dma_buf *dmabuf)
2634a9ee023bSkettenis {
2635a9ee023bSkettenis 	FREF(dmabuf->file);
2636a9ee023bSkettenis }
26377f4dd379Sjsg 
26387f4dd379Sjsg enum pci_bus_speed
pcie_get_speed_cap(struct pci_dev * pdev)26397f4dd379Sjsg pcie_get_speed_cap(struct pci_dev *pdev)
26407f4dd379Sjsg {
2641b699e857Skettenis 	pci_chipset_tag_t	pc;
2642b699e857Skettenis 	pcitag_t		tag;
26437f4dd379Sjsg 	int			pos ;
26447f4dd379Sjsg 	pcireg_t		xcap, lnkcap = 0, lnkcap2 = 0;
26457f4dd379Sjsg 	pcireg_t		id;
26467f4dd379Sjsg 	enum pci_bus_speed	cap = PCI_SPEED_UNKNOWN;
26477f4dd379Sjsg 	int			bus, device, function;
26487f4dd379Sjsg 
2649b699e857Skettenis 	if (pdev == NULL)
2650b699e857Skettenis 		return PCI_SPEED_UNKNOWN;
2651b699e857Skettenis 
2652b699e857Skettenis 	pc = pdev->pc;
2653b699e857Skettenis 	tag = pdev->tag;
2654b699e857Skettenis 
26557f4dd379Sjsg 	if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS,
26567f4dd379Sjsg 	    &pos, NULL))
26577f4dd379Sjsg 		return PCI_SPEED_UNKNOWN;
26587f4dd379Sjsg 
26597f4dd379Sjsg 	id = pci_conf_read(pc, tag, PCI_ID_REG);
26607f4dd379Sjsg 	pci_decompose_tag(pc, tag, &bus, &device, &function);
26617f4dd379Sjsg 
26627f4dd379Sjsg 	/* we've been informed via and serverworks don't make the cut */
26637f4dd379Sjsg 	if (PCI_VENDOR(id) == PCI_VENDOR_VIATECH ||
26647f4dd379Sjsg 	    PCI_VENDOR(id) == PCI_VENDOR_RCC)
26657f4dd379Sjsg 		return PCI_SPEED_UNKNOWN;
26667f4dd379Sjsg 
26677f4dd379Sjsg 	lnkcap = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP);
26687f4dd379Sjsg 	xcap = pci_conf_read(pc, tag, pos + PCI_PCIE_XCAP);
26697f4dd379Sjsg 	if (PCI_PCIE_XCAP_VER(xcap) >= 2)
26707f4dd379Sjsg 		lnkcap2 = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP2);
26717f4dd379Sjsg 
26727f4dd379Sjsg 	lnkcap &= 0x0f;
26737f4dd379Sjsg 	lnkcap2 &= 0xfe;
26747f4dd379Sjsg 
26757f4dd379Sjsg 	if (lnkcap2) { /* PCIE GEN 3.0 */
26767f4dd379Sjsg 		if (lnkcap2 & 0x02)
26777f4dd379Sjsg 			cap = PCIE_SPEED_2_5GT;
26787f4dd379Sjsg 		if (lnkcap2 & 0x04)
26797f4dd379Sjsg 			cap = PCIE_SPEED_5_0GT;
26807f4dd379Sjsg 		if (lnkcap2 & 0x08)
26817f4dd379Sjsg 			cap = PCIE_SPEED_8_0GT;
26827f4dd379Sjsg 		if (lnkcap2 & 0x10)
26837f4dd379Sjsg 			cap = PCIE_SPEED_16_0GT;
26845ca02815Sjsg 		if (lnkcap2 & 0x20)
26855ca02815Sjsg 			cap = PCIE_SPEED_32_0GT;
26865ca02815Sjsg 		if (lnkcap2 & 0x40)
26875ca02815Sjsg 			cap = PCIE_SPEED_64_0GT;
26887f4dd379Sjsg 	} else {
26897f4dd379Sjsg 		if (lnkcap & 0x01)
26907f4dd379Sjsg 			cap = PCIE_SPEED_2_5GT;
26917f4dd379Sjsg 		if (lnkcap & 0x02)
26927f4dd379Sjsg 			cap = PCIE_SPEED_5_0GT;
26937f4dd379Sjsg 	}
26947f4dd379Sjsg 
26957f4dd379Sjsg 	DRM_INFO("probing pcie caps for device %d:%d:%d 0x%04x:0x%04x = %x/%x\n",
26967f4dd379Sjsg 	    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), lnkcap,
26977f4dd379Sjsg 	    lnkcap2);
26987f4dd379Sjsg 	return cap;
26997f4dd379Sjsg }
27007f4dd379Sjsg 
27017f4dd379Sjsg enum pcie_link_width
pcie_get_width_cap(struct pci_dev * pdev)27027f4dd379Sjsg pcie_get_width_cap(struct pci_dev *pdev)
27037f4dd379Sjsg {
27047f4dd379Sjsg 	pci_chipset_tag_t	pc = pdev->pc;
27057f4dd379Sjsg 	pcitag_t		tag = pdev->tag;
27067f4dd379Sjsg 	int			pos ;
27077f4dd379Sjsg 	pcireg_t		lnkcap = 0;
27087f4dd379Sjsg 	pcireg_t		id;
27097f4dd379Sjsg 	int			bus, device, function;
27107f4dd379Sjsg 
27117f4dd379Sjsg 	if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS,
27127f4dd379Sjsg 	    &pos, NULL))
27137f4dd379Sjsg 		return PCIE_LNK_WIDTH_UNKNOWN;
27147f4dd379Sjsg 
27157f4dd379Sjsg 	id = pci_conf_read(pc, tag, PCI_ID_REG);
27167f4dd379Sjsg 	pci_decompose_tag(pc, tag, &bus, &device, &function);
27177f4dd379Sjsg 
27187f4dd379Sjsg 	lnkcap = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP);
27197f4dd379Sjsg 
27207f4dd379Sjsg 	DRM_INFO("probing pcie width for device %d:%d:%d 0x%04x:0x%04x = %x\n",
27217f4dd379Sjsg 	    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), lnkcap);
27227f4dd379Sjsg 
27237f4dd379Sjsg 	if (lnkcap)
27247f4dd379Sjsg 		return (lnkcap & 0x3f0) >> 4;
27257f4dd379Sjsg 	return PCIE_LNK_WIDTH_UNKNOWN;
27267f4dd379Sjsg }
27277f4dd379Sjsg 
27285276e8c8Sjsg bool
pcie_aspm_enabled(struct pci_dev * pdev)27295276e8c8Sjsg pcie_aspm_enabled(struct pci_dev *pdev)
27305276e8c8Sjsg {
27315276e8c8Sjsg 	pci_chipset_tag_t	pc = pdev->pc;
27325276e8c8Sjsg 	pcitag_t		tag = pdev->tag;
27335276e8c8Sjsg 	int			pos ;
27345276e8c8Sjsg 	pcireg_t		lcsr;
27355276e8c8Sjsg 
27365276e8c8Sjsg 	if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS,
27375276e8c8Sjsg 	    &pos, NULL))
27385276e8c8Sjsg 		return false;
27395276e8c8Sjsg 
27405276e8c8Sjsg 	lcsr = pci_conf_read(pc, tag, pos + PCI_PCIE_LCSR);
27415276e8c8Sjsg 	if ((lcsr & (PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1)) != 0)
27425276e8c8Sjsg 		return true;
27435276e8c8Sjsg 
27445276e8c8Sjsg 	return false;
27455276e8c8Sjsg }
27465276e8c8Sjsg 
2747c349dbc7Sjsg static wait_queue_head_t bit_waitq;
2748c349dbc7Sjsg wait_queue_head_t var_waitq;
27497f4dd379Sjsg struct mutex wait_bit_mtx = MUTEX_INITIALIZER(IPL_TTY);
27507f4dd379Sjsg 
27517f4dd379Sjsg int
wait_on_bit(unsigned long * word,int bit,unsigned mode)27527f4dd379Sjsg wait_on_bit(unsigned long *word, int bit, unsigned mode)
27537f4dd379Sjsg {
27547f4dd379Sjsg 	int err;
27557f4dd379Sjsg 
27567f4dd379Sjsg 	if (!test_bit(bit, word))
27577f4dd379Sjsg 		return 0;
27587f4dd379Sjsg 
27597f4dd379Sjsg 	mtx_enter(&wait_bit_mtx);
27607f4dd379Sjsg 	while (test_bit(bit, word)) {
2761d18c2ae1Smpi 		err = msleep_nsec(word, &wait_bit_mtx, PWAIT | mode, "wtb",
2762d18c2ae1Smpi 		    INFSLP);
27637f4dd379Sjsg 		if (err) {
27647f4dd379Sjsg 			mtx_leave(&wait_bit_mtx);
27657f4dd379Sjsg 			return 1;
27667f4dd379Sjsg 		}
27677f4dd379Sjsg 	}
27687f4dd379Sjsg 	mtx_leave(&wait_bit_mtx);
27697f4dd379Sjsg 	return 0;
27707f4dd379Sjsg }
27717f4dd379Sjsg 
27727f4dd379Sjsg int
wait_on_bit_timeout(unsigned long * word,int bit,unsigned mode,int timo)27737f4dd379Sjsg wait_on_bit_timeout(unsigned long *word, int bit, unsigned mode, int timo)
27747f4dd379Sjsg {
27757f4dd379Sjsg 	int err;
27767f4dd379Sjsg 
27777f4dd379Sjsg 	if (!test_bit(bit, word))
27787f4dd379Sjsg 		return 0;
27797f4dd379Sjsg 
27807f4dd379Sjsg 	mtx_enter(&wait_bit_mtx);
27817f4dd379Sjsg 	while (test_bit(bit, word)) {
27827f4dd379Sjsg 		err = msleep(word, &wait_bit_mtx, PWAIT | mode, "wtb", timo);
27837f4dd379Sjsg 		if (err) {
27847f4dd379Sjsg 			mtx_leave(&wait_bit_mtx);
27857f4dd379Sjsg 			return 1;
27867f4dd379Sjsg 		}
27877f4dd379Sjsg 	}
27887f4dd379Sjsg 	mtx_leave(&wait_bit_mtx);
27897f4dd379Sjsg 	return 0;
27907f4dd379Sjsg }
27917f4dd379Sjsg 
27927f4dd379Sjsg void
wake_up_bit(void * word,int bit)27937f4dd379Sjsg wake_up_bit(void *word, int bit)
27947f4dd379Sjsg {
27957f4dd379Sjsg 	mtx_enter(&wait_bit_mtx);
27967f4dd379Sjsg 	wakeup(word);
27977f4dd379Sjsg 	mtx_leave(&wait_bit_mtx);
27987f4dd379Sjsg }
27997f4dd379Sjsg 
2800c349dbc7Sjsg void
clear_and_wake_up_bit(int bit,void * word)2801c349dbc7Sjsg clear_and_wake_up_bit(int bit, void *word)
2802c349dbc7Sjsg {
2803c349dbc7Sjsg 	clear_bit(bit, word);
2804c349dbc7Sjsg 	wake_up_bit(word, bit);
2805c349dbc7Sjsg }
2806c349dbc7Sjsg 
2807c349dbc7Sjsg wait_queue_head_t *
bit_waitqueue(void * word,int bit)2808c349dbc7Sjsg bit_waitqueue(void *word, int bit)
2809c349dbc7Sjsg {
2810c349dbc7Sjsg 	/* XXX hash table of wait queues? */
2811c349dbc7Sjsg 	return &bit_waitq;
2812c349dbc7Sjsg }
2813c349dbc7Sjsg 
2814ad8b1aafSjsg wait_queue_head_t *
__var_waitqueue(void * p)2815ad8b1aafSjsg __var_waitqueue(void *p)
2816ad8b1aafSjsg {
2817ad8b1aafSjsg 	/* XXX hash table of wait queues? */
2818ad8b1aafSjsg 	return &bit_waitq;
2819ad8b1aafSjsg }
2820ad8b1aafSjsg 
28217f4dd379Sjsg struct workqueue_struct *system_wq;
2822c349dbc7Sjsg struct workqueue_struct *system_highpri_wq;
28237f4dd379Sjsg struct workqueue_struct *system_unbound_wq;
28247f4dd379Sjsg struct workqueue_struct *system_long_wq;
28257f4dd379Sjsg struct taskq *taskletq;
28267f4dd379Sjsg 
28277f4dd379Sjsg void
drm_linux_init(void)28287f4dd379Sjsg drm_linux_init(void)
28297f4dd379Sjsg {
28307f4dd379Sjsg 	system_wq = (struct workqueue_struct *)
2831ae8374b9Skettenis 	    taskq_create("drmwq", 4, IPL_HIGH, 0);
2832c349dbc7Sjsg 	system_highpri_wq = (struct workqueue_struct *)
2833c349dbc7Sjsg 	    taskq_create("drmhpwq", 4, IPL_HIGH, 0);
28347f4dd379Sjsg 	system_unbound_wq = (struct workqueue_struct *)
2835ae8374b9Skettenis 	    taskq_create("drmubwq", 4, IPL_HIGH, 0);
28367f4dd379Sjsg 	system_long_wq = (struct workqueue_struct *)
2837ae8374b9Skettenis 	    taskq_create("drmlwq", 4, IPL_HIGH, 0);
28387f4dd379Sjsg 
28397f4dd379Sjsg 	taskletq = taskq_create("drmtskl", 1, IPL_HIGH, 0);
2840c349dbc7Sjsg 
2841c349dbc7Sjsg 	init_waitqueue_head(&bit_waitq);
2842c349dbc7Sjsg 	init_waitqueue_head(&var_waitq);
2843601770a2Skettenis 
2844601770a2Skettenis 	pool_init(&idr_pool, sizeof(struct idr_entry), 0, IPL_TTY, 0,
2845601770a2Skettenis 	    "idrpl", NULL);
284649a189d2Skettenis 
284749a189d2Skettenis 	kmap_atomic_va =
284849a189d2Skettenis 	    (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_waitok);
2849601770a2Skettenis }
2850601770a2Skettenis 
2851601770a2Skettenis void
drm_linux_exit(void)2852601770a2Skettenis drm_linux_exit(void)
2853601770a2Skettenis {
2854601770a2Skettenis 	pool_destroy(&idr_pool);
2855601770a2Skettenis 
2856601770a2Skettenis 	taskq_destroy(taskletq);
2857601770a2Skettenis 
2858601770a2Skettenis 	taskq_destroy((struct taskq *)system_long_wq);
2859601770a2Skettenis 	taskq_destroy((struct taskq *)system_unbound_wq);
2860601770a2Skettenis 	taskq_destroy((struct taskq *)system_highpri_wq);
2861601770a2Skettenis 	taskq_destroy((struct taskq *)system_wq);
28627f4dd379Sjsg }
28637f4dd379Sjsg 
28647f4dd379Sjsg #define PCIE_ECAP_RESIZE_BAR	0x15
28657f4dd379Sjsg #define RBCAP0			0x04
28667f4dd379Sjsg #define RBCTRL0			0x08
28677f4dd379Sjsg #define RBCTRL_BARINDEX_MASK	0x07
28687f4dd379Sjsg #define RBCTRL_BARSIZE_MASK	0x1f00
28697f4dd379Sjsg #define RBCTRL_BARSIZE_SHIFT	8
28707f4dd379Sjsg 
28717f4dd379Sjsg /* size in MB is 1 << nsize */
28727f4dd379Sjsg int
pci_resize_resource(struct pci_dev * pdev,int bar,int nsize)28737f4dd379Sjsg pci_resize_resource(struct pci_dev *pdev, int bar, int nsize)
28747f4dd379Sjsg {
28757f4dd379Sjsg 	pcireg_t	reg;
28767f4dd379Sjsg 	uint32_t	offset, capid;
28777f4dd379Sjsg 
28787f4dd379Sjsg 	KASSERT(bar == 0);
28797f4dd379Sjsg 
28807f4dd379Sjsg 	offset = PCI_PCIE_ECAP;
28817f4dd379Sjsg 
28827f4dd379Sjsg 	/* search PCI Express Extended Capabilities */
28837f4dd379Sjsg 	do {
28847f4dd379Sjsg 		reg = pci_conf_read(pdev->pc, pdev->tag, offset);
28857f4dd379Sjsg 		capid = PCI_PCIE_ECAP_ID(reg);
28867f4dd379Sjsg 		if (capid == PCIE_ECAP_RESIZE_BAR)
28877f4dd379Sjsg 			break;
28887f4dd379Sjsg 		offset = PCI_PCIE_ECAP_NEXT(reg);
28897f4dd379Sjsg 	} while (capid != 0);
28907f4dd379Sjsg 
28917f4dd379Sjsg 	if (capid == 0) {
28927f4dd379Sjsg 		printf("%s: could not find resize bar cap!\n", __func__);
28937f4dd379Sjsg 		return -ENOTSUP;
28947f4dd379Sjsg 	}
28957f4dd379Sjsg 
28967f4dd379Sjsg 	reg = pci_conf_read(pdev->pc, pdev->tag, offset + RBCAP0);
28977f4dd379Sjsg 
28987f4dd379Sjsg 	if ((reg & (1 << (nsize + 4))) == 0) {
28997f4dd379Sjsg 		printf("%s size not supported\n", __func__);
29007f4dd379Sjsg 		return -ENOTSUP;
29017f4dd379Sjsg 	}
29027f4dd379Sjsg 
29037f4dd379Sjsg 	reg = pci_conf_read(pdev->pc, pdev->tag, offset + RBCTRL0);
29047f4dd379Sjsg 	if ((reg & RBCTRL_BARINDEX_MASK) != 0) {
29057f4dd379Sjsg 		printf("%s BAR index not 0\n", __func__);
29067f4dd379Sjsg 		return -EINVAL;
29077f4dd379Sjsg 	}
29087f4dd379Sjsg 
29097f4dd379Sjsg 	reg &= ~RBCTRL_BARSIZE_MASK;
29107f4dd379Sjsg 	reg |= (nsize << RBCTRL_BARSIZE_SHIFT) & RBCTRL_BARSIZE_MASK;
29117f4dd379Sjsg 
29127f4dd379Sjsg 	pci_conf_write(pdev->pc, pdev->tag, offset + RBCTRL0, reg);
29137f4dd379Sjsg 
29147f4dd379Sjsg 	return 0;
29157f4dd379Sjsg }
2916a4e118acSkettenis 
2917a4e118acSkettenis TAILQ_HEAD(, shrinker) shrinkers = TAILQ_HEAD_INITIALIZER(shrinkers);
2918a4e118acSkettenis 
2919a4e118acSkettenis int
register_shrinker(struct shrinker * shrinker,const char * format,...)29201bb76ff1Sjsg register_shrinker(struct shrinker *shrinker, const char *format, ...)
2921a4e118acSkettenis {
2922a4e118acSkettenis 	TAILQ_INSERT_TAIL(&shrinkers, shrinker, next);
2923a4e118acSkettenis 	return 0;
2924a4e118acSkettenis }
2925a4e118acSkettenis 
2926a4e118acSkettenis void
unregister_shrinker(struct shrinker * shrinker)29273990936dSjsg unregister_shrinker(struct shrinker *shrinker)
29283990936dSjsg {
29293990936dSjsg 	TAILQ_REMOVE(&shrinkers, shrinker, next);
29303990936dSjsg }
29313990936dSjsg 
29323990936dSjsg void
drmbackoff(long npages)2933a4e118acSkettenis drmbackoff(long npages)
2934a4e118acSkettenis {
2935a4e118acSkettenis 	struct shrink_control sc;
2936a4e118acSkettenis 	struct shrinker *shrinker;
2937a4e118acSkettenis 	u_long ret;
2938a4e118acSkettenis 
2939a4e118acSkettenis 	shrinker = TAILQ_FIRST(&shrinkers);
2940a4e118acSkettenis 	while (shrinker && npages > 0) {
2941a4e118acSkettenis 		sc.nr_to_scan = npages;
2942a4e118acSkettenis 		ret = shrinker->scan_objects(shrinker, &sc);
2943a4e118acSkettenis 		npages -= ret;
2944a4e118acSkettenis 		shrinker = TAILQ_NEXT(shrinker, next);
2945a4e118acSkettenis 	}
2946a4e118acSkettenis }
2947c349dbc7Sjsg 
2948c349dbc7Sjsg void *
bitmap_zalloc(u_int n,gfp_t flags)2949c349dbc7Sjsg bitmap_zalloc(u_int n, gfp_t flags)
2950c349dbc7Sjsg {
2951c349dbc7Sjsg 	return kcalloc(BITS_TO_LONGS(n), sizeof(long), flags);
2952c349dbc7Sjsg }
2953c349dbc7Sjsg 
2954c349dbc7Sjsg void
bitmap_free(void * p)2955c349dbc7Sjsg bitmap_free(void *p)
2956c349dbc7Sjsg {
2957c349dbc7Sjsg 	kfree(p);
2958c349dbc7Sjsg }
2959c349dbc7Sjsg 
2960c349dbc7Sjsg int
atomic_dec_and_mutex_lock(volatile int * v,struct rwlock * lock)2961c349dbc7Sjsg atomic_dec_and_mutex_lock(volatile int *v, struct rwlock *lock)
2962c349dbc7Sjsg {
2963c349dbc7Sjsg 	if (atomic_add_unless(v, -1, 1))
2964c349dbc7Sjsg 		return 0;
2965c349dbc7Sjsg 
2966c349dbc7Sjsg 	rw_enter_write(lock);
2967c349dbc7Sjsg 	if (atomic_dec_return(v) == 0)
2968c349dbc7Sjsg 		return 1;
2969c349dbc7Sjsg 	rw_exit_write(lock);
2970c349dbc7Sjsg 	return 0;
2971c349dbc7Sjsg }
2972c349dbc7Sjsg 
2973c349dbc7Sjsg int
printk(const char * fmt,...)2974c349dbc7Sjsg printk(const char *fmt, ...)
2975c349dbc7Sjsg {
2976c349dbc7Sjsg 	int ret, level;
2977c349dbc7Sjsg 	va_list ap;
2978c349dbc7Sjsg 
2979c349dbc7Sjsg 	if (fmt != NULL && *fmt == '\001') {
2980c349dbc7Sjsg 		level = fmt[1];
2981c349dbc7Sjsg #ifndef DRMDEBUG
2982c349dbc7Sjsg 		if (level >= KERN_INFO[1] && level <= '9')
2983c349dbc7Sjsg 			return 0;
2984c349dbc7Sjsg #endif
2985c349dbc7Sjsg 		fmt += 2;
2986c349dbc7Sjsg 	}
2987c349dbc7Sjsg 
2988c349dbc7Sjsg 	va_start(ap, fmt);
2989c349dbc7Sjsg 	ret = vprintf(fmt, ap);
2990c349dbc7Sjsg 	va_end(ap);
2991c349dbc7Sjsg 
2992c349dbc7Sjsg 	return ret;
2993c349dbc7Sjsg }
2994cfaa6efeSjsg 
2995cfaa6efeSjsg #define START(node) ((node)->start)
2996cfaa6efeSjsg #define LAST(node) ((node)->last)
2997cfaa6efeSjsg 
2998cfaa6efeSjsg struct interval_tree_node *
interval_tree_iter_first(struct rb_root_cached * root,unsigned long start,unsigned long last)2999cfaa6efeSjsg interval_tree_iter_first(struct rb_root_cached *root, unsigned long start,
3000cfaa6efeSjsg     unsigned long last)
3001cfaa6efeSjsg {
3002cfaa6efeSjsg 	struct interval_tree_node *node;
3003cfaa6efeSjsg 	struct rb_node *rb;
3004cfaa6efeSjsg 
3005cfaa6efeSjsg 	for (rb = rb_first_cached(root); rb; rb = rb_next(rb)) {
3006cfaa6efeSjsg 		node = rb_entry(rb, typeof(*node), rb);
3007cfaa6efeSjsg 		if (LAST(node) >= start && START(node) <= last)
3008cfaa6efeSjsg 			return node;
3009cfaa6efeSjsg 	}
3010cfaa6efeSjsg 	return NULL;
3011cfaa6efeSjsg }
3012cfaa6efeSjsg 
3013cfaa6efeSjsg void
interval_tree_remove(struct interval_tree_node * node,struct rb_root_cached * root)3014cfaa6efeSjsg interval_tree_remove(struct interval_tree_node *node,
3015cfaa6efeSjsg     struct rb_root_cached *root)
3016cfaa6efeSjsg {
3017cfaa6efeSjsg 	rb_erase_cached(&node->rb, root);
3018cfaa6efeSjsg }
3019cfaa6efeSjsg 
3020cfaa6efeSjsg void
interval_tree_insert(struct interval_tree_node * node,struct rb_root_cached * root)3021cfaa6efeSjsg interval_tree_insert(struct interval_tree_node *node,
3022cfaa6efeSjsg     struct rb_root_cached *root)
3023cfaa6efeSjsg {
3024cfaa6efeSjsg 	struct rb_node **iter = &root->rb_root.rb_node;
3025cfaa6efeSjsg 	struct rb_node *parent = NULL;
3026cfaa6efeSjsg 	struct interval_tree_node *iter_node;
3027cfaa6efeSjsg 
3028cfaa6efeSjsg 	while (*iter) {
3029cfaa6efeSjsg 		parent = *iter;
3030cfaa6efeSjsg 		iter_node = rb_entry(*iter, struct interval_tree_node, rb);
3031cfaa6efeSjsg 
3032cfaa6efeSjsg 		if (node->start < iter_node->start)
3033cfaa6efeSjsg 			iter = &(*iter)->rb_left;
3034cfaa6efeSjsg 		else
3035cfaa6efeSjsg 			iter = &(*iter)->rb_right;
3036cfaa6efeSjsg 	}
3037cfaa6efeSjsg 
3038cfaa6efeSjsg 	rb_link_node(&node->rb, parent, iter);
3039cfaa6efeSjsg 	rb_insert_color_cached(&node->rb, root, false);
3040cfaa6efeSjsg }
304161c1bba6Sjsg 
304261c1bba6Sjsg int
syncfile_read(struct file * fp,struct uio * uio,int fflags)304361c1bba6Sjsg syncfile_read(struct file *fp, struct uio *uio, int fflags)
304461c1bba6Sjsg {
304561c1bba6Sjsg 	return ENXIO;
304661c1bba6Sjsg }
304761c1bba6Sjsg 
304861c1bba6Sjsg int
syncfile_write(struct file * fp,struct uio * uio,int fflags)304961c1bba6Sjsg syncfile_write(struct file *fp, struct uio *uio, int fflags)
305061c1bba6Sjsg {
305161c1bba6Sjsg 	return ENXIO;
305261c1bba6Sjsg }
305361c1bba6Sjsg 
305461c1bba6Sjsg int
syncfile_ioctl(struct file * fp,u_long com,caddr_t data,struct proc * p)305561c1bba6Sjsg syncfile_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
305661c1bba6Sjsg {
305761c1bba6Sjsg 	return ENOTTY;
305861c1bba6Sjsg }
305961c1bba6Sjsg 
306061c1bba6Sjsg int
syncfile_kqfilter(struct file * fp,struct knote * kn)306161c1bba6Sjsg syncfile_kqfilter(struct file *fp, struct knote *kn)
306261c1bba6Sjsg {
306361c1bba6Sjsg 	return EINVAL;
306461c1bba6Sjsg }
306561c1bba6Sjsg 
306661c1bba6Sjsg int
syncfile_stat(struct file * fp,struct stat * st,struct proc * p)306761c1bba6Sjsg syncfile_stat(struct file *fp, struct stat *st, struct proc *p)
306861c1bba6Sjsg {
306961c1bba6Sjsg 	memset(st, 0, sizeof(*st));
307061c1bba6Sjsg 	st->st_mode = S_IFIFO;	/* XXX */
307161c1bba6Sjsg 	return 0;
307261c1bba6Sjsg }
307361c1bba6Sjsg 
307461c1bba6Sjsg int
syncfile_close(struct file * fp,struct proc * p)307561c1bba6Sjsg syncfile_close(struct file *fp, struct proc *p)
307661c1bba6Sjsg {
307761c1bba6Sjsg 	struct sync_file *sf = fp->f_data;
307861c1bba6Sjsg 
307961c1bba6Sjsg 	dma_fence_put(sf->fence);
308061c1bba6Sjsg 	fp->f_data = NULL;
308161c1bba6Sjsg 	free(sf, M_DRM, sizeof(struct sync_file));
308261c1bba6Sjsg 	return 0;
308361c1bba6Sjsg }
308461c1bba6Sjsg 
308561c1bba6Sjsg int
syncfile_seek(struct file * fp,off_t * offset,int whence,struct proc * p)308661c1bba6Sjsg syncfile_seek(struct file *fp, off_t *offset, int whence, struct proc *p)
308761c1bba6Sjsg {
308861c1bba6Sjsg 	off_t newoff;
308961c1bba6Sjsg 
309061c1bba6Sjsg 	if (*offset != 0)
309161c1bba6Sjsg 		return EINVAL;
309261c1bba6Sjsg 
309361c1bba6Sjsg 	switch (whence) {
309461c1bba6Sjsg 	case SEEK_SET:
309561c1bba6Sjsg 		newoff = 0;
309661c1bba6Sjsg 		break;
309761c1bba6Sjsg 	case SEEK_END:
309861c1bba6Sjsg 		newoff = 0;
309961c1bba6Sjsg 		break;
310061c1bba6Sjsg 	default:
310161c1bba6Sjsg 		return EINVAL;
310261c1bba6Sjsg 	}
310361c1bba6Sjsg 	mtx_enter(&fp->f_mtx);
310461c1bba6Sjsg 	fp->f_offset = newoff;
310561c1bba6Sjsg 	mtx_leave(&fp->f_mtx);
310661c1bba6Sjsg 	*offset = newoff;
310761c1bba6Sjsg 	return 0;
310861c1bba6Sjsg }
310961c1bba6Sjsg 
311061c1bba6Sjsg const struct fileops syncfileops = {
311161c1bba6Sjsg 	.fo_read	= syncfile_read,
311261c1bba6Sjsg 	.fo_write	= syncfile_write,
311361c1bba6Sjsg 	.fo_ioctl	= syncfile_ioctl,
311461c1bba6Sjsg 	.fo_kqfilter	= syncfile_kqfilter,
311561c1bba6Sjsg 	.fo_stat	= syncfile_stat,
311661c1bba6Sjsg 	.fo_close	= syncfile_close,
311761c1bba6Sjsg 	.fo_seek	= syncfile_seek,
311861c1bba6Sjsg };
311961c1bba6Sjsg 
312061c1bba6Sjsg void
fd_install(int fd,struct file * fp)312161c1bba6Sjsg fd_install(int fd, struct file *fp)
312261c1bba6Sjsg {
312361c1bba6Sjsg 	struct proc *p = curproc;
312461c1bba6Sjsg 	struct filedesc *fdp = p->p_fd;
312561c1bba6Sjsg 
312661c1bba6Sjsg 	if (fp->f_type != DTYPE_SYNC)
312761c1bba6Sjsg 		return;
312861c1bba6Sjsg 
312961c1bba6Sjsg 	fdplock(fdp);
313061c1bba6Sjsg 	/* all callers use get_unused_fd_flags(O_CLOEXEC) */
313161c1bba6Sjsg 	fdinsert(fdp, fd, UF_EXCLOSE, fp);
313261c1bba6Sjsg 	fdpunlock(fdp);
313361c1bba6Sjsg }
313461c1bba6Sjsg 
313561c1bba6Sjsg void
fput(struct file * fp)313661c1bba6Sjsg fput(struct file *fp)
313761c1bba6Sjsg {
313861c1bba6Sjsg 	if (fp->f_type != DTYPE_SYNC)
313961c1bba6Sjsg 		return;
314061c1bba6Sjsg 
314161c1bba6Sjsg 	FRELE(fp, curproc);
314261c1bba6Sjsg }
314361c1bba6Sjsg 
314461c1bba6Sjsg int
get_unused_fd_flags(unsigned int flags)314561c1bba6Sjsg get_unused_fd_flags(unsigned int flags)
314661c1bba6Sjsg {
314761c1bba6Sjsg 	struct proc *p = curproc;
314861c1bba6Sjsg 	struct filedesc *fdp = p->p_fd;
314961c1bba6Sjsg 	int error, fd;
315061c1bba6Sjsg 
315161c1bba6Sjsg 	KASSERT((flags & O_CLOEXEC) != 0);
315261c1bba6Sjsg 
315361c1bba6Sjsg 	fdplock(fdp);
315461c1bba6Sjsg retryalloc:
315561c1bba6Sjsg 	if ((error = fdalloc(p, 0, &fd)) != 0) {
315661c1bba6Sjsg 		if (error == ENOSPC) {
315761c1bba6Sjsg 			fdexpand(p);
315861c1bba6Sjsg 			goto retryalloc;
315961c1bba6Sjsg 		}
316061c1bba6Sjsg 		fdpunlock(fdp);
316161c1bba6Sjsg 		return -1;
316261c1bba6Sjsg 	}
316361c1bba6Sjsg 	fdpunlock(fdp);
316461c1bba6Sjsg 
316561c1bba6Sjsg 	return fd;
316661c1bba6Sjsg }
316761c1bba6Sjsg 
316861c1bba6Sjsg void
put_unused_fd(int fd)316961c1bba6Sjsg put_unused_fd(int fd)
317061c1bba6Sjsg {
317161c1bba6Sjsg 	struct filedesc *fdp = curproc->p_fd;
317261c1bba6Sjsg 
317361c1bba6Sjsg 	fdplock(fdp);
317461c1bba6Sjsg 	fdremove(fdp, fd);
317561c1bba6Sjsg 	fdpunlock(fdp);
317661c1bba6Sjsg }
317761c1bba6Sjsg 
317861c1bba6Sjsg struct dma_fence *
sync_file_get_fence(int fd)317961c1bba6Sjsg sync_file_get_fence(int fd)
318061c1bba6Sjsg {
318161c1bba6Sjsg 	struct proc *p = curproc;
318261c1bba6Sjsg 	struct filedesc *fdp = p->p_fd;
318361c1bba6Sjsg 	struct file *fp;
318461c1bba6Sjsg 	struct sync_file *sf;
318561c1bba6Sjsg 	struct dma_fence *f;
318661c1bba6Sjsg 
318761c1bba6Sjsg 	if ((fp = fd_getfile(fdp, fd)) == NULL)
318861c1bba6Sjsg 		return NULL;
318961c1bba6Sjsg 
319061c1bba6Sjsg 	if (fp->f_type != DTYPE_SYNC) {
319161c1bba6Sjsg 		FRELE(fp, p);
319261c1bba6Sjsg 		return NULL;
319361c1bba6Sjsg 	}
319461c1bba6Sjsg 	sf = fp->f_data;
319561c1bba6Sjsg 	f = dma_fence_get(sf->fence);
319661c1bba6Sjsg 	FRELE(sf->file, p);
319761c1bba6Sjsg 	return f;
319861c1bba6Sjsg }
319961c1bba6Sjsg 
320061c1bba6Sjsg struct sync_file *
sync_file_create(struct dma_fence * fence)320161c1bba6Sjsg sync_file_create(struct dma_fence *fence)
320261c1bba6Sjsg {
320361c1bba6Sjsg 	struct proc *p = curproc;
320461c1bba6Sjsg 	struct sync_file *sf;
320561c1bba6Sjsg 	struct file *fp;
320661c1bba6Sjsg 
320761c1bba6Sjsg 	fp = fnew(p);
320861c1bba6Sjsg 	if (fp == NULL)
320961c1bba6Sjsg 		return NULL;
321061c1bba6Sjsg 	fp->f_type = DTYPE_SYNC;
321161c1bba6Sjsg 	fp->f_ops = &syncfileops;
321261c1bba6Sjsg 	sf = malloc(sizeof(struct sync_file), M_DRM, M_WAITOK | M_ZERO);
321361c1bba6Sjsg 	sf->file = fp;
321461c1bba6Sjsg 	sf->fence = dma_fence_get(fence);
321561c1bba6Sjsg 	fp->f_data = sf;
321661c1bba6Sjsg 	return sf;
321761c1bba6Sjsg }
32181bb76ff1Sjsg 
32191bb76ff1Sjsg bool
drm_firmware_drivers_only(void)32201bb76ff1Sjsg drm_firmware_drivers_only(void)
32211bb76ff1Sjsg {
32221bb76ff1Sjsg 	return false;
32231bb76ff1Sjsg }
3224667382c7Skettenis 
3225667382c7Skettenis 
3226667382c7Skettenis void *
memremap(phys_addr_t phys_addr,size_t size,int flags)3227667382c7Skettenis memremap(phys_addr_t phys_addr, size_t size, int flags)
3228667382c7Skettenis {
3229667382c7Skettenis 	STUB();
3230667382c7Skettenis 	return NULL;
3231667382c7Skettenis }
3232667382c7Skettenis 
3233667382c7Skettenis void
memunmap(void * addr)3234667382c7Skettenis memunmap(void *addr)
3235667382c7Skettenis {
3236667382c7Skettenis 	STUB();
3237667382c7Skettenis }
3238667382c7Skettenis 
3239667382c7Skettenis #include <linux/platform_device.h>
3240667382c7Skettenis 
3241667382c7Skettenis bus_dma_tag_t
dma_tag_lookup(struct device * dev)3242667382c7Skettenis dma_tag_lookup(struct device *dev)
3243667382c7Skettenis {
3244667382c7Skettenis 	extern struct cfdriver drm_cd;
3245667382c7Skettenis 	struct drm_device *drm;
3246667382c7Skettenis 	int i;
3247667382c7Skettenis 
3248667382c7Skettenis 	for (i = 0; i < drm_cd.cd_ndevs; i++) {
3249667382c7Skettenis 		drm = drm_cd.cd_devs[i];
3250667382c7Skettenis 		if (drm && drm->dev == dev)
3251667382c7Skettenis 			return drm->dmat;
3252667382c7Skettenis 	}
3253667382c7Skettenis 
3254667382c7Skettenis 	return ((struct platform_device *)dev)->dmat;
3255667382c7Skettenis }
3256667382c7Skettenis 
3257667382c7Skettenis LIST_HEAD(, drm_dmamem) dmamem_list = LIST_HEAD_INITIALIZER(dmamem_list);
3258667382c7Skettenis 
3259667382c7Skettenis void *
dma_alloc_coherent(struct device * dev,size_t size,dma_addr_t * dma_handle,int gfp)3260667382c7Skettenis dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
3261667382c7Skettenis     int gfp)
3262667382c7Skettenis {
3263667382c7Skettenis 	bus_dma_tag_t dmat = dma_tag_lookup(dev);
3264667382c7Skettenis 	struct drm_dmamem *mem;
3265667382c7Skettenis 
3266667382c7Skettenis 	mem = drm_dmamem_alloc(dmat, size, PAGE_SIZE, 1, size,
3267667382c7Skettenis 	    BUS_DMA_COHERENT, 0);
3268667382c7Skettenis 	if (mem == NULL)
3269667382c7Skettenis 		return NULL;
3270667382c7Skettenis 	*dma_handle = mem->map->dm_segs[0].ds_addr;
3271667382c7Skettenis 	LIST_INSERT_HEAD(&dmamem_list, mem, next);
3272667382c7Skettenis 	return mem->kva;
3273667382c7Skettenis }
3274667382c7Skettenis 
3275667382c7Skettenis void
dma_free_coherent(struct device * dev,size_t size,void * cpu_addr,dma_addr_t dma_handle)3276667382c7Skettenis dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
3277667382c7Skettenis     dma_addr_t dma_handle)
3278667382c7Skettenis {
3279667382c7Skettenis 	bus_dma_tag_t dmat = dma_tag_lookup(dev);
3280667382c7Skettenis 	struct drm_dmamem *mem;
3281667382c7Skettenis 
3282667382c7Skettenis 	LIST_FOREACH(mem, &dmamem_list, next) {
3283667382c7Skettenis 		if (mem->kva == cpu_addr)
3284667382c7Skettenis 			break;
3285667382c7Skettenis 	}
3286667382c7Skettenis 	KASSERT(mem);
3287667382c7Skettenis 	KASSERT(mem->size == size);
3288667382c7Skettenis 	KASSERT(mem->map->dm_segs[0].ds_addr == dma_handle);
3289667382c7Skettenis 
3290667382c7Skettenis 	LIST_REMOVE(mem, next);
3291667382c7Skettenis 	drm_dmamem_free(dmat, mem);
3292667382c7Skettenis }
3293667382c7Skettenis 
3294667382c7Skettenis int
dma_get_sgtable(struct device * dev,struct sg_table * sgt,void * cpu_addr,dma_addr_t dma_addr,size_t size)3295667382c7Skettenis dma_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr,
3296667382c7Skettenis     dma_addr_t dma_addr, size_t size)
3297667382c7Skettenis {
3298667382c7Skettenis 	paddr_t pa;
3299667382c7Skettenis 	int ret;
3300667382c7Skettenis 
3301667382c7Skettenis 	if (!pmap_extract(pmap_kernel(), (vaddr_t)cpu_addr, &pa))
3302667382c7Skettenis 		return -EINVAL;
3303667382c7Skettenis 
3304667382c7Skettenis 	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
3305667382c7Skettenis 	if (ret)
3306667382c7Skettenis 		return ret;
3307667382c7Skettenis 
3308667382c7Skettenis 	sg_set_page(sgt->sgl, PHYS_TO_VM_PAGE(pa), size, 0);
3309667382c7Skettenis 	return 0;
3310667382c7Skettenis }
3311667382c7Skettenis 
3312667382c7Skettenis dma_addr_t
dma_map_resource(struct device * dev,phys_addr_t phys_addr,size_t size,enum dma_data_direction dir,u_long attr)3313667382c7Skettenis dma_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size,
3314667382c7Skettenis     enum dma_data_direction dir, u_long attr)
3315667382c7Skettenis {
3316667382c7Skettenis 	bus_dma_tag_t dmat= dma_tag_lookup(dev);
3317667382c7Skettenis 	bus_dmamap_t map;
3318667382c7Skettenis 	bus_dma_segment_t seg;
3319667382c7Skettenis 
3320667382c7Skettenis 	if (bus_dmamap_create(dmat, size, 1, size, 0,
3321667382c7Skettenis 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &map))
3322667382c7Skettenis 		return DMA_MAPPING_ERROR;
3323667382c7Skettenis 	seg.ds_addr = phys_addr;
3324667382c7Skettenis 	seg.ds_len = size;
3325667382c7Skettenis 	if (bus_dmamap_load_raw(dmat, map, &seg, 1, size, BUS_DMA_WAITOK)) {
3326667382c7Skettenis 		bus_dmamap_destroy(dmat, map);
3327667382c7Skettenis 		return DMA_MAPPING_ERROR;
3328667382c7Skettenis 	}
3329667382c7Skettenis 
3330667382c7Skettenis 	return map->dm_segs[0].ds_addr;
3331667382c7Skettenis }
3332667382c7Skettenis 
3333667382c7Skettenis #ifdef BUS_DMA_FIXED
3334667382c7Skettenis 
3335667382c7Skettenis #include <linux/iommu.h>
3336667382c7Skettenis 
3337667382c7Skettenis size_t
iommu_map_sgtable(struct iommu_domain * domain,u_long iova,struct sg_table * sgt,int prot)3338667382c7Skettenis iommu_map_sgtable(struct iommu_domain *domain, u_long iova,
3339667382c7Skettenis     struct sg_table *sgt, int prot)
3340667382c7Skettenis {
3341667382c7Skettenis 	bus_dma_segment_t seg;
3342667382c7Skettenis 	int error;
3343667382c7Skettenis 
3344667382c7Skettenis 	error = bus_dmamap_create(domain->dmat, sgt->sgl->length, 1,
3345667382c7Skettenis 	    sgt->sgl->length, 0, BUS_DMA_WAITOK, &sgt->dmamap);
3346667382c7Skettenis 	if (error)
3347667382c7Skettenis 		return -ENOMEM;
3348667382c7Skettenis 
3349667382c7Skettenis 	sgt->dmamap->dm_segs[0].ds_addr = iova;
3350667382c7Skettenis 	sgt->dmamap->dm_segs[0].ds_len = sgt->sgl->length;
3351667382c7Skettenis 	sgt->dmamap->dm_nsegs = 1;
3352667382c7Skettenis 	seg.ds_addr = VM_PAGE_TO_PHYS(sgt->sgl->__page);
3353667382c7Skettenis 	seg.ds_len = sgt->sgl->length;
3354667382c7Skettenis 	error = bus_dmamap_load_raw(domain->dmat, sgt->dmamap, &seg, 1,
3355667382c7Skettenis 	    sgt->sgl->length, BUS_DMA_WAITOK | BUS_DMA_FIXED);
3356667382c7Skettenis 	if (error)
3357667382c7Skettenis 		return -ENOMEM;
3358667382c7Skettenis 
3359667382c7Skettenis 	return sg_dma_len(sgt->sgl);
3360667382c7Skettenis }
3361667382c7Skettenis 
3362667382c7Skettenis size_t
iommu_unmap(struct iommu_domain * domain,u_long iova,size_t size)3363667382c7Skettenis iommu_unmap(struct iommu_domain *domain, u_long iova, size_t size)
3364667382c7Skettenis {
3365667382c7Skettenis 	STUB();
3366667382c7Skettenis 	return 0;
3367667382c7Skettenis }
3368667382c7Skettenis 
3369667382c7Skettenis struct iommu_domain *
iommu_get_domain_for_dev(struct device * dev)3370667382c7Skettenis iommu_get_domain_for_dev(struct device *dev)
3371667382c7Skettenis {
3372667382c7Skettenis 	STUB();
3373667382c7Skettenis 	return NULL;
3374667382c7Skettenis }
3375667382c7Skettenis 
3376667382c7Skettenis phys_addr_t
iommu_iova_to_phys(struct iommu_domain * domain,dma_addr_t iova)3377667382c7Skettenis iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
3378667382c7Skettenis {
3379667382c7Skettenis 	STUB();
3380667382c7Skettenis 	return 0;
3381667382c7Skettenis }
3382667382c7Skettenis 
3383667382c7Skettenis struct iommu_domain *
iommu_domain_alloc(struct bus_type * type)3384667382c7Skettenis iommu_domain_alloc(struct bus_type *type)
3385667382c7Skettenis {
3386667382c7Skettenis 	return malloc(sizeof(struct iommu_domain), M_DEVBUF, M_WAITOK | M_ZERO);
3387667382c7Skettenis }
3388667382c7Skettenis 
3389667382c7Skettenis int
iommu_attach_device(struct iommu_domain * domain,struct device * dev)3390667382c7Skettenis iommu_attach_device(struct iommu_domain *domain, struct device *dev)
3391667382c7Skettenis {
3392667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3393667382c7Skettenis 
3394667382c7Skettenis 	domain->dmat = pdev->dmat;
3395667382c7Skettenis 	return 0;
3396667382c7Skettenis }
3397667382c7Skettenis 
3398667382c7Skettenis #endif
3399667382c7Skettenis 
3400667382c7Skettenis #include <linux/component.h>
3401667382c7Skettenis 
3402cefff6e5Skettenis struct component {
3403667382c7Skettenis 	struct device *dev;
3404cefff6e5Skettenis 	struct device *adev;
3405cefff6e5Skettenis 	const struct component_ops *ops;
3406cefff6e5Skettenis 	SLIST_ENTRY(component) next;
3407667382c7Skettenis };
3408667382c7Skettenis 
3409cefff6e5Skettenis SLIST_HEAD(,component) component_list = SLIST_HEAD_INITIALIZER(component_list);
3410cefff6e5Skettenis 
3411667382c7Skettenis int
component_add(struct device * dev,const struct component_ops * ops)3412cefff6e5Skettenis component_add(struct device *dev, const struct component_ops *ops)
3413667382c7Skettenis {
3414cefff6e5Skettenis 	struct component *component;
3415cefff6e5Skettenis 
3416cefff6e5Skettenis 	component = malloc(sizeof(*component), M_DEVBUF, M_WAITOK | M_ZERO);
3417cefff6e5Skettenis 	component->dev = dev;
3418cefff6e5Skettenis 	component->ops = ops;
3419cefff6e5Skettenis 	SLIST_INSERT_HEAD(&component_list, component, next);
3420667382c7Skettenis 	return 0;
3421667382c7Skettenis }
3422667382c7Skettenis 
3423cefff6e5Skettenis int
component_add_typed(struct device * dev,const struct component_ops * ops,int type)3424f005ef32Sjsg component_add_typed(struct device *dev, const struct component_ops *ops,
3425f005ef32Sjsg 	int type)
3426f005ef32Sjsg {
3427f005ef32Sjsg 	return component_add(dev, ops);
3428f005ef32Sjsg }
3429f005ef32Sjsg 
3430f005ef32Sjsg int
component_bind_all(struct device * dev,void * data)3431cefff6e5Skettenis component_bind_all(struct device *dev, void *data)
3432667382c7Skettenis {
3433cefff6e5Skettenis 	struct component *component;
3434cefff6e5Skettenis 	int ret = 0;
3435667382c7Skettenis 
3436cefff6e5Skettenis 	SLIST_FOREACH(component, &component_list, next) {
3437cefff6e5Skettenis 		if (component->adev == dev) {
3438cefff6e5Skettenis 			ret = component->ops->bind(component->dev, NULL, data);
3439cefff6e5Skettenis 			if (ret)
3440cefff6e5Skettenis 				break;
3441667382c7Skettenis 		}
3442667382c7Skettenis 	}
3443667382c7Skettenis 
3444cefff6e5Skettenis 	return ret;
3445cefff6e5Skettenis }
3446cefff6e5Skettenis 
34475fde6622Skettenis struct component_match_entry {
3448cefff6e5Skettenis 	int (*compare)(struct device *, void *);
3449cefff6e5Skettenis 	void *data;
3450cefff6e5Skettenis };
3451cefff6e5Skettenis 
34525fde6622Skettenis struct component_match {
34535fde6622Skettenis 	struct component_match_entry match[4];
34545fde6622Skettenis 	int nmatches;
34555fde6622Skettenis };
34565fde6622Skettenis 
3457667382c7Skettenis int
component_master_add_with_match(struct device * dev,const struct component_master_ops * ops,struct component_match * match)3458667382c7Skettenis component_master_add_with_match(struct device *dev,
3459667382c7Skettenis     const struct component_master_ops *ops, struct component_match *match)
3460667382c7Skettenis {
3461cefff6e5Skettenis 	struct component *component;
3462cefff6e5Skettenis 	int found = 0;
34635fde6622Skettenis 	int i, ret;
3464cefff6e5Skettenis 
3465cefff6e5Skettenis 	SLIST_FOREACH(component, &component_list, next) {
34665fde6622Skettenis 		for (i = 0; i < match->nmatches; i++) {
34675fde6622Skettenis 			struct component_match_entry *m = &match->match[i];
34685fde6622Skettenis 			if (m->compare(component->dev, m->data)) {
3469cefff6e5Skettenis 				component->adev = dev;
3470cefff6e5Skettenis 				found = 1;
34715fde6622Skettenis 				break;
34725fde6622Skettenis 			}
3473cefff6e5Skettenis 		}
3474cefff6e5Skettenis 	}
3475cefff6e5Skettenis 
3476cefff6e5Skettenis 	if (found) {
3477cefff6e5Skettenis 		ret = ops->bind(dev);
3478cefff6e5Skettenis 		if (ret)
3479cefff6e5Skettenis 			return ret;
3480cefff6e5Skettenis 	}
3481cefff6e5Skettenis 
3482667382c7Skettenis 	return 0;
3483667382c7Skettenis }
3484667382c7Skettenis 
3485667382c7Skettenis #ifdef __HAVE_FDT
3486667382c7Skettenis 
3487667382c7Skettenis #include <linux/platform_device.h>
3488667382c7Skettenis #include <dev/ofw/openfirm.h>
3489667382c7Skettenis #include <dev/ofw/fdt.h>
3490667382c7Skettenis #include <machine/fdt.h>
3491667382c7Skettenis 
3492667382c7Skettenis LIST_HEAD(, platform_device) pdev_list = LIST_HEAD_INITIALIZER(pdev_list);
3493667382c7Skettenis 
3494667382c7Skettenis void
platform_device_register(struct platform_device * pdev)3495667382c7Skettenis platform_device_register(struct platform_device *pdev)
3496667382c7Skettenis {
3497cefff6e5Skettenis 	int i;
3498cefff6e5Skettenis 
3499667382c7Skettenis 	pdev->num_resources = pdev->faa->fa_nreg;
3500cefff6e5Skettenis 	if (pdev->faa->fa_nreg > 0) {
3501cefff6e5Skettenis 		pdev->resource = mallocarray(pdev->faa->fa_nreg,
3502cefff6e5Skettenis 		    sizeof(*pdev->resource), M_DEVBUF, M_WAITOK | M_ZERO);
3503cefff6e5Skettenis 		for (i = 0; i < pdev->faa->fa_nreg; i++) {
3504cefff6e5Skettenis 			pdev->resource[i].start = pdev->faa->fa_reg[i].addr;
3505cefff6e5Skettenis 			pdev->resource[i].end = pdev->faa->fa_reg[i].addr +
3506cefff6e5Skettenis 			    pdev->faa->fa_reg[i].size - 1;
3507cefff6e5Skettenis 		}
3508cefff6e5Skettenis 	}
3509667382c7Skettenis 
3510667382c7Skettenis 	pdev->parent = pdev->dev.dv_parent;
3511667382c7Skettenis 	pdev->node = pdev->faa->fa_node;
3512cefff6e5Skettenis 	pdev->iot = pdev->faa->fa_iot;
3513667382c7Skettenis 	pdev->dmat = pdev->faa->fa_dmat;
3514667382c7Skettenis 	LIST_INSERT_HEAD(&pdev_list, pdev, next);
3515667382c7Skettenis }
3516667382c7Skettenis 
3517667382c7Skettenis 
3518667382c7Skettenis struct resource *
platform_get_resource(struct platform_device * pdev,u_int type,u_int num)3519667382c7Skettenis platform_get_resource(struct platform_device *pdev, u_int type, u_int num)
3520667382c7Skettenis {
3521cefff6e5Skettenis 	KASSERT(num < pdev->num_resources);
3522667382c7Skettenis 	return &pdev->resource[num];
3523667382c7Skettenis }
3524667382c7Skettenis 
3525667382c7Skettenis void __iomem *
devm_platform_ioremap_resource_byname(struct platform_device * pdev,const char * name)3526667382c7Skettenis devm_platform_ioremap_resource_byname(struct platform_device *pdev,
3527667382c7Skettenis 				      const char *name)
3528667382c7Skettenis {
3529667382c7Skettenis 	bus_space_handle_t ioh;
3530667382c7Skettenis 	int err, idx;
3531667382c7Skettenis 
3532cefff6e5Skettenis 	idx = OF_getindex(pdev->node, name, "reg-names");
3533cefff6e5Skettenis 	if (idx == -1 || idx >= pdev->num_resources)
3534667382c7Skettenis 		return ERR_PTR(-EINVAL);
3535667382c7Skettenis 
3536cefff6e5Skettenis 	err = bus_space_map(pdev->iot, pdev->resource[idx].start,
3537cefff6e5Skettenis 	    pdev->resource[idx].end - pdev->resource[idx].start + 1,
3538cefff6e5Skettenis 	    BUS_SPACE_MAP_LINEAR, &ioh);
3539667382c7Skettenis 	if (err)
3540667382c7Skettenis 		return ERR_PTR(-err);
3541667382c7Skettenis 
3542cefff6e5Skettenis 	return bus_space_vaddr(pdev->iot, ioh);
3543667382c7Skettenis }
3544667382c7Skettenis 
3545667382c7Skettenis #include <dev/ofw/ofw_clock.h>
3546667382c7Skettenis #include <linux/clk.h>
3547667382c7Skettenis 
3548667382c7Skettenis struct clk *
devm_clk_get(struct device * dev,const char * name)3549667382c7Skettenis devm_clk_get(struct device *dev, const char *name)
3550667382c7Skettenis {
3551667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3552667382c7Skettenis 	struct clk *clk;
3553667382c7Skettenis 
3554667382c7Skettenis 	clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK);
3555667382c7Skettenis 	clk->freq = clock_get_frequency(pdev->node, name);
3556667382c7Skettenis 	return clk;
3557667382c7Skettenis }
3558667382c7Skettenis 
3559667382c7Skettenis u_long
clk_get_rate(struct clk * clk)3560667382c7Skettenis clk_get_rate(struct clk *clk)
3561667382c7Skettenis {
3562667382c7Skettenis 	return clk->freq;
3563667382c7Skettenis }
3564667382c7Skettenis 
3565667382c7Skettenis #include <linux/gpio/consumer.h>
3566667382c7Skettenis #include <dev/ofw/ofw_gpio.h>
3567667382c7Skettenis 
3568667382c7Skettenis struct gpio_desc {
3569667382c7Skettenis 	uint32_t gpios[4];
3570667382c7Skettenis };
3571667382c7Skettenis 
3572667382c7Skettenis struct gpio_desc *
devm_gpiod_get_optional(struct device * dev,const char * name,int flags)3573667382c7Skettenis devm_gpiod_get_optional(struct device *dev, const char *name, int flags)
3574667382c7Skettenis {
3575667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3576667382c7Skettenis 	struct gpio_desc *desc;
3577667382c7Skettenis 	char fullname[128];
3578667382c7Skettenis 	int len;
3579667382c7Skettenis 
3580667382c7Skettenis 	snprintf(fullname, sizeof(fullname), "%s-gpios", name);
3581667382c7Skettenis 
3582667382c7Skettenis 	desc = malloc(sizeof(*desc), M_DEVBUF, M_WAITOK | M_ZERO);
3583667382c7Skettenis 	len = OF_getpropintarray(pdev->node, fullname, desc->gpios,
3584667382c7Skettenis 	     sizeof(desc->gpios));
3585667382c7Skettenis 	KASSERT(len <= sizeof(desc->gpios));
3586667382c7Skettenis 	if (len < 0) {
3587667382c7Skettenis 		free(desc, M_DEVBUF, sizeof(*desc));
3588667382c7Skettenis 		return NULL;
3589667382c7Skettenis 	}
3590667382c7Skettenis 
3591667382c7Skettenis 	switch (flags) {
3592667382c7Skettenis 	case GPIOD_IN:
3593667382c7Skettenis 		gpio_controller_config_pin(desc->gpios, GPIO_CONFIG_INPUT);
3594667382c7Skettenis 		break;
3595667382c7Skettenis 	case GPIOD_OUT_HIGH:
3596667382c7Skettenis 		gpio_controller_config_pin(desc->gpios, GPIO_CONFIG_OUTPUT);
3597667382c7Skettenis 		gpio_controller_set_pin(desc->gpios, 1);
3598667382c7Skettenis 		break;
3599667382c7Skettenis 	default:
3600667382c7Skettenis 		panic("%s: unimplemented flags 0x%x", __func__, flags);
3601667382c7Skettenis 	}
3602667382c7Skettenis 
3603667382c7Skettenis 	return desc;
3604667382c7Skettenis }
3605667382c7Skettenis 
3606667382c7Skettenis int
gpiod_get_value_cansleep(const struct gpio_desc * desc)3607667382c7Skettenis gpiod_get_value_cansleep(const struct gpio_desc *desc)
3608667382c7Skettenis {
3609667382c7Skettenis 	return gpio_controller_get_pin(((struct gpio_desc *)desc)->gpios);
3610667382c7Skettenis }
3611667382c7Skettenis 
3612667382c7Skettenis struct phy {
3613667382c7Skettenis 	int node;
3614667382c7Skettenis 	const char *name;
3615667382c7Skettenis };
3616667382c7Skettenis 
3617667382c7Skettenis struct phy *
devm_phy_optional_get(struct device * dev,const char * name)3618667382c7Skettenis devm_phy_optional_get(struct device *dev, const char *name)
3619667382c7Skettenis {
3620667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3621667382c7Skettenis 	struct phy *phy;
3622667382c7Skettenis 	int idx;
3623667382c7Skettenis 
3624667382c7Skettenis 	idx = OF_getindex(pdev->node, name, "phy-names");
3625667382c7Skettenis 	if (idx == -1)
3626667382c7Skettenis 		return NULL;
3627667382c7Skettenis 
3628667382c7Skettenis 	phy = malloc(sizeof(*phy), M_DEVBUF, M_WAITOK);
3629667382c7Skettenis 	phy->node = pdev->node;
3630667382c7Skettenis 	phy->name = name;
3631667382c7Skettenis 
3632667382c7Skettenis 	return phy;
3633667382c7Skettenis }
3634667382c7Skettenis 
3635667382c7Skettenis struct bus_type platform_bus_type;
3636667382c7Skettenis 
3637667382c7Skettenis #include <dev/ofw/ofw_misc.h>
3638667382c7Skettenis 
3639667382c7Skettenis #include <linux/of.h>
3640667382c7Skettenis #include <linux/platform_device.h>
3641667382c7Skettenis 
3642667382c7Skettenis struct device_node *
__of_devnode(void * arg)3643667382c7Skettenis __of_devnode(void *arg)
3644667382c7Skettenis {
3645667382c7Skettenis 	struct device *dev = container_of(arg, struct device, of_node);
3646667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3647667382c7Skettenis 
3648667382c7Skettenis 	return (struct device_node *)(uintptr_t)pdev->node;
3649667382c7Skettenis }
3650667382c7Skettenis 
3651667382c7Skettenis int
__of_device_is_compatible(struct device_node * np,const char * compatible)3652667382c7Skettenis __of_device_is_compatible(struct device_node *np, const char *compatible)
3653667382c7Skettenis {
3654667382c7Skettenis 	return OF_is_compatible((uintptr_t)np, compatible);
3655667382c7Skettenis }
3656667382c7Skettenis 
3657667382c7Skettenis int
__of_property_present(struct device_node * np,const char * propname)3658667382c7Skettenis __of_property_present(struct device_node *np, const char *propname)
3659667382c7Skettenis {
3660667382c7Skettenis 	return OF_getpropbool((uintptr_t)np, (char *)propname);
3661667382c7Skettenis }
3662667382c7Skettenis 
3663667382c7Skettenis int
__of_property_read_variable_u32_array(struct device_node * np,const char * propname,uint32_t * out_values,size_t sz_min,size_t sz_max)3664667382c7Skettenis __of_property_read_variable_u32_array(struct device_node *np,
3665667382c7Skettenis     const char *propname, uint32_t *out_values, size_t sz_min, size_t sz_max)
3666667382c7Skettenis {
3667667382c7Skettenis 	int len;
3668667382c7Skettenis 
3669667382c7Skettenis 	len = OF_getpropintarray((uintptr_t)np, (char *)propname, out_values,
3670667382c7Skettenis 	    sz_max * sizeof(*out_values));
3671667382c7Skettenis 	if (len < 0)
3672667382c7Skettenis 		return -EINVAL;
3673667382c7Skettenis 	if (len == 0)
3674667382c7Skettenis 		return -ENODATA;
3675667382c7Skettenis 	if (len < sz_min * sizeof(*out_values) ||
3676667382c7Skettenis 	    len > sz_max * sizeof(*out_values))
3677667382c7Skettenis 		return -EOVERFLOW;
3678667382c7Skettenis 	if (sz_min == 1 && sz_max == 1)
3679667382c7Skettenis 		return 0;
3680667382c7Skettenis 	return len / sizeof(*out_values);
3681667382c7Skettenis }
3682667382c7Skettenis 
3683667382c7Skettenis int
__of_property_read_variable_u64_array(struct device_node * np,const char * propname,uint64_t * out_values,size_t sz_min,size_t sz_max)3684667382c7Skettenis __of_property_read_variable_u64_array(struct device_node *np,
3685667382c7Skettenis     const char *propname, uint64_t *out_values, size_t sz_min, size_t sz_max)
3686667382c7Skettenis {
3687667382c7Skettenis 	int len;
3688667382c7Skettenis 
3689667382c7Skettenis 	len = OF_getpropint64array((uintptr_t)np, (char *)propname, out_values,
3690667382c7Skettenis 	    sz_max * sizeof(*out_values));
3691667382c7Skettenis 	if (len < 0)
3692667382c7Skettenis 		return -EINVAL;
3693667382c7Skettenis 	if (len == 0)
3694667382c7Skettenis 		return -ENODATA;
3695667382c7Skettenis 	if (len < sz_min * sizeof(*out_values) ||
3696667382c7Skettenis 	    len > sz_max * sizeof(*out_values))
3697667382c7Skettenis 		return -EOVERFLOW;
3698667382c7Skettenis 	if (sz_min == 1 && sz_max == 1)
3699667382c7Skettenis 		return 0;
3700667382c7Skettenis 	return len / sizeof(*out_values);
3701667382c7Skettenis }
3702667382c7Skettenis 
3703667382c7Skettenis int
__of_property_match_string(struct device_node * np,const char * propname,const char * str)3704667382c7Skettenis __of_property_match_string(struct device_node *np,
3705667382c7Skettenis     const char *propname, const char *str)
3706667382c7Skettenis {
3707667382c7Skettenis 	int idx;
3708667382c7Skettenis 
3709667382c7Skettenis 	idx = OF_getindex((uintptr_t)np, str, propname);
3710667382c7Skettenis 	if (idx == -1)
3711667382c7Skettenis 		return -ENODATA;
3712667382c7Skettenis 	return idx;
3713667382c7Skettenis }
3714667382c7Skettenis 
3715667382c7Skettenis struct device_node *
__of_parse_phandle(struct device_node * np,const char * propname,int idx)3716667382c7Skettenis __of_parse_phandle(struct device_node *np, const char *propname, int idx)
3717667382c7Skettenis {
3718667382c7Skettenis 	uint32_t phandles[16] = {};
3719667382c7Skettenis 	int len, node;
3720667382c7Skettenis 
3721667382c7Skettenis 	len = OF_getpropintarray((uintptr_t)np, (char *)propname, phandles,
3722667382c7Skettenis 	    sizeof(phandles));
3723667382c7Skettenis 	if (len < (idx + 1) * sizeof(uint32_t))
3724667382c7Skettenis 		return NULL;
3725667382c7Skettenis 
3726667382c7Skettenis 	node = OF_getnodebyphandle(phandles[idx]);
3727667382c7Skettenis 	if (node == 0)
3728667382c7Skettenis 		return NULL;
3729667382c7Skettenis 
3730667382c7Skettenis 	return (struct device_node *)(uintptr_t)node;
3731667382c7Skettenis }
3732667382c7Skettenis 
3733667382c7Skettenis int
__of_parse_phandle_with_args(struct device_node * np,const char * propname,const char * cellsname,int idx,struct of_phandle_args * args)3734667382c7Skettenis __of_parse_phandle_with_args(struct device_node *np, const char *propname,
3735667382c7Skettenis     const char *cellsname, int idx, struct of_phandle_args *args)
3736667382c7Skettenis {
3737667382c7Skettenis 	uint32_t phandles[16] = {};
3738667382c7Skettenis 	int i, len, node;
3739667382c7Skettenis 
3740667382c7Skettenis 	len = OF_getpropintarray((uintptr_t)np, (char *)propname, phandles,
3741667382c7Skettenis 	    sizeof(phandles));
3742667382c7Skettenis 	if (len < (idx + 1) * sizeof(uint32_t))
3743667382c7Skettenis 		return -ENOENT;
3744667382c7Skettenis 
3745667382c7Skettenis 	node = OF_getnodebyphandle(phandles[idx]);
3746667382c7Skettenis 	if (node == 0)
3747667382c7Skettenis 		return -ENOENT;
3748667382c7Skettenis 
3749667382c7Skettenis 	args->np = (struct device_node *)(uintptr_t)node;
3750667382c7Skettenis 	args->args_count = OF_getpropint(node, (char *)cellsname, 0);
3751667382c7Skettenis 	for (i = 0; i < args->args_count; i++)
3752667382c7Skettenis 		args->args[i] = phandles[i + 1];
3753667382c7Skettenis 
3754667382c7Skettenis 	return 0;
3755667382c7Skettenis }
3756667382c7Skettenis 
3757667382c7Skettenis int
of_address_to_resource(struct device_node * np,int idx,struct resource * res)3758667382c7Skettenis of_address_to_resource(struct device_node *np, int idx, struct resource *res)
3759667382c7Skettenis {
3760667382c7Skettenis 	uint64_t reg[16] = {};
3761667382c7Skettenis 	int len;
3762667382c7Skettenis 
3763667382c7Skettenis 	KASSERT(idx < 8);
3764667382c7Skettenis 
3765667382c7Skettenis 	len = OF_getpropint64array((uintptr_t)np, "reg", reg, sizeof(reg));
3766667382c7Skettenis 	if (len < 0 || idx >= (len / (2 * sizeof(uint64_t))))
3767667382c7Skettenis 		return -EINVAL;
3768667382c7Skettenis 
3769667382c7Skettenis 	res->start = reg[2 * idx];
3770667382c7Skettenis 	res->end = reg[2 * idx] + reg[2 * idx + 1] - 1;
3771667382c7Skettenis 
3772667382c7Skettenis 	return 0;
3773667382c7Skettenis }
3774667382c7Skettenis 
3775667382c7Skettenis static int
next_node(int node)3776667382c7Skettenis next_node(int node)
3777667382c7Skettenis {
3778667382c7Skettenis 	int peer = OF_peer(node);
3779667382c7Skettenis 
3780667382c7Skettenis 	while (node && !peer) {
3781667382c7Skettenis 		node = OF_parent(node);
3782667382c7Skettenis 		if (node)
3783667382c7Skettenis 			peer = OF_peer(node);
3784667382c7Skettenis 	}
3785667382c7Skettenis 
3786667382c7Skettenis 	return peer;
3787667382c7Skettenis }
3788667382c7Skettenis 
3789667382c7Skettenis static int
find_matching_node(int node,const struct of_device_id * id)3790667382c7Skettenis find_matching_node(int node, const struct of_device_id *id)
3791667382c7Skettenis {
3792667382c7Skettenis 	int child, match;
3793667382c7Skettenis 	int i;
3794667382c7Skettenis 
3795667382c7Skettenis 	for (child = OF_child(node); child; child = OF_peer(child)) {
3796667382c7Skettenis 		match = find_matching_node(child, id);
3797667382c7Skettenis 		if (match)
3798667382c7Skettenis 			return match;
3799667382c7Skettenis 	}
3800667382c7Skettenis 
3801667382c7Skettenis 	for (i = 0; id[i].compatible; i++) {
3802667382c7Skettenis 		if (OF_is_compatible(node, id[i].compatible))
3803667382c7Skettenis 			return node;
3804667382c7Skettenis 	}
3805667382c7Skettenis 
3806667382c7Skettenis 	return 0;
3807667382c7Skettenis }
3808667382c7Skettenis 
3809667382c7Skettenis struct device_node *
__matching_node(struct device_node * np,const struct of_device_id * id)3810667382c7Skettenis __matching_node(struct device_node *np, const struct of_device_id *id)
3811667382c7Skettenis {
3812667382c7Skettenis 	int node = OF_peer(0);
3813667382c7Skettenis 	int match;
3814667382c7Skettenis 
3815667382c7Skettenis 	if (np)
3816667382c7Skettenis 		node = next_node((uintptr_t)np);
3817667382c7Skettenis 	while (node) {
3818667382c7Skettenis 		match = find_matching_node(node, id);
3819667382c7Skettenis 		if (match)
3820667382c7Skettenis 			return (struct device_node *)(uintptr_t)match;
3821667382c7Skettenis 		node = next_node(node);
3822667382c7Skettenis 	}
3823667382c7Skettenis 
3824667382c7Skettenis 	return NULL;
3825667382c7Skettenis }
3826667382c7Skettenis 
3827667382c7Skettenis struct platform_device *
of_platform_device_create(struct device_node * np,const char * bus_id,struct device * parent)3828667382c7Skettenis of_platform_device_create(struct device_node *np, const char *bus_id,
3829667382c7Skettenis     struct device *parent)
3830667382c7Skettenis {
3831667382c7Skettenis 	struct platform_device *pdev;
3832667382c7Skettenis 
3833667382c7Skettenis 	pdev = malloc(sizeof(*pdev), M_DEVBUF, M_WAITOK | M_ZERO);
3834667382c7Skettenis 	pdev->node = (intptr_t)np;
3835667382c7Skettenis 	pdev->parent = parent;
3836667382c7Skettenis 
3837667382c7Skettenis 	LIST_INSERT_HEAD(&pdev_list, pdev, next);
3838667382c7Skettenis 
3839667382c7Skettenis 	return pdev;
3840667382c7Skettenis }
3841667382c7Skettenis 
3842667382c7Skettenis struct platform_device *
of_find_device_by_node(struct device_node * np)3843667382c7Skettenis of_find_device_by_node(struct device_node *np)
3844667382c7Skettenis {
3845667382c7Skettenis 	struct platform_device *pdev;
3846667382c7Skettenis 
3847667382c7Skettenis 	LIST_FOREACH(pdev, &pdev_list, next) {
3848667382c7Skettenis 		if (pdev->node == (intptr_t)np)
3849667382c7Skettenis 			return pdev;
3850667382c7Skettenis 	}
3851667382c7Skettenis 
3852667382c7Skettenis 	return NULL;
3853667382c7Skettenis }
3854667382c7Skettenis 
3855667382c7Skettenis int
of_device_is_available(struct device_node * np)3856667382c7Skettenis of_device_is_available(struct device_node *np)
3857667382c7Skettenis {
3858667382c7Skettenis 	char status[32];
3859667382c7Skettenis 
3860667382c7Skettenis 	if (OF_getprop((uintptr_t)np, "status", status, sizeof(status)) > 0 &&
3861667382c7Skettenis 	    strcmp(status, "disabled") == 0)
3862667382c7Skettenis 		return 0;
3863667382c7Skettenis 
3864667382c7Skettenis 	return 1;
3865667382c7Skettenis }
3866667382c7Skettenis 
3867667382c7Skettenis int
of_dma_configure(struct device * dev,struct device_node * np,int force_dma)3868667382c7Skettenis of_dma_configure(struct device *dev, struct device_node *np, int force_dma)
3869667382c7Skettenis {
3870667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3871667382c7Skettenis 	bus_dma_tag_t dmat = dma_tag_lookup(pdev->parent);
3872667382c7Skettenis 
3873667382c7Skettenis 	pdev->dmat = iommu_device_map(pdev->node, dmat);
3874667382c7Skettenis 	return 0;
3875667382c7Skettenis }
3876667382c7Skettenis 
3877667382c7Skettenis struct device_node *
__of_get_compatible_child(void * p,const char * compat)3878667382c7Skettenis __of_get_compatible_child(void *p, const char *compat)
3879667382c7Skettenis {
3880667382c7Skettenis 	struct device *dev = container_of(p, struct device, of_node);
3881667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3882667382c7Skettenis 	int child;
3883667382c7Skettenis 
3884667382c7Skettenis 	for (child = OF_child(pdev->node); child; child = OF_peer(child)) {
3885667382c7Skettenis 		if (OF_is_compatible(child, compat))
3886667382c7Skettenis 			return (struct device_node *)(uintptr_t)child;
3887667382c7Skettenis 	}
3888667382c7Skettenis 	return NULL;
3889667382c7Skettenis }
3890667382c7Skettenis 
3891667382c7Skettenis struct device_node *
__of_get_child_by_name(void * p,const char * name)3892667382c7Skettenis __of_get_child_by_name(void *p, const char *name)
3893667382c7Skettenis {
3894667382c7Skettenis 	struct device *dev = container_of(p, struct device, of_node);
3895667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3896667382c7Skettenis 	int child;
3897667382c7Skettenis 
3898667382c7Skettenis 	child = OF_getnodebyname(pdev->node, name);
3899667382c7Skettenis 	if (child == 0)
3900667382c7Skettenis 		return NULL;
3901667382c7Skettenis 	return (struct device_node *)(uintptr_t)child;
3902667382c7Skettenis }
3903667382c7Skettenis 
3904cefff6e5Skettenis int
component_compare_of(struct device * dev,void * data)3905cefff6e5Skettenis component_compare_of(struct device *dev, void *data)
3906cefff6e5Skettenis {
3907cefff6e5Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3908cefff6e5Skettenis 
3909cefff6e5Skettenis 	return (pdev->node == (intptr_t)data);
3910cefff6e5Skettenis }
3911cefff6e5Skettenis 
3912cefff6e5Skettenis void
drm_of_component_match_add(struct device * master,struct component_match ** matchptr,int (* compare)(struct device *,void *),struct device_node * np)3913cefff6e5Skettenis drm_of_component_match_add(struct device *master,
3914cefff6e5Skettenis 			   struct component_match **matchptr,
3915cefff6e5Skettenis 			   int (*compare)(struct device *, void *),
3916cefff6e5Skettenis 			   struct device_node *np)
3917cefff6e5Skettenis {
39185fde6622Skettenis 	struct component_match *match = *matchptr;
3919cefff6e5Skettenis 
39205fde6622Skettenis 	if (match == NULL) {
3921cefff6e5Skettenis 		match = malloc(sizeof(struct component_match),
3922cefff6e5Skettenis 		    M_DEVBUF, M_WAITOK | M_ZERO);
3923cefff6e5Skettenis 		*matchptr = match;
3924cefff6e5Skettenis 	}
39255fde6622Skettenis 
39265fde6622Skettenis 	KASSERT(match->nmatches < nitems(match->match));
39275fde6622Skettenis 	match->match[match->nmatches].compare = compare;
39285fde6622Skettenis 	match->match[match->nmatches].data = np;
39295fde6622Skettenis 	match->nmatches++;
3930cefff6e5Skettenis }
3931cefff6e5Skettenis 
3932667382c7Skettenis #endif
3933