2007-08-16 02:30:23

by Robin Getz

[permalink] [raw]
Subject: Early printk behaviour

I was putting together an early printk implementation for the Blackfin, and
was wondering what the expected behaviour was in this situation.

When I set up my bootargs earlyprintk=serial,ttyBF0,57600 and have no console
defined (no graphical console, no serial console).

based on the patch:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=69331af79cf29e26d1231152a172a1a10c2df511

which no longer calls disable_early_printk, the earlyprintk console never gets
turned off (because nothing else ever calls register_console). I get
everything out the early console, until the init section is released (where
the console structure is sitting), and it starts printing out garbage.

Is this expected behaviour?

-Robin


2007-08-16 07:45:58

by Gerd Hoffmann

[permalink] [raw]
Subject: Re: Early printk behaviour

Robin Getz wrote:
> I was putting together an early printk implementation for the Blackfin, and
> was wondering what the expected behaviour was in this situation.
>
> When I set up my bootargs earlyprintk=serial,ttyBF0,57600 and have no console
> defined (no graphical console, no serial console).
>
> based on the patch:
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=69331af79cf29e26d1231152a172a1a10c2df511
>
> which no longer calls disable_early_printk, the earlyprintk console never gets
> turned off (because nothing else ever calls register_console). I get
> everything out the early console, until the init section is released (where
> the console structure is sitting), and it starts printing out garbage.
>
> Is this expected behaviour?

Hmm, sort of, although I didn't think about the case of no real console
replacing the early console. The intention of the patch is to have a
smooth handover from the boot console to the real console. And, yes, if
no real console is ever registered the boot console keeps running ...

So you can either let it running and *not* mark it __init, so it can
keep on going without breaking. Or you can explicitly unregister your
boot console at some point, maybe using a late_initcall.

cheers,
Gerd

2007-08-16 16:47:50

by Mike Frysinger

[permalink] [raw]
Subject: Re: Early printk behaviour

On 8/16/07, Gerd Hoffmann <[email protected]> wrote:
> Robin Getz wrote:
> > I was putting together an early printk implementation for the Blackfin, and
> > was wondering what the expected behaviour was in this situation.
> >
> > When I set up my bootargs earlyprintk=serial,ttyBF0,57600 and have no console
> > defined (no graphical console, no serial console).
> >
> > based on the patch:
> > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=69331af79cf29e26d1231152a172a1a10c2df511
> >
> > which no longer calls disable_early_printk, the earlyprintk console never gets
> > turned off (because nothing else ever calls register_console). I get
> > everything out the early console, until the init section is released (where
> > the console structure is sitting), and it starts printing out garbage.
> >
> > Is this expected behaviour?
>
> Hmm, sort of, although I didn't think about the case of no real console
> replacing the early console. The intention of the patch is to have a
> smooth handover from the boot console to the real console. And, yes, if
> no real console is ever registered the boot console keeps running ...

i think it also occurs in the case where real console != early console

> So you can either let it running and *not* mark it __init, so it can
> keep on going without breaking. Or you can explicitly unregister your
> boot console at some point, maybe using a late_initcall.

wouldnt a common kernel late_initcall() be more appropriate ? if
early console hasnt switched over (for whatever reason), then kill it
...
-mike

2007-08-16 18:56:58

by Robin Getz

[permalink] [raw]
Subject: Re: Early printk behaviour

On Thu 16 Aug 2007 03:45, Gerd Hoffmann pondered:
> Robin Getz wrote:
> > I was putting together an early printk implementation for the Blackfin, and
> > was wondering what the expected behaviour was in this situation.
> >
> > When I set up my bootargs earlyprintk=serial,ttyBF0,57600 and have no console
> > defined (no graphical console, no serial console).
> >
> > based on the patch:
> > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=69331af79cf29e26d1231152a172a1a10c2df511
> >
> > which no longer calls disable_early_printk, the earlyprintk console never gets
> > turned off (because nothing else ever calls register_console). I get
> > everything out the early console, until the init section is released (where
> > the console structure is sitting), and it starts printing out garbage.
> >
> > Is this expected behaviour?
>
> Hmm, sort of, although I didn't think about the case of no real console
> replacing the early console. The intention of the patch is to have a
> smooth handover from the boot console to the real console. And, yes, if
> no real console is ever registered the boot console keeps running ...
>
> So you can either let it running and *not* mark it __init, so it can
> keep on going without breaking. Or you can explicitly unregister your
> boot console at some point, maybe using a late_initcall.

Thanks.

Doing things with late_initcall seems to work - is there any problem calling
unregister_console on an already unregistered console? I looked in the code,
and didn't see any nastyness.

-Robin

2007-08-17 07:49:42

by Gerd Hoffmann

[permalink] [raw]
Subject: Re: Early printk behaviour

Mike Frysinger wrote:
>> Hmm, sort of, although I didn't think about the case of no real console
>> replacing the early console. The intention of the patch is to have a
>> smooth handover from the boot console to the real console. And, yes, if
>> no real console is ever registered the boot console keeps running ...
>
> i think it also occurs in the case where real console != early console

No. At least not of the boot console has the CON_BOOT flag set as it
should. Last message you'll see on the boot console is the handover
printk, telling you which real console device prints the following
messages. Whenever early and real console go to the physical device or
not doesn't matter.

>> So you can either let it running and *not* mark it __init, so it can
>> keep on going without breaking. Or you can explicitly unregister your
>> boot console at some point, maybe using a late_initcall.
>
> wouldnt a common kernel late_initcall() be more appropriate ? if
> early console hasnt switched over (for whatever reason), then kill it

Hmm, yes, should be doable in generic code. Check whenever the current
console has CON_BOOT set and if so unregister it.

cheers,

Gerd

2007-08-17 17:36:54

by Robin Getz

[permalink] [raw]
Subject: [draft] Blackfin Early Printk implmentation

The patch (for review - not inclusion - I will send to Bryan if no one has any
major objections, and he can push it via git) implements early printk for the
Blackfin architecture.

It also adds an early exception handler, so if an
interrupt/exception/violation happens before the kernel enables it's
interrupts (yes that does happen periodically, and it is a nice to have a
debug feature to help , that we don't go back to the bootloaders exception
processing table...

It also removes some of the crap that was trying to implement the same thing
(poorly).

Before I send to Bryan "officially" - I thought I would see what others think.


---

Documentation/kernel-parameters.txt | 3
arch/blackfin/Kconfig | 32 +--
arch/blackfin/kernel/Makefile | 1
arch/blackfin/kernel/early_printk.c | 210 +++++++++++++++++++++
arch/blackfin/kernel/setup.c | 76 +++----
arch/blackfin/mach-bf533/head.S | 249 --------------------------
arch/blackfin/mach-bf537/head.S | 6
arch/blackfin/mach-bf548/head.S | 6
arch/blackfin/mach-bf561/head.S | 6
arch/blackfin/mach-common/entry.S | 45 ++++
drivers/serial/bfin_5xx.c | 130 ++++++++++---
include/asm-blackfin/early_printk.h | 28 ++
include/asm-blackfin/irq_handler.h | 22 ++
13 files changed, 485 insertions(+), 329 deletions(-)



Index: linux-2.6.x/include/asm-blackfin/early_printk.h
===================================================================
--- linux-2.6.x/include/asm-blackfin/early_printk.h (revision 0)
+++ linux-2.6.x/include/asm-blackfin/early_printk.h (revision 0)
@@ -0,0 +1,28 @@
+/*
+ * File: include/asm-blackfin/early_printk.h
+ * Author: Robin Getz <[email protected]
+ *
+ * Created: 14Aug2007
+ * Description: function prototpyes for early printk
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef CONFIG_EARLY_PRINTK
+extern int setup_early_printk(char *);
+#else
+#define setup_early_printk(fmt) do { } while (0)
+#endif /* CONFIG_EARLY_PRINTK */
Index: linux-2.6.x/include/asm-blackfin/irq_handler.h
===================================================================
--- linux-2.6.x/include/asm-blackfin/irq_handler.h (revision 3568)
+++ linux-2.6.x/include/asm-blackfin/irq_handler.h (working copy)
@@ -1,3 +1,24 @@
+/*
+ * File: include/asm-blackfin/irq_handler.h
+ *
+ * Description: function prototypes for interrupt handler routines
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef _IRQ_HANDLER_H
#define _IRQ_HANDLER_H

@@ -22,6 +43,7 @@
asmlinkage void init_exception_buff(void);
asmlinkage void trap_c(struct pt_regs *fp);
asmlinkage void ex_replaceable(void);
+asmlinkage void early_trap(void);

extern void *ex_table[];
extern void return_from_exception(void);
Index: linux-2.6.x/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.x/Documentation/kernel-parameters.txt (revision 3568)
+++ linux-2.6.x/Documentation/kernel-parameters.txt (working copy)
@@ -34,6 +34,7 @@
APIC APIC support is enabled.
APM Advanced Power Management support is enabled.
AX25 Appropriate AX.25 support is enabled.
+ BLACKFIN Blackfin architecture is enabled.
CD Appropriate CD support is enabled.
DRM Direct Rendering Management support is enabled.
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
@@ -558,7 +559,7 @@

dtc3181e= [HW,SCSI]

- earlyprintk= [IA-32,X86-64,SH]
+ earlyprintk= [IA-32,X86-64,SH,BLACKFIN]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]

Index: linux-2.6.x/arch/blackfin/kernel/setup.c
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/setup.c (revision 3568)
+++ linux-2.6.x/arch/blackfin/kernel/setup.c (working copy)
@@ -44,6 +44,7 @@
#include <asm/blackfin.h>
#include <asm/cplbinit.h>
#include <asm/fixed_code.h>
+#include <asm/early_printk.h>

u16 _bfin_swrst;

@@ -134,7 +135,6 @@
unsigned int memsize;
for (;;) {
if (c == ' ') {
-
if (!memcmp(to, "mem=", 4)) {
to += 4;
memsize = memparse(to, &to);
@@ -157,8 +157,10 @@
1;
}
}
+ } else if (!memcmp(to, "earlyprintk=", 12)) {
+ to += 12;
+ setup_early_printk(to);
}
-
}
c = *(to++);
if (!c)
@@ -177,14 +179,7 @@
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
- cclk = get_cclk();
- sclk = get_sclk();

-#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
- if (ANOMALY_05000273 && cclk == sclk)
- panic("ANOMALY 05000273, SCLK can not be same as CCLK");
-#endif
-
#ifdef BF561_FAMILY
if (ANOMALY_05000266) {
bfin_read_IMDMA_D0_IRQ_STATUS();
@@ -192,29 +187,6 @@
}
#endif

-#ifdef DEBUG_SERIAL_EARLY_INIT
- bfin_console_init(); /* early console registration */
- /* this give a chance to get printk() working before crash. */
-#endif
-
- printk(KERN_INFO "Hardware Trace ");
- if (bfin_read_TBUFCTL() & 0x1 )
- printk("Active ");
- else
- printk("Off ");
- if (bfin_read_TBUFCTL() & 0x2)
- printk("and Enabled\n");
- else
- printk("and Disabled\n");
-
-
-#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
- /* we need to initialize the Flashrom device here since we might
- * do things with flash early on in the boot
- */
- flash_probe();
-#endif
-
#if defined(CONFIG_CMDLINE_BOOL)
strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
command_line[sizeof(command_line) - 1] = 0;
@@ -229,8 +201,36 @@
physical_mem_end = 0;
_ramend = CONFIG_MEM_SIZE * 1024 * 1024;

+ /* We parse command line early, to set memory limits and get
+ * early_printk earlier than normal
+ */
parse_cmdline_early(&command_line[0]);

+#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
+ /* we need to initialize the Flashrom device here since we might
+ * do things with flash early on in the boot
+ */
+ flash_probe();
+#endif
+
+ cclk = get_cclk();
+ sclk = get_sclk();
+
+#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
+ if (ANOMALY_05000273 && cclk < (sclk *2))
+ panic("ANOMALY 05000273: CCLK must be >= 2*SCLK ");
+#endif
+
+ printk(KERN_INFO "Hardware Trace ");
+ if (bfin_read_TBUFCTL() & 0x1 )
+ printk("Active ");
+ else
+ printk("Off ");
+ if (bfin_read_TBUFCTL() & 0x2)
+ printk("and Enabled\n");
+ else
+ printk("and Disabled\n");
+
if (physical_mem_end == 0)
physical_mem_end = _ramend;

@@ -298,13 +298,16 @@
* 05000263 - Hardware loop corrupted when taking an ICPLB exception
*/
#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
- if (memory_end >= 56 * 1024 * 1024)
+ if (memory_end >= 56 * 1024 * 1024) {
memory_end = 56 * 1024 * 1024;
+ printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware
anomaly 05000263\n", memory_end >> 20);
+ }
#else
- if (memory_end >= 60 * 1024 * 1024)
+ if (memory_end >= 60 * 1024 * 1024) {
memory_end = 60 * 1024 * 1024;
+ printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware
anomaly 05000263\n", memory_end >> 20);
+ }
#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
- printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware
anomaly 05000263\n", memory_end >> 20);
#endif /* ANOMALY_05000263 */

#if !defined(CONFIG_MTD_UCLINUX)
@@ -340,9 +343,6 @@
printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System
Clock\n",
cclk / 1000000, sclk / 1000000);

- if (ANOMALY_05000273 && (cclk >> 1) <= sclk)
- printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
-
printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);

Index: linux-2.6.x/arch/blackfin/kernel/early_printk.c
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/early_printk.c (revision 0)
+++ linux-2.6.x/arch/blackfin/kernel/early_printk.c (revision 0)
@@ -0,0 +1,210 @@
+/*
+ * File: arch/blackfin/kernel/early_printk.c
+ * Based on: arch/x86_64/kernel/early_printk.c
+ * Author: Robin Getz <[email protected]
+ *
+ * Created: 14Aug2007
+ * Description: allow a console to be used for early printk
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <asm/blackfin.h>
+#include <asm/irq_handler.h>
+#include <asm/early_printk.h>
+
+extern struct console *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag);
+extern int bfin_earlyserial_disable(void);
+
+static struct console *early_console_initialized;
+
+/* Default console
+ * Port n == ttyBFn
+ * cflags == UART output modes
+ */
+#define DEFAULT_PORT 0
+#define DEFAULT_CFLAG CS8|B57600
+
+/*
+ * Set up a temporary Event Vector Table, so if something bad happens before
+ * the kernel is fully started, it doesn't vector off into somewhere we don't
+ * know
+ */
+
+asmlinkage void __init init_early_exception_vectors(void)
+{
+ /* cannot program in software:
+ * evt0 - emulation (jtag)
+ * evt1 - reset
+ */
+ bfin_write_EVT2(early_trap);
+ bfin_write_EVT3(early_trap);
+ bfin_write_EVT5(early_trap);
+ bfin_write_EVT6(early_trap);
+ bfin_write_EVT7(early_trap);
+ bfin_write_EVT8(early_trap);
+ bfin_write_EVT9(early_trap);
+ bfin_write_EVT10(early_trap);
+ bfin_write_EVT11(early_trap);
+ bfin_write_EVT12(early_trap);
+ bfin_write_EVT13(early_trap);
+ bfin_write_EVT14(early_trap);
+ bfin_write_EVT15(early_trap);
+
+ /* Set all the return from interupt, exception, NMI to a known place
+ * so if we do a RETI, RETX or RETN by mistake - we go somewhere known
+ * Note - don't change RETS - we are in a subroutine, or
+ * RETE - since it might screw up if emulator is attached
+ */
+
+ asm("\tRETI = %0;\n"
+ "\tRETX = %0;\n"
+ "\tRETN = %0;\n"
+ : : "p"(early_trap));
+}
+
+int __init setup_early_printk(char *buf)
+{
+ int baud, bit;
+ char parity;
+ unsigned int serial_port = DEFAULT_PORT;
+ unsigned int cflag = DEFAULT_CFLAG;
+
+ /* Crashing in here would be really bad, so check both the var
+ and the pointer before we start using it
+ */
+ if (!buf)
+ return 0;
+
+ if (!*buf)
+ return 0;
+
+ if (early_console_initialized)
+ return 0;
+
+ if (!strncmp(buf, "serial", 6)) {
+ buf += 7;
+ if (!strncmp(buf, "ttyBF", 5)) {
+ buf += 5;
+ serial_port = simple_strtoul(buf, &buf, 10);
+ buf++;
+ }
+
+ cflag = 0;
+ baud = simple_strtoul(buf, &buf, 10);
+ switch (baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 9600:
+ cflag |= B9600;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ default:
+ cflag |= B57600;
+ }
+
+ parity = buf[0];
+ buf++;
+ switch (parity) {
+ case 'e':
+ cflag |= PARENB;
+ break;
+ case 'o':
+ cflag |= PARODD;
+ break;
+ }
+
+ bit = simple_strtoul(buf, &buf, 10);
+ switch (bit) {
+ case 5:
+ cflag |= CS5;
+ break;
+ case 6:
+ cflag |= CS5;
+ break;
+ case 7:
+ cflag |= CS5;
+ break;
+ default:
+ cflag |= CS8;
+ }
+
+ early_console_initialized = bfin_earlyserial_init(serial_port,
+ cflag);
+ } else if (!strncmp(buf, "vga", 3)) {
+ /* TODO: add framebuffer console support? */
+ }
+
+ if (early_console_initialized)
+ printk(KERN_INFO "Early Printk Support Enabled on %s%d\n",
+ early_console_initialized->name,
+ early_console_initialized->index);
+
+ return 0;
+}
+
+int __init disable_early_printk(void)
+{
+ if (!early_console_initialized)
+ return 0;
+
+ printk(KERN_INFO "Unregister %s%d\n", early_console_initialized->name,
+ early_console_initialized->index);
+ unregister_console(early_console_initialized);
+ early_console_initialized = NULL;
+ return 0;
+}
+
+late_initcall(disable_early_printk);
+
+asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
+{
+ unsigned int serial_port = DEFAULT_PORT;
+ unsigned int cflag = DEFAULT_CFLAG;
+
+ /* This can happen before the uart is initialized, so initialize
+ * the UART now
+ */
+ if (!early_console_initialized) {
+ bfin_earlyserial_init(serial_port, cflag);
+ }
+
+ dump_bfin_regs(fp, retaddr);
+ dump_bfin_trace_buffer();
+
+ panic("Died early");
+}
Index: linux-2.6.x/arch/blackfin/kernel/Makefile
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/Makefile (revision 3568)
+++ linux-2.6.x/arch/blackfin/kernel/Makefile (working copy)
@@ -15,3 +15,4 @@
obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
Index: linux-2.6.x/arch/blackfin/Kconfig
===================================================================
--- linux-2.6.x/arch/blackfin/Kconfig (revision 3568)
+++ linux-2.6.x/arch/blackfin/Kconfig (working copy)
@@ -1040,24 +1040,6 @@
also relocates the irq_panic() function to L1 memory, (which is
un-cached).

-config DEBUG_KERNEL_START
- bool "Debug Kernel Startup"
- depends on DEBUG_KERNEL
- help
- Say Y here to put in an mini-execption handler before the kernel
- replaces the bootloader exception handler. This will stop kernels
- from dieing at startup with no visible error messages.
-
-config DEBUG_SERIAL_EARLY_INIT
- bool "Initialize serial driver early"
- default n
- depends on SERIAL_BFIN
- help
- Say Y here if you want to get kernel output early when kernel
- crashes before the normal console initialization. If this option
- is enable, console output will always go to the ttyBF0, no matter
- what kernel boot paramters you set.
-
config DEBUG_HUNT_FOR_ZERO
bool "Catch NULL pointer reads/writes"
default y
@@ -1165,6 +1147,20 @@
Say Y here to disable hardware tracing in some known "jumpy" pieces
of code so that the trace buffer will extend further back.

+config EARLY_PRINTK
+ bool "Early printk"
+ default n
+ help
+ This option enables special console drivers which allow the kernel
+ to print messages very early in the bootup process.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. After enabling this
+ feature, you must add "earlyprintk=serial,ttyBF0,57600" to the
+ command line (bootargs). It is safe to say Y here in all cases, as
+ all of this lives in the init section and is thrown away after the
+ kernel boots completely.
+
config DUAL_CORE_TEST_MODULE
tristate "Dual Core Test Module"
depends on (BF561)
Index: linux-2.6.x/arch/blackfin/mach-bf533/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf533/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf533/head.S (working copy)
@@ -35,9 +35,6 @@
#include <asm/mach-common/clocks.h>
#include <asm/mach/mem_init.h>
#endif
-#if CONFIG_DEBUG_KERNEL_START
-#include <asm/mach-common/def_LPBlackfin.h>
-#endif

.global __rambase
.global __ramstart
@@ -104,36 +101,6 @@
P0 = R1;
R0 = R1;

-#if CONFIG_DEBUG_KERNEL_START
-
-/*
- * Set up a temporary Event Vector Table, so if something bad happens before
- * the kernel is fully started, it doesn't vector off into the bootloaders
- * table
- */
- P0.l = lo(EVT2);
- P0.h = hi(EVT2);
- P1.l = lo(EVT15);
- P1.h = hi(EVT15);
- P2.l = debug_kernel_start_trap;
- P2.h = debug_kernel_start_trap;
-
- RTS = P2;
- RTI = P2;
- RTX = P2;
- RTN = P2;
- RTE = P2;
-
-.Lfill_temp_vector_table:
- [P0++] = P2; /* Core Event Vector Table */
- CC = P0 == P1;
- if !CC JUMP .Lfill_temp_vector_table
- P0 = r0;
- P1 = r0;
- P2 = r0;
-
-#endif
-
p0.h = hi(FIO_MASKA_C);
p0.l = lo(FIO_MASKA_C);
r0 = 0xFFFF(Z);
@@ -214,6 +181,12 @@
fp = sp;
usp = sp;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
@@ -519,216 +492,6 @@
RTS;
ENDPROC(_bfin_reset)

-#if CONFIG_DEBUG_KERNEL_START
-debug_kernel_start_trap:
- /* Set up a temp stack in L1 - SDRAM might not be working */
- P0.L = lo(L1_DATA_A_START + 0x100);
- P0.H = hi(L1_DATA_A_START + 0x100);
- SP = P0;
-
- /* Make sure the Clocks are the way I think they should be */
- r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
- r0 = r0 << 9; /* Shift it over, */
- r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
- r0 = r1 | r0;
- r1 = PLL_BYPASS; /* Bypass the PLL? */
- r1 = r1 << 8; /* Shift it over */
- r0 = r1 | r0; /* add them all together */
-
- p0.h = hi(PLL_CTL);
- p0.l = lo(PLL_CTL); /* Load the address */
- cli r2; /* Disable interrupts */
- ssync;
- w[p0] = r0.l; /* Set the value */
- idle; /* Wait for the PLL to stablize */
- sti r2; /* Enable interrupts */
-
-.Lcheck_again1:
- p0.h = hi(PLL_STAT);
- p0.l = lo(PLL_STAT);
- R0 = W[P0](Z);
- CC = BITTST(R0,5);
- if ! CC jump .Lcheck_again1;
-
- /* Configure SCLK & CCLK Dividers */
- r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
- p0.h = hi(PLL_DIV);
- p0.l = lo(PLL_DIV);
- w[p0] = r0.l;
- ssync;
-
- /* Make sure UART is enabled - you can never be sure */
-
-/*
- * Setup for console. Argument comes from the menuconfig
- */
-
-#ifdef CONFIG_BAUD_9600
-#define CONSOLE_BAUD_RATE 9600
-#elif CONFIG_BAUD_19200
-#define CONSOLE_BAUD_RATE 19200
-#elif CONFIG_BAUD_38400
-#define CONSOLE_BAUD_RATE 38400
-#elif CONFIG_BAUD_57600
-#define CONSOLE_BAUD_RATE 57600
-#elif CONFIG_BAUD_115200
-#define CONSOLE_BAUD_RATE 115200
-#endif
-
- p0.h = hi(UART_GCTL);
- p0.l = lo(UART_GCTL);
- r0 = 0x00(Z);
- w[p0] = r0.L; /* To Turn off UART clocks */
- ssync;
-
- p0.h = hi(UART_LCR);
- p0.l = lo(UART_LCR);
- r0 = 0x83(Z);
- w[p0] = r0.L; /* To enable DLL writes */
- ssync;
-
- R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) /
(CONSOLE_BAUD_RATE * 16));
-
- p0.h = hi(UART_DLL);
- p0.l = lo(UART_DLL);
- r0 = 0xFF(Z);
- r0 = R1 & R0;
- w[p0] = r0.L;
- ssync;
-
- p0.h = hi(UART_DLH);
- p0.l = lo(UART_DLH);
- r1 >>= 8 ;
- w[p0] = r1.L;
- ssync;
-
- p0.h = hi(UART_GCTL);
- p0.l = lo(UART_GCTL);
- r0 = 0x0(Z);
- w[p0] = r0.L; /* To enable UART clock */
- ssync;
-
- p0.h = hi(UART_LCR);
- p0.l = lo(UART_LCR);
- r0 = 0x03(Z);
- w[p0] = r0.L; /* To Turn on UART */
- ssync;
-
- p0.h = hi(UART_GCTL);
- p0.l = lo(UART_GCTL);
- r0 = 0x01(Z);
- w[p0] = r0.L; /* To Turn on UART Clocks */
- ssync;
-
- P0.h = hi(UART_THR);
- P0.l = lo(UART_THR);
- P1.h = hi(UART_LSR);
- P1.l = lo(UART_LSR);
-
- R0.L = 'K';
- call .Lwait_char;
- R0.L='e';
- call .Lwait_char;
- R0.L='r';
- call .Lwait_char;
- R0.L='n'
- call .Lwait_char;
- R0.L='e'
- call .Lwait_char;
- R0.L='l';
- call .Lwait_char;
- R0.L=' ';
- call .Lwait_char;
- R0.L='c';
- call .Lwait_char;
- R0.L='r';
- call .Lwait_char;
- R0.L='a';
- call .Lwait_char;
- R0.L='s';
- call .Lwait_char;
- R0.L='h';
- call .Lwait_char;
- R0.L='\r';
- call .Lwait_char;
- R0.L='\n';
- call .Lwait_char;
-
- R0.L='S';
- call .Lwait_char;
- R0.L='E';
- call .Lwait_char;
- R0.L='Q'
- call .Lwait_char;
- R0.L='S'
- call .Lwait_char;
- R0.L='T';
- call .Lwait_char;
- R0.L='A';
- call .Lwait_char;
- R0.L='T';
- call .Lwait_char;
- R0.L='=';
- call .Lwait_char;
- R2 = SEQSTAT;
- call .Ldump_reg;
-
- R0.L=' ';
- call .Lwait_char;
- R0.L='R';
- call .Lwait_char;
- R0.L='E'
- call .Lwait_char;
- R0.L='T'
- call .Lwait_char;
- R0.L='X';
- call .Lwait_char;
- R0.L='=';
- call .Lwait_char;
- R2 = RETX;
- call .Ldump_reg;
-
- R0.L='\r';
- call .Lwait_char;
- R0.L='\n';
- call .Lwait_char;
-
-.Ldebug_kernel_start_trap_done:
- JUMP .Ldebug_kernel_start_trap_done;
-.Ldump_reg:
- R3 = 32;
- R4 = 0x0F;
- R5 = ':'; /* one past 9 */
-
-.Ldump_reg2:
- R0 = R2;
- R3 += -4;
- R0 >>>= R3;
- R0 = R0 & R4;
- R0 += 0x30;
- CC = R0 <= R5;
- if CC JUMP .Ldump_reg1;
- R0 += 7;
-
-.Ldump_reg1:
- R1.l = W[P1];
- CC = BITTST(R1, 5);
- if !CC JUMP .Ldump_reg1;
- W[P0] = r0;
-
- CC = R3 == 0;
- if !CC JUMP .Ldump_reg2
- RTS;
-
-.Lwait_char:
- R1.l = W[P1];
- CC = BITTST(R1, 5);
- if !CC JUMP .Lwait_char;
- W[P0] = r0;
- RTS;
-
-#endif /* CONFIG_DEBUG_KERNEL_START */
-
.data

/*
Index: linux-2.6.x/arch/blackfin/mach-bf561/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf561/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf561/head.S (working copy)
@@ -169,6 +169,12 @@
fp = sp;
usp = sp;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
Index: linux-2.6.x/arch/blackfin/mach-bf537/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf537/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf537/head.S (working copy)
@@ -224,6 +224,12 @@
fp = sp;
usp = sp;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
Index: linux-2.6.x/arch/blackfin/mach-bf548/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf548/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf548/head.S (working copy)
@@ -125,6 +125,12 @@
FP = SP;
USP = SP;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
Index: linux-2.6.x/arch/blackfin/mach-common/entry.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-common/entry.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-common/entry.S (working copy)
@@ -803,14 +803,57 @@
.section .l1.data.B
#endif
ENTRY(_trace_buff_offset)
- .long 0;
+ .long 0;
ALIGN
ENTRY(_software_trace_buff)
.rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256);
.long 0
.endr
+#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND */
+
+#ifdef CONFIG_EARLY_PRINTK
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
#endif

+ENTRY(_early_trap)
+ SAVE_ALL_SYS
+ trace_buffer_stop(p0, r0);
+
+ /* Turn caches off, to ensure we don't get double exceptions */
+
+ P4.L = LO(IMEM_CONTROL);
+ P4.H = HI(IMEM_CONTROL);
+
+ R5 = [P4]; /* Control Register*/
+ BITCLR(R5,ENICPLB_P);
+ CLI R1;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ P4.L = LO(DMEM_CONTROL);
+ P4.H = HI(DMEM_CONTROL);
+ R5 = [P4];
+ BITCLR(R5,ENDCPLB_P);
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R1;
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ r1 = RETX;
+
+ SP += -12;
+ call _early_trap_c;
+ SP += 12;
+ENDPROC(_early_trap)
+#endif /* CONFIG_EARLY_PRINTK */
+
/*
* Put these in the kernel data section - that should always be covered by
* a CPLB. This is needed to ensure we don't get double fault conditions
Index: linux-2.6.x/drivers/serial/bfin_5xx.c
===================================================================
--- linux-2.6.x/drivers/serial/bfin_5xx.c (revision 3568)
+++ linux-2.6.x/drivers/serial/bfin_5xx.c (working copy)
@@ -961,31 +961,7 @@
}

#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
- struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- while (!(UART_GET_LSR(uart) & THRE))
- barrier();
- UART_PUT_CHAR(uart, ch);
- SSYNC();
-}
-
/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int
count)
-{
- struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
- int flags = 0;
-
- spin_lock_irqsave(&uart->port.lock, flags);
- uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
- spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
-/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
*/
@@ -1037,19 +1013,25 @@
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud,
*parity, *bits);
}
+#endif

+#if defined (CONFIG_SERIAL_BFIN_CONSOLE) || defined (CONFIG_EARLY_PRINTK)
+static struct uart_driver bfin_serial_reg;
+
static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
struct bfin_serial_port *uart;
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
int baud = 57600;
int bits = 8;
int parity = 'n';
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# ifdef CONFIG_SERIAL_BFIN_CTSRTS
int flow = 'r';
-#else
+# else
int flow = 'n';
-#endif
+# endif
+# endif

/*
* Check whether an invalid uart number has been specified, and
@@ -1060,15 +1042,45 @@
co->index = 0;
uart = &bfin_serial_ports[co->index];

+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
bfin_serial_console_get_options(uart, &baud, &parity, &bits);

return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+# else
+ return 0;
+# endif
}
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+ defined (CONFIG_EARLY_PRINTK) */

-static struct uart_driver bfin_serial_reg;
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ while (!(UART_GET_LSR(uart) & THRE))
+ barrier();
+ UART_PUT_CHAR(uart, ch);
+ SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int
count)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+ int flags = 0;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
static struct console bfin_serial_console = {
.name = BFIN_SERIAL_NAME,
.write = bfin_serial_console_write,
@@ -1094,8 +1106,70 @@
#define BFIN_SERIAL_CONSOLE &bfin_serial_console
#else
#define BFIN_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void early_serial_putc(struct uart_port *port, int ch)
+{
+ unsigned timeout = 0xffff;
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
+ cpu_relax();
+ UART_PUT_CHAR(uart, ch);
+}
+
+static __init void early_serial_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
+ unsigned int i;
+
+ for (i = 0; i < n; i++, s++) {
+ if (*s == '\n')
+ early_serial_putc(&uart->port, '\r');
+ early_serial_putc(&uart->port, *s);
+ }
+}
+
+static struct __init console bfin_early_serial_console = {
+ .name = "early_ttyBF",
+ .write = early_serial_write,
+ .device = uart_console_device,
+ .flags = CON_BOOT,
+ .setup = bfin_serial_console_setup,
+ .index = -1,
+ .data = &bfin_serial_reg,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag)
+{
+ struct bfin_serial_port *uart;
+ struct ktermios t;
+
+ if (port == -1 || port >= nr_ports)
+ port = 0;
+ bfin_serial_init_ports();
+ bfin_early_serial_console.index = port;
+ register_console(&bfin_early_serial_console);
+#ifdef CONFIG_KGDB_UART
+ kgdb_entry_state = 0;
+ init_kgdb_uart();
#endif
+ uart = &bfin_serial_ports[port];
+ t.c_cflag = cflag;
+ t.c_iflag = 0;
+ t.c_oflag = 0;
+ t.c_lflag = ICANON;
+ t.c_line = port;
+ bfin_serial_set_termios(&uart->port, &t, &t);
+ return &bfin_early_serial_console;
+}

+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
.driver_name = "bfin-uart",

2007-08-17 17:57:26

by Mike Frysinger

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

On 8/17/07, Robin Getz <[email protected]> wrote:
> + asm("\tRETI = %0;\n"
> + "\tRETX = %0;\n"
> + "\tRETN = %0;\n"
> + : : "p"(early_trap));

general note, i dont think inserting whitespace by hand in asm() is a
good thing ... i see it as whitenoise personally ...

> +int __init disable_early_printk(void)
> +{
> + if (!early_console_initialized)
> + return 0;
> +
> + printk(KERN_INFO "Unregister %s%d\n", early_console_initialized->name,
> + early_console_initialized->index);
> + unregister_console(early_console_initialized);
> + early_console_initialized = NULL;
> + return 0;
> +}
> +
> +late_initcall(disable_early_printk);

i think we agreed this would be OK/good to have in common code
-mike

2007-08-17 17:58:13

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

On Fri, Aug 17, 2007 at 01:36:39PM -0400, Robin Getz wrote:
> The patch (for review - not inclusion - I will send to Bryan if no one has any
> major objections, and he can push it via git) implements early printk for the
> Blackfin architecture.
>
> It also adds an early exception handler, so if an
> interrupt/exception/violation happens before the kernel enables it's
> interrupts (yes that does happen periodically, and it is a nice to have a
> debug feature to help , that we don't go back to the bootloaders exception
> processing table...
>
> It also removes some of the crap that was trying to implement the same thing
> (poorly).

So this patch does three things at least:
-> adds early_printk
-> delete cruft emulating early printk
-> add an early excaption handler

That seems to explain why I could not follow your code changes.
A more fine grained splitup would have helped here.

I noticed that you copied the actual early_printk code from x86_64.
What was preventing you from just using the x86_64 code here?
A simple
#include <arch/x86_64/boot/early_printk.c>
in the blackfin early_printk should do the trick.

alpha btw uses the implementation in lib/*printf.c
Are there a specific reason why blackfin and x86_64 does not do the same?
Thinking that all should do the same so maybe alpha ought to change...

Sam

2007-08-17 18:26:20

by Robin Getz

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

On Fri 17 Aug 2007 13:57, Mike Frysinger pondered:
> On 8/17/07, Robin Getz <[email protected]> wrote:
> > +int __init disable_early_printk(void)
> > +{
> > + if (!early_console_initialized)
> > + return 0;
> > +
> > + printk(KERN_INFO "Unregister %s%d\n",
early_console_initialized->name,
> > + early_console_initialized->index);
> > + unregister_console(early_console_initialized);
> > + early_console_initialized = NULL;
> > + return 0;
> > +}
> > +
> > +late_initcall(disable_early_printk);
>
> i think we agreed this would be OK/good to have in common code

I didn't hear back from Gerd - and in the past this was implemented in the
arch/*/kernel/early_printk.c - so this is where I put it....

-Robin

2007-08-17 18:43:33

by Mike Frysinger

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

On 8/17/07, Robin Getz <[email protected]> wrote:
> On Fri 17 Aug 2007 13:57, Mike Frysinger pondered:
> > On 8/17/07, Robin Getz <[email protected]> wrote:
> > > +int __init disable_early_printk(void)
> > > +{
> > > + if (!early_console_initialized)
> > > + return 0;
> > > +
> > > + printk(KERN_INFO "Unregister %s%d\n",
> early_console_initialized->name,
> > > + early_console_initialized->index);
> > > + unregister_console(early_console_initialized);
> > > + early_console_initialized = NULL;
> > > + return 0;
> > > +}
> > > +
> > > +late_initcall(disable_early_printk);
> >
> > i think we agreed this would be OK/good to have in common code
>
> I didn't hear back from Gerd - and in the past this was implemented in the
> arch/*/kernel/early_printk.c - so this is where I put it....

i think his response was "if you do it and he likes the code he'll say yes" :)
-mike

2007-08-17 20:07:48

by Robin Getz

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

On Fri 17 Aug 2007 13:59, Sam Ravnborg pondered:
> That seems to explain why I could not follow your code changes.
> A more fine grained splitup would have helped here.

Sorry - see below. These aren't proper patches anymore, since it was
faster for me to split them by hand (but should be OK for review).
I will resend later properly.

> I noticed that you copied the actual early_printk code from x86_64.
> What was preventing you from just using the x86_64 code here?

Some was borrowed - but not much. since we don't support vga, or 16550 UARTs
(Blackfin has it's own on-chip UART), I don't think this would work.

> A simple
> #include <arch/x86_64/boot/early_printk.c>
> in the blackfin early_printk should do the trick.

Maybe I'm missing something - but I don't think so. Every one who implements
implements direct IO to the hardware (except me, since I put it into the driver
file, and force Sonic - the serial driver developer - to maintain it forever).

Most of the other early printks talks directly to the hardware.

> Thinking that all should do the same so maybe alpha ought to change...

When I looked at all the printk implementations, I thought they were all
kind of hokey, and not very common - but what do you want for a debug interface
that lasts less than 5 seconds?

./arch/x86_64/kernel/early_printk.c
./arch/blackfin/kernel/early_printk.c
./arch/sh64/kernel/early_printk.c
./arch/sh/kernel/early_printk.c
./arch/i386/kernel/early_printk.c
./arch/mips/kernel/early_printk.c

I didn't see an alpha implementation - where is it done?

-Robin

> So this patch does three things at least:

> -> delete cruft emulating early printk

Index: linux-2.6.x/arch/blackfin/Kconfig
===================================================================
--- linux-2.6.x/arch/blackfin/Kconfig (revision 3568)
+++ linux-2.6.x/arch/blackfin/Kconfig (working copy)
@@ -1040,24 +1040,6 @@
also relocates the irq_panic() function to L1 memory, (which is
un-cached).

-config DEBUG_KERNEL_START
- bool "Debug Kernel Startup"
- depends on DEBUG_KERNEL
- help
- Say Y here to put in an mini-execption handler before the kernel
- replaces the bootloader exception handler. This will stop kernels
- from dieing at startup with no visible error messages.
-
-config DEBUG_SERIAL_EARLY_INIT
- bool "Initialize serial driver early"
- default n
- depends on SERIAL_BFIN
- help
- Say Y here if you want to get kernel output early when kernel
- crashes before the normal console initialization. If this option
- is enable, console output will always go to the ttyBF0, no matter
- what kernel boot paramters you set.
-
config DEBUG_HUNT_FOR_ZERO
bool "Catch NULL pointer reads/writes"
default y
@@ -1165,6 +1147,20 @@
Say Y here to disable hardware tracing in some known "jumpy" pieces
of code so that the trace buffer will extend further back.

Index: linux-2.6.x/arch/blackfin/mach-bf533/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf533/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf533/head.S (working copy)
@@ -35,9 +35,6 @@
#include <asm/mach-common/clocks.h>
#include <asm/mach/mem_init.h>
#endif
-#if CONFIG_DEBUG_KERNEL_START
-#include <asm/mach-common/def_LPBlackfin.h>
-#endif

.global __rambase
.global __ramstart
@@ -104,36 +101,6 @@
P0 = R1;
R0 = R1;

-#if CONFIG_DEBUG_KERNEL_START
-
-/*
- * Set up a temporary Event Vector Table, so if something bad happens before
- * the kernel is fully started, it doesn't vector off into the bootloaders
- * table
- */
- P0.l = lo(EVT2);
- P0.h = hi(EVT2);
- P1.l = lo(EVT15);
- P1.h = hi(EVT15);
- P2.l = debug_kernel_start_trap;
- P2.h = debug_kernel_start_trap;
-
- RTS = P2;
- RTI = P2;
- RTX = P2;
- RTN = P2;
- RTE = P2;
-
-.Lfill_temp_vector_table:
- [P0++] = P2; /* Core Event Vector Table */
- CC = P0 == P1;
- if !CC JUMP .Lfill_temp_vector_table
- P0 = r0;
- P1 = r0;
- P2 = r0;
-
-#endif
-
p0.h = hi(FIO_MASKA_C);
p0.l = lo(FIO_MASKA_C);
r0 = 0xFFFF(Z);
@@ -519,216 +492,6 @@
RTS;
ENDPROC(_bfin_reset)

-#if CONFIG_DEBUG_KERNEL_START
-debug_kernel_start_trap:
- /* Set up a temp stack in L1 - SDRAM might not be working */
- P0.L = lo(L1_DATA_A_START + 0x100);
- P0.H = hi(L1_DATA_A_START + 0x100);
- SP = P0;
-
- /* Make sure the Clocks are the way I think they should be */
- r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
- r0 = r0 << 9; /* Shift it over, */
- r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
- r0 = r1 | r0;
- r1 = PLL_BYPASS; /* Bypass the PLL? */
- r1 = r1 << 8; /* Shift it over */
- r0 = r1 | r0; /* add them all together */
-
- p0.h = hi(PLL_CTL);
- p0.l = lo(PLL_CTL); /* Load the address */
- cli r2; /* Disable interrupts */
- ssync;
- w[p0] = r0.l; /* Set the value */
- idle; /* Wait for the PLL to stablize */
- sti r2; /* Enable interrupts */
-
-.Lcheck_again1:
- p0.h = hi(PLL_STAT);
- p0.l = lo(PLL_STAT);
- R0 = W[P0](Z);
- CC = BITTST(R0,5);
- if ! CC jump .Lcheck_again1;
-
- /* Configure SCLK & CCLK Dividers */
- r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
- p0.h = hi(PLL_DIV);
- p0.l = lo(PLL_DIV);
- w[p0] = r0.l;
- ssync;
-
- /* Make sure UART is enabled - you can never be sure */
-
-/*
- * Setup for console. Argument comes from the menuconfig
- */
-
-#ifdef CONFIG_BAUD_9600
-#define CONSOLE_BAUD_RATE 9600
-#elif CONFIG_BAUD_19200
-#define CONSOLE_BAUD_RATE 19200
-#elif CONFIG_BAUD_38400
-#define CONSOLE_BAUD_RATE 38400
-#elif CONFIG_BAUD_57600
-#define CONSOLE_BAUD_RATE 57600
-#elif CONFIG_BAUD_115200
-#define CONSOLE_BAUD_RATE 115200
-#endif
-
- p0.h = hi(UART_GCTL);
- p0.l = lo(UART_GCTL);
- r0 = 0x00(Z);
- w[p0] = r0.L; /* To Turn off UART clocks */
- ssync;
-
- p0.h = hi(UART_LCR);
- p0.l = lo(UART_LCR);
- r0 = 0x83(Z);
- w[p0] = r0.L; /* To enable DLL writes */
- ssync;
-
- R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16));
-
- p0.h = hi(UART_DLL);
- p0.l = lo(UART_DLL);
- r0 = 0xFF(Z);
- r0 = R1 & R0;
- w[p0] = r0.L;
- ssync;
-
- p0.h = hi(UART_DLH);
- p0.l = lo(UART_DLH);
- r1 >>= 8 ;
- w[p0] = r1.L;
- ssync;
-
- p0.h = hi(UART_GCTL);
- p0.l = lo(UART_GCTL);
- r0 = 0x0(Z);
- w[p0] = r0.L; /* To enable UART clock */
- ssync;
-
- p0.h = hi(UART_LCR);
- p0.l = lo(UART_LCR);
- r0 = 0x03(Z);
- w[p0] = r0.L; /* To Turn on UART */
- ssync;
-
- p0.h = hi(UART_GCTL);
- p0.l = lo(UART_GCTL);
- r0 = 0x01(Z);
- w[p0] = r0.L; /* To Turn on UART Clocks */
- ssync;
-
- P0.h = hi(UART_THR);
- P0.l = lo(UART_THR);
- P1.h = hi(UART_LSR);
- P1.l = lo(UART_LSR);
-
- R0.L = 'K';
- call .Lwait_char;
- R0.L='e';
- call .Lwait_char;
- R0.L='r';
- call .Lwait_char;
- R0.L='n'
- call .Lwait_char;
- R0.L='e'
- call .Lwait_char;
- R0.L='l';
- call .Lwait_char;
- R0.L=' ';
- call .Lwait_char;
- R0.L='c';
- call .Lwait_char;
- R0.L='r';
- call .Lwait_char;
- R0.L='a';
- call .Lwait_char;
- R0.L='s';
- call .Lwait_char;
- R0.L='h';
- call .Lwait_char;
- R0.L='\r';
- call .Lwait_char;
- R0.L='\n';
- call .Lwait_char;
-
- R0.L='S';
- call .Lwait_char;
- R0.L='E';
- call .Lwait_char;
- R0.L='Q'
- call .Lwait_char;
- R0.L='S'
- call .Lwait_char;
- R0.L='T';
- call .Lwait_char;
- R0.L='A';
- call .Lwait_char;
- R0.L='T';
- call .Lwait_char;
- R0.L='=';
- call .Lwait_char;
- R2 = SEQSTAT;
- call .Ldump_reg;
-
- R0.L=' ';
- call .Lwait_char;
- R0.L='R';
- call .Lwait_char;
- R0.L='E'
- call .Lwait_char;
- R0.L='T'
- call .Lwait_char;
- R0.L='X';
- call .Lwait_char;
- R0.L='=';
- call .Lwait_char;
- R2 = RETX;
- call .Ldump_reg;
-
- R0.L='\r';
- call .Lwait_char;
- R0.L='\n';
- call .Lwait_char;
-
-.Ldebug_kernel_start_trap_done:
- JUMP .Ldebug_kernel_start_trap_done;
-.Ldump_reg:
- R3 = 32;
- R4 = 0x0F;
- R5 = ':'; /* one past 9 */
-
-.Ldump_reg2:
- R0 = R2;
- R3 += -4;
- R0 >>>= R3;
- R0 = R0 & R4;
- R0 += 0x30;
- CC = R0 <= R5;
- if CC JUMP .Ldump_reg1;
- R0 += 7;
-
-.Ldump_reg1:
- R1.l = W[P1];
- CC = BITTST(R1, 5);
- if !CC JUMP .Ldump_reg1;
- W[P0] = r0;
-
- CC = R3 == 0;
- if !CC JUMP .Ldump_reg2
- RTS;
-
-.Lwait_char:
- R1.l = W[P1];
- CC = BITTST(R1, 5);
- if !CC JUMP .Lwait_char;
- W[P0] = r0;
- RTS;
-
-#endif /* CONFIG_DEBUG_KERNEL_START */
-
.data

/*
Index: linux-2.6.x/arch/blackfin/kernel/setup.c
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/setup.c (revision 3568)
+++ linux-2.6.x/arch/blackfin/kernel/setup.c (working copy)
@@ -192,29 +187,6 @@
}
#endif

-#ifdef DEBUG_SERIAL_EARLY_INIT
- bfin_console_init(); /* early console registration */
- /* this give a chance to get printk() working before crash. */
-#endif
-


> -> add an early excaption handler

Index: linux-2.6.x/include/asm-blackfin/irq_handler.h
===================================================================
--- linux-2.6.x/include/asm-blackfin/irq_handler.h (revision 3568)
+++ linux-2.6.x/include/asm-blackfin/irq_handler.h (working copy)
@@ -1,3 +1,24 @@
+/*
+ * File: include/asm-blackfin/irq_handler.h
+ *
+ * Description: function prototypes for interrupt handler routines
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef _IRQ_HANDLER_H
#define _IRQ_HANDLER_H

@@ -22,6 +43,7 @@
asmlinkage void init_exception_buff(void);
asmlinkage void trap_c(struct pt_regs *fp);
asmlinkage void ex_replaceable(void);
+asmlinkage void early_trap(void);

extern void *ex_table[];
extern void return_from_exception(void);
Index: linux-2.6.x/arch/blackfin/kernel/early_printk.c
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/early_printk.c (revision 0)
+++ linux-2.6.x/arch/blackfin/kernel/early_printk.c (revision 0)
+/*
+ * Set up a temporary Event Vector Table, so if something bad happens before
+ * the kernel is fully started, it doesn't vector off into somewhere we don't
+ * know
+ */
+
+asmlinkage void __init init_early_exception_vectors(void)
+{
+ /* cannot program in software:
+ * evt0 - emulation (jtag)
+ * evt1 - reset
+ */
+ bfin_write_EVT2(early_trap);
+ bfin_write_EVT3(early_trap);
+ bfin_write_EVT5(early_trap);
+ bfin_write_EVT6(early_trap);
+ bfin_write_EVT7(early_trap);
+ bfin_write_EVT8(early_trap);
+ bfin_write_EVT9(early_trap);
+ bfin_write_EVT10(early_trap);
+ bfin_write_EVT11(early_trap);
+ bfin_write_EVT12(early_trap);
+ bfin_write_EVT13(early_trap);
+ bfin_write_EVT14(early_trap);
+ bfin_write_EVT15(early_trap);
+
+ /* Set all the return from interupt, exception, NMI to a known place
+ * so if we do a RETI, RETX or RETN by mistake - we go somewhere known
+ * Note - don't change RETS - we are in a subroutine, or
+ * RETE - since it might screw up if emulator is attached
+ */
+
+ asm("RETI = %0; RETX = %0; RETN = %0;\n" : : "p"(early_trap));
+}
+
+asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
+{
+ unsigned int serial_port = DEFAULT_PORT;
+ unsigned int cflag = DEFAULT_CFLAG;
+
+ /* This can happen before the uart is initialized, so initialize
+ * the UART now
+ */
+ if (!early_console_initialized) {
+ bfin_earlyserial_init(serial_port, cflag);
+ }
+
+ dump_bfin_regs(fp, retaddr);
+ dump_bfin_trace_buffer();
+
+ panic("Died early");
+}
Index: linux-2.6.x/arch/blackfin/mach-bf533/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf533/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf533/head.S (working copy)
@@ -214,6 +181,12 @@
fp = sp;
usp = sp;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK

Index: linux-2.6.x/arch/blackfin/mach-bf561/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf561/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf561/head.S (working copy)
@@ -169,6 +169,12 @@
fp = sp;
usp = sp;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
Index: linux-2.6.x/arch/blackfin/mach-bf537/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf537/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf537/head.S (working copy)
@@ -224,6 +224,12 @@
fp = sp;
usp = sp;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
Index: linux-2.6.x/arch/blackfin/mach-bf548/head.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-bf548/head.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-bf548/head.S (working copy)
@@ -125,6 +125,12 @@
FP = SP;
USP = SP;

+#ifdef CONFIG_EARLY_PRINTK
+ SP += -12;
+ call _init_early_exception_vectors;
+ SP += 12;
+#endif
+
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bf53x_relocate_l1_mem;
#if CONFIG_BFIN_KERNEL_CLOCK
Index: linux-2.6.x/arch/blackfin/mach-common/entry.S
===================================================================
--- linux-2.6.x/arch/blackfin/mach-common/entry.S (revision 3568)
+++ linux-2.6.x/arch/blackfin/mach-common/entry.S (working copy)
@@ -803,14 +803,57 @@
.section .l1.data.B
#endif
ENTRY(_trace_buff_offset)
- .long 0;
+ .long 0;
ALIGN
ENTRY(_software_trace_buff)
.rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256);
.long 0
.endr
+#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND */
+
+#ifdef CONFIG_EARLY_PRINTK
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
#endif

+ENTRY(_early_trap)
+ SAVE_ALL_SYS
+ trace_buffer_stop(p0, r0);
+
+ /* Turn caches off, to ensure we don't get double exceptions */
+
+ P4.L = LO(IMEM_CONTROL);
+ P4.H = HI(IMEM_CONTROL);
+
+ R5 = [P4]; /* Control Register*/
+ BITCLR(R5,ENICPLB_P);
+ CLI R1;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ P4.L = LO(DMEM_CONTROL);
+ P4.H = HI(DMEM_CONTROL);
+ R5 = [P4];
+ BITCLR(R5,ENDCPLB_P);
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R1;
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ r1 = RETX;
+
+ SP += -12;
+ call _early_trap_c;
+ SP += 12;
+ENDPROC(_early_trap)
+#endif /* CONFIG_EARLY_PRINTK */
+
/*
* Put these in the kernel data section - that should always be covered by
* a CPLB. This is needed to ensure we don't get double fault conditions


> -> adds early_printk





Index: linux-2.6.x/include/asm-blackfin/early_printk.h
===================================================================
--- linux-2.6.x/include/asm-blackfin/early_printk.h (revision 0)
+++ linux-2.6.x/include/asm-blackfin/early_printk.h (revision 0)
@@ -0,0 +1,28 @@
+/*
+ * File: include/asm-blackfin/early_printk.h
+ * Author: Robin Getz <[email protected]
+ *
+ * Created: 14Aug2007
+ * Description: function prototpyes for early printk
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef CONFIG_EARLY_PRINTK
+extern int setup_early_printk(char *);
+#else
+#define setup_early_printk(fmt) do { } while (0)
+#endif /* CONFIG_EARLY_PRINTK */

Index: linux-2.6.x/Documentation/kernel-parameters.txt
===================================================================
--- linux-2.6.x/Documentation/kernel-parameters.txt (revision 3568)
+++ linux-2.6.x/Documentation/kernel-parameters.txt (working copy)
@@ -34,6 +34,7 @@
APIC APIC support is enabled.
APM Advanced Power Management support is enabled.
AX25 Appropriate AX.25 support is enabled.
+ BLACKFIN Blackfin architecture is enabled.
CD Appropriate CD support is enabled.
DRM Direct Rendering Management support is enabled.
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
@@ -558,7 +559,7 @@

dtc3181e= [HW,SCSI]

- earlyprintk= [IA-32,X86-64,SH]
+ earlyprintk= [IA-32,X86-64,SH,BLACKFIN]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]

Index: linux-2.6.x/arch/blackfin/kernel/early_printk.c
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/early_printk.c (revision 0)
+++ linux-2.6.x/arch/blackfin/kernel/early_printk.c (revision 0)
@@ -0,0 +1,210 @@
+/*
+ * File: arch/blackfin/kernel/early_printk.c
+ * Based on: arch/x86_64/kernel/early_printk.c
+ * Author: Robin Getz <[email protected]
+ *
+ * Created: 14Aug2007
+ * Description: allow a console to be used for early printk
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <asm/blackfin.h>
+#include <asm/irq_handler.h>
+#include <asm/early_printk.h>
+
+extern struct console *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag);
+extern int bfin_earlyserial_disable(void);
+
+static struct console *early_console_initialized;
+
+/* Default console
+ * Port n == ttyBFn
+ * cflags == UART output modes
+ */
+#define DEFAULT_PORT 0
+#define DEFAULT_CFLAG CS8|B57600
+
+int __init setup_early_printk(char *buf)
+{
+ int baud, bit;
+ char parity;
+ unsigned int serial_port = DEFAULT_PORT;
+ unsigned int cflag = DEFAULT_CFLAG;
+
+ /* Crashing in here would be really bad, so check both the var
+ and the pointer before we start using it
+ */
+ if (!buf)
+ return 0;
+
+ if (!*buf)
+ return 0;
+
+ if (early_console_initialized)
+ return 0;
+
+ if (!strncmp(buf, "serial", 6)) {
+ buf += 7;
+ if (!strncmp(buf, "ttyBF", 5)) {
+ buf += 5;
+ serial_port = simple_strtoul(buf, &buf, 10);
+ buf++;
+ }
+
+ cflag = 0;
+ baud = simple_strtoul(buf, &buf, 10);
+ switch (baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 9600:
+ cflag |= B9600;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ default:
+ cflag |= B57600;
+ }
+
+ parity = buf[0];
+ buf++;
+ switch (parity) {
+ case 'e':
+ cflag |= PARENB;
+ break;
+ case 'o':
+ cflag |= PARODD;
+ break;
+ }
+
+ bit = simple_strtoul(buf, &buf, 10);
+ switch (bit) {
+ case 5:
+ cflag |= CS5;
+ break;
+ case 6:
+ cflag |= CS5;
+ break;
+ case 7:
+ cflag |= CS5;
+ break;
+ default:
+ cflag |= CS8;
+ }
+
+ early_console_initialized = bfin_earlyserial_init(serial_port,
+ cflag);
+ } else if (!strncmp(buf, "vga", 3)) {
+ /* TODO: add framebuffer console support? */
+ }
+
+ if (early_console_initialized)
+ printk(KERN_INFO "Early Printk Support Enabled on %s%d\n",
+ early_console_initialized->name,
+ early_console_initialized->index);
+
+ return 0;
+}
+
+int __init disable_early_printk(void)
+{
+ if (!early_console_initialized)
+ return 0;
+
+ printk(KERN_INFO "Unregister %s%d\n", early_console_initialized->name,
+ early_console_initialized->index);
+ unregister_console(early_console_initialized);
+ early_console_initialized = NULL;
+ return 0;
+}
+
+late_initcall(disable_early_printk);

Based on Mike's and Gerd's earlier comments I missed (until Mike poked me),
I will move the disable_early_printk into printk.c as a common function (and
a separate patch)

Index: linux-2.6.x/arch/blackfin/kernel/Makefile
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/Makefile (revision 3568)
+++ linux-2.6.x/arch/blackfin/kernel/Makefile (working copy)
@@ -15,3 +15,4 @@
obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
Index: linux-2.6.x/arch/blackfin/Kconfig
===================================================================
--- linux-2.6.x/arch/blackfin/Kconfig (revision 3568)
+++ linux-2.6.x/arch/blackfin/Kconfig (working copy)
@@ -1165,6 +1147,20 @@
Say Y here to disable hardware tracing in some known "jumpy" pieces
of code so that the trace buffer will extend further back.

+config EARLY_PRINTK
+ bool "Early printk"
+ default n
+ help
+ This option enables special console drivers which allow the kernel
+ to print messages very early in the bootup process.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. After enabling this
+ feature, you must add "earlyprintk=serial,ttyBF0,57600" to the
+ command line (bootargs). It is safe to say Y here in all cases, as
+ all of this lives in the init section and is thrown away after the
+ kernel boots completely.
+
config DUAL_CORE_TEST_MODULE
tristate "Dual Core Test Module"
depends on (BF561)

Index: linux-2.6.x/drivers/serial/bfin_5xx.c
===================================================================
--- linux-2.6.x/drivers/serial/bfin_5xx.c (revision 3568)
+++ linux-2.6.x/drivers/serial/bfin_5xx.c (working copy)
@@ -961,31 +961,7 @@
}

#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
- struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- while (!(UART_GET_LSR(uart) & THRE))
- barrier();
- UART_PUT_CHAR(uart, ch);
- SSYNC();
-}
-
/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
- int flags = 0;
-
- spin_lock_irqsave(&uart->port.lock, flags);
- uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
- spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
-/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
*/
@@ -1037,19 +1013,25 @@
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
}
+#endif

+#if defined (CONFIG_SERIAL_BFIN_CONSOLE) || defined (CONFIG_EARLY_PRINTK)
+static struct uart_driver bfin_serial_reg;
+
static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
struct bfin_serial_port *uart;
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
int baud = 57600;
int bits = 8;
int parity = 'n';
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# ifdef CONFIG_SERIAL_BFIN_CTSRTS
int flow = 'r';
-#else
+# else
int flow = 'n';
-#endif
+# endif
+# endif

/*
* Check whether an invalid uart number has been specified, and
@@ -1060,15 +1042,45 @@
co->index = 0;
uart = &bfin_serial_ports[co->index];

+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
bfin_serial_console_get_options(uart, &baud, &parity, &bits);

return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+# else
+ return 0;
+# endif
}
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+ defined (CONFIG_EARLY_PRINTK) */

-static struct uart_driver bfin_serial_reg;
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ while (!(UART_GET_LSR(uart) & THRE))
+ barrier();
+ UART_PUT_CHAR(uart, ch);
+ SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+ int flags = 0;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
static struct console bfin_serial_console = {
.name = BFIN_SERIAL_NAME,
.write = bfin_serial_console_write,
@@ -1094,8 +1106,70 @@
#define BFIN_SERIAL_CONSOLE &bfin_serial_console
#else
#define BFIN_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void early_serial_putc(struct uart_port *port, int ch)
+{
+ unsigned timeout = 0xffff;
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
+ cpu_relax();
+ UART_PUT_CHAR(uart, ch);
+}
+
+static __init void early_serial_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
+ unsigned int i;
+
+ for (i = 0; i < n; i++, s++) {
+ if (*s == '\n')
+ early_serial_putc(&uart->port, '\r');
+ early_serial_putc(&uart->port, *s);
+ }
+}
+
+static struct __init console bfin_early_serial_console = {
+ .name = "early_ttyBF",
+ .write = early_serial_write,
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .setup = bfin_serial_console_setup,
+ .index = -1,
+ .data = &bfin_serial_reg,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag)
+{
+ struct bfin_serial_port *uart;
+ struct ktermios t;
+
+ if (port == -1 || port >= nr_ports)
+ port = 0;
+ bfin_serial_init_ports();
+ bfin_early_serial_console.index = port;
+ register_console(&bfin_early_serial_console);
+#ifdef CONFIG_KGDB_UART
+ kgdb_entry_state = 0;
+ init_kgdb_uart();
#endif
+ uart = &bfin_serial_ports[port];
+ t.c_cflag = cflag;
+ t.c_iflag = 0;
+ t.c_oflag = 0;
+ t.c_lflag = ICANON;
+ t.c_line = port;
+ bfin_serial_set_termios(&uart->port, &t, &t);
+ return &bfin_early_serial_console;
+}

+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
.driver_name = "bfin-uart",


This is a helper to the above - make sure that earlyprintk is parsed as early
as possible. Otherwise there is some time between when kernel exception table
is filled in, and early_parm is evaluated - if a crash happens between this
time, nothing will be printed out.

Index: linux-2.6.x/arch/blackfin/kernel/setup.c
===================================================================
--- linux-2.6.x/arch/blackfin/kernel/setup.c (revision 3568)
+++ linux-2.6.x/arch/blackfin/kernel/setup.c (working copy)
@@ -44,6 +44,7 @@
#include <asm/blackfin.h>
#include <asm/cplbinit.h>
#include <asm/fixed_code.h>
+#include <asm/early_printk.h>

u16 _bfin_swrst;

@@ -134,7 +135,6 @@
unsigned int memsize;
for (;;) {
if (c == ' ') {
-
if (!memcmp(to, "mem=", 4)) {
to += 4;
memsize = memparse(to, &to);
@@ -157,8 +157,10 @@
1;
}
}
+ } else if (!memcmp(to, "earlyprintk=", 12)) {
+ to += 12;
+ setup_early_printk(to);
}
-
}
c = *(to++);
if (!c)
@@ -177,14 +179,7 @@
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
- cclk = get_cclk();
- sclk = get_sclk();

-#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
- if (ANOMALY_05000273 && cclk == sclk)
- panic("ANOMALY 05000273, SCLK can not be same as CCLK");
-#endif
-
#ifdef BF561_FAMILY
if (ANOMALY_05000266) {
bfin_read_IMDMA_D0_IRQ_STATUS();
@@ -192,29 +187,6 @@
}
#endif

-#ifdef DEBUG_SERIAL_EARLY_INIT
- bfin_console_init(); /* early console registration */
- /* this give a chance to get printk() working before crash. */
-#endif
-
- printk(KERN_INFO "Hardware Trace ");
- if (bfin_read_TBUFCTL() & 0x1 )
- printk("Active ");
- else
- printk("Off ");
- if (bfin_read_TBUFCTL() & 0x2)
- printk("and Enabled\n");
- else
- printk("and Disabled\n");
-
-
-#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
- /* we need to initialize the Flashrom device here since we might
- * do things with flash early on in the boot
- */
- flash_probe();
-#endif
-
#if defined(CONFIG_CMDLINE_BOOL)
strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
command_line[sizeof(command_line) - 1] = 0;
@@ -229,8 +201,36 @@
physical_mem_end = 0;
_ramend = CONFIG_MEM_SIZE * 1024 * 1024;

+ /* We parse command line early, to set memory limits and get
+ * early_printk earlier than normal
+ */
parse_cmdline_early(&command_line[0]);

+#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
+ /* we need to initialize the Flashrom device here since we might
+ * do things with flash early on in the boot
+ */
+ flash_probe();
+#endif
+
+ cclk = get_cclk();
+ sclk = get_sclk();
+
+#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
+ if (ANOMALY_05000273 && cclk < (sclk *2))
+ panic("ANOMALY 05000273: CCLK must be >= 2*SCLK ");
+#endif
+
+ printk(KERN_INFO "Hardware Trace ");
+ if (bfin_read_TBUFCTL() & 0x1 )
+ printk("Active ");
+ else
+ printk("Off ");
+ if (bfin_read_TBUFCTL() & 0x2)
+ printk("and Enabled\n");
+ else
+ printk("and Disabled\n");
+
if (physical_mem_end == 0)
physical_mem_end = _ramend;

@@ -298,13 +298,16 @@
* 05000263 - Hardware loop corrupted when taking an ICPLB exception
*/
#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
- if (memory_end >= 56 * 1024 * 1024)
+ if (memory_end >= 56 * 1024 * 1024) {
memory_end = 56 * 1024 * 1024;
+ printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
+ }
#else
- if (memory_end >= 60 * 1024 * 1024)
+ if (memory_end >= 60 * 1024 * 1024) {
memory_end = 60 * 1024 * 1024;
+ printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
+ }
#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
- printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
#endif /* ANOMALY_05000263 */

#if !defined(CONFIG_MTD_UCLINUX)
@@ -340,9 +343,6 @@
printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n",
cclk / 1000000, sclk / 1000000);

- if (ANOMALY_05000273 && (cclk >> 1) <= sclk)
- printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
-
printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);


2007-08-17 21:00:39

by Robin Getz

[permalink] [raw]
Subject: Re: Early printk behaviour

On Fri 17 Aug 2007 03:49, Gerd Hoffmann pondered:
> Mike Frysinger wrote:
> >> Hmm, sort of, although I didn't think about the case of no real console
> >> replacing the early console. The intention of the patch is to have a
> >> smooth handover from the boot console to the real console. And, yes, if
> >> no real console is ever registered the boot console keeps running ...
> >
> > i think it also occurs in the case where real console != early console
>
> No. At least not of the boot console has the CON_BOOT flag set as it
> should. Last message you'll see on the boot console is the handover
> printk, telling you which real console device prints the following
> messages. Whenever early and real console go to the physical device or
> not doesn't matter.
>
> >> So you can either let it running and *not* mark it __init, so it can
> >> keep on going without breaking. Or you can explicitly unregister your
> >> boot console at some point, maybe using a late_initcall.
> >
> > wouldnt a common kernel late_initcall() be more appropriate ? if
> > early console hasnt switched over (for whatever reason), then kill it
>
> Hmm, yes, should be doable in generic code. Check whenever the current
> console has CON_BOOT set and if so unregister it.

Something like:

Index: kernel/printk.c
===================================================================
--- kernel/printk.c (revision 3568)
+++ kernel/printk.c (working copy)
@@ -1104,6 +1104,22 @@
}
EXPORT_SYMBOL(unregister_console);

+int __init disable_boot_consoles(void)
+{
+ struct console *con;
+
+ for (con = console_drivers; con; con = con->next) {
+ if (con->flags & CON_BOOT) {
+ printk(KERN_INFO "Unregister BootConsole %s%d\n",
+ con->name, con->index);
+ unregister_console(con);
+ }
+ }
+ return 0;
+}
+late_initcall(disable_boot_consoles);
+
+
/**
* tty_write_message - write a message to a certain tty, not just the console.
* @tty: the destination tty_struct

2007-08-17 21:10:06

by Mike Frysinger

[permalink] [raw]
Subject: Re: Early printk behaviour

On 8/17/07, Robin Getz <[email protected]> wrote:
> On Fri 17 Aug 2007 03:49, Gerd Hoffmann pondered:
> > Mike Frysinger wrote:
> > >> Hmm, sort of, although I didn't think about the case of no real console
> > >> replacing the early console. The intention of the patch is to have a
> > >> smooth handover from the boot console to the real console. And, yes, if
> > >> no real console is ever registered the boot console keeps running ...
> > >
> > > i think it also occurs in the case where real console != early console
> >
> > No. At least not of the boot console has the CON_BOOT flag set as it
> > should. Last message you'll see on the boot console is the handover
> > printk, telling you which real console device prints the following
> > messages. Whenever early and real console go to the physical device or
> > not doesn't matter.
> >
> > >> So you can either let it running and *not* mark it __init, so it can
> > >> keep on going without breaking. Or you can explicitly unregister your
> > >> boot console at some point, maybe using a late_initcall.
> > >
> > > wouldnt a common kernel late_initcall() be more appropriate ? if
> > > early console hasnt switched over (for whatever reason), then kill it
> >
> > Hmm, yes, should be doable in generic code. Check whenever the current
> > console has CON_BOOT set and if so unregister it.
>
> Something like:
>
> Index: kernel/printk.c
> ===================================================================
> --- kernel/printk.c (revision 3568)
> +++ kernel/printk.c (working copy)
> @@ -1104,6 +1104,22 @@
> }
> EXPORT_SYMBOL(unregister_console);
>
> +int __init disable_boot_consoles(void)
> +{
> + struct console *con;
> +
> + for (con = console_drivers; con; con = con->next) {
> + if (con->flags & CON_BOOT) {
> + printk(KERN_INFO "Unregister BootConsole %s%d\n",
> + con->name, con->index);
> + unregister_console(con);
> + }
> + }
> + return 0;
> +}
> +late_initcall(disable_boot_consoles);

is there any need for a return value then ?
void __init disable_boot_consoles(void);

and if we dont think anyone else wants to call it ...
static void __init disable_boot_consoles(void);
-mike

2007-08-17 21:29:58

by Robin Getz

[permalink] [raw]
Subject: Re: Early printk behaviour

On Fri 17 Aug 2007 17:09, Mike Frysinger pondered:
> On 8/17/07, Robin Getz <[email protected]> wrote:
> >
> > Something like:
> >
> > Index: kernel/printk.c
> > ===================================================================
> > --- kernel/printk.c (revision 3568)
> > +++ kernel/printk.c (working copy)
> > @@ -1104,6 +1104,22 @@
> > }
> > EXPORT_SYMBOL(unregister_console);
> >
> > +int __init disable_boot_consoles(void)
> > +{
> > + struct console *con;
> > +
> > + for (con = console_drivers; con; con = con->next) {
> > + if (con->flags & CON_BOOT) {
> > + printk(KERN_INFO "Unregister BootConsole %s%d\n",
> > + con->name, con->index);
> > + unregister_console(con);
> > + }
> > + }
> > + return 0;
> > +}
> > +late_initcall(disable_boot_consoles);
>
> is there any need for a return value then ?
> void __init disable_boot_consoles(void);

So, we don't get compiler warnings?

Otherwise:
kernel/printk.c:1119: warning: initialization from incompatible pointer type

> and if we dont think anyone else wants to call it ...
> static void __init disable_boot_consoles(void);

So I think static is Ok, but it needs to be int - that is the proper prototype

-Robin

2007-08-18 06:22:26

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

> > What was preventing you from just using the x86_64 code here?
>
> Some was borrowed - but not much. since we don't support vga, or 16550 UARTs
> (Blackfin has it's own on-chip UART), I don't think this would work.
>
> Maybe I'm missing something - but I don't think so. Every one who implements
> implements direct IO to the hardware (except me, since I put it into the driver
> file, and force Sonic - the serial driver developer - to maintain it forever).
>
> Most of the other early printks talks directly to the hardware.
I only looked at your version and it looked general thats why I brought
up the code sharing idea - which I agree is not possible.

> > Thinking that all should do the same so maybe alpha ought to change...
>
> When I looked at all the printk implementations, I thought they were all
> kind of hokey, and not very common - but what do you want for a debug interface
> that lasts less than 5 seconds?
>
> ./arch/x86_64/kernel/early_printk.c
> ./arch/blackfin/kernel/early_printk.c
> ./arch/sh64/kernel/early_printk.c
> ./arch/sh/kernel/early_printk.c
> ./arch/i386/kernel/early_printk.c
> ./arch/mips/kernel/early_printk.c
>
> I didn't see an alpha implementation - where is it done?
Alpha uses the imlementation in lib/*print.c somehow.
And I think the right choice would be to implement
a private version of early_printk for alpha like the
other architectures do.

Thanks for the split-up. I could follow the changes now.

Sam

2007-08-18 15:38:11

by Robin Getz

[permalink] [raw]
Subject: Re: [draft] Blackfin Early Printk implmentation

On Sat 18 Aug 2007 02:23, Sam Ravnborg pondered:
> > > What was preventing you from just using the x86_64 code here?
> >
> > Some was borrowed - but not much. since we don't support vga, or
> > 16550 UARTs (Blackfin has it's own on-chip UART), I don't think
> > this would work. Everyone implements implements direct IO to
> > the hardware (except me, since I put it into the driver file,
> > and force Sonic - the serial driver developer - to maintain it
> > forever).
> >
> > Most of the other early printks talks directly to the hardware.
> I only looked at your version and it looked general thats why I brought
> up the code sharing idea - which I agree is not possible.

Believe me - I would actually like this more - put the I/O parts into the
serial driver or vga driver or xxx driver - and early printk becomes a
generic function that is supported on every platform, with a CON_BOOT
defined.

But, I didn't want (or have the time) to go mucking in everyone else's
arch/drivers to move things around - but the more I think about it - the
better it would be. Maybe on my next long plane trip I will look at it.

> > > Thinking that all should do the same so maybe alpha ought to
> > > change...
> >
> > When I looked at all the printk implementations, I thought they were
> > all kind of hokey, and not very common - but what do you want for a
> > debug interface that lasts less than 5 seconds?
> >
> > ./arch/x86_64/kernel/early_printk.c
> > ./arch/blackfin/kernel/early_printk.c
> > ./arch/sh64/kernel/early_printk.c
> > ./arch/sh/kernel/early_printk.c
> > ./arch/i386/kernel/early_printk.c
> > ./arch/mips/kernel/early_printk.c
> >
> > I didn't see an alpha implementation - where is it done?
> Alpha uses the imlementation in lib/*print.c somehow.
> And I think the right choice would be to implement
> a private version of early_printk for alpha like the
> other architectures do.

When looked for EARLY_PRINTK in ./arch/alpha - and include/asm-alpha, it only
shows up in the Kconfig files - nothing seems to use it...

> Thanks for the split-up. I could follow the changes now.

Any issues/comments? Or do things look OK?

-Robin

2007-08-20 08:01:32

by Gerd Hoffmann

[permalink] [raw]
Subject: Re: Early printk behaviour

Robin Getz wrote:

>> Hmm, yes, should be doable in generic code. Check whenever the current
>> console has CON_BOOT set and if so unregister it.
>
> Something like:
>
> +++ kernel/printk.c (working copy)
> +int __init disable_boot_consoles(void)
> +{
> + struct console *con;
> +
> + for (con = console_drivers; con; con = con->next) {
> + if (con->flags & CON_BOOT) {
> + printk(KERN_INFO "Unregister BootConsole %s%d\n",
> + con->name, con->index);
> + unregister_console(con);
> + }
> + }
> + return 0;
> +}
> +late_initcall(disable_boot_consoles);

Yep, that should work. You can drop the loop though. You can't
register a boot console if another console exists, and the first
non-boot console replaces the boot console, thus you never ever have
more than one console in case the boot console is still active.

The printk should be all lowercase like the other printk's in the file.

Other than that it loosk fine.

cheers,
Gerd