Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/kernel/mips-mt-fpaff.c
10817 views
1
/*
2
* General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels
3
* Copyright (C) 2005 Mips Technologies, Inc
4
*/
5
#include <linux/cpu.h>
6
#include <linux/cpuset.h>
7
#include <linux/cpumask.h>
8
#include <linux/delay.h>
9
#include <linux/kernel.h>
10
#include <linux/init.h>
11
#include <linux/sched.h>
12
#include <linux/security.h>
13
#include <linux/types.h>
14
#include <asm/uaccess.h>
15
16
/*
17
* CPU mask used to set process affinity for MT VPEs/TCs with FPUs
18
*/
19
cpumask_t mt_fpu_cpumask;
20
21
static int fpaff_threshold = -1;
22
unsigned long mt_fpemul_threshold;
23
24
/*
25
* Replacement functions for the sys_sched_setaffinity() and
26
* sys_sched_getaffinity() system calls, so that we can integrate
27
* FPU affinity with the user's requested processor affinity.
28
* This code is 98% identical with the sys_sched_setaffinity()
29
* and sys_sched_getaffinity() system calls, and should be
30
* updated when kernel/sched.c changes.
31
*/
32
33
/*
34
* find_process_by_pid - find a process with a matching PID value.
35
* used in sys_sched_set/getaffinity() in kernel/sched.c, so
36
* cloned here.
37
*/
38
static inline struct task_struct *find_process_by_pid(pid_t pid)
39
{
40
return pid ? find_task_by_vpid(pid) : current;
41
}
42
43
/*
44
* check the target process has a UID that matches the current process's
45
*/
46
static bool check_same_owner(struct task_struct *p)
47
{
48
const struct cred *cred = current_cred(), *pcred;
49
bool match;
50
51
rcu_read_lock();
52
pcred = __task_cred(p);
53
match = (cred->euid == pcred->euid ||
54
cred->euid == pcred->uid);
55
rcu_read_unlock();
56
return match;
57
}
58
59
/*
60
* mipsmt_sys_sched_setaffinity - set the cpu affinity of a process
61
*/
62
asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
63
unsigned long __user *user_mask_ptr)
64
{
65
cpumask_var_t cpus_allowed, new_mask, effective_mask;
66
struct thread_info *ti;
67
struct task_struct *p;
68
int retval;
69
70
if (len < sizeof(new_mask))
71
return -EINVAL;
72
73
if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
74
return -EFAULT;
75
76
get_online_cpus();
77
rcu_read_lock();
78
79
p = find_process_by_pid(pid);
80
if (!p) {
81
rcu_read_unlock();
82
put_online_cpus();
83
return -ESRCH;
84
}
85
86
/* Prevent p going away */
87
get_task_struct(p);
88
rcu_read_unlock();
89
90
if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
91
retval = -ENOMEM;
92
goto out_put_task;
93
}
94
if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
95
retval = -ENOMEM;
96
goto out_free_cpus_allowed;
97
}
98
if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
99
retval = -ENOMEM;
100
goto out_free_new_mask;
101
}
102
retval = -EPERM;
103
if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
104
goto out_unlock;
105
106
retval = security_task_setscheduler(p);
107
if (retval)
108
goto out_unlock;
109
110
/* Record new user-specified CPU set for future reference */
111
cpumask_copy(&p->thread.user_cpus_allowed, new_mask);
112
113
again:
114
/* Compute new global allowed CPU set if necessary */
115
ti = task_thread_info(p);
116
if (test_ti_thread_flag(ti, TIF_FPUBOUND) &&
117
cpus_intersects(*new_mask, mt_fpu_cpumask)) {
118
cpus_and(*effective_mask, *new_mask, mt_fpu_cpumask);
119
retval = set_cpus_allowed_ptr(p, effective_mask);
120
} else {
121
cpumask_copy(effective_mask, new_mask);
122
clear_ti_thread_flag(ti, TIF_FPUBOUND);
123
retval = set_cpus_allowed_ptr(p, new_mask);
124
}
125
126
if (!retval) {
127
cpuset_cpus_allowed(p, cpus_allowed);
128
if (!cpumask_subset(effective_mask, cpus_allowed)) {
129
/*
130
* We must have raced with a concurrent cpuset
131
* update. Just reset the cpus_allowed to the
132
* cpuset's cpus_allowed
133
*/
134
cpumask_copy(new_mask, cpus_allowed);
135
goto again;
136
}
137
}
138
out_unlock:
139
free_cpumask_var(effective_mask);
140
out_free_new_mask:
141
free_cpumask_var(new_mask);
142
out_free_cpus_allowed:
143
free_cpumask_var(cpus_allowed);
144
out_put_task:
145
put_task_struct(p);
146
put_online_cpus();
147
return retval;
148
}
149
150
/*
151
* mipsmt_sys_sched_getaffinity - get the cpu affinity of a process
152
*/
153
asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
154
unsigned long __user *user_mask_ptr)
155
{
156
unsigned int real_len;
157
cpumask_t mask;
158
int retval;
159
struct task_struct *p;
160
161
real_len = sizeof(mask);
162
if (len < real_len)
163
return -EINVAL;
164
165
get_online_cpus();
166
read_lock(&tasklist_lock);
167
168
retval = -ESRCH;
169
p = find_process_by_pid(pid);
170
if (!p)
171
goto out_unlock;
172
retval = security_task_getscheduler(p);
173
if (retval)
174
goto out_unlock;
175
176
cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
177
178
out_unlock:
179
read_unlock(&tasklist_lock);
180
put_online_cpus();
181
if (retval)
182
return retval;
183
if (copy_to_user(user_mask_ptr, &mask, real_len))
184
return -EFAULT;
185
return real_len;
186
}
187
188
189
static int __init fpaff_thresh(char *str)
190
{
191
get_option(&str, &fpaff_threshold);
192
return 1;
193
}
194
__setup("fpaff=", fpaff_thresh);
195
196
/*
197
* FPU Use Factor empirically derived from experiments on 34K
198
*/
199
#define FPUSEFACTOR 2000
200
201
static __init int mt_fp_affinity_init(void)
202
{
203
if (fpaff_threshold >= 0) {
204
mt_fpemul_threshold = fpaff_threshold;
205
} else {
206
mt_fpemul_threshold =
207
(FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ;
208
}
209
printk(KERN_DEBUG "FPU Affinity set after %ld emulations\n",
210
mt_fpemul_threshold);
211
212
return 0;
213
}
214
arch_initcall(mt_fp_affinity_init);
215
216