crunch.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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 <asm/arch/ep93xx-regs.h>
  18. #include <asm/thread_notify.h>
  19. #include <asm/io.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_DEVICE_CONFIG_CRUNCH_ENABLE);
  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_RELEASE:
  46. crunch_task_release(thread);
  47. break;
  48. case THREAD_NOTIFY_SWITCH:
  49. devcfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
  50. if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
  51. devcfg ^= EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
  52. __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
  53. __raw_writel(devcfg, EP93XX_SYSCON_DEVICE_CONFIG);
  54. }
  55. break;
  56. }
  57. return NOTIFY_DONE;
  58. }
  59. static struct notifier_block crunch_notifier_block = {
  60. .notifier_call = crunch_do,
  61. };
  62. static int __init crunch_init(void)
  63. {
  64. thread_register_notifier(&crunch_notifier_block);
  65. elf_hwcap |= HWCAP_CRUNCH;
  66. return 0;
  67. }
  68. late_initcall(crunch_init);