Commit 263c8454 authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Heiko Carstens

s390/ap: introduce low frequency polling possibility

For some events the ap bus needs to poll. For example
when an AP queue is reset until the reset is through.
Also when no interrupt support is available (e.g. zVM)
there is a need to poll until all requests have been
processed and all replies have been delivered.

Polling is done with a high resolution timer by default
run with a rate of 4kHz (LPAR) or 666Hz (zVM guest).

For some events (wait for reset complete, wait for irq
enabled complete) this is a much too high poll rate
which triggers a lot of TAPQ invocations.

This patch introduces the possibility for the state
machine functions to return a new wait enum
AP_SM_WAIT_LOW_TIMEOUT which gives a hint to the
ap_wait() function to eventually set up the timer
with a more relaxed timeout value of 25Hz.

This patch also includes a slight rework of the sysfs
functions parsing the timer related stuff: Use of
kstrtobool and kstrtoul instead of sscanf.
Signed-off-by: default avatarHarald Freudenberger <freude@linux.ibm.com>
Reviewed-by: default avatarHolger Dengler <dengler@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent c81cf436
......@@ -122,7 +122,13 @@ static struct hrtimer ap_poll_timer;
* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
* If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.
*/
static unsigned long long poll_timeout = 250000;
static unsigned long poll_high_timeout = 250000UL;
/*
* Some state machine states only require a low frequency polling.
* We use 25 Hz frequency for these.
*/
static unsigned long poll_low_timeout = 40000000UL;
/* Maximum domain id, if not given via qci */
static int ap_max_domain_id = 15;
......@@ -413,10 +419,13 @@ void ap_wait(enum ap_sm_wait wait)
break;
}
fallthrough;
case AP_SM_WAIT_TIMEOUT:
case AP_SM_WAIT_LOW_TIMEOUT:
case AP_SM_WAIT_HIGH_TIMEOUT:
spin_lock_bh(&ap_poll_timer_lock);
if (!hrtimer_is_queued(&ap_poll_timer)) {
hr_time = poll_timeout;
hr_time =
wait == AP_SM_WAIT_LOW_TIMEOUT ?
poll_low_timeout : poll_high_timeout;
hrtimer_forward_now(&ap_poll_timer, hr_time);
hrtimer_restart(&ap_poll_timer);
}
......@@ -1270,11 +1279,14 @@ static ssize_t poll_thread_show(struct bus_type *bus, char *buf)
static ssize_t poll_thread_store(struct bus_type *bus,
const char *buf, size_t count)
{
int flag, rc;
bool value;
int rc;
if (sscanf(buf, "%d\n", &flag) != 1)
return -EINVAL;
if (flag) {
rc = kstrtobool(buf, &value);
if (rc)
return rc;
if (value) {
rc = ap_poll_thread_start();
if (rc)
count = rc;
......@@ -1288,21 +1300,25 @@ static BUS_ATTR_RW(poll_thread);
static ssize_t poll_timeout_show(struct bus_type *bus, char *buf)
{
return sysfs_emit(buf, "%llu\n", poll_timeout);
return sysfs_emit(buf, "%lu\n", poll_high_timeout);
}
static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
size_t count)
{
unsigned long long time;
unsigned long value;
ktime_t hr_time;
int rc;
rc = kstrtoul(buf, 0, &value);
if (rc)
return rc;
/* 120 seconds = maximum poll interval */
if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 ||
time > 120000000000ULL)
if (value > 120000000000UL)
return -EINVAL;
poll_timeout = time;
hr_time = poll_timeout;
poll_high_timeout = value;
hr_time = poll_high_timeout;
spin_lock_bh(&ap_poll_timer_lock);
hrtimer_cancel(&ap_poll_timer);
......@@ -2265,7 +2281,7 @@ static int __init ap_module_init(void)
* If we are running under z/VM adjust polling to z/VM polling rate.
*/
if (MACHINE_IS_VM)
poll_timeout = 1500000;
poll_high_timeout = 1500000;
hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
ap_poll_timer.function = ap_poll_timeout;
......
......@@ -108,10 +108,11 @@ enum ap_sm_event {
* AP queue state wait behaviour
*/
enum ap_sm_wait {
AP_SM_WAIT_AGAIN = 0, /* retry immediately */
AP_SM_WAIT_TIMEOUT, /* wait for timeout */
AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */
AP_SM_WAIT_NONE, /* no wait */
AP_SM_WAIT_AGAIN = 0, /* retry immediately */
AP_SM_WAIT_HIGH_TIMEOUT, /* poll high freq, wait for timeout */
AP_SM_WAIT_LOW_TIMEOUT, /* poll low freq, wait for timeout */
AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */
AP_SM_WAIT_NONE, /* no wait */
NR_AP_SM_WAIT
};
......
......@@ -221,7 +221,7 @@ static enum ap_sm_wait ap_sm_read(struct ap_queue *aq)
case AP_RESPONSE_NO_PENDING_REPLY:
if (aq->queue_count > 0)
return aq->interrupt ?
AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT;
AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_HIGH_TIMEOUT;
aq->sm_state = AP_SM_STATE_IDLE;
return AP_SM_WAIT_NONE;
default:
......@@ -277,10 +277,10 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
case AP_RESPONSE_Q_FULL:
aq->sm_state = AP_SM_STATE_QUEUE_FULL;
return aq->interrupt ?
AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT;
AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_HIGH_TIMEOUT;
case AP_RESPONSE_RESET_IN_PROGRESS:
aq->sm_state = AP_SM_STATE_RESET_WAIT;
return AP_SM_WAIT_TIMEOUT;
return AP_SM_WAIT_LOW_TIMEOUT;
case AP_RESPONSE_INVALID_DOMAIN:
AP_DBF_WARN("%s RESPONSE_INVALID_DOMAIN on NQAP\n", __func__);
fallthrough;
......@@ -328,7 +328,7 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq)
case AP_RESPONSE_RESET_IN_PROGRESS:
aq->sm_state = AP_SM_STATE_RESET_WAIT;
aq->interrupt = false;
return AP_SM_WAIT_TIMEOUT;
return AP_SM_WAIT_LOW_TIMEOUT;
default:
aq->dev_state = AP_DEV_STATE_ERROR;
aq->last_err_rc = status.response_code;
......@@ -368,7 +368,7 @@ static enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq)
return AP_SM_WAIT_AGAIN;
case AP_RESPONSE_BUSY:
case AP_RESPONSE_RESET_IN_PROGRESS:
return AP_SM_WAIT_TIMEOUT;
return AP_SM_WAIT_LOW_TIMEOUT;
case AP_RESPONSE_Q_NOT_AVAIL:
case AP_RESPONSE_DECONFIGURED:
case AP_RESPONSE_CHECKSTOPPED:
......@@ -412,7 +412,7 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq)
return AP_SM_WAIT_AGAIN;
fallthrough;
case AP_RESPONSE_NO_PENDING_REPLY:
return AP_SM_WAIT_TIMEOUT;
return AP_SM_WAIT_LOW_TIMEOUT;
default:
aq->dev_state = AP_DEV_STATE_ERROR;
aq->last_err_rc = status.response_code;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment