aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Barrat <fbarrat@linux.ibm.com>2018-11-29 19:17:17 +0100
committerVasant Hegde <hegdevasant@linux.vnet.ibm.com>2018-12-14 11:16:37 +0530
commite5e99d277fc54ed757148a9f93e8c75b223dc7b8 (patch)
treec36f9a9e159d1f0384e943e089411ecdb7adbc90
parentad92cf94b5f7a2a6c653c0473918b1d51f9f3875 (diff)
downloadskiboot-e5e99d277fc54ed757148a9f93e8c75b223dc7b8.zip
skiboot-e5e99d277fc54ed757148a9f93e8c75b223dc7b8.tar.gz
skiboot-e5e99d277fc54ed757148a9f93e8c75b223dc7b8.tar.bz2
i2c: Fix i2c request hang during opal init if timers are not checked
[Upstream commit 1bd34e4c60c69faeb825ba5f64658941a1422403] 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. Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Tested-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com> Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
-rw-r--r--core/i2c.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/core/i2c.c b/core/i2c.c
index e833310..0c27f24 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) {
@@ -214,6 +216,8 @@ int i2c_request_send(int bus_id, int dev_addr, int read_write,
for (retries = 0; retries <= MAX_NACK_RETRIES; retries++) {
waited = 0;
i2c_set_req_timeout(req, timeout);
+ timer_count = 0;
+
i2c_queue_req(req);
do {
@@ -222,6 +226,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();