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 24struct crunch_state *crunch_owner; 25 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 34static int crunch_enabled(u32 devcfg) 35{ 36 return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA); 37} 38 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 78static struct notifier_block crunch_notifier_block = { 79 .notifier_call = crunch_do, 80}; 81 82int __init crunch_init(void) 83{ 84 thread_register_notifier(&crunch_notifier_block); 85 elf_hwcap |= HWCAP_CRUNCH; 86 87 return 0; 88} 89