Re: [PATCH 2/6] si4713 : Modified i2c driver to handle cases where interrupts are not used

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Dinesh and Hans,

On Mon, Sep 2, 2013 at 6:29 AM, Dinesh Ram <Dinesh.Ram@xxxxxxx> wrote:
> Hi Hans and Eduardo,
>
> Sorry for my radio silence. I was infact travelling and didn't have much opportunity to check my mails.
> I will go through the list of comments in the thread and try to fix / justify them in the next few days.
> Hans, probably at the end you might have to test it as I don't have the hardware anymore.


I have the board and gave a shot of your driver. Looks like there is
still some work to be done. Please have a look on my comment on the
patch that adds the USB driver. Besides reviewing I will be also
testing your patches.

All best,

>
> Regards,
> Dinesh
> ________________________________________
> From: Hans Verkuil [hverkuil@xxxxxxxxx]
> Sent: 02 September 2013 09:11
> To: edubezval@xxxxxxxxx
> Cc: Dinesh Ram; Linux-Media; Dinesh Ram
> Subject: Re: [PATCH 2/6] si4713 : Modified i2c driver to handle cases where interrupts are not used
>
> On 09/01/2013 04:45 PM, edubezval@xxxxxxxxx wrote:
>> Hello Hans,
>>
>>
>> On Sun, Sep 1, 2013 at 6:57 AM, Hans Verkuil <hverkuil@xxxxxxxxx> wrote:
>>>
>>> On 08/31/2013 01:31 PM, edubezval@xxxxxxxxx wrote:
>>>> Dinesh, Hi
>>>>
>>>>
>>>> On Fri, Aug 30, 2013 at 7:28 AM, Dinesh Ram <dinram@xxxxxxxxx> wrote:
>>>>>
>>>>> Checks have been introduced at several places in the code to test if an interrupt is set or not.
>>>>> For devices which do not use the interrupt, to get a valid response, within a specified timeout,
>>>>> the device is polled instead.
>>>>>
>>>>> Signed-off-by: Dinesh Ram <dinram@xxxxxxxxx>
>>>>> ---
>>>>>  drivers/media/radio/si4713/si4713.c | 110 ++++++++++++++++++++----------------
>>>>>  drivers/media/radio/si4713/si4713.h |   1 +
>>>>>  2 files changed, 63 insertions(+), 48 deletions(-)
>>>>>
>>>>> diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
>>>>> index ac727e3..55c4d27 100644
>>>>> --- a/drivers/media/radio/si4713/si4713.c
>>>>> +++ b/drivers/media/radio/si4713/si4713.c
>>>>> @@ -27,7 +27,6 @@
>>>>>  #include <linux/i2c.h>
>>>>>  #include <linux/slab.h>
>>>>>  #include <linux/gpio.h>
>>>>> -#include <linux/regulator/consumer.h>
>>>>>  #include <linux/module.h>
>>>>>  #include <media/v4l2-device.h>
>>>>>  #include <media/v4l2-ioctl.h>
>>>>> @@ -213,6 +212,7 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command,
>>>>>                                 u8 response[], const int respn, const int usecs)
>>>>>  {
>>>>>         struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
>>>>> +       unsigned long until_jiffies;
>>>>>         u8 data1[MAX_ARGS + 1];
>>>>>         int err;
>>>>>
>>>>> @@ -228,30 +228,39 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command,
>>>>>         if (err != argn + 1) {
>>>>>                 v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n",
>>>>>                         command);
>>>>> -               return (err > 0) ? -EIO : err;
>>>>> +               return err < 0 ? err : -EIO;
>>>>
>>>> Why did you change the semantics here?
>>>
>>> It's a bug fix: if i2c_master_send returns 0, then si4713_send_command() would
>>> return 0 as well instead of -EIO. Highly unlikely to ever happen, but it is a
>>> bug.
>>
>> I am not sure I follow your bug fix. The current code recognizes a
>> successful case only when it succeed to transfer all requested bytes
>> (err == argn + 1 or err == respn). I know there are better ways to
>> retransmit the remaining bytes in case the master fails to transfer
>> all at once, but I don't think it is worth the complication for this
>> driver. Anyways, the driver assumes when returned value is different
>> than expected bytes, but positive, as an error and return -EIO in that
>> case. In case the err response is negative, it just propagates the
>> error code.
>>
>> The assumption is also that for the case no bytes are transfered,
>> presumably when return code is zero, then this code expect that the
>> i2c layer return an error code. Zero bytes transfered is same as a
>> transfer error to me. I am not sure the i2c layer is returning 0. Have
>> you experienced this case in other scenarios (even other drivers)? If
>> yes, I don't think the semantic bug is in this driver, but in the i2c
>> layer. Unless you can explain a case where someone requests to
>> transfer N > 0 bytes, the function return 0 and that is not a transfer
>> error issue.
>
> Frankly, I have no idea if i2c_master_send can ever return 0 (actually, I
> think Dinesh encountered this during development), but if it does then the
> code is clearly wrong so it needs to be fixed. Under no circumstances
> should send_command return 0 when there really was an error of some kind.
>
> I don't see why you have a problem with this. It just improves driver
> robustness. Propagate negative values, and -EIO for all others.
>
>>
>>
>>>
>>>>
>>>>>         }
>>>>>
>>>>> +       until_jiffies = jiffies + usecs_to_jiffies(usecs) + 1;
>>>>> +
>>>>>         /* Wait response from interrupt */
>>>>> -       if (!wait_for_completion_timeout(&sdev->work,
>>>>> +       if (client->irq) {
>>>>> +               if (!wait_for_completion_timeout(&sdev->work,
>>>>>                                 usecs_to_jiffies(usecs) + 1))
>>>>> -               v4l2_warn(&sdev->sd,
>>>>> +                       v4l2_warn(&sdev->sd,
>>>>>                                 "(%s) Device took too much time to answer.\n",
>>>>>                                 __func__);
>>>>> -
>>>>> -       /* Then get the response */
>>>>> -       err = i2c_master_recv(client, response, respn);
>>>>> -       if (err != respn) {
>>>>> -               v4l2_err(&sdev->sd,
>>>>> -                       "Error while reading response for command 0x%02x\n",
>>>>> -                       command);
>>>>> -               return (err > 0) ? -EIO : err;
>>>>>         }
>>>>>
>>>>> -       DBG_BUFFER(&sdev->sd, "Response", response, respn);
>>>>> -       if (check_command_failed(response[0]))
>>>>> -               return -EBUSY;
>>>>> +       do {
>>>>> +               err = i2c_master_recv(client, response, respn);
>>>>> +               if (err != respn) {
>>>>> +                       v4l2_err(&sdev->sd,
>>>>> +                                       "Error %d while reading response for command 0x%02x\n",
>>>>> +                                       err, command);
>>>>> +                       return err < 0 ? err : -EIO;
>>>>
>>>> Again?
>>>>
>>>>> +               }
>>>>>
>>>>> -       return 0;
>>>>> +               DBG_BUFFER(&sdev->sd, "Response", response, respn);
>>>>> +               if (!check_command_failed(response[0]))
>>>>> +                       return 0;
>>>>> +
>>>>> +               if (client->irq)
>>>>> +                       return -EBUSY;
>>>>> +               msleep(1);
>>>>> +       } while (jiffies <= until_jiffies);
>>>>> +
>>>>> +       return -EBUSY;
>>>>>  }
>>>>>
>>>>>  /*
>>>>> @@ -344,14 +353,15 @@ static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val)
>>>>>   */
>>>>>  static int si4713_powerup(struct si4713_device *sdev)
>>>>>  {
>>>>> +       struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
>>>>>         int err;
>>>>>         u8 resp[SI4713_PWUP_NRESP];
>>>>>         /*
>>>>>          *      .First byte = Enabled interrupts and boot function
>>>>>          *      .Second byte = Input operation mode
>>>>>          */
>>>>> -       const u8 args[SI4713_PWUP_NARGS] = {
>>>>> -               SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX,
>>>>> +       u8 args[SI4713_PWUP_NARGS] = {
>>>>> +               SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX,
>>>>>                 SI4713_PWUP_OPMOD_ANALOG,
>>>>>         };
>>>>>
>>>>> @@ -369,18 +379,22 @@ static int si4713_powerup(struct si4713_device *sdev)
>>>>>                 gpio_set_value(sdev->gpio_reset, 1);
>>>>>         }
>>>>>
>>>>> +       if (client->irq)
>>>>> +               args[0] |= SI4713_PWUP_CTSIEN;
>>>>> +
>>>>>         err = si4713_send_command(sdev, SI4713_CMD_POWER_UP,
>>>>>                                         args, ARRAY_SIZE(args),
>>>>>                                         resp, ARRAY_SIZE(resp),
>>>>>                                         TIMEOUT_POWER_UP);
>>>>> -
>>>>> +
>>>>
>>>> Please, do not insert tabulation in blank lines.
>>>>
>>>>>         if (!err) {
>>>>>                 v4l2_dbg(1, debug, &sdev->sd, "Powerup response: 0x%02x\n",
>>>>>                                 resp[0]);
>>>>>                 v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n");
>>>>>                 sdev->power_state = POWER_ON;
>>>>>
>>>>> -               err = si4713_write_property(sdev, SI4713_GPO_IEN,
>>>>> +               if (client->irq)
>>>>> +                       err = si4713_write_property(sdev, SI4713_GPO_IEN,
>>>>>                                                 SI4713_STC_INT | SI4713_CTS);
>>>>>         } else {
>>>>>                 if (gpio_is_valid(sdev->gpio_reset))
>>>>> @@ -447,7 +461,7 @@ static int si4713_checkrev(struct si4713_device *sdev)
>>>>>         if (rval < 0)
>>>>>                 return rval;
>>>>>
>>>>> -       if (resp[1] == SI4713_PRODUCT_NUMBER) {
>>>>> +       if (resp[1] == SI4713_PRODUCT_NUMBER) {
>>>>
>>>> Please, do not insert spaces in the end of the line.
>>>>
>>>>>                 v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n",
>>>>>                                 client->addr << 1, client->adapter->name);
>>>>>         } else {
>>>>> @@ -465,33 +479,34 @@ static int si4713_checkrev(struct si4713_device *sdev)
>>>>>   */
>>>>>  static int si4713_wait_stc(struct si4713_device *sdev, const int usecs)
>>>>>  {
>>>>> -       int err;
>>>>> +       struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
>>>>>         u8 resp[SI4713_GET_STATUS_NRESP];
>>>>> -
>>>>> -       /* Wait response from STC interrupt */
>>>>> -       if (!wait_for_completion_timeout(&sdev->work,
>>>>> -                       usecs_to_jiffies(usecs) + 1))
>>>>> -               v4l2_warn(&sdev->sd,
>>>>> -                       "%s: device took too much time to answer (%d usec).\n",
>>>>> -                               __func__, usecs);
>>>>> -
>>>>> -       /* Clear status bits */
>>>>> -       err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
>>>>> -                                       NULL, 0,
>>>>> -                                       resp, ARRAY_SIZE(resp),
>>>>> -                                       DEFAULT_TIMEOUT);
>>>>> -
>>>>> -       if (err < 0)
>>>>> -               goto exit;
>>>>> -
>>>>> -       v4l2_dbg(1, debug, &sdev->sd,
>>>>> -                       "%s: status bits: 0x%02x\n", __func__, resp[0]);
>>>>> -
>>>>> -       if (!(resp[0] & SI4713_STC_INT))
>>>>> -               err = -EIO;
>>>>> -
>>>>> -exit:
>>>>> -       return err;
>>>>> +       unsigned long start_jiffies = jiffies;
>>>>> +       int err;
>>>>> +
>>>>> +       if (client->irq &&
>>>>> +           !wait_for_completion_timeout(&sdev->work, usecs_to_jiffies(usecs) + 1))
>>>>> +               v4l2_warn(&sdev->sd,
>>>>> +                       "(%s) Device took too much time to answer.\n", __func__);
>>>>> +
>>>>> +       for (;;) {
>>>>> +               /* Clear status bits */
>>>>> +               err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
>>>>> +                               NULL, 0,
>>>>> +                               resp, ARRAY_SIZE(resp),
>>>>> +                               DEFAULT_TIMEOUT);
>>>>> +
>>>>> +               if (err >= 0) {
>>>>
>>>> Why are you polling while the command fails? If the command fails, you
>>>> need to stop, and propagate the error to upper layers. You shall keep
>>>> polling only while the command succeed and (resp[0] & SI4713_STC_INT)
>>>> == 0.
>>>
>>> This needs a comment. Dinesh, correct me if I am wrong but as I remember
>>> the usb device actually does return errors when it is waiting for STC.
>>> It seems the usb device just blocks new usb requests during that wait.
>>>
>>>>
>>>>> +                       v4l2_dbg(1, debug, &sdev->sd,
>>>>> +                                       "%s: status bits: 0x%02x\n", __func__, resp[0]);
>>>>> +
>>>>> +                       if (resp[0] & SI4713_STC_INT)
>>>>> +                               return 0;
>>>>> +               }
>>>>> +               if (jiffies_to_usecs(jiffies - start_jiffies) > usecs)
>>>>> +                       return -EIO;
>>>
>>> Although this should be replaced with:
>>>
>>>                         return err < 0 ? err : -EIO;
>>>
>>>>> +               msleep(3);
>>>>> +       }
>>>>
>>>> Can you please add a comment why you chose msleep(3)? For instance,
>>>> here you sleep for 3 ms, in send command you need only 1ms. Any
>>>> explanation?
>>>
>>> Experimentation. If you flood the USB device with USB requests it hangs.
>>
>>
>> Well, that it is experimentation I don't have doubts :-).
>>
>> I was just requesting you guys to add a comment there to explain the
>> magic number.
>>
>>>
>>>>
>>>> Besides could you please move this for to another function? Something
>>>> like si4713_poll_stc?
>>>
>>> Why? I see no compelling reason to split it. Some more comments would be
>>> useful, though.
>>
>> Just for better code readability, function starts to become confusing
>> with IRQ event check, polling loop, and even experimentation values
>> flying around.
>>
>>>
>>> Regards,
>>>
>>>         Hans
>>>
>>>>
>>>>>  }
>>>>>
>>>>>  /*
>>>>> @@ -1024,7 +1039,6 @@ static int si4713_initialize(struct si4713_device *sdev)
>>>>>         if (rval < 0)
>>>>>                 return rval;
>>>>>
>>>>> -
>>>>>         sdev->frequency = DEFAULT_FREQUENCY;
>>>>>         sdev->stereo = 1;
>>>>>         sdev->tune_rnl = DEFAULT_TUNE_RNL;
>>>>> diff --git a/drivers/media/radio/si4713/si4713.h b/drivers/media/radio/si4713/si4713.h
>>>>> index c274e1f..dc0ce66 100644
>>>>> --- a/drivers/media/radio/si4713/si4713.h
>>>>> +++ b/drivers/media/radio/si4713/si4713.h
>>>>> @@ -15,6 +15,7 @@
>>>>>  #ifndef SI4713_I2C_H
>>>>>  #define SI4713_I2C_H
>>>>>
>>>>> +#include <linux/regulator/consumer.h>
>>>>>  #include <media/v4l2-subdev.h>
>>>>>  #include <media/v4l2-ctrls.h>
>>>>>  #include <media/si4713.h>
>>>>> --
>>>>> 1.8.4.rc2
>>>>>
>>>>> --
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>>
>
> Dinesh, do you have time to work on this? I might have time next week, but that's uncertain.
> Otherwise it will be three weeks from now before I can work on it. I know your internship
> has ended, so I understand if you want me to finish this.
>
> Regards,
>
>         Hans



-- 
Eduardo Bezerra Valentin
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux