diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-07-14 03:58:59 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:10 -0400 |
commit | da7c5af82879828409f6b81431ac2f9f353ab04e (patch) | |
tree | ef5262f45141785e4897e3e2356fcdb710b91b9f /drivers/s390/cio/airq.c | |
parent | 3a3fc29a6d0626fb4897b7391c4e956efbacd394 (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/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 @@ | |||
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 | ||
36 | static union indicator_t indicators; | 37 | static union indicator_t indicators[MAX_ISC]; |
37 | static struct airq_t *airqs[NR_AIRQS]; | 38 | static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; |
38 | 39 | ||
39 | static int register_airq(struct airq_t *airq) | 40 | static 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 | */ |
58 | void *s390_register_adapter_interrupt(adapter_int_handler_t handler, | 60 | void *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); | ||
75 | out: | 78 | out: |
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 | } |
83 | EXPORT_SYMBOL(s390_register_adapter_interrupt); | 87 | EXPORT_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 | */ |
89 | void s390_unregister_adapter_interrupt(void *ind) | 94 | void 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 | ||
111 | void do_adapter_IO(void) | 116 | void 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++; |