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 ]---