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 static struct kmem_cache *airq_iv_cache; 31 32 /** 33 * register_adapter_interrupt() - register adapter interrupt handler 34 * @airq: pointer to adapter interrupt descriptor 35 * 36 * Returns 0 on success, or -EINVAL. 37 */ 38 int register_adapter_interrupt(struct airq_struct *airq) 39 { 40 char dbf_txt[32]; 41 42 if (!airq->handler || airq->isc > MAX_ISC) 43 return -EINVAL; 44 if (!airq->lsi_ptr) { 45 airq->lsi_ptr = kzalloc(1, GFP_KERNEL); 46 if (!airq->lsi_ptr) 47 return -ENOMEM; 48 airq->flags |= AIRQ_PTR_ALLOCATED; 49 } 50 if (!airq->lsi_mask) 51 airq->lsi_mask = 0xff; 52 snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%p", airq); 53 CIO_TRACE_EVENT(4, dbf_txt); 54 isc_register(airq->isc); 55 spin_lock(&airq_lists_lock); 56 hlist_add_head_rcu(&airq->list, &airq_lists[airq->isc]); 57 spin_unlock(&airq_lists_lock); 58 return 0; 59 } 60 EXPORT_SYMBOL(register_adapter_interrupt); 61 62 /** 63 * unregister_adapter_interrupt - unregister adapter interrupt handler 64 * @airq: pointer to adapter interrupt descriptor 65 */ 66 void unregister_adapter_interrupt(struct airq_struct *airq) 67 { 68 char dbf_txt[32]; 69 70 if (hlist_unhashed(&airq->list)) 71 return; 72 snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%p", airq); 73 CIO_TRACE_EVENT(4, dbf_txt); 74 spin_lock(&airq_lists_lock); 75 hlist_del_rcu(&airq->list); 76 spin_unlock(&airq_lists_lock); 77 synchronize_rcu(); 78 isc_unregister(airq->isc); 79 if (airq->flags & AIRQ_PTR_ALLOCATED) { 80 kfree(airq->lsi_ptr); 81 airq->lsi_ptr = NULL; 82 airq->flags &= ~AIRQ_PTR_ALLOCATED; 83 } 84 } 85 EXPORT_SYMBOL(unregister_adapter_interrupt); 86 87 static irqreturn_t do_airq_interrupt(int irq, void *dummy) 88 { 89 struct tpi_info *tpi_info; 90 struct airq_struct *airq; 91 struct hlist_head *head; 92 93 set_cpu_flag(CIF_NOHZ_DELAY); 94 tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; 95 trace_s390_cio_adapter_int(tpi_info); 96 head = &airq_lists[tpi_info->isc]; 97 rcu_read_lock(); 98 hlist_for_each_entry_rcu(airq, head, list) 99 if ((*airq->lsi_ptr & airq->lsi_mask) != 0) 100 airq->handler(airq, !tpi_info->directed_irq); 101 rcu_read_unlock(); 102 103 return IRQ_HANDLED; 104 } 105 106 static struct irqaction airq_interrupt = { 107 .name = "AIO", 108 .handler = do_airq_interrupt, 109 }; 110 111 void __init init_airq_interrupts(void) 112 { 113 irq_set_chip_and_handler(THIN_INTERRUPT, 114 &dummy_irq_chip, handle_percpu_irq); 115 setup_irq(THIN_INTERRUPT, &airq_interrupt); 116 } 117 118 /** 119 * airq_iv_create - create an interrupt vector 120 * @bits: number of bits in the interrupt vector 121 * @flags: allocation flags 122 * 123 * Returns a pointer to an interrupt vector structure 124 */ 125 struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) 126 { 127 struct airq_iv *iv; 128 unsigned long size; 129 130 iv = kzalloc(sizeof(*iv), GFP_KERNEL); 131 if (!iv) 132 goto out; 133 iv->bits = bits; 134 iv->flags = flags; 135 size = BITS_TO_LONGS(bits) * sizeof(unsigned long); 136 137 if (flags & AIRQ_IV_CACHELINE) { 138 if ((cache_line_size() * BITS_PER_BYTE) < bits) 139 goto out_free; 140 141 iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL); 142 if (!iv->vector) 143 goto out_free; 144 } else { 145 iv->vector = kzalloc(size, GFP_KERNEL); 146 if (!iv->vector) 147 goto out_free; 148 } 149 if (flags & AIRQ_IV_ALLOC) { 150 iv->avail = kmalloc(size, GFP_KERNEL); 151 if (!iv->avail) 152 goto out_free; 153 memset(iv->avail, 0xff, size); 154 iv->end = 0; 155 } else 156 iv->end = bits; 157 if (flags & AIRQ_IV_BITLOCK) { 158 iv->bitlock = kzalloc(size, GFP_KERNEL); 159 if (!iv->bitlock) 160 goto out_free; 161 } 162 if (flags & AIRQ_IV_PTR) { 163 size = bits * sizeof(unsigned long); 164 iv->ptr = kzalloc(size, GFP_KERNEL); 165 if (!iv->ptr) 166 goto out_free; 167 } 168 if (flags & AIRQ_IV_DATA) { 169 size = bits * sizeof(unsigned int); 170 iv->data = kzalloc(size, GFP_KERNEL); 171 if (!iv->data) 172 goto out_free; 173 } 174 spin_lock_init(&iv->lock); 175 return iv; 176 177 out_free: 178 kfree(iv->ptr); 179 kfree(iv->bitlock); 180 kfree(iv->avail); 181 if (iv->flags & AIRQ_IV_CACHELINE) 182 kmem_cache_free(airq_iv_cache, iv->vector); 183 else 184 kfree(iv->vector); 185 kfree(iv); 186 out: 187 return NULL; 188 } 189 EXPORT_SYMBOL(airq_iv_create); 190 191 /** 192 * airq_iv_release - release an interrupt vector 193 * @iv: pointer to interrupt vector structure 194 */ 195 void airq_iv_release(struct airq_iv *iv) 196 { 197 kfree(iv->data); 198 kfree(iv->ptr); 199 kfree(iv->bitlock); 200 if (iv->flags & AIRQ_IV_CACHELINE) 201 kmem_cache_free(airq_iv_cache, iv->vector); 202 else 203 kfree(iv->vector); 204 kfree(iv->avail); 205 kfree(iv); 206 } 207 EXPORT_SYMBOL(airq_iv_release); 208 209 /** 210 * airq_iv_alloc - allocate irq bits from an interrupt vector 211 * @iv: pointer to an interrupt vector structure 212 * @num: number of consecutive irq bits to allocate 213 * 214 * Returns the bit number of the first irq in the allocated block of irqs, 215 * or -1UL if no bit is available or the AIRQ_IV_ALLOC flag has not been 216 * specified 217 */ 218 unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num) 219 { 220 unsigned long bit, i, flags; 221 222 if (!iv->avail || num == 0) 223 return -1UL; 224 spin_lock_irqsave(&iv->lock, flags); 225 bit = find_first_bit_inv(iv->avail, iv->bits); 226 while (bit + num <= iv->bits) { 227 for (i = 1; i < num; i++) 228 if (!test_bit_inv(bit + i, iv->avail)) 229 break; 230 if (i >= num) { 231 /* Found a suitable block of irqs */ 232 for (i = 0; i < num; i++) 233 clear_bit_inv(bit + i, iv->avail); 234 if (bit + num >= iv->end) 235 iv->end = bit + num + 1; 236 break; 237 } 238 bit = find_next_bit_inv(iv->avail, iv->bits, bit + i + 1); 239 } 240 if (bit + num > iv->bits) 241 bit = -1UL; 242 spin_unlock_irqrestore(&iv->lock, flags); 243 return bit; 244 } 245 EXPORT_SYMBOL(airq_iv_alloc); 246 247 /** 248 * airq_iv_free - free irq bits of an interrupt vector 249 * @iv: pointer to interrupt vector structure 250 * @bit: number of the first irq bit to free 251 * @num: number of consecutive irq bits to free 252 */ 253 void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num) 254 { 255 unsigned long i, flags; 256 257 if (!iv->avail || num == 0) 258 return; 259 spin_lock_irqsave(&iv->lock, flags); 260 for (i = 0; i < num; i++) { 261 /* Clear (possibly left over) interrupt bit */ 262 clear_bit_inv(bit + i, iv->vector); 263 /* Make the bit positions available again */ 264 set_bit_inv(bit + i, iv->avail); 265 } 266 if (bit + num >= iv->end) { 267 /* Find new end of bit-field */ 268 while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail)) 269 iv->end--; 270 } 271 spin_unlock_irqrestore(&iv->lock, flags); 272 } 273 EXPORT_SYMBOL(airq_iv_free); 274 275 /** 276 * airq_iv_scan - scan interrupt vector for non-zero bits 277 * @iv: pointer to interrupt vector structure 278 * @start: bit number to start the search 279 * @end: bit number to end the search 280 * 281 * Returns the bit number of the next non-zero interrupt bit, or 282 * -1UL if the scan completed without finding any more any non-zero bits. 283 */ 284 unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, 285 unsigned long end) 286 { 287 unsigned long bit; 288 289 /* Find non-zero bit starting from 'ivs->next'. */ 290 bit = find_next_bit_inv(iv->vector, end, start); 291 if (bit >= end) 292 return -1UL; 293 clear_bit_inv(bit, iv->vector); 294 return bit; 295 } 296 EXPORT_SYMBOL(airq_iv_scan); 297 298 static int __init airq_init(void) 299 { 300 airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(), 301 cache_line_size(), 0, NULL); 302 if (!airq_iv_cache) 303 return -ENOMEM; 304 return 0; 305 } 306 subsys_initcall(airq_init); 307