plic.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* Copyright 2018 Canaan Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #include <stddef.h>
  16. #include <stdint.h>
  17. #include "encoding.h"
  18. #include "plic.h"
  19. #include "syscalls.h"
  20. #include "syslog.h"
  21. volatile plic_t *const plic = (volatile plic_t *)PLIC_BASE_ADDR;
  22. static plic_instance_t plic_instance[PLIC_NUM_CORES][IRQN_MAX];
  23. void plic_init(void)
  24. {
  25. int i = 0;
  26. /* Get current core id */
  27. unsigned long core_id = current_coreid();
  28. /* Disable all interrupts for the current core. */
  29. for(i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++)
  30. plic->target_enables.target[core_id].enable[i] = 0;
  31. static uint8_t s_plic_priorities_init_flag = 0;
  32. /* Set priorities to zero. */
  33. if(s_plic_priorities_init_flag == 0)
  34. {
  35. for(i = 0; i < PLIC_NUM_SOURCES; i++)
  36. plic->source_priorities.priority[i] = 0;
  37. s_plic_priorities_init_flag = 1;
  38. }
  39. /* Set the threshold to zero. */
  40. plic->targets.target[core_id].priority_threshold = 0;
  41. /* Clear PLIC instance for every cores */
  42. for(i = 0; i < IRQN_MAX; i++)
  43. {
  44. /* clang-format off */
  45. plic_instance[core_id][i] = (const plic_instance_t){
  46. .callback = NULL,
  47. .ctx = NULL,
  48. };
  49. /* clang-format on */
  50. }
  51. /*
  52. * A successful claim will also atomically clear the corresponding
  53. * pending bit on the interrupt source. A target can perform a claim
  54. * at any time, even if the EIP is not set.
  55. */
  56. i = 0;
  57. while(plic->targets.target[core_id].claim_complete > 0 && i < 100)
  58. {
  59. /* This loop will clear pending bit on the interrupt source */
  60. i++;
  61. }
  62. /* Enable machine external interrupts. */
  63. set_csr(mie, MIP_MEIP);
  64. }
  65. int plic_irq_enable(plic_irq_t irq_number)
  66. {
  67. /* Check parameters */
  68. if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
  69. return -1;
  70. unsigned long core_id = current_coreid();
  71. /* Get current enable bit array by IRQ number */
  72. uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
  73. /* Set enable bit in enable bit array */
  74. current |= (uint32_t)1 << (irq_number % 32);
  75. /* Write back the enable bit array */
  76. plic->target_enables.target[core_id].enable[irq_number / 32] = current;
  77. return 0;
  78. }
  79. int plic_irq_disable(plic_irq_t irq_number)
  80. {
  81. /* Check parameters */
  82. if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
  83. return -1;
  84. unsigned long core_id = current_coreid();
  85. /* Get current enable bit array by IRQ number */
  86. uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
  87. /* Clear enable bit in enable bit array */
  88. current &= ~((uint32_t)1 << (irq_number % 32));
  89. /* Write back the enable bit array */
  90. plic->target_enables.target[core_id].enable[irq_number / 32] = current;
  91. return 0;
  92. }
  93. int plic_set_priority(plic_irq_t irq_number, uint32_t priority)
  94. {
  95. /* Check parameters */
  96. if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
  97. return -1;
  98. /* Set interrupt priority by IRQ number */
  99. plic->source_priorities.priority[irq_number] = priority;
  100. return 0;
  101. }
  102. uint32_t plic_get_priority(plic_irq_t irq_number)
  103. {
  104. /* Check parameters */
  105. if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
  106. return 0;
  107. /* Get interrupt priority by IRQ number */
  108. return plic->source_priorities.priority[irq_number];
  109. }
  110. uint32_t plic_irq_claim(void)
  111. {
  112. unsigned long core_id = current_coreid();
  113. /* Perform IRQ claim */
  114. return plic->targets.target[core_id].claim_complete;
  115. }
  116. int plic_irq_complete(uint32_t source)
  117. {
  118. unsigned long core_id = current_coreid();
  119. /* Perform IRQ complete */
  120. plic->targets.target[core_id].claim_complete = source;
  121. return 0;
  122. }
  123. void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx)
  124. {
  125. /* Read core id */
  126. unsigned long core_id = current_coreid();
  127. /* Set user callback function */
  128. plic_instance[core_id][irq].callback = callback;
  129. /* Assign user context */
  130. plic_instance[core_id][irq].ctx = ctx;
  131. }
  132. void plic_irq_unregister(plic_irq_t irq)
  133. {
  134. /* Just assign NULL to user callback function and context */
  135. plic_irq_register(irq, NULL, NULL);
  136. }
  137. void __attribute__((weak, alias("plic_irq_unregister"))) plic_irq_deregister(plic_irq_t irq);
  138. plic_instance_t (*plic_get_instance(void))[IRQN_MAX]
  139. {
  140. return plic_instance;
  141. }
  142. /*Entry Point for PLIC Interrupt Handler*/
  143. uintptr_t __attribute__((weak))
  144. handle_irq_m_ext(uintptr_t cause, uintptr_t epc)
  145. {
  146. /*
  147. * After the highest-priority pending interrupt is claimed by a target
  148. * and the corresponding IP bit is cleared, other lower-priority
  149. * pending interrupts might then become visible to the target, and so
  150. * the PLIC EIP bit might not be cleared after a claim. The interrupt
  151. * handler can check the local meip/heip/seip/ueip bits before exiting
  152. * the handler, to allow more efficient service of other interrupts
  153. * without first restoring the interrupted context and taking another
  154. * interrupt trap.
  155. */
  156. if(read_csr(mip) & MIP_MEIP)
  157. {
  158. /* Get current core id */
  159. uint64_t core_id = current_coreid();
  160. /* Get primitive interrupt enable flag */
  161. uint64_t ie_flag = read_csr(mie);
  162. /* Get current IRQ num */
  163. uint32_t int_num = plic->targets.target[core_id].claim_complete;
  164. /* Get primitive IRQ threshold */
  165. uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
  166. /* Set new IRQ threshold = current IRQ threshold */
  167. plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
  168. /* Disable software interrupt and timer interrupt */
  169. clear_csr(mie, MIP_MTIP | MIP_MSIP);
  170. /* Enable global interrupt */
  171. set_csr(mstatus, MSTATUS_MIE);
  172. if(plic_instance[core_id][int_num].callback)
  173. plic_instance[core_id][int_num].callback(
  174. plic_instance[core_id][int_num].ctx);
  175. /* Perform IRQ complete */
  176. plic->targets.target[core_id].claim_complete = int_num;
  177. /* Disable global interrupt */
  178. clear_csr(mstatus, MSTATUS_MIE);
  179. /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
  180. set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
  181. /* Restore primitive interrupt enable flag */
  182. write_csr(mie, ie_flag);
  183. /* Restore primitive IRQ threshold */
  184. plic->targets.target[core_id].priority_threshold = int_threshold;
  185. }
  186. return epc;
  187. }