xref: /openbsd-src/sys/dev/pci/drm/drm_linux.c (revision 22008fe3a13384a2d0eb7434eb1b03dcbce0d721)
1*22008fe3Sjsg /*	$OpenBSD: drm_linux.c,v 1.119 2024/09/30 12:21:17 jsg 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>
54a903e442Skettenis #include <linux/suspend.h>
55c349dbc7Sjsg 
56c349dbc7Sjsg #include <drm/drm_device.h>
571bb76ff1Sjsg #include <drm/drm_connector.h>
58c349dbc7Sjsg #include <drm/drm_print.h>
597f4dd379Sjsg 
607ef4208bSjsg #if defined(__amd64__) || defined(__i386__)
617ef4208bSjsg #include "bios.h"
627ef4208bSjsg #endif
637ef4208bSjsg 
645ca02815Sjsg /* allowed to sleep */
655ca02815Sjsg void
665ca02815Sjsg tasklet_unlock_wait(struct tasklet_struct *ts)
675ca02815Sjsg {
685ca02815Sjsg 	while (test_bit(TASKLET_STATE_RUN, &ts->state))
695ca02815Sjsg 		cpu_relax();
705ca02815Sjsg }
715ca02815Sjsg 
725ca02815Sjsg /* must not sleep */
735ca02815Sjsg void
745ca02815Sjsg tasklet_unlock_spin_wait(struct tasklet_struct *ts)
755ca02815Sjsg {
765ca02815Sjsg 	while (test_bit(TASKLET_STATE_RUN, &ts->state))
775ca02815Sjsg 		cpu_relax();
785ca02815Sjsg }
795ca02815Sjsg 
807f4dd379Sjsg void
817f4dd379Sjsg tasklet_run(void *arg)
827f4dd379Sjsg {
837f4dd379Sjsg 	struct tasklet_struct *ts = arg;
847f4dd379Sjsg 
857f4dd379Sjsg 	clear_bit(TASKLET_STATE_SCHED, &ts->state);
867f4dd379Sjsg 	if (tasklet_trylock(ts)) {
875ca02815Sjsg 		if (!atomic_read(&ts->count)) {
885ca02815Sjsg 			if (ts->use_callback)
895ca02815Sjsg 				ts->callback(ts);
905ca02815Sjsg 			else
917f4dd379Sjsg 				ts->func(ts->data);
925ca02815Sjsg 		}
937f4dd379Sjsg 		tasklet_unlock(ts);
947f4dd379Sjsg 	}
957f4dd379Sjsg }
96652bbc39Skettenis 
97ec70c0c7Sjsg /* 32 bit powerpc lacks 64 bit atomics */
98ec70c0c7Sjsg #if defined(__powerpc__) && !defined(__powerpc64__)
99ec70c0c7Sjsg struct mutex atomic64_mtx = MUTEX_INITIALIZER(IPL_HIGH);
100ec70c0c7Sjsg #endif
101ec70c0c7Sjsg 
1023253c27bSkettenis void
1037f4dd379Sjsg set_current_state(int state)
1043253c27bSkettenis {
105c0be31d8Sclaudio 	int prio = state;
106c0be31d8Sclaudio 
107c0be31d8Sclaudio 	KASSERT(state != TASK_RUNNING);
108c0be31d8Sclaudio 	/* check if already on the sleep list */
109c0be31d8Sclaudio 	if (curproc->p_wchan != NULL)
110c0be31d8Sclaudio 		return;
111c0be31d8Sclaudio 	sleep_setup(curproc, prio, "schto");
1127f4dd379Sjsg }
1133253c27bSkettenis 
1147f4dd379Sjsg void
1157f4dd379Sjsg __set_current_state(int state)
1167f4dd379Sjsg {
117c0be31d8Sclaudio 	struct proc *p = curproc;
118c0be31d8Sclaudio 
1197f4dd379Sjsg 	KASSERT(state == TASK_RUNNING);
120a09e9584Sclaudio 	SCHED_LOCK();
121c0be31d8Sclaudio 	unsleep(p);
122c0be31d8Sclaudio 	p->p_stat = SONPROC;
123c0be31d8Sclaudio 	atomic_clearbits_int(&p->p_flag, P_WSLEEP);
124a09e9584Sclaudio 	SCHED_UNLOCK();
1257f4dd379Sjsg }
1267f4dd379Sjsg 
1277f4dd379Sjsg void
1287f4dd379Sjsg schedule(void)
1297f4dd379Sjsg {
1307f4dd379Sjsg 	schedule_timeout(MAX_SCHEDULE_TIMEOUT);
1317f4dd379Sjsg }
1327f4dd379Sjsg 
1337f4dd379Sjsg long
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
153c349dbc7Sjsg schedule_timeout_uninterruptible(long timeout)
154c349dbc7Sjsg {
155c349dbc7Sjsg 	tsleep(curproc, PWAIT, "schtou", timeout);
156c349dbc7Sjsg 	return 0;
157c349dbc7Sjsg }
158c349dbc7Sjsg 
1597f4dd379Sjsg int
1607f4dd379Sjsg wake_up_process(struct proc *p)
1617f4dd379Sjsg {
162a09e9584Sclaudio 	int rv;
163e1b95daaSclaudio 
164a09e9584Sclaudio 	SCHED_LOCK();
165e1edc428Smpi 	rv = wakeup_proc(p, 0);
166a09e9584Sclaudio 	SCHED_UNLOCK();
167e1b95daaSclaudio 	return rv;
1683253c27bSkettenis }
1693253c27bSkettenis 
170c0be31d8Sclaudio int
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
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
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
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
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
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
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 *
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 *
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
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
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
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
324ad8b1aafSjsg kthread_cancel_work_sync(struct kthread_work *work)
325ad8b1aafSjsg {
326ad8b1aafSjsg 	return task_del(work->tq, &work->task);
327ad8b1aafSjsg }
328ad8b1aafSjsg 
329ad8b1aafSjsg void
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
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 *
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
36463b8f014Skettenis kthread_should_park(void)
36563b8f014Skettenis {
36663b8f014Skettenis 	struct kthread *thread = kthread_lookup(curproc);
36763b8f014Skettenis 	return (thread->flags & KTHREAD_SHOULDPARK);
36863b8f014Skettenis }
36963b8f014Skettenis 
37063b8f014Skettenis 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
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
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
40563b8f014Skettenis kthread_should_stop(void)
40663b8f014Skettenis {
40763b8f014Skettenis 	struct kthread *thread = kthread_lookup(curproc);
40863b8f014Skettenis 	return (thread->flags & KTHREAD_SHOULDSTOP);
40963b8f014Skettenis }
41063b8f014Skettenis 
41163b8f014Skettenis void
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
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
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 *
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 *
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
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 *
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
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
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 *
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
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 *
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
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 *
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 *
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
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
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
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 *
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
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
781d71700c3Skettenis idr_init(struct idr *idr)
782d71700c3Skettenis {
783d71700c3Skettenis 	SPLAY_INIT(&idr->tree);
784d71700c3Skettenis }
785d71700c3Skettenis 
786d71700c3Skettenis void
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
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
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 *
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 *
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 *
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 *
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
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
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
9303253c27bSkettenis ida_init(struct ida *ida)
9313253c27bSkettenis {
932d9e6dc4fSkettenis 	idr_init(&ida->idr);
9333253c27bSkettenis }
9343253c27bSkettenis 
9353253c27bSkettenis void
9363253c27bSkettenis ida_destroy(struct ida *ida)
9373253c27bSkettenis {
938d9e6dc4fSkettenis 	idr_destroy(&ida->idr);
9393253c27bSkettenis }
9403253c27bSkettenis 
9413253c27bSkettenis int
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
949d9e6dc4fSkettenis ida_simple_remove(struct ida *ida, unsigned int id)
9507f4dd379Sjsg {
951d9e6dc4fSkettenis 	idr_remove(&ida->idr, id);
9527f4dd379Sjsg }
9537f4dd379Sjsg 
9543253c27bSkettenis int
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
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
9671bb76ff1Sjsg ida_free(struct ida *ida, unsigned int id)
9681bb76ff1Sjsg {
9691bb76ff1Sjsg 	idr_remove(&ida->idr, id);
9701bb76ff1Sjsg }
9711bb76ff1Sjsg 
9721bb76ff1Sjsg int
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
983c349dbc7Sjsg xa_init_flags(struct xarray *xa, gfp_t flags)
984c349dbc7Sjsg {
985c349dbc7Sjsg 	SPLAY_INIT(&xa->xa_tree);
9865ca02815Sjsg 	if (flags & XA_FLAGS_LOCK_IRQ)
9875ca02815Sjsg 		mtx_init(&xa->xa_lock, IPL_TTY);
9885ca02815Sjsg 	else
9895ca02815Sjsg 		mtx_init(&xa->xa_lock, IPL_NONE);
99043925f44Sjsg 	xa->xa_flags = flags;
991c349dbc7Sjsg }
992c349dbc7Sjsg 
993c349dbc7Sjsg void
994c349dbc7Sjsg xa_destroy(struct xarray *xa)
995c349dbc7Sjsg {
996c349dbc7Sjsg 	struct xarray_entry *id;
997c349dbc7Sjsg 
998c349dbc7Sjsg 	while ((id = SPLAY_MIN(xarray_tree, &xa->xa_tree))) {
999c349dbc7Sjsg 		SPLAY_REMOVE(xarray_tree, &xa->xa_tree, id);
1000c349dbc7Sjsg 		pool_put(&xa_pool, id);
1001c349dbc7Sjsg 	}
1002c349dbc7Sjsg }
1003c349dbc7Sjsg 
10041bb76ff1Sjsg /* Don't wrap ids. */
1005c349dbc7Sjsg int
1006*22008fe3Sjsg __xa_alloc(struct xarray *xa, u32 *id, void *entry, struct xarray_range xr,
1007*22008fe3Sjsg     gfp_t gfp)
1008c349dbc7Sjsg {
1009c349dbc7Sjsg 	struct xarray_entry *xid;
1010*22008fe3Sjsg 	uint32_t start = xr.start;
1011*22008fe3Sjsg 	uint32_t end = xr.end;
1012*22008fe3Sjsg 
1013*22008fe3Sjsg 	if (start == 0 && (xa->xa_flags & XA_FLAGS_ALLOC1))
1014*22008fe3Sjsg 		start = 1;
1015c349dbc7Sjsg 
1016be42cb11Sjsg 	if (gfp & GFP_NOWAIT) {
1017be42cb11Sjsg 		xid = pool_get(&xa_pool, PR_NOWAIT);
1018be42cb11Sjsg 	} else {
1019be42cb11Sjsg 		mtx_leave(&xa->xa_lock);
1020be42cb11Sjsg 		xid = pool_get(&xa_pool, PR_WAITOK);
1021be42cb11Sjsg 		mtx_enter(&xa->xa_lock);
1022be42cb11Sjsg 	}
1023be42cb11Sjsg 
1024c349dbc7Sjsg 	if (xid == NULL)
1025c349dbc7Sjsg 		return -ENOMEM;
1026c349dbc7Sjsg 
1027*22008fe3Sjsg 	xid->id = start;
1028c349dbc7Sjsg 
1029c349dbc7Sjsg 	while (SPLAY_INSERT(xarray_tree, &xa->xa_tree, xid)) {
1030*22008fe3Sjsg 		if (xid->id == end)
1031c349dbc7Sjsg 			xid->id = start;
10324ce37e7fSjsg 		else
10334ce37e7fSjsg 			xid->id++;
1034*22008fe3Sjsg 		if (xid->id == start) {
1035c349dbc7Sjsg 			pool_put(&xa_pool, xid);
1036c349dbc7Sjsg 			return -EBUSY;
1037c349dbc7Sjsg 		}
1038c349dbc7Sjsg 	}
1039c349dbc7Sjsg 	xid->ptr = entry;
1040c349dbc7Sjsg 	*id = xid->id;
1041c349dbc7Sjsg 	return 0;
1042c349dbc7Sjsg }
1043c349dbc7Sjsg 
10441bb76ff1Sjsg /*
10451bb76ff1Sjsg  * Wrap ids and store next id.
10461bb76ff1Sjsg  * We walk the entire tree so don't special case wrapping.
10471bb76ff1Sjsg  * The only caller of this (i915_drm_client.c) doesn't use next id.
10481bb76ff1Sjsg  */
10491bb76ff1Sjsg int
1050*22008fe3Sjsg __xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry,
1051*22008fe3Sjsg     struct xarray_range xr, u32 *next, gfp_t gfp)
10521bb76ff1Sjsg {
1053*22008fe3Sjsg 	int r = __xa_alloc(xa, id, entry, xr, gfp);
10541bb76ff1Sjsg 	*next = *id + 1;
10551bb76ff1Sjsg 	return r;
10561bb76ff1Sjsg }
10571bb76ff1Sjsg 
1058c349dbc7Sjsg void *
10595ca02815Sjsg __xa_erase(struct xarray *xa, unsigned long index)
1060c349dbc7Sjsg {
1061c349dbc7Sjsg 	struct xarray_entry find, *res;
1062c349dbc7Sjsg 	void *ptr = NULL;
1063c349dbc7Sjsg 
1064c349dbc7Sjsg 	find.id = index;
1065c349dbc7Sjsg 	res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
1066c349dbc7Sjsg 	if (res) {
1067c349dbc7Sjsg 		SPLAY_REMOVE(xarray_tree, &xa->xa_tree, res);
1068c349dbc7Sjsg 		ptr = res->ptr;
1069c349dbc7Sjsg 		pool_put(&xa_pool, res);
1070c349dbc7Sjsg 	}
1071c349dbc7Sjsg 	return ptr;
1072c349dbc7Sjsg }
1073c349dbc7Sjsg 
1074c349dbc7Sjsg void *
10755ca02815Sjsg __xa_load(struct xarray *xa, unsigned long index)
1076c349dbc7Sjsg {
1077c349dbc7Sjsg 	struct xarray_entry find, *res;
1078c349dbc7Sjsg 
1079c349dbc7Sjsg 	find.id = index;
1080c349dbc7Sjsg 	res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
1081c349dbc7Sjsg 	if (res == NULL)
1082c349dbc7Sjsg 		return NULL;
1083c349dbc7Sjsg 	return res->ptr;
1084c349dbc7Sjsg }
1085c349dbc7Sjsg 
1086c349dbc7Sjsg void *
10875ca02815Sjsg __xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
10885ca02815Sjsg {
10895ca02815Sjsg 	struct xarray_entry find, *res;
10905ca02815Sjsg 	void *prev;
10915ca02815Sjsg 
10925ca02815Sjsg 	if (entry == NULL)
10935ca02815Sjsg 		return __xa_erase(xa, index);
10945ca02815Sjsg 
10955ca02815Sjsg 	find.id = index;
10965ca02815Sjsg 	res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find);
10975ca02815Sjsg 	if (res != NULL) {
10985ca02815Sjsg 		/* index exists */
10995ca02815Sjsg 		/* XXX Multislot entries updates not implemented yet */
11005ca02815Sjsg 		prev = res->ptr;
11015ca02815Sjsg 		res->ptr = entry;
11025ca02815Sjsg 		return prev;
11035ca02815Sjsg 	}
11045ca02815Sjsg 
11055ca02815Sjsg 	/* index not found, add new */
1106be42cb11Sjsg 	if (gfp & GFP_NOWAIT) {
1107be42cb11Sjsg 		res = pool_get(&xa_pool, PR_NOWAIT);
1108be42cb11Sjsg 	} else {
1109be42cb11Sjsg 		mtx_leave(&xa->xa_lock);
1110be42cb11Sjsg 		res = pool_get(&xa_pool, PR_WAITOK);
1111be42cb11Sjsg 		mtx_enter(&xa->xa_lock);
1112be42cb11Sjsg 	}
11135ca02815Sjsg 	if (res == NULL)
11145ca02815Sjsg 		return XA_ERROR(-ENOMEM);
11155ca02815Sjsg 	res->id = index;
11165ca02815Sjsg 	res->ptr = entry;
11175ca02815Sjsg 	if (SPLAY_INSERT(xarray_tree, &xa->xa_tree, res) != NULL)
11185ca02815Sjsg 		return XA_ERROR(-EINVAL);
11195ca02815Sjsg 	return NULL; /* no prev entry at index */
11205ca02815Sjsg }
11215ca02815Sjsg 
11225ca02815Sjsg void *
1123c349dbc7Sjsg xa_get_next(struct xarray *xa, unsigned long *index)
1124c349dbc7Sjsg {
1125c349dbc7Sjsg 	struct xarray_entry *res;
1126c349dbc7Sjsg 
1127c349dbc7Sjsg 	SPLAY_FOREACH(res, xarray_tree, &xa->xa_tree) {
1128c349dbc7Sjsg 		if (res->id >= *index) {
1129c349dbc7Sjsg 			*index = res->id;
1130c349dbc7Sjsg 			return res->ptr;
1131c349dbc7Sjsg 		}
1132c349dbc7Sjsg 	}
1133c349dbc7Sjsg 
1134c349dbc7Sjsg 	return NULL;
1135c349dbc7Sjsg }
1136c349dbc7Sjsg 
1137c349dbc7Sjsg int
11383253c27bSkettenis sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
11393253c27bSkettenis {
11403253c27bSkettenis 	table->sgl = mallocarray(nents, sizeof(struct scatterlist),
1141ad8b1aafSjsg 	    M_DRM, gfp_mask | M_ZERO);
11423253c27bSkettenis 	if (table->sgl == NULL)
11433253c27bSkettenis 		return -ENOMEM;
11443253c27bSkettenis 	table->nents = table->orig_nents = nents;
1145ad8b1aafSjsg 	sg_mark_end(&table->sgl[nents - 1]);
11463253c27bSkettenis 	return 0;
11473253c27bSkettenis }
11483253c27bSkettenis 
11493253c27bSkettenis void
11503253c27bSkettenis sg_free_table(struct sg_table *table)
11513253c27bSkettenis {
11523253c27bSkettenis 	free(table->sgl, M_DRM,
11533253c27bSkettenis 	    table->orig_nents * sizeof(struct scatterlist));
1154ad8b1aafSjsg 	table->orig_nents = 0;
1155ee152407Sjsg 	table->sgl = NULL;
11563253c27bSkettenis }
11573253c27bSkettenis 
11583253c27bSkettenis size_t
11593253c27bSkettenis sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
11603253c27bSkettenis     const void *buf, size_t buflen)
11613253c27bSkettenis {
11623253c27bSkettenis 	panic("%s", __func__);
11633253c27bSkettenis }
11643253c27bSkettenis 
11653253c27bSkettenis int
1166142c034fSkettenis i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
11673253c27bSkettenis {
11683253c27bSkettenis 	void *cmd = NULL;
11693253c27bSkettenis 	int cmdlen = 0;
11703253c27bSkettenis 	int err, ret = 0;
11713253c27bSkettenis 	int op;
11723253c27bSkettenis 
11733253c27bSkettenis 	iic_acquire_bus(&adap->ic, 0);
11743253c27bSkettenis 
11753253c27bSkettenis 	while (num > 2) {
11763253c27bSkettenis 		op = (msgs->flags & I2C_M_RD) ? I2C_OP_READ : I2C_OP_WRITE;
11773253c27bSkettenis 		err = iic_exec(&adap->ic, op, msgs->addr, NULL, 0,
11783253c27bSkettenis 		    msgs->buf, msgs->len, 0);
11793253c27bSkettenis 		if (err) {
11803253c27bSkettenis 			ret = -err;
11813253c27bSkettenis 			goto fail;
11823253c27bSkettenis 		}
11833253c27bSkettenis 		msgs++;
11843253c27bSkettenis 		num--;
11853253c27bSkettenis 		ret++;
11863253c27bSkettenis 	}
11873253c27bSkettenis 
11883253c27bSkettenis 	if (num > 1) {
11893253c27bSkettenis 		cmd = msgs->buf;
11903253c27bSkettenis 		cmdlen = msgs->len;
11913253c27bSkettenis 		msgs++;
11923253c27bSkettenis 		num--;
11933253c27bSkettenis 		ret++;
11943253c27bSkettenis 	}
11953253c27bSkettenis 
1196142c034fSkettenis 	op = (msgs->flags & I2C_M_RD) ?
1197142c034fSkettenis 	    I2C_OP_READ_WITH_STOP : I2C_OP_WRITE_WITH_STOP;
1198142c034fSkettenis 	err = iic_exec(&adap->ic, op, msgs->addr, cmd, cmdlen,
1199142c034fSkettenis 	    msgs->buf, msgs->len, 0);
12003253c27bSkettenis 	if (err) {
12013253c27bSkettenis 		ret = -err;
12023253c27bSkettenis 		goto fail;
12033253c27bSkettenis 	}
12043253c27bSkettenis 	msgs++;
12053253c27bSkettenis 	ret++;
12063253c27bSkettenis 
12073253c27bSkettenis fail:
12083253c27bSkettenis 	iic_release_bus(&adap->ic, 0);
12093253c27bSkettenis 
12103253c27bSkettenis 	return ret;
12113253c27bSkettenis }
12123253c27bSkettenis 
1213142c034fSkettenis int
121465bb161bSjsg __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1215142c034fSkettenis {
12162156c0eeSjsg 	int ret, retries;
1217142c034fSkettenis 
12182156c0eeSjsg 	retries = adap->retries;
12192156c0eeSjsg retry:
1220c349dbc7Sjsg 	if (adap->algo)
1221c349dbc7Sjsg 		ret = adap->algo->master_xfer(adap, msgs, num);
1222c349dbc7Sjsg 	else
1223c349dbc7Sjsg 		ret = i2c_master_xfer(adap, msgs, num);
12242156c0eeSjsg 	if (ret == -EAGAIN && retries > 0) {
12252156c0eeSjsg 		retries--;
12262156c0eeSjsg 		goto retry;
12272156c0eeSjsg 	}
1228c349dbc7Sjsg 
122965bb161bSjsg 	return ret;
123065bb161bSjsg }
123165bb161bSjsg 
123265bb161bSjsg int
123365bb161bSjsg i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
123465bb161bSjsg {
123565bb161bSjsg 	int ret;
123665bb161bSjsg 
123765bb161bSjsg 	if (adap->lock_ops)
123865bb161bSjsg 		adap->lock_ops->lock_bus(adap, 0);
123965bb161bSjsg 
124065bb161bSjsg 	ret = __i2c_transfer(adap, msgs, num);
124165bb161bSjsg 
1242c349dbc7Sjsg 	if (adap->lock_ops)
1243c349dbc7Sjsg 		adap->lock_ops->unlock_bus(adap, 0);
1244c349dbc7Sjsg 
1245c349dbc7Sjsg 	return ret;
1246142c034fSkettenis }
1247142c034fSkettenis 
1248142c034fSkettenis int
1249142c034fSkettenis i2c_bb_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1250142c034fSkettenis {
1251142c034fSkettenis 	struct i2c_algo_bit_data *algo = adap->algo_data;
1252142c034fSkettenis 	struct i2c_adapter bb;
1253142c034fSkettenis 
1254142c034fSkettenis 	memset(&bb, 0, sizeof(bb));
1255142c034fSkettenis 	bb.ic = algo->ic;
1256142c034fSkettenis 	bb.retries = adap->retries;
1257142c034fSkettenis 	return i2c_master_xfer(&bb, msgs, num);
1258142c034fSkettenis }
1259142c034fSkettenis 
1260142c034fSkettenis uint32_t
1261142c034fSkettenis i2c_bb_functionality(struct i2c_adapter *adap)
1262142c034fSkettenis {
1263142c034fSkettenis 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
1264142c034fSkettenis }
1265142c034fSkettenis 
1266142c034fSkettenis struct i2c_algorithm i2c_bit_algo = {
1267142c034fSkettenis 	.master_xfer = i2c_bb_master_xfer,
1268142c034fSkettenis 	.functionality = i2c_bb_functionality
1269142c034fSkettenis };
1270142c034fSkettenis 
1271d8a2843fSjsg int
1272d8a2843fSjsg i2c_bit_add_bus(struct i2c_adapter *adap)
1273d8a2843fSjsg {
1274d8a2843fSjsg 	adap->algo = &i2c_bit_algo;
1275d8a2843fSjsg 	adap->retries = 3;
1276d8a2843fSjsg 
1277d8a2843fSjsg 	return 0;
1278d8a2843fSjsg }
1279d8a2843fSjsg 
1280adfb93f8Skettenis #if defined(__amd64__) || defined(__i386__)
1281adfb93f8Skettenis 
1282adfb93f8Skettenis /*
1283adfb93f8Skettenis  * This is a minimal implementation of the Linux vga_get/vga_put
12845ca02815Sjsg  * interface.  In all likelihood, it will only work for inteldrm(4) as
1285adfb93f8Skettenis  * it assumes that if there is another active VGA device in the
1286adfb93f8Skettenis  * system, it is sitting behind a PCI bridge.
1287adfb93f8Skettenis  */
1288adfb93f8Skettenis 
1289adfb93f8Skettenis extern int pci_enumerate_bus(struct pci_softc *,
1290adfb93f8Skettenis     int (*)(struct pci_attach_args *), struct pci_attach_args *);
1291adfb93f8Skettenis 
1292adfb93f8Skettenis pcitag_t vga_bridge_tag;
1293adfb93f8Skettenis int vga_bridge_disabled;
1294adfb93f8Skettenis 
1295adfb93f8Skettenis int
1296adfb93f8Skettenis vga_disable_bridge(struct pci_attach_args *pa)
1297adfb93f8Skettenis {
1298adfb93f8Skettenis 	pcireg_t bhlc, bc;
1299adfb93f8Skettenis 
1300adfb93f8Skettenis 	if (pa->pa_domain != 0)
1301adfb93f8Skettenis 		return 0;
1302adfb93f8Skettenis 
1303adfb93f8Skettenis 	bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
1304adfb93f8Skettenis 	if (PCI_HDRTYPE_TYPE(bhlc) != 1)
1305adfb93f8Skettenis 		return 0;
1306adfb93f8Skettenis 
1307adfb93f8Skettenis 	bc = pci_conf_read(pa->pa_pc, pa->pa_tag, PPB_REG_BRIDGECONTROL);
1308adfb93f8Skettenis 	if ((bc & PPB_BC_VGA_ENABLE) == 0)
1309adfb93f8Skettenis 		return 0;
1310adfb93f8Skettenis 	bc &= ~PPB_BC_VGA_ENABLE;
1311adfb93f8Skettenis 	pci_conf_write(pa->pa_pc, pa->pa_tag, PPB_REG_BRIDGECONTROL, bc);
1312adfb93f8Skettenis 
1313adfb93f8Skettenis 	vga_bridge_tag = pa->pa_tag;
1314adfb93f8Skettenis 	vga_bridge_disabled = 1;
1315adfb93f8Skettenis 
1316adfb93f8Skettenis 	return 1;
1317adfb93f8Skettenis }
1318adfb93f8Skettenis 
1319adfb93f8Skettenis void
1320adfb93f8Skettenis vga_get_uninterruptible(struct pci_dev *pdev, int rsrc)
1321adfb93f8Skettenis {
132203c13a2aSjsg 	if (pdev->pci->sc_bridgetag != NULL)
132303c13a2aSjsg 		return;
1324adfb93f8Skettenis 	pci_enumerate_bus(pdev->pci, vga_disable_bridge, NULL);
1325adfb93f8Skettenis }
1326adfb93f8Skettenis 
1327adfb93f8Skettenis void
1328adfb93f8Skettenis vga_put(struct pci_dev *pdev, int rsrc)
1329adfb93f8Skettenis {
1330ec031e48Skettenis 	pcireg_t bc;
1331ec031e48Skettenis 
1332ec031e48Skettenis 	if (!vga_bridge_disabled)
1333ec031e48Skettenis 		return;
1334ec031e48Skettenis 
1335ec031e48Skettenis 	bc = pci_conf_read(pdev->pc, vga_bridge_tag, PPB_REG_BRIDGECONTROL);
1336ec031e48Skettenis 	bc |= PPB_BC_VGA_ENABLE;
1337ec031e48Skettenis 	pci_conf_write(pdev->pc, vga_bridge_tag, PPB_REG_BRIDGECONTROL, bc);
1338ec031e48Skettenis 
1339ec031e48Skettenis 	vga_bridge_disabled = 0;
1340adfb93f8Skettenis }
1341adfb93f8Skettenis 
1342adfb93f8Skettenis #endif
134327f2381eSkettenis 
1344a903e442Skettenis suspend_state_t pm_suspend_target_state;
1345a903e442Skettenis 
134627f2381eSkettenis /*
134727f2381eSkettenis  * ACPI types and interfaces.
134827f2381eSkettenis  */
134927f2381eSkettenis 
13509943d3dfSkettenis #ifdef __HAVE_ACPI
135127f2381eSkettenis #include "acpi.h"
135227f2381eSkettenis #endif
135327f2381eSkettenis 
135427f2381eSkettenis #if NACPI > 0
135527f2381eSkettenis 
135627f2381eSkettenis #include <dev/acpi/acpireg.h>
135727f2381eSkettenis #include <dev/acpi/acpivar.h>
13586a77e6adSkettenis #include <dev/acpi/amltypes.h>
13596a77e6adSkettenis #include <dev/acpi/dsdt.h>
136027f2381eSkettenis 
1361a903e442Skettenis struct acpi_fadt acpi_gbl_FADT;
1362a903e442Skettenis 
136327f2381eSkettenis acpi_status
13647f4dd379Sjsg acpi_get_table(const char *sig, int instance,
13657f4dd379Sjsg     struct acpi_table_header **hdr)
136627f2381eSkettenis {
136727f2381eSkettenis 	struct acpi_softc *sc = acpi_softc;
136827f2381eSkettenis 	struct acpi_q *entry;
136927f2381eSkettenis 
137027f2381eSkettenis 	KASSERT(instance == 1);
137127f2381eSkettenis 
13725d868007Skettenis 	if (sc == NULL)
13735d868007Skettenis 		return AE_NOT_FOUND;
13745d868007Skettenis 
137527f2381eSkettenis 	SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) {
137627f2381eSkettenis 		if (memcmp(entry->q_table, sig, strlen(sig)) == 0) {
137727f2381eSkettenis 			*hdr = entry->q_table;
137827f2381eSkettenis 			return 0;
137927f2381eSkettenis 		}
138027f2381eSkettenis 	}
138127f2381eSkettenis 
138227f2381eSkettenis 	return AE_NOT_FOUND;
138327f2381eSkettenis }
138427f2381eSkettenis 
13851bb76ff1Sjsg void
13861bb76ff1Sjsg acpi_put_table(struct acpi_table_header *hdr)
13871bb76ff1Sjsg {
13881bb76ff1Sjsg }
13891bb76ff1Sjsg 
13906a77e6adSkettenis acpi_status
13916a77e6adSkettenis acpi_get_handle(acpi_handle node, const char *name, acpi_handle *rnode)
13926a77e6adSkettenis {
13936a77e6adSkettenis 	node = aml_searchname(node, name);
13946a77e6adSkettenis 	if (node == NULL)
13956a77e6adSkettenis 		return AE_NOT_FOUND;
13966a77e6adSkettenis 
13976a77e6adSkettenis 	*rnode = node;
13986a77e6adSkettenis 	return 0;
13996a77e6adSkettenis }
14006a77e6adSkettenis 
14016a77e6adSkettenis acpi_status
14026a77e6adSkettenis acpi_get_name(acpi_handle node, int type,  struct acpi_buffer *buffer)
14036a77e6adSkettenis {
14046a77e6adSkettenis 	KASSERT(buffer->length != ACPI_ALLOCATE_BUFFER);
14056a77e6adSkettenis 	KASSERT(type == ACPI_FULL_PATHNAME);
14066a77e6adSkettenis 	strlcpy(buffer->pointer, aml_nodename(node), buffer->length);
14076a77e6adSkettenis 	return 0;
14086a77e6adSkettenis }
14096a77e6adSkettenis 
14106a77e6adSkettenis acpi_status
14116a77e6adSkettenis acpi_evaluate_object(acpi_handle node, const char *name,
14126a77e6adSkettenis     struct acpi_object_list *params, struct acpi_buffer *result)
14136a77e6adSkettenis {
14146a77e6adSkettenis 	struct aml_value args[4], res;
14156a77e6adSkettenis 	union acpi_object *obj;
14166a77e6adSkettenis 	uint8_t *data;
14176a77e6adSkettenis 	int i;
14186a77e6adSkettenis 
14196a77e6adSkettenis 	KASSERT(params->count <= nitems(args));
14206a77e6adSkettenis 
14216a77e6adSkettenis 	for (i = 0; i < params->count; i++) {
14226a77e6adSkettenis 		args[i].type = params->pointer[i].type;
14236a77e6adSkettenis 		switch (args[i].type) {
14246a77e6adSkettenis 		case AML_OBJTYPE_INTEGER:
14256a77e6adSkettenis 			args[i].v_integer = params->pointer[i].integer.value;
14266a77e6adSkettenis 			break;
14276a77e6adSkettenis 		case AML_OBJTYPE_BUFFER:
14286a77e6adSkettenis 			args[i].length = params->pointer[i].buffer.length;
14296a77e6adSkettenis 			args[i].v_buffer = params->pointer[i].buffer.pointer;
14306a77e6adSkettenis 			break;
14316a77e6adSkettenis 		default:
14326a77e6adSkettenis 			printf("%s: arg type 0x%02x", __func__, args[i].type);
14336a77e6adSkettenis 			return AE_BAD_PARAMETER;
14346a77e6adSkettenis 		}
14356a77e6adSkettenis 	}
14366a77e6adSkettenis 
14376a77e6adSkettenis 	if (name) {
14386a77e6adSkettenis 		node = aml_searchname(node, name);
14396a77e6adSkettenis 		if (node == NULL)
14406a77e6adSkettenis 			return AE_NOT_FOUND;
14416a77e6adSkettenis 	}
14426a77e6adSkettenis 	if (aml_evalnode(acpi_softc, node, params->count, args, &res)) {
14436a77e6adSkettenis 		aml_freevalue(&res);
14446a77e6adSkettenis 		return AE_ERROR;
14456a77e6adSkettenis 	}
14466a77e6adSkettenis 
14476a77e6adSkettenis 	KASSERT(result->length == ACPI_ALLOCATE_BUFFER);
14486a77e6adSkettenis 
14496a77e6adSkettenis 	result->length = sizeof(union acpi_object);
14506a77e6adSkettenis 	switch (res.type) {
14516a77e6adSkettenis 	case AML_OBJTYPE_BUFFER:
14526a77e6adSkettenis 		result->length += res.length;
14536a77e6adSkettenis 		result->pointer = malloc(result->length, M_DRM, M_WAITOK);
14546a77e6adSkettenis 		obj = (union acpi_object *)result->pointer;
14556a77e6adSkettenis 		data = (uint8_t *)(obj + 1);
14566a77e6adSkettenis 		obj->type = res.type;
14576a77e6adSkettenis 		obj->buffer.length = res.length;
14586a77e6adSkettenis 		obj->buffer.pointer = data;
14596a77e6adSkettenis 		memcpy(data, res.v_buffer, res.length);
14606a77e6adSkettenis 		break;
14616a77e6adSkettenis 	default:
14626a77e6adSkettenis 		printf("%s: return type 0x%02x", __func__, res.type);
14636a77e6adSkettenis 		aml_freevalue(&res);
14646a77e6adSkettenis 		return AE_ERROR;
14656a77e6adSkettenis 	}
14666a77e6adSkettenis 
14676a77e6adSkettenis 	aml_freevalue(&res);
14686a77e6adSkettenis 	return 0;
14696a77e6adSkettenis }
14706a77e6adSkettenis 
14716a77e6adSkettenis SLIST_HEAD(, notifier_block) drm_linux_acpi_notify_list =
14726a77e6adSkettenis 	SLIST_HEAD_INITIALIZER(drm_linux_acpi_notify_list);
14736a77e6adSkettenis 
14746a77e6adSkettenis int
14756a77e6adSkettenis drm_linux_acpi_notify(struct aml_node *node, int notify, void *arg)
14766a77e6adSkettenis {
14776a77e6adSkettenis 	struct acpi_bus_event event;
14786a77e6adSkettenis 	struct notifier_block *nb;
14796a77e6adSkettenis 
14806a77e6adSkettenis 	event.device_class = ACPI_VIDEO_CLASS;
14816a77e6adSkettenis 	event.type = notify;
14826a77e6adSkettenis 
14836a77e6adSkettenis 	SLIST_FOREACH(nb, &drm_linux_acpi_notify_list, link)
14846a77e6adSkettenis 		nb->notifier_call(nb, 0, &event);
14856a77e6adSkettenis 	return 0;
14866a77e6adSkettenis }
14876a77e6adSkettenis 
14886a77e6adSkettenis int
14896a77e6adSkettenis register_acpi_notifier(struct notifier_block *nb)
14906a77e6adSkettenis {
14916a77e6adSkettenis 	SLIST_INSERT_HEAD(&drm_linux_acpi_notify_list, nb, link);
14926a77e6adSkettenis 	return 0;
14936a77e6adSkettenis }
14946a77e6adSkettenis 
14956a77e6adSkettenis int
14966a77e6adSkettenis unregister_acpi_notifier(struct notifier_block *nb)
14976a77e6adSkettenis {
14984d3f7975Skettenis 	struct notifier_block *tmp;
14994d3f7975Skettenis 
15004d3f7975Skettenis 	SLIST_FOREACH(tmp, &drm_linux_acpi_notify_list, link) {
15014d3f7975Skettenis 		if (tmp == nb) {
15024d3f7975Skettenis 			SLIST_REMOVE(&drm_linux_acpi_notify_list, nb,
15034d3f7975Skettenis 			    notifier_block, link);
15046a77e6adSkettenis 			return 0;
15056a77e6adSkettenis 		}
15064d3f7975Skettenis 	}
15074d3f7975Skettenis 
15084d3f7975Skettenis 	return -ENOENT;
15094d3f7975Skettenis }
15106a77e6adSkettenis 
15116a77e6adSkettenis const char *
15126a77e6adSkettenis acpi_format_exception(acpi_status status)
15136a77e6adSkettenis {
15146a77e6adSkettenis 	switch (status) {
15156a77e6adSkettenis 	case AE_NOT_FOUND:
15166a77e6adSkettenis 		return "not found";
15176a77e6adSkettenis 	case AE_BAD_PARAMETER:
15186a77e6adSkettenis 		return "bad parameter";
15196a77e6adSkettenis 	default:
15206a77e6adSkettenis 		return "unknown";
15216a77e6adSkettenis 	}
15226a77e6adSkettenis }
15236a77e6adSkettenis 
15240759fbd1Skettenis int
15250759fbd1Skettenis acpi_target_system_state(void)
15260759fbd1Skettenis {
15270759fbd1Skettenis 	return acpi_softc->sc_state;
15280759fbd1Skettenis }
15290759fbd1Skettenis 
153027f2381eSkettenis #endif
1531e12511f5Skettenis 
15329342ba5eSkettenis SLIST_HEAD(,backlight_device) backlight_device_list =
15339342ba5eSkettenis     SLIST_HEAD_INITIALIZER(backlight_device_list);
15349342ba5eSkettenis 
1535f88c7015Skettenis void
1536f88c7015Skettenis backlight_do_update_status(void *arg)
1537f88c7015Skettenis {
1538f88c7015Skettenis 	backlight_update_status(arg);
1539f88c7015Skettenis }
1540f88c7015Skettenis 
1541e12511f5Skettenis struct backlight_device *
1542e12511f5Skettenis backlight_device_register(const char *name, void *kdev, void *data,
15439342ba5eSkettenis     const struct backlight_ops *ops, const struct backlight_properties *props)
1544e12511f5Skettenis {
1545e12511f5Skettenis 	struct backlight_device *bd;
1546e12511f5Skettenis 
1547e12511f5Skettenis 	bd = malloc(sizeof(*bd), M_DRM, M_WAITOK);
1548e12511f5Skettenis 	bd->ops = ops;
1549e12511f5Skettenis 	bd->props = *props;
1550e12511f5Skettenis 	bd->data = data;
1551e12511f5Skettenis 
1552f88c7015Skettenis 	task_set(&bd->task, backlight_do_update_status, bd);
1553f88c7015Skettenis 
15549342ba5eSkettenis 	SLIST_INSERT_HEAD(&backlight_device_list, bd, next);
15559342ba5eSkettenis 	bd->name = name;
15569342ba5eSkettenis 
1557e12511f5Skettenis 	return bd;
1558e12511f5Skettenis }
1559e12511f5Skettenis 
1560e12511f5Skettenis void
1561e12511f5Skettenis backlight_device_unregister(struct backlight_device *bd)
1562e12511f5Skettenis {
15639342ba5eSkettenis 	SLIST_REMOVE(&backlight_device_list, bd, backlight_device, next);
1564e12511f5Skettenis 	free(bd, M_DRM, sizeof(*bd));
1565e12511f5Skettenis }
1566f88c7015Skettenis 
1567f88c7015Skettenis void
1568f88c7015Skettenis backlight_schedule_update_status(struct backlight_device *bd)
1569f88c7015Skettenis {
1570f88c7015Skettenis 	task_add(systq, &bd->task);
1571f88c7015Skettenis }
1572b8584f42Srobert 
15739342ba5eSkettenis int
1574c349dbc7Sjsg backlight_enable(struct backlight_device *bd)
1575c349dbc7Sjsg {
1576c349dbc7Sjsg 	if (bd == NULL)
1577c349dbc7Sjsg 		return 0;
1578c349dbc7Sjsg 
1579c349dbc7Sjsg 	bd->props.power = FB_BLANK_UNBLANK;
1580c349dbc7Sjsg 
1581c349dbc7Sjsg 	return bd->ops->update_status(bd);
1582c349dbc7Sjsg }
1583c349dbc7Sjsg 
15849342ba5eSkettenis int
1585c349dbc7Sjsg backlight_disable(struct backlight_device *bd)
1586c349dbc7Sjsg {
1587c349dbc7Sjsg 	if (bd == NULL)
1588c349dbc7Sjsg 		return 0;
1589c349dbc7Sjsg 
1590c349dbc7Sjsg 	bd->props.power = FB_BLANK_POWERDOWN;
1591c349dbc7Sjsg 
1592c349dbc7Sjsg 	return bd->ops->update_status(bd);
1593c349dbc7Sjsg }
1594c349dbc7Sjsg 
15959342ba5eSkettenis struct backlight_device *
15969342ba5eSkettenis backlight_device_get_by_name(const char *name)
15979342ba5eSkettenis {
15989342ba5eSkettenis 	struct backlight_device *bd;
15999342ba5eSkettenis 
16009342ba5eSkettenis 	SLIST_FOREACH(bd, &backlight_device_list, next) {
16019342ba5eSkettenis 		if (strcmp(name, bd->name) == 0)
16029342ba5eSkettenis 			return bd;
16039342ba5eSkettenis 	}
16049342ba5eSkettenis 
16059342ba5eSkettenis 	return NULL;
16069342ba5eSkettenis }
16079342ba5eSkettenis 
16089342ba5eSkettenis struct drvdata {
16099342ba5eSkettenis 	struct device *dev;
16109342ba5eSkettenis 	void *data;
16119342ba5eSkettenis 	SLIST_ENTRY(drvdata) next;
16129342ba5eSkettenis };
16139342ba5eSkettenis 
16149342ba5eSkettenis SLIST_HEAD(,drvdata) drvdata_list = SLIST_HEAD_INITIALIZER(drvdata_list);
16159342ba5eSkettenis 
16169342ba5eSkettenis void
16179342ba5eSkettenis dev_set_drvdata(struct device *dev, void *data)
16189342ba5eSkettenis {
16199342ba5eSkettenis 	struct drvdata *drvdata;
16209342ba5eSkettenis 
16219342ba5eSkettenis 	SLIST_FOREACH(drvdata, &drvdata_list, next) {
16229342ba5eSkettenis 		if (drvdata->dev == dev) {
16239342ba5eSkettenis 			drvdata->data = data;
16249342ba5eSkettenis 			return;
16259342ba5eSkettenis 		}
16269342ba5eSkettenis 	}
16279342ba5eSkettenis 
16289342ba5eSkettenis 	if (data == NULL)
16299342ba5eSkettenis 		return;
16309342ba5eSkettenis 
16319342ba5eSkettenis 	drvdata = malloc(sizeof(*drvdata), M_DRM, M_WAITOK);
16329342ba5eSkettenis 	drvdata->dev = dev;
16339342ba5eSkettenis 	drvdata->data = data;
16349342ba5eSkettenis 
16359342ba5eSkettenis 	SLIST_INSERT_HEAD(&drvdata_list, drvdata, next);
16369342ba5eSkettenis }
16379342ba5eSkettenis 
16389342ba5eSkettenis void *
16399342ba5eSkettenis dev_get_drvdata(struct device *dev)
16409342ba5eSkettenis {
16419342ba5eSkettenis 	struct drvdata *drvdata;
16429342ba5eSkettenis 
16439342ba5eSkettenis 	SLIST_FOREACH(drvdata, &drvdata_list, next) {
16449342ba5eSkettenis 		if (drvdata->dev == dev)
16459342ba5eSkettenis 			return drvdata->data;
16469342ba5eSkettenis 	}
16479342ba5eSkettenis 
16489342ba5eSkettenis 	return NULL;
16499342ba5eSkettenis }
16509342ba5eSkettenis 
1651b8584f42Srobert void
1652b8584f42Srobert drm_sysfs_hotplug_event(struct drm_device *dev)
1653b8584f42Srobert {
1654c78098b6Svisa 	knote_locked(&dev->note, NOTE_CHANGE);
1655b8584f42Srobert }
16567ccd5a2cSjsg 
16571bb76ff1Sjsg void
16581bb76ff1Sjsg drm_sysfs_connector_hotplug_event(struct drm_connector *connector)
16591bb76ff1Sjsg {
1660c78098b6Svisa 	knote_locked(&connector->dev->note, NOTE_CHANGE);
16611bb76ff1Sjsg }
16621bb76ff1Sjsg 
16631bb76ff1Sjsg void
16641bb76ff1Sjsg drm_sysfs_connector_status_event(struct drm_connector *connector,
16651bb76ff1Sjsg     struct drm_property *property)
16661bb76ff1Sjsg {
16671bb76ff1Sjsg 	STUB();
16681bb76ff1Sjsg }
16691bb76ff1Sjsg 
1670f005ef32Sjsg void
1671f005ef32Sjsg drm_sysfs_connector_property_event(struct drm_connector *connector,
1672f005ef32Sjsg     struct drm_property *property)
1673f005ef32Sjsg {
1674f005ef32Sjsg 	STUB();
1675f005ef32Sjsg }
1676f005ef32Sjsg 
1677ad8b1aafSjsg struct dma_fence *
1678ad8b1aafSjsg dma_fence_get(struct dma_fence *fence)
1679ad8b1aafSjsg {
1680ad8b1aafSjsg 	if (fence)
1681ad8b1aafSjsg 		kref_get(&fence->refcount);
1682ad8b1aafSjsg 	return fence;
1683ad8b1aafSjsg }
1684ad8b1aafSjsg 
1685ad8b1aafSjsg struct dma_fence *
1686ad8b1aafSjsg dma_fence_get_rcu(struct dma_fence *fence)
1687ad8b1aafSjsg {
1688ad8b1aafSjsg 	if (fence)
1689ad8b1aafSjsg 		kref_get(&fence->refcount);
1690ad8b1aafSjsg 	return fence;
1691ad8b1aafSjsg }
1692ad8b1aafSjsg 
1693ad8b1aafSjsg struct dma_fence *
1694ad8b1aafSjsg dma_fence_get_rcu_safe(struct dma_fence **dfp)
1695ad8b1aafSjsg {
1696ad8b1aafSjsg 	struct dma_fence *fence;
1697ad8b1aafSjsg 	if (dfp == NULL)
1698ad8b1aafSjsg 		return NULL;
1699ad8b1aafSjsg 	fence = *dfp;
1700ad8b1aafSjsg 	if (fence)
1701ad8b1aafSjsg 		kref_get(&fence->refcount);
1702ad8b1aafSjsg 	return fence;
1703ad8b1aafSjsg }
1704ad8b1aafSjsg 
1705ad8b1aafSjsg void
1706ad8b1aafSjsg dma_fence_release(struct kref *ref)
1707ad8b1aafSjsg {
1708ad8b1aafSjsg 	struct dma_fence *fence = container_of(ref, struct dma_fence, refcount);
1709ad8b1aafSjsg 	if (fence->ops && fence->ops->release)
1710ad8b1aafSjsg 		fence->ops->release(fence);
1711ad8b1aafSjsg 	else
1712ad8b1aafSjsg 		free(fence, M_DRM, 0);
1713ad8b1aafSjsg }
1714ad8b1aafSjsg 
1715ad8b1aafSjsg void
1716ad8b1aafSjsg dma_fence_put(struct dma_fence *fence)
1717ad8b1aafSjsg {
1718ad8b1aafSjsg 	if (fence)
1719ad8b1aafSjsg 		kref_put(&fence->refcount, dma_fence_release);
1720ad8b1aafSjsg }
1721ad8b1aafSjsg 
1722ad8b1aafSjsg int
17235ca02815Sjsg dma_fence_signal_timestamp_locked(struct dma_fence *fence, ktime_t timestamp)
1724ad8b1aafSjsg {
1725ad8b1aafSjsg 	struct dma_fence_cb *cur, *tmp;
1726ad8b1aafSjsg 	struct list_head cb_list;
1727ad8b1aafSjsg 
1728ad8b1aafSjsg 	if (fence == NULL)
1729ad8b1aafSjsg 		return -EINVAL;
1730ad8b1aafSjsg 
1731ad8b1aafSjsg 	if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1732ad8b1aafSjsg 		return -EINVAL;
1733ad8b1aafSjsg 
1734ad8b1aafSjsg 	list_replace(&fence->cb_list, &cb_list);
1735ad8b1aafSjsg 
17365ca02815Sjsg 	fence->timestamp = timestamp;
1737ad8b1aafSjsg 	set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
1738ad8b1aafSjsg 
1739ad8b1aafSjsg 	list_for_each_entry_safe(cur, tmp, &cb_list, node) {
1740ad8b1aafSjsg 		INIT_LIST_HEAD(&cur->node);
1741ad8b1aafSjsg 		cur->func(fence, cur);
1742ad8b1aafSjsg 	}
1743ad8b1aafSjsg 
1744ad8b1aafSjsg 	return 0;
1745ad8b1aafSjsg }
1746ad8b1aafSjsg 
1747ad8b1aafSjsg int
1748ad8b1aafSjsg dma_fence_signal(struct dma_fence *fence)
1749ad8b1aafSjsg {
1750ad8b1aafSjsg 	int r;
1751ad8b1aafSjsg 
1752ad8b1aafSjsg 	if (fence == NULL)
1753ad8b1aafSjsg 		return -EINVAL;
1754ad8b1aafSjsg 
1755ad8b1aafSjsg 	mtx_enter(fence->lock);
17565ca02815Sjsg 	r = dma_fence_signal_timestamp_locked(fence, ktime_get());
17575ca02815Sjsg 	mtx_leave(fence->lock);
17585ca02815Sjsg 
17595ca02815Sjsg 	return r;
17605ca02815Sjsg }
17615ca02815Sjsg 
17625ca02815Sjsg int
17635ca02815Sjsg dma_fence_signal_locked(struct dma_fence *fence)
17645ca02815Sjsg {
17655ca02815Sjsg 	if (fence == NULL)
17665ca02815Sjsg 		return -EINVAL;
17675ca02815Sjsg 
17685ca02815Sjsg 	return dma_fence_signal_timestamp_locked(fence, ktime_get());
17695ca02815Sjsg }
17705ca02815Sjsg 
17715ca02815Sjsg int
17725ca02815Sjsg dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp)
17735ca02815Sjsg {
17745ca02815Sjsg 	int r;
17755ca02815Sjsg 
17765ca02815Sjsg 	if (fence == NULL)
17775ca02815Sjsg 		return -EINVAL;
17785ca02815Sjsg 
17795ca02815Sjsg 	mtx_enter(fence->lock);
17805ca02815Sjsg 	r = dma_fence_signal_timestamp_locked(fence, timestamp);
1781ad8b1aafSjsg 	mtx_leave(fence->lock);
1782ad8b1aafSjsg 
1783ad8b1aafSjsg 	return r;
1784ad8b1aafSjsg }
1785ad8b1aafSjsg 
1786ad8b1aafSjsg bool
1787ad8b1aafSjsg dma_fence_is_signaled(struct dma_fence *fence)
1788ad8b1aafSjsg {
1789ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1790ad8b1aafSjsg 		return true;
1791ad8b1aafSjsg 
1792ad8b1aafSjsg 	if (fence->ops->signaled && fence->ops->signaled(fence)) {
1793ad8b1aafSjsg 		dma_fence_signal(fence);
1794ad8b1aafSjsg 		return true;
1795ad8b1aafSjsg 	}
1796ad8b1aafSjsg 
1797ad8b1aafSjsg 	return false;
1798ad8b1aafSjsg }
1799ad8b1aafSjsg 
1800ad8b1aafSjsg bool
1801ad8b1aafSjsg dma_fence_is_signaled_locked(struct dma_fence *fence)
1802ad8b1aafSjsg {
1803ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1804ad8b1aafSjsg 		return true;
1805ad8b1aafSjsg 
1806ad8b1aafSjsg 	if (fence->ops->signaled && fence->ops->signaled(fence)) {
1807ad8b1aafSjsg 		dma_fence_signal_locked(fence);
1808ad8b1aafSjsg 		return true;
1809ad8b1aafSjsg 	}
1810ad8b1aafSjsg 
1811ad8b1aafSjsg 	return false;
1812ad8b1aafSjsg }
1813ad8b1aafSjsg 
18145158102cSjsg ktime_t
18155158102cSjsg dma_fence_timestamp(struct dma_fence *fence)
18165158102cSjsg {
18175158102cSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
18185158102cSjsg 		while (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
18195158102cSjsg 			CPU_BUSY_CYCLE();
18205158102cSjsg 		return fence->timestamp;
18215158102cSjsg 	} else {
18225158102cSjsg 		return ktime_get();
18235158102cSjsg 	}
18245158102cSjsg }
18255158102cSjsg 
1826ad8b1aafSjsg long
1827ad8b1aafSjsg dma_fence_wait_timeout(struct dma_fence *fence, bool intr, long timeout)
1828ad8b1aafSjsg {
1829ad8b1aafSjsg 	if (timeout < 0)
1830ad8b1aafSjsg 		return -EINVAL;
1831ad8b1aafSjsg 
1832ad8b1aafSjsg 	if (fence->ops->wait)
1833ad8b1aafSjsg 		return fence->ops->wait(fence, intr, timeout);
1834ad8b1aafSjsg 	else
1835ad8b1aafSjsg 		return dma_fence_default_wait(fence, intr, timeout);
1836ad8b1aafSjsg }
1837ad8b1aafSjsg 
1838ad8b1aafSjsg long
1839ad8b1aafSjsg dma_fence_wait(struct dma_fence *fence, bool intr)
1840ad8b1aafSjsg {
1841ad8b1aafSjsg 	long ret;
1842ad8b1aafSjsg 
1843ad8b1aafSjsg 	ret = dma_fence_wait_timeout(fence, intr, MAX_SCHEDULE_TIMEOUT);
1844ad8b1aafSjsg 	if (ret < 0)
1845ad8b1aafSjsg 		return ret;
1846ad8b1aafSjsg 
1847ad8b1aafSjsg 	return 0;
1848ad8b1aafSjsg }
1849ad8b1aafSjsg 
1850ad8b1aafSjsg void
1851ad8b1aafSjsg dma_fence_enable_sw_signaling(struct dma_fence *fence)
1852ad8b1aafSjsg {
1853ad8b1aafSjsg 	if (!test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags) &&
1854ad8b1aafSjsg 	    !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
1855ad8b1aafSjsg 	    fence->ops->enable_signaling) {
1856ad8b1aafSjsg 		mtx_enter(fence->lock);
1857ad8b1aafSjsg 		if (!fence->ops->enable_signaling(fence))
1858ad8b1aafSjsg 			dma_fence_signal_locked(fence);
1859ad8b1aafSjsg 		mtx_leave(fence->lock);
1860ad8b1aafSjsg 	}
1861ad8b1aafSjsg }
1862ad8b1aafSjsg 
1863ad8b1aafSjsg void
1864ad8b1aafSjsg dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
1865ad8b1aafSjsg     struct mutex *lock, uint64_t context, uint64_t seqno)
1866ad8b1aafSjsg {
1867ad8b1aafSjsg 	fence->ops = ops;
1868ad8b1aafSjsg 	fence->lock = lock;
1869ad8b1aafSjsg 	fence->context = context;
1870ad8b1aafSjsg 	fence->seqno = seqno;
1871ad8b1aafSjsg 	fence->flags = 0;
1872ad8b1aafSjsg 	fence->error = 0;
1873ad8b1aafSjsg 	kref_init(&fence->refcount);
1874ad8b1aafSjsg 	INIT_LIST_HEAD(&fence->cb_list);
1875ad8b1aafSjsg }
1876ad8b1aafSjsg 
1877ad8b1aafSjsg int
1878ad8b1aafSjsg dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
1879ad8b1aafSjsg     dma_fence_func_t func)
1880ad8b1aafSjsg {
1881ad8b1aafSjsg 	int ret = 0;
1882ad8b1aafSjsg 	bool was_set;
1883ad8b1aafSjsg 
1884ad8b1aafSjsg 	if (WARN_ON(!fence || !func))
1885ad8b1aafSjsg 		return -EINVAL;
1886ad8b1aafSjsg 
1887ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
1888ad8b1aafSjsg 		INIT_LIST_HEAD(&cb->node);
1889ad8b1aafSjsg 		return -ENOENT;
1890ad8b1aafSjsg 	}
1891ad8b1aafSjsg 
1892ad8b1aafSjsg 	mtx_enter(fence->lock);
1893ad8b1aafSjsg 
1894ad8b1aafSjsg 	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags);
1895ad8b1aafSjsg 
1896ad8b1aafSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
1897ad8b1aafSjsg 		ret = -ENOENT;
1898ad8b1aafSjsg 	else if (!was_set && fence->ops->enable_signaling) {
1899ad8b1aafSjsg 		if (!fence->ops->enable_signaling(fence)) {
1900ad8b1aafSjsg 			dma_fence_signal_locked(fence);
1901ad8b1aafSjsg 			ret = -ENOENT;
1902ad8b1aafSjsg 		}
1903ad8b1aafSjsg 	}
1904ad8b1aafSjsg 
1905ad8b1aafSjsg 	if (!ret) {
1906ad8b1aafSjsg 		cb->func = func;
1907ad8b1aafSjsg 		list_add_tail(&cb->node, &fence->cb_list);
1908ad8b1aafSjsg 	} else
1909ad8b1aafSjsg 		INIT_LIST_HEAD(&cb->node);
1910ad8b1aafSjsg 	mtx_leave(fence->lock);
1911ad8b1aafSjsg 
1912ad8b1aafSjsg 	return ret;
1913ad8b1aafSjsg }
1914ad8b1aafSjsg 
1915ad8b1aafSjsg bool
1916ad8b1aafSjsg dma_fence_remove_callback(struct dma_fence *fence, struct dma_fence_cb *cb)
1917ad8b1aafSjsg {
1918ad8b1aafSjsg 	bool ret;
1919ad8b1aafSjsg 
1920ad8b1aafSjsg 	mtx_enter(fence->lock);
1921ad8b1aafSjsg 
1922ad8b1aafSjsg 	ret = !list_empty(&cb->node);
1923ad8b1aafSjsg 	if (ret)
1924ad8b1aafSjsg 		list_del_init(&cb->node);
1925ad8b1aafSjsg 
1926ad8b1aafSjsg 	mtx_leave(fence->lock);
1927ad8b1aafSjsg 
1928ad8b1aafSjsg 	return ret;
1929ad8b1aafSjsg }
1930ad8b1aafSjsg 
1931c349dbc7Sjsg static atomic64_t drm_fence_context_count = ATOMIC64_INIT(1);
19327ccd5a2cSjsg 
1933c349dbc7Sjsg uint64_t
19347f4dd379Sjsg dma_fence_context_alloc(unsigned int num)
19357ccd5a2cSjsg {
1936c349dbc7Sjsg   return atomic64_add_return(num, &drm_fence_context_count) - num;
19377ccd5a2cSjsg }
1938a9ee023bSkettenis 
1939537ee4c6Sjsg struct default_wait_cb {
1940537ee4c6Sjsg 	struct dma_fence_cb base;
1941537ee4c6Sjsg 	struct proc *proc;
1942537ee4c6Sjsg };
1943537ee4c6Sjsg 
194413e5339cSjsg static void
194513e5339cSjsg dma_fence_default_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
194613e5339cSjsg {
1947537ee4c6Sjsg 	struct default_wait_cb *wait =
1948537ee4c6Sjsg 	    container_of(cb, struct default_wait_cb, base);
194956a2da50Sjsg 	wake_up_process(wait->proc);
195013e5339cSjsg }
195113e5339cSjsg 
195213e5339cSjsg long
195313e5339cSjsg dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
195413e5339cSjsg {
195513e5339cSjsg 	long ret = timeout ? timeout : 1;
195619fc7f4fSjsg 	unsigned long end;
195713e5339cSjsg 	int err;
1958537ee4c6Sjsg 	struct default_wait_cb cb;
195913e5339cSjsg 	bool was_set;
196013e5339cSjsg 
196119fc7f4fSjsg 	KASSERT(timeout <= INT_MAX);
196219fc7f4fSjsg 
196313e5339cSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
196413e5339cSjsg 		return ret;
196513e5339cSjsg 
196613e5339cSjsg 	mtx_enter(fence->lock);
196713e5339cSjsg 
196813e5339cSjsg 	was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
196913e5339cSjsg 	    &fence->flags);
197013e5339cSjsg 
197113e5339cSjsg 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
197213e5339cSjsg 		goto out;
197313e5339cSjsg 
197413e5339cSjsg 	if (!was_set && fence->ops->enable_signaling) {
197513e5339cSjsg 		if (!fence->ops->enable_signaling(fence)) {
197613e5339cSjsg 			dma_fence_signal_locked(fence);
197713e5339cSjsg 			goto out;
197813e5339cSjsg 		}
197913e5339cSjsg 	}
198013e5339cSjsg 
198113e5339cSjsg 	if (timeout == 0) {
198213e5339cSjsg 		ret = 0;
198313e5339cSjsg 		goto out;
198413e5339cSjsg 	}
198513e5339cSjsg 
1986537ee4c6Sjsg 	cb.base.func = dma_fence_default_wait_cb;
1987537ee4c6Sjsg 	cb.proc = curproc;
1988537ee4c6Sjsg 	list_add(&cb.base.node, &fence->cb_list);
198913e5339cSjsg 
199019fc7f4fSjsg 	end = jiffies + timeout;
199119fc7f4fSjsg 	for (ret = timeout; ret > 0; ret = MAX(0, end - jiffies)) {
199219fc7f4fSjsg 		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
199319fc7f4fSjsg 			break;
199419fc7f4fSjsg 		err = msleep(curproc, fence->lock, intr ? PCATCH : 0,
199519fc7f4fSjsg 		    "dmafence", ret);
199613e5339cSjsg 		if (err == EINTR || err == ERESTART) {
199713e5339cSjsg 			ret = -ERESTARTSYS;
199813e5339cSjsg 			break;
199913e5339cSjsg 		}
200013e5339cSjsg 	}
200113e5339cSjsg 
2002537ee4c6Sjsg 	if (!list_empty(&cb.base.node))
2003537ee4c6Sjsg 		list_del(&cb.base.node);
200413e5339cSjsg out:
200513e5339cSjsg 	mtx_leave(fence->lock);
200613e5339cSjsg 
200713e5339cSjsg 	return ret;
200813e5339cSjsg }
200913e5339cSjsg 
2010537ee4c6Sjsg static bool
2011537ee4c6Sjsg dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count,
2012537ee4c6Sjsg     uint32_t *idx)
2013537ee4c6Sjsg {
2014537ee4c6Sjsg 	int i;
2015537ee4c6Sjsg 
2016537ee4c6Sjsg 	for (i = 0; i < count; ++i) {
2017537ee4c6Sjsg 		struct dma_fence *fence = fences[i];
2018537ee4c6Sjsg 		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
2019537ee4c6Sjsg 			if (idx)
2020537ee4c6Sjsg 				*idx = i;
2021537ee4c6Sjsg 			return true;
2022537ee4c6Sjsg 		}
2023537ee4c6Sjsg 	}
2024537ee4c6Sjsg 	return false;
2025537ee4c6Sjsg }
2026537ee4c6Sjsg 
2027537ee4c6Sjsg long
2028537ee4c6Sjsg dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count,
2029537ee4c6Sjsg     bool intr, long timeout, uint32_t *idx)
2030537ee4c6Sjsg {
2031537ee4c6Sjsg 	struct default_wait_cb *cb;
203219fc7f4fSjsg 	long ret = timeout;
203319fc7f4fSjsg 	unsigned long end;
2034537ee4c6Sjsg 	int i, err;
203519fc7f4fSjsg 
203619fc7f4fSjsg 	KASSERT(timeout <= INT_MAX);
2037537ee4c6Sjsg 
2038537ee4c6Sjsg 	if (timeout == 0) {
2039537ee4c6Sjsg 		for (i = 0; i < count; i++) {
2040537ee4c6Sjsg 			if (dma_fence_is_signaled(fences[i])) {
2041537ee4c6Sjsg 				if (idx)
2042537ee4c6Sjsg 					*idx = i;
2043537ee4c6Sjsg 				return 1;
2044537ee4c6Sjsg 			}
2045537ee4c6Sjsg 		}
2046537ee4c6Sjsg 		return 0;
2047537ee4c6Sjsg 	}
2048537ee4c6Sjsg 
2049537ee4c6Sjsg 	cb = mallocarray(count, sizeof(*cb), M_DRM, M_WAITOK|M_CANFAIL|M_ZERO);
2050537ee4c6Sjsg 	if (cb == NULL)
2051537ee4c6Sjsg 		return -ENOMEM;
2052537ee4c6Sjsg 
2053537ee4c6Sjsg 	for (i = 0; i < count; i++) {
2054537ee4c6Sjsg 		struct dma_fence *fence = fences[i];
2055537ee4c6Sjsg 		cb[i].proc = curproc;
2056537ee4c6Sjsg 		if (dma_fence_add_callback(fence, &cb[i].base,
2057537ee4c6Sjsg 		    dma_fence_default_wait_cb)) {
2058537ee4c6Sjsg 			if (idx)
2059537ee4c6Sjsg 				*idx = i;
2060537ee4c6Sjsg 			goto cb_cleanup;
2061537ee4c6Sjsg 		}
2062537ee4c6Sjsg 	}
2063537ee4c6Sjsg 
206419fc7f4fSjsg 	end = jiffies + timeout;
206519fc7f4fSjsg 	for (ret = timeout; ret > 0; ret = MAX(0, end - jiffies)) {
2066537ee4c6Sjsg 		if (dma_fence_test_signaled_any(fences, count, idx))
2067537ee4c6Sjsg 			break;
206819fc7f4fSjsg 		err = tsleep(curproc, intr ? PCATCH : 0, "dfwat", ret);
2069537ee4c6Sjsg 		if (err == EINTR || err == ERESTART) {
2070537ee4c6Sjsg 			ret = -ERESTARTSYS;
2071537ee4c6Sjsg 			break;
2072537ee4c6Sjsg 		}
2073537ee4c6Sjsg 	}
2074537ee4c6Sjsg 
2075537ee4c6Sjsg cb_cleanup:
2076537ee4c6Sjsg 	while (i-- > 0)
2077537ee4c6Sjsg 		dma_fence_remove_callback(fences[i], &cb[i].base);
2078537ee4c6Sjsg 	free(cb, M_DRM, count * sizeof(*cb));
2079537ee4c6Sjsg 	return ret;
2080537ee4c6Sjsg }
2081537ee4c6Sjsg 
2082f005ef32Sjsg void
2083f005ef32Sjsg dma_fence_set_deadline(struct dma_fence *f, ktime_t t)
2084f005ef32Sjsg {
2085f005ef32Sjsg 	if (f->ops->set_deadline == NULL)
2086f005ef32Sjsg 		return;
2087f005ef32Sjsg 	if (dma_fence_is_signaled(f) == false)
2088f005ef32Sjsg 		f->ops->set_deadline(f, t);
2089f005ef32Sjsg }
2090f005ef32Sjsg 
2091c349dbc7Sjsg static struct dma_fence dma_fence_stub;
2092c349dbc7Sjsg static struct mutex dma_fence_stub_mtx = MUTEX_INITIALIZER(IPL_TTY);
2093c349dbc7Sjsg 
2094c349dbc7Sjsg static const char *
2095c349dbc7Sjsg dma_fence_stub_get_name(struct dma_fence *fence)
2096c349dbc7Sjsg {
2097c349dbc7Sjsg 	return "stub";
2098c349dbc7Sjsg }
2099c349dbc7Sjsg 
2100c349dbc7Sjsg static const struct dma_fence_ops dma_fence_stub_ops = {
2101c349dbc7Sjsg 	.get_driver_name = dma_fence_stub_get_name,
2102c349dbc7Sjsg 	.get_timeline_name = dma_fence_stub_get_name,
2103c349dbc7Sjsg };
2104c349dbc7Sjsg 
2105c349dbc7Sjsg struct dma_fence *
2106c349dbc7Sjsg dma_fence_get_stub(void)
2107c349dbc7Sjsg {
2108c349dbc7Sjsg 	mtx_enter(&dma_fence_stub_mtx);
2109c349dbc7Sjsg 	if (dma_fence_stub.ops == NULL) {
2110c349dbc7Sjsg 		dma_fence_init(&dma_fence_stub, &dma_fence_stub_ops,
2111c349dbc7Sjsg 		    &dma_fence_stub_mtx, 0, 0);
2112c349dbc7Sjsg 		dma_fence_signal_locked(&dma_fence_stub);
2113c349dbc7Sjsg 	}
2114c349dbc7Sjsg 	mtx_leave(&dma_fence_stub_mtx);
2115c349dbc7Sjsg 
2116c349dbc7Sjsg 	return dma_fence_get(&dma_fence_stub);
2117c349dbc7Sjsg }
2118c349dbc7Sjsg 
21195ca02815Sjsg struct dma_fence *
2120e80177aeSjsg dma_fence_allocate_private_stub(ktime_t ts)
21215ca02815Sjsg {
21225ca02815Sjsg 	struct dma_fence *f = malloc(sizeof(*f), M_DRM,
21235ca02815Sjsg 	    M_ZERO | M_WAITOK | M_CANFAIL);
21245ca02815Sjsg 	if (f == NULL)
2125f69d21f3Sjsg 		return NULL;
21265ca02815Sjsg 	dma_fence_init(f, &dma_fence_stub_ops, &dma_fence_stub_mtx, 0, 0);
2127e80177aeSjsg 	dma_fence_signal_timestamp(f, ts);
21285ca02815Sjsg 	return f;
21295ca02815Sjsg }
21305ca02815Sjsg 
213195f00a37Sjsg static const char *
213295f00a37Sjsg dma_fence_array_get_driver_name(struct dma_fence *fence)
213395f00a37Sjsg {
213495f00a37Sjsg 	return "dma_fence_array";
213595f00a37Sjsg }
213695f00a37Sjsg 
213795f00a37Sjsg static const char *
213895f00a37Sjsg dma_fence_array_get_timeline_name(struct dma_fence *fence)
213995f00a37Sjsg {
214095f00a37Sjsg 	return "unbound";
214195f00a37Sjsg }
214295f00a37Sjsg 
214395f00a37Sjsg static void
21445ca02815Sjsg irq_dma_fence_array_work(void *arg)
214595f00a37Sjsg {
21465ca02815Sjsg 	struct dma_fence_array *dfa = (struct dma_fence_array *)arg;
214795f00a37Sjsg 	dma_fence_signal(&dfa->base);
214895f00a37Sjsg 	dma_fence_put(&dfa->base);
214995f00a37Sjsg }
215095f00a37Sjsg 
215195f00a37Sjsg static void
215295f00a37Sjsg dma_fence_array_cb_func(struct dma_fence *f, struct dma_fence_cb *cb)
215395f00a37Sjsg {
215495f00a37Sjsg 	struct dma_fence_array_cb *array_cb =
215595f00a37Sjsg 	    container_of(cb, struct dma_fence_array_cb, cb);
215695f00a37Sjsg 	struct dma_fence_array *dfa = array_cb->array;
215795f00a37Sjsg 
215895f00a37Sjsg 	if (atomic_dec_and_test(&dfa->num_pending))
21595ca02815Sjsg 		timeout_add(&dfa->to, 1);
216095f00a37Sjsg 	else
216195f00a37Sjsg 		dma_fence_put(&dfa->base);
216295f00a37Sjsg }
216395f00a37Sjsg 
216495f00a37Sjsg static bool
216595f00a37Sjsg dma_fence_array_enable_signaling(struct dma_fence *fence)
216695f00a37Sjsg {
216795f00a37Sjsg 	struct dma_fence_array *dfa = to_dma_fence_array(fence);
216895f00a37Sjsg 	struct dma_fence_array_cb *cb = (void *)(&dfa[1]);
216995f00a37Sjsg 	int i;
217095f00a37Sjsg 
217195f00a37Sjsg 	for (i = 0; i < dfa->num_fences; ++i) {
217295f00a37Sjsg 		cb[i].array = dfa;
217395f00a37Sjsg 		dma_fence_get(&dfa->base);
217495f00a37Sjsg 		if (dma_fence_add_callback(dfa->fences[i], &cb[i].cb,
217595f00a37Sjsg 		    dma_fence_array_cb_func)) {
217695f00a37Sjsg 			dma_fence_put(&dfa->base);
217795f00a37Sjsg 			if (atomic_dec_and_test(&dfa->num_pending))
217895f00a37Sjsg 				return false;
217995f00a37Sjsg 		}
218095f00a37Sjsg 	}
218195f00a37Sjsg 
218295f00a37Sjsg 	return true;
218395f00a37Sjsg }
218495f00a37Sjsg 
2185ad8b1aafSjsg static bool
2186ad8b1aafSjsg dma_fence_array_signaled(struct dma_fence *fence)
218795f00a37Sjsg {
218895f00a37Sjsg 	struct dma_fence_array *dfa = to_dma_fence_array(fence);
218995f00a37Sjsg 
219095f00a37Sjsg 	return atomic_read(&dfa->num_pending) <= 0;
219195f00a37Sjsg }
219295f00a37Sjsg 
2193ad8b1aafSjsg static void
2194ad8b1aafSjsg dma_fence_array_release(struct dma_fence *fence)
219595f00a37Sjsg {
219695f00a37Sjsg 	struct dma_fence_array *dfa = to_dma_fence_array(fence);
219795f00a37Sjsg 	int i;
219895f00a37Sjsg 
219995f00a37Sjsg 	for (i = 0; i < dfa->num_fences; ++i)
220095f00a37Sjsg 		dma_fence_put(dfa->fences[i]);
220195f00a37Sjsg 
220295f00a37Sjsg 	free(dfa->fences, M_DRM, 0);
220395f00a37Sjsg 	dma_fence_free(fence);
220495f00a37Sjsg }
220595f00a37Sjsg 
220695f00a37Sjsg struct dma_fence_array *
220795f00a37Sjsg dma_fence_array_create(int num_fences, struct dma_fence **fences, u64 context,
220895f00a37Sjsg     unsigned seqno, bool signal_on_any)
220995f00a37Sjsg {
221095f00a37Sjsg 	struct dma_fence_array *dfa = malloc(sizeof(*dfa) +
221195f00a37Sjsg 	    (num_fences * sizeof(struct dma_fence_array_cb)),
221295f00a37Sjsg 	    M_DRM, M_WAITOK|M_CANFAIL|M_ZERO);
221395f00a37Sjsg 	if (dfa == NULL)
221495f00a37Sjsg 		return NULL;
221595f00a37Sjsg 
221695f00a37Sjsg 	mtx_init(&dfa->lock, IPL_TTY);
221795f00a37Sjsg 	dma_fence_init(&dfa->base, &dma_fence_array_ops, &dfa->lock,
221895f00a37Sjsg 	    context, seqno);
22195ca02815Sjsg 	timeout_set(&dfa->to, irq_dma_fence_array_work, dfa);
222095f00a37Sjsg 
222195f00a37Sjsg 	dfa->num_fences = num_fences;
222295f00a37Sjsg 	atomic_set(&dfa->num_pending, signal_on_any ? 1 : num_fences);
222395f00a37Sjsg 	dfa->fences = fences;
222495f00a37Sjsg 
222595f00a37Sjsg 	return dfa;
222695f00a37Sjsg }
222795f00a37Sjsg 
22281bb76ff1Sjsg struct dma_fence *
22291bb76ff1Sjsg dma_fence_array_first(struct dma_fence *f)
22301bb76ff1Sjsg {
22311bb76ff1Sjsg 	struct dma_fence_array *dfa;
22321bb76ff1Sjsg 
22331bb76ff1Sjsg 	if (f == NULL)
22341bb76ff1Sjsg 		return NULL;
22351bb76ff1Sjsg 
22361bb76ff1Sjsg 	if ((dfa = to_dma_fence_array(f)) == NULL)
22371bb76ff1Sjsg 		return f;
22381bb76ff1Sjsg 
22391bb76ff1Sjsg 	if (dfa->num_fences > 0)
22401bb76ff1Sjsg 		return dfa->fences[0];
22411bb76ff1Sjsg 
22421bb76ff1Sjsg 	return NULL;
22431bb76ff1Sjsg }
22441bb76ff1Sjsg 
22451bb76ff1Sjsg struct dma_fence *
22461bb76ff1Sjsg dma_fence_array_next(struct dma_fence *f, unsigned int i)
22471bb76ff1Sjsg {
22481bb76ff1Sjsg 	struct dma_fence_array *dfa;
22491bb76ff1Sjsg 
22501bb76ff1Sjsg 	if (f == NULL)
22511bb76ff1Sjsg 		return NULL;
22521bb76ff1Sjsg 
22531bb76ff1Sjsg 	if ((dfa = to_dma_fence_array(f)) == NULL)
22541bb76ff1Sjsg 		return NULL;
22551bb76ff1Sjsg 
22561bb76ff1Sjsg 	if (i < dfa->num_fences)
22571bb76ff1Sjsg 		return dfa->fences[i];
22581bb76ff1Sjsg 
22591bb76ff1Sjsg 	return NULL;
22601bb76ff1Sjsg }
22611bb76ff1Sjsg 
226295f00a37Sjsg const struct dma_fence_ops dma_fence_array_ops = {
226395f00a37Sjsg 	.get_driver_name = dma_fence_array_get_driver_name,
226495f00a37Sjsg 	.get_timeline_name = dma_fence_array_get_timeline_name,
226595f00a37Sjsg 	.enable_signaling = dma_fence_array_enable_signaling,
226695f00a37Sjsg 	.signaled = dma_fence_array_signaled,
226795f00a37Sjsg 	.release = dma_fence_array_release,
226895f00a37Sjsg };
226995f00a37Sjsg 
2270a9ee023bSkettenis int
2271ad8b1aafSjsg dma_fence_chain_find_seqno(struct dma_fence **df, uint64_t seqno)
2272ad8b1aafSjsg {
2273f56254deSjsg 	struct dma_fence_chain *chain;
2274f56254deSjsg 	struct dma_fence *fence;
2275f56254deSjsg 
2276ad8b1aafSjsg 	if (seqno == 0)
2277ad8b1aafSjsg 		return 0;
2278f56254deSjsg 
2279f56254deSjsg 	if ((chain = to_dma_fence_chain(*df)) == NULL)
2280f56254deSjsg 		return -EINVAL;
2281f56254deSjsg 
2282f56254deSjsg 	fence = &chain->base;
2283f56254deSjsg 	if (fence->seqno < seqno)
2284f56254deSjsg 		return -EINVAL;
2285f56254deSjsg 
2286f56254deSjsg 	dma_fence_chain_for_each(*df, fence) {
2287f56254deSjsg 		if ((*df)->context != fence->context)
2288f56254deSjsg 			break;
2289f56254deSjsg 
2290f56254deSjsg 		chain = to_dma_fence_chain(*df);
2291f56254deSjsg 		if (chain->prev_seqno < seqno)
2292f56254deSjsg 			break;
2293f56254deSjsg 	}
2294f56254deSjsg 	dma_fence_put(fence);
2295f56254deSjsg 
2296f56254deSjsg 	return 0;
2297ad8b1aafSjsg }
2298ad8b1aafSjsg 
2299ad8b1aafSjsg void
2300ad8b1aafSjsg dma_fence_chain_init(struct dma_fence_chain *chain, struct dma_fence *prev,
2301ad8b1aafSjsg     struct dma_fence *fence, uint64_t seqno)
2302ad8b1aafSjsg {
2303ad8b1aafSjsg 	uint64_t context;
2304ad8b1aafSjsg 
2305ad8b1aafSjsg 	chain->fence = fence;
2306ad8b1aafSjsg 	chain->prev = prev;
2307ad8b1aafSjsg 	mtx_init(&chain->lock, IPL_TTY);
2308ad8b1aafSjsg 
23095ca02815Sjsg 	/* if prev is a chain */
23105ca02815Sjsg 	if (to_dma_fence_chain(prev) != NULL) {
2311bcd4d0b5Sjsg 		if (__dma_fence_is_later(seqno, prev->seqno, prev->ops)) {
2312ad8b1aafSjsg 			chain->prev_seqno = prev->seqno;
2313ad8b1aafSjsg 			context = prev->context;
2314ad8b1aafSjsg 		} else {
2315ad8b1aafSjsg 			chain->prev_seqno = 0;
2316ad8b1aafSjsg 			context = dma_fence_context_alloc(1);
23175ca02815Sjsg 			seqno = prev->seqno;
23185ca02815Sjsg 		}
23195ca02815Sjsg 	} else {
23205ca02815Sjsg 		chain->prev_seqno = 0;
23215ca02815Sjsg 		context = dma_fence_context_alloc(1);
2322ad8b1aafSjsg 	}
2323ad8b1aafSjsg 
2324ad8b1aafSjsg 	dma_fence_init(&chain->base, &dma_fence_chain_ops, &chain->lock,
2325ad8b1aafSjsg 	    context, seqno);
2326ad8b1aafSjsg }
2327ad8b1aafSjsg 
2328ad8b1aafSjsg static const char *
2329ad8b1aafSjsg dma_fence_chain_get_driver_name(struct dma_fence *fence)
2330ad8b1aafSjsg {
2331ad8b1aafSjsg 	return "dma_fence_chain";
2332ad8b1aafSjsg }
2333ad8b1aafSjsg 
2334ad8b1aafSjsg static const char *
2335ad8b1aafSjsg dma_fence_chain_get_timeline_name(struct dma_fence *fence)
2336ad8b1aafSjsg {
2337ad8b1aafSjsg 	return "unbound";
2338ad8b1aafSjsg }
2339ad8b1aafSjsg 
23405ca02815Sjsg static bool dma_fence_chain_enable_signaling(struct dma_fence *);
23415ca02815Sjsg 
23425ca02815Sjsg static void
23435ca02815Sjsg dma_fence_chain_timo(void *arg)
23445ca02815Sjsg {
23455ca02815Sjsg 	struct dma_fence_chain *chain = (struct dma_fence_chain *)arg;
23465ca02815Sjsg 
23475ca02815Sjsg 	if (dma_fence_chain_enable_signaling(&chain->base) == false)
23485ca02815Sjsg 		dma_fence_signal(&chain->base);
23495ca02815Sjsg 	dma_fence_put(&chain->base);
23505ca02815Sjsg }
23515ca02815Sjsg 
23525ca02815Sjsg static void
23535ca02815Sjsg dma_fence_chain_cb(struct dma_fence *f, struct dma_fence_cb *cb)
23545ca02815Sjsg {
23555ca02815Sjsg 	struct dma_fence_chain *chain =
23565ca02815Sjsg 	    container_of(cb, struct dma_fence_chain, cb);
23575ca02815Sjsg 	timeout_set(&chain->to, dma_fence_chain_timo, chain);
23585ca02815Sjsg 	timeout_add(&chain->to, 1);
23595ca02815Sjsg 	dma_fence_put(f);
23605ca02815Sjsg }
23615ca02815Sjsg 
2362ad8b1aafSjsg static bool
2363ad8b1aafSjsg dma_fence_chain_enable_signaling(struct dma_fence *fence)
2364ad8b1aafSjsg {
23655ca02815Sjsg 	struct dma_fence_chain *chain, *h;
23665ca02815Sjsg 	struct dma_fence *f;
23675ca02815Sjsg 
23685ca02815Sjsg 	h = to_dma_fence_chain(fence);
23695ca02815Sjsg 	dma_fence_get(&h->base);
23705ca02815Sjsg 	dma_fence_chain_for_each(fence, &h->base) {
23715ca02815Sjsg 		chain = to_dma_fence_chain(fence);
23725ca02815Sjsg 		if (chain == NULL)
23735ca02815Sjsg 			f = fence;
23745ca02815Sjsg 		else
23755ca02815Sjsg 			f = chain->fence;
23765ca02815Sjsg 
23775ca02815Sjsg 		dma_fence_get(f);
23785ca02815Sjsg 		if (!dma_fence_add_callback(f, &h->cb, dma_fence_chain_cb)) {
23795ca02815Sjsg 			dma_fence_put(fence);
23805ca02815Sjsg 			return true;
23815ca02815Sjsg 		}
23825ca02815Sjsg 		dma_fence_put(f);
23835ca02815Sjsg 	}
23845ca02815Sjsg 	dma_fence_put(&h->base);
2385ad8b1aafSjsg 	return false;
2386ad8b1aafSjsg }
2387ad8b1aafSjsg 
2388ad8b1aafSjsg static bool
2389ad8b1aafSjsg dma_fence_chain_signaled(struct dma_fence *fence)
2390ad8b1aafSjsg {
23915ca02815Sjsg 	struct dma_fence_chain *chain;
23925ca02815Sjsg 	struct dma_fence *f;
23935ca02815Sjsg 
23945ca02815Sjsg 	dma_fence_chain_for_each(fence, fence) {
23955ca02815Sjsg 		chain = to_dma_fence_chain(fence);
23965ca02815Sjsg 		if (chain == NULL)
23975ca02815Sjsg 			f = fence;
23985ca02815Sjsg 		else
23995ca02815Sjsg 			f = chain->fence;
24005ca02815Sjsg 
24015ca02815Sjsg 		if (dma_fence_is_signaled(f) == false) {
24025ca02815Sjsg 			dma_fence_put(fence);
2403ad8b1aafSjsg 			return false;
2404ad8b1aafSjsg 		}
24055ca02815Sjsg 	}
24065ca02815Sjsg 	return true;
24075ca02815Sjsg }
2408ad8b1aafSjsg 
2409ad8b1aafSjsg static void
2410ad8b1aafSjsg dma_fence_chain_release(struct dma_fence *fence)
2411ad8b1aafSjsg {
24125ca02815Sjsg 	struct dma_fence_chain *chain = to_dma_fence_chain(fence);
24135ca02815Sjsg 	struct dma_fence_chain *prev_chain;
24145ca02815Sjsg 	struct dma_fence *prev;
24155ca02815Sjsg 
24165ca02815Sjsg 	for (prev = chain->prev; prev != NULL; prev = chain->prev) {
24175ca02815Sjsg 		if (kref_read(&prev->refcount) > 1)
24185ca02815Sjsg 			break;
24195ca02815Sjsg 		if ((prev_chain = to_dma_fence_chain(prev)) == NULL)
24205ca02815Sjsg 			break;
24215ca02815Sjsg 		chain->prev = prev_chain->prev;
24225ca02815Sjsg 		prev_chain->prev = NULL;
24235ca02815Sjsg 		dma_fence_put(prev);
24245ca02815Sjsg 	}
24255ca02815Sjsg 	dma_fence_put(prev);
24265ca02815Sjsg 	dma_fence_put(chain->fence);
24275ca02815Sjsg 	dma_fence_free(fence);
2428ad8b1aafSjsg }
2429ad8b1aafSjsg 
2430ad8b1aafSjsg struct dma_fence *
24315ca02815Sjsg dma_fence_chain_walk(struct dma_fence *fence)
2432ad8b1aafSjsg {
24335ca02815Sjsg 	struct dma_fence_chain *chain = to_dma_fence_chain(fence), *prev_chain;
24345ca02815Sjsg 	struct dma_fence *prev, *new_prev, *tmp;
2435ad8b1aafSjsg 
2436ad8b1aafSjsg 	if (chain == NULL) {
2437ad8b1aafSjsg 		dma_fence_put(fence);
2438ad8b1aafSjsg 		return NULL;
2439ad8b1aafSjsg 	}
2440ad8b1aafSjsg 
24415ca02815Sjsg 	while ((prev = dma_fence_get(chain->prev)) != NULL) {
24425ca02815Sjsg 		prev_chain = to_dma_fence_chain(prev);
24435ca02815Sjsg 		if (prev_chain != NULL) {
24445ca02815Sjsg 			if (!dma_fence_is_signaled(prev_chain->fence))
24455ca02815Sjsg 				break;
24465ca02815Sjsg 			new_prev = dma_fence_get(prev_chain->prev);
24475ca02815Sjsg 		} else {
24485ca02815Sjsg 			if (!dma_fence_is_signaled(prev))
24495ca02815Sjsg 				break;
24505ca02815Sjsg 			new_prev = NULL;
24515ca02815Sjsg 		}
24525ca02815Sjsg 		tmp = atomic_cas_ptr(&chain->prev, prev, new_prev);
24535ca02815Sjsg 		dma_fence_put(tmp == prev ? prev : new_prev);
24545ca02815Sjsg 		dma_fence_put(prev);
24555ca02815Sjsg 	}
24565ca02815Sjsg 
2457ad8b1aafSjsg 	dma_fence_put(fence);
24585ca02815Sjsg 	return prev;
2459ad8b1aafSjsg }
2460ad8b1aafSjsg 
2461ad8b1aafSjsg const struct dma_fence_ops dma_fence_chain_ops = {
2462ad8b1aafSjsg 	.get_driver_name = dma_fence_chain_get_driver_name,
2463ad8b1aafSjsg 	.get_timeline_name = dma_fence_chain_get_timeline_name,
2464ad8b1aafSjsg 	.enable_signaling = dma_fence_chain_enable_signaling,
2465ad8b1aafSjsg 	.signaled = dma_fence_chain_signaled,
2466ad8b1aafSjsg 	.release = dma_fence_chain_release,
2467bcd4d0b5Sjsg 	.use_64bit_seqno = true,
2468ad8b1aafSjsg };
2469ad8b1aafSjsg 
24701bb76ff1Sjsg bool
24711bb76ff1Sjsg dma_fence_is_container(struct dma_fence *fence)
24721bb76ff1Sjsg {
24731bb76ff1Sjsg 	return (fence->ops == &dma_fence_chain_ops) ||
24741bb76ff1Sjsg 	    (fence->ops == &dma_fence_array_ops);
24751bb76ff1Sjsg }
24761bb76ff1Sjsg 
2477ad8b1aafSjsg int
24782bd648c0Smpi dmabuf_read(struct file *fp, struct uio *uio, int fflags)
2479a9ee023bSkettenis {
2480a9ee023bSkettenis 	return (ENXIO);
2481a9ee023bSkettenis }
2482a9ee023bSkettenis 
2483a9ee023bSkettenis int
24842bd648c0Smpi dmabuf_write(struct file *fp, struct uio *uio, int fflags)
2485a9ee023bSkettenis {
2486a9ee023bSkettenis 	return (ENXIO);
2487a9ee023bSkettenis }
2488a9ee023bSkettenis 
2489a9ee023bSkettenis int
2490a9ee023bSkettenis dmabuf_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
2491a9ee023bSkettenis {
2492a9ee023bSkettenis 	return (ENOTTY);
2493a9ee023bSkettenis }
2494a9ee023bSkettenis 
2495a9ee023bSkettenis int
2496a9ee023bSkettenis dmabuf_kqfilter(struct file *fp, struct knote *kn)
2497a9ee023bSkettenis {
2498a9ee023bSkettenis 	return (EINVAL);
2499a9ee023bSkettenis }
2500a9ee023bSkettenis 
2501a9ee023bSkettenis int
2502a9ee023bSkettenis dmabuf_stat(struct file *fp, struct stat *st, struct proc *p)
2503a9ee023bSkettenis {
2504a9ee023bSkettenis 	struct dma_buf *dmabuf = fp->f_data;
2505a9ee023bSkettenis 
2506a9ee023bSkettenis 	memset(st, 0, sizeof(*st));
2507a9ee023bSkettenis 	st->st_size = dmabuf->size;
2508a9ee023bSkettenis 	st->st_mode = S_IFIFO;	/* XXX */
2509a9ee023bSkettenis 	return (0);
2510a9ee023bSkettenis }
2511a9ee023bSkettenis 
2512a9ee023bSkettenis int
2513a9ee023bSkettenis dmabuf_close(struct file *fp, struct proc *p)
2514a9ee023bSkettenis {
2515a9ee023bSkettenis 	struct dma_buf *dmabuf = fp->f_data;
2516a9ee023bSkettenis 
2517a9ee023bSkettenis 	fp->f_data = NULL;
2518fcba5756Svisa 	KERNEL_LOCK();
2519a9ee023bSkettenis 	dmabuf->ops->release(dmabuf);
2520fcba5756Svisa 	KERNEL_UNLOCK();
2521a9ee023bSkettenis 	free(dmabuf, M_DRM, sizeof(struct dma_buf));
2522a9ee023bSkettenis 	return (0);
2523a9ee023bSkettenis }
2524a9ee023bSkettenis 
2525f3455eb0Skettenis int
2526f3455eb0Skettenis dmabuf_seek(struct file *fp, off_t *offset, int whence, struct proc *p)
2527f3455eb0Skettenis {
2528f3455eb0Skettenis 	struct dma_buf *dmabuf = fp->f_data;
2529f3455eb0Skettenis 	off_t newoff;
2530f3455eb0Skettenis 
2531f3455eb0Skettenis 	if (*offset != 0)
2532f3455eb0Skettenis 		return (EINVAL);
2533f3455eb0Skettenis 
2534f3455eb0Skettenis 	switch (whence) {
2535f3455eb0Skettenis 	case SEEK_SET:
2536f3455eb0Skettenis 		newoff = 0;
2537f3455eb0Skettenis 		break;
2538f3455eb0Skettenis 	case SEEK_END:
2539f3455eb0Skettenis 		newoff = dmabuf->size;
2540f3455eb0Skettenis 		break;
2541f3455eb0Skettenis 	default:
2542f3455eb0Skettenis 		return (EINVAL);
2543f3455eb0Skettenis 	}
2544836f297bSanton 	mtx_enter(&fp->f_mtx);
2545836f297bSanton 	fp->f_offset = newoff;
2546836f297bSanton 	mtx_leave(&fp->f_mtx);
2547836f297bSanton 	*offset = newoff;
2548f3455eb0Skettenis 	return (0);
2549f3455eb0Skettenis }
2550f3455eb0Skettenis 
2551c02bfb27Svisa const struct fileops dmabufops = {
2552a9ee023bSkettenis 	.fo_read	= dmabuf_read,
2553a9ee023bSkettenis 	.fo_write	= dmabuf_write,
2554a9ee023bSkettenis 	.fo_ioctl	= dmabuf_ioctl,
2555a9ee023bSkettenis 	.fo_kqfilter	= dmabuf_kqfilter,
2556a9ee023bSkettenis 	.fo_stat	= dmabuf_stat,
2557f3455eb0Skettenis 	.fo_close	= dmabuf_close,
2558f3455eb0Skettenis 	.fo_seek	= dmabuf_seek,
2559a9ee023bSkettenis };
2560a9ee023bSkettenis 
2561a9ee023bSkettenis struct dma_buf *
2562a9ee023bSkettenis dma_buf_export(const struct dma_buf_export_info *info)
2563a9ee023bSkettenis {
2564a9ee023bSkettenis 	struct proc *p = curproc;
2565a9ee023bSkettenis 	struct dma_buf *dmabuf;
2566a9ee023bSkettenis 	struct file *fp;
2567a9ee023bSkettenis 
2568d90ebdd6Skettenis 	fp = fnew(p);
2569d90ebdd6Skettenis 	if (fp == NULL)
2570d90ebdd6Skettenis 		return ERR_PTR(-ENFILE);
2571a9ee023bSkettenis 	fp->f_type = DTYPE_DMABUF;
2572a9ee023bSkettenis 	fp->f_ops = &dmabufops;
2573a9ee023bSkettenis 	dmabuf = malloc(sizeof(struct dma_buf), M_DRM, M_WAITOK | M_ZERO);
2574a9ee023bSkettenis 	dmabuf->priv = info->priv;
2575a9ee023bSkettenis 	dmabuf->ops = info->ops;
2576a9ee023bSkettenis 	dmabuf->size = info->size;
2577a9ee023bSkettenis 	dmabuf->file = fp;
2578a9ee023bSkettenis 	fp->f_data = dmabuf;
2579c349dbc7Sjsg 	INIT_LIST_HEAD(&dmabuf->attachments);
2580a9ee023bSkettenis 	return dmabuf;
2581a9ee023bSkettenis }
2582a9ee023bSkettenis 
2583a9ee023bSkettenis struct dma_buf *
2584a9ee023bSkettenis dma_buf_get(int fd)
2585a9ee023bSkettenis {
2586a9ee023bSkettenis 	struct proc *p = curproc;
2587a9ee023bSkettenis 	struct filedesc *fdp = p->p_fd;
2588a9ee023bSkettenis 	struct file *fp;
2589a9ee023bSkettenis 
2590a9ee023bSkettenis 	if ((fp = fd_getfile(fdp, fd)) == NULL)
2591a9ee023bSkettenis 		return ERR_PTR(-EBADF);
2592a9ee023bSkettenis 
2593a9ee023bSkettenis 	if (fp->f_type != DTYPE_DMABUF) {
2594a9ee023bSkettenis 		FRELE(fp, p);
2595a9ee023bSkettenis 		return ERR_PTR(-EINVAL);
2596a9ee023bSkettenis 	}
2597a9ee023bSkettenis 
2598a9ee023bSkettenis 	return fp->f_data;
2599a9ee023bSkettenis }
2600a9ee023bSkettenis 
2601a9ee023bSkettenis void
2602a9ee023bSkettenis dma_buf_put(struct dma_buf *dmabuf)
2603a9ee023bSkettenis {
2604a9ee023bSkettenis 	KASSERT(dmabuf);
2605a9ee023bSkettenis 	KASSERT(dmabuf->file);
2606a9ee023bSkettenis 
2607a9ee023bSkettenis 	FRELE(dmabuf->file, curproc);
2608a9ee023bSkettenis }
2609a9ee023bSkettenis 
2610a9ee023bSkettenis int
2611a9ee023bSkettenis dma_buf_fd(struct dma_buf *dmabuf, int flags)
2612a9ee023bSkettenis {
2613a9ee023bSkettenis 	struct proc *p = curproc;
2614a9ee023bSkettenis 	struct filedesc *fdp = p->p_fd;
2615a9ee023bSkettenis 	struct file *fp = dmabuf->file;
2616a9ee023bSkettenis 	int fd, cloexec, error;
2617a9ee023bSkettenis 
2618a9ee023bSkettenis 	cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0;
2619a9ee023bSkettenis 
2620a9ee023bSkettenis 	fdplock(fdp);
2621a9ee023bSkettenis restart:
2622a9ee023bSkettenis 	if ((error = fdalloc(p, 0, &fd)) != 0) {
2623a9ee023bSkettenis 		if (error == ENOSPC) {
2624a9ee023bSkettenis 			fdexpand(p);
2625a9ee023bSkettenis 			goto restart;
2626a9ee023bSkettenis 		}
2627a9ee023bSkettenis 		fdpunlock(fdp);
2628a9ee023bSkettenis 		return -error;
2629a9ee023bSkettenis 	}
2630a9ee023bSkettenis 
2631a9ee023bSkettenis 	fdinsert(fdp, fd, cloexec, fp);
2632a9ee023bSkettenis 	fdpunlock(fdp);
2633a9ee023bSkettenis 
2634a9ee023bSkettenis 	return fd;
2635a9ee023bSkettenis }
2636a9ee023bSkettenis 
2637a9ee023bSkettenis void
2638a9ee023bSkettenis get_dma_buf(struct dma_buf *dmabuf)
2639a9ee023bSkettenis {
2640a9ee023bSkettenis 	FREF(dmabuf->file);
2641a9ee023bSkettenis }
26427f4dd379Sjsg 
26437f4dd379Sjsg enum pci_bus_speed
26447f4dd379Sjsg pcie_get_speed_cap(struct pci_dev *pdev)
26457f4dd379Sjsg {
2646b699e857Skettenis 	pci_chipset_tag_t	pc;
2647b699e857Skettenis 	pcitag_t		tag;
26487f4dd379Sjsg 	int			pos ;
26497f4dd379Sjsg 	pcireg_t		xcap, lnkcap = 0, lnkcap2 = 0;
26507f4dd379Sjsg 	pcireg_t		id;
26517f4dd379Sjsg 	enum pci_bus_speed	cap = PCI_SPEED_UNKNOWN;
26527f4dd379Sjsg 	int			bus, device, function;
26537f4dd379Sjsg 
2654b699e857Skettenis 	if (pdev == NULL)
2655b699e857Skettenis 		return PCI_SPEED_UNKNOWN;
2656b699e857Skettenis 
2657b699e857Skettenis 	pc = pdev->pc;
2658b699e857Skettenis 	tag = pdev->tag;
2659b699e857Skettenis 
26607f4dd379Sjsg 	if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS,
26617f4dd379Sjsg 	    &pos, NULL))
26627f4dd379Sjsg 		return PCI_SPEED_UNKNOWN;
26637f4dd379Sjsg 
26647f4dd379Sjsg 	id = pci_conf_read(pc, tag, PCI_ID_REG);
26657f4dd379Sjsg 	pci_decompose_tag(pc, tag, &bus, &device, &function);
26667f4dd379Sjsg 
26677f4dd379Sjsg 	/* we've been informed via and serverworks don't make the cut */
26687f4dd379Sjsg 	if (PCI_VENDOR(id) == PCI_VENDOR_VIATECH ||
26697f4dd379Sjsg 	    PCI_VENDOR(id) == PCI_VENDOR_RCC)
26707f4dd379Sjsg 		return PCI_SPEED_UNKNOWN;
26717f4dd379Sjsg 
26727f4dd379Sjsg 	lnkcap = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP);
26737f4dd379Sjsg 	xcap = pci_conf_read(pc, tag, pos + PCI_PCIE_XCAP);
26747f4dd379Sjsg 	if (PCI_PCIE_XCAP_VER(xcap) >= 2)
26757f4dd379Sjsg 		lnkcap2 = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP2);
26767f4dd379Sjsg 
26777f4dd379Sjsg 	lnkcap &= 0x0f;
26787f4dd379Sjsg 	lnkcap2 &= 0xfe;
26797f4dd379Sjsg 
26807f4dd379Sjsg 	if (lnkcap2) { /* PCIE GEN 3.0 */
26817f4dd379Sjsg 		if (lnkcap2 & 0x02)
26827f4dd379Sjsg 			cap = PCIE_SPEED_2_5GT;
26837f4dd379Sjsg 		if (lnkcap2 & 0x04)
26847f4dd379Sjsg 			cap = PCIE_SPEED_5_0GT;
26857f4dd379Sjsg 		if (lnkcap2 & 0x08)
26867f4dd379Sjsg 			cap = PCIE_SPEED_8_0GT;
26877f4dd379Sjsg 		if (lnkcap2 & 0x10)
26887f4dd379Sjsg 			cap = PCIE_SPEED_16_0GT;
26895ca02815Sjsg 		if (lnkcap2 & 0x20)
26905ca02815Sjsg 			cap = PCIE_SPEED_32_0GT;
26915ca02815Sjsg 		if (lnkcap2 & 0x40)
26925ca02815Sjsg 			cap = PCIE_SPEED_64_0GT;
26937f4dd379Sjsg 	} else {
26947f4dd379Sjsg 		if (lnkcap & 0x01)
26957f4dd379Sjsg 			cap = PCIE_SPEED_2_5GT;
26967f4dd379Sjsg 		if (lnkcap & 0x02)
26977f4dd379Sjsg 			cap = PCIE_SPEED_5_0GT;
26987f4dd379Sjsg 	}
26997f4dd379Sjsg 
27007f4dd379Sjsg 	DRM_INFO("probing pcie caps for device %d:%d:%d 0x%04x:0x%04x = %x/%x\n",
27017f4dd379Sjsg 	    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), lnkcap,
27027f4dd379Sjsg 	    lnkcap2);
27037f4dd379Sjsg 	return cap;
27047f4dd379Sjsg }
27057f4dd379Sjsg 
27067f4dd379Sjsg enum pcie_link_width
27077f4dd379Sjsg pcie_get_width_cap(struct pci_dev *pdev)
27087f4dd379Sjsg {
27097f4dd379Sjsg 	pci_chipset_tag_t	pc = pdev->pc;
27107f4dd379Sjsg 	pcitag_t		tag = pdev->tag;
27117f4dd379Sjsg 	int			pos ;
27127f4dd379Sjsg 	pcireg_t		lnkcap = 0;
27137f4dd379Sjsg 	pcireg_t		id;
27147f4dd379Sjsg 	int			bus, device, function;
27157f4dd379Sjsg 
27167f4dd379Sjsg 	if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS,
27177f4dd379Sjsg 	    &pos, NULL))
27187f4dd379Sjsg 		return PCIE_LNK_WIDTH_UNKNOWN;
27197f4dd379Sjsg 
27207f4dd379Sjsg 	id = pci_conf_read(pc, tag, PCI_ID_REG);
27217f4dd379Sjsg 	pci_decompose_tag(pc, tag, &bus, &device, &function);
27227f4dd379Sjsg 
27237f4dd379Sjsg 	lnkcap = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP);
27247f4dd379Sjsg 
27257f4dd379Sjsg 	DRM_INFO("probing pcie width for device %d:%d:%d 0x%04x:0x%04x = %x\n",
27267f4dd379Sjsg 	    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), lnkcap);
27277f4dd379Sjsg 
27287f4dd379Sjsg 	if (lnkcap)
27297f4dd379Sjsg 		return (lnkcap & 0x3f0) >> 4;
27307f4dd379Sjsg 	return PCIE_LNK_WIDTH_UNKNOWN;
27317f4dd379Sjsg }
27327f4dd379Sjsg 
27335276e8c8Sjsg bool
27345276e8c8Sjsg pcie_aspm_enabled(struct pci_dev *pdev)
27355276e8c8Sjsg {
27365276e8c8Sjsg 	pci_chipset_tag_t	pc = pdev->pc;
27375276e8c8Sjsg 	pcitag_t		tag = pdev->tag;
27385276e8c8Sjsg 	int			pos ;
27395276e8c8Sjsg 	pcireg_t		lcsr;
27405276e8c8Sjsg 
27415276e8c8Sjsg 	if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS,
27425276e8c8Sjsg 	    &pos, NULL))
27435276e8c8Sjsg 		return false;
27445276e8c8Sjsg 
27455276e8c8Sjsg 	lcsr = pci_conf_read(pc, tag, pos + PCI_PCIE_LCSR);
27465276e8c8Sjsg 	if ((lcsr & (PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1)) != 0)
27475276e8c8Sjsg 		return true;
27485276e8c8Sjsg 
27495276e8c8Sjsg 	return false;
27505276e8c8Sjsg }
27515276e8c8Sjsg 
2752c349dbc7Sjsg static wait_queue_head_t bit_waitq;
2753c349dbc7Sjsg wait_queue_head_t var_waitq;
27547f4dd379Sjsg struct mutex wait_bit_mtx = MUTEX_INITIALIZER(IPL_TTY);
27557f4dd379Sjsg 
27567f4dd379Sjsg int
27577f4dd379Sjsg wait_on_bit(unsigned long *word, int bit, unsigned mode)
27587f4dd379Sjsg {
27597f4dd379Sjsg 	int err;
27607f4dd379Sjsg 
27617f4dd379Sjsg 	if (!test_bit(bit, word))
27627f4dd379Sjsg 		return 0;
27637f4dd379Sjsg 
27647f4dd379Sjsg 	mtx_enter(&wait_bit_mtx);
27657f4dd379Sjsg 	while (test_bit(bit, word)) {
2766d18c2ae1Smpi 		err = msleep_nsec(word, &wait_bit_mtx, PWAIT | mode, "wtb",
2767d18c2ae1Smpi 		    INFSLP);
27687f4dd379Sjsg 		if (err) {
27697f4dd379Sjsg 			mtx_leave(&wait_bit_mtx);
27707f4dd379Sjsg 			return 1;
27717f4dd379Sjsg 		}
27727f4dd379Sjsg 	}
27737f4dd379Sjsg 	mtx_leave(&wait_bit_mtx);
27747f4dd379Sjsg 	return 0;
27757f4dd379Sjsg }
27767f4dd379Sjsg 
27777f4dd379Sjsg int
27787f4dd379Sjsg wait_on_bit_timeout(unsigned long *word, int bit, unsigned mode, int timo)
27797f4dd379Sjsg {
27807f4dd379Sjsg 	int err;
27817f4dd379Sjsg 
27827f4dd379Sjsg 	if (!test_bit(bit, word))
27837f4dd379Sjsg 		return 0;
27847f4dd379Sjsg 
27857f4dd379Sjsg 	mtx_enter(&wait_bit_mtx);
27867f4dd379Sjsg 	while (test_bit(bit, word)) {
27877f4dd379Sjsg 		err = msleep(word, &wait_bit_mtx, PWAIT | mode, "wtb", timo);
27887f4dd379Sjsg 		if (err) {
27897f4dd379Sjsg 			mtx_leave(&wait_bit_mtx);
27907f4dd379Sjsg 			return 1;
27917f4dd379Sjsg 		}
27927f4dd379Sjsg 	}
27937f4dd379Sjsg 	mtx_leave(&wait_bit_mtx);
27947f4dd379Sjsg 	return 0;
27957f4dd379Sjsg }
27967f4dd379Sjsg 
27977f4dd379Sjsg void
27987f4dd379Sjsg wake_up_bit(void *word, int bit)
27997f4dd379Sjsg {
28007f4dd379Sjsg 	mtx_enter(&wait_bit_mtx);
28017f4dd379Sjsg 	wakeup(word);
28027f4dd379Sjsg 	mtx_leave(&wait_bit_mtx);
28037f4dd379Sjsg }
28047f4dd379Sjsg 
2805c349dbc7Sjsg void
2806c349dbc7Sjsg clear_and_wake_up_bit(int bit, void *word)
2807c349dbc7Sjsg {
2808c349dbc7Sjsg 	clear_bit(bit, word);
2809c349dbc7Sjsg 	wake_up_bit(word, bit);
2810c349dbc7Sjsg }
2811c349dbc7Sjsg 
2812c349dbc7Sjsg wait_queue_head_t *
2813c349dbc7Sjsg bit_waitqueue(void *word, int bit)
2814c349dbc7Sjsg {
2815c349dbc7Sjsg 	/* XXX hash table of wait queues? */
2816c349dbc7Sjsg 	return &bit_waitq;
2817c349dbc7Sjsg }
2818c349dbc7Sjsg 
2819ad8b1aafSjsg wait_queue_head_t *
2820ad8b1aafSjsg __var_waitqueue(void *p)
2821ad8b1aafSjsg {
2822ad8b1aafSjsg 	/* XXX hash table of wait queues? */
2823ad8b1aafSjsg 	return &bit_waitq;
2824ad8b1aafSjsg }
2825ad8b1aafSjsg 
28267f4dd379Sjsg struct workqueue_struct *system_wq;
2827c349dbc7Sjsg struct workqueue_struct *system_highpri_wq;
28287f4dd379Sjsg struct workqueue_struct *system_unbound_wq;
28297f4dd379Sjsg struct workqueue_struct *system_long_wq;
28307f4dd379Sjsg struct taskq *taskletq;
28317f4dd379Sjsg 
28327f4dd379Sjsg void
28337f4dd379Sjsg drm_linux_init(void)
28347f4dd379Sjsg {
28357f4dd379Sjsg 	system_wq = (struct workqueue_struct *)
2836ae8374b9Skettenis 	    taskq_create("drmwq", 4, IPL_HIGH, 0);
2837c349dbc7Sjsg 	system_highpri_wq = (struct workqueue_struct *)
2838c349dbc7Sjsg 	    taskq_create("drmhpwq", 4, IPL_HIGH, 0);
28397f4dd379Sjsg 	system_unbound_wq = (struct workqueue_struct *)
2840ae8374b9Skettenis 	    taskq_create("drmubwq", 4, IPL_HIGH, 0);
28417f4dd379Sjsg 	system_long_wq = (struct workqueue_struct *)
2842ae8374b9Skettenis 	    taskq_create("drmlwq", 4, IPL_HIGH, 0);
28437f4dd379Sjsg 
28447f4dd379Sjsg 	taskletq = taskq_create("drmtskl", 1, IPL_HIGH, 0);
2845c349dbc7Sjsg 
2846c349dbc7Sjsg 	init_waitqueue_head(&bit_waitq);
2847c349dbc7Sjsg 	init_waitqueue_head(&var_waitq);
2848601770a2Skettenis 
2849601770a2Skettenis 	pool_init(&idr_pool, sizeof(struct idr_entry), 0, IPL_TTY, 0,
2850601770a2Skettenis 	    "idrpl", NULL);
285171c1aa0fSjsg 	pool_init(&xa_pool, sizeof(struct xarray_entry), 0, IPL_NONE, 0,
285271c1aa0fSjsg 	    "xapl", NULL);
285349a189d2Skettenis 
285449a189d2Skettenis 	kmap_atomic_va =
285549a189d2Skettenis 	    (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_waitok);
2856a903e442Skettenis 
2857a903e442Skettenis #if NACPI > 0
2858a903e442Skettenis 	if (acpi_softc) {
2859a903e442Skettenis 		memcpy(&acpi_gbl_FADT, acpi_softc->sc_fadt,
2860a903e442Skettenis 		    sizeof(acpi_gbl_FADT));
2861a903e442Skettenis 	}
2862a903e442Skettenis #endif
2863601770a2Skettenis }
2864601770a2Skettenis 
2865601770a2Skettenis void
2866601770a2Skettenis drm_linux_exit(void)
2867601770a2Skettenis {
286871c1aa0fSjsg 	pool_destroy(&xa_pool);
2869601770a2Skettenis 	pool_destroy(&idr_pool);
2870601770a2Skettenis 
2871601770a2Skettenis 	taskq_destroy(taskletq);
2872601770a2Skettenis 
2873601770a2Skettenis 	taskq_destroy((struct taskq *)system_long_wq);
2874601770a2Skettenis 	taskq_destroy((struct taskq *)system_unbound_wq);
2875601770a2Skettenis 	taskq_destroy((struct taskq *)system_highpri_wq);
2876601770a2Skettenis 	taskq_destroy((struct taskq *)system_wq);
28777f4dd379Sjsg }
28787f4dd379Sjsg 
28797f4dd379Sjsg #define PCIE_ECAP_RESIZE_BAR	0x15
28807f4dd379Sjsg #define RBCAP0			0x04
28817f4dd379Sjsg #define RBCTRL0			0x08
28827f4dd379Sjsg #define RBCTRL_BARINDEX_MASK	0x07
28837f4dd379Sjsg #define RBCTRL_BARSIZE_MASK	0x1f00
28847f4dd379Sjsg #define RBCTRL_BARSIZE_SHIFT	8
28857f4dd379Sjsg 
28867f4dd379Sjsg /* size in MB is 1 << nsize */
28877f4dd379Sjsg int
28887f4dd379Sjsg pci_resize_resource(struct pci_dev *pdev, int bar, int nsize)
28897f4dd379Sjsg {
28907f4dd379Sjsg 	pcireg_t	reg;
28917f4dd379Sjsg 	uint32_t	offset, capid;
28927f4dd379Sjsg 
28937f4dd379Sjsg 	KASSERT(bar == 0);
28947f4dd379Sjsg 
28957f4dd379Sjsg 	offset = PCI_PCIE_ECAP;
28967f4dd379Sjsg 
28977f4dd379Sjsg 	/* search PCI Express Extended Capabilities */
28987f4dd379Sjsg 	do {
28997f4dd379Sjsg 		reg = pci_conf_read(pdev->pc, pdev->tag, offset);
29007f4dd379Sjsg 		capid = PCI_PCIE_ECAP_ID(reg);
29017f4dd379Sjsg 		if (capid == PCIE_ECAP_RESIZE_BAR)
29027f4dd379Sjsg 			break;
29037f4dd379Sjsg 		offset = PCI_PCIE_ECAP_NEXT(reg);
29047f4dd379Sjsg 	} while (capid != 0);
29057f4dd379Sjsg 
29067f4dd379Sjsg 	if (capid == 0) {
29077f4dd379Sjsg 		printf("%s: could not find resize bar cap!\n", __func__);
29087f4dd379Sjsg 		return -ENOTSUP;
29097f4dd379Sjsg 	}
29107f4dd379Sjsg 
29117f4dd379Sjsg 	reg = pci_conf_read(pdev->pc, pdev->tag, offset + RBCAP0);
29127f4dd379Sjsg 
29137f4dd379Sjsg 	if ((reg & (1 << (nsize + 4))) == 0) {
29147f4dd379Sjsg 		printf("%s size not supported\n", __func__);
29157f4dd379Sjsg 		return -ENOTSUP;
29167f4dd379Sjsg 	}
29177f4dd379Sjsg 
29187f4dd379Sjsg 	reg = pci_conf_read(pdev->pc, pdev->tag, offset + RBCTRL0);
29197f4dd379Sjsg 	if ((reg & RBCTRL_BARINDEX_MASK) != 0) {
29207f4dd379Sjsg 		printf("%s BAR index not 0\n", __func__);
29217f4dd379Sjsg 		return -EINVAL;
29227f4dd379Sjsg 	}
29237f4dd379Sjsg 
29247f4dd379Sjsg 	reg &= ~RBCTRL_BARSIZE_MASK;
29257f4dd379Sjsg 	reg |= (nsize << RBCTRL_BARSIZE_SHIFT) & RBCTRL_BARSIZE_MASK;
29267f4dd379Sjsg 
29277f4dd379Sjsg 	pci_conf_write(pdev->pc, pdev->tag, offset + RBCTRL0, reg);
29287f4dd379Sjsg 
29297f4dd379Sjsg 	return 0;
29307f4dd379Sjsg }
2931a4e118acSkettenis 
2932a4e118acSkettenis TAILQ_HEAD(, shrinker) shrinkers = TAILQ_HEAD_INITIALIZER(shrinkers);
2933a4e118acSkettenis 
2934a4e118acSkettenis int
29351bb76ff1Sjsg register_shrinker(struct shrinker *shrinker, const char *format, ...)
2936a4e118acSkettenis {
2937a4e118acSkettenis 	TAILQ_INSERT_TAIL(&shrinkers, shrinker, next);
2938a4e118acSkettenis 	return 0;
2939a4e118acSkettenis }
2940a4e118acSkettenis 
2941a4e118acSkettenis void
29423990936dSjsg unregister_shrinker(struct shrinker *shrinker)
29433990936dSjsg {
29443990936dSjsg 	TAILQ_REMOVE(&shrinkers, shrinker, next);
29453990936dSjsg }
29463990936dSjsg 
2947789ce988Smpi unsigned long
2948a4e118acSkettenis drmbackoff(long npages)
2949a4e118acSkettenis {
2950a4e118acSkettenis 	struct shrink_control sc;
2951a4e118acSkettenis 	struct shrinker *shrinker;
2952789ce988Smpi 	u_long ret, freed = 0;
2953a4e118acSkettenis 
2954a4e118acSkettenis 	shrinker = TAILQ_FIRST(&shrinkers);
2955a4e118acSkettenis 	while (shrinker && npages > 0) {
2956a4e118acSkettenis 		sc.nr_to_scan = npages;
2957a4e118acSkettenis 		ret = shrinker->scan_objects(shrinker, &sc);
2958789ce988Smpi 		if (ret == SHRINK_STOP)
2959789ce988Smpi 			break;
2960a4e118acSkettenis 		npages -= ret;
2961789ce988Smpi 		freed += ret;
2962a4e118acSkettenis 		shrinker = TAILQ_NEXT(shrinker, next);
2963a4e118acSkettenis 	}
2964789ce988Smpi 
2965789ce988Smpi 	return freed;
2966a4e118acSkettenis }
2967c349dbc7Sjsg 
2968c349dbc7Sjsg void *
2969c349dbc7Sjsg bitmap_zalloc(u_int n, gfp_t flags)
2970c349dbc7Sjsg {
2971c349dbc7Sjsg 	return kcalloc(BITS_TO_LONGS(n), sizeof(long), flags);
2972c349dbc7Sjsg }
2973c349dbc7Sjsg 
2974c349dbc7Sjsg void
2975c349dbc7Sjsg bitmap_free(void *p)
2976c349dbc7Sjsg {
2977c349dbc7Sjsg 	kfree(p);
2978c349dbc7Sjsg }
2979c349dbc7Sjsg 
2980c349dbc7Sjsg int
2981c349dbc7Sjsg atomic_dec_and_mutex_lock(volatile int *v, struct rwlock *lock)
2982c349dbc7Sjsg {
2983c349dbc7Sjsg 	if (atomic_add_unless(v, -1, 1))
2984c349dbc7Sjsg 		return 0;
2985c349dbc7Sjsg 
2986c349dbc7Sjsg 	rw_enter_write(lock);
2987c349dbc7Sjsg 	if (atomic_dec_return(v) == 0)
2988c349dbc7Sjsg 		return 1;
2989c349dbc7Sjsg 	rw_exit_write(lock);
2990c349dbc7Sjsg 	return 0;
2991c349dbc7Sjsg }
2992c349dbc7Sjsg 
2993c349dbc7Sjsg int
2994c349dbc7Sjsg printk(const char *fmt, ...)
2995c349dbc7Sjsg {
2996c349dbc7Sjsg 	int ret, level;
2997c349dbc7Sjsg 	va_list ap;
2998c349dbc7Sjsg 
2999c349dbc7Sjsg 	if (fmt != NULL && *fmt == '\001') {
3000c349dbc7Sjsg 		level = fmt[1];
3001c349dbc7Sjsg #ifndef DRMDEBUG
3002c349dbc7Sjsg 		if (level >= KERN_INFO[1] && level <= '9')
3003c349dbc7Sjsg 			return 0;
3004c349dbc7Sjsg #endif
3005c349dbc7Sjsg 		fmt += 2;
3006c349dbc7Sjsg 	}
3007c349dbc7Sjsg 
3008c349dbc7Sjsg 	va_start(ap, fmt);
3009c349dbc7Sjsg 	ret = vprintf(fmt, ap);
3010c349dbc7Sjsg 	va_end(ap);
3011c349dbc7Sjsg 
3012c349dbc7Sjsg 	return ret;
3013c349dbc7Sjsg }
3014cfaa6efeSjsg 
3015cfaa6efeSjsg #define START(node) ((node)->start)
3016cfaa6efeSjsg #define LAST(node) ((node)->last)
3017cfaa6efeSjsg 
3018cfaa6efeSjsg struct interval_tree_node *
3019cfaa6efeSjsg interval_tree_iter_first(struct rb_root_cached *root, unsigned long start,
3020cfaa6efeSjsg     unsigned long last)
3021cfaa6efeSjsg {
3022cfaa6efeSjsg 	struct interval_tree_node *node;
3023cfaa6efeSjsg 	struct rb_node *rb;
3024cfaa6efeSjsg 
3025cfaa6efeSjsg 	for (rb = rb_first_cached(root); rb; rb = rb_next(rb)) {
3026cfaa6efeSjsg 		node = rb_entry(rb, typeof(*node), rb);
3027cfaa6efeSjsg 		if (LAST(node) >= start && START(node) <= last)
3028cfaa6efeSjsg 			return node;
3029cfaa6efeSjsg 	}
3030cfaa6efeSjsg 	return NULL;
3031cfaa6efeSjsg }
3032cfaa6efeSjsg 
3033cfaa6efeSjsg void
3034cfaa6efeSjsg interval_tree_remove(struct interval_tree_node *node,
3035cfaa6efeSjsg     struct rb_root_cached *root)
3036cfaa6efeSjsg {
3037cfaa6efeSjsg 	rb_erase_cached(&node->rb, root);
3038cfaa6efeSjsg }
3039cfaa6efeSjsg 
3040cfaa6efeSjsg void
3041cfaa6efeSjsg interval_tree_insert(struct interval_tree_node *node,
3042cfaa6efeSjsg     struct rb_root_cached *root)
3043cfaa6efeSjsg {
3044cfaa6efeSjsg 	struct rb_node **iter = &root->rb_root.rb_node;
3045cfaa6efeSjsg 	struct rb_node *parent = NULL;
3046cfaa6efeSjsg 	struct interval_tree_node *iter_node;
3047cfaa6efeSjsg 
3048cfaa6efeSjsg 	while (*iter) {
3049cfaa6efeSjsg 		parent = *iter;
3050cfaa6efeSjsg 		iter_node = rb_entry(*iter, struct interval_tree_node, rb);
3051cfaa6efeSjsg 
3052cfaa6efeSjsg 		if (node->start < iter_node->start)
3053cfaa6efeSjsg 			iter = &(*iter)->rb_left;
3054cfaa6efeSjsg 		else
3055cfaa6efeSjsg 			iter = &(*iter)->rb_right;
3056cfaa6efeSjsg 	}
3057cfaa6efeSjsg 
3058cfaa6efeSjsg 	rb_link_node(&node->rb, parent, iter);
3059cfaa6efeSjsg 	rb_insert_color_cached(&node->rb, root, false);
3060cfaa6efeSjsg }
306161c1bba6Sjsg 
306261c1bba6Sjsg int
306361c1bba6Sjsg syncfile_read(struct file *fp, struct uio *uio, int fflags)
306461c1bba6Sjsg {
306561c1bba6Sjsg 	return ENXIO;
306661c1bba6Sjsg }
306761c1bba6Sjsg 
306861c1bba6Sjsg int
306961c1bba6Sjsg syncfile_write(struct file *fp, struct uio *uio, int fflags)
307061c1bba6Sjsg {
307161c1bba6Sjsg 	return ENXIO;
307261c1bba6Sjsg }
307361c1bba6Sjsg 
307461c1bba6Sjsg int
307561c1bba6Sjsg syncfile_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
307661c1bba6Sjsg {
307761c1bba6Sjsg 	return ENOTTY;
307861c1bba6Sjsg }
307961c1bba6Sjsg 
308061c1bba6Sjsg int
308161c1bba6Sjsg syncfile_kqfilter(struct file *fp, struct knote *kn)
308261c1bba6Sjsg {
308361c1bba6Sjsg 	return EINVAL;
308461c1bba6Sjsg }
308561c1bba6Sjsg 
308661c1bba6Sjsg int
308761c1bba6Sjsg syncfile_stat(struct file *fp, struct stat *st, struct proc *p)
308861c1bba6Sjsg {
308961c1bba6Sjsg 	memset(st, 0, sizeof(*st));
309061c1bba6Sjsg 	st->st_mode = S_IFIFO;	/* XXX */
309161c1bba6Sjsg 	return 0;
309261c1bba6Sjsg }
309361c1bba6Sjsg 
309461c1bba6Sjsg int
309561c1bba6Sjsg syncfile_close(struct file *fp, struct proc *p)
309661c1bba6Sjsg {
309761c1bba6Sjsg 	struct sync_file *sf = fp->f_data;
309861c1bba6Sjsg 
309961c1bba6Sjsg 	dma_fence_put(sf->fence);
310061c1bba6Sjsg 	fp->f_data = NULL;
310161c1bba6Sjsg 	free(sf, M_DRM, sizeof(struct sync_file));
310261c1bba6Sjsg 	return 0;
310361c1bba6Sjsg }
310461c1bba6Sjsg 
310561c1bba6Sjsg int
310661c1bba6Sjsg syncfile_seek(struct file *fp, off_t *offset, int whence, struct proc *p)
310761c1bba6Sjsg {
310861c1bba6Sjsg 	off_t newoff;
310961c1bba6Sjsg 
311061c1bba6Sjsg 	if (*offset != 0)
311161c1bba6Sjsg 		return EINVAL;
311261c1bba6Sjsg 
311361c1bba6Sjsg 	switch (whence) {
311461c1bba6Sjsg 	case SEEK_SET:
311561c1bba6Sjsg 		newoff = 0;
311661c1bba6Sjsg 		break;
311761c1bba6Sjsg 	case SEEK_END:
311861c1bba6Sjsg 		newoff = 0;
311961c1bba6Sjsg 		break;
312061c1bba6Sjsg 	default:
312161c1bba6Sjsg 		return EINVAL;
312261c1bba6Sjsg 	}
312361c1bba6Sjsg 	mtx_enter(&fp->f_mtx);
312461c1bba6Sjsg 	fp->f_offset = newoff;
312561c1bba6Sjsg 	mtx_leave(&fp->f_mtx);
312661c1bba6Sjsg 	*offset = newoff;
312761c1bba6Sjsg 	return 0;
312861c1bba6Sjsg }
312961c1bba6Sjsg 
313061c1bba6Sjsg const struct fileops syncfileops = {
313161c1bba6Sjsg 	.fo_read	= syncfile_read,
313261c1bba6Sjsg 	.fo_write	= syncfile_write,
313361c1bba6Sjsg 	.fo_ioctl	= syncfile_ioctl,
313461c1bba6Sjsg 	.fo_kqfilter	= syncfile_kqfilter,
313561c1bba6Sjsg 	.fo_stat	= syncfile_stat,
313661c1bba6Sjsg 	.fo_close	= syncfile_close,
313761c1bba6Sjsg 	.fo_seek	= syncfile_seek,
313861c1bba6Sjsg };
313961c1bba6Sjsg 
314061c1bba6Sjsg void
314161c1bba6Sjsg fd_install(int fd, struct file *fp)
314261c1bba6Sjsg {
314361c1bba6Sjsg 	struct proc *p = curproc;
314461c1bba6Sjsg 	struct filedesc *fdp = p->p_fd;
314561c1bba6Sjsg 
314661c1bba6Sjsg 	if (fp->f_type != DTYPE_SYNC)
314761c1bba6Sjsg 		return;
314861c1bba6Sjsg 
314961c1bba6Sjsg 	fdplock(fdp);
315061c1bba6Sjsg 	/* all callers use get_unused_fd_flags(O_CLOEXEC) */
315161c1bba6Sjsg 	fdinsert(fdp, fd, UF_EXCLOSE, fp);
315261c1bba6Sjsg 	fdpunlock(fdp);
315361c1bba6Sjsg }
315461c1bba6Sjsg 
315561c1bba6Sjsg void
315661c1bba6Sjsg fput(struct file *fp)
315761c1bba6Sjsg {
315861c1bba6Sjsg 	if (fp->f_type != DTYPE_SYNC)
315961c1bba6Sjsg 		return;
316061c1bba6Sjsg 
316161c1bba6Sjsg 	FRELE(fp, curproc);
316261c1bba6Sjsg }
316361c1bba6Sjsg 
316461c1bba6Sjsg int
316561c1bba6Sjsg get_unused_fd_flags(unsigned int flags)
316661c1bba6Sjsg {
316761c1bba6Sjsg 	struct proc *p = curproc;
316861c1bba6Sjsg 	struct filedesc *fdp = p->p_fd;
316961c1bba6Sjsg 	int error, fd;
317061c1bba6Sjsg 
317161c1bba6Sjsg 	KASSERT((flags & O_CLOEXEC) != 0);
317261c1bba6Sjsg 
317361c1bba6Sjsg 	fdplock(fdp);
317461c1bba6Sjsg retryalloc:
317561c1bba6Sjsg 	if ((error = fdalloc(p, 0, &fd)) != 0) {
317661c1bba6Sjsg 		if (error == ENOSPC) {
317761c1bba6Sjsg 			fdexpand(p);
317861c1bba6Sjsg 			goto retryalloc;
317961c1bba6Sjsg 		}
318061c1bba6Sjsg 		fdpunlock(fdp);
318161c1bba6Sjsg 		return -1;
318261c1bba6Sjsg 	}
318361c1bba6Sjsg 	fdpunlock(fdp);
318461c1bba6Sjsg 
318561c1bba6Sjsg 	return fd;
318661c1bba6Sjsg }
318761c1bba6Sjsg 
318861c1bba6Sjsg void
318961c1bba6Sjsg put_unused_fd(int fd)
319061c1bba6Sjsg {
319161c1bba6Sjsg 	struct filedesc *fdp = curproc->p_fd;
319261c1bba6Sjsg 
319361c1bba6Sjsg 	fdplock(fdp);
319461c1bba6Sjsg 	fdremove(fdp, fd);
319561c1bba6Sjsg 	fdpunlock(fdp);
319661c1bba6Sjsg }
319761c1bba6Sjsg 
319861c1bba6Sjsg struct dma_fence *
319961c1bba6Sjsg sync_file_get_fence(int fd)
320061c1bba6Sjsg {
320161c1bba6Sjsg 	struct proc *p = curproc;
320261c1bba6Sjsg 	struct filedesc *fdp = p->p_fd;
320361c1bba6Sjsg 	struct file *fp;
320461c1bba6Sjsg 	struct sync_file *sf;
320561c1bba6Sjsg 	struct dma_fence *f;
320661c1bba6Sjsg 
320761c1bba6Sjsg 	if ((fp = fd_getfile(fdp, fd)) == NULL)
320861c1bba6Sjsg 		return NULL;
320961c1bba6Sjsg 
321061c1bba6Sjsg 	if (fp->f_type != DTYPE_SYNC) {
321161c1bba6Sjsg 		FRELE(fp, p);
321261c1bba6Sjsg 		return NULL;
321361c1bba6Sjsg 	}
321461c1bba6Sjsg 	sf = fp->f_data;
321561c1bba6Sjsg 	f = dma_fence_get(sf->fence);
321661c1bba6Sjsg 	FRELE(sf->file, p);
321761c1bba6Sjsg 	return f;
321861c1bba6Sjsg }
321961c1bba6Sjsg 
322061c1bba6Sjsg struct sync_file *
322161c1bba6Sjsg sync_file_create(struct dma_fence *fence)
322261c1bba6Sjsg {
322361c1bba6Sjsg 	struct proc *p = curproc;
322461c1bba6Sjsg 	struct sync_file *sf;
322561c1bba6Sjsg 	struct file *fp;
322661c1bba6Sjsg 
322761c1bba6Sjsg 	fp = fnew(p);
322861c1bba6Sjsg 	if (fp == NULL)
322961c1bba6Sjsg 		return NULL;
323061c1bba6Sjsg 	fp->f_type = DTYPE_SYNC;
323161c1bba6Sjsg 	fp->f_ops = &syncfileops;
323261c1bba6Sjsg 	sf = malloc(sizeof(struct sync_file), M_DRM, M_WAITOK | M_ZERO);
323361c1bba6Sjsg 	sf->file = fp;
323461c1bba6Sjsg 	sf->fence = dma_fence_get(fence);
323561c1bba6Sjsg 	fp->f_data = sf;
323661c1bba6Sjsg 	return sf;
323761c1bba6Sjsg }
32381bb76ff1Sjsg 
32391bb76ff1Sjsg bool
32401bb76ff1Sjsg drm_firmware_drivers_only(void)
32411bb76ff1Sjsg {
32421bb76ff1Sjsg 	return false;
32431bb76ff1Sjsg }
3244667382c7Skettenis 
3245667382c7Skettenis 
3246667382c7Skettenis void *
3247667382c7Skettenis memremap(phys_addr_t phys_addr, size_t size, int flags)
3248667382c7Skettenis {
3249667382c7Skettenis 	STUB();
3250667382c7Skettenis 	return NULL;
3251667382c7Skettenis }
3252667382c7Skettenis 
3253667382c7Skettenis void
3254667382c7Skettenis memunmap(void *addr)
3255667382c7Skettenis {
3256667382c7Skettenis 	STUB();
3257667382c7Skettenis }
3258667382c7Skettenis 
3259667382c7Skettenis #include <linux/platform_device.h>
3260667382c7Skettenis 
3261667382c7Skettenis bus_dma_tag_t
3262667382c7Skettenis dma_tag_lookup(struct device *dev)
3263667382c7Skettenis {
3264667382c7Skettenis 	extern struct cfdriver drm_cd;
3265667382c7Skettenis 	struct drm_device *drm;
3266667382c7Skettenis 	int i;
3267667382c7Skettenis 
3268667382c7Skettenis 	for (i = 0; i < drm_cd.cd_ndevs; i++) {
3269667382c7Skettenis 		drm = drm_cd.cd_devs[i];
3270667382c7Skettenis 		if (drm && drm->dev == dev)
3271667382c7Skettenis 			return drm->dmat;
3272667382c7Skettenis 	}
3273667382c7Skettenis 
3274667382c7Skettenis 	return ((struct platform_device *)dev)->dmat;
3275667382c7Skettenis }
3276667382c7Skettenis 
3277667382c7Skettenis LIST_HEAD(, drm_dmamem) dmamem_list = LIST_HEAD_INITIALIZER(dmamem_list);
3278667382c7Skettenis 
3279667382c7Skettenis void *
3280667382c7Skettenis dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
3281667382c7Skettenis     int gfp)
3282667382c7Skettenis {
3283667382c7Skettenis 	bus_dma_tag_t dmat = dma_tag_lookup(dev);
3284667382c7Skettenis 	struct drm_dmamem *mem;
3285667382c7Skettenis 
3286667382c7Skettenis 	mem = drm_dmamem_alloc(dmat, size, PAGE_SIZE, 1, size,
3287667382c7Skettenis 	    BUS_DMA_COHERENT, 0);
3288667382c7Skettenis 	if (mem == NULL)
3289667382c7Skettenis 		return NULL;
3290667382c7Skettenis 	*dma_handle = mem->map->dm_segs[0].ds_addr;
3291667382c7Skettenis 	LIST_INSERT_HEAD(&dmamem_list, mem, next);
3292667382c7Skettenis 	return mem->kva;
3293667382c7Skettenis }
3294667382c7Skettenis 
3295667382c7Skettenis void
3296667382c7Skettenis dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
3297667382c7Skettenis     dma_addr_t dma_handle)
3298667382c7Skettenis {
3299667382c7Skettenis 	bus_dma_tag_t dmat = dma_tag_lookup(dev);
3300667382c7Skettenis 	struct drm_dmamem *mem;
3301667382c7Skettenis 
3302667382c7Skettenis 	LIST_FOREACH(mem, &dmamem_list, next) {
3303667382c7Skettenis 		if (mem->kva == cpu_addr)
3304667382c7Skettenis 			break;
3305667382c7Skettenis 	}
3306667382c7Skettenis 	KASSERT(mem);
3307667382c7Skettenis 	KASSERT(mem->size == size);
3308667382c7Skettenis 	KASSERT(mem->map->dm_segs[0].ds_addr == dma_handle);
3309667382c7Skettenis 
3310667382c7Skettenis 	LIST_REMOVE(mem, next);
3311667382c7Skettenis 	drm_dmamem_free(dmat, mem);
3312667382c7Skettenis }
3313667382c7Skettenis 
3314667382c7Skettenis int
3315667382c7Skettenis dma_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr,
3316667382c7Skettenis     dma_addr_t dma_addr, size_t size)
3317667382c7Skettenis {
3318667382c7Skettenis 	paddr_t pa;
3319667382c7Skettenis 	int ret;
3320667382c7Skettenis 
3321667382c7Skettenis 	if (!pmap_extract(pmap_kernel(), (vaddr_t)cpu_addr, &pa))
3322667382c7Skettenis 		return -EINVAL;
3323667382c7Skettenis 
3324667382c7Skettenis 	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
3325667382c7Skettenis 	if (ret)
3326667382c7Skettenis 		return ret;
3327667382c7Skettenis 
3328667382c7Skettenis 	sg_set_page(sgt->sgl, PHYS_TO_VM_PAGE(pa), size, 0);
3329667382c7Skettenis 	return 0;
3330667382c7Skettenis }
3331667382c7Skettenis 
3332667382c7Skettenis dma_addr_t
3333667382c7Skettenis dma_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size,
3334667382c7Skettenis     enum dma_data_direction dir, u_long attr)
3335667382c7Skettenis {
3336667382c7Skettenis 	bus_dma_tag_t dmat= dma_tag_lookup(dev);
3337667382c7Skettenis 	bus_dmamap_t map;
3338667382c7Skettenis 	bus_dma_segment_t seg;
3339667382c7Skettenis 
3340667382c7Skettenis 	if (bus_dmamap_create(dmat, size, 1, size, 0,
3341667382c7Skettenis 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &map))
3342667382c7Skettenis 		return DMA_MAPPING_ERROR;
3343667382c7Skettenis 	seg.ds_addr = phys_addr;
3344667382c7Skettenis 	seg.ds_len = size;
3345667382c7Skettenis 	if (bus_dmamap_load_raw(dmat, map, &seg, 1, size, BUS_DMA_WAITOK)) {
3346667382c7Skettenis 		bus_dmamap_destroy(dmat, map);
3347667382c7Skettenis 		return DMA_MAPPING_ERROR;
3348667382c7Skettenis 	}
3349667382c7Skettenis 
3350667382c7Skettenis 	return map->dm_segs[0].ds_addr;
3351667382c7Skettenis }
3352667382c7Skettenis 
3353667382c7Skettenis #ifdef BUS_DMA_FIXED
3354667382c7Skettenis 
3355667382c7Skettenis #include <linux/iommu.h>
3356667382c7Skettenis 
3357667382c7Skettenis size_t
3358667382c7Skettenis iommu_map_sgtable(struct iommu_domain *domain, u_long iova,
3359667382c7Skettenis     struct sg_table *sgt, int prot)
3360667382c7Skettenis {
3361667382c7Skettenis 	bus_dma_segment_t seg;
3362667382c7Skettenis 	int error;
3363667382c7Skettenis 
3364667382c7Skettenis 	error = bus_dmamap_create(domain->dmat, sgt->sgl->length, 1,
3365667382c7Skettenis 	    sgt->sgl->length, 0, BUS_DMA_WAITOK, &sgt->dmamap);
3366667382c7Skettenis 	if (error)
3367667382c7Skettenis 		return -ENOMEM;
3368667382c7Skettenis 
3369667382c7Skettenis 	sgt->dmamap->dm_segs[0].ds_addr = iova;
3370667382c7Skettenis 	sgt->dmamap->dm_segs[0].ds_len = sgt->sgl->length;
3371667382c7Skettenis 	sgt->dmamap->dm_nsegs = 1;
3372667382c7Skettenis 	seg.ds_addr = VM_PAGE_TO_PHYS(sgt->sgl->__page);
3373667382c7Skettenis 	seg.ds_len = sgt->sgl->length;
3374667382c7Skettenis 	error = bus_dmamap_load_raw(domain->dmat, sgt->dmamap, &seg, 1,
3375667382c7Skettenis 	    sgt->sgl->length, BUS_DMA_WAITOK | BUS_DMA_FIXED);
3376667382c7Skettenis 	if (error)
3377667382c7Skettenis 		return -ENOMEM;
3378667382c7Skettenis 
3379667382c7Skettenis 	return sg_dma_len(sgt->sgl);
3380667382c7Skettenis }
3381667382c7Skettenis 
3382667382c7Skettenis size_t
3383667382c7Skettenis iommu_unmap(struct iommu_domain *domain, u_long iova, size_t size)
3384667382c7Skettenis {
3385667382c7Skettenis 	STUB();
3386667382c7Skettenis 	return 0;
3387667382c7Skettenis }
3388667382c7Skettenis 
3389667382c7Skettenis struct iommu_domain *
3390667382c7Skettenis iommu_get_domain_for_dev(struct device *dev)
3391667382c7Skettenis {
3392667382c7Skettenis 	STUB();
3393667382c7Skettenis 	return NULL;
3394667382c7Skettenis }
3395667382c7Skettenis 
3396667382c7Skettenis phys_addr_t
3397667382c7Skettenis iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
3398667382c7Skettenis {
3399667382c7Skettenis 	STUB();
3400667382c7Skettenis 	return 0;
3401667382c7Skettenis }
3402667382c7Skettenis 
3403667382c7Skettenis struct iommu_domain *
3404667382c7Skettenis iommu_domain_alloc(struct bus_type *type)
3405667382c7Skettenis {
3406667382c7Skettenis 	return malloc(sizeof(struct iommu_domain), M_DEVBUF, M_WAITOK | M_ZERO);
3407667382c7Skettenis }
3408667382c7Skettenis 
3409667382c7Skettenis int
3410667382c7Skettenis iommu_attach_device(struct iommu_domain *domain, struct device *dev)
3411667382c7Skettenis {
3412667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3413667382c7Skettenis 
3414667382c7Skettenis 	domain->dmat = pdev->dmat;
3415667382c7Skettenis 	return 0;
3416667382c7Skettenis }
3417667382c7Skettenis 
3418667382c7Skettenis #endif
3419667382c7Skettenis 
3420667382c7Skettenis #include <linux/component.h>
3421667382c7Skettenis 
3422cefff6e5Skettenis struct component {
3423667382c7Skettenis 	struct device *dev;
3424cefff6e5Skettenis 	struct device *adev;
3425cefff6e5Skettenis 	const struct component_ops *ops;
3426cefff6e5Skettenis 	SLIST_ENTRY(component) next;
3427667382c7Skettenis };
3428667382c7Skettenis 
3429cefff6e5Skettenis SLIST_HEAD(,component) component_list = SLIST_HEAD_INITIALIZER(component_list);
3430cefff6e5Skettenis 
3431667382c7Skettenis int
3432cefff6e5Skettenis component_add(struct device *dev, const struct component_ops *ops)
3433667382c7Skettenis {
3434cefff6e5Skettenis 	struct component *component;
3435cefff6e5Skettenis 
3436cefff6e5Skettenis 	component = malloc(sizeof(*component), M_DEVBUF, M_WAITOK | M_ZERO);
3437cefff6e5Skettenis 	component->dev = dev;
3438cefff6e5Skettenis 	component->ops = ops;
3439cefff6e5Skettenis 	SLIST_INSERT_HEAD(&component_list, component, next);
3440667382c7Skettenis 	return 0;
3441667382c7Skettenis }
3442667382c7Skettenis 
3443cefff6e5Skettenis int
3444f005ef32Sjsg component_add_typed(struct device *dev, const struct component_ops *ops,
3445f005ef32Sjsg 	int type)
3446f005ef32Sjsg {
3447f005ef32Sjsg 	return component_add(dev, ops);
3448f005ef32Sjsg }
3449f005ef32Sjsg 
3450f005ef32Sjsg int
3451cefff6e5Skettenis component_bind_all(struct device *dev, void *data)
3452667382c7Skettenis {
3453cefff6e5Skettenis 	struct component *component;
3454cefff6e5Skettenis 	int ret = 0;
3455667382c7Skettenis 
3456cefff6e5Skettenis 	SLIST_FOREACH(component, &component_list, next) {
3457cefff6e5Skettenis 		if (component->adev == dev) {
3458cefff6e5Skettenis 			ret = component->ops->bind(component->dev, NULL, data);
3459cefff6e5Skettenis 			if (ret)
3460cefff6e5Skettenis 				break;
3461667382c7Skettenis 		}
3462667382c7Skettenis 	}
3463667382c7Skettenis 
3464cefff6e5Skettenis 	return ret;
3465cefff6e5Skettenis }
3466cefff6e5Skettenis 
34675fde6622Skettenis struct component_match_entry {
3468cefff6e5Skettenis 	int (*compare)(struct device *, void *);
3469cefff6e5Skettenis 	void *data;
3470cefff6e5Skettenis };
3471cefff6e5Skettenis 
34725fde6622Skettenis struct component_match {
34735fde6622Skettenis 	struct component_match_entry match[4];
34745fde6622Skettenis 	int nmatches;
34755fde6622Skettenis };
34765fde6622Skettenis 
3477667382c7Skettenis int
3478667382c7Skettenis component_master_add_with_match(struct device *dev,
3479667382c7Skettenis     const struct component_master_ops *ops, struct component_match *match)
3480667382c7Skettenis {
3481cefff6e5Skettenis 	struct component *component;
3482cefff6e5Skettenis 	int found = 0;
34835fde6622Skettenis 	int i, ret;
3484cefff6e5Skettenis 
3485cefff6e5Skettenis 	SLIST_FOREACH(component, &component_list, next) {
34865fde6622Skettenis 		for (i = 0; i < match->nmatches; i++) {
34875fde6622Skettenis 			struct component_match_entry *m = &match->match[i];
34885fde6622Skettenis 			if (m->compare(component->dev, m->data)) {
3489cefff6e5Skettenis 				component->adev = dev;
3490cefff6e5Skettenis 				found = 1;
34915fde6622Skettenis 				break;
34925fde6622Skettenis 			}
3493cefff6e5Skettenis 		}
3494cefff6e5Skettenis 	}
3495cefff6e5Skettenis 
3496cefff6e5Skettenis 	if (found) {
3497cefff6e5Skettenis 		ret = ops->bind(dev);
3498cefff6e5Skettenis 		if (ret)
3499cefff6e5Skettenis 			return ret;
3500cefff6e5Skettenis 	}
3501cefff6e5Skettenis 
3502667382c7Skettenis 	return 0;
3503667382c7Skettenis }
3504667382c7Skettenis 
3505667382c7Skettenis #ifdef __HAVE_FDT
3506667382c7Skettenis 
3507667382c7Skettenis #include <linux/platform_device.h>
3508667382c7Skettenis #include <dev/ofw/openfirm.h>
3509667382c7Skettenis #include <dev/ofw/fdt.h>
3510667382c7Skettenis #include <machine/fdt.h>
3511667382c7Skettenis 
3512667382c7Skettenis LIST_HEAD(, platform_device) pdev_list = LIST_HEAD_INITIALIZER(pdev_list);
3513667382c7Skettenis 
3514667382c7Skettenis void
3515667382c7Skettenis platform_device_register(struct platform_device *pdev)
3516667382c7Skettenis {
3517cefff6e5Skettenis 	int i;
3518cefff6e5Skettenis 
3519667382c7Skettenis 	pdev->num_resources = pdev->faa->fa_nreg;
3520cefff6e5Skettenis 	if (pdev->faa->fa_nreg > 0) {
3521cefff6e5Skettenis 		pdev->resource = mallocarray(pdev->faa->fa_nreg,
3522cefff6e5Skettenis 		    sizeof(*pdev->resource), M_DEVBUF, M_WAITOK | M_ZERO);
3523cefff6e5Skettenis 		for (i = 0; i < pdev->faa->fa_nreg; i++) {
3524cefff6e5Skettenis 			pdev->resource[i].start = pdev->faa->fa_reg[i].addr;
3525cefff6e5Skettenis 			pdev->resource[i].end = pdev->faa->fa_reg[i].addr +
3526cefff6e5Skettenis 			    pdev->faa->fa_reg[i].size - 1;
3527cefff6e5Skettenis 		}
3528cefff6e5Skettenis 	}
3529667382c7Skettenis 
3530667382c7Skettenis 	pdev->parent = pdev->dev.dv_parent;
3531667382c7Skettenis 	pdev->node = pdev->faa->fa_node;
3532cefff6e5Skettenis 	pdev->iot = pdev->faa->fa_iot;
3533667382c7Skettenis 	pdev->dmat = pdev->faa->fa_dmat;
3534667382c7Skettenis 	LIST_INSERT_HEAD(&pdev_list, pdev, next);
3535667382c7Skettenis }
3536667382c7Skettenis 
3537667382c7Skettenis 
3538667382c7Skettenis struct resource *
3539667382c7Skettenis platform_get_resource(struct platform_device *pdev, u_int type, u_int num)
3540667382c7Skettenis {
3541cefff6e5Skettenis 	KASSERT(num < pdev->num_resources);
3542667382c7Skettenis 	return &pdev->resource[num];
3543667382c7Skettenis }
3544667382c7Skettenis 
3545667382c7Skettenis void __iomem *
3546667382c7Skettenis devm_platform_ioremap_resource_byname(struct platform_device *pdev,
3547667382c7Skettenis 				      const char *name)
3548667382c7Skettenis {
3549667382c7Skettenis 	bus_space_handle_t ioh;
3550667382c7Skettenis 	int err, idx;
3551667382c7Skettenis 
3552cefff6e5Skettenis 	idx = OF_getindex(pdev->node, name, "reg-names");
3553cefff6e5Skettenis 	if (idx == -1 || idx >= pdev->num_resources)
3554667382c7Skettenis 		return ERR_PTR(-EINVAL);
3555667382c7Skettenis 
3556cefff6e5Skettenis 	err = bus_space_map(pdev->iot, pdev->resource[idx].start,
3557cefff6e5Skettenis 	    pdev->resource[idx].end - pdev->resource[idx].start + 1,
3558cefff6e5Skettenis 	    BUS_SPACE_MAP_LINEAR, &ioh);
3559667382c7Skettenis 	if (err)
3560667382c7Skettenis 		return ERR_PTR(-err);
3561667382c7Skettenis 
3562cefff6e5Skettenis 	return bus_space_vaddr(pdev->iot, ioh);
3563667382c7Skettenis }
3564667382c7Skettenis 
3565667382c7Skettenis #include <dev/ofw/ofw_clock.h>
3566667382c7Skettenis #include <linux/clk.h>
3567667382c7Skettenis 
3568667382c7Skettenis struct clk *
3569667382c7Skettenis devm_clk_get(struct device *dev, const char *name)
3570667382c7Skettenis {
3571667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3572667382c7Skettenis 	struct clk *clk;
3573667382c7Skettenis 
3574667382c7Skettenis 	clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK);
3575667382c7Skettenis 	clk->freq = clock_get_frequency(pdev->node, name);
3576667382c7Skettenis 	return clk;
3577667382c7Skettenis }
3578667382c7Skettenis 
3579667382c7Skettenis u_long
3580667382c7Skettenis clk_get_rate(struct clk *clk)
3581667382c7Skettenis {
3582667382c7Skettenis 	return clk->freq;
3583667382c7Skettenis }
3584667382c7Skettenis 
3585667382c7Skettenis #include <linux/gpio/consumer.h>
3586667382c7Skettenis #include <dev/ofw/ofw_gpio.h>
3587667382c7Skettenis 
3588667382c7Skettenis struct gpio_desc {
3589667382c7Skettenis 	uint32_t gpios[4];
3590667382c7Skettenis };
3591667382c7Skettenis 
3592667382c7Skettenis struct gpio_desc *
3593667382c7Skettenis devm_gpiod_get_optional(struct device *dev, const char *name, int flags)
3594667382c7Skettenis {
3595667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3596667382c7Skettenis 	struct gpio_desc *desc;
3597667382c7Skettenis 	char fullname[128];
3598667382c7Skettenis 	int len;
3599667382c7Skettenis 
3600667382c7Skettenis 	snprintf(fullname, sizeof(fullname), "%s-gpios", name);
3601667382c7Skettenis 
3602667382c7Skettenis 	desc = malloc(sizeof(*desc), M_DEVBUF, M_WAITOK | M_ZERO);
3603667382c7Skettenis 	len = OF_getpropintarray(pdev->node, fullname, desc->gpios,
3604667382c7Skettenis 	     sizeof(desc->gpios));
3605667382c7Skettenis 	KASSERT(len <= sizeof(desc->gpios));
3606667382c7Skettenis 	if (len < 0) {
3607667382c7Skettenis 		free(desc, M_DEVBUF, sizeof(*desc));
3608667382c7Skettenis 		return NULL;
3609667382c7Skettenis 	}
3610667382c7Skettenis 
3611667382c7Skettenis 	switch (flags) {
3612667382c7Skettenis 	case GPIOD_IN:
3613667382c7Skettenis 		gpio_controller_config_pin(desc->gpios, GPIO_CONFIG_INPUT);
3614667382c7Skettenis 		break;
3615667382c7Skettenis 	case GPIOD_OUT_HIGH:
3616667382c7Skettenis 		gpio_controller_config_pin(desc->gpios, GPIO_CONFIG_OUTPUT);
3617667382c7Skettenis 		gpio_controller_set_pin(desc->gpios, 1);
3618667382c7Skettenis 		break;
3619667382c7Skettenis 	default:
3620667382c7Skettenis 		panic("%s: unimplemented flags 0x%x", __func__, flags);
3621667382c7Skettenis 	}
3622667382c7Skettenis 
3623667382c7Skettenis 	return desc;
3624667382c7Skettenis }
3625667382c7Skettenis 
3626667382c7Skettenis int
3627667382c7Skettenis gpiod_get_value_cansleep(const struct gpio_desc *desc)
3628667382c7Skettenis {
3629667382c7Skettenis 	return gpio_controller_get_pin(((struct gpio_desc *)desc)->gpios);
3630667382c7Skettenis }
3631667382c7Skettenis 
3632667382c7Skettenis struct phy {
3633667382c7Skettenis 	int node;
3634667382c7Skettenis 	const char *name;
3635667382c7Skettenis };
3636667382c7Skettenis 
3637667382c7Skettenis struct phy *
3638667382c7Skettenis devm_phy_optional_get(struct device *dev, const char *name)
3639667382c7Skettenis {
3640667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3641667382c7Skettenis 	struct phy *phy;
3642667382c7Skettenis 	int idx;
3643667382c7Skettenis 
3644667382c7Skettenis 	idx = OF_getindex(pdev->node, name, "phy-names");
3645667382c7Skettenis 	if (idx == -1)
3646667382c7Skettenis 		return NULL;
3647667382c7Skettenis 
3648667382c7Skettenis 	phy = malloc(sizeof(*phy), M_DEVBUF, M_WAITOK);
3649667382c7Skettenis 	phy->node = pdev->node;
3650667382c7Skettenis 	phy->name = name;
3651667382c7Skettenis 
3652667382c7Skettenis 	return phy;
3653667382c7Skettenis }
3654667382c7Skettenis 
3655667382c7Skettenis struct bus_type platform_bus_type;
3656667382c7Skettenis 
3657667382c7Skettenis #include <dev/ofw/ofw_misc.h>
3658667382c7Skettenis 
3659667382c7Skettenis #include <linux/of.h>
3660667382c7Skettenis #include <linux/platform_device.h>
3661667382c7Skettenis 
3662667382c7Skettenis struct device_node *
3663667382c7Skettenis __of_devnode(void *arg)
3664667382c7Skettenis {
3665667382c7Skettenis 	struct device *dev = container_of(arg, struct device, of_node);
3666667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3667667382c7Skettenis 
3668667382c7Skettenis 	return (struct device_node *)(uintptr_t)pdev->node;
3669667382c7Skettenis }
3670667382c7Skettenis 
3671667382c7Skettenis int
3672667382c7Skettenis __of_device_is_compatible(struct device_node *np, const char *compatible)
3673667382c7Skettenis {
3674667382c7Skettenis 	return OF_is_compatible((uintptr_t)np, compatible);
3675667382c7Skettenis }
3676667382c7Skettenis 
3677667382c7Skettenis int
3678667382c7Skettenis __of_property_present(struct device_node *np, const char *propname)
3679667382c7Skettenis {
3680667382c7Skettenis 	return OF_getpropbool((uintptr_t)np, (char *)propname);
3681667382c7Skettenis }
3682667382c7Skettenis 
3683667382c7Skettenis int
3684667382c7Skettenis __of_property_read_variable_u32_array(struct device_node *np,
3685667382c7Skettenis     const char *propname, uint32_t *out_values, size_t sz_min, size_t sz_max)
3686667382c7Skettenis {
3687667382c7Skettenis 	int len;
3688667382c7Skettenis 
3689667382c7Skettenis 	len = OF_getpropintarray((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
3704667382c7Skettenis __of_property_read_variable_u64_array(struct device_node *np,
3705667382c7Skettenis     const char *propname, uint64_t *out_values, size_t sz_min, size_t sz_max)
3706667382c7Skettenis {
3707667382c7Skettenis 	int len;
3708667382c7Skettenis 
3709667382c7Skettenis 	len = OF_getpropint64array((uintptr_t)np, (char *)propname, out_values,
3710667382c7Skettenis 	    sz_max * sizeof(*out_values));
3711667382c7Skettenis 	if (len < 0)
3712667382c7Skettenis 		return -EINVAL;
3713667382c7Skettenis 	if (len == 0)
3714667382c7Skettenis 		return -ENODATA;
3715667382c7Skettenis 	if (len < sz_min * sizeof(*out_values) ||
3716667382c7Skettenis 	    len > sz_max * sizeof(*out_values))
3717667382c7Skettenis 		return -EOVERFLOW;
3718667382c7Skettenis 	if (sz_min == 1 && sz_max == 1)
3719667382c7Skettenis 		return 0;
3720667382c7Skettenis 	return len / sizeof(*out_values);
3721667382c7Skettenis }
3722667382c7Skettenis 
3723667382c7Skettenis int
3724667382c7Skettenis __of_property_match_string(struct device_node *np,
3725667382c7Skettenis     const char *propname, const char *str)
3726667382c7Skettenis {
3727667382c7Skettenis 	int idx;
3728667382c7Skettenis 
3729667382c7Skettenis 	idx = OF_getindex((uintptr_t)np, str, propname);
3730667382c7Skettenis 	if (idx == -1)
3731667382c7Skettenis 		return -ENODATA;
3732667382c7Skettenis 	return idx;
3733667382c7Skettenis }
3734667382c7Skettenis 
3735667382c7Skettenis struct device_node *
3736667382c7Skettenis __of_parse_phandle(struct device_node *np, const char *propname, int idx)
3737667382c7Skettenis {
3738667382c7Skettenis 	uint32_t phandles[16] = {};
3739667382c7Skettenis 	int len, node;
3740667382c7Skettenis 
3741667382c7Skettenis 	len = OF_getpropintarray((uintptr_t)np, (char *)propname, phandles,
3742667382c7Skettenis 	    sizeof(phandles));
3743667382c7Skettenis 	if (len < (idx + 1) * sizeof(uint32_t))
3744667382c7Skettenis 		return NULL;
3745667382c7Skettenis 
3746667382c7Skettenis 	node = OF_getnodebyphandle(phandles[idx]);
3747667382c7Skettenis 	if (node == 0)
3748667382c7Skettenis 		return NULL;
3749667382c7Skettenis 
3750667382c7Skettenis 	return (struct device_node *)(uintptr_t)node;
3751667382c7Skettenis }
3752667382c7Skettenis 
3753667382c7Skettenis int
3754667382c7Skettenis __of_parse_phandle_with_args(struct device_node *np, const char *propname,
3755667382c7Skettenis     const char *cellsname, int idx, struct of_phandle_args *args)
3756667382c7Skettenis {
3757667382c7Skettenis 	uint32_t phandles[16] = {};
3758667382c7Skettenis 	int i, len, node;
3759667382c7Skettenis 
3760667382c7Skettenis 	len = OF_getpropintarray((uintptr_t)np, (char *)propname, phandles,
3761667382c7Skettenis 	    sizeof(phandles));
3762667382c7Skettenis 	if (len < (idx + 1) * sizeof(uint32_t))
3763667382c7Skettenis 		return -ENOENT;
3764667382c7Skettenis 
3765667382c7Skettenis 	node = OF_getnodebyphandle(phandles[idx]);
3766667382c7Skettenis 	if (node == 0)
3767667382c7Skettenis 		return -ENOENT;
3768667382c7Skettenis 
3769667382c7Skettenis 	args->np = (struct device_node *)(uintptr_t)node;
3770667382c7Skettenis 	args->args_count = OF_getpropint(node, (char *)cellsname, 0);
3771667382c7Skettenis 	for (i = 0; i < args->args_count; i++)
3772667382c7Skettenis 		args->args[i] = phandles[i + 1];
3773667382c7Skettenis 
3774667382c7Skettenis 	return 0;
3775667382c7Skettenis }
3776667382c7Skettenis 
3777667382c7Skettenis int
3778667382c7Skettenis of_address_to_resource(struct device_node *np, int idx, struct resource *res)
3779667382c7Skettenis {
3780667382c7Skettenis 	uint64_t reg[16] = {};
3781667382c7Skettenis 	int len;
3782667382c7Skettenis 
3783667382c7Skettenis 	KASSERT(idx < 8);
3784667382c7Skettenis 
3785667382c7Skettenis 	len = OF_getpropint64array((uintptr_t)np, "reg", reg, sizeof(reg));
3786667382c7Skettenis 	if (len < 0 || idx >= (len / (2 * sizeof(uint64_t))))
3787667382c7Skettenis 		return -EINVAL;
3788667382c7Skettenis 
3789667382c7Skettenis 	res->start = reg[2 * idx];
3790667382c7Skettenis 	res->end = reg[2 * idx] + reg[2 * idx + 1] - 1;
3791667382c7Skettenis 
3792667382c7Skettenis 	return 0;
3793667382c7Skettenis }
3794667382c7Skettenis 
3795667382c7Skettenis static int
3796667382c7Skettenis next_node(int node)
3797667382c7Skettenis {
3798667382c7Skettenis 	int peer = OF_peer(node);
3799667382c7Skettenis 
3800667382c7Skettenis 	while (node && !peer) {
3801667382c7Skettenis 		node = OF_parent(node);
3802667382c7Skettenis 		if (node)
3803667382c7Skettenis 			peer = OF_peer(node);
3804667382c7Skettenis 	}
3805667382c7Skettenis 
3806667382c7Skettenis 	return peer;
3807667382c7Skettenis }
3808667382c7Skettenis 
3809667382c7Skettenis static int
3810667382c7Skettenis find_matching_node(int node, const struct of_device_id *id)
3811667382c7Skettenis {
3812667382c7Skettenis 	int child, match;
3813667382c7Skettenis 	int i;
3814667382c7Skettenis 
3815667382c7Skettenis 	for (child = OF_child(node); child; child = OF_peer(child)) {
3816667382c7Skettenis 		match = find_matching_node(child, id);
3817667382c7Skettenis 		if (match)
3818667382c7Skettenis 			return match;
3819667382c7Skettenis 	}
3820667382c7Skettenis 
3821667382c7Skettenis 	for (i = 0; id[i].compatible; i++) {
3822667382c7Skettenis 		if (OF_is_compatible(node, id[i].compatible))
3823667382c7Skettenis 			return node;
3824667382c7Skettenis 	}
3825667382c7Skettenis 
3826667382c7Skettenis 	return 0;
3827667382c7Skettenis }
3828667382c7Skettenis 
3829667382c7Skettenis struct device_node *
3830667382c7Skettenis __matching_node(struct device_node *np, const struct of_device_id *id)
3831667382c7Skettenis {
3832667382c7Skettenis 	int node = OF_peer(0);
3833667382c7Skettenis 	int match;
3834667382c7Skettenis 
3835667382c7Skettenis 	if (np)
3836667382c7Skettenis 		node = next_node((uintptr_t)np);
3837667382c7Skettenis 	while (node) {
3838667382c7Skettenis 		match = find_matching_node(node, id);
3839667382c7Skettenis 		if (match)
3840667382c7Skettenis 			return (struct device_node *)(uintptr_t)match;
3841667382c7Skettenis 		node = next_node(node);
3842667382c7Skettenis 	}
3843667382c7Skettenis 
3844667382c7Skettenis 	return NULL;
3845667382c7Skettenis }
3846667382c7Skettenis 
3847667382c7Skettenis struct platform_device *
3848667382c7Skettenis of_platform_device_create(struct device_node *np, const char *bus_id,
3849667382c7Skettenis     struct device *parent)
3850667382c7Skettenis {
3851667382c7Skettenis 	struct platform_device *pdev;
3852667382c7Skettenis 
3853667382c7Skettenis 	pdev = malloc(sizeof(*pdev), M_DEVBUF, M_WAITOK | M_ZERO);
3854667382c7Skettenis 	pdev->node = (intptr_t)np;
3855667382c7Skettenis 	pdev->parent = parent;
3856667382c7Skettenis 
3857667382c7Skettenis 	LIST_INSERT_HEAD(&pdev_list, pdev, next);
3858667382c7Skettenis 
3859667382c7Skettenis 	return pdev;
3860667382c7Skettenis }
3861667382c7Skettenis 
3862667382c7Skettenis struct platform_device *
3863667382c7Skettenis of_find_device_by_node(struct device_node *np)
3864667382c7Skettenis {
3865667382c7Skettenis 	struct platform_device *pdev;
3866667382c7Skettenis 
3867667382c7Skettenis 	LIST_FOREACH(pdev, &pdev_list, next) {
3868667382c7Skettenis 		if (pdev->node == (intptr_t)np)
3869667382c7Skettenis 			return pdev;
3870667382c7Skettenis 	}
3871667382c7Skettenis 
3872667382c7Skettenis 	return NULL;
3873667382c7Skettenis }
3874667382c7Skettenis 
3875667382c7Skettenis int
3876667382c7Skettenis of_device_is_available(struct device_node *np)
3877667382c7Skettenis {
3878667382c7Skettenis 	char status[32];
3879667382c7Skettenis 
3880667382c7Skettenis 	if (OF_getprop((uintptr_t)np, "status", status, sizeof(status)) > 0 &&
3881667382c7Skettenis 	    strcmp(status, "disabled") == 0)
3882667382c7Skettenis 		return 0;
3883667382c7Skettenis 
3884667382c7Skettenis 	return 1;
3885667382c7Skettenis }
3886667382c7Skettenis 
3887667382c7Skettenis int
3888667382c7Skettenis of_dma_configure(struct device *dev, struct device_node *np, int force_dma)
3889667382c7Skettenis {
3890667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3891667382c7Skettenis 	bus_dma_tag_t dmat = dma_tag_lookup(pdev->parent);
3892667382c7Skettenis 
3893667382c7Skettenis 	pdev->dmat = iommu_device_map(pdev->node, dmat);
3894667382c7Skettenis 	return 0;
3895667382c7Skettenis }
3896667382c7Skettenis 
3897667382c7Skettenis struct device_node *
3898667382c7Skettenis __of_get_compatible_child(void *p, const char *compat)
3899667382c7Skettenis {
3900667382c7Skettenis 	struct device *dev = container_of(p, struct device, of_node);
3901667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3902667382c7Skettenis 	int child;
3903667382c7Skettenis 
3904667382c7Skettenis 	for (child = OF_child(pdev->node); child; child = OF_peer(child)) {
3905667382c7Skettenis 		if (OF_is_compatible(child, compat))
3906667382c7Skettenis 			return (struct device_node *)(uintptr_t)child;
3907667382c7Skettenis 	}
3908667382c7Skettenis 	return NULL;
3909667382c7Skettenis }
3910667382c7Skettenis 
3911667382c7Skettenis struct device_node *
3912667382c7Skettenis __of_get_child_by_name(void *p, const char *name)
3913667382c7Skettenis {
3914667382c7Skettenis 	struct device *dev = container_of(p, struct device, of_node);
3915667382c7Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3916667382c7Skettenis 	int child;
3917667382c7Skettenis 
3918667382c7Skettenis 	child = OF_getnodebyname(pdev->node, name);
3919667382c7Skettenis 	if (child == 0)
3920667382c7Skettenis 		return NULL;
3921667382c7Skettenis 	return (struct device_node *)(uintptr_t)child;
3922667382c7Skettenis }
3923667382c7Skettenis 
3924cefff6e5Skettenis int
3925cefff6e5Skettenis component_compare_of(struct device *dev, void *data)
3926cefff6e5Skettenis {
3927cefff6e5Skettenis 	struct platform_device *pdev = (struct platform_device *)dev;
3928cefff6e5Skettenis 
3929cefff6e5Skettenis 	return (pdev->node == (intptr_t)data);
3930cefff6e5Skettenis }
3931cefff6e5Skettenis 
3932cefff6e5Skettenis void
3933cefff6e5Skettenis drm_of_component_match_add(struct device *master,
3934cefff6e5Skettenis 			   struct component_match **matchptr,
3935cefff6e5Skettenis 			   int (*compare)(struct device *, void *),
3936cefff6e5Skettenis 			   struct device_node *np)
3937cefff6e5Skettenis {
39385fde6622Skettenis 	struct component_match *match = *matchptr;
3939cefff6e5Skettenis 
39405fde6622Skettenis 	if (match == NULL) {
3941cefff6e5Skettenis 		match = malloc(sizeof(struct component_match),
3942cefff6e5Skettenis 		    M_DEVBUF, M_WAITOK | M_ZERO);
3943cefff6e5Skettenis 		*matchptr = match;
3944cefff6e5Skettenis 	}
39455fde6622Skettenis 
39465fde6622Skettenis 	KASSERT(match->nmatches < nitems(match->match));
39475fde6622Skettenis 	match->match[match->nmatches].compare = compare;
39485fde6622Skettenis 	match->match[match->nmatches].data = np;
39495fde6622Skettenis 	match->nmatches++;
3950cefff6e5Skettenis }
3951cefff6e5Skettenis 
3952667382c7Skettenis #endif
3953