New upstream version 18.02
[deb_dpdk.git] / drivers / bus / dpaa / base / qbman / dpaa_sys.c
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
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
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
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  */
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
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  */
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 }