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 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 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 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 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 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 */ 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