diff options
Diffstat (limited to 'drivers/s390/crypto/ap_bus.c')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f9f682f19415..60cea6c24349 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -107,6 +107,7 @@ debug_info_t *ap_dbf_info; static bool ap_scan_bus(void); static bool ap_scan_bus_result; /* result of last ap_scan_bus() */ static DEFINE_MUTEX(ap_scan_bus_mutex); /* mutex ap_scan_bus() invocations */ +static struct task_struct *ap_scan_bus_task; /* thread holding the scan mutex */ static atomic64_t ap_scan_bus_count; /* counter ap_scan_bus() invocations */ static int ap_scan_bus_time = AP_CONFIG_TIME; static struct timer_list ap_scan_bus_timer; @@ -733,7 +734,7 @@ static void ap_check_bindings_complete(void) if (!completion_done(&ap_apqn_bindings_complete)) { complete_all(&ap_apqn_bindings_complete); ap_send_bindings_complete_uevent(); - pr_debug("%s all apqn bindings complete\n", __func__); + pr_debug("all apqn bindings complete\n"); } } } @@ -768,7 +769,7 @@ int ap_wait_apqn_bindings_complete(unsigned long timeout) else if (l == 0 && timeout) rc = -ETIME; - pr_debug("%s rc=%d\n", __func__, rc); + pr_debug("rc=%d\n", rc); return rc; } EXPORT_SYMBOL(ap_wait_apqn_bindings_complete); @@ -795,8 +796,7 @@ static int __ap_revise_reserved(struct device *dev, void *dummy) drvres = to_ap_drv(dev->driver)->flags & AP_DRIVER_FLAG_DEFAULT; if (!!devres != !!drvres) { - pr_debug("%s reprobing queue=%02x.%04x\n", - __func__, card, queue); + pr_debug("reprobing queue=%02x.%04x\n", card, queue); rc = device_reprobe(dev); if (rc) AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n", @@ -1000,17 +1000,31 @@ bool ap_bus_force_rescan(void) unsigned long scan_counter = atomic64_read(&ap_scan_bus_count); bool rc = false; - pr_debug(">%s scan counter=%lu\n", __func__, scan_counter); + pr_debug("> scan counter=%lu\n", scan_counter); /* Only trigger AP bus scans after the initial scan is done */ if (scan_counter <= 0) goto out; + /* + * There is one unlikely but nevertheless valid scenario where the + * thread holding the mutex may try to send some crypto load but + * all cards are offline so a rescan is triggered which causes + * a recursive call of ap_bus_force_rescan(). A simple return if + * the mutex is already locked by this thread solves this. + */ + if (mutex_is_locked(&ap_scan_bus_mutex)) { + if (ap_scan_bus_task == current) + goto out; + } + /* Try to acquire the AP scan bus mutex */ if (mutex_trylock(&ap_scan_bus_mutex)) { /* mutex acquired, run the AP bus scan */ + ap_scan_bus_task = current; ap_scan_bus_result = ap_scan_bus(); rc = ap_scan_bus_result; + ap_scan_bus_task = NULL; mutex_unlock(&ap_scan_bus_mutex); goto out; } @@ -1029,7 +1043,7 @@ bool ap_bus_force_rescan(void) mutex_unlock(&ap_scan_bus_mutex); out: - pr_debug("%s rc=%d\n", __func__, rc); + pr_debug("rc=%d\n", rc); return rc; } EXPORT_SYMBOL(ap_bus_force_rescan); @@ -1043,7 +1057,7 @@ static int ap_bus_cfg_chg(struct notifier_block *nb, if (action != CHSC_NOTIFY_AP_CFG) return NOTIFY_DONE; - pr_debug("%s config change, forcing bus rescan\n", __func__); + pr_debug("config change, forcing bus rescan\n"); ap_bus_force_rescan(); @@ -1900,8 +1914,8 @@ static inline void ap_scan_domains(struct ap_card *ac) aq->last_err_rc = AP_RESPONSE_CHECKSTOPPED; } spin_unlock_bh(&aq->lock); - pr_debug("%s(%d,%d) queue dev checkstop on\n", - __func__, ac->id, dom); + pr_debug("(%d,%d) queue dev checkstop on\n", + ac->id, dom); /* 'receive' pending messages with -EAGAIN */ ap_flush_queue(aq); goto put_dev_and_continue; @@ -1911,8 +1925,8 @@ static inline void ap_scan_domains(struct ap_card *ac) if (aq->dev_state > AP_DEV_STATE_UNINITIATED) _ap_queue_init_state(aq); spin_unlock_bh(&aq->lock); - pr_debug("%s(%d,%d) queue dev checkstop off\n", - __func__, ac->id, dom); + pr_debug("(%d,%d) queue dev checkstop off\n", + ac->id, dom); goto put_dev_and_continue; } /* config state change */ @@ -1924,8 +1938,8 @@ static inline void ap_scan_domains(struct ap_card *ac) aq->last_err_rc = AP_RESPONSE_DECONFIGURED; } spin_unlock_bh(&aq->lock); - pr_debug("%s(%d,%d) queue dev config off\n", - __func__, ac->id, dom); + pr_debug("(%d,%d) queue dev config off\n", + ac->id, dom); ap_send_config_uevent(&aq->ap_dev, aq->config); /* 'receive' pending messages with -EAGAIN */ ap_flush_queue(aq); @@ -1936,8 +1950,8 @@ static inline void ap_scan_domains(struct ap_card *ac) if (aq->dev_state > AP_DEV_STATE_UNINITIATED) _ap_queue_init_state(aq); spin_unlock_bh(&aq->lock); - pr_debug("%s(%d,%d) queue dev config on\n", - __func__, ac->id, dom); + pr_debug("(%d,%d) queue dev config on\n", + ac->id, dom); ap_send_config_uevent(&aq->ap_dev, aq->config); goto put_dev_and_continue; } @@ -2009,8 +2023,8 @@ static inline void ap_scan_adapter(int ap) ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); } else { - pr_debug("%s(%d) no type info (no APQN found), ignored\n", - __func__, ap); + pr_debug("(%d) no type info (no APQN found), ignored\n", + ap); } return; } @@ -2022,8 +2036,7 @@ static inline void ap_scan_adapter(int ap) ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); } else { - pr_debug("%s(%d) no valid type (0) info, ignored\n", - __func__, ap); + pr_debug("(%d) no valid type (0) info, ignored\n", ap); } return; } @@ -2202,7 +2215,7 @@ static bool ap_scan_bus(void) bool config_changed; int ap; - pr_debug(">%s\n", __func__); + pr_debug(">\n"); /* (re-)fetch configuration via QCI */ config_changed = ap_get_configuration(); @@ -2243,7 +2256,7 @@ static bool ap_scan_bus(void) } if (atomic64_inc_return(&ap_scan_bus_count) == 1) { - pr_debug("%s init scan complete\n", __func__); + pr_debug("init scan complete\n"); ap_send_init_scan_done_uevent(); } @@ -2251,7 +2264,7 @@ static bool ap_scan_bus(void) mod_timer(&ap_scan_bus_timer, jiffies + ap_scan_bus_time * HZ); - pr_debug("<%s config_changed=%d\n", __func__, config_changed); + pr_debug("< config_changed=%d\n", config_changed); return config_changed; } @@ -2284,7 +2297,9 @@ static void ap_scan_bus_wq_callback(struct work_struct *unused) * system_long_wq which invokes this function here again. */ if (mutex_trylock(&ap_scan_bus_mutex)) { + ap_scan_bus_task = current; ap_scan_bus_result = ap_scan_bus(); + ap_scan_bus_task = NULL; mutex_unlock(&ap_scan_bus_mutex); } } |