diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/airq.c | 19 | ||||
-rw-r--r-- | drivers/s390/cio/eadm_sch.c | 29 | ||||
-rw-r--r-- | drivers/s390/cio/eadm_sch.h | 4 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_debug.h | 8 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 2 |
5 files changed, 38 insertions, 24 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index d028fd800c9..f055df0b167 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -194,15 +194,14 @@ EXPORT_SYMBOL(airq_iv_release); */ unsigned long airq_iv_alloc_bit(struct airq_iv *iv) { - const unsigned long be_to_le = BITS_PER_LONG - 1; unsigned long bit; if (!iv->avail) return -1UL; spin_lock(&iv->lock); - bit = find_first_bit_left(iv->avail, iv->bits); + bit = find_first_bit_inv(iv->avail, iv->bits); if (bit < iv->bits) { - clear_bit(bit ^ be_to_le, iv->avail); + clear_bit_inv(bit, iv->avail); if (bit >= iv->end) iv->end = bit + 1; } else @@ -220,19 +219,17 @@ EXPORT_SYMBOL(airq_iv_alloc_bit); */ void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit) { - const unsigned long be_to_le = BITS_PER_LONG - 1; - if (!iv->avail) return; spin_lock(&iv->lock); /* Clear (possibly left over) interrupt bit */ - clear_bit(bit ^ be_to_le, iv->vector); + clear_bit_inv(bit, iv->vector); /* Make the bit position available again */ - set_bit(bit ^ be_to_le, iv->avail); + set_bit_inv(bit, iv->avail); if (bit == iv->end - 1) { /* Find new end of bit-field */ while (--iv->end > 0) - if (!test_bit((iv->end - 1) ^ be_to_le, iv->avail)) + if (!test_bit_inv(iv->end - 1, iv->avail)) break; } spin_unlock(&iv->lock); @@ -251,15 +248,13 @@ EXPORT_SYMBOL(airq_iv_free_bit); unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, unsigned long end) { - const unsigned long be_to_le = BITS_PER_LONG - 1; unsigned long bit; /* Find non-zero bit starting from 'ivs->next'. */ - bit = find_next_bit_left(iv->vector, end, start); + bit = find_next_bit_inv(iv->vector, end, start); if (bit >= end) return -1UL; - /* Clear interrupt bit (find left uses big-endian bit numbers) */ - clear_bit(bit ^ be_to_le, iv->vector); + clear_bit_inv(bit, iv->vector); return bit; } EXPORT_SYMBOL(airq_iv_scan); diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index d9eddcba7e8..aca7bfc113a 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -6,6 +6,7 @@ */ #include <linux/kernel_stat.h> +#include <linux/completion.h> #include <linux/workqueue.h> #include <linux/spinlock.h> #include <linux/device.h> @@ -42,7 +43,7 @@ static debug_info_t *eadm_debug; static void EADM_LOG_HEX(int level, void *data, int length) { - if (level > eadm_debug->level) + if (!debug_level_enabled(eadm_debug, level)) return; while (length > 0) { debug_event(eadm_debug, level, data, length); @@ -159,6 +160,9 @@ static void eadm_subchannel_irq(struct subchannel *sch) } scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); private->state = EADM_IDLE; + + if (private->completion) + complete(private->completion); } static struct subchannel *eadm_get_idle_sch(void) @@ -255,13 +259,32 @@ out: static void eadm_quiesce(struct subchannel *sch) { + struct eadm_private *private = get_eadm_private(sch); + DECLARE_COMPLETION_ONSTACK(completion); int ret; + spin_lock_irq(sch->lock); + if (private->state != EADM_BUSY) + goto disable; + + if (eadm_subchannel_clear(sch)) + goto disable; + + private->completion = &completion; + spin_unlock_irq(sch->lock); + + wait_for_completion_io(&completion); + + spin_lock_irq(sch->lock); + private->completion = NULL; + +disable: + eadm_subchannel_set_timeout(sch, 0); do { - spin_lock_irq(sch->lock); ret = cio_disable_subchannel(sch); - spin_unlock_irq(sch->lock); } while (ret == -EBUSY); + + spin_unlock_irq(sch->lock); } static int eadm_subchannel_remove(struct subchannel *sch) diff --git a/drivers/s390/cio/eadm_sch.h b/drivers/s390/cio/eadm_sch.h index 2779be09398..9664e4653f9 100644 --- a/drivers/s390/cio/eadm_sch.h +++ b/drivers/s390/cio/eadm_sch.h @@ -1,6 +1,7 @@ #ifndef EADM_SCH_H #define EADM_SCH_H +#include <linux/completion.h> #include <linux/device.h> #include <linux/timer.h> #include <linux/list.h> @@ -9,9 +10,10 @@ struct eadm_private { union orb orb; enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state; + struct completion *completion; + struct subchannel *sch; struct timer_list timer; struct list_head head; - struct subchannel *sch; } __aligned(8); #define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev)) diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index 647b422bb22..dfac9bfefea 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -16,12 +16,6 @@ extern debug_info_t *qdio_dbf_setup; extern debug_info_t *qdio_dbf_error; -/* sort out low debug levels early to avoid wasted sprints */ -static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) -{ - return (level <= dbf_grp->level); -} - #define DBF_ERR 3 /* error conditions */ #define DBF_WARN 4 /* warning conditions */ #define DBF_INFO 6 /* informational */ @@ -65,7 +59,7 @@ static inline void DBF_ERROR_HEX(void *addr, int len) #define DBF_DEV_EVENT(level, device, text...) \ do { \ char debug_buffer[QDIO_DBF_LEN]; \ - if (qdio_dbf_passes(device->debug_area, level)) { \ + if (debug_level_enabled(device->debug_area, level)) { \ snprintf(debug_buffer, QDIO_DBF_LEN, text); \ debug_text_event(device->debug_area, level, debug_buffer); \ } \ diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index bbd3e511c77..3e602e8affa 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -528,7 +528,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) case SLSB_P_INPUT_PRIMED: inbound_primed(q, count); q->first_to_check = add_buf(q->first_to_check, count); - if (atomic_sub(count, &q->nr_buf_used) == 0) + if (atomic_sub_return(count, &q->nr_buf_used) == 0) qperf_inc(q, inbound_queue_full); if (q->irq_ptr->perf_stat_enabled) account_sbals(q, count); |