1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 *
3 * Copyright 2013-2016 Freescale Semiconductor Inc.
4 * Copyright 2017 NXP
5 *
6 */
7
8 #include <process.h>
9 #include "dpaa_sys.h"
10
11 struct process_interrupt {
12 int irq;
13 irqreturn_t (*isr)(int irq, void *arg);
14 unsigned long flags;
15 const char *name;
16 void *arg;
17 struct list_head node;
18 };
19
20 static COMPAT_LIST_HEAD(process_irq_list);
21 static pthread_mutex_t process_irq_lock = PTHREAD_MUTEX_INITIALIZER;
22
process_interrupt_install(struct process_interrupt * irq)23 static void process_interrupt_install(struct process_interrupt *irq)
24 {
25 int ret;
26 /* Add the irq to the end of the list */
27 ret = pthread_mutex_lock(&process_irq_lock);
28 assert(!ret);
29 list_add_tail(&irq->node, &process_irq_list);
30 ret = pthread_mutex_unlock(&process_irq_lock);
31 assert(!ret);
32 }
33
process_interrupt_remove(struct process_interrupt * irq)34 static void process_interrupt_remove(struct process_interrupt *irq)
35 {
36 int ret;
37
38 ret = pthread_mutex_lock(&process_irq_lock);
39 assert(!ret);
40 list_del(&irq->node);
41 ret = pthread_mutex_unlock(&process_irq_lock);
42 assert(!ret);
43 }
44
process_interrupt_find(int irq_num)45 static struct process_interrupt *process_interrupt_find(int irq_num)
46 {
47 int ret;
48 struct process_interrupt *i = NULL;
49
50 ret = pthread_mutex_lock(&process_irq_lock);
51 assert(!ret);
52 list_for_each_entry(i, &process_irq_list, node) {
53 if (i->irq == irq_num)
54 goto done;
55 }
56 done:
57 ret = pthread_mutex_unlock(&process_irq_lock);
58 assert(!ret);
59 return i;
60 }
61
62 /* This is the interface from the platform-agnostic driver code to (de)register
63 * interrupt handlers. We simply create/destroy corresponding structs.
64 */
qbman_request_irq(int irq,irqreturn_t (* isr)(int irq,void * arg),unsigned long flags,const char * name,void * arg __maybe_unused)65 int qbman_request_irq(int irq, irqreturn_t (*isr)(int irq, void *arg),
66 unsigned long flags, const char *name,
67 void *arg __maybe_unused)
68 {
69 struct process_interrupt *irq_node =
70 kmalloc(sizeof(*irq_node), GFP_KERNEL);
71
72 if (!irq_node)
73 return -ENOMEM;
74 irq_node->irq = irq;
75 irq_node->isr = isr;
76 irq_node->flags = flags;
77 irq_node->name = name;
78 irq_node->arg = arg;
79 process_interrupt_install(irq_node);
80 return 0;
81 }
82
qbman_free_irq(int irq,__maybe_unused void * arg)83 int qbman_free_irq(int irq, __maybe_unused void *arg)
84 {
85 struct process_interrupt *irq_node = process_interrupt_find(irq);
86
87 if (!irq_node)
88 return -EINVAL;
89 process_interrupt_remove(irq_node);
90 kfree(irq_node);
91 return 0;
92 }
93
94 /* This is the interface from the platform-specific driver code to obtain
95 * interrupt handlers that have been registered.
96 */
qbman_invoke_irq(int irq)97 void qbman_invoke_irq(int irq)
98 {
99 struct process_interrupt *irq_node = process_interrupt_find(irq);
100
101 if (irq_node)
102 irq_node->isr(irq, irq_node->arg);
103 }
104