1*d81734caSHemant Agrawal /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
290632b75SShreyansh Jain *
390632b75SShreyansh Jain * Copyright 2013-2016 Freescale Semiconductor Inc.
4*d81734caSHemant Agrawal * Copyright 2017 NXP
590632b75SShreyansh Jain *
690632b75SShreyansh Jain */
790632b75SShreyansh Jain
890632b75SShreyansh Jain #include <process.h>
990632b75SShreyansh Jain #include "dpaa_sys.h"
1090632b75SShreyansh Jain
1190632b75SShreyansh Jain struct process_interrupt {
1290632b75SShreyansh Jain int irq;
1390632b75SShreyansh Jain irqreturn_t (*isr)(int irq, void *arg);
1490632b75SShreyansh Jain unsigned long flags;
1590632b75SShreyansh Jain const char *name;
1690632b75SShreyansh Jain void *arg;
1790632b75SShreyansh Jain struct list_head node;
1890632b75SShreyansh Jain };
1990632b75SShreyansh Jain
2090632b75SShreyansh Jain static COMPAT_LIST_HEAD(process_irq_list);
2190632b75SShreyansh Jain static pthread_mutex_t process_irq_lock = PTHREAD_MUTEX_INITIALIZER;
2290632b75SShreyansh Jain
process_interrupt_install(struct process_interrupt * irq)2390632b75SShreyansh Jain static void process_interrupt_install(struct process_interrupt *irq)
2490632b75SShreyansh Jain {
2590632b75SShreyansh Jain int ret;
2690632b75SShreyansh Jain /* Add the irq to the end of the list */
2790632b75SShreyansh Jain ret = pthread_mutex_lock(&process_irq_lock);
2890632b75SShreyansh Jain assert(!ret);
2990632b75SShreyansh Jain list_add_tail(&irq->node, &process_irq_list);
3090632b75SShreyansh Jain ret = pthread_mutex_unlock(&process_irq_lock);
3190632b75SShreyansh Jain assert(!ret);
3290632b75SShreyansh Jain }
3390632b75SShreyansh Jain
process_interrupt_remove(struct process_interrupt * irq)3490632b75SShreyansh Jain static void process_interrupt_remove(struct process_interrupt *irq)
3590632b75SShreyansh Jain {
3690632b75SShreyansh Jain int ret;
3790632b75SShreyansh Jain
3890632b75SShreyansh Jain ret = pthread_mutex_lock(&process_irq_lock);
3990632b75SShreyansh Jain assert(!ret);
4090632b75SShreyansh Jain list_del(&irq->node);
4190632b75SShreyansh Jain ret = pthread_mutex_unlock(&process_irq_lock);
4290632b75SShreyansh Jain assert(!ret);
4390632b75SShreyansh Jain }
4490632b75SShreyansh Jain
process_interrupt_find(int irq_num)4590632b75SShreyansh Jain static struct process_interrupt *process_interrupt_find(int irq_num)
4690632b75SShreyansh Jain {
4790632b75SShreyansh Jain int ret;
4890632b75SShreyansh Jain struct process_interrupt *i = NULL;
4990632b75SShreyansh Jain
5090632b75SShreyansh Jain ret = pthread_mutex_lock(&process_irq_lock);
5190632b75SShreyansh Jain assert(!ret);
5290632b75SShreyansh Jain list_for_each_entry(i, &process_irq_list, node) {
5390632b75SShreyansh Jain if (i->irq == irq_num)
5490632b75SShreyansh Jain goto done;
5590632b75SShreyansh Jain }
5690632b75SShreyansh Jain done:
5790632b75SShreyansh Jain ret = pthread_mutex_unlock(&process_irq_lock);
5890632b75SShreyansh Jain assert(!ret);
5990632b75SShreyansh Jain return i;
6090632b75SShreyansh Jain }
6190632b75SShreyansh Jain
6290632b75SShreyansh Jain /* This is the interface from the platform-agnostic driver code to (de)register
6390632b75SShreyansh Jain * interrupt handlers. We simply create/destroy corresponding structs.
6490632b75SShreyansh Jain */
qbman_request_irq(int irq,irqreturn_t (* isr)(int irq,void * arg),unsigned long flags,const char * name,void * arg __maybe_unused)6590632b75SShreyansh Jain int qbman_request_irq(int irq, irqreturn_t (*isr)(int irq, void *arg),
6690632b75SShreyansh Jain unsigned long flags, const char *name,
6790632b75SShreyansh Jain void *arg __maybe_unused)
6890632b75SShreyansh Jain {
6990632b75SShreyansh Jain struct process_interrupt *irq_node =
7090632b75SShreyansh Jain kmalloc(sizeof(*irq_node), GFP_KERNEL);
7190632b75SShreyansh Jain
7290632b75SShreyansh Jain if (!irq_node)
7390632b75SShreyansh Jain return -ENOMEM;
7490632b75SShreyansh Jain irq_node->irq = irq;
7590632b75SShreyansh Jain irq_node->isr = isr;
7690632b75SShreyansh Jain irq_node->flags = flags;
7790632b75SShreyansh Jain irq_node->name = name;
7890632b75SShreyansh Jain irq_node->arg = arg;
7990632b75SShreyansh Jain process_interrupt_install(irq_node);
8090632b75SShreyansh Jain return 0;
8190632b75SShreyansh Jain }
8290632b75SShreyansh Jain
qbman_free_irq(int irq,__maybe_unused void * arg)8390632b75SShreyansh Jain int qbman_free_irq(int irq, __maybe_unused void *arg)
8490632b75SShreyansh Jain {
8590632b75SShreyansh Jain struct process_interrupt *irq_node = process_interrupt_find(irq);
8690632b75SShreyansh Jain
8790632b75SShreyansh Jain if (!irq_node)
8890632b75SShreyansh Jain return -EINVAL;
8990632b75SShreyansh Jain process_interrupt_remove(irq_node);
9090632b75SShreyansh Jain kfree(irq_node);
9190632b75SShreyansh Jain return 0;
9290632b75SShreyansh Jain }
9390632b75SShreyansh Jain
9490632b75SShreyansh Jain /* This is the interface from the platform-specific driver code to obtain
9590632b75SShreyansh Jain * interrupt handlers that have been registered.
9690632b75SShreyansh Jain */
qbman_invoke_irq(int irq)9790632b75SShreyansh Jain void qbman_invoke_irq(int irq)
9890632b75SShreyansh Jain {
9990632b75SShreyansh Jain struct process_interrupt *irq_node = process_interrupt_find(irq);
10090632b75SShreyansh Jain
10190632b75SShreyansh Jain if (irq_node)
10290632b75SShreyansh Jain irq_node->isr(irq, irq_node->arg);
10390632b75SShreyansh Jain }
104