crunch.c 1.9 KB

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