1 /*
2  * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	nuttx/irq.c
9  * @brief	NuttX libmetal irq definitions.
10  */
11 
12 #include <metal/errno.h>
13 #include <metal/irq_controller.h>
14 #include <metal/alloc.h>
15 #include <nuttx/arch.h>
16 #include <nuttx/irq.h>
17 
metal_irq_save_disable(void)18 unsigned int metal_irq_save_disable(void)
19 {
20 	return up_irq_save();
21 }
22 
metal_irq_restore_enable(unsigned int flags)23 void metal_irq_restore_enable(unsigned int flags)
24 {
25 	up_irq_restore(flags);
26 }
27 
28 /* Implement the default irq controller */
metal_cntr_irq_set_enable(struct metal_irq_controller * cntr,int irq,unsigned int enable)29 static void metal_cntr_irq_set_enable(struct metal_irq_controller *cntr,
30 				      int irq, unsigned int enable)
31 {
32 #ifndef CONFIG_ARCH_NOINTC
33 	if (irq >= 0 && irq < cntr->irq_num) {
34 		if (enable == METAL_IRQ_ENABLE)
35 			up_enable_irq(irq);
36 		else
37 			up_disable_irq(irq);
38 	}
39 #endif
40 }
41 
metal_cntr_irq_handler(int irq,void * context,void * data)42 static int metal_cntr_irq_handler(int irq, void *context, void *data)
43 {
44 	if (context != NULL)
45 		return metal_irq_handle(data, irq);
46 
47 	/* context == NULL mean unregister */
48 	irqchain_detach(irq, metal_cntr_irq_handler, data);
49 	metal_free_memory(data);
50 	return 0;
51 }
52 
metal_cntr_irq_attach(struct metal_irq_controller * cntr,int irq,metal_irq_handler hd,void * arg)53 static int metal_cntr_irq_attach(struct metal_irq_controller *cntr,
54 				 int irq, metal_irq_handler hd, void *arg)
55 {
56 	if (irq < 0 || irq >= cntr->irq_num)
57 		return -EINVAL;
58 
59 	if (hd) {
60 		struct metal_irq *data;
61 
62 		data = metal_allocate_memory(sizeof(*data));
63 		if (data == NULL)
64 			return -ENOMEM;
65 
66 		data->hd  = hd;
67 		data->arg = arg;
68 
69 		irq_attach(irq, metal_cntr_irq_handler, data);
70 	} else {
71 		unsigned int flags;
72 
73 		flags = metal_irq_save_disable();
74 		irq_dispatch(irq, NULL); /* fake a irq request */
75 		metal_irq_restore_enable(flags);
76 	}
77 
78 	return 0;
79 }
80 
metal_cntr_irq_init(void)81 int metal_cntr_irq_init(void)
82 {
83 	static METAL_IRQ_CONTROLLER_DECLARE(metal_cntr_irq,
84 					    0,
85 					    NR_IRQS ? NR_IRQS : 1,
86 					    NULL,
87 					    metal_cntr_irq_set_enable,
88 					    metal_cntr_irq_attach,
89 					    NULL);
90 	return metal_irq_register_controller(&metal_cntr_irq);
91 }
92