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