aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2008-07-14 03:58:59 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 04:02:10 -0400
commitda7c5af82879828409f6b81431ac2f9f353ab04e (patch)
treeef5262f45141785e4897e3e2356fcdb710b91b9f /drivers
parent3a3fc29a6d0626fb4897b7391c4e956efbacd394 (diff)
[S390] cio: Allow adapter interrupt handlers per isc.
Enhance the adapter interruption API so that device drivers can register a handler for a specific interruption subclass. This will allow different device drivers to move to differently prioritized subclasses in order to avoid congestion. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/cio/airq.c45
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/cio.h2
-rw-r--r--drivers/s390/cio/qdio.c6
4 files changed, 31 insertions, 24 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 @@
15#include <linux/rcupdate.h> 15#include <linux/rcupdate.h>
16 16
17#include <asm/airq.h> 17#include <asm/airq.h>
18#include <asm/isc.h>
18 19
19#include "cio.h" 20#include "cio.h"
20#include "cio_debug.h" 21#include "cio_debug.h"
@@ -33,15 +34,15 @@ struct airq_t {
33 void *drv_data; 34 void *drv_data;
34}; 35};
35 36
36static union indicator_t indicators; 37static union indicator_t indicators[MAX_ISC];
37static struct airq_t *airqs[NR_AIRQS]; 38static struct airq_t *airqs[MAX_ISC][NR_AIRQS];
38 39
39static int register_airq(struct airq_t *airq) 40static int register_airq(struct airq_t *airq, u8 isc)
40{ 41{
41 int i; 42 int i;
42 43
43 for (i = 0; i < NR_AIRQS; i++) 44 for (i = 0; i < NR_AIRQS; i++)
44 if (!cmpxchg(&airqs[i], NULL, airq)) 45 if (!cmpxchg(&airqs[isc][i], NULL, airq))
45 return i; 46 return i;
46 return -ENOMEM; 47 return -ENOMEM;
47} 48}
@@ -50,18 +51,21 @@ static int register_airq(struct airq_t *airq)
50 * s390_register_adapter_interrupt() - register adapter interrupt handler 51 * s390_register_adapter_interrupt() - register adapter interrupt handler
51 * @handler: adapter handler to be registered 52 * @handler: adapter handler to be registered
52 * @drv_data: driver data passed with each call to the handler 53 * @drv_data: driver data passed with each call to the handler
54 * @isc: isc for which the handler should be called
53 * 55 *
54 * Returns: 56 * Returns:
55 * Pointer to the indicator to be used on success 57 * Pointer to the indicator to be used on success
56 * ERR_PTR() if registration failed 58 * ERR_PTR() if registration failed
57 */ 59 */
58void *s390_register_adapter_interrupt(adapter_int_handler_t handler, 60void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
59 void *drv_data) 61 void *drv_data, u8 isc)
60{ 62{
61 struct airq_t *airq; 63 struct airq_t *airq;
62 char dbf_txt[16]; 64 char dbf_txt[16];
63 int ret; 65 int ret;
64 66
67 if (isc > MAX_ISC)
68 return ERR_PTR(-EINVAL);
65 airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); 69 airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
66 if (!airq) { 70 if (!airq) {
67 ret = -ENOMEM; 71 ret = -ENOMEM;
@@ -69,34 +73,35 @@ void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
69 } 73 }
70 airq->handler = handler; 74 airq->handler = handler;
71 airq->drv_data = drv_data; 75 airq->drv_data = drv_data;
72 ret = register_airq(airq); 76
73 if (ret < 0) 77 ret = register_airq(airq, isc);
74 kfree(airq);
75out: 78out:
76 snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); 79 snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
77 CIO_TRACE_EVENT(4, dbf_txt); 80 CIO_TRACE_EVENT(4, dbf_txt);
78 if (ret < 0) 81 if (ret < 0) {
82 kfree(airq);
79 return ERR_PTR(ret); 83 return ERR_PTR(ret);
80 else 84 } else
81 return &indicators.byte[ret]; 85 return &indicators[isc].byte[ret];
82} 86}
83EXPORT_SYMBOL(s390_register_adapter_interrupt); 87EXPORT_SYMBOL(s390_register_adapter_interrupt);
84 88
85/** 89/**
86 * s390_unregister_adapter_interrupt - unregister adapter interrupt handler 90 * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
87 * @ind: indicator for which the handler is to be unregistered 91 * @ind: indicator for which the handler is to be unregistered
92 * @isc: interruption subclass
88 */ 93 */
89void s390_unregister_adapter_interrupt(void *ind) 94void s390_unregister_adapter_interrupt(void *ind, u8 isc)
90{ 95{
91 struct airq_t *airq; 96 struct airq_t *airq;
92 char dbf_txt[16]; 97 char dbf_txt[16];
93 int i; 98 int i;
94 99
95 i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]); 100 i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]);
96 snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); 101 snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
97 CIO_TRACE_EVENT(4, dbf_txt); 102 CIO_TRACE_EVENT(4, dbf_txt);
98 indicators.byte[i] = 0; 103 indicators[isc].byte[i] = 0;
99 airq = xchg(&airqs[i], NULL); 104 airq = xchg(&airqs[isc][i], NULL);
100 /* 105 /*
101 * Allow interrupts to complete. This will ensure that the airq handle 106 * Allow interrupts to complete. This will ensure that the airq handle
102 * is no longer referenced by any interrupt handler. 107 * is no longer referenced by any interrupt handler.
@@ -108,7 +113,7 @@ EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
108 113
109#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) 114#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
110 115
111void do_adapter_IO(void) 116void do_adapter_IO(u8 isc)
112{ 117{
113 int w; 118 int w;
114 int i; 119 int i;
@@ -120,22 +125,22 @@ void do_adapter_IO(void)
120 * fetch operations. 125 * fetch operations.
121 */ 126 */
122 for (w = 0; w < NR_AIRQ_WORDS; w++) { 127 for (w = 0; w < NR_AIRQ_WORDS; w++) {
123 word = indicators.word[w]; 128 word = indicators[isc].word[w];
124 i = w * NR_AIRQS_PER_WORD; 129 i = w * NR_AIRQS_PER_WORD;
125 /* 130 /*
126 * Check bytes within word for active indicators. 131 * Check bytes within word for active indicators.
127 */ 132 */
128 while (word) { 133 while (word) {
129 if (word & INDICATOR_MASK) { 134 if (word & INDICATOR_MASK) {
130 airq = airqs[i]; 135 airq = airqs[isc][i];
131 if (likely(airq)) 136 if (likely(airq))
132 airq->handler(&indicators.byte[i], 137 airq->handler(&indicators[isc].byte[i],
133 airq->drv_data); 138 airq->drv_data);
134 else 139 else
135 /* 140 /*
136 * Reset ill-behaved indicator. 141 * Reset ill-behaved indicator.
137 */ 142 */
138 indicators.byte[i] = 0; 143 indicators[isc].byte[i] = 0;
139 } 144 }
140 word <<= 8; 145 word <<= 8;
141 i++; 146 i++;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index a4f9130910d6..bf616daeff4c 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -641,7 +641,7 @@ do_IRQ (struct pt_regs *regs)
641 */ 641 */
642 if (tpi_info->adapter_IO == 1 && 642 if (tpi_info->adapter_IO == 1 &&
643 tpi_info->int_type == IO_INTERRUPT_TYPE) { 643 tpi_info->int_type == IO_INTERRUPT_TYPE) {
644 do_adapter_IO(); 644 do_adapter_IO(tpi_info->isc);
645 continue; 645 continue;
646 } 646 }
647 sch = (struct subchannel *)(unsigned long)tpi_info->intparm; 647 sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 49ee6395116d..2e7e571d1200 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -106,7 +106,7 @@ int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
106int cio_tm_intrg(struct subchannel *sch); 106int cio_tm_intrg(struct subchannel *sch);
107 107
108int cio_create_sch_lock(struct subchannel *); 108int cio_create_sch_lock(struct subchannel *);
109void do_adapter_IO(void); 109void do_adapter_IO(u8 isc);
110void do_IRQ(struct pt_regs *); 110void do_IRQ(struct pt_regs *);
111 111
112/* Use with care. */ 112/* Use with care. */
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index f9be265e7e8f..8476f8c35c2d 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -3713,7 +3713,8 @@ tiqdio_register_thinints(void)
3713 char dbf_text[20]; 3713 char dbf_text[20];
3714 3714
3715 tiqdio_ind = 3715 tiqdio_ind =
3716 s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL); 3716 s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL,
3717 TIQDIO_THININT_ISC);
3717 if (IS_ERR(tiqdio_ind)) { 3718 if (IS_ERR(tiqdio_ind)) {
3718 sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind)); 3719 sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
3719 QDIO_DBF_TEXT0(0,setup,dbf_text); 3720 QDIO_DBF_TEXT0(0,setup,dbf_text);
@@ -3729,7 +3730,8 @@ static void
3729tiqdio_unregister_thinints(void) 3730tiqdio_unregister_thinints(void)
3730{ 3731{
3731 if (tiqdio_ind) 3732 if (tiqdio_ind)
3732 s390_unregister_adapter_interrupt(tiqdio_ind); 3733 s390_unregister_adapter_interrupt(tiqdio_ind,
3734 TIQDIO_THININT_ISC);
3733} 3735}
3734 3736
3735static int 3737static int