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