[Skiboot] [PATCH] i2c: Fix i2c request hang during opal init if timers are not checked

Stewart Smith stewart at linux.ibm.com
Tue Dec 11 14:41:54 AEDT 2018


Frederic Barrat <fbarrat at linux.ibm.com> writes:
> If an i2c request cannot go through the first time, because the bus is
> found in error and need a reset or it's locked by the OCC for example,
> the underlying i2c implementation is using timers to manage the
> request. However during opal init, opal pollers may not be called, it
> depends in the context in which the i2c request is made. If the
> pollers are not called, the timers are not checked and we can end up
> with an i2c request which will not move foward and skiboot hangs.
>
> Fix it by explicitly checking the timers if we are waiting for an i2c
> request to complete and it seems to be taking a while.

Okay, I see what happens here: we're doing the i2c request in the main
thread and doing time_wait() with a value that'll never run pollers and
thus never check_timers() either.

Looking at the code here, is there any reason we shouldn't just call
check_timers(false) straight after the time_wait() ?

>
> Signed-off-by: Frederic Barrat <fbarrat at linux.ibm.com>
> ---
>  core/i2c.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/core/i2c.c b/core/i2c.c
> index 26926fc2..3c600024 100644
> --- a/core/i2c.c
> +++ b/core/i2c.c
> @@ -21,6 +21,7 @@
>  #include <opal-msg.h>
>  #include <timebase.h>
>  #include <processor.h>
> +#include <timer.h>
>  
>  static LIST_HEAD(i2c_bus_list);
>  
> @@ -177,6 +178,7 @@ int i2c_request_send(int bus_id, int dev_addr, int read_write,
>  	struct i2c_bus *bus;
>  	uint64_t time_to_wait = 0;
>  	struct i2c_sync_userdata ud;
> +	uint64_t timer_period = msecs_to_tb(5), timer_count;
>  
>  	bus = i2c_find_bus_by_id(bus_id);
>  	if (!bus) {
> @@ -215,6 +217,7 @@ int i2c_request_send(int bus_id, int dev_addr, int read_write,
>  
>  	for (retries = 0; retries <= MAX_NACK_RETRIES; retries++) {
>  		waited = 0;
> +		timer_count = 0;
>  
>  		i2c_queue_req(req);
>  
> @@ -224,6 +227,19 @@ int i2c_request_send(int bus_id, int dev_addr, int read_write,
>  				time_to_wait = REQ_COMPLETE_POLLING;
>  			time_wait(time_to_wait);
>  			waited += time_to_wait;
> +			timer_count += time_to_wait;
> +			if (timer_count > timer_period) {
> +				/*
> +				 * The above request may be relying on
> +				 * timers to complete, yet there may
> +				 * not be called, especially during
> +				 * opal init. We could be looping here
> +				 * forever. So explicitly check the
> +				 * timers once in a while
> +				 */
> +				check_timers(false);
> +				timer_count = 0;
> +			}
>  		} while (!ud.done);
>  
>  		lwsync();
> -- 
> 2.19.1
>
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
>

-- 
Stewart Smith
OPAL Architect, IBM.



More information about the Skiboot mailing list