5 Replies Latest reply: Jun 15, 2012 10:28 AM by bflino RSS

    How to load xeno_16550A.ko module

    bflino

      Hello everybody,

       

      I have compiled the kernel for BF518 so that the serial port support is provided by kernel modules.

       

      I first tried successfully to use the bfin_5xx.ko module with:

       

      insmod /lib/modules/2.6.34.7-ADI-2010R1/kernel/drivers/serial/serial_core.ko

      insmod /lib/modules/2.6.34.7-ADI-2010R1/kernel/drivers/serial/bfin_5xx.ko

       

      within /etc/rc.

      Serial port communication is working right at this point.

      With bfin_5xx.ko loaded, dmesg command outputs:

       

      bfin-uart: Blackfin serial driver

      bfin-uart.0: ttyBF0 at MMIO 0xffc00400 (irq = 29) is a BFIN-UART

       

      Now, before trying to load the xenomai serial port real time driver xeno_16550A, I have discarded bfin_5xx with:

       

      rmmod bfin_5xx

       

      and finally tried to load it:

       

      cd /lib/modules/2.6.34.7-ADI-2010R1/kernel/drivers/xenomai/serial

      modprobe xeno_16550A mem=0xffc00400 irq=29

       

      but here the device hangs and reboots.

       

      Any hint?

      Thank you very much in advance

        • 1. Re: How to load xeno_16550A.ko module
          sonic

          Do you have the xeno uart device connecting to Blackfin? Because xeno uart is not a device built by ADI. You’d better open debug option in xeno_16550A driver and trace where it crashes.

          • 2. Re: How to load xeno_16550A.ko module
            bflino

            sonic,

             

            if I understand correctly your first question, the xeno uart device is not created, i.e. the system crashes before loading the kernel module.

             

            Regarding the second question, the module init function (source in .../linux-2.6.x/drivers/xenomai/serial/16550A.c) is executed up to a kmalloc call, which looks like the responsible for crash:

             

            ...

            int __init rt_16550_init(void)
            {
              struct rtdm_device *dev;

             

              ...
              dev = kmalloc(sizeof(struct rtdm_device), GFP_KERNEL);

              ...

             

            The allocation size is just 180 bytes, so that should not be the problem.

            Note that even deleting code before dev = kmalloc..., within rt_16550_init, the device hangs at the same kmalloc line.

             

            What is strange to me, if I write from scratch a very simple ko module doing just the kmalloc call, it works fine.

            Might the kmalloc function called by 16550A.c be different from the "standard" kmalloc?

             

            Any hint for further investigation?

            Thank you

            • 3. Re: How to load xeno_16550A.ko module
              sonic

              How do you connect the xeno UART device to blackin on your board? Map registers into async memory region? Link interrupt to GPIO?

              What is the error log on your console when kernel crash?

              Do you have gnICE or ICE100B JTAG tool? We don't have your hardware, you'd better debug the driver init code via JTAG tool on your board.

              • 4. Re: How to load xeno_16550A.ko module
                bflino

                We are mapping registers into async memory region.

                 

                • The error log is:

                 

                Illegal use of supervisor resource
                <5> - Attempted to use a Supervisor register or instruction from User mode.
                <5>   Supervisor resources are registers and instructions that are reserved
                <5>   for Supervisor use: Supervisor only registers, all MMRs, and Supervisor
                <5>   only instructions.
                Kernel OOPS in progress
                Deferred Exception context
                CURRENT PROCESS:
                COMM=modprobe PID=228  CPU=0
                TEXT = 0x00500040-0x00532e20        DATA = 0x00532e40-0x0053cf28
                BSS = 0x0053cf28-0x0053e680  USER-STACK = 0x00543e8c

                return address: [0x0048e158]; contents of:
                0x0048e130:  320d  9108  0c00  1406  320d  e120  00e1  4f48
                0x0048e140:  9308  320e  9108  0c00  1403  6080  9308  0c42
                0x0048e150:  1460  adb1  6000  914a [e690] 0001  6c12  0030
                0x0048e160:  0000  0000  0024  9911  0040  6c1a  0030  0000

                ADSP-BF518-0.0(Detected 0.2) 400(MHz CCLK) 80(MHz SCLK) (mpu off)
                Linux version 2.6.34.7-ADI-2010R1 (devmachine@ubuntu) (gcc version 4.3.5 (ADI-20                                             10R1-RC4) ) #221 Wed Feb 29 16:46:09 CET 2012

                SEQUENCER STATUS:               Not tainted
                SEQSTAT: 0000002e  IPEND: 8008  IMASK: ffff  SYSCFG: 0006
                  EXCAUSE   : 0x2e
                  physical IVG3 asserted : <0xffa00760> { _trap + 0x0 }
                  physical IVG15 asserted : <0xffa00f10> { _evt_system_call + 0x0 }
                  logical irq   6 mapped  : <0xffa003a8> { _bfin_coretmr_interrupt + 0x0 }
                  logical irq  29 mapped  : <0x000d763c> { _bfin_serial_dma_rx_int + 0x0 }
                  logical irq  30 mapped  : <0x000d73b0> { _bfin_serial_dma_tx_int + 0x0 }
                  logical irq  35 mapped  : <0x000eb6fc> { _bfin_mac_interrupt + 0x0 }
                RETE: <0x00000000> /* Maybe null pointer? */
                RETN: <0x00b23e6c> /* kernel dynamic memory (maybe user-space) */
                RETX: <0x00000480> /* Maybe fixed code section */
                RETS: <0x0048e0ec> { :xeno_16550A:_init_module + 0xec }
                PC  : <0x0048e158> { :xeno_16550A:_init_module + 0x158 }
                DCPLB_FAULT_ADDR: <0xffc00401> /* system mmrs */
                ICPLB_FAULT_ADDR: <0x0048e158> { :xeno_16550A:_init_module + 0x158 }
                PROCESSOR STATE:
                R0 : 00000000    R1 : 00922232    R2 : 0092222c    R3 : fffffffc
                R4 : 004b18d4    R5 : 004b18f4    R6 : 004b1914    R7 : 0092222c
                P0 : 00922232    P1 : 004b1978    P2 : ffc00400    P3 : 004b1938
                P4 : 00000000    P5 : 00922220    FP : 004b1958    SP : 00b23d90
                LB0: 000c0e64    LT0: 000c0e62    LC0: 00000000
                LB1: 000bfe0a    LT1: 000bfe00    LC1: 00000000
                B0 : 00000000    L0 : 00000000    M0 : 00000000    I0 : 0048e310
                B1 : 00000000    L1 : 00000000    M1 : 00000000    I1 : 0049de00
                B2 : 00000000    L2 : 00000000    M2 : 00000000    I2 : 00000000
                B3 : 00000000    L3 : 00000000    M3 : 00000000    I3 : 00000000
                A0.w: 00000000   A0.x: 00000000   A1.w: 00000000   A1.x: 00000000
                USP : 00543bc0  ASTAT: 00003025

                Hardware Trace:
                   0 Target : <0x00003f0c> { _trap_c + 0x0 }
                     Source : <0xffa006f4> { _exception_to_level5 + 0xa4 } JUMP.L
                   1 Target : <0xffa00650> { _exception_to_level5 + 0x0 }
                     Source : <0xffa00504> { _bfin_return_from_exception + 0x18 } RTX
                   2 Target : <0xffa004ec> { _bfin_return_from_exception + 0x0 }
                     Source : <0xffa005a8> { _ex_trap_c + 0x74 } JUMP.S
                   3 Target : <0xffa00534> { _ex_trap_c + 0x0 }
                     Source : <0xffa007b8> { _trap + 0x58 } JUMP (P4)
                   4 Target : <0xffa00760> { _trap + 0x0 }
                      FAULT : <0x0048e158> { :xeno_16550A:_init_module + 0x158 } B[P2 + 0x4]= R0
                     Source : <0x0048e156> { :xeno_16550A:_init_module + 0x156 } P2 = [P1]
                   5 Target : <0x0048e130> { :xeno_16550A:_init_module + 0x130 }
                     Source : <0x0048e1ca> { :xeno_16550A:_init_module + 0x1ca } IF !CC JUMP pcr                                             el (BP)
                   6 Target : <0x0048e1c4> { :xeno_16550A:_init_module + 0x1c4 }
                     Source : <0x0048e258> { :xeno_16550A:_init_module + 0x258 } JUMP.S
                   7 Target : <0x0048e254> { :xeno_16550A:_init_module + 0x254 }
                     Source : <0x0048e1c0> { :xeno_16550A:_init_module + 0x1c0 } IF CC JUMP pcre                                             l (BP)
                   8 Target : <0x0048e1ba> { :xeno_16550A:_init_module + 0x1ba }
                     Source : <0x0048e0fc> { :xeno_16550A:_init_module + 0xfc } IF !CC JUMP pcre                                             l (BP)
                   9 Target : <0x0048e0ec> { :xeno_16550A:_init_module + 0xec }
                     Source : <0x000c0b3e> { _snprintf + 0x12 } RTS
                  10 Target : <0x000c0b3a> { _snprintf + 0xe }
                     Source : <0x000c08ac> { _vsnprintf + 0xac } RTS
                  11 Target : <0x000c087a> { _vsnprintf + 0x7a }
                     Source : <0x000bfe40> { _number + 0x194 } RTS
                  12 Target : <0x000bfe34> { _number + 0x188 }
                     Source : <0x000bfe18> { _number + 0x16c } IF CC JUMP pcrel
                  13 Target : <0x000bfdea> { _number + 0x13e }
                     Source : <0x000bfdd2> { _number + 0x126 } IF !CC JUMP pcrel
                  14 Target : <0x000bfdca> { _number + 0x11e }
                     Source : <0x000bfe58> { _number + 0x1ac } IF CC JUMP pcrel
                  15 Target : <0x000bfe42> { _number + 0x196 }
                     Source : <0x000bfdc6> { _number + 0x11a } IF CC JUMP pcrel (BP)
                Kernel Stack
                Stack info:
                SP: [0x00b23cc8] <0x00b23cc8> /* kernel dynamic memory (maybe user-space) */
                Memory from 0x00b23cc0 to 00b24000
                00b23cc0: 00b23d90  00000013 [004b1938] 00008008  00000004  004b18f4  0000002e                                               00b23d90
                00b23ce0: 00b23cc8  00000001  0086a3a0  0013d76a  00030005  00829060  00829be0                                               00b22008
                00b23d00: 00000001  0000001f  000bb27a  00805824  ffffffff  0000001f  000bb27a                                               00805824
                00b23d20: 00805820  001b9be4  00000000  00000001  00000000  00000001  001b9be4                                               008464e0
                00b23d40: 00b23d44  0080f794  00000000  001b9bf8  00000002  00000000  000080d0                                               0049dc00
                00b23d60: 0049dc00  0009f90e  ffa006f8  0019b000  ffe02014  00008008  0000002e                                               004b18f4
                00b23d80: 004b18d4  00923dcc  00b23dc0  00000480  00000480  00008008  0000002e                                               00000000
                00b23da0: 00b23e6c  00000480  0048e158 <0048e0ec> 00000000  00003025  000bfe0a                                               000c0e64
                00b23dc0: 000bfe00  000c0e62  00000000  00000000  00000000  00000000  00000000                                               00000000
                00b23de0: 00000000  00000000  00000000  00000000  00000000  00000000  00000000                                               00000000
                00b23e00: 00000000  00000000  00000000  00000000  00000000  00000000  0049de00                                               0048e310
                00b23e20: 00543bc0  004b1958  00922220  00000000  004b1938  ffc00400  004b1978                                               00922232
                00b23e40: 0092222c  004b1914  004b18f4  004b18d4  fffffffc  0092222c  00922232                                               00000000
                00b23e60: 00000000  00922232  00000006  004ae130  004ade54  004a1200  00000000                                               00000013
                00b23e80: 004b18b4  004b1978  0048e000 <00001028> 004b1768  0019900c  0019cb20                                               004a4004
                00b23ea0: 000037d4  00000000  0051ae9c  00000000  00000000  000241d0  004b1768                                               004a4004
                00b23ec0: 00543bcc  0002d560  004b1768  00000080  0053cb20  004a4004  000037d4                                               0053cb70
                00b23ee0: 00000000  0006b7be  00000000  00933120  ffffe000 <ffa00910> 0002d4bc                                               00000080
                00b23f00: 00000000  ffffe000  00bec19c  0053de98  0053cb0c  00b22000  000037d4                                               0051ae9c
                00b23f20: 00bec19c  00500f9c  00008000  00000000  00000000  00b24000  00500f9c                                               00500f9c
                00b23f40: 0051b1ce  ffa00f74  02001004  00509255  0050a14d  00509254  0050a14c                                               00000000
                00b23f60: 00000000  00000000  00000000  00000000  00000000  00000000  0053cb28                                               00000000
                00b23f80: 00000001  00000000  00000000  00000000  00000000  00000000  00000000                                               00000001
                00b23fa0: 00000000  00000000  00543c3c  00000000  0053cb64  00543bc0  00543bcc                                               0053de98
                00b23fc0: 0053cb0c  0053cb20  004a77d8  004a7ff4  00000080  004a4004  0053cb70                                               00bec19c
                00b23fe0: 0051ae9c  000037d4  0053cb70  000037d4  004a4004  004a4004  00000080                                               00000006
                Return addresses in stack:
                    address : <0x0048e0ec> { :xeno_16550A:_init_module + 0xec }
                    address : <0x00001028> { _do_one_initcall + 0x28 }
                    address : <0xffa00910> { _system_call + 0x88 }
                Modules linked in: xeno_16550A(+)
                Kernel panic - not syncing: Kernel exception

                 

                • We are evaluating buying gnICE.

                • Using KGDB I have discovered the following:

                 

                at loading of the module with modprobe xeno_16550A mem=0xffc00400 irq=29, code executed in kernel/module.c:

                 

                /* This is where the real work happens */
                SYSCALL_DEFINE3(init_module, void __user *, umod,
                  unsigned long, len, const char __user *, uargs)
                {
                struct module *mod;
                int ret = 0;

                /* Must have permission */
                if (!capable(CAP_SYS_MODULE) || modules_disabled)
                  return -EPERM;

                /* Only one module load at a time, please */
                if (mutex_lock_interruptible(&module_mutex) != 0)
                  return -EINTR;

                /* Do all the hard work */
                mod = load_module(umod, len, uargs);
                if (IS_ERR(mod)) {
                  mutex_unlock(&module_mutex);
                  return PTR_ERR(mod);
                }

                /* Drop lock so they can recurse */
                mutex_unlock(&module_mutex);

                blocking_notifier_call_chain(&module_notify_list,
                   MODULE_STATE_COMING, mod);

                do_mod_ctors(mod);
                /* Start the module */
                if (mod->init != NULL)
                  ret = do_one_initcall(mod->init);

                 

                and then init/main.c:

                 

                int do_one_initcall(initcall_t fn)
                {
                int count = preempt_count();
                ktime_t calltime, delta, rettime;

                if (initcall_debug) {
                  call.caller = task_pid_nr(current);
                  printk("calling  %pF @ %i\n", fn, call.caller);
                  calltime = ktime_get();
                  trace_boot_call(&call, fn);
                  enable_boot_trace();
                }

                ret.result = fn();

                 

                Where the value of fn is 0xa13000.

                But then, instead of executing rt_16550_init(), the function ipipe_test_foreign_stack in linux/ipipe.h is called:

                 

                static inline int ipipe_test_foreign_stack(void)

                {

                /* Must be called hw interrupts off. */

                return test_bit(IPIPE_NOSTACK_FLAG, &ipipe_this_cpudom_var(status));

                }

                 

                at this point the debugger hangs.

                I tried to load xeno_16550A symbols with:

                 

                add-symbol-file .../xeno_16550A.ko 0xa13000

                 

                and when stepping into ipipe_test_foreign_stack, the debugger (ddd + gdb) tells me:

                 

                (gdb) step

                0x00a13002 in rt_16550_exit () at include/linux/ipipe.h:576

                 

                strange because I am doing init, not exit...

                 

                Any more hints? Thank you!

                • 5. Re: How to load xeno_16550A.ko module
                  bflino

                  For those who might be interested in the solution, we finally managed to find the issues.

                  The line:

                   

                  FAULT : <0x0048e158> { :xeno_16550A:_init_module + 0x158 } B[P2 + 0x4]= R0
                     
                  within the Hardware Trace in error log output shows a wrong access to the UART register area at 0xffc00400.

                  As the hardware reference manual says, these registers must be accessed in words ("Software must use 16-bit word load/store instructions to access these registers"), not bytes, like done by the driver (16550 standard has one byte wide registers).

                  Thus 16550A_io.h must be updated to replace memory access calls like this:

                   

                  inb -> inw
                  outb -> outw
                  readb -> readw
                  writeb -> writew

                   

                  That solves the kernel crash at insmod/modprobe of the module.


                  Note that kgdb did not provide useful information (it did not track the real problem).

                   

                  Once that the module can be loaded, other changes needed to make it work properly are corrections in the register offsets in 16550A.c:

                   

                  from:
                  #define RHR  0 /* Receive Holding Buffer */
                  #define THR  0 /* Transmit Holding Buffer */
                  #define DLL  0 /* Divisor Latch LSB */
                  #define IER  1 /* Interrupt Enable Register */
                  #define DLM  1 /* Divisor Latch MSB */
                  #define IIR  2 /* Interrupt Id Register */
                  #define FCR  2 /* Fifo Control Register */
                  #define LCR  3 /* Line Control Register */
                  #define MCR  4 /* Modem Control Register */
                  #define LSR  5 /* Line Status Register */
                  #define MSR  6 /* Modem Status Register */

                   

                  into:
                  #define RHR  0x00 /* Receive Holding Buffer */
                  #define THR  0x00 /* Transmit Holding Buffer */
                  #define DLL  0x00 /* Divisor Latch LSB */
                  #define IER  0x04 /* Interrupt Enable Register */
                  #define DLM  0x04 /* Divisor Latch MSB */
                  #define IIR  0x08 /* Interrupt Id Register */
                  #define LCR  0x0C /* Line Control Register */
                  #define MCR  0x10 /* Modem Control Register */
                  #define LSR  0x14 /* Line Status Register */

                   

                  note that some registers are not present in blackfin, so the corresponding code should be commented accordingly.

                  Finally, note that blackfin has three IRQs (29: RX, 30: TX, 19: STAT) instead of the standard unique IRQ in 16550, so modify the following code:

                   

                  err = rtdm_irq_request(&ctx->irq_handle, irq[dev_id],
                            rt_16550_interrupt,
                            RTDM_IRQTYPE_SHARED | RTDM_IRQTYPE_EDGE,
                            context->device->proc_name, ctx);

                   

                  into something like this (add two new fields for ctx):

                   

                  err = rtdm_irq_request(&ctx->irq_handle_rx, irq[dev_id],
                            rt_16550_interrupt,
                            RTDM_IRQTYPE_SHARED | RTDM_IRQTYPE_EDGE,
                            context->device->proc_name, ctx);  // IRQ 29
                  if (!err)
                  {
                    err = rtdm_irq_request(&ctx->irq_handle_tx, irq[dev_id] + 1,
                            rt_16550_interrupt,
                            RTDM_IRQTYPE_SHARED | RTDM_IRQTYPE_EDGE,
                            context->device->proc_name, ctx);    // IRQ 30
                    if (!err)
                    {
                    err = rtdm_irq_request(&ctx->irq_handle_stat, 19,
                              rt_16550_interrupt,
                              RTDM_IRQTYPE_SHARED | RTDM_IRQTYPE_EDGE,
                              context->device->proc_name, ctx);    // IRQ 19
                    } 
                  }

                   

                  and install the module with (BF518):

                   

                  insmod xeno_16550A.ko io=0xffc00400 irq=29 baud_base=5000000 tx_fifo=1

                   

                  (baud_base = SCLK / 16 = 80000000 / 16 = 5000000 in the example).

                   

                  Use the kernel PIO option to communicate with the peripheral device.

                   

                  Update June 2012:

                   

                  Blackfin specific initialization is needed in rt_serial_init too (add blue text):

                  ...

                  #define GCTL    0x24 /* Global Control Register     */

                  ...

                  int __init rt_serial_init(void)
                  {
                  struct rtdm_device *dev;
                  unsigned long base, tmpReg;
                  int err;
                  int i;


                  for (i = 0; i < MAX_DEVICES; i++) {
                    if (!io[i])
                     continue;

                    err = -EINVAL;

                    dev = kmalloc(sizeof(struct rtdm_device), GFP_KERNEL);
                    err = -ENOMEM;
                    if (!dev)
                     goto cleanup_out;

                    memcpy(dev, &device_tmpl, sizeof(struct rtdm_device));
                    snprintf(dev->device_name, RTDM_MAX_DEVNAME_LEN, "rtser%d",i);
                    dev->device_id = i;

                    dev->proc_name = dev->device_name;

                    err = rt_serial_init_io(i, dev->device_name);
                    if (err)
                     goto kfree_out;

                    /* Write PortG MUX to select 2nd function (UART0, Bits 11=0:10=1) */
                    tmpReg = bfin_read16(PORTG_MUX);
                    bfin_write16(PORTG_MUX, tmpReg & 0xf7ff);
                    bfin_write16(PORTG_MUX, tmpReg | 0x400);
                    /* Write PortG FER to set peripheral bits (PG9/PG10)    */
                    tmpReg = bfin_read16(PORTG_FER);
                    bfin_write16(PORTG_FER, tmpReg | 0x600);
                   
                    baud_base[i] = get_sclk()/16;

                    /* Mask all UART interrupts and clear pending ones. */
                    base = io[i];
                    /* Enable UART0              */
                    rt_serial_reg_out( base, GCTL,1);
                    rt_serial_reg_out( base, IER, 0);
                    rt_serial_reg_in( base, IIR);
                    rt_serial_reg_in( base, LSR);
                    rt_serial_reg_in( base, RHR);

                    ...