diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-02-13 07:02:32 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-02-21 02:50:22 -0500 |
commit | fe7c30a420761654777d3cc15412fc7626407e93 (patch) | |
tree | 95f4377d7aced89fb5511fa2de3521e30347dac8 /drivers/s390/cio | |
parent | ec66ad66a0de87866be347b5ecc83bd46427f53b (diff) |
s390/airq: add support for irq ranges
Add airq_iv_alloc and airq_iv_free to allocate and free consecutive
ranges of irqs from the interrupt vector.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/airq.c | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index f055df0b167f..445564c790f6 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c | |||
@@ -186,55 +186,71 @@ void airq_iv_release(struct airq_iv *iv) | |||
186 | EXPORT_SYMBOL(airq_iv_release); | 186 | EXPORT_SYMBOL(airq_iv_release); |
187 | 187 | ||
188 | /** | 188 | /** |
189 | * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector | 189 | * airq_iv_alloc - allocate irq bits from an interrupt vector |
190 | * @iv: pointer to an interrupt vector structure | 190 | * @iv: pointer to an interrupt vector structure |
191 | * @num: number of consecutive irq bits to allocate | ||
191 | * | 192 | * |
192 | * Returns the bit number of the allocated irq, or -1UL if no bit | 193 | * Returns the bit number of the first irq in the allocated block of irqs, |
193 | * is available or the AIRQ_IV_ALLOC flag has not been specified | 194 | * or -1UL if no bit is available or the AIRQ_IV_ALLOC flag has not been |
195 | * specified | ||
194 | */ | 196 | */ |
195 | unsigned long airq_iv_alloc_bit(struct airq_iv *iv) | 197 | unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num) |
196 | { | 198 | { |
197 | unsigned long bit; | 199 | unsigned long bit, i; |
198 | 200 | ||
199 | if (!iv->avail) | 201 | if (!iv->avail || num == 0) |
200 | return -1UL; | 202 | return -1UL; |
201 | spin_lock(&iv->lock); | 203 | spin_lock(&iv->lock); |
202 | bit = find_first_bit_inv(iv->avail, iv->bits); | 204 | bit = find_first_bit_inv(iv->avail, iv->bits); |
203 | if (bit < iv->bits) { | 205 | while (bit + num <= iv->bits) { |
204 | clear_bit_inv(bit, iv->avail); | 206 | for (i = 1; i < num; i++) |
205 | if (bit >= iv->end) | 207 | if (!test_bit_inv(bit + i, iv->avail)) |
206 | iv->end = bit + 1; | 208 | break; |
207 | } else | 209 | if (i >= num) { |
210 | /* Found a suitable block of irqs */ | ||
211 | for (i = 0; i < num; i++) | ||
212 | clear_bit_inv(bit + i, iv->avail); | ||
213 | if (bit + num >= iv->end) | ||
214 | iv->end = bit + num + 1; | ||
215 | break; | ||
216 | } | ||
217 | bit = find_next_bit_inv(iv->avail, iv->bits, bit + i + 1); | ||
218 | } | ||
219 | if (bit + num > iv->bits) | ||
208 | bit = -1UL; | 220 | bit = -1UL; |
209 | spin_unlock(&iv->lock); | 221 | spin_unlock(&iv->lock); |
210 | return bit; | 222 | return bit; |
211 | 223 | ||
212 | } | 224 | } |
213 | EXPORT_SYMBOL(airq_iv_alloc_bit); | 225 | EXPORT_SYMBOL(airq_iv_alloc); |
214 | 226 | ||
215 | /** | 227 | /** |
216 | * airq_iv_free_bit - free an irq bit of an interrupt vector | 228 | * airq_iv_free - free irq bits of an interrupt vector |
217 | * @iv: pointer to interrupt vector structure | 229 | * @iv: pointer to interrupt vector structure |
218 | * @bit: number of the irq bit to free | 230 | * @bit: number of the first irq bit to free |
231 | * @num: number of consecutive irq bits to free | ||
219 | */ | 232 | */ |
220 | void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit) | 233 | void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num) |
221 | { | 234 | { |
222 | if (!iv->avail) | 235 | unsigned long i; |
236 | |||
237 | if (!iv->avail || num == 0) | ||
223 | return; | 238 | return; |
224 | spin_lock(&iv->lock); | 239 | spin_lock(&iv->lock); |
225 | /* Clear (possibly left over) interrupt bit */ | 240 | for (i = 0; i < num; i++) { |
226 | clear_bit_inv(bit, iv->vector); | 241 | /* Clear (possibly left over) interrupt bit */ |
227 | /* Make the bit position available again */ | 242 | clear_bit_inv(bit + i, iv->vector); |
228 | set_bit_inv(bit, iv->avail); | 243 | /* Make the bit positions available again */ |
229 | if (bit == iv->end - 1) { | 244 | set_bit_inv(bit + i, iv->avail); |
245 | } | ||
246 | if (bit + num >= iv->end) { | ||
230 | /* Find new end of bit-field */ | 247 | /* Find new end of bit-field */ |
231 | while (--iv->end > 0) | 248 | while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail)) |
232 | if (!test_bit_inv(iv->end - 1, iv->avail)) | 249 | iv->end--; |
233 | break; | ||
234 | } | 250 | } |
235 | spin_unlock(&iv->lock); | 251 | spin_unlock(&iv->lock); |
236 | } | 252 | } |
237 | EXPORT_SYMBOL(airq_iv_free_bit); | 253 | EXPORT_SYMBOL(airq_iv_free); |
238 | 254 | ||
239 | /** | 255 | /** |
240 | * airq_iv_scan - scan interrupt vector for non-zero bits | 256 | * airq_iv_scan - scan interrupt vector for non-zero bits |