From: Cyril Bur <cyrilbur@gmail.com>
To: linuxppc-dev@lists.ozlabs.org, linux-mtd@lists.infradead.org
Cc: benh@kernel.crashing.org, stewart@linux.vnet.ibm.com,
dwmw2@infradead.org, rlippert@google.com, alistair@popple.id.au
Subject: [PATCH v3 08/10] powerpc/opal: Add opal_async_wait_response_interruptible() to opal-async
Date: Wed, 12 Jul 2017 14:23:02 +1000 [thread overview]
Message-ID: <20170712042304.19745-9-cyrilbur@gmail.com> (raw)
In-Reply-To: <20170712042304.19745-1-cyrilbur@gmail.com>
This patch adds an _interruptible version of opal_async_wait_response().
This is useful when a long running OPAL call is performed on behalf of a
userspace thread, for example, the opal_flash_{read,write,erase}
functions performed by the powernv-flash MTD driver.
It is foreseeable that these functions would take upwards of two minutes
causing the wait_event() to block long enough to cause hung task
warnings. Furthermore, wait_event_interruptible() is preferable as
otherwise there is no way for signals to stop the process which is going
to be confusing in userspace.
Signed-off-by: Cyril Bur <cyrilbur@gmail.com>
---
arch/powerpc/include/asm/opal.h | 2 +
arch/powerpc/platforms/powernv/opal-async.c | 87 +++++++++++++++++++++++++++--
2 files changed, 85 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 5553ad2f3e53..6e9e53d744f3 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -294,6 +294,8 @@ extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
extern int opal_async_get_token_interruptible(void);
extern int opal_async_release_token(int token);
extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
+extern int opal_async_wait_response_interruptible(uint64_t token,
+ struct opal_msg *msg);
extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data);
struct rtc_time;
diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c
index d692372a0363..f6b30cfceb8f 100644
--- a/arch/powerpc/platforms/powernv/opal-async.c
+++ b/arch/powerpc/platforms/powernv/opal-async.c
@@ -26,6 +26,8 @@
enum opal_async_token_state {
ASYNC_TOKEN_FREE,
ASYNC_TOKEN_ALLOCATED,
+ ASYNC_TOKEN_DISPATCHED,
+ ASYNC_TOKEN_ABANDONED,
ASYNC_TOKEN_COMPLETED
};
@@ -59,8 +61,10 @@ static int __opal_async_get_token(void)
}
/*
- * Note: If the returned token is used in an opal call and opal returns
- * OPAL_ASYNC_COMPLETION you MUST opal_async_wait_response() before
+ * Note: If the returned token is used in an opal call and opal
+ * returns OPAL_ASYNC_COMPLETION you MUST one of
+ * opal_async_wait_response() or
+ * opal_async_wait_response_interruptible() at least once before
* calling another other opal_async_* function
*/
int opal_async_get_token_interruptible(void)
@@ -97,6 +101,16 @@ static int __opal_async_release_token(int token)
opal_async_tokens[token].state = ASYNC_TOKEN_FREE;
rc = 0;
break;
+ /*
+ * DISPATCHED and ABANDONED tokens must wait for OPAL to
+ * respond.
+ * Mark a DISPATCHED token as ABANDONED so that the response
+ * response handling code knows no one cares and that it can
+ * free it then.
+ */
+ case ASYNC_TOKEN_DISPATCHED:
+ opal_async_tokens[token].state = ASYNC_TOKEN_ABANDONED;
+ /* Fall through */
default:
rc = 1;
}
@@ -129,7 +143,11 @@ int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
return -EINVAL;
}
- /* Wakeup the poller before we wait for events to speed things
+ /*
+ * There is no need to mark the token as dispatched, wait_event()
+ * will block until the token completes.
+ *
+ * Wakeup the poller before we wait for events to speed things
* up on platforms or simulators where the interrupts aren't
* functional.
*/
@@ -142,11 +160,66 @@ int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
}
EXPORT_SYMBOL_GPL(opal_async_wait_response);
+int opal_async_wait_response_interruptible(uint64_t token, struct opal_msg *msg)
+{
+ unsigned long flags;
+ int ret;
+
+ if (token >= opal_max_async_tokens) {
+ pr_err("%s: Invalid token passed\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!msg) {
+ pr_err("%s: Invalid message pointer passed\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * The first time this gets called we mark the token as DISPATCHED
+ * so that if wait_event_interruptible() returns not zero and the
+ * caller frees the token, we know not to actually free the token
+ * until the response comes.
+ *
+ * Only change if the token is ALLOCATED - it may have been
+ * completed even before the caller gets around to calling this
+ * the first time.
+ *
+ * There is also a dirty great comment at the token allocation
+ * function that if the opal call returns OPAL_ASYNC_COMPLETION to
+ * the caller then the caller *must* call this or the not
+ * interruptible version before doing anything else with the
+ * token.
+ */
+ if (opal_async_tokens[token].state == ASYNC_TOKEN_ALLOCATED) {
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ if (opal_async_tokens[token].state == ASYNC_TOKEN_ALLOCATED)
+ opal_async_tokens[token].state = ASYNC_TOKEN_DISPATCHED;
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+ }
+
+ /*
+ * Wakeup the poller before we wait for events to speed things
+ * up on platforms or simulators where the interrupts aren't
+ * functional.
+ */
+ opal_wake_poller();
+ ret = wait_event_interruptible(opal_async_wait,
+ opal_async_tokens[token].state ==
+ ASYNC_TOKEN_COMPLETED);
+ if (!ret)
+ memcpy(msg, &opal_async_tokens[token].response, sizeof(*msg));
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(opal_async_wait_response_interruptible);
+
/* Called from interrupt context */
static int opal_async_comp_event(struct notifier_block *nb,
unsigned long msg_type, void *msg)
{
struct opal_msg *comp_msg = msg;
+ enum opal_async_token_state state;
unsigned long flags;
uint64_t token;
@@ -154,11 +227,17 @@ static int opal_async_comp_event(struct notifier_block *nb,
return 0;
token = be64_to_cpu(comp_msg->params[0]);
- memcpy(&opal_async_tokens[token].response, comp_msg, sizeof(*comp_msg));
spin_lock_irqsave(&opal_async_comp_lock, flags);
+ state = opal_async_tokens[token].state;
opal_async_tokens[token].state = ASYNC_TOKEN_COMPLETED;
spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+ if (state == ASYNC_TOKEN_ABANDONED) {
+ /* Free the token, no one else will */
+ opal_async_release_token(token);
+ return 0;
+ }
+ memcpy(&opal_async_tokens[token].response, comp_msg, sizeof(*comp_msg));
wake_up(&opal_async_wait);
return 0;
--
2.13.2
next prev parent reply other threads:[~2017-07-12 4:23 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-12 4:22 [PATCH v3 00/10] Allow opal-async waiters to get interrupted Cyril Bur
2017-07-12 4:22 ` [PATCH v3 01/10] mtd: powernv_flash: Use WARN_ON_ONCE() rather than BUG_ON() Cyril Bur
2017-07-17 6:19 ` Balbir Singh
2017-07-17 11:33 ` Frans Klaver
2017-07-18 0:27 ` Cyril Bur
2017-07-12 4:22 ` [PATCH v3 02/10] mtd: powernv_flash: Lock around concurrent access to OPAL Cyril Bur
2017-07-17 7:34 ` Balbir Singh
2017-07-17 7:55 ` Cyril Bur
2017-07-17 9:29 ` Balbir Singh
2017-07-18 1:14 ` Cyril Bur
2017-07-18 3:12 ` Michael Ellerman
2017-07-12 4:22 ` [PATCH v3 03/10] mtd: powernv_flash: Don't treat OPAL_SUCCESS as an error Cyril Bur
2017-07-17 8:50 ` Balbir Singh
2017-07-18 0:42 ` Cyril Bur
2017-07-12 4:22 ` [PATCH v3 04/10] mtd: powernv_flash: Remove pointless goto in driver init Cyril Bur
2017-07-12 4:22 ` [PATCH v3 05/10] powerpc/opal: Make __opal_async_{get, release}_token() static Cyril Bur
2017-07-12 4:23 ` [PATCH v3 06/10] powerpc/opal: Rework the opal-async interface Cyril Bur
2017-07-17 11:30 ` Balbir Singh
2017-07-18 0:40 ` Cyril Bur
2017-07-18 3:20 ` Michael Ellerman
2017-07-12 4:23 ` [PATCH v3 07/10] powernv/opal-sensor: remove not needed lock Cyril Bur
2017-07-12 4:23 ` Cyril Bur [this message]
2017-07-12 4:23 ` [PATCH v3 09/10] powerpc/powernv: Add OPAL_BUSY to opal_error_code() Cyril Bur
2017-07-12 4:23 ` [PATCH v3 10/10] mtd: powernv_flash: Use opal_async_wait_response_interruptible() Cyril Bur
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170712042304.19745-9-cyrilbur@gmail.com \
--to=cyrilbur@gmail.com \
--cc=alistair@popple.id.au \
--cc=benh@kernel.crashing.org \
--cc=dwmw2@infradead.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=rlippert@google.com \
--cc=stewart@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).