1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for adapter interruptions 4 * 5 * Copyright IBM Corp. 1999, 2007 6 * Author(s): Ingo Adlung <adlung@de.ibm.com> 7 * Cornelia Huck <cornelia.huck@de.ibm.com> 8 * Arnd Bergmann <arndb@de.ibm.com> 9 * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 10 */ 11 12 #include <linux/init.h> 13 #include <linux/irq.h> 14 #include <linux/kernel_stat.h> 15 #include <linux/module.h> 16 #include <linux/mutex.h> 17 #include <linux/rculist.h> 18 #include <linux/slab.h> 19 20 #include <asm/airq.h> 21 #include <asm/isc.h> 22 23 #include "cio.h" 24 #include "cio_debug.h" 25 #include "ioasm.h" 26 27 static DEFINE_SPINLOCK(airq_lists_lock); 28 static struct hlist_head airq_lists[MAX_ISC+1]; 29 30 /** 31 * register_adapter_interrupt() - register adapter interrupt handler 32 * @airq: pointer to adapter interrupt descriptor 33 * 34 * Returns 0 on success, or -EINVAL. 35 */ 36 int register_adapter_interrupt(struct airq_struct *airq) 37 { 38 char dbf_txt[32]; 39 40 if (!airq->handler || airq->isc > MAX_ISC) 41 return -EINVAL; 42 if (!airq->lsi_ptr) { 43 airq->lsi_ptr = kzalloc(1, GFP_KERNEL); 44 if (!airq->lsi_ptr) 45 return -ENOMEM; 46 airq->flags |= AIRQ_PTR_ALLOCATED; 47 } 48 if (!airq->lsi_mask) 49 airq->lsi_mask = 0xff; 50 snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%p", airq); 51 CIO_TRACE_EVENT(4, dbf_txt); 52 isc_register(airq->isc); 53 spin_lock(&airq_lists_lock); 54 hlist_add_head_rcu(&airq->list, &airq_lists[airq->isc]); 55 spin_unlock(&airq_lists_lock); 56 return 0; 57 } 58 EXPORT_SYMBOL(register_adapter_interrupt); 59 60 /** 61 * unregister_adapter_interrupt - unregister adapter interrupt handler 62 * @airq: pointer to adapter interrupt descriptor 63 */ 64 void unregister_adapter_interrupt(struct airq_struct *airq) 65 { 66 char dbf_txt[32]; 67 68 if (hlist_unhashed(&airq->list)) 69 return; 70 snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%p", airq); 71 CIO_TRACE_EVENT(4, dbf_txt); 72 spin_lock(&airq_lists_lock); 73 hlist_del_rcu(&airq->list); 74 spin_unlock(&airq_lists_lock); 75 synchronize_rcu(); 76 isc_unregister(airq->isc); 77 if (airq->flags & AIRQ_PTR_ALLOCATED) { 78 kfree(airq->lsi_ptr); 79 airq->lsi_ptr = NULL; 80 airq->flags &= ~AIRQ_PTR_ALLOCATED; 81 } 82 } 83 EXPORT_SYMBOL(unregister_adapter_interrupt); 84 85 static irqreturn_t do_airq_interrupt(int irq, void *dummy) 86 { 87 struct tpi_info *tpi_info; 88 struct airq_struct *airq; 89 struct hlist_head *head; 90 91 set_cpu_flag(CIF_NOHZ_DELAY); 92 tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; 93 trace_s390_cio_adapter_int(tpi_info); 94 head = &airq_lists[tpi_info->isc]; 95 rcu_read_lock(); 96 hlist_for_each_entry_rcu(airq, head, list) 97 if ((*airq->lsi_ptr & airq->lsi_mask) != 0) 98 airq->handler(airq); 99 rcu_read_unlock(); 100 101 return IRQ_HANDLED; 102 } 103 104 static struct irqaction airq_interrupt = { 105 .name = "AIO", 106 .handler = do_airq_interrupt, 107 }; 108 109 void __init init_airq_interrupts(void) 110 { 111 irq_set_chip_and_handler(THIN_INTERRUPT, 112 &dummy_irq_chip, handle_percpu_irq); 113 setup_irq(THIN_INTERRUPT, &airq_interrupt); 114 } 115 116 /** 117 * airq_iv_create - create an interrupt vector 118 * @bits: number of bits in the interrupt vector 119 * @flags: allocation flags 120 * 121 * Returns a pointer to an interrupt vector structure 122 */ 123 struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) 124 { 125 struct airq_iv *iv; 126 unsigned long size; 127 128 iv = kzalloc(sizeof(*iv), GFP_KERNEL); 129 if (!iv) 130 goto out; 131 iv->bits = bits; 132 size = BITS_TO_LONGS(bits) * sizeof(unsigned long); 133 iv->vector = kzalloc(size, GFP_KERNEL); 134 if (!iv->vector) 135 goto out_free; 136 if (flags & AIRQ_IV_ALLOC) { 137 iv->avail = kmalloc(size, GFP_KERNEL); 138 if (!iv->avail) 139 goto out_free; 140 memset(iv->avail, 0xff, size); 141 iv->end = 0; 142 } else 143 iv->end = bits; 144 if (flags & AIRQ_IV_BITLOCK) { 145 iv->bitlock = kzalloc(size, GFP_KERNEL); 146 if (!iv->bitlock) 147 goto out_free; 148 } 149 if (flags & AIRQ_IV_PTR) { 150 size = bits * sizeof(unsigned long); 151 iv->ptr = kzalloc(size, GFP_KERNEL); 152 if (!iv->ptr) 153 goto out_free; 154 } 155 if (flags & AIRQ_IV_DATA) { 156 size = bits * sizeof(unsigned int); 157 iv->data = kzalloc(size, GFP_KERNEL); 158 if (!iv->data) 159 goto out_free; 160 } 161 spin_lock_init(&iv->lock); 162 return iv; 163 164 out_free: 165 kfree(iv->ptr); 166 kfree(iv->bitlock); 167 kfree(iv->avail); 168 kfree(iv->vector); 169 kfree(iv); 170 out: 171 return NULL; 172 } 173 EXPORT_SYMBOL(airq_iv_create); 174 175 /** 176 * airq_iv_release - release an interrupt vector 177 * @iv: pointer to interrupt vector structure 178 */ 179 void airq_iv_release(struct airq_iv *iv) 180 { 181 kfree(iv->data); 182 kfree(iv->ptr); 183 kfree(iv->bitlock); 184 kfree(iv->vector); 185 kfree(iv->avail); 186 kfree(iv); 187 } 188 EXPORT_SYMBOL(airq_iv_release); 189 190 /** 191 * airq_iv_alloc - allocate irq bits from an interrupt vector 192 * @iv: pointer to an interrupt vector structure 193 * @num: number of consecutive irq bits to allocate 194 * 195 * Returns the bit number of the first irq in the allocated block of irqs, 196 * or -1UL if no bit is available or the AIRQ_IV_ALLOC flag has not been 197 * specified 198 */ 199 unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num) 200 { 201 unsigned long bit, i, flags; 202 203 if (!iv->avail || num == 0) 204 return -1UL; 205 spin_lock_irqsave(&iv->lock, flags); 206 bit = find_first_bit_inv(iv->avail, iv->bits); 207 while (bit + num <= iv->bits) { 208 for (i = 1; i < num; i++) 209 if (!test_bit_inv(bit + i, iv->avail)) 210 break; 211 if (i >= num) { 212 /* Found a suitable block of irqs */ 213 for (i = 0; i < num; i++) 214 clear_bit_inv(bit + i, iv->avail); 215 if (bit + num >= iv->end) 216 iv->end = bit + num + 1; 217 break; 218 } 219 bit = find_next_bit_inv(iv->avail, iv->bits, bit + i + 1); 220 } 221 if (bit + num > iv->bits) 222 bit = -1UL; 223 spin_unlock_irqrestore(&iv->lock, flags); 224 return bit; 225 } 226 EXPORT_SYMBOL(airq_iv_alloc); 227 228 /** 229 * airq_iv_free - free irq bits of an interrupt vector 230 * @iv: pointer to interrupt vector structure 231 * @bit: number of the first irq bit to free 232 * @num: number of consecutive irq bits to free 233 */ 234 void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num) 235 { 236 unsigned long i, flags; 237 238 if (!iv->avail || num == 0) 239 return; 240 spin_lock_irqsave(&iv->lock, flags); 241 for (i = 0; i < num; i++) { 242 /* Clear (possibly left over) interrupt bit */ 243 clear_bit_inv(bit + i, iv->vector); 244 /* Make the bit positions available again */ 245 set_bit_inv(bit + i, iv->avail); 246 } 247 if (bit + num >= iv->end) { 248 /* Find new end of bit-field */ 249 while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail)) 250 iv->end--; 251 } 252 spin_unlock_irqrestore(&iv->lock, flags); 253 } 254 EXPORT_SYMBOL(airq_iv_free); 255 256 /** 257 * airq_iv_scan - scan interrupt vector for non-zero bits 258 * @iv: pointer to interrupt vector structure 259 * @start: bit number to start the search 260 * @end: bit number to end the search 261 * 262 * Returns the bit number of the next non-zero interrupt bit, or 263 * -1UL if the scan completed without finding any more any non-zero bits. 264 */ 265 unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, 266 unsigned long end) 267 { 268 unsigned long bit; 269 270 /* Find non-zero bit starting from 'ivs->next'. */ 271 bit = find_next_bit_inv(iv->vector, end, start); 272 if (bit >= end) 273 return -1UL; 274 clear_bit_inv(bit, iv->vector); 275 return bit; 276 } 277 EXPORT_SYMBOL(airq_iv_scan); 278