From: Cyril Bur <cyrilbur@gmail.com>
To: linux-mtd@lists.infradead.org, linuxppc-dev@lists.ozlabs.org,
stewart@linux.vnet.ibm.com
Cc: dwmw2@infradead.org, computersforpeace@gmail.com,
boris.brezillon@free-electrons.com, sjitindarsingh@gmail.com
Subject: [PATCH v4 08/10] powerpc/opal: Add opal_async_wait_response_interruptible() to opal-async
Date: Tue, 10 Oct 2017 14:33:00 +1100 [thread overview]
Message-ID: <20171010033302.20854-9-cyrilbur@gmail.com> (raw)
In-Reply-To: <20171010033302.20854-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 0078eb5acf98..f95ca4560bfa 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -307,6 +307,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 fbae8a37ce2c..e2004606b75b 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_UNALLOCATED = 0,
ASYNC_TOKEN_ALLOCATED,
+ ASYNC_TOKEN_DISPATCHED,
+ ASYNC_TOKEN_ABANDONED,
ASYNC_TOKEN_COMPLETED
};
@@ -58,8 +60,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)
@@ -96,6 +100,16 @@ static int __opal_async_release_token(int token)
opal_async_tokens[token].state = ASYNC_TOKEN_UNALLOCATED;
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;
}
@@ -128,7 +142,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.
*/
@@ -141,11 +159,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;
@@ -153,11 +226,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.14.2
next prev parent reply other threads:[~2017-10-10 3:33 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-10 3:32 [PATCH v4 00/10] Allow opal-async waiters to get interrupted Cyril Bur
2017-10-10 3:32 ` [PATCH v4 01/10] mtd: powernv_flash: Use WARN_ON_ONCE() rather than BUG_ON() Cyril Bur
2017-10-30 8:49 ` Boris Brezillon
2017-10-10 3:32 ` [PATCH v4 02/10] mtd: powernv_flash: Don't treat OPAL_SUCCESS as an error Cyril Bur
2017-10-30 8:50 ` Boris Brezillon
2017-10-10 3:32 ` [PATCH v4 03/10] mtd: powernv_flash: Remove pointless goto in driver init Cyril Bur
2017-10-30 8:51 ` Boris Brezillon
2017-10-10 3:32 ` [PATCH v4 04/10] mtd: powernv_flash: Don't return -ERESTARTSYS on interrupted token acquisition Cyril Bur
2017-10-30 8:51 ` Boris Brezillon
2017-10-10 3:32 ` [PATCH v4 05/10] powerpc/opal: Make __opal_async_{get, release}_token() static Cyril Bur
2017-10-10 3:32 ` [PATCH v4 06/10] powerpc/opal: Rework the opal-async interface Cyril Bur
2017-10-10 3:32 ` [PATCH v4 07/10] powernv/opal-sensor: remove not needed lock Cyril Bur
2017-10-10 3:33 ` Cyril Bur [this message]
2017-10-10 3:33 ` [PATCH v4 09/10] powerpc/powernv: Add OPAL_BUSY to opal_error_code() Cyril Bur
2017-10-10 3:33 ` [PATCH v4 10/10] mtd: powernv_flash: Use opal_async_wait_response_interruptible() Cyril Bur
2017-10-30 9:14 ` Boris Brezillon
2017-10-30 9:15 ` [PATCH v4 00/10] Allow opal-async waiters to get interrupted Boris Brezillon
2017-10-30 22:52 ` 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=20171010033302.20854-9-cyrilbur@gmail.com \
--to=cyrilbur@gmail.com \
--cc=boris.brezillon@free-electrons.com \
--cc=computersforpeace@gmail.com \
--cc=dwmw2@infradead.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=sjitindarsingh@gmail.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).