console_init() question
From: Povolotsky, Alexander <hidden>
Date: 2005-01-28 02:17:09
Hi, =20
I am struggling with bringing up the MPC 880 board on Linux 2.6-10.rc3 =
...
I could see that only 3 characters (see below) from the linux_banner =
are
printed
in __init start_kernel() (init/main.c) upon booting.
Then a lot of garbage is outputted and eventually kernel hangs ...
...
after gunzip
done.
Now booting the kernel
Lin=FF=FF=FF=FF=FF=FF=FF=FF=C0=FF=FF=FF=FF=FF=FF=FF=FF=C08=C0=FF=FF=FF=FF=
=FF=FF=FF=FF=C0X=C0=FF=FF=FF=FF=FF=FF=FF=FF=C0x=C0=FF=FF=FF=FF=FF=FF=FF=FF=
=C0~=C0=FF=FF=FF=FF=FF=FF=FF=FF=C0=B8=C0=FF=FF=FF=FF=FF=FF=FF=FF=C0
=D8=C0=FF=FF
<more garbage>
<hangs> ...=20
...
Very laborious debugging (without BDM and soft reset button - but with =
great
help) shows that the hang is caused by the console
serial driver at about (or just soon after)=20
console_drivers =3D console;
statement in
register_console(struct console * console)
function (in kernel/printk.c )=20
=20
I can not find (so far ) any specific error in values supplied vi =
bd_info
from the ("custom" modified pSOS bootloader) causing above problem.=20
The debug output showing my serial settings was saved into log buffer = and read at "bootloader time" after=20 "software stimulated" "soft reboot" - it is listed here. Could someone kindly spare 5 min examining supplied debug output from = both cpm_uart_set_termios()
(in drivers/serial/cpm_uart/cpm_uart_core.c) and cpm_setbrg() (in arch/ppc/8xx_io/commproc.c) and tell
me what is wrong there ?
The output is supplied at the end of my e-mail after the listings of functions (with my print statements) =20 Thanks, Alex =20
PS - I noticed (with help and via "trial and error" way) that =
console_init()
code is written to work only with
"boot" (unmapped) memory and therefore only could work if
executed prior to mem_init().=20
Suppose I would disable (comment out in main.c ) the =
console_init()
call
and suppose (I do not know yet since did not tried that) the =
kernel
booting
will continue without any additional problems and will =
sucessfully
finish (just without the console ;-) )
- is there any existant "non-standard" "debugging" =
"experimental"
code,
which I could integrate and execute with the aim to "late" =
launch my
serial console at that point ?
***************** drivers/serial/cpm_uart/cpm_uart_core.c
******************
....
#define DEBUG=20
....
static void cpm_uart_set_termios(struct uart_port *port,
struct termios *termios, struct =termios
*old)
{
int baud;
unsigned long flags;
u16 cval, scval, prev_mode;
int bits, sbits;
struct uart_cpm_port *pinfo =3D (struct uart_cpm_port *)port;
volatile smc_t *smcp =3D pinfo->smcp;
volatile scc_t *sccp =3D pinfo->sccp;
#ifdef DEBUG
pr_debug("CPM uart[%d]:set_termios\n", port->line);
#endif
=20
baud =3D uart_get_baud_rate(port, termios, old, 0, =port->uartclk /
16);
=20
#ifdef DEBUG
pr_debug("CPM uart baud=3D%d\n", baud);
#endif
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity =bit,
* 1 or 2 stop bits, minus 1.
* The value 'bits' counts this for us.
*/
cval =3D 0;
scval =3D 0;
=20
/* byte size */
switch (termios->c_cflag & CSIZE) {
case CS5:
bits =3D 5;
break;
case CS6:
bits =3D 6;
break;
case CS7:
bits =3D 7;
break;
case CS8:
bits =3D 8;
break;
/* Never happens, but GCC is too dumb to figure it =out */
default:
bits =3D 8;
break;
}
sbits =3D bits - 5;
#ifdef DEBUG
pr_debug("CPM uart bits=3D%d\n", bits);
pr_debug("CPM uart sbits=3D%d\n", sbits);
#endif
=20
if (termios->c_cflag & CSTOPB) {
cval |=3D SMCMR_SL; /* Two stops */
scval |=3D SCU_PSMR_SL;
bits++;
}
=20
if (termios->c_cflag & PARENB) {
cval |=3D SMCMR_PEN;
scval |=3D SCU_PSMR_PEN;
bits++;
if (!(termios->c_cflag & PARODD)) {
cval |=3D SMCMR_PM_EVEN;
scval |=3D (SCU_PSMR_REVP | SCU_PSMR_TEVP);
}
}
#ifdef DEBUG
pr_debug("CPM uart bits=3D%d\n", bits);
pr_debug("CPM uart cval=3D%d\n", cval);
pr_debug("CPM uart scval=3D%d\n", scval);
#endif
=20
/*
* Set up parity check flag
*/
#define RELEVANT_IFLAG(iflag) (iflag &
(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
=20
port->read_status_mask =3D (BD_SC_EMPTY | BD_SC_OV);
if (termios->c_iflag & INPCK)
port->read_status_mask |=3D BD_SC_FR | BD_SC_PR;
if ((termios->c_iflag & BRKINT) || (termios->c_iflag & =PARMRK))
port->read_status_mask |=3D BD_SC_BR;
=20
/*
* Characters to ignore
*/
port->ignore_status_mask =3D 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |=3D BD_SC_PR | BD_SC_FR;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |=3D BD_SC_BR;
/*
* If we're ignore parity and break indicators, =ignore
* overruns too. (For real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |=3D BD_SC_OV;
ifdef DEBUG
if (termios->c_iflag & IGNPAR)
pr_debug("CPM uart real raw support");
endif
}
/*
* !!! ignore all characters if CREAD is not set
*/
if ((termios->c_cflag & CREAD) =3D=3D 0)
port->read_status_mask &=3D ~BD_SC_EMPTY;
ifdef DEBUG
if ((termios->c_cflag & CREAD) =3D=3D 0)
pr_debug("CPM uart CREAD is not set");
endif
=20
spin_lock_irqsave(&port->lock, flags);
=20
/* Start bit has not been added (so don't, because we would =just
* subtract it later), and we need to add one for the number =
of
* stops bits (there is always at least one).
*/
bits++;
ifdef DEBUG
pr_debug("CPM uart bits=3D%d\n", bits);
endif
if (IS_SMC(pinfo)) {
/* Set the mode register. We want to keep a copy of =the
* enables, because we want to put them back if they =
were
* present.
*/
prev_mode =3D smcp->smc_smcmr;
smcp->smc_smcmr =3D smcr_mk_clen(bits) | cval |
SMCMR_SM_UART;
smcp->smc_smcmr |=3D (prev_mode & (SMCMR_REN | =SMCMR_TEN));
ifdef DEBUG
pr_debug("CPM uart IS_SMCpinfo > 0 \n");
endif
} else {
sccp->scc_psmr =3D (sbits << 12) | scval;
}
=20
cpm_set_brg(pinfo->brg - 1, baud);
ifdef DEBUG
pr_debug(" returned from cpm_set_brg");
endif
spin_unlock_irqrestore(&port->lock, flags);
ifdef DEBUG
pr_debug("after spin_unlock_irqrestore");
#endif
*(int*)0 =3D 0xdeadbeef; <=3D=3D=3D=3D I have inserted here =to force
crash and soft reboot - it works !
#ifdef DEBUG
pr_debug("after deadbeef"); <<=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =I have inserted here
for double check - never reached ...
#endif
=20
}
=20
***************************** arch/ppc/8xx_io/commproc.c
***********************************=20
=20
#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq)
#define BRG_UART_CLK (BRG_INT_CLK/16)
#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
=20
void
cpm_setbrg(uint brg, uint rate)
{
volatile uint *bp;
unsigned long brgUrtClkDiv16 =3D BRG_UART_CLK_DIV16;
=20
/* This is good enough to get SMCs running.....
*/
bp =3D (uint *)&cpmp->cp_brgc1;
=20
printk("cpm_setbrg: BRG_UART_CLK_DIV16 %lu",brgUrtClkDiv16);
printk("cpm_setbrg: *bp came as %u",*bp);
printk("cpm_setbrg: rate came as %u",rate);
bp +=3D brg;
=20
printk("cpm_setbrg: *bp is now %u",*bp);
/* The BRG has a 12-bit counter. For really slow baud rates =(or
* really fast processors), we may have to further divide by =
16.
*/
if (((BRG_UART_CLK / rate) - 1) < 4096)
*bp =3D (((BRG_UART_CLK / rate) - 1) << 1) | =CPM_BRG_EN;
else
*bp =3D (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
CPM_BRG_EN |
CPM_BRG_DIV16;
=20
=20
printk("cpm_setbrg: *bp is set to %u",*bp);
=20
}
=20
****************************
Now the output in the log buffer from both cpm_uart_set_termios() and
cpm_setbrg() ) :
*********************************************
=20
< 7>CPM uart[0]:set_termios.
<7>CPM uart baud =3D115200.
<7>CPM uart bits=3D8.
.<7>CPM uart cval=3D0.
.<7>CPM uart bits=3D9.
.<4>cpm_setbrg: BRG_UART_CLK_DIV16 195312
cpm_setbrg: *bp came as 65588
cpm_setbrg: rate came as 115200
cpm_setbrg: *bp is now 65588
cpm_setbrg: *bp is set to 65588
<7>returned from cpm_set_brg
<7>after spin_unlock_irqrestore
=20