1*22008fe3Sjsg /* $OpenBSD: drm_linux.c,v 1.119 2024/09/30 12:21:17 jsg Exp $ */ 2652bbc39Skettenis /* 3652bbc39Skettenis * Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org> 4d71700c3Skettenis * Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org> 5652bbc39Skettenis * 6652bbc39Skettenis * Permission to use, copy, modify, and distribute this software for any 7652bbc39Skettenis * purpose with or without fee is hereby granted, provided that the above 8652bbc39Skettenis * copyright notice and this permission notice appear in all copies. 9652bbc39Skettenis * 10652bbc39Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11652bbc39Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12652bbc39Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13652bbc39Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14652bbc39Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15652bbc39Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16652bbc39Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17652bbc39Skettenis */ 18652bbc39Skettenis 19c349dbc7Sjsg #include <sys/types.h> 2085fcfc35Svisa #include <sys/systm.h> 21c349dbc7Sjsg #include <sys/param.h> 22b8584f42Srobert #include <sys/event.h> 23a9ee023bSkettenis #include <sys/filedesc.h> 2463b8f014Skettenis #include <sys/kthread.h> 25a9ee023bSkettenis #include <sys/stat.h> 26f3455eb0Skettenis #include <sys/unistd.h> 27c349dbc7Sjsg #include <sys/proc.h> 28c349dbc7Sjsg #include <sys/pool.h> 29c349dbc7Sjsg #include <sys/fcntl.h> 30c349dbc7Sjsg 31c349dbc7Sjsg #include <dev/pci/ppbreg.h> 32c349dbc7Sjsg 337f4dd379Sjsg #include <linux/dma-buf.h> 347f4dd379Sjsg #include <linux/mod_devicetable.h> 357f4dd379Sjsg #include <linux/acpi.h> 367f4dd379Sjsg #include <linux/pagevec.h> 3795f00a37Sjsg #include <linux/dma-fence-array.h> 38ad8b1aafSjsg #include <linux/dma-fence-chain.h> 39c349dbc7Sjsg #include <linux/interrupt.h> 40c349dbc7Sjsg #include <linux/err.h> 41c349dbc7Sjsg #include <linux/idr.h> 42c349dbc7Sjsg #include <linux/scatterlist.h> 43c349dbc7Sjsg #include <linux/i2c.h> 44c349dbc7Sjsg #include <linux/pci.h> 45c349dbc7Sjsg #include <linux/notifier.h> 46c349dbc7Sjsg #include <linux/backlight.h> 47c349dbc7Sjsg #include <linux/shrinker.h> 48c349dbc7Sjsg #include <linux/fb.h> 49c349dbc7Sjsg #include <linux/xarray.h> 50cfaa6efeSjsg #include <linux/interval_tree.h> 51ad8b1aafSjsg #include <linux/kthread.h> 525ca02815Sjsg #include <linux/processor.h> 5361c1bba6Sjsg #include <linux/sync_file.h> 54a903e442Skettenis #include <linux/suspend.h> 55c349dbc7Sjsg 56c349dbc7Sjsg #include <drm/drm_device.h> 571bb76ff1Sjsg #include <drm/drm_connector.h> 58c349dbc7Sjsg #include <drm/drm_print.h> 597f4dd379Sjsg 607ef4208bSjsg #if defined(__amd64__) || defined(__i386__) 617ef4208bSjsg #include "bios.h" 627ef4208bSjsg #endif 637ef4208bSjsg 645ca02815Sjsg /* allowed to sleep */ 655ca02815Sjsg void 665ca02815Sjsg tasklet_unlock_wait(struct tasklet_struct *ts) 675ca02815Sjsg { 685ca02815Sjsg while (test_bit(TASKLET_STATE_RUN, &ts->state)) 695ca02815Sjsg cpu_relax(); 705ca02815Sjsg } 715ca02815Sjsg 725ca02815Sjsg /* must not sleep */ 735ca02815Sjsg void 745ca02815Sjsg tasklet_unlock_spin_wait(struct tasklet_struct *ts) 755ca02815Sjsg { 765ca02815Sjsg while (test_bit(TASKLET_STATE_RUN, &ts->state)) 775ca02815Sjsg cpu_relax(); 785ca02815Sjsg } 795ca02815Sjsg 807f4dd379Sjsg void 817f4dd379Sjsg tasklet_run(void *arg) 827f4dd379Sjsg { 837f4dd379Sjsg struct tasklet_struct *ts = arg; 847f4dd379Sjsg 857f4dd379Sjsg clear_bit(TASKLET_STATE_SCHED, &ts->state); 867f4dd379Sjsg if (tasklet_trylock(ts)) { 875ca02815Sjsg if (!atomic_read(&ts->count)) { 885ca02815Sjsg if (ts->use_callback) 895ca02815Sjsg ts->callback(ts); 905ca02815Sjsg else 917f4dd379Sjsg ts->func(ts->data); 925ca02815Sjsg } 937f4dd379Sjsg tasklet_unlock(ts); 947f4dd379Sjsg } 957f4dd379Sjsg } 96652bbc39Skettenis 97ec70c0c7Sjsg /* 32 bit powerpc lacks 64 bit atomics */ 98ec70c0c7Sjsg #if defined(__powerpc__) && !defined(__powerpc64__) 99ec70c0c7Sjsg struct mutex atomic64_mtx = MUTEX_INITIALIZER(IPL_HIGH); 100ec70c0c7Sjsg #endif 101ec70c0c7Sjsg 1023253c27bSkettenis void 1037f4dd379Sjsg set_current_state(int state) 1043253c27bSkettenis { 105c0be31d8Sclaudio int prio = state; 106c0be31d8Sclaudio 107c0be31d8Sclaudio KASSERT(state != TASK_RUNNING); 108c0be31d8Sclaudio /* check if already on the sleep list */ 109c0be31d8Sclaudio if (curproc->p_wchan != NULL) 110c0be31d8Sclaudio return; 111c0be31d8Sclaudio sleep_setup(curproc, prio, "schto"); 1127f4dd379Sjsg } 1133253c27bSkettenis 1147f4dd379Sjsg void 1157f4dd379Sjsg __set_current_state(int state) 1167f4dd379Sjsg { 117c0be31d8Sclaudio struct proc *p = curproc; 118c0be31d8Sclaudio 1197f4dd379Sjsg KASSERT(state == TASK_RUNNING); 120a09e9584Sclaudio SCHED_LOCK(); 121c0be31d8Sclaudio unsleep(p); 122c0be31d8Sclaudio p->p_stat = SONPROC; 123c0be31d8Sclaudio atomic_clearbits_int(&p->p_flag, P_WSLEEP); 124a09e9584Sclaudio SCHED_UNLOCK(); 1257f4dd379Sjsg } 1267f4dd379Sjsg 1277f4dd379Sjsg void 1287f4dd379Sjsg schedule(void) 1297f4dd379Sjsg { 1307f4dd379Sjsg schedule_timeout(MAX_SCHEDULE_TIMEOUT); 1317f4dd379Sjsg } 1327f4dd379Sjsg 1337f4dd379Sjsg long 1347f4dd379Sjsg schedule_timeout(long timeout) 1357f4dd379Sjsg { 136c2a61337Sjsg unsigned long deadline; 137c0be31d8Sclaudio int timo = 0; 1387f4dd379Sjsg 1397f4dd379Sjsg KASSERT(!cold); 1407f4dd379Sjsg 1417f4dd379Sjsg if (timeout != MAX_SCHEDULE_TIMEOUT) 142436960cfSmpi timo = timeout; 1437f4dd379Sjsg if (timeout != MAX_SCHEDULE_TIMEOUT) 144c2a61337Sjsg deadline = jiffies + timeout; 145c0be31d8Sclaudio sleep_finish(timo, timeout > 0); 1467f4dd379Sjsg if (timeout != MAX_SCHEDULE_TIMEOUT) 147c2a61337Sjsg timeout = deadline - jiffies; 1487f4dd379Sjsg 1497f4dd379Sjsg return timeout > 0 ? timeout : 0; 1507f4dd379Sjsg } 1517f4dd379Sjsg 152c349dbc7Sjsg long 153c349dbc7Sjsg schedule_timeout_uninterruptible(long timeout) 154c349dbc7Sjsg { 155c349dbc7Sjsg tsleep(curproc, PWAIT, "schtou", timeout); 156c349dbc7Sjsg return 0; 157c349dbc7Sjsg } 158c349dbc7Sjsg 1597f4dd379Sjsg int 1607f4dd379Sjsg wake_up_process(struct proc *p) 1617f4dd379Sjsg { 162a09e9584Sclaudio int rv; 163e1b95daaSclaudio 164a09e9584Sclaudio SCHED_LOCK(); 165e1edc428Smpi rv = wakeup_proc(p, 0); 166a09e9584Sclaudio SCHED_UNLOCK(); 167e1b95daaSclaudio return rv; 1683253c27bSkettenis } 1693253c27bSkettenis 170c0be31d8Sclaudio int 171c0be31d8Sclaudio autoremove_wake_function(struct wait_queue_entry *wqe, unsigned int mode, 172c0be31d8Sclaudio int sync, void *key) 173c0be31d8Sclaudio { 174c0be31d8Sclaudio if (wqe->private) 175c0be31d8Sclaudio wake_up_process(wqe->private); 176c0be31d8Sclaudio list_del_init(&wqe->entry); 177c0be31d8Sclaudio return 0; 178c0be31d8Sclaudio } 179c0be31d8Sclaudio 180c0be31d8Sclaudio void 181c0be31d8Sclaudio prepare_to_wait(wait_queue_head_t *wqh, wait_queue_entry_t *wqe, int state) 182c0be31d8Sclaudio { 183c0be31d8Sclaudio mtx_enter(&wqh->lock); 184c0be31d8Sclaudio if (list_empty(&wqe->entry)) 185c0be31d8Sclaudio __add_wait_queue(wqh, wqe); 186c0be31d8Sclaudio mtx_leave(&wqh->lock); 187c0be31d8Sclaudio 188c0be31d8Sclaudio set_current_state(state); 189c0be31d8Sclaudio } 190c0be31d8Sclaudio 191c0be31d8Sclaudio void 192c0be31d8Sclaudio finish_wait(wait_queue_head_t *wqh, wait_queue_entry_t *wqe) 193c0be31d8Sclaudio { 194c0be31d8Sclaudio __set_current_state(TASK_RUNNING); 195c0be31d8Sclaudio 196c0be31d8Sclaudio mtx_enter(&wqh->lock); 197c0be31d8Sclaudio if (!list_empty(&wqe->entry)) 198c0be31d8Sclaudio list_del_init(&wqe->entry); 199c0be31d8Sclaudio mtx_leave(&wqh->lock); 200c0be31d8Sclaudio } 201c0be31d8Sclaudio 2023253c27bSkettenis void 2033253c27bSkettenis flush_workqueue(struct workqueue_struct *wq) 2043253c27bSkettenis { 2053253c27bSkettenis if (cold) 2063253c27bSkettenis return; 2073253c27bSkettenis 20815e28df9Sjsg if (wq) 2097f4dd379Sjsg taskq_barrier((struct taskq *)wq); 2103253c27bSkettenis } 2113253c27bSkettenis 2127f4dd379Sjsg bool 2133253c27bSkettenis flush_work(struct work_struct *work) 2143253c27bSkettenis { 2153253c27bSkettenis if (cold) 2167f4dd379Sjsg return false; 2173253c27bSkettenis 21815e28df9Sjsg if (work->tq) 219b11a6e7fSsthen taskq_barrier(work->tq); 2207f4dd379Sjsg return false; 2213253c27bSkettenis } 2223253c27bSkettenis 2237f4dd379Sjsg bool 2243253c27bSkettenis flush_delayed_work(struct delayed_work *dwork) 2253253c27bSkettenis { 2267f4dd379Sjsg bool ret = false; 2273253c27bSkettenis 2283253c27bSkettenis if (cold) 2297f4dd379Sjsg return false; 2303253c27bSkettenis 2317f4dd379Sjsg while (timeout_pending(&dwork->to)) { 2327f4dd379Sjsg tsleep(dwork, PWAIT, "fldwto", 1); 2337f4dd379Sjsg ret = true; 2343253c27bSkettenis } 2357f4dd379Sjsg 23615e28df9Sjsg if (dwork->tq) 237b11a6e7fSsthen taskq_barrier(dwork->tq); 2387f4dd379Sjsg return ret; 2393253c27bSkettenis } 2403253c27bSkettenis 24163b8f014Skettenis struct kthread { 24263b8f014Skettenis int (*func)(void *); 24363b8f014Skettenis void *data; 24463b8f014Skettenis struct proc *proc; 24563b8f014Skettenis volatile u_int flags; 24663b8f014Skettenis #define KTHREAD_SHOULDSTOP 0x0000001 24763b8f014Skettenis #define KTHREAD_STOPPED 0x0000002 24863b8f014Skettenis #define KTHREAD_SHOULDPARK 0x0000004 24963b8f014Skettenis #define KTHREAD_PARKED 0x0000008 25063b8f014Skettenis LIST_ENTRY(kthread) next; 25163b8f014Skettenis }; 25263b8f014Skettenis 25363b8f014Skettenis LIST_HEAD(, kthread) kthread_list = LIST_HEAD_INITIALIZER(kthread_list); 25463b8f014Skettenis 25563b8f014Skettenis void 25663b8f014Skettenis kthread_func(void *arg) 25763b8f014Skettenis { 25863b8f014Skettenis struct kthread *thread = arg; 25963b8f014Skettenis int ret; 26063b8f014Skettenis 26163b8f014Skettenis ret = thread->func(thread->data); 26263b8f014Skettenis thread->flags |= KTHREAD_STOPPED; 2638224282cSsemarie wakeup(thread); 26463b8f014Skettenis kthread_exit(ret); 26563b8f014Skettenis } 26663b8f014Skettenis 26763b8f014Skettenis struct proc * 26863b8f014Skettenis kthread_run(int (*func)(void *), void *data, const char *name) 26963b8f014Skettenis { 27063b8f014Skettenis struct kthread *thread; 27163b8f014Skettenis 27263b8f014Skettenis thread = malloc(sizeof(*thread), M_DRM, M_WAITOK); 27363b8f014Skettenis thread->func = func; 27463b8f014Skettenis thread->data = data; 27563b8f014Skettenis thread->flags = 0; 27663b8f014Skettenis 27763b8f014Skettenis if (kthread_create(kthread_func, thread, &thread->proc, name)) { 27863b8f014Skettenis free(thread, M_DRM, sizeof(*thread)); 27963b8f014Skettenis return ERR_PTR(-ENOMEM); 28063b8f014Skettenis } 28163b8f014Skettenis 28263b8f014Skettenis LIST_INSERT_HEAD(&kthread_list, thread, next); 28363b8f014Skettenis return thread->proc; 28463b8f014Skettenis } 28563b8f014Skettenis 286ad8b1aafSjsg struct kthread_worker * 287ad8b1aafSjsg kthread_create_worker(unsigned int flags, const char *fmt, ...) 288ad8b1aafSjsg { 289ad8b1aafSjsg char name[MAXCOMLEN+1]; 290ad8b1aafSjsg va_list ap; 291ad8b1aafSjsg 292ad8b1aafSjsg struct kthread_worker *w = malloc(sizeof(*w), M_DRM, M_WAITOK); 293ad8b1aafSjsg va_start(ap, fmt); 294ad8b1aafSjsg vsnprintf(name, sizeof(name), fmt, ap); 295ad8b1aafSjsg va_end(ap); 296ad8b1aafSjsg w->tq = taskq_create(name, 1, IPL_HIGH, 0); 297ad8b1aafSjsg 298ad8b1aafSjsg return w; 299ad8b1aafSjsg } 300ad8b1aafSjsg 301ad8b1aafSjsg void 302ad8b1aafSjsg kthread_destroy_worker(struct kthread_worker *worker) 303ad8b1aafSjsg { 304ad8b1aafSjsg taskq_destroy(worker->tq); 305ad8b1aafSjsg free(worker, M_DRM, sizeof(*worker)); 306ad8b1aafSjsg 307ad8b1aafSjsg } 308ad8b1aafSjsg 309ad8b1aafSjsg void 310ad8b1aafSjsg kthread_init_work(struct kthread_work *work, void (*func)(struct kthread_work *)) 311ad8b1aafSjsg { 312ad8b1aafSjsg work->tq = NULL; 313ad8b1aafSjsg task_set(&work->task, (void (*)(void *))func, work); 314ad8b1aafSjsg } 315ad8b1aafSjsg 316ad8b1aafSjsg bool 317ad8b1aafSjsg kthread_queue_work(struct kthread_worker *worker, struct kthread_work *work) 318ad8b1aafSjsg { 319ad8b1aafSjsg work->tq = worker->tq; 320ad8b1aafSjsg return task_add(work->tq, &work->task); 321ad8b1aafSjsg } 322ad8b1aafSjsg 323ad8b1aafSjsg bool 324ad8b1aafSjsg kthread_cancel_work_sync(struct kthread_work *work) 325ad8b1aafSjsg { 326ad8b1aafSjsg return task_del(work->tq, &work->task); 327ad8b1aafSjsg } 328ad8b1aafSjsg 329ad8b1aafSjsg void 330ad8b1aafSjsg kthread_flush_work(struct kthread_work *work) 331ad8b1aafSjsg { 332ad8b1aafSjsg if (cold) 333ad8b1aafSjsg return; 334ad8b1aafSjsg 335ad8b1aafSjsg if (work->tq) 336b11a6e7fSsthen taskq_barrier(work->tq); 337ad8b1aafSjsg } 338ad8b1aafSjsg 339ad8b1aafSjsg void 340ad8b1aafSjsg kthread_flush_worker(struct kthread_worker *worker) 341ad8b1aafSjsg { 342ad8b1aafSjsg if (cold) 343ad8b1aafSjsg return; 344ad8b1aafSjsg 345ad8b1aafSjsg if (worker->tq) 346ad8b1aafSjsg taskq_barrier(worker->tq); 347ad8b1aafSjsg } 348ad8b1aafSjsg 34963b8f014Skettenis struct kthread * 35063b8f014Skettenis kthread_lookup(struct proc *p) 35163b8f014Skettenis { 35263b8f014Skettenis struct kthread *thread; 35363b8f014Skettenis 35463b8f014Skettenis LIST_FOREACH(thread, &kthread_list, next) { 35563b8f014Skettenis if (thread->proc == p) 35663b8f014Skettenis break; 35763b8f014Skettenis } 35863b8f014Skettenis KASSERT(thread); 35963b8f014Skettenis 36063b8f014Skettenis return thread; 36163b8f014Skettenis } 36263b8f014Skettenis 36363b8f014Skettenis int 36463b8f014Skettenis kthread_should_park(void) 36563b8f014Skettenis { 36663b8f014Skettenis struct kthread *thread = kthread_lookup(curproc); 36763b8f014Skettenis return (thread->flags & KTHREAD_SHOULDPARK); 36863b8f014Skettenis } 36963b8f014Skettenis 37063b8f014Skettenis void 37163b8f014Skettenis kthread_parkme(void) 37263b8f014Skettenis { 37363b8f014Skettenis struct kthread *thread = kthread_lookup(curproc); 37463b8f014Skettenis 37563b8f014Skettenis while (thread->flags & KTHREAD_SHOULDPARK) { 37663b8f014Skettenis thread->flags |= KTHREAD_PARKED; 37763b8f014Skettenis wakeup(thread); 3781ccb306fSclaudio tsleep_nsec(thread, PPAUSE, "parkme", INFSLP); 37963b8f014Skettenis thread->flags &= ~KTHREAD_PARKED; 38063b8f014Skettenis } 38163b8f014Skettenis } 38263b8f014Skettenis 38363b8f014Skettenis void 38463b8f014Skettenis kthread_park(struct proc *p) 38563b8f014Skettenis { 38663b8f014Skettenis struct kthread *thread = kthread_lookup(p); 38763b8f014Skettenis 38863b8f014Skettenis while ((thread->flags & KTHREAD_PARKED) == 0) { 38963b8f014Skettenis thread->flags |= KTHREAD_SHOULDPARK; 39063b8f014Skettenis wake_up_process(thread->proc); 3911ccb306fSclaudio tsleep_nsec(thread, PPAUSE, "park", INFSLP); 39263b8f014Skettenis } 39363b8f014Skettenis } 39463b8f014Skettenis 39563b8f014Skettenis void 39663b8f014Skettenis kthread_unpark(struct proc *p) 39763b8f014Skettenis { 39863b8f014Skettenis struct kthread *thread = kthread_lookup(p); 39963b8f014Skettenis 40063b8f014Skettenis thread->flags &= ~KTHREAD_SHOULDPARK; 40163b8f014Skettenis wakeup(thread); 40263b8f014Skettenis } 40363b8f014Skettenis 40463b8f014Skettenis int 40563b8f014Skettenis kthread_should_stop(void) 40663b8f014Skettenis { 40763b8f014Skettenis struct kthread *thread = kthread_lookup(curproc); 40863b8f014Skettenis return (thread->flags & KTHREAD_SHOULDSTOP); 40963b8f014Skettenis } 41063b8f014Skettenis 41163b8f014Skettenis void 41263b8f014Skettenis kthread_stop(struct proc *p) 41363b8f014Skettenis { 41463b8f014Skettenis struct kthread *thread = kthread_lookup(p); 41563b8f014Skettenis 41663b8f014Skettenis while ((thread->flags & KTHREAD_STOPPED) == 0) { 41763b8f014Skettenis thread->flags |= KTHREAD_SHOULDSTOP; 4188224282cSsemarie kthread_unpark(p); 41963b8f014Skettenis wake_up_process(thread->proc); 4201ccb306fSclaudio tsleep_nsec(thread, PPAUSE, "stop", INFSLP); 42163b8f014Skettenis } 42263b8f014Skettenis LIST_REMOVE(thread, next); 42363b8f014Skettenis free(thread, M_DRM, sizeof(*thread)); 42463b8f014Skettenis } 42563b8f014Skettenis 426a3f8ffedSjsg #if NBIOS > 0 427a3f8ffedSjsg extern char smbios_board_vendor[]; 428a3f8ffedSjsg extern char smbios_board_prod[]; 429a3f8ffedSjsg extern char smbios_board_serial[]; 430a3f8ffedSjsg #endif 431a3f8ffedSjsg 432807828a6Sjsg bool 433807828a6Sjsg dmi_match(int slot, const char *str) 434807828a6Sjsg { 435807828a6Sjsg switch (slot) { 436807828a6Sjsg case DMI_SYS_VENDOR: 437807828a6Sjsg if (hw_vendor != NULL && 438807828a6Sjsg !strcmp(hw_vendor, str)) 439807828a6Sjsg return true; 440807828a6Sjsg break; 441807828a6Sjsg case DMI_PRODUCT_NAME: 442807828a6Sjsg if (hw_prod != NULL && 443807828a6Sjsg !strcmp(hw_prod, str)) 444807828a6Sjsg return true; 445807828a6Sjsg break; 446807828a6Sjsg case DMI_PRODUCT_VERSION: 447807828a6Sjsg if (hw_ver != NULL && 448807828a6Sjsg !strcmp(hw_ver, str)) 449807828a6Sjsg return true; 450807828a6Sjsg break; 451a3f8ffedSjsg #if NBIOS > 0 452a3f8ffedSjsg case DMI_BOARD_VENDOR: 453a3f8ffedSjsg if (strcmp(smbios_board_vendor, str) == 0) 454a3f8ffedSjsg return true; 455a3f8ffedSjsg break; 456a3f8ffedSjsg case DMI_BOARD_NAME: 457a3f8ffedSjsg if (strcmp(smbios_board_prod, str) == 0) 458a3f8ffedSjsg return true; 459a3f8ffedSjsg break; 460a3f8ffedSjsg case DMI_BOARD_SERIAL: 461a3f8ffedSjsg if (strcmp(smbios_board_serial, str) == 0) 462a3f8ffedSjsg return true; 463a3f8ffedSjsg break; 464a3f8ffedSjsg #else 465a3f8ffedSjsg case DMI_BOARD_VENDOR: 466a3f8ffedSjsg if (hw_vendor != NULL && 467a3f8ffedSjsg !strcmp(hw_vendor, str)) 468a3f8ffedSjsg return true; 469a3f8ffedSjsg break; 470a3f8ffedSjsg case DMI_BOARD_NAME: 471a3f8ffedSjsg if (hw_prod != NULL && 472a3f8ffedSjsg !strcmp(hw_prod, str)) 473a3f8ffedSjsg return true; 474a3f8ffedSjsg break; 475a3f8ffedSjsg #endif 476807828a6Sjsg case DMI_NONE: 477807828a6Sjsg default: 478807828a6Sjsg return false; 479807828a6Sjsg } 480807828a6Sjsg 481807828a6Sjsg return false; 482807828a6Sjsg } 4830046ae84Sjsg 4840046ae84Sjsg static bool 4850046ae84Sjsg dmi_found(const struct dmi_system_id *dsi) 4860046ae84Sjsg { 4870046ae84Sjsg int i, slot; 4880046ae84Sjsg 4890046ae84Sjsg for (i = 0; i < nitems(dsi->matches); i++) { 4900046ae84Sjsg slot = dsi->matches[i].slot; 491807828a6Sjsg if (slot == DMI_NONE) 4920046ae84Sjsg break; 493807828a6Sjsg if (!dmi_match(slot, dsi->matches[i].substr)) 4940046ae84Sjsg return false; 4950046ae84Sjsg } 4960046ae84Sjsg 4970046ae84Sjsg return true; 4980046ae84Sjsg } 4990046ae84Sjsg 500b1c2f9d1Sjsg const struct dmi_system_id * 501b1c2f9d1Sjsg dmi_first_match(const struct dmi_system_id *sysid) 502b1c2f9d1Sjsg { 503b1c2f9d1Sjsg const struct dmi_system_id *dsi; 504b1c2f9d1Sjsg 505b1c2f9d1Sjsg for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { 506b1c2f9d1Sjsg if (dmi_found(dsi)) 507b1c2f9d1Sjsg return dsi; 508b1c2f9d1Sjsg } 509b1c2f9d1Sjsg 510b1c2f9d1Sjsg return NULL; 511b1c2f9d1Sjsg } 512b1c2f9d1Sjsg 5137ef4208bSjsg #if NBIOS > 0 514b1c2f9d1Sjsg extern char smbios_bios_date[]; 515d5650ceeSjsg extern char smbios_bios_version[]; 516b1c2f9d1Sjsg #endif 517b1c2f9d1Sjsg 518b1c2f9d1Sjsg const char * 519b1c2f9d1Sjsg dmi_get_system_info(int slot) 520b1c2f9d1Sjsg { 5217ef4208bSjsg #if NBIOS > 0 522d5650ceeSjsg switch (slot) { 523d5650ceeSjsg case DMI_BIOS_DATE: 524b1c2f9d1Sjsg return smbios_bios_date; 525d5650ceeSjsg case DMI_BIOS_VERSION: 526d5650ceeSjsg return smbios_bios_version; 527d5650ceeSjsg default: 528d5650ceeSjsg printf("%s slot %d not handled\n", __func__, slot); 529d5650ceeSjsg } 530b1c2f9d1Sjsg #endif 531b1c2f9d1Sjsg return NULL; 532b1c2f9d1Sjsg } 533b1c2f9d1Sjsg 5340046ae84Sjsg int 5350046ae84Sjsg dmi_check_system(const struct dmi_system_id *sysid) 5360046ae84Sjsg { 5370046ae84Sjsg const struct dmi_system_id *dsi; 5380046ae84Sjsg int num = 0; 5390046ae84Sjsg 5400046ae84Sjsg for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { 5410046ae84Sjsg if (dmi_found(dsi)) { 5420046ae84Sjsg num++; 5430046ae84Sjsg if (dsi->callback && dsi->callback(dsi)) 5440046ae84Sjsg break; 5450046ae84Sjsg } 5460046ae84Sjsg } 5470046ae84Sjsg return (num); 5480046ae84Sjsg } 549332cefa1Sjsg 550c260f068Skettenis struct vm_page * 551c260f068Skettenis alloc_pages(unsigned int gfp_mask, unsigned int order) 552c260f068Skettenis { 553c260f068Skettenis int flags = (gfp_mask & M_NOWAIT) ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK; 554804f6649Skettenis struct uvm_constraint_range *constraint = &no_constraint; 555c260f068Skettenis struct pglist mlist; 556c260f068Skettenis 557c260f068Skettenis if (gfp_mask & M_CANFAIL) 558c260f068Skettenis flags |= UVM_PLA_FAILOK; 5593253c27bSkettenis if (gfp_mask & M_ZERO) 5603253c27bSkettenis flags |= UVM_PLA_ZERO; 561804f6649Skettenis if (gfp_mask & __GFP_DMA32) 562804f6649Skettenis constraint = &dma_constraint; 563c260f068Skettenis 564c260f068Skettenis TAILQ_INIT(&mlist); 565804f6649Skettenis if (uvm_pglistalloc(PAGE_SIZE << order, constraint->ucr_low, 566804f6649Skettenis constraint->ucr_high, PAGE_SIZE, 0, &mlist, 1, flags)) 567c260f068Skettenis return NULL; 568c260f068Skettenis return TAILQ_FIRST(&mlist); 569c260f068Skettenis } 570c260f068Skettenis 571c260f068Skettenis void 572c260f068Skettenis __free_pages(struct vm_page *page, unsigned int order) 573c260f068Skettenis { 574c260f068Skettenis struct pglist mlist; 575c260f068Skettenis int i; 576c260f068Skettenis 577c260f068Skettenis TAILQ_INIT(&mlist); 578c260f068Skettenis for (i = 0; i < (1 << order); i++) 579c260f068Skettenis TAILQ_INSERT_TAIL(&mlist, &page[i], pageq); 580c260f068Skettenis uvm_pglistfree(&mlist); 581c260f068Skettenis } 582c260f068Skettenis 5837f4dd379Sjsg void 5847f4dd379Sjsg __pagevec_release(struct pagevec *pvec) 5857f4dd379Sjsg { 5867f4dd379Sjsg struct pglist mlist; 5877f4dd379Sjsg int i; 5887f4dd379Sjsg 5897f4dd379Sjsg TAILQ_INIT(&mlist); 5907f4dd379Sjsg for (i = 0; i < pvec->nr; i++) 5917f4dd379Sjsg TAILQ_INSERT_TAIL(&mlist, pvec->pages[i], pageq); 5927f4dd379Sjsg uvm_pglistfree(&mlist); 5937f4dd379Sjsg pagevec_reinit(pvec); 5947f4dd379Sjsg } 5957f4dd379Sjsg 59674cebfa8Skettenis static struct kmem_va_mode kv_physwait = { 59774cebfa8Skettenis .kv_map = &phys_map, 59874cebfa8Skettenis .kv_wait = 1, 59974cebfa8Skettenis }; 60074cebfa8Skettenis 601332cefa1Sjsg void * 602332cefa1Sjsg kmap(struct vm_page *pg) 603332cefa1Sjsg { 604332cefa1Sjsg vaddr_t va; 605332cefa1Sjsg 606332cefa1Sjsg #if defined (__HAVE_PMAP_DIRECT) 607332cefa1Sjsg va = pmap_map_direct(pg); 608332cefa1Sjsg #else 60974cebfa8Skettenis va = (vaddr_t)km_alloc(PAGE_SIZE, &kv_physwait, &kp_none, &kd_waitok); 610332cefa1Sjsg pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), PROT_READ | PROT_WRITE); 611332cefa1Sjsg pmap_update(pmap_kernel()); 612332cefa1Sjsg #endif 613332cefa1Sjsg return (void *)va; 614332cefa1Sjsg } 615332cefa1Sjsg 616332cefa1Sjsg void 6176942ea66Sjsg kunmap_va(void *addr) 618332cefa1Sjsg { 619332cefa1Sjsg vaddr_t va = (vaddr_t)addr; 620332cefa1Sjsg 621332cefa1Sjsg #if defined (__HAVE_PMAP_DIRECT) 622332cefa1Sjsg pmap_unmap_direct(va); 623332cefa1Sjsg #else 624332cefa1Sjsg pmap_kremove(va, PAGE_SIZE); 625332cefa1Sjsg pmap_update(pmap_kernel()); 62674cebfa8Skettenis km_free((void *)va, PAGE_SIZE, &kv_physwait, &kp_none); 627332cefa1Sjsg #endif 628332cefa1Sjsg } 629332cefa1Sjsg 63049a189d2Skettenis vaddr_t kmap_atomic_va; 63149a189d2Skettenis int kmap_atomic_inuse; 63249a189d2Skettenis 63349a189d2Skettenis void * 63449a189d2Skettenis kmap_atomic_prot(struct vm_page *pg, pgprot_t prot) 63549a189d2Skettenis { 63649a189d2Skettenis KASSERT(!kmap_atomic_inuse); 63749a189d2Skettenis 63849a189d2Skettenis kmap_atomic_inuse = 1; 63949a189d2Skettenis pmap_kenter_pa(kmap_atomic_va, VM_PAGE_TO_PHYS(pg) | prot, 64049a189d2Skettenis PROT_READ | PROT_WRITE); 64149a189d2Skettenis return (void *)kmap_atomic_va; 64249a189d2Skettenis } 64349a189d2Skettenis 64449a189d2Skettenis void 64549a189d2Skettenis kunmap_atomic(void *addr) 64649a189d2Skettenis { 64749a189d2Skettenis KASSERT(kmap_atomic_inuse); 64849a189d2Skettenis 64949a189d2Skettenis pmap_kremove(kmap_atomic_va, PAGE_SIZE); 65049a189d2Skettenis kmap_atomic_inuse = 0; 65149a189d2Skettenis } 65249a189d2Skettenis 653332cefa1Sjsg void * 654332cefa1Sjsg vmap(struct vm_page **pages, unsigned int npages, unsigned long flags, 655332cefa1Sjsg pgprot_t prot) 656332cefa1Sjsg { 657332cefa1Sjsg vaddr_t va; 658332cefa1Sjsg paddr_t pa; 659332cefa1Sjsg int i; 660332cefa1Sjsg 66174cebfa8Skettenis va = (vaddr_t)km_alloc(PAGE_SIZE * npages, &kv_any, &kp_none, 66274cebfa8Skettenis &kd_nowait); 663332cefa1Sjsg if (va == 0) 664332cefa1Sjsg return NULL; 665332cefa1Sjsg for (i = 0; i < npages; i++) { 666332cefa1Sjsg pa = VM_PAGE_TO_PHYS(pages[i]) | prot; 667332cefa1Sjsg pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa, 668332cefa1Sjsg PROT_READ | PROT_WRITE, 669332cefa1Sjsg PROT_READ | PROT_WRITE | PMAP_WIRED); 670332cefa1Sjsg pmap_update(pmap_kernel()); 671332cefa1Sjsg } 672332cefa1Sjsg 673332cefa1Sjsg return (void *)va; 674332cefa1Sjsg } 675332cefa1Sjsg 676c036ab16Sjsg void * 677c036ab16Sjsg vmap_pfn(unsigned long *pfns, unsigned int npfn, pgprot_t prot) 678c036ab16Sjsg { 679c036ab16Sjsg vaddr_t va; 680c036ab16Sjsg paddr_t pa; 681c036ab16Sjsg int i; 682c036ab16Sjsg 683c036ab16Sjsg va = (vaddr_t)km_alloc(PAGE_SIZE * npfn, &kv_any, &kp_none, 684c036ab16Sjsg &kd_nowait); 685c036ab16Sjsg if (va == 0) 686c036ab16Sjsg return NULL; 687c036ab16Sjsg for (i = 0; i < npfn; i++) { 688c036ab16Sjsg pa = round_page(pfns[i]) | prot; 689c036ab16Sjsg pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa, 690c036ab16Sjsg PROT_READ | PROT_WRITE, 691c036ab16Sjsg PROT_READ | PROT_WRITE | PMAP_WIRED); 692c036ab16Sjsg pmap_update(pmap_kernel()); 693c036ab16Sjsg } 694c036ab16Sjsg 695c036ab16Sjsg return (void *)va; 696c036ab16Sjsg } 697c036ab16Sjsg 698332cefa1Sjsg void 699332cefa1Sjsg vunmap(void *addr, size_t size) 700332cefa1Sjsg { 701332cefa1Sjsg vaddr_t va = (vaddr_t)addr; 702332cefa1Sjsg 703332cefa1Sjsg pmap_remove(pmap_kernel(), va, va + size); 704332cefa1Sjsg pmap_update(pmap_kernel()); 70574cebfa8Skettenis km_free((void *)va, size, &kv_any, &kp_none); 706332cefa1Sjsg } 707332cefa1Sjsg 708ad8b1aafSjsg bool 709ad8b1aafSjsg is_vmalloc_addr(const void *p) 710ad8b1aafSjsg { 711ad8b1aafSjsg vaddr_t min, max, addr; 712ad8b1aafSjsg 713ad8b1aafSjsg min = vm_map_min(kernel_map); 714ad8b1aafSjsg max = vm_map_max(kernel_map); 715ad8b1aafSjsg addr = (vaddr_t)p; 716ad8b1aafSjsg 717ad8b1aafSjsg if (addr >= min && addr <= max) 718ad8b1aafSjsg return true; 719ad8b1aafSjsg else 720ad8b1aafSjsg return false; 721ad8b1aafSjsg } 722ad8b1aafSjsg 7233253c27bSkettenis void 7243253c27bSkettenis print_hex_dump(const char *level, const char *prefix_str, int prefix_type, 7253253c27bSkettenis int rowsize, int groupsize, const void *buf, size_t len, bool ascii) 7263253c27bSkettenis { 7273253c27bSkettenis const uint8_t *cbuf = buf; 7283253c27bSkettenis int i; 7293253c27bSkettenis 7303253c27bSkettenis for (i = 0; i < len; i++) { 7313253c27bSkettenis if ((i % rowsize) == 0) 7323253c27bSkettenis printf("%s", prefix_str); 7333253c27bSkettenis printf("%02x", cbuf[i]); 7343253c27bSkettenis if ((i % rowsize) == (rowsize - 1)) 7353253c27bSkettenis printf("\n"); 7363253c27bSkettenis else 7373253c27bSkettenis printf(" "); 7383253c27bSkettenis } 7393253c27bSkettenis } 7403253c27bSkettenis 7413253c27bSkettenis void * 7423253c27bSkettenis memchr_inv(const void *s, int c, size_t n) 7433253c27bSkettenis { 7443253c27bSkettenis if (n != 0) { 7453253c27bSkettenis const unsigned char *p = s; 7463253c27bSkettenis 7473253c27bSkettenis do { 7483253c27bSkettenis if (*p++ != (unsigned char)c) 7493253c27bSkettenis return ((void *)(p - 1)); 7503253c27bSkettenis } while (--n != 0); 7513253c27bSkettenis } 7523253c27bSkettenis return (NULL); 7533253c27bSkettenis } 7543253c27bSkettenis 75589859f0fSkettenis int 75689859f0fSkettenis panic_cmp(struct rb_node *a, struct rb_node *b) 75789859f0fSkettenis { 75889859f0fSkettenis panic(__func__); 75989859f0fSkettenis } 76089859f0fSkettenis 76189859f0fSkettenis #undef RB_ROOT 76289859f0fSkettenis #define RB_ROOT(head) (head)->rbh_root 76389859f0fSkettenis 76489859f0fSkettenis RB_GENERATE(linux_root, rb_node, __entry, panic_cmp); 76589859f0fSkettenis 766d71700c3Skettenis /* 767d71700c3Skettenis * This is a fairly minimal implementation of the Linux "idr" API. It 7685ca02815Sjsg * probably isn't very efficient, and definitely isn't RCU safe. The 769d71700c3Skettenis * pre-load buffer is global instead of per-cpu; we rely on the kernel 770d71700c3Skettenis * lock to make this work. We do randomize our IDs in order to make 771d71700c3Skettenis * them harder to guess. 772d71700c3Skettenis */ 773d71700c3Skettenis 774d71700c3Skettenis int idr_cmp(struct idr_entry *, struct idr_entry *); 775d71700c3Skettenis SPLAY_PROTOTYPE(idr_tree, idr_entry, entry, idr_cmp); 776d71700c3Skettenis 777d71700c3Skettenis struct pool idr_pool; 778d71700c3Skettenis struct idr_entry *idr_entry_cache; 779d71700c3Skettenis 780d71700c3Skettenis void 781d71700c3Skettenis idr_init(struct idr *idr) 782d71700c3Skettenis { 783d71700c3Skettenis SPLAY_INIT(&idr->tree); 784d71700c3Skettenis } 785d71700c3Skettenis 786d71700c3Skettenis void 787d71700c3Skettenis idr_destroy(struct idr *idr) 788d71700c3Skettenis { 789d71700c3Skettenis struct idr_entry *id; 790d71700c3Skettenis 791d71700c3Skettenis while ((id = SPLAY_MIN(idr_tree, &idr->tree))) { 792d71700c3Skettenis SPLAY_REMOVE(idr_tree, &idr->tree, id); 793d71700c3Skettenis pool_put(&idr_pool, id); 794d71700c3Skettenis } 795d71700c3Skettenis } 796d71700c3Skettenis 797d71700c3Skettenis void 798d71700c3Skettenis idr_preload(unsigned int gfp_mask) 799d71700c3Skettenis { 800d71700c3Skettenis int flags = (gfp_mask & GFP_NOWAIT) ? PR_NOWAIT : PR_WAITOK; 801d71700c3Skettenis 802d71700c3Skettenis KERNEL_ASSERT_LOCKED(); 803d71700c3Skettenis 804d71700c3Skettenis if (idr_entry_cache == NULL) 805d71700c3Skettenis idr_entry_cache = pool_get(&idr_pool, flags); 806d71700c3Skettenis } 807d71700c3Skettenis 808d71700c3Skettenis int 809d9e6dc4fSkettenis idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask) 810d71700c3Skettenis { 811d71700c3Skettenis int flags = (gfp_mask & GFP_NOWAIT) ? PR_NOWAIT : PR_WAITOK; 812d71700c3Skettenis struct idr_entry *id; 8138c3d1b55Skettenis int begin; 814d71700c3Skettenis 815d71700c3Skettenis KERNEL_ASSERT_LOCKED(); 816d71700c3Skettenis 817d71700c3Skettenis if (idr_entry_cache) { 818d71700c3Skettenis id = idr_entry_cache; 819d71700c3Skettenis idr_entry_cache = NULL; 820d71700c3Skettenis } else { 821d71700c3Skettenis id = pool_get(&idr_pool, flags); 822d71700c3Skettenis if (id == NULL) 823d71700c3Skettenis return -ENOMEM; 824d71700c3Skettenis } 825d71700c3Skettenis 826d71700c3Skettenis if (end <= 0) 827d71700c3Skettenis end = INT_MAX; 828d71700c3Skettenis 8293253c27bSkettenis #ifdef notyet 8308c3d1b55Skettenis id->id = begin = start + arc4random_uniform(end - start); 8313253c27bSkettenis #else 8323253c27bSkettenis id->id = begin = start; 8333253c27bSkettenis #endif 834d71700c3Skettenis while (SPLAY_INSERT(idr_tree, &idr->tree, id)) { 8354ce37e7fSjsg if (id->id == end) 836d71700c3Skettenis id->id = start; 8374ce37e7fSjsg else 8384ce37e7fSjsg id->id++; 8398c3d1b55Skettenis if (id->id == begin) { 8408c3d1b55Skettenis pool_put(&idr_pool, id); 8418c3d1b55Skettenis return -ENOSPC; 8428c3d1b55Skettenis } 843d71700c3Skettenis } 844d71700c3Skettenis id->ptr = ptr; 845d71700c3Skettenis return id->id; 846d71700c3Skettenis } 847d71700c3Skettenis 8483253c27bSkettenis void * 849d9e6dc4fSkettenis idr_replace(struct idr *idr, void *ptr, unsigned long id) 8503253c27bSkettenis { 8513253c27bSkettenis struct idr_entry find, *res; 8523253c27bSkettenis void *old; 8533253c27bSkettenis 8543253c27bSkettenis find.id = id; 8553253c27bSkettenis res = SPLAY_FIND(idr_tree, &idr->tree, &find); 8563253c27bSkettenis if (res == NULL) 8573253c27bSkettenis return ERR_PTR(-ENOENT); 8583253c27bSkettenis old = res->ptr; 8593253c27bSkettenis res->ptr = ptr; 8603253c27bSkettenis return old; 8613253c27bSkettenis } 8623253c27bSkettenis 8637f4dd379Sjsg void * 864d9e6dc4fSkettenis idr_remove(struct idr *idr, unsigned long id) 865d71700c3Skettenis { 866d71700c3Skettenis struct idr_entry find, *res; 8677f4dd379Sjsg void *ptr = NULL; 868d71700c3Skettenis 869d71700c3Skettenis find.id = id; 870d71700c3Skettenis res = SPLAY_FIND(idr_tree, &idr->tree, &find); 871d71700c3Skettenis if (res) { 872d71700c3Skettenis SPLAY_REMOVE(idr_tree, &idr->tree, res); 8737f4dd379Sjsg ptr = res->ptr; 874d71700c3Skettenis pool_put(&idr_pool, res); 875d71700c3Skettenis } 8767f4dd379Sjsg return ptr; 877d71700c3Skettenis } 878d71700c3Skettenis 879d71700c3Skettenis void * 880d9e6dc4fSkettenis idr_find(struct idr *idr, unsigned long id) 881d71700c3Skettenis { 882d71700c3Skettenis struct idr_entry find, *res; 883d71700c3Skettenis 884d71700c3Skettenis find.id = id; 885d71700c3Skettenis res = SPLAY_FIND(idr_tree, &idr->tree, &find); 886d71700c3Skettenis if (res == NULL) 887d71700c3Skettenis return NULL; 888d71700c3Skettenis return res->ptr; 889d71700c3Skettenis } 890d71700c3Skettenis 8913253c27bSkettenis void * 8923253c27bSkettenis idr_get_next(struct idr *idr, int *id) 8933253c27bSkettenis { 8943253c27bSkettenis struct idr_entry *res; 8953253c27bSkettenis 89623c0d2a5Skettenis SPLAY_FOREACH(res, idr_tree, &idr->tree) { 89723c0d2a5Skettenis if (res->id >= *id) { 8983253c27bSkettenis *id = res->id; 8993253c27bSkettenis return res->ptr; 9003253c27bSkettenis } 90123c0d2a5Skettenis } 90223c0d2a5Skettenis 90323c0d2a5Skettenis return NULL; 90423c0d2a5Skettenis } 9053253c27bSkettenis 906d71700c3Skettenis int 907d71700c3Skettenis idr_for_each(struct idr *idr, int (*func)(int, void *, void *), void *data) 908d71700c3Skettenis { 909d71700c3Skettenis struct idr_entry *id; 910d71700c3Skettenis int ret; 911d71700c3Skettenis 912d71700c3Skettenis SPLAY_FOREACH(id, idr_tree, &idr->tree) { 913d71700c3Skettenis ret = func(id->id, id->ptr, data); 914d71700c3Skettenis if (ret) 915d71700c3Skettenis return ret; 916d71700c3Skettenis } 917d71700c3Skettenis 918d71700c3Skettenis return 0; 919d71700c3Skettenis } 920d71700c3Skettenis 921d71700c3Skettenis int 922d71700c3Skettenis idr_cmp(struct idr_entry *a, struct idr_entry *b) 923d71700c3Skettenis { 924d71700c3Skettenis return (a->id < b->id ? -1 : a->id > b->id); 925d71700c3Skettenis } 926d71700c3Skettenis 927d71700c3Skettenis SPLAY_GENERATE(idr_tree, idr_entry, entry, idr_cmp); 928d71700c3Skettenis 9293253c27bSkettenis void 9303253c27bSkettenis ida_init(struct ida *ida) 9313253c27bSkettenis { 932d9e6dc4fSkettenis idr_init(&ida->idr); 9333253c27bSkettenis } 9343253c27bSkettenis 9353253c27bSkettenis void 9363253c27bSkettenis ida_destroy(struct ida *ida) 9373253c27bSkettenis { 938d9e6dc4fSkettenis idr_destroy(&ida->idr); 9393253c27bSkettenis } 9403253c27bSkettenis 9413253c27bSkettenis int 9423253c27bSkettenis ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, 943d9e6dc4fSkettenis gfp_t gfp_mask) 9443253c27bSkettenis { 945d9e6dc4fSkettenis return idr_alloc(&ida->idr, NULL, start, end, gfp_mask); 9463253c27bSkettenis } 9473253c27bSkettenis 9487f4dd379Sjsg void 949d9e6dc4fSkettenis ida_simple_remove(struct ida *ida, unsigned int id) 9507f4dd379Sjsg { 951d9e6dc4fSkettenis idr_remove(&ida->idr, id); 9527f4dd379Sjsg } 9537f4dd379Sjsg 9543253c27bSkettenis int 9551bb76ff1Sjsg ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp) 9561bb76ff1Sjsg { 9571bb76ff1Sjsg return idr_alloc(&ida->idr, NULL, min, INT_MAX, gfp); 9581bb76ff1Sjsg } 9591bb76ff1Sjsg 9601bb76ff1Sjsg int 9611bb76ff1Sjsg ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp) 9621bb76ff1Sjsg { 9631bb76ff1Sjsg return idr_alloc(&ida->idr, NULL, 0, max - 1, gfp); 9641bb76ff1Sjsg } 9651bb76ff1Sjsg 9661bb76ff1Sjsg void 9671bb76ff1Sjsg ida_free(struct ida *ida, unsigned int id) 9681bb76ff1Sjsg { 9691bb76ff1Sjsg idr_remove(&ida->idr, id); 9701bb76ff1Sjsg } 9711bb76ff1Sjsg 9721bb76ff1Sjsg int 973c349dbc7Sjsg xarray_cmp(struct xarray_entry *a, struct xarray_entry *b) 974c349dbc7Sjsg { 975c349dbc7Sjsg return (a->id < b->id ? -1 : a->id > b->id); 976c349dbc7Sjsg } 977c349dbc7Sjsg 978c349dbc7Sjsg SPLAY_PROTOTYPE(xarray_tree, xarray_entry, entry, xarray_cmp); 979c349dbc7Sjsg struct pool xa_pool; 980c349dbc7Sjsg SPLAY_GENERATE(xarray_tree, xarray_entry, entry, xarray_cmp); 981c349dbc7Sjsg 982c349dbc7Sjsg void 983c349dbc7Sjsg xa_init_flags(struct xarray *xa, gfp_t flags) 984c349dbc7Sjsg { 985c349dbc7Sjsg SPLAY_INIT(&xa->xa_tree); 9865ca02815Sjsg if (flags & XA_FLAGS_LOCK_IRQ) 9875ca02815Sjsg mtx_init(&xa->xa_lock, IPL_TTY); 9885ca02815Sjsg else 9895ca02815Sjsg mtx_init(&xa->xa_lock, IPL_NONE); 99043925f44Sjsg xa->xa_flags = flags; 991c349dbc7Sjsg } 992c349dbc7Sjsg 993c349dbc7Sjsg void 994c349dbc7Sjsg xa_destroy(struct xarray *xa) 995c349dbc7Sjsg { 996c349dbc7Sjsg struct xarray_entry *id; 997c349dbc7Sjsg 998c349dbc7Sjsg while ((id = SPLAY_MIN(xarray_tree, &xa->xa_tree))) { 999c349dbc7Sjsg SPLAY_REMOVE(xarray_tree, &xa->xa_tree, id); 1000c349dbc7Sjsg pool_put(&xa_pool, id); 1001c349dbc7Sjsg } 1002c349dbc7Sjsg } 1003c349dbc7Sjsg 10041bb76ff1Sjsg /* Don't wrap ids. */ 1005c349dbc7Sjsg int 1006*22008fe3Sjsg __xa_alloc(struct xarray *xa, u32 *id, void *entry, struct xarray_range xr, 1007*22008fe3Sjsg gfp_t gfp) 1008c349dbc7Sjsg { 1009c349dbc7Sjsg struct xarray_entry *xid; 1010*22008fe3Sjsg uint32_t start = xr.start; 1011*22008fe3Sjsg uint32_t end = xr.end; 1012*22008fe3Sjsg 1013*22008fe3Sjsg if (start == 0 && (xa->xa_flags & XA_FLAGS_ALLOC1)) 1014*22008fe3Sjsg start = 1; 1015c349dbc7Sjsg 1016be42cb11Sjsg if (gfp & GFP_NOWAIT) { 1017be42cb11Sjsg xid = pool_get(&xa_pool, PR_NOWAIT); 1018be42cb11Sjsg } else { 1019be42cb11Sjsg mtx_leave(&xa->xa_lock); 1020be42cb11Sjsg xid = pool_get(&xa_pool, PR_WAITOK); 1021be42cb11Sjsg mtx_enter(&xa->xa_lock); 1022be42cb11Sjsg } 1023be42cb11Sjsg 1024c349dbc7Sjsg if (xid == NULL) 1025c349dbc7Sjsg return -ENOMEM; 1026c349dbc7Sjsg 1027*22008fe3Sjsg xid->id = start; 1028c349dbc7Sjsg 1029c349dbc7Sjsg while (SPLAY_INSERT(xarray_tree, &xa->xa_tree, xid)) { 1030*22008fe3Sjsg if (xid->id == end) 1031c349dbc7Sjsg xid->id = start; 10324ce37e7fSjsg else 10334ce37e7fSjsg xid->id++; 1034*22008fe3Sjsg if (xid->id == start) { 1035c349dbc7Sjsg pool_put(&xa_pool, xid); 1036c349dbc7Sjsg return -EBUSY; 1037c349dbc7Sjsg } 1038c349dbc7Sjsg } 1039c349dbc7Sjsg xid->ptr = entry; 1040c349dbc7Sjsg *id = xid->id; 1041c349dbc7Sjsg return 0; 1042c349dbc7Sjsg } 1043c349dbc7Sjsg 10441bb76ff1Sjsg /* 10451bb76ff1Sjsg * Wrap ids and store next id. 10461bb76ff1Sjsg * We walk the entire tree so don't special case wrapping. 10471bb76ff1Sjsg * The only caller of this (i915_drm_client.c) doesn't use next id. 10481bb76ff1Sjsg */ 10491bb76ff1Sjsg int 1050*22008fe3Sjsg __xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry, 1051*22008fe3Sjsg struct xarray_range xr, u32 *next, gfp_t gfp) 10521bb76ff1Sjsg { 1053*22008fe3Sjsg int r = __xa_alloc(xa, id, entry, xr, gfp); 10541bb76ff1Sjsg *next = *id + 1; 10551bb76ff1Sjsg return r; 10561bb76ff1Sjsg } 10571bb76ff1Sjsg 1058c349dbc7Sjsg void * 10595ca02815Sjsg __xa_erase(struct xarray *xa, unsigned long index) 1060c349dbc7Sjsg { 1061c349dbc7Sjsg struct xarray_entry find, *res; 1062c349dbc7Sjsg void *ptr = NULL; 1063c349dbc7Sjsg 1064c349dbc7Sjsg find.id = index; 1065c349dbc7Sjsg res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find); 1066c349dbc7Sjsg if (res) { 1067c349dbc7Sjsg SPLAY_REMOVE(xarray_tree, &xa->xa_tree, res); 1068c349dbc7Sjsg ptr = res->ptr; 1069c349dbc7Sjsg pool_put(&xa_pool, res); 1070c349dbc7Sjsg } 1071c349dbc7Sjsg return ptr; 1072c349dbc7Sjsg } 1073c349dbc7Sjsg 1074c349dbc7Sjsg void * 10755ca02815Sjsg __xa_load(struct xarray *xa, unsigned long index) 1076c349dbc7Sjsg { 1077c349dbc7Sjsg struct xarray_entry find, *res; 1078c349dbc7Sjsg 1079c349dbc7Sjsg find.id = index; 1080c349dbc7Sjsg res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find); 1081c349dbc7Sjsg if (res == NULL) 1082c349dbc7Sjsg return NULL; 1083c349dbc7Sjsg return res->ptr; 1084c349dbc7Sjsg } 1085c349dbc7Sjsg 1086c349dbc7Sjsg void * 10875ca02815Sjsg __xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) 10885ca02815Sjsg { 10895ca02815Sjsg struct xarray_entry find, *res; 10905ca02815Sjsg void *prev; 10915ca02815Sjsg 10925ca02815Sjsg if (entry == NULL) 10935ca02815Sjsg return __xa_erase(xa, index); 10945ca02815Sjsg 10955ca02815Sjsg find.id = index; 10965ca02815Sjsg res = SPLAY_FIND(xarray_tree, &xa->xa_tree, &find); 10975ca02815Sjsg if (res != NULL) { 10985ca02815Sjsg /* index exists */ 10995ca02815Sjsg /* XXX Multislot entries updates not implemented yet */ 11005ca02815Sjsg prev = res->ptr; 11015ca02815Sjsg res->ptr = entry; 11025ca02815Sjsg return prev; 11035ca02815Sjsg } 11045ca02815Sjsg 11055ca02815Sjsg /* index not found, add new */ 1106be42cb11Sjsg if (gfp & GFP_NOWAIT) { 1107be42cb11Sjsg res = pool_get(&xa_pool, PR_NOWAIT); 1108be42cb11Sjsg } else { 1109be42cb11Sjsg mtx_leave(&xa->xa_lock); 1110be42cb11Sjsg res = pool_get(&xa_pool, PR_WAITOK); 1111be42cb11Sjsg mtx_enter(&xa->xa_lock); 1112be42cb11Sjsg } 11135ca02815Sjsg if (res == NULL) 11145ca02815Sjsg return XA_ERROR(-ENOMEM); 11155ca02815Sjsg res->id = index; 11165ca02815Sjsg res->ptr = entry; 11175ca02815Sjsg if (SPLAY_INSERT(xarray_tree, &xa->xa_tree, res) != NULL) 11185ca02815Sjsg return XA_ERROR(-EINVAL); 11195ca02815Sjsg return NULL; /* no prev entry at index */ 11205ca02815Sjsg } 11215ca02815Sjsg 11225ca02815Sjsg void * 1123c349dbc7Sjsg xa_get_next(struct xarray *xa, unsigned long *index) 1124c349dbc7Sjsg { 1125c349dbc7Sjsg struct xarray_entry *res; 1126c349dbc7Sjsg 1127c349dbc7Sjsg SPLAY_FOREACH(res, xarray_tree, &xa->xa_tree) { 1128c349dbc7Sjsg if (res->id >= *index) { 1129c349dbc7Sjsg *index = res->id; 1130c349dbc7Sjsg return res->ptr; 1131c349dbc7Sjsg } 1132c349dbc7Sjsg } 1133c349dbc7Sjsg 1134c349dbc7Sjsg return NULL; 1135c349dbc7Sjsg } 1136c349dbc7Sjsg 1137c349dbc7Sjsg int 11383253c27bSkettenis sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) 11393253c27bSkettenis { 11403253c27bSkettenis table->sgl = mallocarray(nents, sizeof(struct scatterlist), 1141ad8b1aafSjsg M_DRM, gfp_mask | M_ZERO); 11423253c27bSkettenis if (table->sgl == NULL) 11433253c27bSkettenis return -ENOMEM; 11443253c27bSkettenis table->nents = table->orig_nents = nents; 1145ad8b1aafSjsg sg_mark_end(&table->sgl[nents - 1]); 11463253c27bSkettenis return 0; 11473253c27bSkettenis } 11483253c27bSkettenis 11493253c27bSkettenis void 11503253c27bSkettenis sg_free_table(struct sg_table *table) 11513253c27bSkettenis { 11523253c27bSkettenis free(table->sgl, M_DRM, 11533253c27bSkettenis table->orig_nents * sizeof(struct scatterlist)); 1154ad8b1aafSjsg table->orig_nents = 0; 1155ee152407Sjsg table->sgl = NULL; 11563253c27bSkettenis } 11573253c27bSkettenis 11583253c27bSkettenis size_t 11593253c27bSkettenis sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, 11603253c27bSkettenis const void *buf, size_t buflen) 11613253c27bSkettenis { 11623253c27bSkettenis panic("%s", __func__); 11633253c27bSkettenis } 11643253c27bSkettenis 11653253c27bSkettenis int 1166142c034fSkettenis i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 11673253c27bSkettenis { 11683253c27bSkettenis void *cmd = NULL; 11693253c27bSkettenis int cmdlen = 0; 11703253c27bSkettenis int err, ret = 0; 11713253c27bSkettenis int op; 11723253c27bSkettenis 11733253c27bSkettenis iic_acquire_bus(&adap->ic, 0); 11743253c27bSkettenis 11753253c27bSkettenis while (num > 2) { 11763253c27bSkettenis op = (msgs->flags & I2C_M_RD) ? I2C_OP_READ : I2C_OP_WRITE; 11773253c27bSkettenis err = iic_exec(&adap->ic, op, msgs->addr, NULL, 0, 11783253c27bSkettenis msgs->buf, msgs->len, 0); 11793253c27bSkettenis if (err) { 11803253c27bSkettenis ret = -err; 11813253c27bSkettenis goto fail; 11823253c27bSkettenis } 11833253c27bSkettenis msgs++; 11843253c27bSkettenis num--; 11853253c27bSkettenis ret++; 11863253c27bSkettenis } 11873253c27bSkettenis 11883253c27bSkettenis if (num > 1) { 11893253c27bSkettenis cmd = msgs->buf; 11903253c27bSkettenis cmdlen = msgs->len; 11913253c27bSkettenis msgs++; 11923253c27bSkettenis num--; 11933253c27bSkettenis ret++; 11943253c27bSkettenis } 11953253c27bSkettenis 1196142c034fSkettenis op = (msgs->flags & I2C_M_RD) ? 1197142c034fSkettenis I2C_OP_READ_WITH_STOP : I2C_OP_WRITE_WITH_STOP; 1198142c034fSkettenis err = iic_exec(&adap->ic, op, msgs->addr, cmd, cmdlen, 1199142c034fSkettenis msgs->buf, msgs->len, 0); 12003253c27bSkettenis if (err) { 12013253c27bSkettenis ret = -err; 12023253c27bSkettenis goto fail; 12033253c27bSkettenis } 12043253c27bSkettenis msgs++; 12053253c27bSkettenis ret++; 12063253c27bSkettenis 12073253c27bSkettenis fail: 12083253c27bSkettenis iic_release_bus(&adap->ic, 0); 12093253c27bSkettenis 12103253c27bSkettenis return ret; 12113253c27bSkettenis } 12123253c27bSkettenis 1213142c034fSkettenis int 121465bb161bSjsg __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 1215142c034fSkettenis { 12162156c0eeSjsg int ret, retries; 1217142c034fSkettenis 12182156c0eeSjsg retries = adap->retries; 12192156c0eeSjsg retry: 1220c349dbc7Sjsg if (adap->algo) 1221c349dbc7Sjsg ret = adap->algo->master_xfer(adap, msgs, num); 1222c349dbc7Sjsg else 1223c349dbc7Sjsg ret = i2c_master_xfer(adap, msgs, num); 12242156c0eeSjsg if (ret == -EAGAIN && retries > 0) { 12252156c0eeSjsg retries--; 12262156c0eeSjsg goto retry; 12272156c0eeSjsg } 1228c349dbc7Sjsg 122965bb161bSjsg return ret; 123065bb161bSjsg } 123165bb161bSjsg 123265bb161bSjsg int 123365bb161bSjsg i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 123465bb161bSjsg { 123565bb161bSjsg int ret; 123665bb161bSjsg 123765bb161bSjsg if (adap->lock_ops) 123865bb161bSjsg adap->lock_ops->lock_bus(adap, 0); 123965bb161bSjsg 124065bb161bSjsg ret = __i2c_transfer(adap, msgs, num); 124165bb161bSjsg 1242c349dbc7Sjsg if (adap->lock_ops) 1243c349dbc7Sjsg adap->lock_ops->unlock_bus(adap, 0); 1244c349dbc7Sjsg 1245c349dbc7Sjsg return ret; 1246142c034fSkettenis } 1247142c034fSkettenis 1248142c034fSkettenis int 1249142c034fSkettenis i2c_bb_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 1250142c034fSkettenis { 1251142c034fSkettenis struct i2c_algo_bit_data *algo = adap->algo_data; 1252142c034fSkettenis struct i2c_adapter bb; 1253142c034fSkettenis 1254142c034fSkettenis memset(&bb, 0, sizeof(bb)); 1255142c034fSkettenis bb.ic = algo->ic; 1256142c034fSkettenis bb.retries = adap->retries; 1257142c034fSkettenis return i2c_master_xfer(&bb, msgs, num); 1258142c034fSkettenis } 1259142c034fSkettenis 1260142c034fSkettenis uint32_t 1261142c034fSkettenis i2c_bb_functionality(struct i2c_adapter *adap) 1262142c034fSkettenis { 1263142c034fSkettenis return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 1264142c034fSkettenis } 1265142c034fSkettenis 1266142c034fSkettenis struct i2c_algorithm i2c_bit_algo = { 1267142c034fSkettenis .master_xfer = i2c_bb_master_xfer, 1268142c034fSkettenis .functionality = i2c_bb_functionality 1269142c034fSkettenis }; 1270142c034fSkettenis 1271d8a2843fSjsg int 1272d8a2843fSjsg i2c_bit_add_bus(struct i2c_adapter *adap) 1273d8a2843fSjsg { 1274d8a2843fSjsg adap->algo = &i2c_bit_algo; 1275d8a2843fSjsg adap->retries = 3; 1276d8a2843fSjsg 1277d8a2843fSjsg return 0; 1278d8a2843fSjsg } 1279d8a2843fSjsg 1280adfb93f8Skettenis #if defined(__amd64__) || defined(__i386__) 1281adfb93f8Skettenis 1282adfb93f8Skettenis /* 1283adfb93f8Skettenis * This is a minimal implementation of the Linux vga_get/vga_put 12845ca02815Sjsg * interface. In all likelihood, it will only work for inteldrm(4) as 1285adfb93f8Skettenis * it assumes that if there is another active VGA device in the 1286adfb93f8Skettenis * system, it is sitting behind a PCI bridge. 1287adfb93f8Skettenis */ 1288adfb93f8Skettenis 1289adfb93f8Skettenis extern int pci_enumerate_bus(struct pci_softc *, 1290adfb93f8Skettenis int (*)(struct pci_attach_args *), struct pci_attach_args *); 1291adfb93f8Skettenis 1292adfb93f8Skettenis pcitag_t vga_bridge_tag; 1293adfb93f8Skettenis int vga_bridge_disabled; 1294adfb93f8Skettenis 1295adfb93f8Skettenis int 1296adfb93f8Skettenis vga_disable_bridge(struct pci_attach_args *pa) 1297adfb93f8Skettenis { 1298adfb93f8Skettenis pcireg_t bhlc, bc; 1299adfb93f8Skettenis 1300adfb93f8Skettenis if (pa->pa_domain != 0) 1301adfb93f8Skettenis return 0; 1302adfb93f8Skettenis 1303adfb93f8Skettenis bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); 1304adfb93f8Skettenis if (PCI_HDRTYPE_TYPE(bhlc) != 1) 1305adfb93f8Skettenis return 0; 1306adfb93f8Skettenis 1307adfb93f8Skettenis bc = pci_conf_read(pa->pa_pc, pa->pa_tag, PPB_REG_BRIDGECONTROL); 1308adfb93f8Skettenis if ((bc & PPB_BC_VGA_ENABLE) == 0) 1309adfb93f8Skettenis return 0; 1310adfb93f8Skettenis bc &= ~PPB_BC_VGA_ENABLE; 1311adfb93f8Skettenis pci_conf_write(pa->pa_pc, pa->pa_tag, PPB_REG_BRIDGECONTROL, bc); 1312adfb93f8Skettenis 1313adfb93f8Skettenis vga_bridge_tag = pa->pa_tag; 1314adfb93f8Skettenis vga_bridge_disabled = 1; 1315adfb93f8Skettenis 1316adfb93f8Skettenis return 1; 1317adfb93f8Skettenis } 1318adfb93f8Skettenis 1319adfb93f8Skettenis void 1320adfb93f8Skettenis vga_get_uninterruptible(struct pci_dev *pdev, int rsrc) 1321adfb93f8Skettenis { 132203c13a2aSjsg if (pdev->pci->sc_bridgetag != NULL) 132303c13a2aSjsg return; 1324adfb93f8Skettenis pci_enumerate_bus(pdev->pci, vga_disable_bridge, NULL); 1325adfb93f8Skettenis } 1326adfb93f8Skettenis 1327adfb93f8Skettenis void 1328adfb93f8Skettenis vga_put(struct pci_dev *pdev, int rsrc) 1329adfb93f8Skettenis { 1330ec031e48Skettenis pcireg_t bc; 1331ec031e48Skettenis 1332ec031e48Skettenis if (!vga_bridge_disabled) 1333ec031e48Skettenis return; 1334ec031e48Skettenis 1335ec031e48Skettenis bc = pci_conf_read(pdev->pc, vga_bridge_tag, PPB_REG_BRIDGECONTROL); 1336ec031e48Skettenis bc |= PPB_BC_VGA_ENABLE; 1337ec031e48Skettenis pci_conf_write(pdev->pc, vga_bridge_tag, PPB_REG_BRIDGECONTROL, bc); 1338ec031e48Skettenis 1339ec031e48Skettenis vga_bridge_disabled = 0; 1340adfb93f8Skettenis } 1341adfb93f8Skettenis 1342adfb93f8Skettenis #endif 134327f2381eSkettenis 1344a903e442Skettenis suspend_state_t pm_suspend_target_state; 1345a903e442Skettenis 134627f2381eSkettenis /* 134727f2381eSkettenis * ACPI types and interfaces. 134827f2381eSkettenis */ 134927f2381eSkettenis 13509943d3dfSkettenis #ifdef __HAVE_ACPI 135127f2381eSkettenis #include "acpi.h" 135227f2381eSkettenis #endif 135327f2381eSkettenis 135427f2381eSkettenis #if NACPI > 0 135527f2381eSkettenis 135627f2381eSkettenis #include <dev/acpi/acpireg.h> 135727f2381eSkettenis #include <dev/acpi/acpivar.h> 13586a77e6adSkettenis #include <dev/acpi/amltypes.h> 13596a77e6adSkettenis #include <dev/acpi/dsdt.h> 136027f2381eSkettenis 1361a903e442Skettenis struct acpi_fadt acpi_gbl_FADT; 1362a903e442Skettenis 136327f2381eSkettenis acpi_status 13647f4dd379Sjsg acpi_get_table(const char *sig, int instance, 13657f4dd379Sjsg struct acpi_table_header **hdr) 136627f2381eSkettenis { 136727f2381eSkettenis struct acpi_softc *sc = acpi_softc; 136827f2381eSkettenis struct acpi_q *entry; 136927f2381eSkettenis 137027f2381eSkettenis KASSERT(instance == 1); 137127f2381eSkettenis 13725d868007Skettenis if (sc == NULL) 13735d868007Skettenis return AE_NOT_FOUND; 13745d868007Skettenis 137527f2381eSkettenis SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { 137627f2381eSkettenis if (memcmp(entry->q_table, sig, strlen(sig)) == 0) { 137727f2381eSkettenis *hdr = entry->q_table; 137827f2381eSkettenis return 0; 137927f2381eSkettenis } 138027f2381eSkettenis } 138127f2381eSkettenis 138227f2381eSkettenis return AE_NOT_FOUND; 138327f2381eSkettenis } 138427f2381eSkettenis 13851bb76ff1Sjsg void 13861bb76ff1Sjsg acpi_put_table(struct acpi_table_header *hdr) 13871bb76ff1Sjsg { 13881bb76ff1Sjsg } 13891bb76ff1Sjsg 13906a77e6adSkettenis acpi_status 13916a77e6adSkettenis acpi_get_handle(acpi_handle node, const char *name, acpi_handle *rnode) 13926a77e6adSkettenis { 13936a77e6adSkettenis node = aml_searchname(node, name); 13946a77e6adSkettenis if (node == NULL) 13956a77e6adSkettenis return AE_NOT_FOUND; 13966a77e6adSkettenis 13976a77e6adSkettenis *rnode = node; 13986a77e6adSkettenis return 0; 13996a77e6adSkettenis } 14006a77e6adSkettenis 14016a77e6adSkettenis acpi_status 14026a77e6adSkettenis acpi_get_name(acpi_handle node, int type, struct acpi_buffer *buffer) 14036a77e6adSkettenis { 14046a77e6adSkettenis KASSERT(buffer->length != ACPI_ALLOCATE_BUFFER); 14056a77e6adSkettenis KASSERT(type == ACPI_FULL_PATHNAME); 14066a77e6adSkettenis strlcpy(buffer->pointer, aml_nodename(node), buffer->length); 14076a77e6adSkettenis return 0; 14086a77e6adSkettenis } 14096a77e6adSkettenis 14106a77e6adSkettenis acpi_status 14116a77e6adSkettenis acpi_evaluate_object(acpi_handle node, const char *name, 14126a77e6adSkettenis struct acpi_object_list *params, struct acpi_buffer *result) 14136a77e6adSkettenis { 14146a77e6adSkettenis struct aml_value args[4], res; 14156a77e6adSkettenis union acpi_object *obj; 14166a77e6adSkettenis uint8_t *data; 14176a77e6adSkettenis int i; 14186a77e6adSkettenis 14196a77e6adSkettenis KASSERT(params->count <= nitems(args)); 14206a77e6adSkettenis 14216a77e6adSkettenis for (i = 0; i < params->count; i++) { 14226a77e6adSkettenis args[i].type = params->pointer[i].type; 14236a77e6adSkettenis switch (args[i].type) { 14246a77e6adSkettenis case AML_OBJTYPE_INTEGER: 14256a77e6adSkettenis args[i].v_integer = params->pointer[i].integer.value; 14266a77e6adSkettenis break; 14276a77e6adSkettenis case AML_OBJTYPE_BUFFER: 14286a77e6adSkettenis args[i].length = params->pointer[i].buffer.length; 14296a77e6adSkettenis args[i].v_buffer = params->pointer[i].buffer.pointer; 14306a77e6adSkettenis break; 14316a77e6adSkettenis default: 14326a77e6adSkettenis printf("%s: arg type 0x%02x", __func__, args[i].type); 14336a77e6adSkettenis return AE_BAD_PARAMETER; 14346a77e6adSkettenis } 14356a77e6adSkettenis } 14366a77e6adSkettenis 14376a77e6adSkettenis if (name) { 14386a77e6adSkettenis node = aml_searchname(node, name); 14396a77e6adSkettenis if (node == NULL) 14406a77e6adSkettenis return AE_NOT_FOUND; 14416a77e6adSkettenis } 14426a77e6adSkettenis if (aml_evalnode(acpi_softc, node, params->count, args, &res)) { 14436a77e6adSkettenis aml_freevalue(&res); 14446a77e6adSkettenis return AE_ERROR; 14456a77e6adSkettenis } 14466a77e6adSkettenis 14476a77e6adSkettenis KASSERT(result->length == ACPI_ALLOCATE_BUFFER); 14486a77e6adSkettenis 14496a77e6adSkettenis result->length = sizeof(union acpi_object); 14506a77e6adSkettenis switch (res.type) { 14516a77e6adSkettenis case AML_OBJTYPE_BUFFER: 14526a77e6adSkettenis result->length += res.length; 14536a77e6adSkettenis result->pointer = malloc(result->length, M_DRM, M_WAITOK); 14546a77e6adSkettenis obj = (union acpi_object *)result->pointer; 14556a77e6adSkettenis data = (uint8_t *)(obj + 1); 14566a77e6adSkettenis obj->type = res.type; 14576a77e6adSkettenis obj->buffer.length = res.length; 14586a77e6adSkettenis obj->buffer.pointer = data; 14596a77e6adSkettenis memcpy(data, res.v_buffer, res.length); 14606a77e6adSkettenis break; 14616a77e6adSkettenis default: 14626a77e6adSkettenis printf("%s: return type 0x%02x", __func__, res.type); 14636a77e6adSkettenis aml_freevalue(&res); 14646a77e6adSkettenis return AE_ERROR; 14656a77e6adSkettenis } 14666a77e6adSkettenis 14676a77e6adSkettenis aml_freevalue(&res); 14686a77e6adSkettenis return 0; 14696a77e6adSkettenis } 14706a77e6adSkettenis 14716a77e6adSkettenis SLIST_HEAD(, notifier_block) drm_linux_acpi_notify_list = 14726a77e6adSkettenis SLIST_HEAD_INITIALIZER(drm_linux_acpi_notify_list); 14736a77e6adSkettenis 14746a77e6adSkettenis int 14756a77e6adSkettenis drm_linux_acpi_notify(struct aml_node *node, int notify, void *arg) 14766a77e6adSkettenis { 14776a77e6adSkettenis struct acpi_bus_event event; 14786a77e6adSkettenis struct notifier_block *nb; 14796a77e6adSkettenis 14806a77e6adSkettenis event.device_class = ACPI_VIDEO_CLASS; 14816a77e6adSkettenis event.type = notify; 14826a77e6adSkettenis 14836a77e6adSkettenis SLIST_FOREACH(nb, &drm_linux_acpi_notify_list, link) 14846a77e6adSkettenis nb->notifier_call(nb, 0, &event); 14856a77e6adSkettenis return 0; 14866a77e6adSkettenis } 14876a77e6adSkettenis 14886a77e6adSkettenis int 14896a77e6adSkettenis register_acpi_notifier(struct notifier_block *nb) 14906a77e6adSkettenis { 14916a77e6adSkettenis SLIST_INSERT_HEAD(&drm_linux_acpi_notify_list, nb, link); 14926a77e6adSkettenis return 0; 14936a77e6adSkettenis } 14946a77e6adSkettenis 14956a77e6adSkettenis int 14966a77e6adSkettenis unregister_acpi_notifier(struct notifier_block *nb) 14976a77e6adSkettenis { 14984d3f7975Skettenis struct notifier_block *tmp; 14994d3f7975Skettenis 15004d3f7975Skettenis SLIST_FOREACH(tmp, &drm_linux_acpi_notify_list, link) { 15014d3f7975Skettenis if (tmp == nb) { 15024d3f7975Skettenis SLIST_REMOVE(&drm_linux_acpi_notify_list, nb, 15034d3f7975Skettenis notifier_block, link); 15046a77e6adSkettenis return 0; 15056a77e6adSkettenis } 15064d3f7975Skettenis } 15074d3f7975Skettenis 15084d3f7975Skettenis return -ENOENT; 15094d3f7975Skettenis } 15106a77e6adSkettenis 15116a77e6adSkettenis const char * 15126a77e6adSkettenis acpi_format_exception(acpi_status status) 15136a77e6adSkettenis { 15146a77e6adSkettenis switch (status) { 15156a77e6adSkettenis case AE_NOT_FOUND: 15166a77e6adSkettenis return "not found"; 15176a77e6adSkettenis case AE_BAD_PARAMETER: 15186a77e6adSkettenis return "bad parameter"; 15196a77e6adSkettenis default: 15206a77e6adSkettenis return "unknown"; 15216a77e6adSkettenis } 15226a77e6adSkettenis } 15236a77e6adSkettenis 15240759fbd1Skettenis int 15250759fbd1Skettenis acpi_target_system_state(void) 15260759fbd1Skettenis { 15270759fbd1Skettenis return acpi_softc->sc_state; 15280759fbd1Skettenis } 15290759fbd1Skettenis 153027f2381eSkettenis #endif 1531e12511f5Skettenis 15329342ba5eSkettenis SLIST_HEAD(,backlight_device) backlight_device_list = 15339342ba5eSkettenis SLIST_HEAD_INITIALIZER(backlight_device_list); 15349342ba5eSkettenis 1535f88c7015Skettenis void 1536f88c7015Skettenis backlight_do_update_status(void *arg) 1537f88c7015Skettenis { 1538f88c7015Skettenis backlight_update_status(arg); 1539f88c7015Skettenis } 1540f88c7015Skettenis 1541e12511f5Skettenis struct backlight_device * 1542e12511f5Skettenis backlight_device_register(const char *name, void *kdev, void *data, 15439342ba5eSkettenis const struct backlight_ops *ops, const struct backlight_properties *props) 1544e12511f5Skettenis { 1545e12511f5Skettenis struct backlight_device *bd; 1546e12511f5Skettenis 1547e12511f5Skettenis bd = malloc(sizeof(*bd), M_DRM, M_WAITOK); 1548e12511f5Skettenis bd->ops = ops; 1549e12511f5Skettenis bd->props = *props; 1550e12511f5Skettenis bd->data = data; 1551e12511f5Skettenis 1552f88c7015Skettenis task_set(&bd->task, backlight_do_update_status, bd); 1553f88c7015Skettenis 15549342ba5eSkettenis SLIST_INSERT_HEAD(&backlight_device_list, bd, next); 15559342ba5eSkettenis bd->name = name; 15569342ba5eSkettenis 1557e12511f5Skettenis return bd; 1558e12511f5Skettenis } 1559e12511f5Skettenis 1560e12511f5Skettenis void 1561e12511f5Skettenis backlight_device_unregister(struct backlight_device *bd) 1562e12511f5Skettenis { 15639342ba5eSkettenis SLIST_REMOVE(&backlight_device_list, bd, backlight_device, next); 1564e12511f5Skettenis free(bd, M_DRM, sizeof(*bd)); 1565e12511f5Skettenis } 1566f88c7015Skettenis 1567f88c7015Skettenis void 1568f88c7015Skettenis backlight_schedule_update_status(struct backlight_device *bd) 1569f88c7015Skettenis { 1570f88c7015Skettenis task_add(systq, &bd->task); 1571f88c7015Skettenis } 1572b8584f42Srobert 15739342ba5eSkettenis int 1574c349dbc7Sjsg backlight_enable(struct backlight_device *bd) 1575c349dbc7Sjsg { 1576c349dbc7Sjsg if (bd == NULL) 1577c349dbc7Sjsg return 0; 1578c349dbc7Sjsg 1579c349dbc7Sjsg bd->props.power = FB_BLANK_UNBLANK; 1580c349dbc7Sjsg 1581c349dbc7Sjsg return bd->ops->update_status(bd); 1582c349dbc7Sjsg } 1583c349dbc7Sjsg 15849342ba5eSkettenis int 1585c349dbc7Sjsg backlight_disable(struct backlight_device *bd) 1586c349dbc7Sjsg { 1587c349dbc7Sjsg if (bd == NULL) 1588c349dbc7Sjsg return 0; 1589c349dbc7Sjsg 1590c349dbc7Sjsg bd->props.power = FB_BLANK_POWERDOWN; 1591c349dbc7Sjsg 1592c349dbc7Sjsg return bd->ops->update_status(bd); 1593c349dbc7Sjsg } 1594c349dbc7Sjsg 15959342ba5eSkettenis struct backlight_device * 15969342ba5eSkettenis backlight_device_get_by_name(const char *name) 15979342ba5eSkettenis { 15989342ba5eSkettenis struct backlight_device *bd; 15999342ba5eSkettenis 16009342ba5eSkettenis SLIST_FOREACH(bd, &backlight_device_list, next) { 16019342ba5eSkettenis if (strcmp(name, bd->name) == 0) 16029342ba5eSkettenis return bd; 16039342ba5eSkettenis } 16049342ba5eSkettenis 16059342ba5eSkettenis return NULL; 16069342ba5eSkettenis } 16079342ba5eSkettenis 16089342ba5eSkettenis struct drvdata { 16099342ba5eSkettenis struct device *dev; 16109342ba5eSkettenis void *data; 16119342ba5eSkettenis SLIST_ENTRY(drvdata) next; 16129342ba5eSkettenis }; 16139342ba5eSkettenis 16149342ba5eSkettenis SLIST_HEAD(,drvdata) drvdata_list = SLIST_HEAD_INITIALIZER(drvdata_list); 16159342ba5eSkettenis 16169342ba5eSkettenis void 16179342ba5eSkettenis dev_set_drvdata(struct device *dev, void *data) 16189342ba5eSkettenis { 16199342ba5eSkettenis struct drvdata *drvdata; 16209342ba5eSkettenis 16219342ba5eSkettenis SLIST_FOREACH(drvdata, &drvdata_list, next) { 16229342ba5eSkettenis if (drvdata->dev == dev) { 16239342ba5eSkettenis drvdata->data = data; 16249342ba5eSkettenis return; 16259342ba5eSkettenis } 16269342ba5eSkettenis } 16279342ba5eSkettenis 16289342ba5eSkettenis if (data == NULL) 16299342ba5eSkettenis return; 16309342ba5eSkettenis 16319342ba5eSkettenis drvdata = malloc(sizeof(*drvdata), M_DRM, M_WAITOK); 16329342ba5eSkettenis drvdata->dev = dev; 16339342ba5eSkettenis drvdata->data = data; 16349342ba5eSkettenis 16359342ba5eSkettenis SLIST_INSERT_HEAD(&drvdata_list, drvdata, next); 16369342ba5eSkettenis } 16379342ba5eSkettenis 16389342ba5eSkettenis void * 16399342ba5eSkettenis dev_get_drvdata(struct device *dev) 16409342ba5eSkettenis { 16419342ba5eSkettenis struct drvdata *drvdata; 16429342ba5eSkettenis 16439342ba5eSkettenis SLIST_FOREACH(drvdata, &drvdata_list, next) { 16449342ba5eSkettenis if (drvdata->dev == dev) 16459342ba5eSkettenis return drvdata->data; 16469342ba5eSkettenis } 16479342ba5eSkettenis 16489342ba5eSkettenis return NULL; 16499342ba5eSkettenis } 16509342ba5eSkettenis 1651b8584f42Srobert void 1652b8584f42Srobert drm_sysfs_hotplug_event(struct drm_device *dev) 1653b8584f42Srobert { 1654c78098b6Svisa knote_locked(&dev->note, NOTE_CHANGE); 1655b8584f42Srobert } 16567ccd5a2cSjsg 16571bb76ff1Sjsg void 16581bb76ff1Sjsg drm_sysfs_connector_hotplug_event(struct drm_connector *connector) 16591bb76ff1Sjsg { 1660c78098b6Svisa knote_locked(&connector->dev->note, NOTE_CHANGE); 16611bb76ff1Sjsg } 16621bb76ff1Sjsg 16631bb76ff1Sjsg void 16641bb76ff1Sjsg drm_sysfs_connector_status_event(struct drm_connector *connector, 16651bb76ff1Sjsg struct drm_property *property) 16661bb76ff1Sjsg { 16671bb76ff1Sjsg STUB(); 16681bb76ff1Sjsg } 16691bb76ff1Sjsg 1670f005ef32Sjsg void 1671f005ef32Sjsg drm_sysfs_connector_property_event(struct drm_connector *connector, 1672f005ef32Sjsg struct drm_property *property) 1673f005ef32Sjsg { 1674f005ef32Sjsg STUB(); 1675f005ef32Sjsg } 1676f005ef32Sjsg 1677ad8b1aafSjsg struct dma_fence * 1678ad8b1aafSjsg dma_fence_get(struct dma_fence *fence) 1679ad8b1aafSjsg { 1680ad8b1aafSjsg if (fence) 1681ad8b1aafSjsg kref_get(&fence->refcount); 1682ad8b1aafSjsg return fence; 1683ad8b1aafSjsg } 1684ad8b1aafSjsg 1685ad8b1aafSjsg struct dma_fence * 1686ad8b1aafSjsg dma_fence_get_rcu(struct dma_fence *fence) 1687ad8b1aafSjsg { 1688ad8b1aafSjsg if (fence) 1689ad8b1aafSjsg kref_get(&fence->refcount); 1690ad8b1aafSjsg return fence; 1691ad8b1aafSjsg } 1692ad8b1aafSjsg 1693ad8b1aafSjsg struct dma_fence * 1694ad8b1aafSjsg dma_fence_get_rcu_safe(struct dma_fence **dfp) 1695ad8b1aafSjsg { 1696ad8b1aafSjsg struct dma_fence *fence; 1697ad8b1aafSjsg if (dfp == NULL) 1698ad8b1aafSjsg return NULL; 1699ad8b1aafSjsg fence = *dfp; 1700ad8b1aafSjsg if (fence) 1701ad8b1aafSjsg kref_get(&fence->refcount); 1702ad8b1aafSjsg return fence; 1703ad8b1aafSjsg } 1704ad8b1aafSjsg 1705ad8b1aafSjsg void 1706ad8b1aafSjsg dma_fence_release(struct kref *ref) 1707ad8b1aafSjsg { 1708ad8b1aafSjsg struct dma_fence *fence = container_of(ref, struct dma_fence, refcount); 1709ad8b1aafSjsg if (fence->ops && fence->ops->release) 1710ad8b1aafSjsg fence->ops->release(fence); 1711ad8b1aafSjsg else 1712ad8b1aafSjsg free(fence, M_DRM, 0); 1713ad8b1aafSjsg } 1714ad8b1aafSjsg 1715ad8b1aafSjsg void 1716ad8b1aafSjsg dma_fence_put(struct dma_fence *fence) 1717ad8b1aafSjsg { 1718ad8b1aafSjsg if (fence) 1719ad8b1aafSjsg kref_put(&fence->refcount, dma_fence_release); 1720ad8b1aafSjsg } 1721ad8b1aafSjsg 1722ad8b1aafSjsg int 17235ca02815Sjsg dma_fence_signal_timestamp_locked(struct dma_fence *fence, ktime_t timestamp) 1724ad8b1aafSjsg { 1725ad8b1aafSjsg struct dma_fence_cb *cur, *tmp; 1726ad8b1aafSjsg struct list_head cb_list; 1727ad8b1aafSjsg 1728ad8b1aafSjsg if (fence == NULL) 1729ad8b1aafSjsg return -EINVAL; 1730ad8b1aafSjsg 1731ad8b1aafSjsg if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 1732ad8b1aafSjsg return -EINVAL; 1733ad8b1aafSjsg 1734ad8b1aafSjsg list_replace(&fence->cb_list, &cb_list); 1735ad8b1aafSjsg 17365ca02815Sjsg fence->timestamp = timestamp; 1737ad8b1aafSjsg set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); 1738ad8b1aafSjsg 1739ad8b1aafSjsg list_for_each_entry_safe(cur, tmp, &cb_list, node) { 1740ad8b1aafSjsg INIT_LIST_HEAD(&cur->node); 1741ad8b1aafSjsg cur->func(fence, cur); 1742ad8b1aafSjsg } 1743ad8b1aafSjsg 1744ad8b1aafSjsg return 0; 1745ad8b1aafSjsg } 1746ad8b1aafSjsg 1747ad8b1aafSjsg int 1748ad8b1aafSjsg dma_fence_signal(struct dma_fence *fence) 1749ad8b1aafSjsg { 1750ad8b1aafSjsg int r; 1751ad8b1aafSjsg 1752ad8b1aafSjsg if (fence == NULL) 1753ad8b1aafSjsg return -EINVAL; 1754ad8b1aafSjsg 1755ad8b1aafSjsg mtx_enter(fence->lock); 17565ca02815Sjsg r = dma_fence_signal_timestamp_locked(fence, ktime_get()); 17575ca02815Sjsg mtx_leave(fence->lock); 17585ca02815Sjsg 17595ca02815Sjsg return r; 17605ca02815Sjsg } 17615ca02815Sjsg 17625ca02815Sjsg int 17635ca02815Sjsg dma_fence_signal_locked(struct dma_fence *fence) 17645ca02815Sjsg { 17655ca02815Sjsg if (fence == NULL) 17665ca02815Sjsg return -EINVAL; 17675ca02815Sjsg 17685ca02815Sjsg return dma_fence_signal_timestamp_locked(fence, ktime_get()); 17695ca02815Sjsg } 17705ca02815Sjsg 17715ca02815Sjsg int 17725ca02815Sjsg dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp) 17735ca02815Sjsg { 17745ca02815Sjsg int r; 17755ca02815Sjsg 17765ca02815Sjsg if (fence == NULL) 17775ca02815Sjsg return -EINVAL; 17785ca02815Sjsg 17795ca02815Sjsg mtx_enter(fence->lock); 17805ca02815Sjsg r = dma_fence_signal_timestamp_locked(fence, timestamp); 1781ad8b1aafSjsg mtx_leave(fence->lock); 1782ad8b1aafSjsg 1783ad8b1aafSjsg return r; 1784ad8b1aafSjsg } 1785ad8b1aafSjsg 1786ad8b1aafSjsg bool 1787ad8b1aafSjsg dma_fence_is_signaled(struct dma_fence *fence) 1788ad8b1aafSjsg { 1789ad8b1aafSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 1790ad8b1aafSjsg return true; 1791ad8b1aafSjsg 1792ad8b1aafSjsg if (fence->ops->signaled && fence->ops->signaled(fence)) { 1793ad8b1aafSjsg dma_fence_signal(fence); 1794ad8b1aafSjsg return true; 1795ad8b1aafSjsg } 1796ad8b1aafSjsg 1797ad8b1aafSjsg return false; 1798ad8b1aafSjsg } 1799ad8b1aafSjsg 1800ad8b1aafSjsg bool 1801ad8b1aafSjsg dma_fence_is_signaled_locked(struct dma_fence *fence) 1802ad8b1aafSjsg { 1803ad8b1aafSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 1804ad8b1aafSjsg return true; 1805ad8b1aafSjsg 1806ad8b1aafSjsg if (fence->ops->signaled && fence->ops->signaled(fence)) { 1807ad8b1aafSjsg dma_fence_signal_locked(fence); 1808ad8b1aafSjsg return true; 1809ad8b1aafSjsg } 1810ad8b1aafSjsg 1811ad8b1aafSjsg return false; 1812ad8b1aafSjsg } 1813ad8b1aafSjsg 18145158102cSjsg ktime_t 18155158102cSjsg dma_fence_timestamp(struct dma_fence *fence) 18165158102cSjsg { 18175158102cSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { 18185158102cSjsg while (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) 18195158102cSjsg CPU_BUSY_CYCLE(); 18205158102cSjsg return fence->timestamp; 18215158102cSjsg } else { 18225158102cSjsg return ktime_get(); 18235158102cSjsg } 18245158102cSjsg } 18255158102cSjsg 1826ad8b1aafSjsg long 1827ad8b1aafSjsg dma_fence_wait_timeout(struct dma_fence *fence, bool intr, long timeout) 1828ad8b1aafSjsg { 1829ad8b1aafSjsg if (timeout < 0) 1830ad8b1aafSjsg return -EINVAL; 1831ad8b1aafSjsg 1832ad8b1aafSjsg if (fence->ops->wait) 1833ad8b1aafSjsg return fence->ops->wait(fence, intr, timeout); 1834ad8b1aafSjsg else 1835ad8b1aafSjsg return dma_fence_default_wait(fence, intr, timeout); 1836ad8b1aafSjsg } 1837ad8b1aafSjsg 1838ad8b1aafSjsg long 1839ad8b1aafSjsg dma_fence_wait(struct dma_fence *fence, bool intr) 1840ad8b1aafSjsg { 1841ad8b1aafSjsg long ret; 1842ad8b1aafSjsg 1843ad8b1aafSjsg ret = dma_fence_wait_timeout(fence, intr, MAX_SCHEDULE_TIMEOUT); 1844ad8b1aafSjsg if (ret < 0) 1845ad8b1aafSjsg return ret; 1846ad8b1aafSjsg 1847ad8b1aafSjsg return 0; 1848ad8b1aafSjsg } 1849ad8b1aafSjsg 1850ad8b1aafSjsg void 1851ad8b1aafSjsg dma_fence_enable_sw_signaling(struct dma_fence *fence) 1852ad8b1aafSjsg { 1853ad8b1aafSjsg if (!test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags) && 1854ad8b1aafSjsg !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && 1855ad8b1aafSjsg fence->ops->enable_signaling) { 1856ad8b1aafSjsg mtx_enter(fence->lock); 1857ad8b1aafSjsg if (!fence->ops->enable_signaling(fence)) 1858ad8b1aafSjsg dma_fence_signal_locked(fence); 1859ad8b1aafSjsg mtx_leave(fence->lock); 1860ad8b1aafSjsg } 1861ad8b1aafSjsg } 1862ad8b1aafSjsg 1863ad8b1aafSjsg void 1864ad8b1aafSjsg dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, 1865ad8b1aafSjsg struct mutex *lock, uint64_t context, uint64_t seqno) 1866ad8b1aafSjsg { 1867ad8b1aafSjsg fence->ops = ops; 1868ad8b1aafSjsg fence->lock = lock; 1869ad8b1aafSjsg fence->context = context; 1870ad8b1aafSjsg fence->seqno = seqno; 1871ad8b1aafSjsg fence->flags = 0; 1872ad8b1aafSjsg fence->error = 0; 1873ad8b1aafSjsg kref_init(&fence->refcount); 1874ad8b1aafSjsg INIT_LIST_HEAD(&fence->cb_list); 1875ad8b1aafSjsg } 1876ad8b1aafSjsg 1877ad8b1aafSjsg int 1878ad8b1aafSjsg dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb, 1879ad8b1aafSjsg dma_fence_func_t func) 1880ad8b1aafSjsg { 1881ad8b1aafSjsg int ret = 0; 1882ad8b1aafSjsg bool was_set; 1883ad8b1aafSjsg 1884ad8b1aafSjsg if (WARN_ON(!fence || !func)) 1885ad8b1aafSjsg return -EINVAL; 1886ad8b1aafSjsg 1887ad8b1aafSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { 1888ad8b1aafSjsg INIT_LIST_HEAD(&cb->node); 1889ad8b1aafSjsg return -ENOENT; 1890ad8b1aafSjsg } 1891ad8b1aafSjsg 1892ad8b1aafSjsg mtx_enter(fence->lock); 1893ad8b1aafSjsg 1894ad8b1aafSjsg was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags); 1895ad8b1aafSjsg 1896ad8b1aafSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 1897ad8b1aafSjsg ret = -ENOENT; 1898ad8b1aafSjsg else if (!was_set && fence->ops->enable_signaling) { 1899ad8b1aafSjsg if (!fence->ops->enable_signaling(fence)) { 1900ad8b1aafSjsg dma_fence_signal_locked(fence); 1901ad8b1aafSjsg ret = -ENOENT; 1902ad8b1aafSjsg } 1903ad8b1aafSjsg } 1904ad8b1aafSjsg 1905ad8b1aafSjsg if (!ret) { 1906ad8b1aafSjsg cb->func = func; 1907ad8b1aafSjsg list_add_tail(&cb->node, &fence->cb_list); 1908ad8b1aafSjsg } else 1909ad8b1aafSjsg INIT_LIST_HEAD(&cb->node); 1910ad8b1aafSjsg mtx_leave(fence->lock); 1911ad8b1aafSjsg 1912ad8b1aafSjsg return ret; 1913ad8b1aafSjsg } 1914ad8b1aafSjsg 1915ad8b1aafSjsg bool 1916ad8b1aafSjsg dma_fence_remove_callback(struct dma_fence *fence, struct dma_fence_cb *cb) 1917ad8b1aafSjsg { 1918ad8b1aafSjsg bool ret; 1919ad8b1aafSjsg 1920ad8b1aafSjsg mtx_enter(fence->lock); 1921ad8b1aafSjsg 1922ad8b1aafSjsg ret = !list_empty(&cb->node); 1923ad8b1aafSjsg if (ret) 1924ad8b1aafSjsg list_del_init(&cb->node); 1925ad8b1aafSjsg 1926ad8b1aafSjsg mtx_leave(fence->lock); 1927ad8b1aafSjsg 1928ad8b1aafSjsg return ret; 1929ad8b1aafSjsg } 1930ad8b1aafSjsg 1931c349dbc7Sjsg static atomic64_t drm_fence_context_count = ATOMIC64_INIT(1); 19327ccd5a2cSjsg 1933c349dbc7Sjsg uint64_t 19347f4dd379Sjsg dma_fence_context_alloc(unsigned int num) 19357ccd5a2cSjsg { 1936c349dbc7Sjsg return atomic64_add_return(num, &drm_fence_context_count) - num; 19377ccd5a2cSjsg } 1938a9ee023bSkettenis 1939537ee4c6Sjsg struct default_wait_cb { 1940537ee4c6Sjsg struct dma_fence_cb base; 1941537ee4c6Sjsg struct proc *proc; 1942537ee4c6Sjsg }; 1943537ee4c6Sjsg 194413e5339cSjsg static void 194513e5339cSjsg dma_fence_default_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb) 194613e5339cSjsg { 1947537ee4c6Sjsg struct default_wait_cb *wait = 1948537ee4c6Sjsg container_of(cb, struct default_wait_cb, base); 194956a2da50Sjsg wake_up_process(wait->proc); 195013e5339cSjsg } 195113e5339cSjsg 195213e5339cSjsg long 195313e5339cSjsg dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) 195413e5339cSjsg { 195513e5339cSjsg long ret = timeout ? timeout : 1; 195619fc7f4fSjsg unsigned long end; 195713e5339cSjsg int err; 1958537ee4c6Sjsg struct default_wait_cb cb; 195913e5339cSjsg bool was_set; 196013e5339cSjsg 196119fc7f4fSjsg KASSERT(timeout <= INT_MAX); 196219fc7f4fSjsg 196313e5339cSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 196413e5339cSjsg return ret; 196513e5339cSjsg 196613e5339cSjsg mtx_enter(fence->lock); 196713e5339cSjsg 196813e5339cSjsg was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, 196913e5339cSjsg &fence->flags); 197013e5339cSjsg 197113e5339cSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 197213e5339cSjsg goto out; 197313e5339cSjsg 197413e5339cSjsg if (!was_set && fence->ops->enable_signaling) { 197513e5339cSjsg if (!fence->ops->enable_signaling(fence)) { 197613e5339cSjsg dma_fence_signal_locked(fence); 197713e5339cSjsg goto out; 197813e5339cSjsg } 197913e5339cSjsg } 198013e5339cSjsg 198113e5339cSjsg if (timeout == 0) { 198213e5339cSjsg ret = 0; 198313e5339cSjsg goto out; 198413e5339cSjsg } 198513e5339cSjsg 1986537ee4c6Sjsg cb.base.func = dma_fence_default_wait_cb; 1987537ee4c6Sjsg cb.proc = curproc; 1988537ee4c6Sjsg list_add(&cb.base.node, &fence->cb_list); 198913e5339cSjsg 199019fc7f4fSjsg end = jiffies + timeout; 199119fc7f4fSjsg for (ret = timeout; ret > 0; ret = MAX(0, end - jiffies)) { 199219fc7f4fSjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) 199319fc7f4fSjsg break; 199419fc7f4fSjsg err = msleep(curproc, fence->lock, intr ? PCATCH : 0, 199519fc7f4fSjsg "dmafence", ret); 199613e5339cSjsg if (err == EINTR || err == ERESTART) { 199713e5339cSjsg ret = -ERESTARTSYS; 199813e5339cSjsg break; 199913e5339cSjsg } 200013e5339cSjsg } 200113e5339cSjsg 2002537ee4c6Sjsg if (!list_empty(&cb.base.node)) 2003537ee4c6Sjsg list_del(&cb.base.node); 200413e5339cSjsg out: 200513e5339cSjsg mtx_leave(fence->lock); 200613e5339cSjsg 200713e5339cSjsg return ret; 200813e5339cSjsg } 200913e5339cSjsg 2010537ee4c6Sjsg static bool 2011537ee4c6Sjsg dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count, 2012537ee4c6Sjsg uint32_t *idx) 2013537ee4c6Sjsg { 2014537ee4c6Sjsg int i; 2015537ee4c6Sjsg 2016537ee4c6Sjsg for (i = 0; i < count; ++i) { 2017537ee4c6Sjsg struct dma_fence *fence = fences[i]; 2018537ee4c6Sjsg if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { 2019537ee4c6Sjsg if (idx) 2020537ee4c6Sjsg *idx = i; 2021537ee4c6Sjsg return true; 2022537ee4c6Sjsg } 2023537ee4c6Sjsg } 2024537ee4c6Sjsg return false; 2025537ee4c6Sjsg } 2026537ee4c6Sjsg 2027537ee4c6Sjsg long 2028537ee4c6Sjsg dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, 2029537ee4c6Sjsg bool intr, long timeout, uint32_t *idx) 2030537ee4c6Sjsg { 2031537ee4c6Sjsg struct default_wait_cb *cb; 203219fc7f4fSjsg long ret = timeout; 203319fc7f4fSjsg unsigned long end; 2034537ee4c6Sjsg int i, err; 203519fc7f4fSjsg 203619fc7f4fSjsg KASSERT(timeout <= INT_MAX); 2037537ee4c6Sjsg 2038537ee4c6Sjsg if (timeout == 0) { 2039537ee4c6Sjsg for (i = 0; i < count; i++) { 2040537ee4c6Sjsg if (dma_fence_is_signaled(fences[i])) { 2041537ee4c6Sjsg if (idx) 2042537ee4c6Sjsg *idx = i; 2043537ee4c6Sjsg return 1; 2044537ee4c6Sjsg } 2045537ee4c6Sjsg } 2046537ee4c6Sjsg return 0; 2047537ee4c6Sjsg } 2048537ee4c6Sjsg 2049537ee4c6Sjsg cb = mallocarray(count, sizeof(*cb), M_DRM, M_WAITOK|M_CANFAIL|M_ZERO); 2050537ee4c6Sjsg if (cb == NULL) 2051537ee4c6Sjsg return -ENOMEM; 2052537ee4c6Sjsg 2053537ee4c6Sjsg for (i = 0; i < count; i++) { 2054537ee4c6Sjsg struct dma_fence *fence = fences[i]; 2055537ee4c6Sjsg cb[i].proc = curproc; 2056537ee4c6Sjsg if (dma_fence_add_callback(fence, &cb[i].base, 2057537ee4c6Sjsg dma_fence_default_wait_cb)) { 2058537ee4c6Sjsg if (idx) 2059537ee4c6Sjsg *idx = i; 2060537ee4c6Sjsg goto cb_cleanup; 2061537ee4c6Sjsg } 2062537ee4c6Sjsg } 2063537ee4c6Sjsg 206419fc7f4fSjsg end = jiffies + timeout; 206519fc7f4fSjsg for (ret = timeout; ret > 0; ret = MAX(0, end - jiffies)) { 2066537ee4c6Sjsg if (dma_fence_test_signaled_any(fences, count, idx)) 2067537ee4c6Sjsg break; 206819fc7f4fSjsg err = tsleep(curproc, intr ? PCATCH : 0, "dfwat", ret); 2069537ee4c6Sjsg if (err == EINTR || err == ERESTART) { 2070537ee4c6Sjsg ret = -ERESTARTSYS; 2071537ee4c6Sjsg break; 2072537ee4c6Sjsg } 2073537ee4c6Sjsg } 2074537ee4c6Sjsg 2075537ee4c6Sjsg cb_cleanup: 2076537ee4c6Sjsg while (i-- > 0) 2077537ee4c6Sjsg dma_fence_remove_callback(fences[i], &cb[i].base); 2078537ee4c6Sjsg free(cb, M_DRM, count * sizeof(*cb)); 2079537ee4c6Sjsg return ret; 2080537ee4c6Sjsg } 2081537ee4c6Sjsg 2082f005ef32Sjsg void 2083f005ef32Sjsg dma_fence_set_deadline(struct dma_fence *f, ktime_t t) 2084f005ef32Sjsg { 2085f005ef32Sjsg if (f->ops->set_deadline == NULL) 2086f005ef32Sjsg return; 2087f005ef32Sjsg if (dma_fence_is_signaled(f) == false) 2088f005ef32Sjsg f->ops->set_deadline(f, t); 2089f005ef32Sjsg } 2090f005ef32Sjsg 2091c349dbc7Sjsg static struct dma_fence dma_fence_stub; 2092c349dbc7Sjsg static struct mutex dma_fence_stub_mtx = MUTEX_INITIALIZER(IPL_TTY); 2093c349dbc7Sjsg 2094c349dbc7Sjsg static const char * 2095c349dbc7Sjsg dma_fence_stub_get_name(struct dma_fence *fence) 2096c349dbc7Sjsg { 2097c349dbc7Sjsg return "stub"; 2098c349dbc7Sjsg } 2099c349dbc7Sjsg 2100c349dbc7Sjsg static const struct dma_fence_ops dma_fence_stub_ops = { 2101c349dbc7Sjsg .get_driver_name = dma_fence_stub_get_name, 2102c349dbc7Sjsg .get_timeline_name = dma_fence_stub_get_name, 2103c349dbc7Sjsg }; 2104c349dbc7Sjsg 2105c349dbc7Sjsg struct dma_fence * 2106c349dbc7Sjsg dma_fence_get_stub(void) 2107c349dbc7Sjsg { 2108c349dbc7Sjsg mtx_enter(&dma_fence_stub_mtx); 2109c349dbc7Sjsg if (dma_fence_stub.ops == NULL) { 2110c349dbc7Sjsg dma_fence_init(&dma_fence_stub, &dma_fence_stub_ops, 2111c349dbc7Sjsg &dma_fence_stub_mtx, 0, 0); 2112c349dbc7Sjsg dma_fence_signal_locked(&dma_fence_stub); 2113c349dbc7Sjsg } 2114c349dbc7Sjsg mtx_leave(&dma_fence_stub_mtx); 2115c349dbc7Sjsg 2116c349dbc7Sjsg return dma_fence_get(&dma_fence_stub); 2117c349dbc7Sjsg } 2118c349dbc7Sjsg 21195ca02815Sjsg struct dma_fence * 2120e80177aeSjsg dma_fence_allocate_private_stub(ktime_t ts) 21215ca02815Sjsg { 21225ca02815Sjsg struct dma_fence *f = malloc(sizeof(*f), M_DRM, 21235ca02815Sjsg M_ZERO | M_WAITOK | M_CANFAIL); 21245ca02815Sjsg if (f == NULL) 2125f69d21f3Sjsg return NULL; 21265ca02815Sjsg dma_fence_init(f, &dma_fence_stub_ops, &dma_fence_stub_mtx, 0, 0); 2127e80177aeSjsg dma_fence_signal_timestamp(f, ts); 21285ca02815Sjsg return f; 21295ca02815Sjsg } 21305ca02815Sjsg 213195f00a37Sjsg static const char * 213295f00a37Sjsg dma_fence_array_get_driver_name(struct dma_fence *fence) 213395f00a37Sjsg { 213495f00a37Sjsg return "dma_fence_array"; 213595f00a37Sjsg } 213695f00a37Sjsg 213795f00a37Sjsg static const char * 213895f00a37Sjsg dma_fence_array_get_timeline_name(struct dma_fence *fence) 213995f00a37Sjsg { 214095f00a37Sjsg return "unbound"; 214195f00a37Sjsg } 214295f00a37Sjsg 214395f00a37Sjsg static void 21445ca02815Sjsg irq_dma_fence_array_work(void *arg) 214595f00a37Sjsg { 21465ca02815Sjsg struct dma_fence_array *dfa = (struct dma_fence_array *)arg; 214795f00a37Sjsg dma_fence_signal(&dfa->base); 214895f00a37Sjsg dma_fence_put(&dfa->base); 214995f00a37Sjsg } 215095f00a37Sjsg 215195f00a37Sjsg static void 215295f00a37Sjsg dma_fence_array_cb_func(struct dma_fence *f, struct dma_fence_cb *cb) 215395f00a37Sjsg { 215495f00a37Sjsg struct dma_fence_array_cb *array_cb = 215595f00a37Sjsg container_of(cb, struct dma_fence_array_cb, cb); 215695f00a37Sjsg struct dma_fence_array *dfa = array_cb->array; 215795f00a37Sjsg 215895f00a37Sjsg if (atomic_dec_and_test(&dfa->num_pending)) 21595ca02815Sjsg timeout_add(&dfa->to, 1); 216095f00a37Sjsg else 216195f00a37Sjsg dma_fence_put(&dfa->base); 216295f00a37Sjsg } 216395f00a37Sjsg 216495f00a37Sjsg static bool 216595f00a37Sjsg dma_fence_array_enable_signaling(struct dma_fence *fence) 216695f00a37Sjsg { 216795f00a37Sjsg struct dma_fence_array *dfa = to_dma_fence_array(fence); 216895f00a37Sjsg struct dma_fence_array_cb *cb = (void *)(&dfa[1]); 216995f00a37Sjsg int i; 217095f00a37Sjsg 217195f00a37Sjsg for (i = 0; i < dfa->num_fences; ++i) { 217295f00a37Sjsg cb[i].array = dfa; 217395f00a37Sjsg dma_fence_get(&dfa->base); 217495f00a37Sjsg if (dma_fence_add_callback(dfa->fences[i], &cb[i].cb, 217595f00a37Sjsg dma_fence_array_cb_func)) { 217695f00a37Sjsg dma_fence_put(&dfa->base); 217795f00a37Sjsg if (atomic_dec_and_test(&dfa->num_pending)) 217895f00a37Sjsg return false; 217995f00a37Sjsg } 218095f00a37Sjsg } 218195f00a37Sjsg 218295f00a37Sjsg return true; 218395f00a37Sjsg } 218495f00a37Sjsg 2185ad8b1aafSjsg static bool 2186ad8b1aafSjsg dma_fence_array_signaled(struct dma_fence *fence) 218795f00a37Sjsg { 218895f00a37Sjsg struct dma_fence_array *dfa = to_dma_fence_array(fence); 218995f00a37Sjsg 219095f00a37Sjsg return atomic_read(&dfa->num_pending) <= 0; 219195f00a37Sjsg } 219295f00a37Sjsg 2193ad8b1aafSjsg static void 2194ad8b1aafSjsg dma_fence_array_release(struct dma_fence *fence) 219595f00a37Sjsg { 219695f00a37Sjsg struct dma_fence_array *dfa = to_dma_fence_array(fence); 219795f00a37Sjsg int i; 219895f00a37Sjsg 219995f00a37Sjsg for (i = 0; i < dfa->num_fences; ++i) 220095f00a37Sjsg dma_fence_put(dfa->fences[i]); 220195f00a37Sjsg 220295f00a37Sjsg free(dfa->fences, M_DRM, 0); 220395f00a37Sjsg dma_fence_free(fence); 220495f00a37Sjsg } 220595f00a37Sjsg 220695f00a37Sjsg struct dma_fence_array * 220795f00a37Sjsg dma_fence_array_create(int num_fences, struct dma_fence **fences, u64 context, 220895f00a37Sjsg unsigned seqno, bool signal_on_any) 220995f00a37Sjsg { 221095f00a37Sjsg struct dma_fence_array *dfa = malloc(sizeof(*dfa) + 221195f00a37Sjsg (num_fences * sizeof(struct dma_fence_array_cb)), 221295f00a37Sjsg M_DRM, M_WAITOK|M_CANFAIL|M_ZERO); 221395f00a37Sjsg if (dfa == NULL) 221495f00a37Sjsg return NULL; 221595f00a37Sjsg 221695f00a37Sjsg mtx_init(&dfa->lock, IPL_TTY); 221795f00a37Sjsg dma_fence_init(&dfa->base, &dma_fence_array_ops, &dfa->lock, 221895f00a37Sjsg context, seqno); 22195ca02815Sjsg timeout_set(&dfa->to, irq_dma_fence_array_work, dfa); 222095f00a37Sjsg 222195f00a37Sjsg dfa->num_fences = num_fences; 222295f00a37Sjsg atomic_set(&dfa->num_pending, signal_on_any ? 1 : num_fences); 222395f00a37Sjsg dfa->fences = fences; 222495f00a37Sjsg 222595f00a37Sjsg return dfa; 222695f00a37Sjsg } 222795f00a37Sjsg 22281bb76ff1Sjsg struct dma_fence * 22291bb76ff1Sjsg dma_fence_array_first(struct dma_fence *f) 22301bb76ff1Sjsg { 22311bb76ff1Sjsg struct dma_fence_array *dfa; 22321bb76ff1Sjsg 22331bb76ff1Sjsg if (f == NULL) 22341bb76ff1Sjsg return NULL; 22351bb76ff1Sjsg 22361bb76ff1Sjsg if ((dfa = to_dma_fence_array(f)) == NULL) 22371bb76ff1Sjsg return f; 22381bb76ff1Sjsg 22391bb76ff1Sjsg if (dfa->num_fences > 0) 22401bb76ff1Sjsg return dfa->fences[0]; 22411bb76ff1Sjsg 22421bb76ff1Sjsg return NULL; 22431bb76ff1Sjsg } 22441bb76ff1Sjsg 22451bb76ff1Sjsg struct dma_fence * 22461bb76ff1Sjsg dma_fence_array_next(struct dma_fence *f, unsigned int i) 22471bb76ff1Sjsg { 22481bb76ff1Sjsg struct dma_fence_array *dfa; 22491bb76ff1Sjsg 22501bb76ff1Sjsg if (f == NULL) 22511bb76ff1Sjsg return NULL; 22521bb76ff1Sjsg 22531bb76ff1Sjsg if ((dfa = to_dma_fence_array(f)) == NULL) 22541bb76ff1Sjsg return NULL; 22551bb76ff1Sjsg 22561bb76ff1Sjsg if (i < dfa->num_fences) 22571bb76ff1Sjsg return dfa->fences[i]; 22581bb76ff1Sjsg 22591bb76ff1Sjsg return NULL; 22601bb76ff1Sjsg } 22611bb76ff1Sjsg 226295f00a37Sjsg const struct dma_fence_ops dma_fence_array_ops = { 226395f00a37Sjsg .get_driver_name = dma_fence_array_get_driver_name, 226495f00a37Sjsg .get_timeline_name = dma_fence_array_get_timeline_name, 226595f00a37Sjsg .enable_signaling = dma_fence_array_enable_signaling, 226695f00a37Sjsg .signaled = dma_fence_array_signaled, 226795f00a37Sjsg .release = dma_fence_array_release, 226895f00a37Sjsg }; 226995f00a37Sjsg 2270a9ee023bSkettenis int 2271ad8b1aafSjsg dma_fence_chain_find_seqno(struct dma_fence **df, uint64_t seqno) 2272ad8b1aafSjsg { 2273f56254deSjsg struct dma_fence_chain *chain; 2274f56254deSjsg struct dma_fence *fence; 2275f56254deSjsg 2276ad8b1aafSjsg if (seqno == 0) 2277ad8b1aafSjsg return 0; 2278f56254deSjsg 2279f56254deSjsg if ((chain = to_dma_fence_chain(*df)) == NULL) 2280f56254deSjsg return -EINVAL; 2281f56254deSjsg 2282f56254deSjsg fence = &chain->base; 2283f56254deSjsg if (fence->seqno < seqno) 2284f56254deSjsg return -EINVAL; 2285f56254deSjsg 2286f56254deSjsg dma_fence_chain_for_each(*df, fence) { 2287f56254deSjsg if ((*df)->context != fence->context) 2288f56254deSjsg break; 2289f56254deSjsg 2290f56254deSjsg chain = to_dma_fence_chain(*df); 2291f56254deSjsg if (chain->prev_seqno < seqno) 2292f56254deSjsg break; 2293f56254deSjsg } 2294f56254deSjsg dma_fence_put(fence); 2295f56254deSjsg 2296f56254deSjsg return 0; 2297ad8b1aafSjsg } 2298ad8b1aafSjsg 2299ad8b1aafSjsg void 2300ad8b1aafSjsg dma_fence_chain_init(struct dma_fence_chain *chain, struct dma_fence *prev, 2301ad8b1aafSjsg struct dma_fence *fence, uint64_t seqno) 2302ad8b1aafSjsg { 2303ad8b1aafSjsg uint64_t context; 2304ad8b1aafSjsg 2305ad8b1aafSjsg chain->fence = fence; 2306ad8b1aafSjsg chain->prev = prev; 2307ad8b1aafSjsg mtx_init(&chain->lock, IPL_TTY); 2308ad8b1aafSjsg 23095ca02815Sjsg /* if prev is a chain */ 23105ca02815Sjsg if (to_dma_fence_chain(prev) != NULL) { 2311bcd4d0b5Sjsg if (__dma_fence_is_later(seqno, prev->seqno, prev->ops)) { 2312ad8b1aafSjsg chain->prev_seqno = prev->seqno; 2313ad8b1aafSjsg context = prev->context; 2314ad8b1aafSjsg } else { 2315ad8b1aafSjsg chain->prev_seqno = 0; 2316ad8b1aafSjsg context = dma_fence_context_alloc(1); 23175ca02815Sjsg seqno = prev->seqno; 23185ca02815Sjsg } 23195ca02815Sjsg } else { 23205ca02815Sjsg chain->prev_seqno = 0; 23215ca02815Sjsg context = dma_fence_context_alloc(1); 2322ad8b1aafSjsg } 2323ad8b1aafSjsg 2324ad8b1aafSjsg dma_fence_init(&chain->base, &dma_fence_chain_ops, &chain->lock, 2325ad8b1aafSjsg context, seqno); 2326ad8b1aafSjsg } 2327ad8b1aafSjsg 2328ad8b1aafSjsg static const char * 2329ad8b1aafSjsg dma_fence_chain_get_driver_name(struct dma_fence *fence) 2330ad8b1aafSjsg { 2331ad8b1aafSjsg return "dma_fence_chain"; 2332ad8b1aafSjsg } 2333ad8b1aafSjsg 2334ad8b1aafSjsg static const char * 2335ad8b1aafSjsg dma_fence_chain_get_timeline_name(struct dma_fence *fence) 2336ad8b1aafSjsg { 2337ad8b1aafSjsg return "unbound"; 2338ad8b1aafSjsg } 2339ad8b1aafSjsg 23405ca02815Sjsg static bool dma_fence_chain_enable_signaling(struct dma_fence *); 23415ca02815Sjsg 23425ca02815Sjsg static void 23435ca02815Sjsg dma_fence_chain_timo(void *arg) 23445ca02815Sjsg { 23455ca02815Sjsg struct dma_fence_chain *chain = (struct dma_fence_chain *)arg; 23465ca02815Sjsg 23475ca02815Sjsg if (dma_fence_chain_enable_signaling(&chain->base) == false) 23485ca02815Sjsg dma_fence_signal(&chain->base); 23495ca02815Sjsg dma_fence_put(&chain->base); 23505ca02815Sjsg } 23515ca02815Sjsg 23525ca02815Sjsg static void 23535ca02815Sjsg dma_fence_chain_cb(struct dma_fence *f, struct dma_fence_cb *cb) 23545ca02815Sjsg { 23555ca02815Sjsg struct dma_fence_chain *chain = 23565ca02815Sjsg container_of(cb, struct dma_fence_chain, cb); 23575ca02815Sjsg timeout_set(&chain->to, dma_fence_chain_timo, chain); 23585ca02815Sjsg timeout_add(&chain->to, 1); 23595ca02815Sjsg dma_fence_put(f); 23605ca02815Sjsg } 23615ca02815Sjsg 2362ad8b1aafSjsg static bool 2363ad8b1aafSjsg dma_fence_chain_enable_signaling(struct dma_fence *fence) 2364ad8b1aafSjsg { 23655ca02815Sjsg struct dma_fence_chain *chain, *h; 23665ca02815Sjsg struct dma_fence *f; 23675ca02815Sjsg 23685ca02815Sjsg h = to_dma_fence_chain(fence); 23695ca02815Sjsg dma_fence_get(&h->base); 23705ca02815Sjsg dma_fence_chain_for_each(fence, &h->base) { 23715ca02815Sjsg chain = to_dma_fence_chain(fence); 23725ca02815Sjsg if (chain == NULL) 23735ca02815Sjsg f = fence; 23745ca02815Sjsg else 23755ca02815Sjsg f = chain->fence; 23765ca02815Sjsg 23775ca02815Sjsg dma_fence_get(f); 23785ca02815Sjsg if (!dma_fence_add_callback(f, &h->cb, dma_fence_chain_cb)) { 23795ca02815Sjsg dma_fence_put(fence); 23805ca02815Sjsg return true; 23815ca02815Sjsg } 23825ca02815Sjsg dma_fence_put(f); 23835ca02815Sjsg } 23845ca02815Sjsg dma_fence_put(&h->base); 2385ad8b1aafSjsg return false; 2386ad8b1aafSjsg } 2387ad8b1aafSjsg 2388ad8b1aafSjsg static bool 2389ad8b1aafSjsg dma_fence_chain_signaled(struct dma_fence *fence) 2390ad8b1aafSjsg { 23915ca02815Sjsg struct dma_fence_chain *chain; 23925ca02815Sjsg struct dma_fence *f; 23935ca02815Sjsg 23945ca02815Sjsg dma_fence_chain_for_each(fence, fence) { 23955ca02815Sjsg chain = to_dma_fence_chain(fence); 23965ca02815Sjsg if (chain == NULL) 23975ca02815Sjsg f = fence; 23985ca02815Sjsg else 23995ca02815Sjsg f = chain->fence; 24005ca02815Sjsg 24015ca02815Sjsg if (dma_fence_is_signaled(f) == false) { 24025ca02815Sjsg dma_fence_put(fence); 2403ad8b1aafSjsg return false; 2404ad8b1aafSjsg } 24055ca02815Sjsg } 24065ca02815Sjsg return true; 24075ca02815Sjsg } 2408ad8b1aafSjsg 2409ad8b1aafSjsg static void 2410ad8b1aafSjsg dma_fence_chain_release(struct dma_fence *fence) 2411ad8b1aafSjsg { 24125ca02815Sjsg struct dma_fence_chain *chain = to_dma_fence_chain(fence); 24135ca02815Sjsg struct dma_fence_chain *prev_chain; 24145ca02815Sjsg struct dma_fence *prev; 24155ca02815Sjsg 24165ca02815Sjsg for (prev = chain->prev; prev != NULL; prev = chain->prev) { 24175ca02815Sjsg if (kref_read(&prev->refcount) > 1) 24185ca02815Sjsg break; 24195ca02815Sjsg if ((prev_chain = to_dma_fence_chain(prev)) == NULL) 24205ca02815Sjsg break; 24215ca02815Sjsg chain->prev = prev_chain->prev; 24225ca02815Sjsg prev_chain->prev = NULL; 24235ca02815Sjsg dma_fence_put(prev); 24245ca02815Sjsg } 24255ca02815Sjsg dma_fence_put(prev); 24265ca02815Sjsg dma_fence_put(chain->fence); 24275ca02815Sjsg dma_fence_free(fence); 2428ad8b1aafSjsg } 2429ad8b1aafSjsg 2430ad8b1aafSjsg struct dma_fence * 24315ca02815Sjsg dma_fence_chain_walk(struct dma_fence *fence) 2432ad8b1aafSjsg { 24335ca02815Sjsg struct dma_fence_chain *chain = to_dma_fence_chain(fence), *prev_chain; 24345ca02815Sjsg struct dma_fence *prev, *new_prev, *tmp; 2435ad8b1aafSjsg 2436ad8b1aafSjsg if (chain == NULL) { 2437ad8b1aafSjsg dma_fence_put(fence); 2438ad8b1aafSjsg return NULL; 2439ad8b1aafSjsg } 2440ad8b1aafSjsg 24415ca02815Sjsg while ((prev = dma_fence_get(chain->prev)) != NULL) { 24425ca02815Sjsg prev_chain = to_dma_fence_chain(prev); 24435ca02815Sjsg if (prev_chain != NULL) { 24445ca02815Sjsg if (!dma_fence_is_signaled(prev_chain->fence)) 24455ca02815Sjsg break; 24465ca02815Sjsg new_prev = dma_fence_get(prev_chain->prev); 24475ca02815Sjsg } else { 24485ca02815Sjsg if (!dma_fence_is_signaled(prev)) 24495ca02815Sjsg break; 24505ca02815Sjsg new_prev = NULL; 24515ca02815Sjsg } 24525ca02815Sjsg tmp = atomic_cas_ptr(&chain->prev, prev, new_prev); 24535ca02815Sjsg dma_fence_put(tmp == prev ? prev : new_prev); 24545ca02815Sjsg dma_fence_put(prev); 24555ca02815Sjsg } 24565ca02815Sjsg 2457ad8b1aafSjsg dma_fence_put(fence); 24585ca02815Sjsg return prev; 2459ad8b1aafSjsg } 2460ad8b1aafSjsg 2461ad8b1aafSjsg const struct dma_fence_ops dma_fence_chain_ops = { 2462ad8b1aafSjsg .get_driver_name = dma_fence_chain_get_driver_name, 2463ad8b1aafSjsg .get_timeline_name = dma_fence_chain_get_timeline_name, 2464ad8b1aafSjsg .enable_signaling = dma_fence_chain_enable_signaling, 2465ad8b1aafSjsg .signaled = dma_fence_chain_signaled, 2466ad8b1aafSjsg .release = dma_fence_chain_release, 2467bcd4d0b5Sjsg .use_64bit_seqno = true, 2468ad8b1aafSjsg }; 2469ad8b1aafSjsg 24701bb76ff1Sjsg bool 24711bb76ff1Sjsg dma_fence_is_container(struct dma_fence *fence) 24721bb76ff1Sjsg { 24731bb76ff1Sjsg return (fence->ops == &dma_fence_chain_ops) || 24741bb76ff1Sjsg (fence->ops == &dma_fence_array_ops); 24751bb76ff1Sjsg } 24761bb76ff1Sjsg 2477ad8b1aafSjsg int 24782bd648c0Smpi dmabuf_read(struct file *fp, struct uio *uio, int fflags) 2479a9ee023bSkettenis { 2480a9ee023bSkettenis return (ENXIO); 2481a9ee023bSkettenis } 2482a9ee023bSkettenis 2483a9ee023bSkettenis int 24842bd648c0Smpi dmabuf_write(struct file *fp, struct uio *uio, int fflags) 2485a9ee023bSkettenis { 2486a9ee023bSkettenis return (ENXIO); 2487a9ee023bSkettenis } 2488a9ee023bSkettenis 2489a9ee023bSkettenis int 2490a9ee023bSkettenis dmabuf_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) 2491a9ee023bSkettenis { 2492a9ee023bSkettenis return (ENOTTY); 2493a9ee023bSkettenis } 2494a9ee023bSkettenis 2495a9ee023bSkettenis int 2496a9ee023bSkettenis dmabuf_kqfilter(struct file *fp, struct knote *kn) 2497a9ee023bSkettenis { 2498a9ee023bSkettenis return (EINVAL); 2499a9ee023bSkettenis } 2500a9ee023bSkettenis 2501a9ee023bSkettenis int 2502a9ee023bSkettenis dmabuf_stat(struct file *fp, struct stat *st, struct proc *p) 2503a9ee023bSkettenis { 2504a9ee023bSkettenis struct dma_buf *dmabuf = fp->f_data; 2505a9ee023bSkettenis 2506a9ee023bSkettenis memset(st, 0, sizeof(*st)); 2507a9ee023bSkettenis st->st_size = dmabuf->size; 2508a9ee023bSkettenis st->st_mode = S_IFIFO; /* XXX */ 2509a9ee023bSkettenis return (0); 2510a9ee023bSkettenis } 2511a9ee023bSkettenis 2512a9ee023bSkettenis int 2513a9ee023bSkettenis dmabuf_close(struct file *fp, struct proc *p) 2514a9ee023bSkettenis { 2515a9ee023bSkettenis struct dma_buf *dmabuf = fp->f_data; 2516a9ee023bSkettenis 2517a9ee023bSkettenis fp->f_data = NULL; 2518fcba5756Svisa KERNEL_LOCK(); 2519a9ee023bSkettenis dmabuf->ops->release(dmabuf); 2520fcba5756Svisa KERNEL_UNLOCK(); 2521a9ee023bSkettenis free(dmabuf, M_DRM, sizeof(struct dma_buf)); 2522a9ee023bSkettenis return (0); 2523a9ee023bSkettenis } 2524a9ee023bSkettenis 2525f3455eb0Skettenis int 2526f3455eb0Skettenis dmabuf_seek(struct file *fp, off_t *offset, int whence, struct proc *p) 2527f3455eb0Skettenis { 2528f3455eb0Skettenis struct dma_buf *dmabuf = fp->f_data; 2529f3455eb0Skettenis off_t newoff; 2530f3455eb0Skettenis 2531f3455eb0Skettenis if (*offset != 0) 2532f3455eb0Skettenis return (EINVAL); 2533f3455eb0Skettenis 2534f3455eb0Skettenis switch (whence) { 2535f3455eb0Skettenis case SEEK_SET: 2536f3455eb0Skettenis newoff = 0; 2537f3455eb0Skettenis break; 2538f3455eb0Skettenis case SEEK_END: 2539f3455eb0Skettenis newoff = dmabuf->size; 2540f3455eb0Skettenis break; 2541f3455eb0Skettenis default: 2542f3455eb0Skettenis return (EINVAL); 2543f3455eb0Skettenis } 2544836f297bSanton mtx_enter(&fp->f_mtx); 2545836f297bSanton fp->f_offset = newoff; 2546836f297bSanton mtx_leave(&fp->f_mtx); 2547836f297bSanton *offset = newoff; 2548f3455eb0Skettenis return (0); 2549f3455eb0Skettenis } 2550f3455eb0Skettenis 2551c02bfb27Svisa const struct fileops dmabufops = { 2552a9ee023bSkettenis .fo_read = dmabuf_read, 2553a9ee023bSkettenis .fo_write = dmabuf_write, 2554a9ee023bSkettenis .fo_ioctl = dmabuf_ioctl, 2555a9ee023bSkettenis .fo_kqfilter = dmabuf_kqfilter, 2556a9ee023bSkettenis .fo_stat = dmabuf_stat, 2557f3455eb0Skettenis .fo_close = dmabuf_close, 2558f3455eb0Skettenis .fo_seek = dmabuf_seek, 2559a9ee023bSkettenis }; 2560a9ee023bSkettenis 2561a9ee023bSkettenis struct dma_buf * 2562a9ee023bSkettenis dma_buf_export(const struct dma_buf_export_info *info) 2563a9ee023bSkettenis { 2564a9ee023bSkettenis struct proc *p = curproc; 2565a9ee023bSkettenis struct dma_buf *dmabuf; 2566a9ee023bSkettenis struct file *fp; 2567a9ee023bSkettenis 2568d90ebdd6Skettenis fp = fnew(p); 2569d90ebdd6Skettenis if (fp == NULL) 2570d90ebdd6Skettenis return ERR_PTR(-ENFILE); 2571a9ee023bSkettenis fp->f_type = DTYPE_DMABUF; 2572a9ee023bSkettenis fp->f_ops = &dmabufops; 2573a9ee023bSkettenis dmabuf = malloc(sizeof(struct dma_buf), M_DRM, M_WAITOK | M_ZERO); 2574a9ee023bSkettenis dmabuf->priv = info->priv; 2575a9ee023bSkettenis dmabuf->ops = info->ops; 2576a9ee023bSkettenis dmabuf->size = info->size; 2577a9ee023bSkettenis dmabuf->file = fp; 2578a9ee023bSkettenis fp->f_data = dmabuf; 2579c349dbc7Sjsg INIT_LIST_HEAD(&dmabuf->attachments); 2580a9ee023bSkettenis return dmabuf; 2581a9ee023bSkettenis } 2582a9ee023bSkettenis 2583a9ee023bSkettenis struct dma_buf * 2584a9ee023bSkettenis dma_buf_get(int fd) 2585a9ee023bSkettenis { 2586a9ee023bSkettenis struct proc *p = curproc; 2587a9ee023bSkettenis struct filedesc *fdp = p->p_fd; 2588a9ee023bSkettenis struct file *fp; 2589a9ee023bSkettenis 2590a9ee023bSkettenis if ((fp = fd_getfile(fdp, fd)) == NULL) 2591a9ee023bSkettenis return ERR_PTR(-EBADF); 2592a9ee023bSkettenis 2593a9ee023bSkettenis if (fp->f_type != DTYPE_DMABUF) { 2594a9ee023bSkettenis FRELE(fp, p); 2595a9ee023bSkettenis return ERR_PTR(-EINVAL); 2596a9ee023bSkettenis } 2597a9ee023bSkettenis 2598a9ee023bSkettenis return fp->f_data; 2599a9ee023bSkettenis } 2600a9ee023bSkettenis 2601a9ee023bSkettenis void 2602a9ee023bSkettenis dma_buf_put(struct dma_buf *dmabuf) 2603a9ee023bSkettenis { 2604a9ee023bSkettenis KASSERT(dmabuf); 2605a9ee023bSkettenis KASSERT(dmabuf->file); 2606a9ee023bSkettenis 2607a9ee023bSkettenis FRELE(dmabuf->file, curproc); 2608a9ee023bSkettenis } 2609a9ee023bSkettenis 2610a9ee023bSkettenis int 2611a9ee023bSkettenis dma_buf_fd(struct dma_buf *dmabuf, int flags) 2612a9ee023bSkettenis { 2613a9ee023bSkettenis struct proc *p = curproc; 2614a9ee023bSkettenis struct filedesc *fdp = p->p_fd; 2615a9ee023bSkettenis struct file *fp = dmabuf->file; 2616a9ee023bSkettenis int fd, cloexec, error; 2617a9ee023bSkettenis 2618a9ee023bSkettenis cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0; 2619a9ee023bSkettenis 2620a9ee023bSkettenis fdplock(fdp); 2621a9ee023bSkettenis restart: 2622a9ee023bSkettenis if ((error = fdalloc(p, 0, &fd)) != 0) { 2623a9ee023bSkettenis if (error == ENOSPC) { 2624a9ee023bSkettenis fdexpand(p); 2625a9ee023bSkettenis goto restart; 2626a9ee023bSkettenis } 2627a9ee023bSkettenis fdpunlock(fdp); 2628a9ee023bSkettenis return -error; 2629a9ee023bSkettenis } 2630a9ee023bSkettenis 2631a9ee023bSkettenis fdinsert(fdp, fd, cloexec, fp); 2632a9ee023bSkettenis fdpunlock(fdp); 2633a9ee023bSkettenis 2634a9ee023bSkettenis return fd; 2635a9ee023bSkettenis } 2636a9ee023bSkettenis 2637a9ee023bSkettenis void 2638a9ee023bSkettenis get_dma_buf(struct dma_buf *dmabuf) 2639a9ee023bSkettenis { 2640a9ee023bSkettenis FREF(dmabuf->file); 2641a9ee023bSkettenis } 26427f4dd379Sjsg 26437f4dd379Sjsg enum pci_bus_speed 26447f4dd379Sjsg pcie_get_speed_cap(struct pci_dev *pdev) 26457f4dd379Sjsg { 2646b699e857Skettenis pci_chipset_tag_t pc; 2647b699e857Skettenis pcitag_t tag; 26487f4dd379Sjsg int pos ; 26497f4dd379Sjsg pcireg_t xcap, lnkcap = 0, lnkcap2 = 0; 26507f4dd379Sjsg pcireg_t id; 26517f4dd379Sjsg enum pci_bus_speed cap = PCI_SPEED_UNKNOWN; 26527f4dd379Sjsg int bus, device, function; 26537f4dd379Sjsg 2654b699e857Skettenis if (pdev == NULL) 2655b699e857Skettenis return PCI_SPEED_UNKNOWN; 2656b699e857Skettenis 2657b699e857Skettenis pc = pdev->pc; 2658b699e857Skettenis tag = pdev->tag; 2659b699e857Skettenis 26607f4dd379Sjsg if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, 26617f4dd379Sjsg &pos, NULL)) 26627f4dd379Sjsg return PCI_SPEED_UNKNOWN; 26637f4dd379Sjsg 26647f4dd379Sjsg id = pci_conf_read(pc, tag, PCI_ID_REG); 26657f4dd379Sjsg pci_decompose_tag(pc, tag, &bus, &device, &function); 26667f4dd379Sjsg 26677f4dd379Sjsg /* we've been informed via and serverworks don't make the cut */ 26687f4dd379Sjsg if (PCI_VENDOR(id) == PCI_VENDOR_VIATECH || 26697f4dd379Sjsg PCI_VENDOR(id) == PCI_VENDOR_RCC) 26707f4dd379Sjsg return PCI_SPEED_UNKNOWN; 26717f4dd379Sjsg 26727f4dd379Sjsg lnkcap = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP); 26737f4dd379Sjsg xcap = pci_conf_read(pc, tag, pos + PCI_PCIE_XCAP); 26747f4dd379Sjsg if (PCI_PCIE_XCAP_VER(xcap) >= 2) 26757f4dd379Sjsg lnkcap2 = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP2); 26767f4dd379Sjsg 26777f4dd379Sjsg lnkcap &= 0x0f; 26787f4dd379Sjsg lnkcap2 &= 0xfe; 26797f4dd379Sjsg 26807f4dd379Sjsg if (lnkcap2) { /* PCIE GEN 3.0 */ 26817f4dd379Sjsg if (lnkcap2 & 0x02) 26827f4dd379Sjsg cap = PCIE_SPEED_2_5GT; 26837f4dd379Sjsg if (lnkcap2 & 0x04) 26847f4dd379Sjsg cap = PCIE_SPEED_5_0GT; 26857f4dd379Sjsg if (lnkcap2 & 0x08) 26867f4dd379Sjsg cap = PCIE_SPEED_8_0GT; 26877f4dd379Sjsg if (lnkcap2 & 0x10) 26887f4dd379Sjsg cap = PCIE_SPEED_16_0GT; 26895ca02815Sjsg if (lnkcap2 & 0x20) 26905ca02815Sjsg cap = PCIE_SPEED_32_0GT; 26915ca02815Sjsg if (lnkcap2 & 0x40) 26925ca02815Sjsg cap = PCIE_SPEED_64_0GT; 26937f4dd379Sjsg } else { 26947f4dd379Sjsg if (lnkcap & 0x01) 26957f4dd379Sjsg cap = PCIE_SPEED_2_5GT; 26967f4dd379Sjsg if (lnkcap & 0x02) 26977f4dd379Sjsg cap = PCIE_SPEED_5_0GT; 26987f4dd379Sjsg } 26997f4dd379Sjsg 27007f4dd379Sjsg DRM_INFO("probing pcie caps for device %d:%d:%d 0x%04x:0x%04x = %x/%x\n", 27017f4dd379Sjsg bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), lnkcap, 27027f4dd379Sjsg lnkcap2); 27037f4dd379Sjsg return cap; 27047f4dd379Sjsg } 27057f4dd379Sjsg 27067f4dd379Sjsg enum pcie_link_width 27077f4dd379Sjsg pcie_get_width_cap(struct pci_dev *pdev) 27087f4dd379Sjsg { 27097f4dd379Sjsg pci_chipset_tag_t pc = pdev->pc; 27107f4dd379Sjsg pcitag_t tag = pdev->tag; 27117f4dd379Sjsg int pos ; 27127f4dd379Sjsg pcireg_t lnkcap = 0; 27137f4dd379Sjsg pcireg_t id; 27147f4dd379Sjsg int bus, device, function; 27157f4dd379Sjsg 27167f4dd379Sjsg if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, 27177f4dd379Sjsg &pos, NULL)) 27187f4dd379Sjsg return PCIE_LNK_WIDTH_UNKNOWN; 27197f4dd379Sjsg 27207f4dd379Sjsg id = pci_conf_read(pc, tag, PCI_ID_REG); 27217f4dd379Sjsg pci_decompose_tag(pc, tag, &bus, &device, &function); 27227f4dd379Sjsg 27237f4dd379Sjsg lnkcap = pci_conf_read(pc, tag, pos + PCI_PCIE_LCAP); 27247f4dd379Sjsg 27257f4dd379Sjsg DRM_INFO("probing pcie width for device %d:%d:%d 0x%04x:0x%04x = %x\n", 27267f4dd379Sjsg bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), lnkcap); 27277f4dd379Sjsg 27287f4dd379Sjsg if (lnkcap) 27297f4dd379Sjsg return (lnkcap & 0x3f0) >> 4; 27307f4dd379Sjsg return PCIE_LNK_WIDTH_UNKNOWN; 27317f4dd379Sjsg } 27327f4dd379Sjsg 27335276e8c8Sjsg bool 27345276e8c8Sjsg pcie_aspm_enabled(struct pci_dev *pdev) 27355276e8c8Sjsg { 27365276e8c8Sjsg pci_chipset_tag_t pc = pdev->pc; 27375276e8c8Sjsg pcitag_t tag = pdev->tag; 27385276e8c8Sjsg int pos ; 27395276e8c8Sjsg pcireg_t lcsr; 27405276e8c8Sjsg 27415276e8c8Sjsg if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, 27425276e8c8Sjsg &pos, NULL)) 27435276e8c8Sjsg return false; 27445276e8c8Sjsg 27455276e8c8Sjsg lcsr = pci_conf_read(pc, tag, pos + PCI_PCIE_LCSR); 27465276e8c8Sjsg if ((lcsr & (PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1)) != 0) 27475276e8c8Sjsg return true; 27485276e8c8Sjsg 27495276e8c8Sjsg return false; 27505276e8c8Sjsg } 27515276e8c8Sjsg 2752c349dbc7Sjsg static wait_queue_head_t bit_waitq; 2753c349dbc7Sjsg wait_queue_head_t var_waitq; 27547f4dd379Sjsg struct mutex wait_bit_mtx = MUTEX_INITIALIZER(IPL_TTY); 27557f4dd379Sjsg 27567f4dd379Sjsg int 27577f4dd379Sjsg wait_on_bit(unsigned long *word, int bit, unsigned mode) 27587f4dd379Sjsg { 27597f4dd379Sjsg int err; 27607f4dd379Sjsg 27617f4dd379Sjsg if (!test_bit(bit, word)) 27627f4dd379Sjsg return 0; 27637f4dd379Sjsg 27647f4dd379Sjsg mtx_enter(&wait_bit_mtx); 27657f4dd379Sjsg while (test_bit(bit, word)) { 2766d18c2ae1Smpi err = msleep_nsec(word, &wait_bit_mtx, PWAIT | mode, "wtb", 2767d18c2ae1Smpi INFSLP); 27687f4dd379Sjsg if (err) { 27697f4dd379Sjsg mtx_leave(&wait_bit_mtx); 27707f4dd379Sjsg return 1; 27717f4dd379Sjsg } 27727f4dd379Sjsg } 27737f4dd379Sjsg mtx_leave(&wait_bit_mtx); 27747f4dd379Sjsg return 0; 27757f4dd379Sjsg } 27767f4dd379Sjsg 27777f4dd379Sjsg int 27787f4dd379Sjsg wait_on_bit_timeout(unsigned long *word, int bit, unsigned mode, int timo) 27797f4dd379Sjsg { 27807f4dd379Sjsg int err; 27817f4dd379Sjsg 27827f4dd379Sjsg if (!test_bit(bit, word)) 27837f4dd379Sjsg return 0; 27847f4dd379Sjsg 27857f4dd379Sjsg mtx_enter(&wait_bit_mtx); 27867f4dd379Sjsg while (test_bit(bit, word)) { 27877f4dd379Sjsg err = msleep(word, &wait_bit_mtx, PWAIT | mode, "wtb", timo); 27887f4dd379Sjsg if (err) { 27897f4dd379Sjsg mtx_leave(&wait_bit_mtx); 27907f4dd379Sjsg return 1; 27917f4dd379Sjsg } 27927f4dd379Sjsg } 27937f4dd379Sjsg mtx_leave(&wait_bit_mtx); 27947f4dd379Sjsg return 0; 27957f4dd379Sjsg } 27967f4dd379Sjsg 27977f4dd379Sjsg void 27987f4dd379Sjsg wake_up_bit(void *word, int bit) 27997f4dd379Sjsg { 28007f4dd379Sjsg mtx_enter(&wait_bit_mtx); 28017f4dd379Sjsg wakeup(word); 28027f4dd379Sjsg mtx_leave(&wait_bit_mtx); 28037f4dd379Sjsg } 28047f4dd379Sjsg 2805c349dbc7Sjsg void 2806c349dbc7Sjsg clear_and_wake_up_bit(int bit, void *word) 2807c349dbc7Sjsg { 2808c349dbc7Sjsg clear_bit(bit, word); 2809c349dbc7Sjsg wake_up_bit(word, bit); 2810c349dbc7Sjsg } 2811c349dbc7Sjsg 2812c349dbc7Sjsg wait_queue_head_t * 2813c349dbc7Sjsg bit_waitqueue(void *word, int bit) 2814c349dbc7Sjsg { 2815c349dbc7Sjsg /* XXX hash table of wait queues? */ 2816c349dbc7Sjsg return &bit_waitq; 2817c349dbc7Sjsg } 2818c349dbc7Sjsg 2819ad8b1aafSjsg wait_queue_head_t * 2820ad8b1aafSjsg __var_waitqueue(void *p) 2821ad8b1aafSjsg { 2822ad8b1aafSjsg /* XXX hash table of wait queues? */ 2823ad8b1aafSjsg return &bit_waitq; 2824ad8b1aafSjsg } 2825ad8b1aafSjsg 28267f4dd379Sjsg struct workqueue_struct *system_wq; 2827c349dbc7Sjsg struct workqueue_struct *system_highpri_wq; 28287f4dd379Sjsg struct workqueue_struct *system_unbound_wq; 28297f4dd379Sjsg struct workqueue_struct *system_long_wq; 28307f4dd379Sjsg struct taskq *taskletq; 28317f4dd379Sjsg 28327f4dd379Sjsg void 28337f4dd379Sjsg drm_linux_init(void) 28347f4dd379Sjsg { 28357f4dd379Sjsg system_wq = (struct workqueue_struct *) 2836ae8374b9Skettenis taskq_create("drmwq", 4, IPL_HIGH, 0); 2837c349dbc7Sjsg system_highpri_wq = (struct workqueue_struct *) 2838c349dbc7Sjsg taskq_create("drmhpwq", 4, IPL_HIGH, 0); 28397f4dd379Sjsg system_unbound_wq = (struct workqueue_struct *) 2840ae8374b9Skettenis taskq_create("drmubwq", 4, IPL_HIGH, 0); 28417f4dd379Sjsg system_long_wq = (struct workqueue_struct *) 2842ae8374b9Skettenis taskq_create("drmlwq", 4, IPL_HIGH, 0); 28437f4dd379Sjsg 28447f4dd379Sjsg taskletq = taskq_create("drmtskl", 1, IPL_HIGH, 0); 2845c349dbc7Sjsg 2846c349dbc7Sjsg init_waitqueue_head(&bit_waitq); 2847c349dbc7Sjsg init_waitqueue_head(&var_waitq); 2848601770a2Skettenis 2849601770a2Skettenis pool_init(&idr_pool, sizeof(struct idr_entry), 0, IPL_TTY, 0, 2850601770a2Skettenis "idrpl", NULL); 285171c1aa0fSjsg pool_init(&xa_pool, sizeof(struct xarray_entry), 0, IPL_NONE, 0, 285271c1aa0fSjsg "xapl", NULL); 285349a189d2Skettenis 285449a189d2Skettenis kmap_atomic_va = 285549a189d2Skettenis (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_waitok); 2856a903e442Skettenis 2857a903e442Skettenis #if NACPI > 0 2858a903e442Skettenis if (acpi_softc) { 2859a903e442Skettenis memcpy(&acpi_gbl_FADT, acpi_softc->sc_fadt, 2860a903e442Skettenis sizeof(acpi_gbl_FADT)); 2861a903e442Skettenis } 2862a903e442Skettenis #endif 2863601770a2Skettenis } 2864601770a2Skettenis 2865601770a2Skettenis void 2866601770a2Skettenis drm_linux_exit(void) 2867601770a2Skettenis { 286871c1aa0fSjsg pool_destroy(&xa_pool); 2869601770a2Skettenis pool_destroy(&idr_pool); 2870601770a2Skettenis 2871601770a2Skettenis taskq_destroy(taskletq); 2872601770a2Skettenis 2873601770a2Skettenis taskq_destroy((struct taskq *)system_long_wq); 2874601770a2Skettenis taskq_destroy((struct taskq *)system_unbound_wq); 2875601770a2Skettenis taskq_destroy((struct taskq *)system_highpri_wq); 2876601770a2Skettenis taskq_destroy((struct taskq *)system_wq); 28777f4dd379Sjsg } 28787f4dd379Sjsg 28797f4dd379Sjsg #define PCIE_ECAP_RESIZE_BAR 0x15 28807f4dd379Sjsg #define RBCAP0 0x04 28817f4dd379Sjsg #define RBCTRL0 0x08 28827f4dd379Sjsg #define RBCTRL_BARINDEX_MASK 0x07 28837f4dd379Sjsg #define RBCTRL_BARSIZE_MASK 0x1f00 28847f4dd379Sjsg #define RBCTRL_BARSIZE_SHIFT 8 28857f4dd379Sjsg 28867f4dd379Sjsg /* size in MB is 1 << nsize */ 28877f4dd379Sjsg int 28887f4dd379Sjsg pci_resize_resource(struct pci_dev *pdev, int bar, int nsize) 28897f4dd379Sjsg { 28907f4dd379Sjsg pcireg_t reg; 28917f4dd379Sjsg uint32_t offset, capid; 28927f4dd379Sjsg 28937f4dd379Sjsg KASSERT(bar == 0); 28947f4dd379Sjsg 28957f4dd379Sjsg offset = PCI_PCIE_ECAP; 28967f4dd379Sjsg 28977f4dd379Sjsg /* search PCI Express Extended Capabilities */ 28987f4dd379Sjsg do { 28997f4dd379Sjsg reg = pci_conf_read(pdev->pc, pdev->tag, offset); 29007f4dd379Sjsg capid = PCI_PCIE_ECAP_ID(reg); 29017f4dd379Sjsg if (capid == PCIE_ECAP_RESIZE_BAR) 29027f4dd379Sjsg break; 29037f4dd379Sjsg offset = PCI_PCIE_ECAP_NEXT(reg); 29047f4dd379Sjsg } while (capid != 0); 29057f4dd379Sjsg 29067f4dd379Sjsg if (capid == 0) { 29077f4dd379Sjsg printf("%s: could not find resize bar cap!\n", __func__); 29087f4dd379Sjsg return -ENOTSUP; 29097f4dd379Sjsg } 29107f4dd379Sjsg 29117f4dd379Sjsg reg = pci_conf_read(pdev->pc, pdev->tag, offset + RBCAP0); 29127f4dd379Sjsg 29137f4dd379Sjsg if ((reg & (1 << (nsize + 4))) == 0) { 29147f4dd379Sjsg printf("%s size not supported\n", __func__); 29157f4dd379Sjsg return -ENOTSUP; 29167f4dd379Sjsg } 29177f4dd379Sjsg 29187f4dd379Sjsg reg = pci_conf_read(pdev->pc, pdev->tag, offset + RBCTRL0); 29197f4dd379Sjsg if ((reg & RBCTRL_BARINDEX_MASK) != 0) { 29207f4dd379Sjsg printf("%s BAR index not 0\n", __func__); 29217f4dd379Sjsg return -EINVAL; 29227f4dd379Sjsg } 29237f4dd379Sjsg 29247f4dd379Sjsg reg &= ~RBCTRL_BARSIZE_MASK; 29257f4dd379Sjsg reg |= (nsize << RBCTRL_BARSIZE_SHIFT) & RBCTRL_BARSIZE_MASK; 29267f4dd379Sjsg 29277f4dd379Sjsg pci_conf_write(pdev->pc, pdev->tag, offset + RBCTRL0, reg); 29287f4dd379Sjsg 29297f4dd379Sjsg return 0; 29307f4dd379Sjsg } 2931a4e118acSkettenis 2932a4e118acSkettenis TAILQ_HEAD(, shrinker) shrinkers = TAILQ_HEAD_INITIALIZER(shrinkers); 2933a4e118acSkettenis 2934a4e118acSkettenis int 29351bb76ff1Sjsg register_shrinker(struct shrinker *shrinker, const char *format, ...) 2936a4e118acSkettenis { 2937a4e118acSkettenis TAILQ_INSERT_TAIL(&shrinkers, shrinker, next); 2938a4e118acSkettenis return 0; 2939a4e118acSkettenis } 2940a4e118acSkettenis 2941a4e118acSkettenis void 29423990936dSjsg unregister_shrinker(struct shrinker *shrinker) 29433990936dSjsg { 29443990936dSjsg TAILQ_REMOVE(&shrinkers, shrinker, next); 29453990936dSjsg } 29463990936dSjsg 2947789ce988Smpi unsigned long 2948a4e118acSkettenis drmbackoff(long npages) 2949a4e118acSkettenis { 2950a4e118acSkettenis struct shrink_control sc; 2951a4e118acSkettenis struct shrinker *shrinker; 2952789ce988Smpi u_long ret, freed = 0; 2953a4e118acSkettenis 2954a4e118acSkettenis shrinker = TAILQ_FIRST(&shrinkers); 2955a4e118acSkettenis while (shrinker && npages > 0) { 2956a4e118acSkettenis sc.nr_to_scan = npages; 2957a4e118acSkettenis ret = shrinker->scan_objects(shrinker, &sc); 2958789ce988Smpi if (ret == SHRINK_STOP) 2959789ce988Smpi break; 2960a4e118acSkettenis npages -= ret; 2961789ce988Smpi freed += ret; 2962a4e118acSkettenis shrinker = TAILQ_NEXT(shrinker, next); 2963a4e118acSkettenis } 2964789ce988Smpi 2965789ce988Smpi return freed; 2966a4e118acSkettenis } 2967c349dbc7Sjsg 2968c349dbc7Sjsg void * 2969c349dbc7Sjsg bitmap_zalloc(u_int n, gfp_t flags) 2970c349dbc7Sjsg { 2971c349dbc7Sjsg return kcalloc(BITS_TO_LONGS(n), sizeof(long), flags); 2972c349dbc7Sjsg } 2973c349dbc7Sjsg 2974c349dbc7Sjsg void 2975c349dbc7Sjsg bitmap_free(void *p) 2976c349dbc7Sjsg { 2977c349dbc7Sjsg kfree(p); 2978c349dbc7Sjsg } 2979c349dbc7Sjsg 2980c349dbc7Sjsg int 2981c349dbc7Sjsg atomic_dec_and_mutex_lock(volatile int *v, struct rwlock *lock) 2982c349dbc7Sjsg { 2983c349dbc7Sjsg if (atomic_add_unless(v, -1, 1)) 2984c349dbc7Sjsg return 0; 2985c349dbc7Sjsg 2986c349dbc7Sjsg rw_enter_write(lock); 2987c349dbc7Sjsg if (atomic_dec_return(v) == 0) 2988c349dbc7Sjsg return 1; 2989c349dbc7Sjsg rw_exit_write(lock); 2990c349dbc7Sjsg return 0; 2991c349dbc7Sjsg } 2992c349dbc7Sjsg 2993c349dbc7Sjsg int 2994c349dbc7Sjsg printk(const char *fmt, ...) 2995c349dbc7Sjsg { 2996c349dbc7Sjsg int ret, level; 2997c349dbc7Sjsg va_list ap; 2998c349dbc7Sjsg 2999c349dbc7Sjsg if (fmt != NULL && *fmt == '\001') { 3000c349dbc7Sjsg level = fmt[1]; 3001c349dbc7Sjsg #ifndef DRMDEBUG 3002c349dbc7Sjsg if (level >= KERN_INFO[1] && level <= '9') 3003c349dbc7Sjsg return 0; 3004c349dbc7Sjsg #endif 3005c349dbc7Sjsg fmt += 2; 3006c349dbc7Sjsg } 3007c349dbc7Sjsg 3008c349dbc7Sjsg va_start(ap, fmt); 3009c349dbc7Sjsg ret = vprintf(fmt, ap); 3010c349dbc7Sjsg va_end(ap); 3011c349dbc7Sjsg 3012c349dbc7Sjsg return ret; 3013c349dbc7Sjsg } 3014cfaa6efeSjsg 3015cfaa6efeSjsg #define START(node) ((node)->start) 3016cfaa6efeSjsg #define LAST(node) ((node)->last) 3017cfaa6efeSjsg 3018cfaa6efeSjsg struct interval_tree_node * 3019cfaa6efeSjsg interval_tree_iter_first(struct rb_root_cached *root, unsigned long start, 3020cfaa6efeSjsg unsigned long last) 3021cfaa6efeSjsg { 3022cfaa6efeSjsg struct interval_tree_node *node; 3023cfaa6efeSjsg struct rb_node *rb; 3024cfaa6efeSjsg 3025cfaa6efeSjsg for (rb = rb_first_cached(root); rb; rb = rb_next(rb)) { 3026cfaa6efeSjsg node = rb_entry(rb, typeof(*node), rb); 3027cfaa6efeSjsg if (LAST(node) >= start && START(node) <= last) 3028cfaa6efeSjsg return node; 3029cfaa6efeSjsg } 3030cfaa6efeSjsg return NULL; 3031cfaa6efeSjsg } 3032cfaa6efeSjsg 3033cfaa6efeSjsg void 3034cfaa6efeSjsg interval_tree_remove(struct interval_tree_node *node, 3035cfaa6efeSjsg struct rb_root_cached *root) 3036cfaa6efeSjsg { 3037cfaa6efeSjsg rb_erase_cached(&node->rb, root); 3038cfaa6efeSjsg } 3039cfaa6efeSjsg 3040cfaa6efeSjsg void 3041cfaa6efeSjsg interval_tree_insert(struct interval_tree_node *node, 3042cfaa6efeSjsg struct rb_root_cached *root) 3043cfaa6efeSjsg { 3044cfaa6efeSjsg struct rb_node **iter = &root->rb_root.rb_node; 3045cfaa6efeSjsg struct rb_node *parent = NULL; 3046cfaa6efeSjsg struct interval_tree_node *iter_node; 3047cfaa6efeSjsg 3048cfaa6efeSjsg while (*iter) { 3049cfaa6efeSjsg parent = *iter; 3050cfaa6efeSjsg iter_node = rb_entry(*iter, struct interval_tree_node, rb); 3051cfaa6efeSjsg 3052cfaa6efeSjsg if (node->start < iter_node->start) 3053cfaa6efeSjsg iter = &(*iter)->rb_left; 3054cfaa6efeSjsg else 3055cfaa6efeSjsg iter = &(*iter)->rb_right; 3056cfaa6efeSjsg } 3057cfaa6efeSjsg 3058cfaa6efeSjsg rb_link_node(&node->rb, parent, iter); 3059cfaa6efeSjsg rb_insert_color_cached(&node->rb, root, false); 3060cfaa6efeSjsg } 306161c1bba6Sjsg 306261c1bba6Sjsg int 306361c1bba6Sjsg syncfile_read(struct file *fp, struct uio *uio, int fflags) 306461c1bba6Sjsg { 306561c1bba6Sjsg return ENXIO; 306661c1bba6Sjsg } 306761c1bba6Sjsg 306861c1bba6Sjsg int 306961c1bba6Sjsg syncfile_write(struct file *fp, struct uio *uio, int fflags) 307061c1bba6Sjsg { 307161c1bba6Sjsg return ENXIO; 307261c1bba6Sjsg } 307361c1bba6Sjsg 307461c1bba6Sjsg int 307561c1bba6Sjsg syncfile_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p) 307661c1bba6Sjsg { 307761c1bba6Sjsg return ENOTTY; 307861c1bba6Sjsg } 307961c1bba6Sjsg 308061c1bba6Sjsg int 308161c1bba6Sjsg syncfile_kqfilter(struct file *fp, struct knote *kn) 308261c1bba6Sjsg { 308361c1bba6Sjsg return EINVAL; 308461c1bba6Sjsg } 308561c1bba6Sjsg 308661c1bba6Sjsg int 308761c1bba6Sjsg syncfile_stat(struct file *fp, struct stat *st, struct proc *p) 308861c1bba6Sjsg { 308961c1bba6Sjsg memset(st, 0, sizeof(*st)); 309061c1bba6Sjsg st->st_mode = S_IFIFO; /* XXX */ 309161c1bba6Sjsg return 0; 309261c1bba6Sjsg } 309361c1bba6Sjsg 309461c1bba6Sjsg int 309561c1bba6Sjsg syncfile_close(struct file *fp, struct proc *p) 309661c1bba6Sjsg { 309761c1bba6Sjsg struct sync_file *sf = fp->f_data; 309861c1bba6Sjsg 309961c1bba6Sjsg dma_fence_put(sf->fence); 310061c1bba6Sjsg fp->f_data = NULL; 310161c1bba6Sjsg free(sf, M_DRM, sizeof(struct sync_file)); 310261c1bba6Sjsg return 0; 310361c1bba6Sjsg } 310461c1bba6Sjsg 310561c1bba6Sjsg int 310661c1bba6Sjsg syncfile_seek(struct file *fp, off_t *offset, int whence, struct proc *p) 310761c1bba6Sjsg { 310861c1bba6Sjsg off_t newoff; 310961c1bba6Sjsg 311061c1bba6Sjsg if (*offset != 0) 311161c1bba6Sjsg return EINVAL; 311261c1bba6Sjsg 311361c1bba6Sjsg switch (whence) { 311461c1bba6Sjsg case SEEK_SET: 311561c1bba6Sjsg newoff = 0; 311661c1bba6Sjsg break; 311761c1bba6Sjsg case SEEK_END: 311861c1bba6Sjsg newoff = 0; 311961c1bba6Sjsg break; 312061c1bba6Sjsg default: 312161c1bba6Sjsg return EINVAL; 312261c1bba6Sjsg } 312361c1bba6Sjsg mtx_enter(&fp->f_mtx); 312461c1bba6Sjsg fp->f_offset = newoff; 312561c1bba6Sjsg mtx_leave(&fp->f_mtx); 312661c1bba6Sjsg *offset = newoff; 312761c1bba6Sjsg return 0; 312861c1bba6Sjsg } 312961c1bba6Sjsg 313061c1bba6Sjsg const struct fileops syncfileops = { 313161c1bba6Sjsg .fo_read = syncfile_read, 313261c1bba6Sjsg .fo_write = syncfile_write, 313361c1bba6Sjsg .fo_ioctl = syncfile_ioctl, 313461c1bba6Sjsg .fo_kqfilter = syncfile_kqfilter, 313561c1bba6Sjsg .fo_stat = syncfile_stat, 313661c1bba6Sjsg .fo_close = syncfile_close, 313761c1bba6Sjsg .fo_seek = syncfile_seek, 313861c1bba6Sjsg }; 313961c1bba6Sjsg 314061c1bba6Sjsg void 314161c1bba6Sjsg fd_install(int fd, struct file *fp) 314261c1bba6Sjsg { 314361c1bba6Sjsg struct proc *p = curproc; 314461c1bba6Sjsg struct filedesc *fdp = p->p_fd; 314561c1bba6Sjsg 314661c1bba6Sjsg if (fp->f_type != DTYPE_SYNC) 314761c1bba6Sjsg return; 314861c1bba6Sjsg 314961c1bba6Sjsg fdplock(fdp); 315061c1bba6Sjsg /* all callers use get_unused_fd_flags(O_CLOEXEC) */ 315161c1bba6Sjsg fdinsert(fdp, fd, UF_EXCLOSE, fp); 315261c1bba6Sjsg fdpunlock(fdp); 315361c1bba6Sjsg } 315461c1bba6Sjsg 315561c1bba6Sjsg void 315661c1bba6Sjsg fput(struct file *fp) 315761c1bba6Sjsg { 315861c1bba6Sjsg if (fp->f_type != DTYPE_SYNC) 315961c1bba6Sjsg return; 316061c1bba6Sjsg 316161c1bba6Sjsg FRELE(fp, curproc); 316261c1bba6Sjsg } 316361c1bba6Sjsg 316461c1bba6Sjsg int 316561c1bba6Sjsg get_unused_fd_flags(unsigned int flags) 316661c1bba6Sjsg { 316761c1bba6Sjsg struct proc *p = curproc; 316861c1bba6Sjsg struct filedesc *fdp = p->p_fd; 316961c1bba6Sjsg int error, fd; 317061c1bba6Sjsg 317161c1bba6Sjsg KASSERT((flags & O_CLOEXEC) != 0); 317261c1bba6Sjsg 317361c1bba6Sjsg fdplock(fdp); 317461c1bba6Sjsg retryalloc: 317561c1bba6Sjsg if ((error = fdalloc(p, 0, &fd)) != 0) { 317661c1bba6Sjsg if (error == ENOSPC) { 317761c1bba6Sjsg fdexpand(p); 317861c1bba6Sjsg goto retryalloc; 317961c1bba6Sjsg } 318061c1bba6Sjsg fdpunlock(fdp); 318161c1bba6Sjsg return -1; 318261c1bba6Sjsg } 318361c1bba6Sjsg fdpunlock(fdp); 318461c1bba6Sjsg 318561c1bba6Sjsg return fd; 318661c1bba6Sjsg } 318761c1bba6Sjsg 318861c1bba6Sjsg void 318961c1bba6Sjsg put_unused_fd(int fd) 319061c1bba6Sjsg { 319161c1bba6Sjsg struct filedesc *fdp = curproc->p_fd; 319261c1bba6Sjsg 319361c1bba6Sjsg fdplock(fdp); 319461c1bba6Sjsg fdremove(fdp, fd); 319561c1bba6Sjsg fdpunlock(fdp); 319661c1bba6Sjsg } 319761c1bba6Sjsg 319861c1bba6Sjsg struct dma_fence * 319961c1bba6Sjsg sync_file_get_fence(int fd) 320061c1bba6Sjsg { 320161c1bba6Sjsg struct proc *p = curproc; 320261c1bba6Sjsg struct filedesc *fdp = p->p_fd; 320361c1bba6Sjsg struct file *fp; 320461c1bba6Sjsg struct sync_file *sf; 320561c1bba6Sjsg struct dma_fence *f; 320661c1bba6Sjsg 320761c1bba6Sjsg if ((fp = fd_getfile(fdp, fd)) == NULL) 320861c1bba6Sjsg return NULL; 320961c1bba6Sjsg 321061c1bba6Sjsg if (fp->f_type != DTYPE_SYNC) { 321161c1bba6Sjsg FRELE(fp, p); 321261c1bba6Sjsg return NULL; 321361c1bba6Sjsg } 321461c1bba6Sjsg sf = fp->f_data; 321561c1bba6Sjsg f = dma_fence_get(sf->fence); 321661c1bba6Sjsg FRELE(sf->file, p); 321761c1bba6Sjsg return f; 321861c1bba6Sjsg } 321961c1bba6Sjsg 322061c1bba6Sjsg struct sync_file * 322161c1bba6Sjsg sync_file_create(struct dma_fence *fence) 322261c1bba6Sjsg { 322361c1bba6Sjsg struct proc *p = curproc; 322461c1bba6Sjsg struct sync_file *sf; 322561c1bba6Sjsg struct file *fp; 322661c1bba6Sjsg 322761c1bba6Sjsg fp = fnew(p); 322861c1bba6Sjsg if (fp == NULL) 322961c1bba6Sjsg return NULL; 323061c1bba6Sjsg fp->f_type = DTYPE_SYNC; 323161c1bba6Sjsg fp->f_ops = &syncfileops; 323261c1bba6Sjsg sf = malloc(sizeof(struct sync_file), M_DRM, M_WAITOK | M_ZERO); 323361c1bba6Sjsg sf->file = fp; 323461c1bba6Sjsg sf->fence = dma_fence_get(fence); 323561c1bba6Sjsg fp->f_data = sf; 323661c1bba6Sjsg return sf; 323761c1bba6Sjsg } 32381bb76ff1Sjsg 32391bb76ff1Sjsg bool 32401bb76ff1Sjsg drm_firmware_drivers_only(void) 32411bb76ff1Sjsg { 32421bb76ff1Sjsg return false; 32431bb76ff1Sjsg } 3244667382c7Skettenis 3245667382c7Skettenis 3246667382c7Skettenis void * 3247667382c7Skettenis memremap(phys_addr_t phys_addr, size_t size, int flags) 3248667382c7Skettenis { 3249667382c7Skettenis STUB(); 3250667382c7Skettenis return NULL; 3251667382c7Skettenis } 3252667382c7Skettenis 3253667382c7Skettenis void 3254667382c7Skettenis memunmap(void *addr) 3255667382c7Skettenis { 3256667382c7Skettenis STUB(); 3257667382c7Skettenis } 3258667382c7Skettenis 3259667382c7Skettenis #include <linux/platform_device.h> 3260667382c7Skettenis 3261667382c7Skettenis bus_dma_tag_t 3262667382c7Skettenis dma_tag_lookup(struct device *dev) 3263667382c7Skettenis { 3264667382c7Skettenis extern struct cfdriver drm_cd; 3265667382c7Skettenis struct drm_device *drm; 3266667382c7Skettenis int i; 3267667382c7Skettenis 3268667382c7Skettenis for (i = 0; i < drm_cd.cd_ndevs; i++) { 3269667382c7Skettenis drm = drm_cd.cd_devs[i]; 3270667382c7Skettenis if (drm && drm->dev == dev) 3271667382c7Skettenis return drm->dmat; 3272667382c7Skettenis } 3273667382c7Skettenis 3274667382c7Skettenis return ((struct platform_device *)dev)->dmat; 3275667382c7Skettenis } 3276667382c7Skettenis 3277667382c7Skettenis LIST_HEAD(, drm_dmamem) dmamem_list = LIST_HEAD_INITIALIZER(dmamem_list); 3278667382c7Skettenis 3279667382c7Skettenis void * 3280667382c7Skettenis dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, 3281667382c7Skettenis int gfp) 3282667382c7Skettenis { 3283667382c7Skettenis bus_dma_tag_t dmat = dma_tag_lookup(dev); 3284667382c7Skettenis struct drm_dmamem *mem; 3285667382c7Skettenis 3286667382c7Skettenis mem = drm_dmamem_alloc(dmat, size, PAGE_SIZE, 1, size, 3287667382c7Skettenis BUS_DMA_COHERENT, 0); 3288667382c7Skettenis if (mem == NULL) 3289667382c7Skettenis return NULL; 3290667382c7Skettenis *dma_handle = mem->map->dm_segs[0].ds_addr; 3291667382c7Skettenis LIST_INSERT_HEAD(&dmamem_list, mem, next); 3292667382c7Skettenis return mem->kva; 3293667382c7Skettenis } 3294667382c7Skettenis 3295667382c7Skettenis void 3296667382c7Skettenis dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, 3297667382c7Skettenis dma_addr_t dma_handle) 3298667382c7Skettenis { 3299667382c7Skettenis bus_dma_tag_t dmat = dma_tag_lookup(dev); 3300667382c7Skettenis struct drm_dmamem *mem; 3301667382c7Skettenis 3302667382c7Skettenis LIST_FOREACH(mem, &dmamem_list, next) { 3303667382c7Skettenis if (mem->kva == cpu_addr) 3304667382c7Skettenis break; 3305667382c7Skettenis } 3306667382c7Skettenis KASSERT(mem); 3307667382c7Skettenis KASSERT(mem->size == size); 3308667382c7Skettenis KASSERT(mem->map->dm_segs[0].ds_addr == dma_handle); 3309667382c7Skettenis 3310667382c7Skettenis LIST_REMOVE(mem, next); 3311667382c7Skettenis drm_dmamem_free(dmat, mem); 3312667382c7Skettenis } 3313667382c7Skettenis 3314667382c7Skettenis int 3315667382c7Skettenis dma_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr, 3316667382c7Skettenis dma_addr_t dma_addr, size_t size) 3317667382c7Skettenis { 3318667382c7Skettenis paddr_t pa; 3319667382c7Skettenis int ret; 3320667382c7Skettenis 3321667382c7Skettenis if (!pmap_extract(pmap_kernel(), (vaddr_t)cpu_addr, &pa)) 3322667382c7Skettenis return -EINVAL; 3323667382c7Skettenis 3324667382c7Skettenis ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 3325667382c7Skettenis if (ret) 3326667382c7Skettenis return ret; 3327667382c7Skettenis 3328667382c7Skettenis sg_set_page(sgt->sgl, PHYS_TO_VM_PAGE(pa), size, 0); 3329667382c7Skettenis return 0; 3330667382c7Skettenis } 3331667382c7Skettenis 3332667382c7Skettenis dma_addr_t 3333667382c7Skettenis dma_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size, 3334667382c7Skettenis enum dma_data_direction dir, u_long attr) 3335667382c7Skettenis { 3336667382c7Skettenis bus_dma_tag_t dmat= dma_tag_lookup(dev); 3337667382c7Skettenis bus_dmamap_t map; 3338667382c7Skettenis bus_dma_segment_t seg; 3339667382c7Skettenis 3340667382c7Skettenis if (bus_dmamap_create(dmat, size, 1, size, 0, 3341667382c7Skettenis BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &map)) 3342667382c7Skettenis return DMA_MAPPING_ERROR; 3343667382c7Skettenis seg.ds_addr = phys_addr; 3344667382c7Skettenis seg.ds_len = size; 3345667382c7Skettenis if (bus_dmamap_load_raw(dmat, map, &seg, 1, size, BUS_DMA_WAITOK)) { 3346667382c7Skettenis bus_dmamap_destroy(dmat, map); 3347667382c7Skettenis return DMA_MAPPING_ERROR; 3348667382c7Skettenis } 3349667382c7Skettenis 3350667382c7Skettenis return map->dm_segs[0].ds_addr; 3351667382c7Skettenis } 3352667382c7Skettenis 3353667382c7Skettenis #ifdef BUS_DMA_FIXED 3354667382c7Skettenis 3355667382c7Skettenis #include <linux/iommu.h> 3356667382c7Skettenis 3357667382c7Skettenis size_t 3358667382c7Skettenis iommu_map_sgtable(struct iommu_domain *domain, u_long iova, 3359667382c7Skettenis struct sg_table *sgt, int prot) 3360667382c7Skettenis { 3361667382c7Skettenis bus_dma_segment_t seg; 3362667382c7Skettenis int error; 3363667382c7Skettenis 3364667382c7Skettenis error = bus_dmamap_create(domain->dmat, sgt->sgl->length, 1, 3365667382c7Skettenis sgt->sgl->length, 0, BUS_DMA_WAITOK, &sgt->dmamap); 3366667382c7Skettenis if (error) 3367667382c7Skettenis return -ENOMEM; 3368667382c7Skettenis 3369667382c7Skettenis sgt->dmamap->dm_segs[0].ds_addr = iova; 3370667382c7Skettenis sgt->dmamap->dm_segs[0].ds_len = sgt->sgl->length; 3371667382c7Skettenis sgt->dmamap->dm_nsegs = 1; 3372667382c7Skettenis seg.ds_addr = VM_PAGE_TO_PHYS(sgt->sgl->__page); 3373667382c7Skettenis seg.ds_len = sgt->sgl->length; 3374667382c7Skettenis error = bus_dmamap_load_raw(domain->dmat, sgt->dmamap, &seg, 1, 3375667382c7Skettenis sgt->sgl->length, BUS_DMA_WAITOK | BUS_DMA_FIXED); 3376667382c7Skettenis if (error) 3377667382c7Skettenis return -ENOMEM; 3378667382c7Skettenis 3379667382c7Skettenis return sg_dma_len(sgt->sgl); 3380667382c7Skettenis } 3381667382c7Skettenis 3382667382c7Skettenis size_t 3383667382c7Skettenis iommu_unmap(struct iommu_domain *domain, u_long iova, size_t size) 3384667382c7Skettenis { 3385667382c7Skettenis STUB(); 3386667382c7Skettenis return 0; 3387667382c7Skettenis } 3388667382c7Skettenis 3389667382c7Skettenis struct iommu_domain * 3390667382c7Skettenis iommu_get_domain_for_dev(struct device *dev) 3391667382c7Skettenis { 3392667382c7Skettenis STUB(); 3393667382c7Skettenis return NULL; 3394667382c7Skettenis } 3395667382c7Skettenis 3396667382c7Skettenis phys_addr_t 3397667382c7Skettenis iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) 3398667382c7Skettenis { 3399667382c7Skettenis STUB(); 3400667382c7Skettenis return 0; 3401667382c7Skettenis } 3402667382c7Skettenis 3403667382c7Skettenis struct iommu_domain * 3404667382c7Skettenis iommu_domain_alloc(struct bus_type *type) 3405667382c7Skettenis { 3406667382c7Skettenis return malloc(sizeof(struct iommu_domain), M_DEVBUF, M_WAITOK | M_ZERO); 3407667382c7Skettenis } 3408667382c7Skettenis 3409667382c7Skettenis int 3410667382c7Skettenis iommu_attach_device(struct iommu_domain *domain, struct device *dev) 3411667382c7Skettenis { 3412667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3413667382c7Skettenis 3414667382c7Skettenis domain->dmat = pdev->dmat; 3415667382c7Skettenis return 0; 3416667382c7Skettenis } 3417667382c7Skettenis 3418667382c7Skettenis #endif 3419667382c7Skettenis 3420667382c7Skettenis #include <linux/component.h> 3421667382c7Skettenis 3422cefff6e5Skettenis struct component { 3423667382c7Skettenis struct device *dev; 3424cefff6e5Skettenis struct device *adev; 3425cefff6e5Skettenis const struct component_ops *ops; 3426cefff6e5Skettenis SLIST_ENTRY(component) next; 3427667382c7Skettenis }; 3428667382c7Skettenis 3429cefff6e5Skettenis SLIST_HEAD(,component) component_list = SLIST_HEAD_INITIALIZER(component_list); 3430cefff6e5Skettenis 3431667382c7Skettenis int 3432cefff6e5Skettenis component_add(struct device *dev, const struct component_ops *ops) 3433667382c7Skettenis { 3434cefff6e5Skettenis struct component *component; 3435cefff6e5Skettenis 3436cefff6e5Skettenis component = malloc(sizeof(*component), M_DEVBUF, M_WAITOK | M_ZERO); 3437cefff6e5Skettenis component->dev = dev; 3438cefff6e5Skettenis component->ops = ops; 3439cefff6e5Skettenis SLIST_INSERT_HEAD(&component_list, component, next); 3440667382c7Skettenis return 0; 3441667382c7Skettenis } 3442667382c7Skettenis 3443cefff6e5Skettenis int 3444f005ef32Sjsg component_add_typed(struct device *dev, const struct component_ops *ops, 3445f005ef32Sjsg int type) 3446f005ef32Sjsg { 3447f005ef32Sjsg return component_add(dev, ops); 3448f005ef32Sjsg } 3449f005ef32Sjsg 3450f005ef32Sjsg int 3451cefff6e5Skettenis component_bind_all(struct device *dev, void *data) 3452667382c7Skettenis { 3453cefff6e5Skettenis struct component *component; 3454cefff6e5Skettenis int ret = 0; 3455667382c7Skettenis 3456cefff6e5Skettenis SLIST_FOREACH(component, &component_list, next) { 3457cefff6e5Skettenis if (component->adev == dev) { 3458cefff6e5Skettenis ret = component->ops->bind(component->dev, NULL, data); 3459cefff6e5Skettenis if (ret) 3460cefff6e5Skettenis break; 3461667382c7Skettenis } 3462667382c7Skettenis } 3463667382c7Skettenis 3464cefff6e5Skettenis return ret; 3465cefff6e5Skettenis } 3466cefff6e5Skettenis 34675fde6622Skettenis struct component_match_entry { 3468cefff6e5Skettenis int (*compare)(struct device *, void *); 3469cefff6e5Skettenis void *data; 3470cefff6e5Skettenis }; 3471cefff6e5Skettenis 34725fde6622Skettenis struct component_match { 34735fde6622Skettenis struct component_match_entry match[4]; 34745fde6622Skettenis int nmatches; 34755fde6622Skettenis }; 34765fde6622Skettenis 3477667382c7Skettenis int 3478667382c7Skettenis component_master_add_with_match(struct device *dev, 3479667382c7Skettenis const struct component_master_ops *ops, struct component_match *match) 3480667382c7Skettenis { 3481cefff6e5Skettenis struct component *component; 3482cefff6e5Skettenis int found = 0; 34835fde6622Skettenis int i, ret; 3484cefff6e5Skettenis 3485cefff6e5Skettenis SLIST_FOREACH(component, &component_list, next) { 34865fde6622Skettenis for (i = 0; i < match->nmatches; i++) { 34875fde6622Skettenis struct component_match_entry *m = &match->match[i]; 34885fde6622Skettenis if (m->compare(component->dev, m->data)) { 3489cefff6e5Skettenis component->adev = dev; 3490cefff6e5Skettenis found = 1; 34915fde6622Skettenis break; 34925fde6622Skettenis } 3493cefff6e5Skettenis } 3494cefff6e5Skettenis } 3495cefff6e5Skettenis 3496cefff6e5Skettenis if (found) { 3497cefff6e5Skettenis ret = ops->bind(dev); 3498cefff6e5Skettenis if (ret) 3499cefff6e5Skettenis return ret; 3500cefff6e5Skettenis } 3501cefff6e5Skettenis 3502667382c7Skettenis return 0; 3503667382c7Skettenis } 3504667382c7Skettenis 3505667382c7Skettenis #ifdef __HAVE_FDT 3506667382c7Skettenis 3507667382c7Skettenis #include <linux/platform_device.h> 3508667382c7Skettenis #include <dev/ofw/openfirm.h> 3509667382c7Skettenis #include <dev/ofw/fdt.h> 3510667382c7Skettenis #include <machine/fdt.h> 3511667382c7Skettenis 3512667382c7Skettenis LIST_HEAD(, platform_device) pdev_list = LIST_HEAD_INITIALIZER(pdev_list); 3513667382c7Skettenis 3514667382c7Skettenis void 3515667382c7Skettenis platform_device_register(struct platform_device *pdev) 3516667382c7Skettenis { 3517cefff6e5Skettenis int i; 3518cefff6e5Skettenis 3519667382c7Skettenis pdev->num_resources = pdev->faa->fa_nreg; 3520cefff6e5Skettenis if (pdev->faa->fa_nreg > 0) { 3521cefff6e5Skettenis pdev->resource = mallocarray(pdev->faa->fa_nreg, 3522cefff6e5Skettenis sizeof(*pdev->resource), M_DEVBUF, M_WAITOK | M_ZERO); 3523cefff6e5Skettenis for (i = 0; i < pdev->faa->fa_nreg; i++) { 3524cefff6e5Skettenis pdev->resource[i].start = pdev->faa->fa_reg[i].addr; 3525cefff6e5Skettenis pdev->resource[i].end = pdev->faa->fa_reg[i].addr + 3526cefff6e5Skettenis pdev->faa->fa_reg[i].size - 1; 3527cefff6e5Skettenis } 3528cefff6e5Skettenis } 3529667382c7Skettenis 3530667382c7Skettenis pdev->parent = pdev->dev.dv_parent; 3531667382c7Skettenis pdev->node = pdev->faa->fa_node; 3532cefff6e5Skettenis pdev->iot = pdev->faa->fa_iot; 3533667382c7Skettenis pdev->dmat = pdev->faa->fa_dmat; 3534667382c7Skettenis LIST_INSERT_HEAD(&pdev_list, pdev, next); 3535667382c7Skettenis } 3536667382c7Skettenis 3537667382c7Skettenis 3538667382c7Skettenis struct resource * 3539667382c7Skettenis platform_get_resource(struct platform_device *pdev, u_int type, u_int num) 3540667382c7Skettenis { 3541cefff6e5Skettenis KASSERT(num < pdev->num_resources); 3542667382c7Skettenis return &pdev->resource[num]; 3543667382c7Skettenis } 3544667382c7Skettenis 3545667382c7Skettenis void __iomem * 3546667382c7Skettenis devm_platform_ioremap_resource_byname(struct platform_device *pdev, 3547667382c7Skettenis const char *name) 3548667382c7Skettenis { 3549667382c7Skettenis bus_space_handle_t ioh; 3550667382c7Skettenis int err, idx; 3551667382c7Skettenis 3552cefff6e5Skettenis idx = OF_getindex(pdev->node, name, "reg-names"); 3553cefff6e5Skettenis if (idx == -1 || idx >= pdev->num_resources) 3554667382c7Skettenis return ERR_PTR(-EINVAL); 3555667382c7Skettenis 3556cefff6e5Skettenis err = bus_space_map(pdev->iot, pdev->resource[idx].start, 3557cefff6e5Skettenis pdev->resource[idx].end - pdev->resource[idx].start + 1, 3558cefff6e5Skettenis BUS_SPACE_MAP_LINEAR, &ioh); 3559667382c7Skettenis if (err) 3560667382c7Skettenis return ERR_PTR(-err); 3561667382c7Skettenis 3562cefff6e5Skettenis return bus_space_vaddr(pdev->iot, ioh); 3563667382c7Skettenis } 3564667382c7Skettenis 3565667382c7Skettenis #include <dev/ofw/ofw_clock.h> 3566667382c7Skettenis #include <linux/clk.h> 3567667382c7Skettenis 3568667382c7Skettenis struct clk * 3569667382c7Skettenis devm_clk_get(struct device *dev, const char *name) 3570667382c7Skettenis { 3571667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3572667382c7Skettenis struct clk *clk; 3573667382c7Skettenis 3574667382c7Skettenis clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK); 3575667382c7Skettenis clk->freq = clock_get_frequency(pdev->node, name); 3576667382c7Skettenis return clk; 3577667382c7Skettenis } 3578667382c7Skettenis 3579667382c7Skettenis u_long 3580667382c7Skettenis clk_get_rate(struct clk *clk) 3581667382c7Skettenis { 3582667382c7Skettenis return clk->freq; 3583667382c7Skettenis } 3584667382c7Skettenis 3585667382c7Skettenis #include <linux/gpio/consumer.h> 3586667382c7Skettenis #include <dev/ofw/ofw_gpio.h> 3587667382c7Skettenis 3588667382c7Skettenis struct gpio_desc { 3589667382c7Skettenis uint32_t gpios[4]; 3590667382c7Skettenis }; 3591667382c7Skettenis 3592667382c7Skettenis struct gpio_desc * 3593667382c7Skettenis devm_gpiod_get_optional(struct device *dev, const char *name, int flags) 3594667382c7Skettenis { 3595667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3596667382c7Skettenis struct gpio_desc *desc; 3597667382c7Skettenis char fullname[128]; 3598667382c7Skettenis int len; 3599667382c7Skettenis 3600667382c7Skettenis snprintf(fullname, sizeof(fullname), "%s-gpios", name); 3601667382c7Skettenis 3602667382c7Skettenis desc = malloc(sizeof(*desc), M_DEVBUF, M_WAITOK | M_ZERO); 3603667382c7Skettenis len = OF_getpropintarray(pdev->node, fullname, desc->gpios, 3604667382c7Skettenis sizeof(desc->gpios)); 3605667382c7Skettenis KASSERT(len <= sizeof(desc->gpios)); 3606667382c7Skettenis if (len < 0) { 3607667382c7Skettenis free(desc, M_DEVBUF, sizeof(*desc)); 3608667382c7Skettenis return NULL; 3609667382c7Skettenis } 3610667382c7Skettenis 3611667382c7Skettenis switch (flags) { 3612667382c7Skettenis case GPIOD_IN: 3613667382c7Skettenis gpio_controller_config_pin(desc->gpios, GPIO_CONFIG_INPUT); 3614667382c7Skettenis break; 3615667382c7Skettenis case GPIOD_OUT_HIGH: 3616667382c7Skettenis gpio_controller_config_pin(desc->gpios, GPIO_CONFIG_OUTPUT); 3617667382c7Skettenis gpio_controller_set_pin(desc->gpios, 1); 3618667382c7Skettenis break; 3619667382c7Skettenis default: 3620667382c7Skettenis panic("%s: unimplemented flags 0x%x", __func__, flags); 3621667382c7Skettenis } 3622667382c7Skettenis 3623667382c7Skettenis return desc; 3624667382c7Skettenis } 3625667382c7Skettenis 3626667382c7Skettenis int 3627667382c7Skettenis gpiod_get_value_cansleep(const struct gpio_desc *desc) 3628667382c7Skettenis { 3629667382c7Skettenis return gpio_controller_get_pin(((struct gpio_desc *)desc)->gpios); 3630667382c7Skettenis } 3631667382c7Skettenis 3632667382c7Skettenis struct phy { 3633667382c7Skettenis int node; 3634667382c7Skettenis const char *name; 3635667382c7Skettenis }; 3636667382c7Skettenis 3637667382c7Skettenis struct phy * 3638667382c7Skettenis devm_phy_optional_get(struct device *dev, const char *name) 3639667382c7Skettenis { 3640667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3641667382c7Skettenis struct phy *phy; 3642667382c7Skettenis int idx; 3643667382c7Skettenis 3644667382c7Skettenis idx = OF_getindex(pdev->node, name, "phy-names"); 3645667382c7Skettenis if (idx == -1) 3646667382c7Skettenis return NULL; 3647667382c7Skettenis 3648667382c7Skettenis phy = malloc(sizeof(*phy), M_DEVBUF, M_WAITOK); 3649667382c7Skettenis phy->node = pdev->node; 3650667382c7Skettenis phy->name = name; 3651667382c7Skettenis 3652667382c7Skettenis return phy; 3653667382c7Skettenis } 3654667382c7Skettenis 3655667382c7Skettenis struct bus_type platform_bus_type; 3656667382c7Skettenis 3657667382c7Skettenis #include <dev/ofw/ofw_misc.h> 3658667382c7Skettenis 3659667382c7Skettenis #include <linux/of.h> 3660667382c7Skettenis #include <linux/platform_device.h> 3661667382c7Skettenis 3662667382c7Skettenis struct device_node * 3663667382c7Skettenis __of_devnode(void *arg) 3664667382c7Skettenis { 3665667382c7Skettenis struct device *dev = container_of(arg, struct device, of_node); 3666667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3667667382c7Skettenis 3668667382c7Skettenis return (struct device_node *)(uintptr_t)pdev->node; 3669667382c7Skettenis } 3670667382c7Skettenis 3671667382c7Skettenis int 3672667382c7Skettenis __of_device_is_compatible(struct device_node *np, const char *compatible) 3673667382c7Skettenis { 3674667382c7Skettenis return OF_is_compatible((uintptr_t)np, compatible); 3675667382c7Skettenis } 3676667382c7Skettenis 3677667382c7Skettenis int 3678667382c7Skettenis __of_property_present(struct device_node *np, const char *propname) 3679667382c7Skettenis { 3680667382c7Skettenis return OF_getpropbool((uintptr_t)np, (char *)propname); 3681667382c7Skettenis } 3682667382c7Skettenis 3683667382c7Skettenis int 3684667382c7Skettenis __of_property_read_variable_u32_array(struct device_node *np, 3685667382c7Skettenis const char *propname, uint32_t *out_values, size_t sz_min, size_t sz_max) 3686667382c7Skettenis { 3687667382c7Skettenis int len; 3688667382c7Skettenis 3689667382c7Skettenis len = OF_getpropintarray((uintptr_t)np, (char *)propname, out_values, 3690667382c7Skettenis sz_max * sizeof(*out_values)); 3691667382c7Skettenis if (len < 0) 3692667382c7Skettenis return -EINVAL; 3693667382c7Skettenis if (len == 0) 3694667382c7Skettenis return -ENODATA; 3695667382c7Skettenis if (len < sz_min * sizeof(*out_values) || 3696667382c7Skettenis len > sz_max * sizeof(*out_values)) 3697667382c7Skettenis return -EOVERFLOW; 3698667382c7Skettenis if (sz_min == 1 && sz_max == 1) 3699667382c7Skettenis return 0; 3700667382c7Skettenis return len / sizeof(*out_values); 3701667382c7Skettenis } 3702667382c7Skettenis 3703667382c7Skettenis int 3704667382c7Skettenis __of_property_read_variable_u64_array(struct device_node *np, 3705667382c7Skettenis const char *propname, uint64_t *out_values, size_t sz_min, size_t sz_max) 3706667382c7Skettenis { 3707667382c7Skettenis int len; 3708667382c7Skettenis 3709667382c7Skettenis len = OF_getpropint64array((uintptr_t)np, (char *)propname, out_values, 3710667382c7Skettenis sz_max * sizeof(*out_values)); 3711667382c7Skettenis if (len < 0) 3712667382c7Skettenis return -EINVAL; 3713667382c7Skettenis if (len == 0) 3714667382c7Skettenis return -ENODATA; 3715667382c7Skettenis if (len < sz_min * sizeof(*out_values) || 3716667382c7Skettenis len > sz_max * sizeof(*out_values)) 3717667382c7Skettenis return -EOVERFLOW; 3718667382c7Skettenis if (sz_min == 1 && sz_max == 1) 3719667382c7Skettenis return 0; 3720667382c7Skettenis return len / sizeof(*out_values); 3721667382c7Skettenis } 3722667382c7Skettenis 3723667382c7Skettenis int 3724667382c7Skettenis __of_property_match_string(struct device_node *np, 3725667382c7Skettenis const char *propname, const char *str) 3726667382c7Skettenis { 3727667382c7Skettenis int idx; 3728667382c7Skettenis 3729667382c7Skettenis idx = OF_getindex((uintptr_t)np, str, propname); 3730667382c7Skettenis if (idx == -1) 3731667382c7Skettenis return -ENODATA; 3732667382c7Skettenis return idx; 3733667382c7Skettenis } 3734667382c7Skettenis 3735667382c7Skettenis struct device_node * 3736667382c7Skettenis __of_parse_phandle(struct device_node *np, const char *propname, int idx) 3737667382c7Skettenis { 3738667382c7Skettenis uint32_t phandles[16] = {}; 3739667382c7Skettenis int len, node; 3740667382c7Skettenis 3741667382c7Skettenis len = OF_getpropintarray((uintptr_t)np, (char *)propname, phandles, 3742667382c7Skettenis sizeof(phandles)); 3743667382c7Skettenis if (len < (idx + 1) * sizeof(uint32_t)) 3744667382c7Skettenis return NULL; 3745667382c7Skettenis 3746667382c7Skettenis node = OF_getnodebyphandle(phandles[idx]); 3747667382c7Skettenis if (node == 0) 3748667382c7Skettenis return NULL; 3749667382c7Skettenis 3750667382c7Skettenis return (struct device_node *)(uintptr_t)node; 3751667382c7Skettenis } 3752667382c7Skettenis 3753667382c7Skettenis int 3754667382c7Skettenis __of_parse_phandle_with_args(struct device_node *np, const char *propname, 3755667382c7Skettenis const char *cellsname, int idx, struct of_phandle_args *args) 3756667382c7Skettenis { 3757667382c7Skettenis uint32_t phandles[16] = {}; 3758667382c7Skettenis int i, len, node; 3759667382c7Skettenis 3760667382c7Skettenis len = OF_getpropintarray((uintptr_t)np, (char *)propname, phandles, 3761667382c7Skettenis sizeof(phandles)); 3762667382c7Skettenis if (len < (idx + 1) * sizeof(uint32_t)) 3763667382c7Skettenis return -ENOENT; 3764667382c7Skettenis 3765667382c7Skettenis node = OF_getnodebyphandle(phandles[idx]); 3766667382c7Skettenis if (node == 0) 3767667382c7Skettenis return -ENOENT; 3768667382c7Skettenis 3769667382c7Skettenis args->np = (struct device_node *)(uintptr_t)node; 3770667382c7Skettenis args->args_count = OF_getpropint(node, (char *)cellsname, 0); 3771667382c7Skettenis for (i = 0; i < args->args_count; i++) 3772667382c7Skettenis args->args[i] = phandles[i + 1]; 3773667382c7Skettenis 3774667382c7Skettenis return 0; 3775667382c7Skettenis } 3776667382c7Skettenis 3777667382c7Skettenis int 3778667382c7Skettenis of_address_to_resource(struct device_node *np, int idx, struct resource *res) 3779667382c7Skettenis { 3780667382c7Skettenis uint64_t reg[16] = {}; 3781667382c7Skettenis int len; 3782667382c7Skettenis 3783667382c7Skettenis KASSERT(idx < 8); 3784667382c7Skettenis 3785667382c7Skettenis len = OF_getpropint64array((uintptr_t)np, "reg", reg, sizeof(reg)); 3786667382c7Skettenis if (len < 0 || idx >= (len / (2 * sizeof(uint64_t)))) 3787667382c7Skettenis return -EINVAL; 3788667382c7Skettenis 3789667382c7Skettenis res->start = reg[2 * idx]; 3790667382c7Skettenis res->end = reg[2 * idx] + reg[2 * idx + 1] - 1; 3791667382c7Skettenis 3792667382c7Skettenis return 0; 3793667382c7Skettenis } 3794667382c7Skettenis 3795667382c7Skettenis static int 3796667382c7Skettenis next_node(int node) 3797667382c7Skettenis { 3798667382c7Skettenis int peer = OF_peer(node); 3799667382c7Skettenis 3800667382c7Skettenis while (node && !peer) { 3801667382c7Skettenis node = OF_parent(node); 3802667382c7Skettenis if (node) 3803667382c7Skettenis peer = OF_peer(node); 3804667382c7Skettenis } 3805667382c7Skettenis 3806667382c7Skettenis return peer; 3807667382c7Skettenis } 3808667382c7Skettenis 3809667382c7Skettenis static int 3810667382c7Skettenis find_matching_node(int node, const struct of_device_id *id) 3811667382c7Skettenis { 3812667382c7Skettenis int child, match; 3813667382c7Skettenis int i; 3814667382c7Skettenis 3815667382c7Skettenis for (child = OF_child(node); child; child = OF_peer(child)) { 3816667382c7Skettenis match = find_matching_node(child, id); 3817667382c7Skettenis if (match) 3818667382c7Skettenis return match; 3819667382c7Skettenis } 3820667382c7Skettenis 3821667382c7Skettenis for (i = 0; id[i].compatible; i++) { 3822667382c7Skettenis if (OF_is_compatible(node, id[i].compatible)) 3823667382c7Skettenis return node; 3824667382c7Skettenis } 3825667382c7Skettenis 3826667382c7Skettenis return 0; 3827667382c7Skettenis } 3828667382c7Skettenis 3829667382c7Skettenis struct device_node * 3830667382c7Skettenis __matching_node(struct device_node *np, const struct of_device_id *id) 3831667382c7Skettenis { 3832667382c7Skettenis int node = OF_peer(0); 3833667382c7Skettenis int match; 3834667382c7Skettenis 3835667382c7Skettenis if (np) 3836667382c7Skettenis node = next_node((uintptr_t)np); 3837667382c7Skettenis while (node) { 3838667382c7Skettenis match = find_matching_node(node, id); 3839667382c7Skettenis if (match) 3840667382c7Skettenis return (struct device_node *)(uintptr_t)match; 3841667382c7Skettenis node = next_node(node); 3842667382c7Skettenis } 3843667382c7Skettenis 3844667382c7Skettenis return NULL; 3845667382c7Skettenis } 3846667382c7Skettenis 3847667382c7Skettenis struct platform_device * 3848667382c7Skettenis of_platform_device_create(struct device_node *np, const char *bus_id, 3849667382c7Skettenis struct device *parent) 3850667382c7Skettenis { 3851667382c7Skettenis struct platform_device *pdev; 3852667382c7Skettenis 3853667382c7Skettenis pdev = malloc(sizeof(*pdev), M_DEVBUF, M_WAITOK | M_ZERO); 3854667382c7Skettenis pdev->node = (intptr_t)np; 3855667382c7Skettenis pdev->parent = parent; 3856667382c7Skettenis 3857667382c7Skettenis LIST_INSERT_HEAD(&pdev_list, pdev, next); 3858667382c7Skettenis 3859667382c7Skettenis return pdev; 3860667382c7Skettenis } 3861667382c7Skettenis 3862667382c7Skettenis struct platform_device * 3863667382c7Skettenis of_find_device_by_node(struct device_node *np) 3864667382c7Skettenis { 3865667382c7Skettenis struct platform_device *pdev; 3866667382c7Skettenis 3867667382c7Skettenis LIST_FOREACH(pdev, &pdev_list, next) { 3868667382c7Skettenis if (pdev->node == (intptr_t)np) 3869667382c7Skettenis return pdev; 3870667382c7Skettenis } 3871667382c7Skettenis 3872667382c7Skettenis return NULL; 3873667382c7Skettenis } 3874667382c7Skettenis 3875667382c7Skettenis int 3876667382c7Skettenis of_device_is_available(struct device_node *np) 3877667382c7Skettenis { 3878667382c7Skettenis char status[32]; 3879667382c7Skettenis 3880667382c7Skettenis if (OF_getprop((uintptr_t)np, "status", status, sizeof(status)) > 0 && 3881667382c7Skettenis strcmp(status, "disabled") == 0) 3882667382c7Skettenis return 0; 3883667382c7Skettenis 3884667382c7Skettenis return 1; 3885667382c7Skettenis } 3886667382c7Skettenis 3887667382c7Skettenis int 3888667382c7Skettenis of_dma_configure(struct device *dev, struct device_node *np, int force_dma) 3889667382c7Skettenis { 3890667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3891667382c7Skettenis bus_dma_tag_t dmat = dma_tag_lookup(pdev->parent); 3892667382c7Skettenis 3893667382c7Skettenis pdev->dmat = iommu_device_map(pdev->node, dmat); 3894667382c7Skettenis return 0; 3895667382c7Skettenis } 3896667382c7Skettenis 3897667382c7Skettenis struct device_node * 3898667382c7Skettenis __of_get_compatible_child(void *p, const char *compat) 3899667382c7Skettenis { 3900667382c7Skettenis struct device *dev = container_of(p, struct device, of_node); 3901667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3902667382c7Skettenis int child; 3903667382c7Skettenis 3904667382c7Skettenis for (child = OF_child(pdev->node); child; child = OF_peer(child)) { 3905667382c7Skettenis if (OF_is_compatible(child, compat)) 3906667382c7Skettenis return (struct device_node *)(uintptr_t)child; 3907667382c7Skettenis } 3908667382c7Skettenis return NULL; 3909667382c7Skettenis } 3910667382c7Skettenis 3911667382c7Skettenis struct device_node * 3912667382c7Skettenis __of_get_child_by_name(void *p, const char *name) 3913667382c7Skettenis { 3914667382c7Skettenis struct device *dev = container_of(p, struct device, of_node); 3915667382c7Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3916667382c7Skettenis int child; 3917667382c7Skettenis 3918667382c7Skettenis child = OF_getnodebyname(pdev->node, name); 3919667382c7Skettenis if (child == 0) 3920667382c7Skettenis return NULL; 3921667382c7Skettenis return (struct device_node *)(uintptr_t)child; 3922667382c7Skettenis } 3923667382c7Skettenis 3924cefff6e5Skettenis int 3925cefff6e5Skettenis component_compare_of(struct device *dev, void *data) 3926cefff6e5Skettenis { 3927cefff6e5Skettenis struct platform_device *pdev = (struct platform_device *)dev; 3928cefff6e5Skettenis 3929cefff6e5Skettenis return (pdev->node == (intptr_t)data); 3930cefff6e5Skettenis } 3931cefff6e5Skettenis 3932cefff6e5Skettenis void 3933cefff6e5Skettenis drm_of_component_match_add(struct device *master, 3934cefff6e5Skettenis struct component_match **matchptr, 3935cefff6e5Skettenis int (*compare)(struct device *, void *), 3936cefff6e5Skettenis struct device_node *np) 3937cefff6e5Skettenis { 39385fde6622Skettenis struct component_match *match = *matchptr; 3939cefff6e5Skettenis 39405fde6622Skettenis if (match == NULL) { 3941cefff6e5Skettenis match = malloc(sizeof(struct component_match), 3942cefff6e5Skettenis M_DEVBUF, M_WAITOK | M_ZERO); 3943cefff6e5Skettenis *matchptr = match; 3944cefff6e5Skettenis } 39455fde6622Skettenis 39465fde6622Skettenis KASSERT(match->nmatches < nitems(match->match)); 39475fde6622Skettenis match->match[match->nmatches].compare = compare; 39485fde6622Skettenis match->match[match->nmatches].data = np; 39495fde6622Skettenis match->nmatches++; 3950cefff6e5Skettenis } 3951cefff6e5Skettenis 3952667382c7Skettenis #endif 3953