diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/chp.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index c602211ab94e..46be25c7461e 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -38,7 +38,6 @@ enum cfg_task_t { /* Map for pending configure tasks. */ static enum cfg_task_t chp_cfg_task[__MAX_CSSID + 1][__MAX_CHPID + 1]; static DEFINE_SPINLOCK(cfg_lock); -static int cfg_busy; /* Map for channel-path status. */ static struct sclp_chp_info chp_info; @@ -666,6 +665,20 @@ static void cfg_set_task(struct chp_id chpid, enum cfg_task_t cfg) chp_cfg_task[chpid.cssid][chpid.id] = cfg; } +/* Fetch the first configure task. Set chpid accordingly. */ +static enum cfg_task_t chp_cfg_fetch_task(struct chp_id *chpid) +{ + enum cfg_task_t t = cfg_none; + + chp_id_for_each(chpid) { + t = cfg_get_task(*chpid); + if (t != cfg_none) + break; + } + + return t; +} + /* Perform one configure/deconfigure request. Reschedule work function until * last request. */ static void cfg_func(struct work_struct *work) @@ -675,14 +688,7 @@ static void cfg_func(struct work_struct *work) int rc; spin_lock(&cfg_lock); - t = cfg_none; - chp_id_for_each(&chpid) { - t = cfg_get_task(chpid); - if (t != cfg_none) { - cfg_set_task(chpid, cfg_none); - break; - } - } + t = chp_cfg_fetch_task(&chpid); spin_unlock(&cfg_lock); switch (t) { @@ -709,12 +715,13 @@ static void cfg_func(struct work_struct *work) case cfg_none: /* Get updated information after last change. */ info_update(); - spin_lock(&cfg_lock); - cfg_busy = 0; - spin_unlock(&cfg_lock); wake_up_interruptible(&cfg_wait_queue); return; } + spin_lock(&cfg_lock); + if (t == cfg_get_task(chpid)) + cfg_set_task(chpid, cfg_none); + spin_unlock(&cfg_lock); schedule_work(&cfg_work); } @@ -731,7 +738,6 @@ void chp_cfg_schedule(struct chp_id chpid, int configure) configure); spin_lock(&cfg_lock); cfg_set_task(chpid, configure ? cfg_configure : cfg_deconfigure); - cfg_busy = 1; spin_unlock(&cfg_lock); schedule_work(&cfg_work); } @@ -752,9 +758,21 @@ void chp_cfg_cancel_deconfigure(struct chp_id chpid) spin_unlock(&cfg_lock); } +static bool cfg_idle(void) +{ + struct chp_id chpid; + enum cfg_task_t t; + + spin_lock(&cfg_lock); + t = chp_cfg_fetch_task(&chpid); + spin_unlock(&cfg_lock); + + return t == cfg_none; +} + static int cfg_wait_idle(void) { - if (wait_event_interruptible(cfg_wait_queue, !cfg_busy)) + if (wait_event_interruptible(cfg_wait_queue, cfg_idle())) return -ERESTARTSYS; return 0; } |