From: Peter Hurley <peter@hurleysoftware.com>
To: Bin Gao <bin.gao@linux.intel.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>,
One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>,
linux-kernel@vger.kernel.org,
"linux-serial@vger.kernel.org" <linux-serial@vger.kernel.org>
Subject: Re: [PATCH v4 1/2] serial_core: add pci uart early console support
Date: Tue, 26 May 2015 13:12:34 -0400 [thread overview]
Message-ID: <5564A982.9050600@hurleysoftware.com> (raw)
In-Reply-To: <20150522160659.GA108447@worksta>
Hi Bin,
Please don't drop lists (or other addressees) from patch revisions.
[ +cc linux-serial]
On 05/22/2015 12:06 PM, Bin Gao wrote:
> On some Intel Atom SoCs, the legacy IO port UART(0x3F8) is not available.
> Instead, a 8250 compatible PCI uart can be used as early console.
> This patch adds pci support to the 8250 early console driver uart8250.
> For example, to enable pci uart(00:21.3) as early console on these
> platforms, append the following line to the kernel command line
> (assume baud rate is 115200):
> earlyprintk=uart8250,pci32,0:24.2,115200n8
>
> Signed-off-by: Bin Gao <bin.gao@intel.com>
> ---
> Changes in v4:
> - moved PCI_EARLY definition from arch/x86/Kconfig to drivers/pci/Kconfig
> - added 'earlyprintk' for x86 as alias to the early param 'earlycon'
> arch/x86/Kconfig | 1 +
> drivers/pci/Kconfig | 11 +++
> drivers/tty/serial/earlycon.c | 9 +++
> drivers/tty/serial/serial_core.c | 145 ++++++++++++++++++++++++++++++++++++++-
Please update Documentation/kernel-parameters.txt with pci-specific
earlycon parameter formats.
> 4 files changed, 164 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 226d569..bdedd61 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -143,6 +143,7 @@ config X86
> select ACPI_LEGACY_TABLES_LOOKUP if ACPI
> select X86_FEATURE_NAMES if PROC_FS
> select SRCU
> + select PCI_EARLY if PCI
>
> config INSTRUCTION_DECODER
> def_bool y
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index 7a8f1c5..4f0f055 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -114,4 +114,15 @@ config PCI_LABEL
> def_bool y if (DMI || ACPI)
> select NLS
>
> +config PCI_EARLY
> + bool "Early PCI access"
> + depends on PCI
> + default n
> + help
> + This option indicates that a group of APIs are available (in
> + asm/pci-direct.h) so the kernel can access pci config registers
> + before the PCI subsystem is initialized. Any arch that supports
> + early pci APIs should enable this option which is required by
> + arch independent codes, e.g. uart8250 pci early console driver.
> +
> source "drivers/pci/host/Kconfig"
> diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
> index 6dc471e..63ae60e 100644
> --- a/drivers/tty/serial/earlycon.c
> +++ b/drivers/tty/serial/earlycon.c
> @@ -193,6 +193,15 @@ static int __init param_setup_earlycon(char *buf)
> }
> early_param("earlycon", param_setup_earlycon);
>
> +/* x86 uses "earlyprintk=xxx", so we keep the compatibility here */
> +#ifdef CONFIG_X86
> +static int __init param_setup_earlycon_x86(char *buf)
> +{
> + return param_setup_earlycon(buf);
> +}
> +early_param("earlyprintk", param_setup_earlycon_x86);
> +#endif
> +
Please move this hunk to patch 2/2.
FYI, there is a proposal to evaluate "earlyprintk=" earlier than
parse_early_params(), which this would break.
https://lkml.org/lkml/2015/5/18/127
> int __init of_setup_earlycon(unsigned long addr,
> int (*setup)(struct earlycon_device *, const char *))
> {
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 0b7bb12..19ca2a0 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -34,10 +34,15 @@
> #include <linux/serial_core.h>
> #include <linux/delay.h>
> #include <linux/mutex.h>
> +#include <linux/pci_regs.h>
>
> #include <asm/irq.h>
> #include <asm/uaccess.h>
>
> +#ifdef CONFIG_PCI_EARLY
> +#include <asm/pci-direct.h>
> +#endif
> +
> /*
> * This is used to lock changes in serial line configuration.
> */
> @@ -1808,6 +1813,110 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
> return ports + idx;
> }
>
> +static int parse_bdf(char *options, char **endp, char delimiter, u8 *val)
If this function is only used from parse_pci_options(), please enclose it
in #ifdef CONFIG_PCI_EARLY scope with parse_pci_options().
> +{
> + char str[4]; /* max 3 chars, plus a NULL terminator */
> + char *p = options;
> + int i = 0;
> +
> + while (*p) {
> + if (i >= 4)
> + return -EINVAL;
> +
> + if (*p == delimiter) {
> + str[i++] = 0;
> + if (endp)
> + *endp = p + 1;
> + return kstrtou8(str, 10, val); /* decimal, no hex */
> + }
> +
> + str[i++] = *p++;
> + }
Is all this to avoid using simple_strtoul()?
If yes, I'd rather you use simple_strtoul() like the rest of the console
code and ignore the (misguided) advice that simple_strtoul() is obsolete.
The code above is exactly what is wrong with the kstrto* api.
> +
> + return -EINVAL;
> +}
> +
> +#ifdef CONFIG_PCI_EARLY
> +/*
> + * The whole pci option from the command line is: pci[32],B:D.F[,options]
> + * Examples:
> + * pci,0:21.3,115200n8
> + * pci32,0:21.3
> + * Here pci32 means 8250 UART registers are 32-bit width(regshift = 2).
> + * pci means 8250 UART registers are 8-bit width(regshift = 0).
> + * B,D and F are bus, device and function, in decimal(not hex).
> + * The additional options(115200n8) would be parsed by the earlycon framework.
> + *
> + * @options: the pci options
> + * @phys: the pointer to return pci mem or io address
> + * return: <0: error
> + * 0: pci mem
> + * 1: pci io
> + */
> +static int parse_pci_options(char *options, unsigned long *phys)
> +{
> + u8 bus, dev, func;
> + char *endp;
> + u64 bar0;
> + u16 cmd;
> + int pci_io = 0;
> +
> + if (!early_pci_allowed()) {
> + pr_err("earlycon pci not available(early pci not allowed)\n");
Error message is redundant.
> + return -EINVAL;
> + }
> +
> + /* We come here with options=B:D.F[,options] */
> + if (parse_bdf(options, &endp, ':', &bus))
> + goto failed;
> +
> + if (parse_bdf(endp, &endp, '.', &dev))
> + goto failed;
> +
> + if (parse_bdf(endp, &endp, ',', &func))
> + goto failed;
> +
> + /*
> + * On these platforms class code in pci config is broken,
^^^^^^^^^^^^^^^
which platforms?
> + * so skip checking it.
> + */
> +
> + bar0 = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0);
> +
> + /* The BAR is IO or Memory? */
> + if ((bar0 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
> + pci_io = 1;
> +
> + if ((bar0 & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
> + PCI_BASE_ADDRESS_MEM_TYPE_64)
> + bar0 |= (u64)read_pci_config(bus, dev, func,
> + PCI_BASE_ADDRESS_0 + 4) << 32;
> +
> + *phys = bar0 & (pci_io ? PCI_BASE_ADDRESS_IO_MASK :
> + PCI_BASE_ADDRESS_MEM_MASK);
> +
> + /* Enable address decoding */
> + cmd = read_pci_config_16(bus, dev, func, PCI_COMMAND);
> + write_pci_config_16(bus, dev, func, PCI_COMMAND,
> + cmd | (pci_io ? PCI_COMMAND_IO : PCI_COMMAND_MEMORY));
> +
> + pr_info("Use 8250 uart at PCI 0000:%02u:%02u.%01u as early console\n",
> + bus, dev, func);
I think one earlycon banner is sufficient; you could make this pr_debug()
instead. Existing convention for earlycon messages is
"earlycon: ...."
> + return pci_io;
> +
> +failed:
> + pr_err("Invalid earlycon pci parameters\n");
> + return -EINVAL;
> +}
> +
> +#else
> +static int parse_pci_options(char *options, unsigned long *phys)
> +{
> + pr_err("earlycon pci not available(need CONFIG_PCI_EARLY)\n");
"earlycon: PCI not supported (requires CONFIG_PCI_EARLY=y)" ?
> + return -EINVAL;
> +}
> +#endif
> +
> /**
> * uart_parse_earlycon - Parse earlycon options
> * @p: ptr to 2nd field (ie., just beyond '<name>,')
> @@ -1816,8 +1925,9 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
> * @options: ptr for <options> field; NULL if not present (out)
> *
> * Decodes earlycon kernel command line parameters of the form
> - * earlycon=<name>,io|mmio|mmio32,<addr>,<options>
> + * earlycon=<name>,io|mmio|mmio32|pci|pci32,<addr>,<options>
Document the pci/pci32 format separately because
earlycon=uart8250,pci32,<addr>,<options> is not a valid form.
> * console=<name>,io|mmio|mmio32,<addr>,<options>
> + * For pci/pci32, the <addr> format is B:D.F, e.g. 0:24.2
> *
> * The optional form
> * earlycon=<name>,0x<addr>,<options>
> @@ -1829,12 +1939,23 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
> int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
> char **options)
> {
> + int pci = 0, ret;
> + unsigned long phys;
> +
> if (strncmp(p, "mmio,", 5) == 0) {
> *iotype = UPIO_MEM;
> p += 5;
> } else if (strncmp(p, "mmio32,", 7) == 0) {
> *iotype = UPIO_MEM32;
> p += 7;
> + } else if (strncmp(p, "pci,", 4) == 0) {
> + pci = 1;
> + p += 4;
> + ret = parse_pci_options(p, &phys);
> + } else if (strncmp(p, "pci32,", 6) == 0) {
> + pci = 2;
> + p += 6;
> + ret = parse_pci_options(p, &phys);
> } else if (strncmp(p, "io,", 3) == 0) {
> *iotype = UPIO_PORT;
> p += 3;
> @@ -1844,7 +1965,27 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
> return -EINVAL;
> }
>
> - *addr = simple_strtoul(p, NULL, 0);
> + if (pci) {
> + if (ret < 0) /* error */
> + return ret;
> +
> + /*
> + * Once PCI mem/io is read from PCI BAR, we can reuse
> + * mmio/mmio32/io type to minimize code change.
> + */
> + if (ret > 0) /* PCI io */
> + *iotype = UPIO_PORT;
> + else { /* ret = 0: PCI mem */
> + if (pci == 2)
> + *iotype = UPIO_MEM32;
> + else
> + *iotype = UPIO_MEM;
> + }
> +
> + *addr = phys;
> + } else
> + *addr = simple_strtoul(p, NULL, 0);
> +
I'd like to see this refactored without the logic steering locals.
Like this:
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
+ *addr = simple_strtoul(p, NULL, 0);
} else if (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32;
p += 7;
+ *addr = simple_strtoul(p, NULL, 0);
+ } else if (strncmp(p, "pci,", 4) == 0) {
+ pci = 1;
+ p += 4;
+ ret = parse_pci_options(p, addr);
+ if (ret < 0)
+ return ret;
+ *iotype = (ret > 0) ? UPIO_PORT : UPIO_MEM;
+ } else if (strncmp(p, "pci32,", 6) == 0) {
+ pci = 2;
+ p += 6;
+ ret = parse_pci_options(p, addr);
+ if (ret < 0)
+ return ret;
+ *iotype = (ret > 0) ? UPIO_PORT : UPIO_MEM32;
} else if (strncmp(p, "io,", 3) == 0) {
*iotype = UPIO_PORT;
p += 3;
+ *addr = simple_strtoul(p, NULL, 0);
Regards,
Peter Hurley
> - *addr = simple_strtoul(p, NULL, 0);
> p = strchr(p, ',');
> if (p)
> p++;
>
next prev parent reply other threads:[~2015-05-26 17:12 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-22 16:06 [PATCH v4 1/2] serial_core: add pci uart early console support Bin Gao
2015-05-24 19:52 ` Greg Kroah-Hartman
2015-05-27 23:18 ` Bin Gao
2015-05-26 17:12 ` Peter Hurley [this message]
2015-05-27 23:14 ` Bin Gao
2015-05-28 0:21 ` Peter Hurley
2015-05-28 17:54 ` Bin Gao
-- strict thread matches above, loose matches on Subject: below --
2015-05-21 17:57 Bin Gao
2015-05-20 21:17 Bin Gao
2015-05-21 4:31 ` Greg Kroah-Hartman
2015-05-21 18:00 ` Bin Gao
2015-05-22 5:11 ` Greg Kroah-Hartman
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=5564A982.9050600@hurleysoftware.com \
--to=peter@hurleysoftware.com \
--cc=bin.gao@linux.intel.com \
--cc=gnomes@lxorguk.ukuu.org.uk \
--cc=gregkh@linuxfoundation.org \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.