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