public inbox for linux-i2c@vger.kernel.org
 help / color / mirror / Atom feed
From: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
To: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	ivanov.aleks-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	David Brownell
	<dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
Subject: Re: [PATCH] at24: use timeout also for read
Date: Sun, 22 Nov 2009 21:08:46 +0100	[thread overview]
Message-ID: <20091122210846.14666e23@hyperion.delvare> (raw)
In-Reply-To: <1257711297-19927-1-git-send-email-w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

Hi Wolfram,

Sorry for the late review.

On Sun,  8 Nov 2009 21:14:57 +0100, Wolfram Sang wrote:
> Writes may take some time on EEPROMs, so for consecutive writes, we already
> have a loop waiting for the EEPROM to become ready. Use such a loop for reads,
> too, in case somebody wants to immediately read after a write. Detailed bug
> report and test case can be found here:
> 
> http://article.gmane.org/gmane.linux.drivers.i2c/4660
> 
> Reported-by: Aleksandar Ivanov <ivanov.aleks-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Cc: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> Cc: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
> ---
> 
> I could reproduce the errornous behaviour and this patch fixes it for me.

Looks overall good, with just one comment:

> 
>  drivers/misc/eeprom/at24.c |   78 ++++++++++++++++++++++++++-----------------
>  1 files changed, 47 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> index db39f4a..78aa46c 100644
> --- a/drivers/misc/eeprom/at24.c
> +++ b/drivers/misc/eeprom/at24.c
> @@ -158,6 +158,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
>  	struct i2c_msg msg[2];
>  	u8 msgbuf[2];
>  	struct i2c_client *client;
> +	unsigned long timeout, read_time;
>  	int status, i;
>  
>  	memset(msg, 0, sizeof(msg));
> @@ -183,47 +184,62 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
>  	if (count > io_limit)
>  		count = io_limit;
>  
> -	/* Smaller eeproms can work given some SMBus extension calls */
>  	if (at24->use_smbus) {
> +		/* Smaller eeproms can work given some SMBus extension calls */
>  		if (count > I2C_SMBUS_BLOCK_MAX)
>  			count = I2C_SMBUS_BLOCK_MAX;
> -		status = i2c_smbus_read_i2c_block_data(client, offset,
> -				count, buf);
> -		dev_dbg(&client->dev, "smbus read %zu@%d --> %d\n",
> -				count, offset, status);
> -		return (status < 0) ? -EIO : status;
> +	} else {
> +		/*
> +		 * When we have a better choice than SMBus calls, use a
> +		 * combined I2C message. Write address; then read up to
> +		 * io_limit data bytes. Note that read page rollover helps us
> +		 * here (unlike writes). msgbuf is u8 and will cast to our
> +		 * needs.
> +		 */
> +		i = 0;
> +		if (at24->chip.flags & AT24_FLAG_ADDR16)
> +			msgbuf[i++] = offset >> 8;
> +		msgbuf[i++] = offset;
> +
> +		msg[0].addr = client->addr;
> +		msg[0].buf = msgbuf;
> +		msg[0].len = i;
> +
> +		msg[1].addr = client->addr;
> +		msg[1].flags = I2C_M_RD;
> +		msg[1].buf = buf;
> +		msg[1].len = count;
>  	}
>  
>  	/*
> -	 * When we have a better choice than SMBus calls, use a combined
> -	 * I2C message. Write address; then read up to io_limit data bytes.
> -	 * Note that read page rollover helps us here (unlike writes).
> -	 * msgbuf is u8 and will cast to our needs.
> +	 * Reads fail if the previous write didn't complete yet. We may
> +	 * loop a few times until this one succeeds, waiting at least
> +	 * long enough for one entire page write to work.
>  	 */
> -	i = 0;
> -	if (at24->chip.flags & AT24_FLAG_ADDR16)
> -		msgbuf[i++] = offset >> 8;
> -	msgbuf[i++] = offset;
> -
> -	msg[0].addr = client->addr;
> -	msg[0].buf = msgbuf;
> -	msg[0].len = i;
> +	timeout = jiffies + msecs_to_jiffies(write_timeout);
> +	do {
> +		read_time = jiffies;
> +		if (at24->use_smbus) {
> +			status = i2c_smbus_read_i2c_block_data(client, offset,
> +					count, buf);
> +			if (status == 0)
> +				status = count;

I don't think this is needed. i2c_smbus_read_i2c_block_data() returns
the number of bytes read, or a negative error code. I don't think it
can ever return 0 (and if it did, it would not mean success.) Thus
returning status without additional processing should be fine.

> +		} else {
> +			status = i2c_transfer(client->adapter, msg, 2);
> +			if (status == 2)
> +				status = count;
> +		}
> +		dev_dbg(&client->dev, "read %zu@%d --> %zd (%ld)\n",
> +				count, offset, status, jiffies);
>  
> -	msg[1].addr = client->addr;
> -	msg[1].flags = I2C_M_RD;
> -	msg[1].buf = buf;
> -	msg[1].len = count;
> +		if (status == count)
> +			return count;
>  
> -	status = i2c_transfer(client->adapter, msg, 2);
> -	dev_dbg(&client->dev, "i2c read %zu@%d --> %d\n",
> -			count, offset, status);
> +		/* REVISIT: at HZ=100, this is sloooow */
> +		msleep(1);
> +	} while (time_before(read_time, timeout));
>  
> -	if (status == 2)
> -		return count;
> -	else if (status >= 0)
> -		return -EIO;
> -	else
> -		return status;
> +	return -ETIMEDOUT;
>  }
>  
>  static ssize_t at24_read(struct at24_data *at24,

Other than that this looks good. If the above change is OK with you
then I can push this fix to Linus quickly.

-- 
Jean Delvare

  parent reply	other threads:[~2009-11-22 20:08 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <533f29860911050810w4d939b39x2ad11c189f13c977@mail.gmail.com>
     [not found] ` <533f29860911050810w4d939b39x2ad11c189f13c977-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-11-05 17:25   ` at24 driver - a possible problem Wolfram Sang
     [not found]     ` <20091105172537.GA3332-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-06 12:15       ` Jean Delvare
     [not found]         ` <20091106131524.76ae52b9-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-11-06 12:49           ` Wolfram Sang
     [not found]             ` <20091106124905.GA3980-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-06 12:57               ` Aleksandar Ivanov
     [not found]                 ` <533f29860911060457m70a1adfcr2dd11f0785748014-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-11-06 20:58                   ` David Brownell
     [not found]                     ` <200911061258.52179.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2009-11-08 20:23                       ` Wolfram Sang
     [not found]                         ` <20091108202331.GA6374-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-08 21:30                           ` David Brownell
2009-11-09  8:46                           ` Jean Delvare
     [not found]                             ` <20091109094638.2f05b29f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-11-09  9:10                               ` Wolfram Sang
     [not found]                                 ` <20091109091045.GA3983-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-09 12:24                                   ` Aleksandar Ivanov
2009-11-08 20:14           ` [PATCH] at24: use timeout also for read Wolfram Sang
     [not found]             ` <1257711297-19927-1-git-send-email-w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-16 18:50               ` Wolfram Sang
     [not found]                 ` <20091116185030.GB21491-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-16 18:56                   ` Jean Delvare
2009-11-22 20:08               ` Jean Delvare [this message]
     [not found]                 ` <20091122210846.14666e23-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-11-25  8:09                   ` Jean Delvare
     [not found]                     ` <20091125090907.3e4e9155-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-11-25  9:20                       ` Wolfram Sang
2009-11-25  9:37                   ` [PATCH V2] " Wolfram Sang
     [not found]                     ` <1259141876-15458-1-git-send-email-w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-11-25 10:24                       ` Jean Delvare

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20091122210846.14666e23@hyperion.delvare \
    --to=khali-puyad+kwke1g9huczpvpmw@public.gmane.org \
    --cc=dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    --cc=ivanov.aleks-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox