1 /*
2 * Copyright (c) 2018 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include "platform_p.h"
9
10 #include <assert.h>
11 #include <lk/err.h>
12 #include <lk/debug.h>
13 #include <lk/reg.h>
14 #include <lk/trace.h>
15 #include <kernel/debug.h>
16 #include <kernel/thread.h>
17 #include <platform/interrupts.h>
18 #include <platform/sifive.h>
19
20 #define LOCAL_TRACE 0
21
22 // Driver for PLIC implementation in SiFive E and U boards
23
24 #define PLIC_PRIORITY(irq) (PLIC_BASE + 4 * (irq))
25 #define PLIC_PENDING(irq) (PLIC_BASE + 0x1000 + (4 * ((irq) / 32)))
26 #define PLIC_ENABLE(irq, hart) (PLIC_BASE + 0x2000 + (0x80 * PLIC_HART_IDX(hart)) + (4 * ((irq) / 32)))
27 #define PLIC_THRESHOLD(hart) (PLIC_BASE + 0x200000 + (0x1000 * PLIC_HART_IDX(hart)))
28 #define PLIC_COMPLETE(hart) (PLIC_BASE + 0x200004 + (0x1000 * PLIC_HART_IDX(hart)))
29 #define PLIC_CLAIM(hart) PLIC_COMPLETE(hart)
30
31 static struct int_handlers {
32 int_handler handler;
33 void *arg;
34 } handlers[SIFIVE_NUM_IRQS];
35
plic_early_init(void)36 void plic_early_init(void) {
37 // mask all irqs and set their priority to 1
38 for (int i = 1; i < SIFIVE_NUM_IRQS; i++) {
39 *REG32(PLIC_ENABLE(i, riscv_current_hart())) &= ~(1 << (i % 32));
40 *REG32(PLIC_PRIORITY(i)) = 1;
41 }
42
43 // set global priority threshold to 0
44 *REG32(PLIC_THRESHOLD(riscv_current_hart())) = 0;
45 }
46
plic_init(void)47 void plic_init(void) {
48 }
49
mask_interrupt(unsigned int vector)50 status_t mask_interrupt(unsigned int vector) {
51 *REG32(PLIC_ENABLE(vector, riscv_current_hart())) &= ~(1 << (vector % 32));
52 return NO_ERROR;
53 }
54
unmask_interrupt(unsigned int vector)55 status_t unmask_interrupt(unsigned int vector) {
56 *REG32(PLIC_ENABLE(vector, riscv_current_hart())) |= (1 << (vector % 32));
57 return NO_ERROR;
58 }
59
register_int_handler(unsigned int vector,int_handler handler,void * arg)60 void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
61 LTRACEF("vector %u handler %p arg %p\n", vector, handler, arg);
62
63 DEBUG_ASSERT(vector < SIFIVE_NUM_IRQS);
64
65 handlers[vector].handler = handler;
66 handlers[vector].arg = arg;
67 }
68
riscv_platform_irq(void)69 enum handler_return riscv_platform_irq(void) {
70 // see what irq triggered it
71 uint32_t vector = *REG32(PLIC_CLAIM(riscv_current_hart()));
72 LTRACEF("vector %u\n", vector);
73
74 if (unlikely(vector == 0)) {
75 // nothing pending
76 return INT_NO_RESCHEDULE;
77 }
78
79 THREAD_STATS_INC(interrupts);
80 KEVLOG_IRQ_ENTER(vector);
81
82 enum handler_return ret = INT_NO_RESCHEDULE;
83 if (handlers[vector].handler) {
84 ret = handlers[vector].handler(handlers[vector].arg);
85 }
86
87 // ack the interrupt
88 *REG32(PLIC_COMPLETE(riscv_current_hart())) = vector;
89
90 KEVLOG_IRQ_EXIT(vector);
91
92 return ret;
93 }
94
95