189 lines
6.8 KiB
Diff
189 lines
6.8 KiB
Diff
|
From: John Ogness <john.ogness@linutronix.de>
|
||
|
Date: Wed, 4 Sep 2024 14:11:20 +0206
|
||
|
Subject: [PATCH 38/54] printk: nbcon: Add function for printers to reacquire
|
||
|
ownership
|
||
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.11/older/patches-6.11-rt7.tar.xz
|
||
|
|
||
|
Since ownership can be lost at any time due to handover or
|
||
|
takeover, a printing context _must_ be prepared to back out
|
||
|
immediately and carefully. However, there are scenarios where
|
||
|
the printing context must reacquire ownership in order to
|
||
|
finalize or revert hardware changes.
|
||
|
|
||
|
One such example is when interrupts are disabled during
|
||
|
printing. No other context will automagically re-enable the
|
||
|
interrupts. For this case, the disabling context _must_
|
||
|
reacquire nbcon ownership so that it can re-enable the
|
||
|
interrupts.
|
||
|
|
||
|
Provide nbcon_reacquire_nobuf() for exactly this purpose. It
|
||
|
allows a printing context to reacquire ownership using the same
|
||
|
priority as its previous ownership.
|
||
|
|
||
|
Note that after a successful reacquire the printing context
|
||
|
will have no output buffer because that has been lost. This
|
||
|
function cannot be used to resume printing.
|
||
|
|
||
|
Signed-off-by: John Ogness <john.ogness@linutronix.de>
|
||
|
Reviewed-by: Petr Mladek <pmladek@suse.com>
|
||
|
Link: https://lore.kernel.org/r/20240904120536.115780-2-john.ogness@linutronix.de
|
||
|
Signed-off-by: Petr Mladek <pmladek@suse.com>
|
||
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||
|
---
|
||
|
include/linux/console.h | 6 +++
|
||
|
kernel/printk/nbcon.c | 74 +++++++++++++++++++++++++++++++++++++++++++-----
|
||
|
2 files changed, 73 insertions(+), 7 deletions(-)
|
||
|
|
||
|
--- a/include/linux/console.h
|
||
|
+++ b/include/linux/console.h
|
||
|
@@ -366,6 +366,10 @@ struct console {
|
||
|
*
|
||
|
* The callback should allow the takeover whenever it is safe. It
|
||
|
* increases the chance to see messages when the system is in trouble.
|
||
|
+ * If the driver must reacquire ownership in order to finalize or
|
||
|
+ * revert hardware changes, nbcon_reacquire_nobuf() can be used.
|
||
|
+ * However, on reacquire the buffer content is no longer available. A
|
||
|
+ * reacquire cannot be used to resume printing.
|
||
|
*
|
||
|
* The callback can be called from any context (including NMI).
|
||
|
* Therefore it must avoid usage of any locking and instead rely
|
||
|
@@ -558,12 +562,14 @@ extern void nbcon_cpu_emergency_exit(voi
|
||
|
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
|
||
|
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
|
||
|
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
|
||
|
+extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
|
||
|
#else
|
||
|
static inline void nbcon_cpu_emergency_enter(void) { }
|
||
|
static inline void nbcon_cpu_emergency_exit(void) { }
|
||
|
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
|
||
|
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
|
||
|
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
|
||
|
+static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
|
||
|
#endif
|
||
|
|
||
|
extern int console_set_on_cmdline;
|
||
|
--- a/kernel/printk/nbcon.c
|
||
|
+++ b/kernel/printk/nbcon.c
|
||
|
@@ -830,6 +830,19 @@ static bool __nbcon_context_update_unsaf
|
||
|
return nbcon_context_can_proceed(ctxt, &cur);
|
||
|
}
|
||
|
|
||
|
+static void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
|
||
|
+ char *buf, unsigned int len)
|
||
|
+{
|
||
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
||
|
+ struct console *con = ctxt->console;
|
||
|
+ struct nbcon_state cur;
|
||
|
+
|
||
|
+ wctxt->outbuf = buf;
|
||
|
+ wctxt->len = len;
|
||
|
+ nbcon_state_read(con, &cur);
|
||
|
+ wctxt->unsafe_takeover = cur.unsafe_takeover;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* nbcon_enter_unsafe - Enter an unsafe region in the driver
|
||
|
* @wctxt: The write context that was handed to the write function
|
||
|
@@ -845,8 +858,12 @@ static bool __nbcon_context_update_unsaf
|
||
|
bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt)
|
||
|
{
|
||
|
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
||
|
+ bool is_owner;
|
||
|
|
||
|
- return nbcon_context_enter_unsafe(ctxt);
|
||
|
+ is_owner = nbcon_context_enter_unsafe(ctxt);
|
||
|
+ if (!is_owner)
|
||
|
+ nbcon_write_context_set_buf(wctxt, NULL, 0);
|
||
|
+ return is_owner;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(nbcon_enter_unsafe);
|
||
|
|
||
|
@@ -865,12 +882,44 @@ EXPORT_SYMBOL_GPL(nbcon_enter_unsafe);
|
||
|
bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt)
|
||
|
{
|
||
|
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
||
|
+ bool ret;
|
||
|
|
||
|
- return nbcon_context_exit_unsafe(ctxt);
|
||
|
+ ret = nbcon_context_exit_unsafe(ctxt);
|
||
|
+ if (!ret)
|
||
|
+ nbcon_write_context_set_buf(wctxt, NULL, 0);
|
||
|
+ return ret;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(nbcon_exit_unsafe);
|
||
|
|
||
|
/**
|
||
|
+ * nbcon_reacquire_nobuf - Reacquire a console after losing ownership
|
||
|
+ * while printing
|
||
|
+ * @wctxt: The write context that was handed to the write callback
|
||
|
+ *
|
||
|
+ * Since ownership can be lost at any time due to handover or takeover, a
|
||
|
+ * printing context _must_ be prepared to back out immediately and
|
||
|
+ * carefully. However, there are scenarios where the printing context must
|
||
|
+ * reacquire ownership in order to finalize or revert hardware changes.
|
||
|
+ *
|
||
|
+ * This function allows a printing context to reacquire ownership using the
|
||
|
+ * same priority as its previous ownership.
|
||
|
+ *
|
||
|
+ * Note that after a successful reacquire the printing context will have no
|
||
|
+ * output buffer because that has been lost. This function cannot be used to
|
||
|
+ * resume printing.
|
||
|
+ */
|
||
|
+void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
|
||
|
+{
|
||
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
||
|
+
|
||
|
+ while (!nbcon_context_try_acquire(ctxt))
|
||
|
+ cpu_relax();
|
||
|
+
|
||
|
+ nbcon_write_context_set_buf(wctxt, NULL, 0);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
|
||
|
+
|
||
|
+/**
|
||
|
* nbcon_emit_next_record - Emit a record in the acquired context
|
||
|
* @wctxt: The write context that will be handed to the write function
|
||
|
*
|
||
|
@@ -895,7 +944,6 @@ static bool nbcon_emit_next_record(struc
|
||
|
.pbufs = ctxt->pbufs,
|
||
|
};
|
||
|
unsigned long con_dropped;
|
||
|
- struct nbcon_state cur;
|
||
|
unsigned long dropped;
|
||
|
|
||
|
/*
|
||
|
@@ -930,10 +978,7 @@ static bool nbcon_emit_next_record(struc
|
||
|
goto update_con;
|
||
|
|
||
|
/* Initialize the write context for driver callbacks. */
|
||
|
- wctxt->outbuf = &pmsg.pbufs->outbuf[0];
|
||
|
- wctxt->len = pmsg.outbuf_len;
|
||
|
- nbcon_state_read(con, &cur);
|
||
|
- wctxt->unsafe_takeover = cur.unsafe_takeover;
|
||
|
+ nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
|
||
|
|
||
|
if (con->write_atomic) {
|
||
|
con->write_atomic(con, wctxt);
|
||
|
@@ -947,6 +992,21 @@ static bool nbcon_emit_next_record(struc
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
+ if (!wctxt->outbuf) {
|
||
|
+ /*
|
||
|
+ * Ownership was lost and reacquired by the driver. Handle it
|
||
|
+ * as if ownership was lost.
|
||
|
+ */
|
||
|
+ nbcon_context_release(ctxt);
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Ownership may have been lost but _not_ reacquired by the driver.
|
||
|
+ * This case is detected and handled when entering unsafe to update
|
||
|
+ * dropped/seq values.
|
||
|
+ */
|
||
|
+
|
||
|
/*
|
||
|
* Since any dropped message was successfully output, reset the
|
||
|
* dropped count for the console.
|