[i2c] [PATCH] i2c: improve lost-arbitration handling in i2c-algo-pcf

Jean Delvare khali at linux-fr.org
Fri Aug 10 17:37:21 CEST 2007


Hi Eric,

When sending a patch, please set the attachment type to something more
friendly than "application/octet-stream".

On Thu, 19 Jul 2007 22:26:08 -0700, Eric Brower wrote:
> Attached is a patch that improves multi-master support for PCF8584.
> The current implementation of multi-master support (mine) in
> i2c-algo-pcf does not properly handle a collision detected during wait_for_bb()
> and thus causes an error that is only recoverable by reloading the
> relevant device drivers.  I'd appreciate your consideration of this
> patch.
> 
> The only affected driver is i2c-envctrl.c-- currently out-of-kernel,
> in development; you
> can find it here if you are interested:
> 
>    http://www.david-web.co.uk/index.php?p=envctrl
> 
> This change has been tested by a few individuals (on Sun Microsystems
> E250 servers) over the course of several months, and rectifies
> occasional errors seen without the patch applied.
> 
> I'll be happy to provide further clarification if you are interested.
> Please cc me on responses-- I am not a member of this list.

Note that I can't test your patch, as I don't have supported hardware.

> Commit text:
> 
> Improve lost-arbitration handling of PCF8584
> Signed-off-by: Eric Brower <ebrower at gmail.com>

Review:

> diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
> index ecb2c2d..2cc0302 100644
> --- a/drivers/i2c/algos/i2c-algo-pcf.c
> +++ b/drivers/i2c/algos/i2c-algo-pcf.c
> @@ -78,6 +78,31 @@ static void i2c_stop(struct i2c_algo_pcf
>  	set_pcf(adap, 1, I2C_PCF_STOP);
>  }
>  
> +static inline void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
> +{
> +	DEB2(printk(KERN_INFO 
> +		"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
> +		 *status));
> +	/* Cleanup from LAB-- reset and enable ESO.
> +	 * This resets the PCF8584; since we've lost the bus, no
> +	 * further attempts should be made by callers to clean up 
> +	 * (no i2c_stop() etc.)
> +	 */
> +	set_pcf(adap, 1, I2C_PCF_PIN);
> +	set_pcf(adap, 1, I2C_PCF_ESO);
> +	/* We pause for a time period sufficient for any running 
> +	 * I2C transaction to complete-- the arbitration logic won't 
> +	 * work properly until the next START is seen.
> +	 * It is assumed the bus driver or client has set a proper value.
> +	 */
> +	if (adap->lab_mdelay) {
> +		mdelay(adap->lab_mdelay);
> +	}

Out of curiosity: on what basis will the value of lab_mdelay be chosen
by the driver author? This seems to be pretty arbitrary, as you don't
know what kind of transactions the other master is doing. The
underlying question being: is it worth having a per-adapter parameter
for this, as opposed to a hard-coded value?

Also, it seems to me that you could sleep here. If you sleep a bit
longer than expected, it shouldn't be a problem, right?

> +	DEB2(printk(KERN_INFO 
> +		"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", 
> +		get_pcf(adap,1)));

Coding style: space after comma.

> +}

This function is too big to be inlined, especially given that it should
rarely be called, so speeding it up isn't very interesting.

> +
>  static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
>  
>  	int timeout = DEF_TIMEOUT;
> @@ -86,6 +111,10 @@ static int wait_for_bb(struct i2c_algo_p
>  	status = get_pcf(adap, 1);
>  #ifndef STUB_I2C
>  	while (timeout-- && !(status & I2C_PCF_BB)) {
> +		if (status & I2C_PCF_LAB) {
> +			handle_lab(adap, &status);
> +			return -EINTR;
> +		}

How can this happen? We check for busy bus before we start
transmitting, and arbitration can't be lost until we at least try to
transmit.

>  		udelay(100); /* wait for 100 us */
>  		status = get_pcf(adap, 1);
>  	}

> @@ -109,23 +139,7 @@ static int wait_for_pin(struct i2c_algo_
>  		*status = get_pcf(adap, 1);
>  	}
>  	if (*status & I2C_PCF_LAB) {
> -		DEB2(printk(KERN_INFO 
> -			"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
> -			 *status));
> -		/* Cleanup from LAB-- reset and enable ESO.
> -		 * This resets the PCF8584; since we've lost the bus, no
> -		 * further attempts should be made by callers to clean up 
> -		 * (no i2c_stop() etc.)
> -		 */
> -		set_pcf(adap, 1, I2C_PCF_PIN);
> -		set_pcf(adap, 1, I2C_PCF_ESO);
> -		/* TODO: we should pause for a time period sufficient for any
> -		 * running I2C transaction to complete-- the arbitration
> -		 * logic won't work properly until the next START is seen.
> -		 */
> -		DEB2(printk(KERN_INFO 
> -			"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", 
> -			get_pcf(adap,1)));
> +		handle_lab(adap, status);
>  		return(-EINTR);
>  	}
>  #endif
> @@ -218,9 +232,8 @@ static inline int try_address(struct i2c
>  				break;	/* success! */
>  			}
>  		}
> -		if (wfp == -EINTR) {
> +		else if (wfp == -EINTR) {
>  			/* arbitration lost */
> -			udelay(adap->udelay);
>  			return -EINTR;
>  		}
>  		i2c_stop(adap);
> @@ -378,6 +393,10 @@ static int pcf_xfer(struct i2c_adapter *
>  	/* Check for bus busy */
>  	timeout = wait_for_bb(adap);
>  	if (timeout) {
> +		if (timeout == -EINTR) {
> +			/* arbitration lost */
> +			return -EINTR;
> +		}
>  		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
>  		            "Timeout waiting for BB in pcf_xfer\n");)
>  		return -EIO;
> diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
> index 994eb86..d11c141 100644
> --- a/include/linux/i2c-algo-pcf.h
> +++ b/include/linux/i2c-algo-pcf.h
> @@ -36,6 +36,12 @@ struct i2c_algo_pcf_data {
>  	/* local settings */
>  	int udelay;
>  	int timeout;
> +
> +	/* Multi-master lost arbitration back-off delay (msecs)
> +	 * This should be set by the bus adapter or knowledgable client 
> +	 * if bus is multi-mastered, else zero
> +	 */
> +	unsigned long lab_mdelay;
>  };
>  
>  int i2c_pcf_add_bus(struct i2c_adapter *);

As a side question, shouldn't i2c-algo-pcf retry, rather than fail, on
arbitration lost?

-- 
Jean Delvare



More information about the i2c mailing list