Eric Brower napsal(a):
> Attached is a revised patch to provide enhanced multi-master
> arbitration support for i2c-algo-pcf.  The initial patch was
> commented-on about 10 months ago, so I've included the prior mail
> below for reference and interspersed my comments.  I am not a member
> of this list, so please copy me directly on replies.  The attached
> patch has been tested against a fairly recent Linus 2.6 GIT tree.
> 
> Ref: http://lists.lm-sensors.org/pipermail/i2c/2007-August/001690.html
> 
> Commit text:
> Improve lost-arbitration handling of PCF8584.  This is necessary for
> support of a currently out-of-kernel driver for Sun Microsystems E250
> environmental management; perhaps others.
> Signed-off-by: Eric Brower <ebrower at gmail.com>
> 
> Daniel, please ACK if you are comfortable doing so.
> 
> 
>> Hi Eric,
>>
>> When sending a patch, please set the attachment type to something more
>> friendly than "application/octet-stream".
> 
> Will do.  I've tried to fool gmail with a .txt extension, rather than .patch.
> 
>> 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?
> 
> The driver (bus adapter) author shall select a value that is longer
> than the longest start/stop bus transaction possible by either master.
>  This is not entirely arbitrary, and can be determined by snooping the
> i2c bus.  Unfortunately, for proper lost-arbitration functionality
> with PCF8584 you must determine a sufficient value.  This is described
> in the Philips/NXP AN96040 document:
> 
> "Attention ! In both cases, the PCF8584 is not able to recognise that
> there is still an ongoing
> transmission. In order to prevent another arbitration problem the
> controlling software should
> wait for a time, longer than the longest message which can be sent
> over the bus, before trying
> to access the bus again."
> 
> The parameter should be per-adapter, not hard-coded, for the above reason.
> 
> Here's an example of a bus driver (i2c-envctrl) setting a desired value:
> 
> static struct i2c_algo_pcf_data pcf_envctrl_data = {
>         .setpcf     = pcf_envctrl_setbyte,
>         .getpcf     = pcf_envctrl_getbyte,
>         .getown     = pcf_envctrl_getown,
>         .getclock   = pcf_envctrl_getclock,
>         .waitforpin = pcf_envctrl_waitforpin,
>         .udelay     = 10,
>         .timeout    = 100,
>         /*
>          * This could be made dynamic based upon get_clock(), but
>          * we know clock does not change within this implementation, so:
>          * 10,000 uSec per bit (@100kHz) * 9 bits/byte * 3 trans
>          */
>         .lab_mdelay = 270,
>  };
> 
> 
>> 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?
> 
> Not a problem.  The pause is only intended to ensure at least
> "lab_mdelay" msecs prior to the next attempt to use the bus.  This
> gives the internal state machine of PCF8584 sufficient time to see a
> stop or start sequence on the bus.
> 
>>> +   DEB2(printk(KERN_INFO
>>> +           "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
>>> +           get_pcf(adap,1)));
>> Coding style: space after comma.
> 
> Done.  Thanks.
> 
>>> +}
>> This function is too big to be inlined, especially given that it should
>> rarely be called, so speeding it up isn't very interesting.
> 
> Understood-- inline removed.
> 
>>> +
>>>  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.
> 
> This is a side-effect that occurs when the lab_mdelay value is not
> long enough to ensure a stop or start sequence is seen by the master.
> The internal state machine of the PCF8584 can trigger LAB at an
> unexpected time.  In fact, you are correct that we should not see it
> here; given the current structure of the driver, however, we do see it
> here and the driver otherwise makes no attempt to resolve the issue.
> This state requires a driver reload to rectify.  Future work on this
> driver could perhaps resolve the issue of this (and other unexpected
> conditions) via a reset.
> 
> However, if we assume the bus driver author has selected a proper
> value, we should not expect this to occur.  So, I've removed this
> section and it could be added back in the future as "insurance"
> against unexpected behavior if necessary.
> 
>>>             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?
> 
> It is not a safe assumption that a command (or series of commands) can
> be re-tried after arbitration is lost.  A convenience function or
> setting in the driver may be worthwhile for cases where the consumer
> knows the action to be safe, but I would divorce such an enhancement
> from this proposed patch.
> 
>> --
>> Jean Delvare
> 
> Thank you again for your consideration.  Apologies for the tardiness of a 
> reply.
> 
> 
> ------------------------------------------------------------------------
> 
> diff --git a/drivers/i2c/algos/i2c-algo-pcf.c 
> b/drivers/i2c/algos/i2c-algo-pcf.c
> index ecb2c2d..5b8e686 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 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);
> +     }
> +     DEB2(printk(KERN_INFO 
> +             "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", 
> +             get_pcf(adap, 1)));
> +}
> +
>  static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
>  
>       int timeout = DEF_TIMEOUT;
> @@ -109,23 +134,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
> 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 *);

Sorry for long delay I was on holiday. I today compile 2.6.26 and start 
testing. I patch vanilla with take2 without 
problem. But I found  may be bug in 2.6.26 because is not possible select algos 
in i2c and i2c-algo-pcf is not compiled.
This is needed by i2-envctrl.

                        Dan







-- 
Mydatex s r.o.
http://www.mydatex.cz
email: [EMAIL PROTECTED]
mob: 604200362
tel: 226210085

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

Reply via email to