This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

tsc2007 driver problem with workqueue "Unable to handle kernel paging request at virtual address"

Hi

I am getting kernel oops because of  i2c_master_send function when i call tsc2007_wq_function function with schedule_work(&work), but when i directly call same function in timer function, it is working but in this case "BUG: scheduling while atomic: swapper" warning occurs and linux is crashing.

if "&normal_i2c" causes this problem which is in "static DECLARE_WORK(work, (void (*)(void *))tsc2007_wq_function, &normal_i2c)" has anybody got any idea what to write instead of it.


static unsigned int short normal_i2c[] = { 0x48, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1 (tsc2007);
static void tsc2007_wq_function(void *);
static DECLARE_WORK(work, (void (*)(void *))tsc2007_wq_function, &normal_i2c);
static void tsc2007_wq_function(void *arg)
{
 struct tsc2007_data *data = (struct tsc2007_data *)arg;
 struct i2c_client *client = &data->client;
 u16 x_value = 0;
 u16 y_value = 0;
 u8 measure_y = TSC2007_CMD (MEAS_YPOS, data->pd, data->m);
 u8 measure_x = TSC2007_CMD (MEAS_XPOS, data->pd, data->m);
 data->kernel_x = 0;
 data->kernel_y = 0;
 i2c_master_send (client,&measure_y, BYTES_TO_TX);
 i2c_master_recv (client,(u8 *)&y_value, BYTES_TO_RX);
 i2c_master_send (client,&measure_x, BYTES_TO_TX);
 i2c_master_recv (client,(u8 *)&x_value, BYTES_TO_RX);
 
 if (data->m == M_12BIT){
    data->kernel_y = (((be16_to_cpu (y_value)) >> 4) & VALUE_MASK);
    data->kernel_x = (((be16_to_cpu (x_value)) >> 4) & VALUE_MASK);
 }
 else if (data->m == M_8BIT){
    data->kernel_y = y_value;
    data->kernel_x = x_value;
 }
}

 

 

////////kernel oops message/////////

# ts_test
[   26.710000] Unable to handle kernel paging request at virtual address 00bbe59f
[   26.710000] pgd = c49d0000
[   26.720000] [00bbe59f] *pgd=00000000
[   26.720000] Internal error: Oops: 1 [#1]
[   26.720000] Modules linked in:
[   26.720000] CPU: 0
[   26.720000] PC is at i2c_transfer+0x18/0xe8
[   26.720000] LR is at i2c_master_send+0x44/0x54
[   26.720000] pc : [<c024aa5c>]    lr : [<c024b630>]    Not tainted
[   26.720000] sp : c0581eb8  ip : c0581ee8  fp : c0581ee4
[   26.720000] r10: c03e5f9c  r9 : c028e108  r8 : 00000000
[   26.720000] r7 : c03e5e00  r6 : 000001b6  r5 : 000001b4  r4 : fffefffe
[   26.720000] r3 : 00bbe59f  r2 : 00000001  r1 : c0581eec  r0 : fffefffe
[   26.720000] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  Segment kernel
[   26.720000] Control: 5317F
[   26.720000] Table: 849D0000  DAC: 00000017
[   26.720000] Process events/0 (pid: 12, stack limit = 0xc0580258)
[   26.720000] Stack: (0xc0581eb8 to 0xc0582000)
[   26.720000] 1ea0:                                                       c053eeb0 00000001
[   26.720000] 1ec0: 000001b4 000001b6 c03e5e00 00000000 c028e108 c03e5f9c c0581f0c c0581ee8
[   26.720000] 1ee0: c024b630 c024aa54 c055d040 0000fffe c0580001 c0581f17 c005f9d0 c03e5f9c
[   26.720000] 1f00: c0581f34 c0581f10 c028e174 c024b5fc 00009dc8 d0c00000 00000000 80000013
[   26.720000] 1f20: c05366a0 c0580000 c0581f6c c0581f38 c00625a4 c028e118 c05366b8 c05366a8
[   26.720000] 1f40: 00000002 00000000 c05366a8 c0580000 c05366a0 c05366b0 00000002 c0581f84
[   26.720000] 1f60: c0581fcc c0581f70 c0062dac c00624d4 00000001 00000000 c0049c08 00010000
[   26.720000] 1f80: 00000000 00000000 c055d040 c004b200 00100100 00200200 ffffffff ffffffff
[   26.720000] 1fa0: 00000000 c05366a0 c0580000 c0062ca4 c0551ee0 00000000 00000000 00000000
[   26.720000] 1fc0: c0581ff4 c0581fd0 c0065d10 c0062cb4 ffffffff ffffffff 00000000 00000000
[   26.720000] 1fe0: 00000000 00000000 00000000 c0581ff8 c0052a74 c0065c38 00000000 4800133a
[   26.720000] Backtrace:
[   26.720000] [<c024aa44>] (i2c_transfer+0x0/0xe8) from [<c024b630>] (i2c_master_send+0x44/0x54)
[   26.720000] [<c024b5ec>] (i2c_master_send+0x0/0x54) from [<c028e174>] (tsc2007_wq_function+0x6c/0x104)
[   26.720000]  r4 = C03E5F9C
[   26.720000] [<c028e108>] (tsc2007_wq_function+0x0/0x104) from [<c00625a4>] (run_workqueue+0xe0/0x170)
[   26.720000]  r6 = C0580000  r5 = C05366A0  r4 = 80000013
[   26.720000] [<c00624c4>] (run_workqueue+0x0/0x170) from [<c0062dac>] (worker_thread+0x108/0x144)
[   26.720000] [<c0062ca4>] (worker_thread+0x0/0x144) from [<c0065d10>] (kthread+0xe8/0x128)
[   26.720000] [<c0065c28>] (kthread+0x0/0x128) from [<c0052a74>] (do_exit+0x0/0x9cc)
[   26.720000]  r7 = 00000000  r6 = 00000000  r5 = 00000000  r4 = 00000000
[   26.720000] Code: e24cb004 e24dd004 e590300c e1a04000 (e5933000)
[   26.720000]  <7>evbug.c: Event. Dev: <NULL>, Type: 1, Code: 330, Value: 0
[   27.930000] evbug.c: Event. Dev: <NULL>, Type: 3, Code: 24, Value: 0
[   27.940000] evbug.c: Event. Dev: <NULL>, Type: 0, Code: 0, Value: 0
946684823.822249:    269 -19110   7500
946684825.041995:    269 -19110      0

 

2 Replies

  • Hi Ali,

    I forwarded your problem to an export on Linux, and asked for help. The following is his analysis:

    "

    I am looking at my kernel that I use for OMAP development (2.6.33) ...    In a cursory check, the panic trace suggests that the i2c_transfer function is 232 bytes long, where mine is 240 bytes long, a discrepancy of 4 bytes.  Right now I am trying 2.6.32 to see if it might match.  Right now I am working out a build on that version... so while I do this, I'll critique what I see here...

    First, with
    static unsigned int short normal_i2c[] = { 0x48, I2C_CLIENT_END };
    ...
    static DECLARE_WORK(work, (void (*)(void *))tsc2007_wq_function, &normal_i2c);
    static void tsc2007_wq_function(void *arg)

    What I see here is that this person is creating a task to deal with the data (&normal_i2c) which is then being passed to the work queue function, and then being cast...

    static void tsc2007_wq_function(void *arg)
    {
     struct tsc2007_data *data = (struct tsc2007_data *)arg;


    ... to a tsc2007_data.   It's an array of unsigned short ints.  I have no idea (I searched for it, didn't find it) what type the tsc2007_data is; or more to the point, what this structure contains.  I am convinced that it is not as small as the array being passed to the function, observing that within that structure there is an i2c_client structure which we take the address of here:

     struct i2c_client *client = &data->client;


    This is declared in include/linux/i2c.h...

       188  struct i2c_client {
       189          unsigned short flags;           /* div., see below              */
       190          unsigned short addr;            /* chip address - NOTE: 7bit    */
       191                                          /* addresses are stored in the  */
       192                                          /* _LOWER_ 7 bits               */
       193          char name[I2C_NAME_SIZE];
       194          struct i2c_adapter *adapter;    /* the adapter we sit on        */
       195          struct i2c_driver *driver;      /* and our access routines      */
       196          struct device dev;              /* the device structure         */
       197          int irq;                        /* irq issued by device         */
       198          struct list_head detected;
       199  };


    So, supposing that the client structure is the first element in the tsc2007_data structure, immediately the address that we're going to use is I2C_CLIENT_END (assuming we don't have any padding between elements) which is not right.

    Now that the build is complete, I've found that the i2c_transfer function blew up on line 1084  (assuming that I am using the right kernel version, which I'm not... this one's i2c_transfer function is 220 bytes long).  This does look correct to me, considering the type of oops/panic that we're seeing and the code, even though the kernel that I've built is different in this function:

    In drivers/i2c/i2c-core.c:

      1062  int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
      1063  {
      1064          unsigned long orig_jiffies;
      1065          int ret, try;
      1066
      1067          /* REVISIT the fault reporting model here is weak:
    ...
      1082           */
      1083
    *1084          if (adap->algo->master_xfer) {


    What we see going on here in 1084 is a check to see whether adap->algo->master_xfer is zero.  The field adap is taken straight out of i2c_client, deeper into the structure than the pointer to (two unsigned short ints) normal_i2c will support.

    I'd like to see the way this function is being called in the timer function... it's possible that it's being called correctly there, but I can guarantee you it's not being called correctly in this instance.   The data that needs to be passed to DECLARE_WORK should be a pointer to a properly-populated tsc2007_data structure, but right now, it's a pointer to an unsigned int array of two elements.

    "

  • In reply to Wendy Fang:

    Hi,

    I wonder if this problem has been resolved. I experience something similar on beagleboard clone board with tsc2007 on i2c bus 2 using Linux2.6.29-omap1. The driver works fine except for reading tsc2007 data via i2c WHILE inside timer function. I reads tsc2007 OK inside probe() but not when inside timer function where it causes kernel dump. Timer function looks like

     

    static void tsc2007_timer( unsigned long data ){

           unsigned long flags;

           struct tsc2007 *ts = (struct tsc2007 *)data;

           if (unlikely(!ts->get_pendown_state() && ts->pendown)) 

           {

                  struct input_dev *input = ts->input;

                  dev_dbg(&ts->client->dev, "UP\n");

                  input_report_key(input, BTN_TOUCH, 0);

                  input_report_abs(input, ABS_PRESSURE, 0);

                  input_sync(input);

                  ts->pendown = 0;

                  enable_irq( ts->irq );

                  ts->irq_disabled = 0;

           } else {

                  // pen is still down, continue with the measurement 

                  dev_dbg(&ts->client->dev, "DOWN\n");

                  tsc2007_read_values( ts ); // this makes kernel crash  

                  tsc2007_send_event(ts);

           }

    }   

     

    Here is the kernel dump caused by tsc2007_read_values( ts ) call

    [ 2750.183441] ------------[ cut here ]------------

    [ 2750.188110] WARNING: at kernel/mutex.c:351 mutex_trylock+0x68/0x13c()

    [ 2750.194580] Modules linked in: tsc2007 g_zero [last unloaded: tsc2007]

    [ 2750.201171] [<c035da80>] (dump_stack+0x0/0x14) from [<c005bfa8>] (warn_slowpath+0x68/0x9c)

    [ 2750.209533] [<c005bf40>] (warn_slowpath+0x0/0x9c) from [<c035ed74>] (mutex_trylock+0x68/0x13c)

    [ 2750.218231]  r3:c04e636c r2:00000000

    [ 2750.221862]  r7:00000001 r6:cfb2ee38 r5:00000049 r4:cfb2ee58

    [ 2750.227600] [<c035ed0c>] (mutex_trylock+0x0/0x13c) from [<c022a7a0>] (i2c_transfer+0xec/0x164)

    [ 2750.236297]  r6:cfb2ee38 r5:00000049 r4:00000001

    [ 2750.240966] [<c022a6b4>] (i2c_transfer+0x0/0x164) from [<c022b540>] (i2c_master_send+0x44/0x54     )

    [ 2750.249755] [<c022b4fc>] (i2c_master_send+0x0/0x54) from [<bf011078>] (tsc2007_read_values+0x2     c/0x418 [tsc2007])

    [ 2750.260040]  r4:cfbb31c0

    [ 2750.262573] [<bf01104c>] (tsc2007_read_values+0x0/0x418 [tsc2007]) from [<bf011880>] (tsc2007_     timer+0xe0/0x2a4 [tsc2007])

    [ 2750.273651]  r5:cfbb31c0 r4:00000103

    [ 2750.277282] [<bf0117a0>] (tsc2007_timer+0x0/0x2a4 [tsc2007]) from [<c00660dc>] (run_timer_soft     irq+0x1ac/0x250)

    [ 2750.287384] [<c0065f30>] (run_timer_softirq+0x0/0x250) from [<c0061ac0>] (__do_softirq+0x6c/0x     10c)

    [ 2750.296417] [<c0061a54>] (__do_softirq+0x0/0x10c) from [<c0061ba8>] (irq_exit+0x48/0x94)

    [ 2750.304595] [<c0061b60>] (irq_exit+0x0/0x94) from [<c003705c>] (__exception_text_start+0x5c/0x     70)

    [ 2750.313568] [<c0037000>] (__exception_text_start+0x0/0x70) from [<c0037a84>] (__irq_svc+0x44/0     xa4)

    [ 2750.322631] Exception stack(0xc0473f20 to 0xc0473f68)

    [ 2750.327697] 3f20: 2b4e76c4 a0000013 0051f4c5 00000000 c0043ad0 c0472000 c047603c c0038f1c

    [ 2750.336120] 3f40: c04a9bc8 411fc082 0000001f c0473f8c c0473f90 c0473f68 c0038edc c0043adc

    [ 2750.344512] 3f60: 60000013 ffffffff

    [ 2750.352905]  r5:d8200000 r4:ffffffff

    [ 2750.356506] [<c0043ad0>] (omap3_pm_idle+0x0/0x130) from [<c0038edc>] (cpu_idle+0x50/0x90)

    [ 2750.364776] [<c0038e8c>] (cpu_idle+0x0/0x90) from [<c0359924>] (rest_init+0x6c/0x80)

    [ 2750.372619]  r8:8002a3c4 r7:c0475ed0 r6:c002bea4 r5:c04a9764 r4:c04e34d4

    [ 2750.379394] [<c03598b8>] (rest_init+0x0/0x80) from [<c0008968>] (start_kernel+0x25c/0x2b8)

    [ 2750.387756] [<c000870c>] (start_kernel+0x0/0x2b8) from [<80008034>] (0x80008034)

    [ 2750.395233] ---[ end trace 91dd314bb23dd928 ]---

     

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.