1/* 2 * General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels 3 * Copyright (C) 2005 Mips Technologies, Inc 4 */ 5 6#include <linux/device.h> 7#include <linux/kernel.h> 8#include <linux/sched.h> 9#include <linux/cpumask.h> 10#include <linux/module.h> 11#include <linux/interrupt.h> 12#include <linux/security.h> 13 14#include <asm/cpu.h> 15#include <asm/processor.h> 16#include <asm/atomic.h> 17#include <asm/system.h> 18#include <asm/hardirq.h> 19#include <asm/mmu_context.h> 20#include <asm/smp.h> 21#include <asm/mipsmtregs.h> 22#include <asm/r4kcache.h> 23#include <asm/cacheflush.h> 24 25/* 26 * CPU mask used to set process affinity for MT VPEs/TCs with FPUs 27 */ 28 29cpumask_t mt_fpu_cpumask; 30 31#ifdef CONFIG_MIPS_MT_FPAFF 32 33#include <linux/cpu.h> 34#include <linux/delay.h> 35#include <asm/uaccess.h> 36 37unsigned long mt_fpemul_threshold = 0; 38 39/* 40 * Replacement functions for the sys_sched_setaffinity() and 41 * sys_sched_getaffinity() system calls, so that we can integrate 42 * FPU affinity with the user's requested processor affinity. 43 * This code is 98% identical with the sys_sched_setaffinity() 44 * and sys_sched_getaffinity() system calls, and should be 45 * updated when kernel/sched.c changes. 46 */ 47 48/* 49 * find_process_by_pid - find a process with a matching PID value. 50 * used in sys_sched_set/getaffinity() in kernel/sched.c, so 51 * cloned here. 52 */ 53static inline struct task_struct *find_process_by_pid(pid_t pid) 54{ 55 return pid ? find_task_by_pid(pid) : current; 56} 57 58 59/* 60 * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process 61 */ 62asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, 63 unsigned long __user *user_mask_ptr) 64{ 65 cpumask_t new_mask; 66 cpumask_t effective_mask; 67 int retval; 68 struct task_struct *p; 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 lock_cpu_hotplug(); 77 read_lock(&tasklist_lock); 78 79 p = find_process_by_pid(pid); 80 if (!p) { 81 read_unlock(&tasklist_lock); 82 unlock_cpu_hotplug(); 83 return -ESRCH; 84 } 85 86 /* 87 * It is not safe to call set_cpus_allowed with the 88 * tasklist_lock held. We will bump the task_struct's 89 * usage count and drop tasklist_lock before invoking 90 * set_cpus_allowed. 91 */ 92 get_task_struct(p); 93 94 retval = -EPERM; 95 if ((current->euid != p->euid) && (current->euid != p->uid) && 96 !capable(CAP_SYS_NICE)) { 97 read_unlock(&tasklist_lock); 98 goto out_unlock; 99 } 100 101 retval = security_task_setscheduler(p, 0, NULL); 102 if (retval) 103 goto out_unlock; 104 105 /* Record new user-specified CPU set for future reference */ 106 p->thread.user_cpus_allowed = new_mask; 107 108 /* Unlock the task list */ 109 read_unlock(&tasklist_lock); 110 111 /* Compute new global allowed CPU set if necessary */ 112 if( (p->thread.mflags & MF_FPUBOUND) 113 && cpus_intersects(new_mask, mt_fpu_cpumask)) { 114 cpus_and(effective_mask, new_mask, mt_fpu_cpumask); 115 retval = set_cpus_allowed(p, effective_mask); 116 } else { 117 p->thread.mflags &= ~MF_FPUBOUND; 118 retval = set_cpus_allowed(p, new_mask); 119 } 120 121 122out_unlock: 123 put_task_struct(p); 124 unlock_cpu_hotplug(); 125 return retval; 126} 127 128/* 129 * mipsmt_sys_sched_getaffinity - get the cpu affinity of a process 130 */ 131asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, 132 unsigned long __user *user_mask_ptr) 133{ 134 unsigned int real_len; 135 cpumask_t mask; 136 int retval; 137 struct task_struct *p; 138 139 real_len = sizeof(mask); 140 if (len < real_len) 141 return -EINVAL; 142 143 lock_cpu_hotplug(); 144 read_lock(&tasklist_lock); 145 146 retval = -ESRCH; 147 p = find_process_by_pid(pid); 148 if (!p) 149 goto out_unlock; 150 retval = security_task_getscheduler(p); 151 if (retval) 152 goto out_unlock; 153 154 cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); 155 156out_unlock: 157 read_unlock(&tasklist_lock); 158 unlock_cpu_hotplug(); 159 if (retval) 160 return retval; 161 if (copy_to_user(user_mask_ptr, &mask, real_len)) 162 return -EFAULT; 163 return real_len; 164} 165 166#endif /* CONFIG_MIPS_MT_FPAFF */ 167 168/* 169 * Dump new MIPS MT state for the core. Does not leave TCs halted. 170 * Takes an argument which taken to be a pre-call MVPControl value. 171 */ 172 173void mips_mt_regdump(unsigned long mvpctl) 174{ 175 unsigned long flags; 176 unsigned long vpflags; 177 unsigned long mvpconf0; 178 int nvpe; 179 int ntc; 180 int i; 181 int tc; 182 unsigned long haltval; 183 unsigned long tcstatval; 184#ifdef CONFIG_MIPS_MT_SMTC 185 void smtc_soft_dump(void); 186#endif /* CONFIG_MIPT_MT_SMTC */ 187 188 local_irq_save(flags); 189 vpflags = dvpe(); 190 printk("=== MIPS MT State Dump ===\n"); 191 printk("-- Global State --\n"); 192 printk(" MVPControl Passed: %08lx\n", mvpctl); 193 printk(" MVPControl Read: %08lx\n", vpflags); 194 printk(" MVPConf0 : %08lx\n", (mvpconf0 = read_c0_mvpconf0())); 195 nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; 196 ntc = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; 197 printk("-- per-VPE State --\n"); 198 for(i = 0; i < nvpe; i++) { 199 for(tc = 0; tc < ntc; tc++) { 200 settc(tc); 201 if((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { 202 printk(" VPE %d\n", i); 203 printk(" VPEControl : %08lx\n", read_vpe_c0_vpecontrol()); 204 printk(" VPEConf0 : %08lx\n", read_vpe_c0_vpeconf0()); 205 printk(" VPE%d.Status : %08lx\n", 206 i, read_vpe_c0_status()); 207 printk(" VPE%d.EPC : %08lx\n", i, read_vpe_c0_epc()); 208 printk(" VPE%d.Cause : %08lx\n", i, read_vpe_c0_cause()); 209 printk(" VPE%d.Config7 : %08lx\n", 210 i, read_vpe_c0_config7()); 211 break; /* Next VPE */ 212 } 213 } 214 } 215 printk("-- per-TC State --\n"); 216 for(tc = 0; tc < ntc; tc++) { 217 settc(tc); 218 if(read_tc_c0_tcbind() == read_c0_tcbind()) { 219 /* Are we dumping ourself? */ 220 haltval = 0; /* Then we're not halted, and mustn't be */ 221 tcstatval = flags; /* And pre-dump TCStatus is flags */ 222 printk(" TC %d (current TC with VPE EPC above)\n", tc); 223 } else { 224 haltval = read_tc_c0_tchalt(); 225 write_tc_c0_tchalt(1); 226 tcstatval = read_tc_c0_tcstatus(); 227 printk(" TC %d\n", tc); 228 } 229 printk(" TCStatus : %08lx\n", tcstatval); 230 printk(" TCBind : %08lx\n", read_tc_c0_tcbind()); 231 printk(" TCRestart : %08lx\n", read_tc_c0_tcrestart()); 232 printk(" TCHalt : %08lx\n", haltval); 233 printk(" TCContext : %08lx\n", read_tc_c0_tccontext()); 234 if (!haltval) 235 write_tc_c0_tchalt(0); 236 } 237#ifdef CONFIG_MIPS_MT_SMTC 238 smtc_soft_dump(); 239#endif /* CONFIG_MIPT_MT_SMTC */ 240 printk("===========================\n"); 241 evpe(vpflags); 242 local_irq_restore(flags); 243} 244 245static int mt_opt_norps = 0; 246static int mt_opt_rpsctl = -1; 247static int mt_opt_nblsu = -1; 248static int mt_opt_forceconfig7 = 0; 249static int mt_opt_config7 = -1; 250 251static int __init rps_disable(char *s) 252{ 253 mt_opt_norps = 1; 254 return 1; 255} 256__setup("norps", rps_disable); 257 258static int __init rpsctl_set(char *str) 259{ 260 get_option(&str, &mt_opt_rpsctl); 261 return 1; 262} 263__setup("rpsctl=", rpsctl_set); 264 265static int __init nblsu_set(char *str) 266{ 267 get_option(&str, &mt_opt_nblsu); 268 return 1; 269} 270__setup("nblsu=", nblsu_set); 271 272static int __init config7_set(char *str) 273{ 274 get_option(&str, &mt_opt_config7); 275 mt_opt_forceconfig7 = 1; 276 return 1; 277} 278__setup("config7=", config7_set); 279 280/* Experimental cache flush control parameters that should go away some day */ 281int mt_protiflush = 0; 282int mt_protdflush = 0; 283int mt_n_iflushes = 1; 284int mt_n_dflushes = 1; 285 286static int __init set_protiflush(char *s) 287{ 288 mt_protiflush = 1; 289 return 1; 290} 291__setup("protiflush", set_protiflush); 292 293static int __init set_protdflush(char *s) 294{ 295 mt_protdflush = 1; 296 return 1; 297} 298__setup("protdflush", set_protdflush); 299 300static int __init niflush(char *s) 301{ 302 get_option(&s, &mt_n_iflushes); 303 return 1; 304} 305__setup("niflush=", niflush); 306 307static int __init ndflush(char *s) 308{ 309 get_option(&s, &mt_n_dflushes); 310 return 1; 311} 312__setup("ndflush=", ndflush); 313#ifdef CONFIG_MIPS_MT_FPAFF 314static int fpaff_threshold = -1; 315 316static int __init fpaff_thresh(char *str) 317{ 318 get_option(&str, &fpaff_threshold); 319 return 1; 320} 321 322__setup("fpaff=", fpaff_thresh); 323#endif /* CONFIG_MIPS_MT_FPAFF */ 324 325static unsigned int itc_base = 0; 326 327static int __init set_itc_base(char *str) 328{ 329 get_option(&str, &itc_base); 330 return 1; 331} 332 333__setup("itcbase=", set_itc_base); 334 335void mips_mt_set_cpuoptions(void) 336{ 337 unsigned int oconfig7 = read_c0_config7(); 338 unsigned int nconfig7 = oconfig7; 339 340 if (mt_opt_norps) { 341 printk("\"norps\" option deprectated: use \"rpsctl=\"\n"); 342 } 343 if (mt_opt_rpsctl >= 0) { 344 printk("34K return prediction stack override set to %d.\n", 345 mt_opt_rpsctl); 346 if (mt_opt_rpsctl) 347 nconfig7 |= (1 << 2); 348 else 349 nconfig7 &= ~(1 << 2); 350 } 351 if (mt_opt_nblsu >= 0) { 352 printk("34K ALU/LSU sync override set to %d.\n", mt_opt_nblsu); 353 if (mt_opt_nblsu) 354 nconfig7 |= (1 << 5); 355 else 356 nconfig7 &= ~(1 << 5); 357 } 358 if (mt_opt_forceconfig7) { 359 printk("CP0.Config7 forced to 0x%08x.\n", mt_opt_config7); 360 nconfig7 = mt_opt_config7; 361 } 362 if (oconfig7 != nconfig7) { 363 __asm__ __volatile("sync"); 364 write_c0_config7(nconfig7); 365 ehb (); 366 printk("Config7: 0x%08x\n", read_c0_config7()); 367 } 368 369 /* Report Cache management debug options */ 370 if (mt_protiflush) 371 printk("I-cache flushes single-threaded\n"); 372 if (mt_protdflush) 373 printk("D-cache flushes single-threaded\n"); 374 if (mt_n_iflushes != 1) 375 printk("I-Cache Flushes Repeated %d times\n", mt_n_iflushes); 376 if (mt_n_dflushes != 1) 377 printk("D-Cache Flushes Repeated %d times\n", mt_n_dflushes); 378 379#ifdef CONFIG_MIPS_MT_FPAFF 380 /* FPU Use Factor empirically derived from experiments on 34K */ 381#define FPUSEFACTOR 333 382 383 if (fpaff_threshold >= 0) { 384 mt_fpemul_threshold = fpaff_threshold; 385 } else { 386 mt_fpemul_threshold = 387 (FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ; 388 } 389 printk("FPU Affinity set after %ld emulations\n", 390 mt_fpemul_threshold); 391#endif /* CONFIG_MIPS_MT_FPAFF */ 392 393 if (itc_base != 0) { 394 /* 395 * Configure ITC mapping. This code is very 396 * specific to the 34K core family, which uses 397 * a special mode bit ("ITC") in the ErrCtl 398 * register to enable access to ITC control 399 * registers via cache "tag" operations. 400 */ 401 unsigned long ectlval; 402 unsigned long itcblkgrn; 403 404 /* ErrCtl register is known as "ecc" to Linux */ 405 ectlval = read_c0_ecc(); 406 write_c0_ecc(ectlval | (0x1 << 26)); 407 ehb(); 408#define INDEX_0 (0x80000000) 409#define INDEX_8 (0x80000008) 410 /* Read "cache tag" for Dcache pseudo-index 8 */ 411 cache_op(Index_Load_Tag_D, INDEX_8); 412 ehb(); 413 itcblkgrn = read_c0_dtaglo(); 414 itcblkgrn &= 0xfffe0000; 415 /* Set for 128 byte pitch of ITC cells */ 416 itcblkgrn |= 0x00000c00; 417 /* Stage in Tag register */ 418 write_c0_dtaglo(itcblkgrn); 419 ehb(); 420 /* Write out to ITU with CACHE op */ 421 cache_op(Index_Store_Tag_D, INDEX_8); 422 /* Now set base address, and turn ITC on with 0x1 bit */ 423 write_c0_dtaglo((itc_base & 0xfffffc00) | 0x1 ); 424 ehb(); 425 /* Write out to ITU with CACHE op */ 426 cache_op(Index_Store_Tag_D, INDEX_0); 427 write_c0_ecc(ectlval); 428 ehb(); 429 printk("Mapped %ld ITC cells starting at 0x%08x\n", 430 ((itcblkgrn & 0x7fe00000) >> 20), itc_base); 431 } 432} 433 434/* 435 * Function to protect cache flushes from concurrent execution 436 * depends on MP software model chosen. 437 */ 438 439void mt_cflush_lockdown(void) 440{ 441#ifdef CONFIG_MIPS_MT_SMTC 442 void smtc_cflush_lockdown(void); 443 444 smtc_cflush_lockdown(); 445#endif /* CONFIG_MIPS_MT_SMTC */ 446 /* FILL IN VSMP and AP/SP VERSIONS HERE */ 447} 448 449void mt_cflush_release(void) 450{ 451#ifdef CONFIG_MIPS_MT_SMTC 452 void smtc_cflush_release(void); 453 454 smtc_cflush_release(); 455#endif /* CONFIG_MIPS_MT_SMTC */ 456 /* FILL IN VSMP and AP/SP VERSIONS HERE */ 457} 458 459struct class *mt_class; 460 461static int __init mt_init(void) 462{ 463 struct class *mtc; 464 465 mtc = class_create(THIS_MODULE, "mt"); 466 if (IS_ERR(mtc)) 467 return PTR_ERR(mtc); 468 469 mt_class = mtc; 470 471 return 0; 472} 473 474subsys_initcall(mt_init); 475