summaryrefslogtreecommitdiff
path: root/drivers/s390/cio/airq.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/s390/cio/airq.c
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/s390/cio/airq.c')
-rw-r--r--drivers/s390/cio/airq.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
new file mode 100644
index 00000000..65d2e769
--- /dev/null
+++ b/drivers/s390/cio/airq.c
@@ -0,0 +1,151 @@
+/*
+ * drivers/s390/cio/airq.c
+ * Support for adapter interruptions
+ *
+ * Copyright IBM Corp. 1999,2007
+ * Author(s): Ingo Adlung <adlung@de.ibm.com>
+ * Cornelia Huck <cornelia.huck@de.ibm.com>
+ * Arnd Bergmann <arndb@de.ibm.com>
+ * Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/rcupdate.h>
+
+#include <asm/airq.h>
+#include <asm/isc.h>
+
+#include "cio.h"
+#include "cio_debug.h"
+
+#define NR_AIRQS 32
+#define NR_AIRQS_PER_WORD sizeof(unsigned long)
+#define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD)
+
+union indicator_t {
+ unsigned long word[NR_AIRQ_WORDS];
+ unsigned char byte[NR_AIRQS];
+} __attribute__((packed));
+
+struct airq_t {
+ adapter_int_handler_t handler;
+ void *drv_data;
+};
+
+static union indicator_t indicators[MAX_ISC+1];
+static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS];
+
+static int register_airq(struct airq_t *airq, u8 isc)
+{
+ int i;
+
+ for (i = 0; i < NR_AIRQS; i++)
+ if (!cmpxchg(&airqs[isc][i], NULL, airq))
+ return i;
+ return -ENOMEM;
+}
+
+/**
+ * s390_register_adapter_interrupt() - register adapter interrupt handler
+ * @handler: adapter handler to be registered
+ * @drv_data: driver data passed with each call to the handler
+ * @isc: isc for which the handler should be called
+ *
+ * Returns:
+ * Pointer to the indicator to be used on success
+ * ERR_PTR() if registration failed
+ */
+void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
+ void *drv_data, u8 isc)
+{
+ struct airq_t *airq;
+ char dbf_txt[16];
+ int ret;
+
+ if (isc > MAX_ISC)
+ return ERR_PTR(-EINVAL);
+ airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
+ if (!airq) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ airq->handler = handler;
+ airq->drv_data = drv_data;
+
+ ret = register_airq(airq, isc);
+out:
+ snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
+ CIO_TRACE_EVENT(4, dbf_txt);
+ if (ret < 0) {
+ kfree(airq);
+ return ERR_PTR(ret);
+ } else
+ return &indicators[isc].byte[ret];
+}
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
+
+/**
+ * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
+ * @ind: indicator for which the handler is to be unregistered
+ * @isc: interruption subclass
+ */
+void s390_unregister_adapter_interrupt(void *ind, u8 isc)
+{
+ struct airq_t *airq;
+ char dbf_txt[16];
+ int i;
+
+ i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]);
+ snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
+ CIO_TRACE_EVENT(4, dbf_txt);
+ indicators[isc].byte[i] = 0;
+ airq = xchg(&airqs[isc][i], NULL);
+ /*
+ * Allow interrupts to complete. This will ensure that the airq handle
+ * is no longer referenced by any interrupt handler.
+ */
+ synchronize_sched();
+ kfree(airq);
+}
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
+
+#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
+
+void do_adapter_IO(u8 isc)
+{
+ int w;
+ int i;
+ unsigned long word;
+ struct airq_t *airq;
+
+ /*
+ * Access indicator array in word-sized chunks to minimize storage
+ * fetch operations.
+ */
+ for (w = 0; w < NR_AIRQ_WORDS; w++) {
+ word = indicators[isc].word[w];
+ i = w * NR_AIRQS_PER_WORD;
+ /*
+ * Check bytes within word for active indicators.
+ */
+ while (word) {
+ if (word & INDICATOR_MASK) {
+ airq = airqs[isc][i];
+ /* Make sure gcc reads from airqs only once. */
+ barrier();
+ if (likely(airq))
+ airq->handler(&indicators[isc].byte[i],
+ airq->drv_data);
+ else
+ /*
+ * Reset ill-behaved indicator.
+ */
+ indicators[isc].byte[i] = 0;
+ }
+ word <<= 8;
+ i++;
+ }
+ }
+}