mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: Magnus Lindholm <linmag7@gmail.com>
Cc: sparclinux@vger.kernel.org,
	"David S . Miller" <davem@davemloft.net>,
	Andreas Larsson <andreas@gaisler.com>,
	linux-kernel@vger.kernel.org, Jiri Slaby <jirislaby@kernel.org>,
	linuxppc-dev@lists.ozlabs.org, linux-serial@vger.kernel.org
Subject: Re: [PATCH 7/7] hvc: add an M3000 firmware console backend
Date: Sun, 4 Oct 2026 14:50:29 +0200	[thread overview]
Message-ID: <2026100415-impromptu-sultry-ce6b@gregkh> (raw)
In-Reply-To: <20261002161515.932316-8-linmag7@gmail.com>

On Fri, Oct 02, 2026 at 06:14:29PM +0200, Magnus Lindholm wrote:
> Provide hvc0 through the IKKAKU Open Firmware pseudo-console, validating
> model and console properties before matching. Serialize firmware calls,
> keep the bounce buffer in locked mappings and poll input each open tick.
> 
> Keep output buffers const and bound no-progress retries because HVC
> retries EAGAIN indefinitely. A stalled firmware call remains unbounded.
> Use the existing SPARC p1275 interface and HVC output contract.
> 
> Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
> ---
>  MAINTAINERS                 |   6 ++
>  drivers/tty/hvc/Kconfig     |  10 +++
>  drivers/tty/hvc/Makefile    |   2 +
>  drivers/tty/hvc/hvc_m3000.c | 167 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 185 insertions(+)
>  create mode 100644 drivers/tty/hvc/hvc_m3000.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3a19da74d00c..5bc9b1cabd0a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10728,6 +10728,12 @@ L:	platform-driver-x86@vger.kernel.org
>  S:	Maintained
>  F:	drivers/platform/x86/fujitsu-laptop.c
>  
> +FUJITSU M3000 FIRMWARE CONSOLE
> +M:	Magnus Lindholm <linmag7@gmail.com>
> +L:	linux-serial@vger.kernel.org
> +S:	Maintained
> +F:	drivers/tty/hvc/hvc_m3000.c
> +
>  FUJITSU TABLET EXTRAS
>  M:	Robert Gerlach <khnz@gmx.de>
>  L:	platform-driver-x86@vger.kernel.org
> diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
> index 5866195de26a..0feb7ec98f4f 100644
> --- a/drivers/tty/hvc/Kconfig
> +++ b/drivers/tty/hvc/Kconfig
> @@ -134,3 +134,13 @@ config HVCS
>  	  will depend on arch specific APIs exported from hvcserver.ko
>  	  which will also be compiled when this driver is built as a
>  	  module.
> +
> +config HVC_M3000
> +	bool "M3000 firmware pseudo-console"
> +	depends on SPARC64_VII
> +	select HVC_DRIVER
> +	help
> +	  Provide hvc0 using Open Firmware stdin/stdout on IKKAKU only.
> +	  Input is polled; no native UART registers are accessed.
> +	  Firmware calls are serialized and use a locked-image bounce buffer.
> +	  Say Y to use the M3000 firmware pseudo-console as hvc0.
> diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
> index 98880e357941..5b0277deb7c9 100644
> --- a/drivers/tty/hvc/Makefile
> +++ b/drivers/tty/hvc/Makefile
> @@ -11,3 +11,5 @@ obj-$(CONFIG_HVC_IUCV)		+= hvc_iucv.o
>  obj-$(CONFIG_HVC_UDBG)		+= hvc_udbg.o
>  obj-$(CONFIG_HVC_RISCV_SBI)	+= hvc_riscv_sbi.o
>  obj-$(CONFIG_HVCS)		+= hvcs.o
> +
> +obj-$(CONFIG_HVC_M3000) += hvc_m3000.o

No need for a blank line, right?  And why no tab used here?

> diff --git a/drivers/tty/hvc/hvc_m3000.c b/drivers/tty/hvc/hvc_m3000.c
> new file mode 100644
> index 000000000000..0ef4c888a6a2
> --- /dev/null
> +++ b/drivers/tty/hvc/hvc_m3000.c
> @@ -0,0 +1,167 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Experimental M3000 Open Firmware pseudo-console backend. */

What will make it not "experimental"?

And no copyright?



> +#include <linux/console.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/irqflags.h>
> +#include <linux/string.h>
> +#include <linux/spinlock.h>
> +#include <linux/timer.h>
> +#include <asm/oplib.h>
> +#include <asm/spitfire.h>
> +#include "hvc_console.h"
> +
> +#define M3000_WRITE_ATTEMPTS 8

why 8?

> +
> +static int m3000_stdin;
> +static bool m3000_ready;
> +/* Keep firmware buffers within the locked kernel image mappings. */
> +static u8 m3000_buffer[256];
> +static DEFINE_RAW_SPINLOCK(m3000_buffer_lock);
> +static struct timer_list m3000_poll_timer;
> +static bool m3000_poll_active;

Shouldn't these be in a structure attached to the console somewhere?
Otherwise you have limited yourself to just one of these.

> +
> +/*
> + * HVC's idle backoff can exceed the firmware input FIFO's capacity.
> + * Wake its worker each tick while open; keep PROM calls out of the timer.
> + */
> +static void m3000_poll_tick(struct timer_list *timer)
> +{
> +	if (!READ_ONCE(m3000_poll_active))
> +		return;

Why are you accessing m3000_poll_active like this in an attempt to not
use a real lock?  Are you _sure_ a bool will work this way properly?

> +	hvc_kick();
> +	mod_timer(&m3000_poll_timer, jiffies + 1);
> +}
> +
> +static int m3000_open(struct hvc_struct *hp, int data)
> +{
> +	WRITE_ONCE(m3000_poll_active, true);
> +	mod_timer(&m3000_poll_timer, jiffies + 1);
> +	return 0;
> +}
> +
> +static void m3000_close(struct hvc_struct *hp, int data)
> +{
> +	WRITE_ONCE(m3000_poll_active, false);
> +	timer_delete_sync(&m3000_poll_timer);
> +}
> +
> +static ssize_t m3000_io(u8 *in, const u8 *out, size_t count)
> +{
> +	unsigned long args[7], flags;
> +	bool input = in != NULL;
> +	int ret;
> +
> +	if (!count)
> +		return 0;
> +	count = min_t(size_t, count, input ? 1 : sizeof(m3000_buffer));

No need for min_t(), why not just min()?

> +	/* Serialize the bounce buffer; p1275 separately serializes firmware. */
> +	raw_spin_lock_irqsave(&m3000_buffer_lock, flags);

why is this a "raw" spinlock?

> +	if (!input)
> +		memcpy(m3000_buffer, out, count);
> +	args[0] = (unsigned long)(input ? "read" : "write");

A string being cast to an unsigned long?  Are you _sure_?

> +	args[1] = 3;
> +	args[2] = 1;
> +	args[3] = (unsigned int)(input ? m3000_stdin : prom_stdout);
> +	args[4] = (unsigned long)m3000_buffer;
> +	args[5] = count;
> +	args[6] = (unsigned long)-1;
> +	p1275_cmd_direct(args);
> +	ret = (int)args[6];
> +	if (ret > 0 && ret <= count && input)
> +		memcpy(in, m3000_buffer, ret);
> +	raw_spin_unlock_irqrestore(&m3000_buffer_lock, flags);
> +	if (ret == -2 || ret == 0)
> +		return input ? 0 : -EAGAIN;
> +	if (ret < 0 || ret > count)
> +		return -EIO;
> +	return ret;
> +}
> +
> +static ssize_t m3000_get(u32 termno, u8 *buf, size_t count)
> +{
> +	return m3000_io(buf, NULL, count);
> +}
> +
> +static ssize_t m3000_put(u32 termno, const u8 *buf, size_t count)
> +{
> +	ssize_t ret;
> +	int attempt;
> +
> +	/*
> +	 * HVC retries -EAGAIN forever, so drop this chunk without logging when
> +	 * the no-progress budget expires. This cannot bound a stalled firmware
> +	 * call or lock acquisition.
> +	 */
> +	for (attempt = 0; attempt < M3000_WRITE_ATTEMPTS; attempt++) {
> +		ret = m3000_io(NULL, buf, count);
> +		if (ret != -EAGAIN)
> +			return ret;
> +		cpu_relax();
> +	}
> +	return -EIO;
> +}
> +
> +static const struct hv_ops m3000_ops = {
> +	.get_chars = m3000_get,
> +	.put_chars = m3000_put,
> +	.notifier_add = m3000_open,
> +	.notifier_del = m3000_close,
> +	.notifier_hangup = m3000_close,
> +};
> +
> +static bool __init m3000_property_matches(phandle node, const char *prop,
> +					 const char *expected)
> +{
> +	char value[64];
> +	int len;
> +
> +	len = prom_getproperty(node, prop, value, sizeof(value) - 1);
> +	if (len <= 0)
> +		return false;
> +	value[len] = '\0';
> +	return !strcmp(value, expected);
> +}
> +
> +static int __init m3000_console_init(void)
> +{
> +	phandle node;
> +	int ret;
> +
> +	if (tlb_type != sparc64_vii)
> +		return -ENODEV;
> +	if (!m3000_property_matches(prom_finddevice("/"), "model", "IKKAKU"))
> +		return -ENODEV;
> +	m3000_stdin = prom_getint(prom_chosen_node, "stdin");
> +	if (!m3000_stdin || m3000_stdin == -1 || !prom_stdout || prom_stdout == -1)
> +		return -ENODEV;
> +	node = prom_inst2pkg(prom_stdout);
> +	if (!m3000_property_matches(node, "name", "pseudo-console"))
> +		return -ENODEV;
> +	node = prom_inst2pkg(m3000_stdin);
> +	if (!m3000_property_matches(node, "name", "pseudo-console"))
> +		return -ENODEV;
> +	ret = hvc_instantiate(0, 0, &m3000_ops);
> +	if (ret < 0)
> +		return ret;
> +	m3000_ready = true;
> +	return 0;
> +}
> +console_initcall(m3000_console_init);
> +
> +static int __init m3000_tty_init(void)
> +{
> +	struct hvc_struct *hp;
> +
> +	if (!m3000_ready)
> +		return -ENODEV;
> +	timer_setup(&m3000_poll_timer, m3000_poll_tick, 0);
> +	hp = hvc_alloc(0, 0, &m3000_ops, sizeof(m3000_buffer));
> +	if (IS_ERR(hp))
> +		return PTR_ERR(hp);
> +	hp->ws.ws_row = 24;
> +	hp->ws.ws_col = 80;
> +	pr_info("M3000: firmware-backed hvc0 tty ready (serialized, polled input)\n");

When drivers work properly, they are quiet.

thanks,

greg k-h

  reply	other threads:[~2026-10-04 12:50 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-02 16:14 [PATCH 0/7] sparc64: add Fujitsu M3000 support Magnus Lindholm
2026-10-02 16:14 ` [PATCH 1/7] sparc64: return from the generic clear_page implementation Magnus Lindholm
2026-10-02 16:14 ` [PATCH 2/7] sparc64: honor queued spinlock layout in secondary startup Magnus Lindholm
2026-10-02 16:14 ` [PATCH 3/7] sparc64: avoid huge kernel PUD mappings on sun4u Magnus Lindholm
2026-10-02 16:14 ` [PATCH 4/7] sparc64: add SPARC64 VII CPU, MMU and SMP support Magnus Lindholm
2026-10-04 14:59   ` Krzysztof Kozlowski
2026-10-04 15:39     ` Magnus Lindholm
2026-10-02 16:14 ` [PATCH 5/7] sparc64: add M3000 Oberon PCIe support Magnus Lindholm
2026-10-02 16:14 ` [PATCH 6/7] tg3: normalize inherited M3000 register byte order Magnus Lindholm
2026-10-02 16:14 ` [PATCH 7/7] hvc: add an M3000 firmware console backend Magnus Lindholm
2026-10-04 12:50   ` Greg Kroah-Hartman [this message]
2026-10-04 15:24     ` Magnus Lindholm

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=2026100415-impromptu-sultry-ce6b@gregkh \
    --to=gregkh@linuxfoundation.org \
    --cc=andreas@gaisler.com \
    --cc=davem@davemloft.net \
    --cc=jirislaby@kernel.org \
    --cc=linmag7@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=sparclinux@vger.kernel.org \
    /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

all inboxes | Powered by JetHome®