xref: /optee_os/core/drivers/hfic.c (revision 38376d366fe20fc0dedb69e61489870bcb37368c)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <compiler.h>
8 #include <config.h>
9 #include <drivers/hfic.h>
10 #include <kernel/interrupt.h>
11 #include <kernel/panic.h>
12 #include <kernel/thread.h>
13 
14 /*
15  * For documentation of the paravirtualized interface see:
16  * https://hafnium.readthedocs.io/en/latest/design/secure-partition-manager.html#paravirtualized-interfaces
17  */
18 
19 #define HF_INTERRUPT_ENABLE		0xff03
20 #define HF_INTERRUPT_GET		0xff04
21 #define HF_INTERRUPT_DEACTIVATE		0xff08
22 #define HF_INTERRUPT_RECONFIGURE	0xff09
23 
24 #define HF_INVALID_INTID		0xffffffff
25 #define HF_MAILBOX_READABLE_INTID	1
26 #define HF_MAILBOX_WRITABLE_INTID	2
27 #define HF_VIRTUAL_TIMER_INTID		3
28 #define HF_MANAGED_EXIT_INTID		4
29 #define HF_NOTIFICATION_PENDING_INTID	5
30 #define HF_IPI_INTID			9
31 
32 #define HF_INTERRUPT_TYPE_IRQ	0
33 #define HF_INTERRUPT_TYPE_FIQ	1
34 #define HF_ENABLE		1
35 #define HF_DISABLE		0
36 
37 #define HF_INT_RECONFIGURE_STATUS 2
38 
39 struct hfic_data {
40 	struct itr_chip chip;
41 };
42 
43 static struct hfic_data hfic_data __nex_bss;
44 
hfic_static_it(size_t it)45 static bool __maybe_unused hfic_static_it(size_t it)
46 {
47 	switch (it) {
48 	case HF_MAILBOX_READABLE_INTID:
49 	case HF_MAILBOX_WRITABLE_INTID:
50 	case HF_VIRTUAL_TIMER_INTID:
51 	case HF_MANAGED_EXIT_INTID:
52 	case HF_NOTIFICATION_PENDING_INTID:
53 	case HF_IPI_INTID:
54 		return true;
55 	default:
56 		return false;
57 	}
58 }
59 
hfic_op_configure(struct itr_chip * chip __unused,size_t it,uint32_t type __unused,uint32_t prio __unused)60 static void hfic_op_configure(struct itr_chip *chip __unused, size_t it,
61 			      uint32_t type __unused, uint32_t prio __unused)
62 {
63 	uint32_t res __maybe_unused = 0;
64 
65 	res = thread_hvc(HF_INTERRUPT_ENABLE, it, HF_ENABLE,
66 			 HF_INTERRUPT_TYPE_IRQ);
67 	assert(!res || hfic_static_it(it));
68 }
69 
hfic_op_enable(struct itr_chip * chip __unused,size_t it)70 static void hfic_op_enable(struct itr_chip *chip __unused, size_t it)
71 {
72 	uint32_t res __maybe_unused = 0;
73 
74 	res = thread_hvc(HF_INTERRUPT_RECONFIGURE, it,
75 			 HF_INT_RECONFIGURE_STATUS, HF_ENABLE);
76 	assert(!res || hfic_static_it(it));
77 }
78 
hfic_op_disable(struct itr_chip * chip __unused,size_t it)79 static void hfic_op_disable(struct itr_chip *chip __unused, size_t it)
80 {
81 	uint32_t res __maybe_unused = 0;
82 
83 	res = thread_hvc(HF_INTERRUPT_RECONFIGURE, it,
84 			 HF_INT_RECONFIGURE_STATUS, HF_DISABLE);
85 	assert(!res || hfic_static_it(it));
86 }
87 
88 static const struct itr_ops hfic_ops = {
89 	.configure = hfic_op_configure,
90 	.mask = hfic_op_disable,
91 	.unmask = hfic_op_enable,
92 	.enable = hfic_op_enable,
93 	.disable = hfic_op_disable,
94 };
95 
hfic_init(void)96 void hfic_init(void)
97 {
98 	hfic_data.chip.ops = &hfic_ops;
99 	interrupt_main_init(&hfic_data.chip);
100 }
101 
102 /* Override interrupt_main_handler() with driver implementation */
interrupt_main_handler(void)103 void interrupt_main_handler(void)
104 {
105 	uint32_t id = 0;
106 	uint32_t res __maybe_unused = 0;
107 
108 	id = thread_hvc(HF_INTERRUPT_GET, 0, 0, 0);
109 	if (id == HF_INVALID_INTID) {
110 		DMSG("ignoring invalid interrupt %#"PRIx32, id);
111 		return;
112 	}
113 
114 	interrupt_call_handlers(&hfic_data.chip, id);
115 
116 	res = thread_hvc(HF_INTERRUPT_DEACTIVATE, id, id, 0);
117 	assert(!res);
118 }
119