console_init() question
Povolotsky, Alexander
Alexander.Povolotsky at marconi.com
Fri Jan 28 13:07:26 EST 2005
> Hi,
>
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ÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÀ8ÀÿÿÿÿÿÿÿÿÀXÀÿÿÿÿÿÿÿÿÀxÀÿÿÿÿÿÿÿÿÀ~ÀÿÿÿÿÿÿÿÿÀ¸ÀÿÿÿÿÿÿÿÿÀ
ØÀÿÿ
<more garbage>
<hangs> ...
...
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)
console_drivers = console;
statement in
register_console(struct console * console)
function (in kernel/printk.c )
I can not find (so far ) any specific error in values supplied vi bd_info
from the ("custom" modified pSOS bootloader) causing above problem.
>
The debug output showing my serial settings was saved into log buffer and
read at "bootloader time" after
"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)
>
> Thanks,
> Alex
>
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().
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
> ....
> 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 = (struct uart_cpm_port *)port;
> volatile smc_t *smcp = pinfo->smcp;
> volatile scc_t *sccp = pinfo->sccp;
> #ifdef DEBUG
> pr_debug("CPM uart[%d]:set_termios\n", port->line);
> #endif
>
> baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk /
> 16);
>
> #ifdef DEBUG
> pr_debug("CPM uart baud=%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 = 0;
> scval = 0;
>
> /* byte size */
> switch (termios->c_cflag & CSIZE) {
> case CS5:
> bits = 5;
> break;
> case CS6:
> bits = 6;
> break;
> case CS7:
> bits = 7;
> break;
> case CS8:
> bits = 8;
> break;
> /* Never happens, but GCC is too dumb to figure it out */
> default:
> bits = 8;
> break;
> }
> sbits = bits - 5;
> #ifdef DEBUG
> pr_debug("CPM uart bits=%d\n", bits);
> pr_debug("CPM uart sbits=%d\n", sbits);
> #endif
>
> if (termios->c_cflag & CSTOPB) {
> cval |= SMCMR_SL; /* Two stops */
> scval |= SCU_PSMR_SL;
> bits++;
> }
>
> if (termios->c_cflag & PARENB) {
> cval |= SMCMR_PEN;
> scval |= SCU_PSMR_PEN;
> bits++;
> if (!(termios->c_cflag & PARODD)) {
> cval |= SMCMR_PM_EVEN;
> scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP);
> }
> }
> #ifdef DEBUG
> pr_debug("CPM uart bits=%d\n", bits);
> pr_debug("CPM uart cval=%d\n", cval);
> pr_debug("CPM uart scval=%d\n", scval);
> #endif
>
> /*
> * Set up parity check flag
> */
> #define RELEVANT_IFLAG(iflag) (iflag &
> (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
>
> port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
> if (termios->c_iflag & INPCK)
> port->read_status_mask |= BD_SC_FR | BD_SC_PR;
> if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
> port->read_status_mask |= BD_SC_BR;
>
> /*
> * Characters to ignore
> */
> port->ignore_status_mask = 0;
> if (termios->c_iflag & IGNPAR)
> port->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
> if (termios->c_iflag & IGNBRK) {
> port->ignore_status_mask |= 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 |= 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) == 0)
> port->read_status_mask &= ~BD_SC_EMPTY;
> ifdef DEBUG
> if ((termios->c_cflag & CREAD) == 0)
> pr_debug("CPM uart CREAD is not set");
> endif
>
> spin_lock_irqsave(&port->lock, flags);
>
> /* 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=%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 = smcp->smc_smcmr;
> smcp->smc_smcmr = smcr_mk_clen(bits) | cval |
> SMCMR_SM_UART;
> smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
> ifdef DEBUG
> pr_debug("CPM uart IS_SMCpinfo > 0 \n");
> endif
> } else {
> sccp->scc_psmr = (sbits << 12) | scval;
> }
>
> 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 = 0xdeadbeef; <==== I have inserted here to force
> crash and soft reboot - it works !
> #ifdef DEBUG
> pr_debug("after deadbeef"); <<========== I have inserted here
> for double check - never reached ...
> #endif
>
> }
>
> ***************************** arch/ppc/8xx_io/commproc.c
> ***********************************
>
> #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)
>
> void
> cpm_setbrg(uint brg, uint rate)
> {
> volatile uint *bp;
> unsigned long brgUrtClkDiv16 = BRG_UART_CLK_DIV16;
>
> /* This is good enough to get SMCs running.....
> */
> bp = (uint *)&cpmp->cp_brgc1;
>
> 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 += brg;
>
> 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 = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
> else
> *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
> CPM_BRG_EN |
> CPM_BRG_DIV16;
>
>
> printk("cpm_setbrg: *bp is set to %u",*bp);
>
> }
>
> ****************************
> Now the output in the log buffer from both cpm_uart_set_termios() and
> cpm_setbrg() ) :
> *********************************************
>
> < 7>CPM uart[0]:set_termios.
> <7>CPM uart baud =115200.
> <7>CPM uart bits=8.
> .<7>CPM uart cval=0.
> .<7>CPM uart bits=9.
> .<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
>
More information about the Linuxppc-embedded
mailing list