aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2014-02-13 07:02:32 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-03-04 04:41:04 -0500
commit84ec96a6150477b9509664557bc6ad4eaa21f72a (patch)
treec43505c1a361a69e0d9df17c18b8bc4275ea27cc
parent2e0210432d34bc7f01644905c2bb2d5d9be5b6ac (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.h14
-rw-r--r--drivers/s390/cio/airq.c66
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
45struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags); 45struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
46void airq_iv_release(struct airq_iv *iv); 46void airq_iv_release(struct airq_iv *iv);
47unsigned long airq_iv_alloc_bit(struct airq_iv *iv); 47unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num);
48void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit); 48void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num);
49unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, 49unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
50 unsigned long end); 50 unsigned long end);
51 51
52static inline unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
53{
54 return airq_iv_alloc(iv, 1);
55}
56
57static inline void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
58{
59 airq_iv_free(iv, bit, 1);
60}
61
52static inline unsigned long airq_iv_end(struct airq_iv *iv) 62static 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)
186EXPORT_SYMBOL(airq_iv_release); 186EXPORT_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 */
195unsigned long airq_iv_alloc_bit(struct airq_iv *iv) 197unsigned 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}
213EXPORT_SYMBOL(airq_iv_alloc_bit); 225EXPORT_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 */
220void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit) 233void 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}
237EXPORT_SYMBOL(airq_iv_free_bit); 253EXPORT_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