Branch data Line data Source code
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 : 0 : static void process_interrupt_install(struct process_interrupt *irq) 24 : : { 25 : : int ret; 26 : : /* Add the irq to the end of the list */ 27 : 0 : ret = pthread_mutex_lock(&process_irq_lock); 28 [ # # ]: 0 : assert(!ret); 29 : 0 : list_add_tail(&irq->node, &process_irq_list); 30 : 0 : ret = pthread_mutex_unlock(&process_irq_lock); 31 [ # # ]: 0 : assert(!ret); 32 : 0 : } 33 : : 34 : 0 : static void process_interrupt_remove(struct process_interrupt *irq) 35 : : { 36 : : int ret; 37 : : 38 : 0 : ret = pthread_mutex_lock(&process_irq_lock); 39 [ # # ]: 0 : assert(!ret); 40 : 0 : list_del(&irq->node); 41 : 0 : ret = pthread_mutex_unlock(&process_irq_lock); 42 [ # # ]: 0 : assert(!ret); 43 : 0 : } 44 : : 45 : 0 : static struct process_interrupt *process_interrupt_find(int irq_num) 46 : : { 47 : : int ret; 48 : : struct process_interrupt *i = NULL; 49 : : 50 : 0 : ret = pthread_mutex_lock(&process_irq_lock); 51 [ # # ]: 0 : assert(!ret); 52 [ # # ]: 0 : list_for_each_entry(i, &process_irq_list, node) { 53 [ # # ]: 0 : if (i->irq == irq_num) 54 : 0 : goto done; 55 : : } 56 : 0 : done: 57 : 0 : ret = pthread_mutex_unlock(&process_irq_lock); 58 [ # # ]: 0 : assert(!ret); 59 : 0 : 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 : 0 : 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 : 0 : kmalloc(sizeof(*irq_node), GFP_KERNEL); 71 : : 72 [ # # ]: 0 : if (!irq_node) 73 : : return -ENOMEM; 74 : 0 : irq_node->irq = irq; 75 : 0 : irq_node->isr = isr; 76 : 0 : irq_node->flags = flags; 77 : 0 : irq_node->name = name; 78 : 0 : irq_node->arg = arg; 79 : 0 : process_interrupt_install(irq_node); 80 : 0 : return 0; 81 : : } 82 : : 83 : 0 : int qbman_free_irq(int irq, __maybe_unused void *arg) 84 : : { 85 : 0 : struct process_interrupt *irq_node = process_interrupt_find(irq); 86 : : 87 [ # # ]: 0 : if (!irq_node) 88 : : return -EINVAL; 89 : 0 : process_interrupt_remove(irq_node); 90 : 0 : kfree(irq_node); 91 : 0 : 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 : 0 : void qbman_invoke_irq(int irq) 98 : : { 99 : 0 : struct process_interrupt *irq_node = process_interrupt_find(irq); 100 : : 101 [ # # ]: 0 : if (irq_node) 102 : 0 : irq_node->isr(irq, irq_node->arg); 103 : 0 : }