fiq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/arm/kernel/fiq.c
  3.  *
  4.  *  Copyright (C) 1998 Russell King
  5.  *  Copyright (C) 1998, 1999 Phil Blundell
  6.  *
  7.  *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
  8.  *
  9.  *  FIQ support re-written by Russell King to be more generic
  10.  *
  11.  * We now properly support a method by which the FIQ handlers can
  12.  * be stacked onto the vector.  We still do not support sharing
  13.  * the FIQ vector itself.
  14.  *
  15.  * Operation is as follows:
  16.  *  1. Owner A claims FIQ:
  17.  *     - default_fiq relinquishes control.
  18.  *  2. Owner A:
  19.  *     - inserts code.
  20.  *     - sets any registers,
  21.  *     - enables FIQ.
  22.  *  3. Owner B claims FIQ:
  23.  *     - if owner A has a relinquish function.
  24.  *       - disable FIQs.
  25.  *       - saves any registers.
  26.  *       - returns zero.
  27.  *  4. Owner B:
  28.  *     - inserts code.
  29.  *     - sets any registers,
  30.  *     - enables FIQ.
  31.  *  5. Owner B releases FIQ:
  32.  *     - Owner A is asked to reacquire FIQ:
  33.  *  - inserts code.
  34.  *  - restores saved registers.
  35.  *  - enables FIQ.
  36.  *  6. Goto 3
  37.  */
  38. #include <linux/config.h>
  39. #include <linux/module.h>
  40. #include <linux/mm.h>
  41. #include <linux/mman.h>
  42. #include <linux/init.h>
  43. #include <asm/fiq.h>
  44. #include <asm/io.h>
  45. #include <asm/irq.h>
  46. #include <asm/pgalloc.h>
  47. #include <asm/system.h>
  48. #include <asm/uaccess.h>
  49. #define FIQ_VECTOR (vectors_base() + 0x1c)
  50. static unsigned long no_fiq_insn;
  51. #ifdef CONFIG_CPU_32
  52. static inline void unprotect_page_0(void)
  53. {
  54. modify_domain(DOMAIN_USER, DOMAIN_MANAGER);
  55. }
  56. static inline void protect_page_0(void)
  57. {
  58. modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
  59. }
  60. #else
  61. #define unprotect_page_0()
  62. #define protect_page_0()
  63. #endif
  64. /* Default reacquire function
  65.  * - we always relinquish FIQ control
  66.  * - we always reacquire FIQ control
  67.  */
  68. static int fiq_def_op(void *ref, int relinquish)
  69. {
  70. if (!relinquish) {
  71. unprotect_page_0();
  72. *(unsigned long *)FIQ_VECTOR = no_fiq_insn;
  73. protect_page_0();
  74. flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + 4);
  75. }
  76. return 0;
  77. }
  78. static struct fiq_handler default_owner = {
  79. name: "default",
  80. fiq_op: fiq_def_op,
  81. };
  82. static struct fiq_handler *current_fiq = &default_owner;
  83. int get_fiq_list(char *buf)
  84. {
  85. char *p = buf;
  86. if (current_fiq != &default_owner)
  87. p += sprintf(p, "FIQ:              %sn",
  88.      current_fiq->name);
  89. return p - buf;
  90. }
  91. void set_fiq_handler(void *start, unsigned int length)
  92. {
  93. unprotect_page_0();
  94. memcpy((void *)FIQ_VECTOR, start, length);
  95. protect_page_0();
  96. flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + length);
  97. }
  98. /*
  99.  * Taking an interrupt in FIQ mode is death, so both these functions
  100.  * disable irqs for the duration. 
  101.  */
  102. void set_fiq_regs(struct pt_regs *regs)
  103. {
  104. register unsigned long tmp, tmp2;
  105. __asm__ volatile (
  106. #ifdef CONFIG_CPU_26
  107. "mov %0, pc
  108. bic %1, %0, #0x3
  109. orr %1, %1, %3
  110. teqp %1, #0 @ select FIQ mode
  111. mov r0, r0
  112. ldmia %2, {r8 - r14}
  113. teqp %0, #0 @ return to SVC mode
  114. mov r0, r0"
  115. #endif
  116. #ifdef CONFIG_CPU_32
  117. "mrs %0, cpsr
  118. mov %1, %3
  119. msr cpsr_c, %1 @ select FIQ mode
  120. mov r0, r0
  121. ldmia %2, {r8 - r14}
  122. msr cpsr_c, %0 @ return to SVC mode
  123. mov r0, r0"
  124. #endif
  125. : "=&r" (tmp), "=&r" (tmp2)
  126. : "r" (&regs->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE)
  127. /* These registers aren't modified by the above code in a way
  128.    visible to the compiler, but we mark them as clobbers anyway
  129.    so that GCC won't put any of the input or output operands in
  130.    them.  */
  131. : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
  132. }
  133. void get_fiq_regs(struct pt_regs *regs)
  134. {
  135. register unsigned long tmp, tmp2;
  136. __asm__ volatile (
  137. #ifdef CONFIG_CPU_26
  138. "mov %0, pc
  139. bic %1, %0, #0x3
  140. orr %1, %1, %3
  141. teqp %1, #0 @ select FIQ mode
  142. mov r0, r0
  143. stmia %2, {r8 - r14}
  144. teqp %0, #0 @ return to SVC mode
  145. mov r0, r0"
  146. #endif
  147. #ifdef CONFIG_CPU_32
  148. "mrs %0, cpsr
  149. mov %1, %3
  150. msr cpsr_c, %1 @ select FIQ mode
  151. mov r0, r0
  152. stmia %2, {r8 - r14}
  153. msr cpsr_c, %0 @ return to SVC mode
  154. mov r0, r0"
  155. #endif
  156. : "=&r" (tmp), "=&r" (tmp2)
  157. : "r" (&regs->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE)
  158. /* These registers aren't modified by the above code in a way
  159.    visible to the compiler, but we mark them as clobbers anyway
  160.    so that GCC won't put any of the input or output operands in
  161.    them.  */
  162. : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
  163. }
  164. int claim_fiq(struct fiq_handler *f)
  165. {
  166. int ret = 0;
  167. if (current_fiq) {
  168. ret = -EBUSY;
  169. if (current_fiq->fiq_op != NULL)
  170. ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
  171. }
  172. if (!ret) {
  173. f->next = current_fiq;
  174. current_fiq = f;
  175. }
  176. return ret;
  177. }
  178. void release_fiq(struct fiq_handler *f)
  179. {
  180. if (current_fiq != f) {
  181. printk(KERN_ERR "%s FIQ trying to release %s FIQn",
  182.        f->name, current_fiq->name);
  183. #ifdef CONFIG_DEBUG_ERRORS
  184. __backtrace();
  185. #endif
  186. return;
  187. }
  188. do
  189. current_fiq = current_fiq->next;
  190. while (current_fiq->fiq_op(current_fiq->dev_id, 0));
  191. }
  192. void enable_fiq(int fiq)
  193. {
  194. enable_irq(fiq + FIQ_START);
  195. }
  196. void disable_fiq(int fiq)
  197. {
  198. disable_irq(fiq + FIQ_START);
  199. }
  200. EXPORT_SYMBOL(set_fiq_handler);
  201. EXPORT_SYMBOL(set_fiq_regs);
  202. EXPORT_SYMBOL(get_fiq_regs);
  203. EXPORT_SYMBOL(claim_fiq);
  204. EXPORT_SYMBOL(release_fiq);
  205. EXPORT_SYMBOL(enable_fiq);
  206. EXPORT_SYMBOL(disable_fiq);
  207. void __init init_FIQ(void)
  208. {
  209. no_fiq_insn = *(unsigned long *)FIQ_VECTOR;
  210. set_fs(get_fs());
  211. }