^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright IBM Corp. 2000, 2009
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Cornelia Huck <cornelia.huck@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Jan Glauber <jang@linux.vnet.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel_stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/rculist.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/qdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/airq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/isc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "cio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "ioasm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "qdio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "qdio_debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Restriction: only 63 iqdio subchannels would have its own indicator,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * after that, subsequent subchannels share one indicator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define TIQDIO_NR_NONSHARED_IND 63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define TIQDIO_SHARED_IND 63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* device state change indicators */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct indicator_t {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u32 ind; /* u32 because of compare-and-swap performance */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) atomic_t count; /* use count, 0 or 1 for non-shared indicators */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* list of thin interrupt input queues */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static LIST_HEAD(tiq_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static DEFINE_MUTEX(tiq_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static struct indicator_t *q_indicators;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u64 last_ai_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* returns addr for the device state change indicator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static u32 *get_indicator(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) for (i = 0; i < TIQDIO_NR_NONSHARED_IND; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (!atomic_cmpxchg(&q_indicators[i].count, 0, 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return &q_indicators[i].ind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* use the shared indicator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) atomic_inc(&q_indicators[TIQDIO_SHARED_IND].count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return &q_indicators[TIQDIO_SHARED_IND].ind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void put_indicator(u32 *addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct indicator_t *ind = container_of(addr, struct indicator_t, ind);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) atomic_dec(&ind->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) void tiqdio_add_device(struct qdio_irq *irq_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) mutex_lock(&tiq_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) list_add_rcu(&irq_ptr->entry, &tiq_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mutex_unlock(&tiq_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) void tiqdio_remove_device(struct qdio_irq *irq_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) mutex_lock(&tiq_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) list_del_rcu(&irq_ptr->entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) mutex_unlock(&tiq_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) synchronize_rcu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) INIT_LIST_HEAD(&irq_ptr->entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static inline int references_shared_dsci(struct qdio_irq *irq_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int test_nonshared_ind(struct qdio_irq *irq_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (!is_thinint_irq(irq_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (references_shared_dsci(irq_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (*irq_ptr->dsci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static inline u32 clear_shared_ind(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (!atomic_read(&q_indicators[TIQDIO_SHARED_IND].count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct qdio_q *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (!references_shared_dsci(irq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) xchg(irq->dsci, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (irq->irq_poll) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq->poll_state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) irq->irq_poll(irq->cdev, irq->int_parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) QDIO_PERF_STAT_INC(irq, int_discarded);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) for_each_input_queue(irq, q, i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * Call inbound processing but not directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * since that could starve other thinint queues.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) tasklet_schedule(&q->tasklet);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * tiqdio_thinint_handler - thin interrupt handler for qdio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * @airq: pointer to adapter interrupt descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * @floating: flag to recognize floating vs. directed interrupts (unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) u32 si_used = clear_shared_ind();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct qdio_irq *irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) last_ai_time = S390_lowcore.int_clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) inc_irq_stat(IRQIO_QAI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* protect tiq_list entries, only changed in activate or shutdown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) list_for_each_entry_rcu(irq, &tiq_list, entry) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* only process queues from changed sets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (unlikely(references_shared_dsci(irq))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (!si_used)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) } else if (!*irq->dsci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) tiqdio_call_inq_handlers(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) QDIO_PERF_STAT_INC(irq, adapter_int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static struct airq_struct tiqdio_airq = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .handler = tiqdio_thinint_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .isc = QDIO_AIRQ_ISC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct chsc_scssc_area *scssc = (void *)irq_ptr->chsc_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) u64 summary_indicator_addr, subchannel_indicator_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) summary_indicator_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) subchannel_indicator_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) summary_indicator_addr = virt_to_phys(tiqdio_airq.lsi_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) subchannel_indicator_addr = virt_to_phys(irq_ptr->dsci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) subchannel_indicator_addr, tiqdio_airq.isc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) scssc->response.code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) DBF_EVENT("setscind");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) DBF_HEX(&summary_indicator_addr, sizeof(summary_indicator_addr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) DBF_HEX(&subchannel_indicator_addr, sizeof(subchannel_indicator_addr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int qdio_establish_thinint(struct qdio_irq *irq_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (!is_thinint_irq(irq_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) irq_ptr->dsci = get_indicator();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) DBF_HEX(&irq_ptr->dsci, sizeof(void *));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) rc = set_subchannel_ind(irq_ptr, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) put_indicator(irq_ptr->dsci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!is_thinint_irq(irq_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /* reset adapter interrupt indicators */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) set_subchannel_ind(irq_ptr, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) put_indicator(irq_ptr->dsci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) int __init qdio_thinint_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) q_indicators = kcalloc(TIQDIO_NR_INDICATORS, sizeof(struct indicator_t),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!q_indicators)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) rc = register_adapter_interrupt(&tiqdio_airq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) DBF_EVENT("RTI:%x", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) kfree(q_indicators);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) void __exit qdio_thinint_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) WARN_ON(!list_empty(&tiq_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) unregister_adapter_interrupt(&tiqdio_airq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) kfree(q_indicators);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }