1 /*- 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * BSD LICENSE 6 * 7 * Copyright 2013-2016 Freescale Semiconductor Inc. 8 * Copyright 2017 NXP. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are met: 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * * Neither the name of the above-listed copyright holders nor the 18 * names of any contributors may be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * GPL LICENSE SUMMARY 22 * 23 * ALTERNATIVELY, this software may be distributed under the terms of the 24 * GNU General Public License ("GPL") as published by the Free Software 25 * Foundation, either version 2 of that License or (at your option) any 26 * later version. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 #include <process.h> 42 #include "dpaa_sys.h" 43 44 struct process_interrupt { 45 int irq; 46 irqreturn_t (*isr)(int irq, void *arg); 47 unsigned long flags; 48 const char *name; 49 void *arg; 50 struct list_head node; 51 }; 52 53 static COMPAT_LIST_HEAD(process_irq_list); 54 static pthread_mutex_t process_irq_lock = PTHREAD_MUTEX_INITIALIZER; 55 56 static void process_interrupt_install(struct process_interrupt *irq) 57 { 58 int ret; 59 /* Add the irq to the end of the list */ 60 ret = pthread_mutex_lock(&process_irq_lock); 61 assert(!ret); 62 list_add_tail(&irq->node, &process_irq_list); 63 ret = pthread_mutex_unlock(&process_irq_lock); 64 assert(!ret); 65 } 66 67 static void process_interrupt_remove(struct process_interrupt *irq) 68 { 69 int ret; 70 71 ret = pthread_mutex_lock(&process_irq_lock); 72 assert(!ret); 73 list_del(&irq->node); 74 ret = pthread_mutex_unlock(&process_irq_lock); 75 assert(!ret); 76 } 77 78 static struct process_interrupt *process_interrupt_find(int irq_num) 79 { 80 int ret; 81 struct process_interrupt *i = NULL; 82 83 ret = pthread_mutex_lock(&process_irq_lock); 84 assert(!ret); 85 list_for_each_entry(i, &process_irq_list, node) { 86 if (i->irq == irq_num) 87 goto done; 88 } 89 done: 90 ret = pthread_mutex_unlock(&process_irq_lock); 91 assert(!ret); 92 return i; 93 } 94 95 /* This is the interface from the platform-agnostic driver code to (de)register 96 * interrupt handlers. We simply create/destroy corresponding structs. 97 */ 98 int qbman_request_irq(int irq, irqreturn_t (*isr)(int irq, void *arg), 99 unsigned long flags, const char *name, 100 void *arg __maybe_unused) 101 { 102 struct process_interrupt *irq_node = 103 kmalloc(sizeof(*irq_node), GFP_KERNEL); 104 105 if (!irq_node) 106 return -ENOMEM; 107 irq_node->irq = irq; 108 irq_node->isr = isr; 109 irq_node->flags = flags; 110 irq_node->name = name; 111 irq_node->arg = arg; 112 process_interrupt_install(irq_node); 113 return 0; 114 } 115 116 int qbman_free_irq(int irq, __maybe_unused void *arg) 117 { 118 struct process_interrupt *irq_node = process_interrupt_find(irq); 119 120 if (!irq_node) 121 return -EINVAL; 122 process_interrupt_remove(irq_node); 123 kfree(irq_node); 124 return 0; 125 } 126 127 /* This is the interface from the platform-specific driver code to obtain 128 * interrupt handlers that have been registered. 129 */ 130 void qbman_invoke_irq(int irq) 131 { 132 struct process_interrupt *irq_node = process_interrupt_find(irq); 133 134 if (irq_node) 135 irq_node->isr(irq, irq_node->arg); 136 } 137