| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /* Copyright 2018 Canaan Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <stddef.h>
- #include <stdint.h>
- #include "encoding.h"
- #include "plic.h"
- #include "syscalls.h"
- #include "syslog.h"
- volatile plic_t *const plic = (volatile plic_t *)PLIC_BASE_ADDR;
- static plic_instance_t plic_instance[PLIC_NUM_CORES][IRQN_MAX];
- void plic_init(void)
- {
- int i = 0;
- /* Get current core id */
- unsigned long core_id = current_coreid();
- /* Disable all interrupts for the current core. */
- for(i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++)
- plic->target_enables.target[core_id].enable[i] = 0;
- static uint8_t s_plic_priorities_init_flag = 0;
- /* Set priorities to zero. */
- if(s_plic_priorities_init_flag == 0)
- {
- for(i = 0; i < PLIC_NUM_SOURCES; i++)
- plic->source_priorities.priority[i] = 0;
- s_plic_priorities_init_flag = 1;
- }
- /* Set the threshold to zero. */
- plic->targets.target[core_id].priority_threshold = 0;
- /* Clear PLIC instance for every cores */
- for(i = 0; i < IRQN_MAX; i++)
- {
- /* clang-format off */
- plic_instance[core_id][i] = (const plic_instance_t){
- .callback = NULL,
- .ctx = NULL,
- };
- /* clang-format on */
- }
- /*
- * A successful claim will also atomically clear the corresponding
- * pending bit on the interrupt source. A target can perform a claim
- * at any time, even if the EIP is not set.
- */
- i = 0;
- while(plic->targets.target[core_id].claim_complete > 0 && i < 100)
- {
- /* This loop will clear pending bit on the interrupt source */
- i++;
- }
- /* Enable machine external interrupts. */
- set_csr(mie, MIP_MEIP);
- }
- int plic_irq_enable(plic_irq_t irq_number)
- {
- /* Check parameters */
- if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
- return -1;
- unsigned long core_id = current_coreid();
- /* Get current enable bit array by IRQ number */
- uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
- /* Set enable bit in enable bit array */
- current |= (uint32_t)1 << (irq_number % 32);
- /* Write back the enable bit array */
- plic->target_enables.target[core_id].enable[irq_number / 32] = current;
- return 0;
- }
- int plic_irq_disable(plic_irq_t irq_number)
- {
- /* Check parameters */
- if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
- return -1;
- unsigned long core_id = current_coreid();
- /* Get current enable bit array by IRQ number */
- uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
- /* Clear enable bit in enable bit array */
- current &= ~((uint32_t)1 << (irq_number % 32));
- /* Write back the enable bit array */
- plic->target_enables.target[core_id].enable[irq_number / 32] = current;
- return 0;
- }
- int plic_set_priority(plic_irq_t irq_number, uint32_t priority)
- {
- /* Check parameters */
- if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
- return -1;
- /* Set interrupt priority by IRQ number */
- plic->source_priorities.priority[irq_number] = priority;
- return 0;
- }
- uint32_t plic_get_priority(plic_irq_t irq_number)
- {
- /* Check parameters */
- if(PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
- return 0;
- /* Get interrupt priority by IRQ number */
- return plic->source_priorities.priority[irq_number];
- }
- uint32_t plic_irq_claim(void)
- {
- unsigned long core_id = current_coreid();
- /* Perform IRQ claim */
- return plic->targets.target[core_id].claim_complete;
- }
- int plic_irq_complete(uint32_t source)
- {
- unsigned long core_id = current_coreid();
- /* Perform IRQ complete */
- plic->targets.target[core_id].claim_complete = source;
- return 0;
- }
- void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx)
- {
- /* Read core id */
- unsigned long core_id = current_coreid();
- /* Set user callback function */
- plic_instance[core_id][irq].callback = callback;
- /* Assign user context */
- plic_instance[core_id][irq].ctx = ctx;
- }
- void plic_irq_unregister(plic_irq_t irq)
- {
- /* Just assign NULL to user callback function and context */
- plic_irq_register(irq, NULL, NULL);
- }
- void __attribute__((weak, alias("plic_irq_unregister"))) plic_irq_deregister(plic_irq_t irq);
- plic_instance_t (*plic_get_instance(void))[IRQN_MAX]
- {
- return plic_instance;
- }
- /*Entry Point for PLIC Interrupt Handler*/
- uintptr_t __attribute__((weak))
- handle_irq_m_ext(uintptr_t cause, uintptr_t epc)
- {
- /*
- * After the highest-priority pending interrupt is claimed by a target
- * and the corresponding IP bit is cleared, other lower-priority
- * pending interrupts might then become visible to the target, and so
- * the PLIC EIP bit might not be cleared after a claim. The interrupt
- * handler can check the local meip/heip/seip/ueip bits before exiting
- * the handler, to allow more efficient service of other interrupts
- * without first restoring the interrupted context and taking another
- * interrupt trap.
- */
- if(read_csr(mip) & MIP_MEIP)
- {
- /* Get current core id */
- uint64_t core_id = current_coreid();
- /* Get primitive interrupt enable flag */
- uint64_t ie_flag = read_csr(mie);
- /* Get current IRQ num */
- uint32_t int_num = plic->targets.target[core_id].claim_complete;
- /* Get primitive IRQ threshold */
- uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
- /* Set new IRQ threshold = current IRQ threshold */
- plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
- /* Disable software interrupt and timer interrupt */
- clear_csr(mie, MIP_MTIP | MIP_MSIP);
- /* Enable global interrupt */
- set_csr(mstatus, MSTATUS_MIE);
- if(plic_instance[core_id][int_num].callback)
- plic_instance[core_id][int_num].callback(
- plic_instance[core_id][int_num].ctx);
- /* Perform IRQ complete */
- plic->targets.target[core_id].claim_complete = int_num;
- /* Disable global interrupt */
- clear_csr(mstatus, MSTATUS_MIE);
- /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
- set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
- /* Restore primitive interrupt enable flag */
- write_csr(mie, ie_flag);
- /* Restore primitive IRQ threshold */
- plic->targets.target[core_id].priority_threshold = int_threshold;
- }
- return epc;
- }
|