1 /* 2 * arch/arm/kernel/crunch.c 3 * Cirrus MaverickCrunch context switching and handling 4 * 5 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/types.h> 14 #include <linux/kernel.h> 15 #include <linux/signal.h> 16 #include <linux/sched.h> 17 #include <linux/init.h> 18 #include <linux/io.h> 19 20 #include <asm/thread_notify.h> 21 22 #include "soc.h" 23 24 struct crunch_state *crunch_owner; 25 crunch_task_release(struct thread_info * thread)26void crunch_task_release(struct thread_info *thread) 27 { 28 local_irq_disable(); 29 if (crunch_owner == &thread->crunchstate) 30 crunch_owner = NULL; 31 local_irq_enable(); 32 } 33 crunch_enabled(u32 devcfg)34static int crunch_enabled(u32 devcfg) 35 { 36 return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA); 37 } 38 crunch_do(struct notifier_block * self,unsigned long cmd,void * t)39static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t) 40 { 41 struct thread_info *thread = (struct thread_info *)t; 42 struct crunch_state *crunch_state; 43 u32 devcfg; 44 45 crunch_state = &thread->crunchstate; 46 47 switch (cmd) { 48 case THREAD_NOTIFY_FLUSH: 49 memset(crunch_state, 0, sizeof(*crunch_state)); 50 51 /* 52 * FALLTHROUGH: Ensure we don't try to overwrite our newly 53 * initialised state information on the first fault. 54 */ 55 56 case THREAD_NOTIFY_EXIT: 57 crunch_task_release(thread); 58 break; 59 60 case THREAD_NOTIFY_SWITCH: 61 devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG); 62 if (crunch_enabled(devcfg) || crunch_owner == crunch_state) { 63 /* 64 * We don't use ep93xx_syscon_swlocked_write() here 65 * because we are on the context switch path and 66 * preemption is already disabled. 67 */ 68 devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA; 69 __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); 70 __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG); 71 } 72 break; 73 } 74 75 return NOTIFY_DONE; 76 } 77 78 static struct notifier_block crunch_notifier_block = { 79 .notifier_call = crunch_do, 80 }; 81 crunch_init(void)82int __init crunch_init(void) 83 { 84 thread_register_notifier(&crunch_notifier_block); 85 elf_hwcap |= HWCAP_CRUNCH; 86 87 return 0; 88 } 89