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