xref: /dflybsd-src/sys/dev/drm/linux_sched.c (revision 0e32b8c55fb2ed20206f2a71f5f7f8b3a2d1f40a)
1*0e32b8c5SMatthew Dillon /*
2*0e32b8c5SMatthew Dillon  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3*0e32b8c5SMatthew Dillon  *
4*0e32b8c5SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5*0e32b8c5SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6*0e32b8c5SMatthew Dillon  *
7*0e32b8c5SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8*0e32b8c5SMatthew Dillon  * modification, are permitted provided that the following conditions
9*0e32b8c5SMatthew Dillon  * are met:
10*0e32b8c5SMatthew Dillon  *
11*0e32b8c5SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12*0e32b8c5SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13*0e32b8c5SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14*0e32b8c5SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15*0e32b8c5SMatthew Dillon  *    the documentation and/or other materials provided with the
16*0e32b8c5SMatthew Dillon  *    distribution.
17*0e32b8c5SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18*0e32b8c5SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19*0e32b8c5SMatthew Dillon  *    from this software without specific, prior written permission.
20*0e32b8c5SMatthew Dillon  *
21*0e32b8c5SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*0e32b8c5SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*0e32b8c5SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*0e32b8c5SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*0e32b8c5SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*0e32b8c5SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*0e32b8c5SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*0e32b8c5SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*0e32b8c5SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*0e32b8c5SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*0e32b8c5SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*0e32b8c5SMatthew Dillon  * SUCH DAMAGE.
33*0e32b8c5SMatthew Dillon  */
34*0e32b8c5SMatthew Dillon #include <sys/cdefs.h>
35*0e32b8c5SMatthew Dillon 
36*0e32b8c5SMatthew Dillon #include <sys/condvar.h>
37*0e32b8c5SMatthew Dillon #include <sys/queue.h>
38*0e32b8c5SMatthew Dillon #include <sys/lock.h>
39*0e32b8c5SMatthew Dillon 
40*0e32b8c5SMatthew Dillon #include <linux/compiler.h>
41*0e32b8c5SMatthew Dillon 
42*0e32b8c5SMatthew Dillon #include <linux/atomic.h>
43*0e32b8c5SMatthew Dillon #include <linux/errno.h>
44*0e32b8c5SMatthew Dillon #include <linux/kref.h>
45*0e32b8c5SMatthew Dillon #include <linux/fence.h>
46*0e32b8c5SMatthew Dillon #include <linux/sched.h>
47*0e32b8c5SMatthew Dillon #include <linux/slab.h>
48*0e32b8c5SMatthew Dillon #include <linux/spinlock.h>
49*0e32b8c5SMatthew Dillon 
50*0e32b8c5SMatthew Dillon /*
51*0e32b8c5SMatthew Dillon  * Called when curthread->td_linux_task is NULL.  We must allocated, initialize,
52*0e32b8c5SMatthew Dillon  * and install a task_struct in td (the current thread).
53*0e32b8c5SMatthew Dillon  *
54*0e32b8c5SMatthew Dillon  * All threads belonging to the same process have a common mm_struct which
55*0e32b8c5SMatthew Dillon  * is stored as p->p_linux_mm.  This must be allocated, initialized, and
56*0e32b8c5SMatthew Dillon  * and installed if necessary.
57*0e32b8c5SMatthew Dillon  */
58*0e32b8c5SMatthew Dillon struct task_struct *
59*0e32b8c5SMatthew Dillon linux_task_alloc(struct thread *td)
60*0e32b8c5SMatthew Dillon {
61*0e32b8c5SMatthew Dillon 	struct task_struct *task;
62*0e32b8c5SMatthew Dillon 	struct mm_struct *mm;
63*0e32b8c5SMatthew Dillon 	struct proc *p;
64*0e32b8c5SMatthew Dillon 
65*0e32b8c5SMatthew Dillon 	task = kzalloc(sizeof(*task), GFP_KERNEL);
66*0e32b8c5SMatthew Dillon 	task->dfly_td = td;
67*0e32b8c5SMatthew Dillon 
68*0e32b8c5SMatthew Dillon 	if ((p = td->td_proc) != NULL) {
69*0e32b8c5SMatthew Dillon 		if ((mm = p->p_linux_mm) == NULL) {
70*0e32b8c5SMatthew Dillon 			mm = kzalloc(sizeof(*mm), GFP_KERNEL);
71*0e32b8c5SMatthew Dillon 			mm->refs = 1;
72*0e32b8c5SMatthew Dillon 			lockinit(&mm->mmap_sem, "drmmms", 0, LK_CANRECURSE);
73*0e32b8c5SMatthew Dillon 			lwkt_gettoken(&p->p_token);
74*0e32b8c5SMatthew Dillon 			if (p->p_linux_mm == NULL) {
75*0e32b8c5SMatthew Dillon 				p->p_linux_mm = mm;
76*0e32b8c5SMatthew Dillon 			} else {
77*0e32b8c5SMatthew Dillon 				linux_mm_drop(mm);
78*0e32b8c5SMatthew Dillon 				mm = p->p_linux_mm;
79*0e32b8c5SMatthew Dillon 			}
80*0e32b8c5SMatthew Dillon 			lwkt_reltoken(&p->p_token);
81*0e32b8c5SMatthew Dillon 		}
82*0e32b8c5SMatthew Dillon 		task->mm = mm;
83*0e32b8c5SMatthew Dillon 		atomic_add_long(&mm->refs, 1);
84*0e32b8c5SMatthew Dillon 	}
85*0e32b8c5SMatthew Dillon 	td->td_linux_task = task;
86*0e32b8c5SMatthew Dillon 
87*0e32b8c5SMatthew Dillon 	return task;
88*0e32b8c5SMatthew Dillon }
89*0e32b8c5SMatthew Dillon 
90*0e32b8c5SMatthew Dillon /*
91*0e32b8c5SMatthew Dillon  * Called at thread exit
92*0e32b8c5SMatthew Dillon  */
93*0e32b8c5SMatthew Dillon void
94*0e32b8c5SMatthew Dillon linux_task_drop(struct thread *td)
95*0e32b8c5SMatthew Dillon {
96*0e32b8c5SMatthew Dillon 	struct task_struct *task;
97*0e32b8c5SMatthew Dillon 	struct mm_struct *mm;
98*0e32b8c5SMatthew Dillon 
99*0e32b8c5SMatthew Dillon 	task = td->td_linux_task;
100*0e32b8c5SMatthew Dillon 	td->td_linux_task = NULL;
101*0e32b8c5SMatthew Dillon 	if ((mm = task->mm) != NULL) {
102*0e32b8c5SMatthew Dillon 		atomic_add_long(&mm->refs, -1);	/* proc ref always remains */
103*0e32b8c5SMatthew Dillon 		task->mm = NULL;
104*0e32b8c5SMatthew Dillon 	}
105*0e32b8c5SMatthew Dillon 	kprintf("FREE TASK %p\n", task);
106*0e32b8c5SMatthew Dillon 	kfree(task);
107*0e32b8c5SMatthew Dillon }
108*0e32b8c5SMatthew Dillon 
109*0e32b8c5SMatthew Dillon void
110*0e32b8c5SMatthew Dillon linux_proc_drop(struct proc *p)
111*0e32b8c5SMatthew Dillon {
112*0e32b8c5SMatthew Dillon 	struct mm_struct *mm;
113*0e32b8c5SMatthew Dillon 
114*0e32b8c5SMatthew Dillon 	if ((mm = p->p_linux_mm) != NULL) {
115*0e32b8c5SMatthew Dillon 		p->p_linux_mm = NULL;
116*0e32b8c5SMatthew Dillon 		linux_mm_drop(mm);
117*0e32b8c5SMatthew Dillon 	}
118*0e32b8c5SMatthew Dillon }
119*0e32b8c5SMatthew Dillon 
120*0e32b8c5SMatthew Dillon void
121*0e32b8c5SMatthew Dillon linux_mm_drop(struct mm_struct *mm)
122*0e32b8c5SMatthew Dillon {
123*0e32b8c5SMatthew Dillon 	long refs;
124*0e32b8c5SMatthew Dillon 
125*0e32b8c5SMatthew Dillon 	refs = atomic_fetchadd_long(&mm->refs, -1);
126*0e32b8c5SMatthew Dillon 	KKASSERT(refs > 0);
127*0e32b8c5SMatthew Dillon 	if (refs == 1) {
128*0e32b8c5SMatthew Dillon 		lockuninit(&mm->mmap_sem);
129*0e32b8c5SMatthew Dillon 		kfree(mm);
130*0e32b8c5SMatthew Dillon 		kprintf("FREE MM %p\n", mm);
131*0e32b8c5SMatthew Dillon 	}
132*0e32b8c5SMatthew Dillon }
133