crunch.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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. #include <linux/module.h>
  12. #include <linux/types.h>
  13. #include <linux/kernel.h>
  14. #include <linux/signal.h>
  15. #include <linux/sched.h>
  16. #include <linux/init.h>
  17. #include <linux/io.h>
  18. #include <mach/ep93xx-regs.h>
  19. #include <asm/thread_notify.h>
  20. struct crunch_state *crunch_owner;
  21. void crunch_task_release(struct thread_info *thread)
  22. {
  23. local_irq_disable();
  24. if (crunch_owner == &thread->crunchstate)
  25. crunch_owner = NULL;
  26. local_irq_enable();
  27. }
  28. static int crunch_enabled(u32 devcfg)
  29. {
  30. return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
  31. }
  32. static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
  33. {
  34. struct thread_info *thread = (struct thread_info *)t;
  35. struct crunch_state *crunch_state;
  36. u32 devcfg;
  37. crunch_state = &thread->crunchstate;
  38. switch (cmd) {
  39. case THREAD_NOTIFY_FLUSH:
  40. memset(crunch_state, 0, sizeof(*crunch_state));
  41. /*
  42. * FALLTHROUGH: Ensure we don't try to overwrite our newly
  43. * initialised state information on the first fault.
  44. */
  45. case THREAD_NOTIFY_EXIT:
  46. crunch_task_release(thread);
  47. break;
  48. case THREAD_NOTIFY_SWITCH:
  49. devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
  50. if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
  51. /*
  52. * We don't use ep93xx_syscon_swlocked_write() here
  53. * because we are on the context switch path and
  54. * preemption is already disabled.
  55. */
  56. devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
  57. __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
  58. __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
  59. }
  60. break;
  61. }
  62. return NOTIFY_DONE;
  63. }
  64. static struct notifier_block crunch_notifier_block = {
  65. .notifier_call = crunch_do,
  66. };
  67. static int __init crunch_init(void)
  68. {
  69. thread_register_notifier(&crunch_notifier_block);
  70. elf_hwcap |= HWCAP_CRUNCH;
  71. return 0;
  72. }
  73. late_initcall(crunch_init);