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/cpumask.h> 7 #include <linux/delay.h> 8 #include <linux/kernel.h> 9 #include <linux/init.h> 10 #include <linux/sched.h> 11 #include <linux/security.h> 12 #include <linux/types.h> 13 #include <asm/uaccess.h> 14 15 /* 16 * CPU mask used to set process affinity for MT VPEs/TCs with FPUs 17 */ 18 cpumask_t mt_fpu_cpumask; 19 20 static int fpaff_threshold = -1; 21 unsigned long mt_fpemul_threshold; 22 23 /* 24 * Replacement functions for the sys_sched_setaffinity() and 25 * sys_sched_getaffinity() system calls, so that we can integrate 26 * FPU affinity with the user's requested processor affinity. 27 * This code is 98% identical with the sys_sched_setaffinity() 28 * and sys_sched_getaffinity() system calls, and should be 29 * updated when kernel/sched.c changes. 30 */ 31 32 /* 33 * find_process_by_pid - find a process with a matching PID value. 34 * used in sys_sched_set/getaffinity() in kernel/sched.c, so 35 * cloned here. 36 */ 37 static inline struct task_struct *find_process_by_pid(pid_t pid) 38 { 39 return pid ? find_task_by_vpid(pid) : current; 40 } 41 42 43 /* 44 * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process 45 */ 46 asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, 47 unsigned long __user *user_mask_ptr) 48 { 49 cpumask_t new_mask; 50 cpumask_t effective_mask; 51 int retval; 52 struct task_struct *p; 53 struct thread_info *ti; 54 uid_t euid; 55 56 if (len < sizeof(new_mask)) 57 return -EINVAL; 58 59 if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) 60 return -EFAULT; 61 62 get_online_cpus(); 63 read_lock(&tasklist_lock); 64 65 p = find_process_by_pid(pid); 66 if (!p) { 67 read_unlock(&tasklist_lock); 68 put_online_cpus(); 69 return -ESRCH; 70 } 71 72 /* 73 * It is not safe to call set_cpus_allowed with the 74 * tasklist_lock held. We will bump the task_struct's 75 * usage count and drop tasklist_lock before invoking 76 * set_cpus_allowed. 77 */ 78 get_task_struct(p); 79 80 euid = current_euid(); 81 retval = -EPERM; 82 if (euid != p->cred->euid && euid != p->cred->uid && 83 !capable(CAP_SYS_NICE)) { 84 read_unlock(&tasklist_lock); 85 goto out_unlock; 86 } 87 88 retval = security_task_setscheduler(p, 0, NULL); 89 if (retval) 90 goto out_unlock; 91 92 /* Record new user-specified CPU set for future reference */ 93 p->thread.user_cpus_allowed = new_mask; 94 95 /* Unlock the task list */ 96 read_unlock(&tasklist_lock); 97 98 /* Compute new global allowed CPU set if necessary */ 99 ti = task_thread_info(p); 100 if (test_ti_thread_flag(ti, TIF_FPUBOUND) && 101 cpus_intersects(new_mask, mt_fpu_cpumask)) { 102 cpus_and(effective_mask, new_mask, mt_fpu_cpumask); 103 retval = set_cpus_allowed(p, effective_mask); 104 } else { 105 clear_ti_thread_flag(ti, TIF_FPUBOUND); 106 retval = set_cpus_allowed(p, new_mask); 107 } 108 109 out_unlock: 110 put_task_struct(p); 111 put_online_cpus(); 112 return retval; 113 } 114 115 /* 116 * mipsmt_sys_sched_getaffinity - get the cpu affinity of a process 117 */ 118 asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, 119 unsigned long __user *user_mask_ptr) 120 { 121 unsigned int real_len; 122 cpumask_t mask; 123 int retval; 124 struct task_struct *p; 125 126 real_len = sizeof(mask); 127 if (len < real_len) 128 return -EINVAL; 129 130 get_online_cpus(); 131 read_lock(&tasklist_lock); 132 133 retval = -ESRCH; 134 p = find_process_by_pid(pid); 135 if (!p) 136 goto out_unlock; 137 retval = security_task_getscheduler(p); 138 if (retval) 139 goto out_unlock; 140 141 cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); 142 143 out_unlock: 144 read_unlock(&tasklist_lock); 145 put_online_cpus(); 146 if (retval) 147 return retval; 148 if (copy_to_user(user_mask_ptr, &mask, real_len)) 149 return -EFAULT; 150 return real_len; 151 } 152 153 154 static int __init fpaff_thresh(char *str) 155 { 156 get_option(&str, &fpaff_threshold); 157 return 1; 158 } 159 __setup("fpaff=", fpaff_thresh); 160 161 /* 162 * FPU Use Factor empirically derived from experiments on 34K 163 */ 164 #define FPUSEFACTOR 2000 165 166 static __init int mt_fp_affinity_init(void) 167 { 168 if (fpaff_threshold >= 0) { 169 mt_fpemul_threshold = fpaff_threshold; 170 } else { 171 mt_fpemul_threshold = 172 (FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ; 173 } 174 printk(KERN_DEBUG "FPU Affinity set after %ld emulations\n", 175 mt_fpemul_threshold); 176 177 return 0; 178 } 179 arch_initcall(mt_fp_affinity_init); 180