diff options
Diffstat (limited to 'drivers/s390/cio/airq.c')
-rw-r--r-- | drivers/s390/cio/airq.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index b7a07a866291..fe6cea15bbaf 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -15,6 +15,7 @@ #include <linux/rcupdate.h> #include <asm/airq.h> +#include <asm/isc.h> #include "cio.h" #include "cio_debug.h" @@ -33,15 +34,15 @@ struct airq_t { void *drv_data; }; -static union indicator_t indicators; -static struct airq_t *airqs[NR_AIRQS]; +static union indicator_t indicators[MAX_ISC]; +static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; -static int register_airq(struct airq_t *airq) +static int register_airq(struct airq_t *airq, u8 isc) { int i; for (i = 0; i < NR_AIRQS; i++) - if (!cmpxchg(&airqs[i], NULL, airq)) + if (!cmpxchg(&airqs[isc][i], NULL, airq)) return i; return -ENOMEM; } @@ -50,18 +51,21 @@ static int register_airq(struct airq_t *airq) * 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) + 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; @@ -69,34 +73,35 @@ void *s390_register_adapter_interrupt(adapter_int_handler_t handler, } airq->handler = handler; airq->drv_data = drv_data; - ret = register_airq(airq); - if (ret < 0) - kfree(airq); + + ret = register_airq(airq, isc); out: snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); CIO_TRACE_EVENT(4, dbf_txt); - if (ret < 0) + if (ret < 0) { + kfree(airq); return ERR_PTR(ret); - else - return &indicators.byte[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) +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.byte[0]); + 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.byte[i] = 0; - airq = xchg(&airqs[i], NULL); + 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. @@ -108,7 +113,7 @@ EXPORT_SYMBOL(s390_unregister_adapter_interrupt); #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) -void do_adapter_IO(void) +void do_adapter_IO(u8 isc) { int w; int i; @@ -120,22 +125,22 @@ void do_adapter_IO(void) * fetch operations. */ for (w = 0; w < NR_AIRQ_WORDS; w++) { - word = indicators.word[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[i]; + airq = airqs[isc][i]; if (likely(airq)) - airq->handler(&indicators.byte[i], + airq->handler(&indicators[isc].byte[i], airq->drv_data); else /* * Reset ill-behaved indicator. */ - indicators.byte[i] = 0; + indicators[isc].byte[i] = 0; } word <<= 8; i++; |