diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-02-13 07:02:32 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-03-04 04:41:04 -0500 |
commit | 84ec96a6150477b9509664557bc6ad4eaa21f72a (patch) | |
tree | c43505c1a361a69e0d9df17c18b8bc4275ea27cc | |
parent | 2e0210432d34bc7f01644905c2bb2d5d9be5b6ac (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>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/airq.h | 14 | ||||
-rw-r--r-- | drivers/s390/cio/airq.c | 66 |
2 files changed, 53 insertions, 27 deletions
diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h index 4bbb5957ed1b..bd93ff6661b8 100644 --- a/arch/s390/include/asm/airq.h +++ b/arch/s390/include/asm/airq.h | |||
@@ -44,11 +44,21 @@ struct airq_iv { | |||
44 | 44 | ||
45 | struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags); | 45 | struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags); |
46 | void airq_iv_release(struct airq_iv *iv); | 46 | void airq_iv_release(struct airq_iv *iv); |
47 | unsigned long airq_iv_alloc_bit(struct airq_iv *iv); | 47 | unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num); |
48 | void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit); | 48 | void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num); |
49 | unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, | 49 | unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, |
50 | unsigned long end); | 50 | unsigned long end); |
51 | 51 | ||
52 | static inline unsigned long airq_iv_alloc_bit(struct airq_iv *iv) | ||
53 | { | ||
54 | return airq_iv_alloc(iv, 1); | ||
55 | } | ||
56 | |||
57 | static inline void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit) | ||
58 | { | ||
59 | airq_iv_free(iv, bit, 1); | ||
60 | } | ||
61 | |||
52 | static inline unsigned long airq_iv_end(struct airq_iv *iv) | 62 | static inline unsigned long airq_iv_end(struct airq_iv *iv) |
53 | { | 63 | { |
54 | return iv->end; | 64 | return iv->end; |
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 |