diff options
author | Doug Anderson <dianders@chromium.org> | 2014-04-30 13:44:06 -0400 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2014-06-03 03:11:47 -0400 |
commit | c9a81d67ce4c9cd9b73f8ec6dba827882555d47e (patch) | |
tree | 743426964b110e65372e848ce4cad51e4183c5b1 /drivers/mfd | |
parent | 362196e5d0832ce3c4e1df376c02cff812a2391b (diff) |
mfd: cros_ec: spi: Make the cros_ec_spi timeout more reliable
The cros_ec_spi transfer had two problems with its timeout code:
1. It looked at the timeout even in the case that it found valid data.
2. If the cros_ec_spi code got switched out for a while, it's possible
it could get a timeout after a single loop. Let's be paranoid and
make sure we do one last transfer after the timeout expires.
Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Andrew Bresticker <abrestic@chromium.org>
Tested-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/cros_ec_spi.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index a2a605de79a7..4f863c346547 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c | |||
@@ -113,7 +113,9 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | |||
113 | 113 | ||
114 | /* Receive data until we see the header byte */ | 114 | /* Receive data until we see the header byte */ |
115 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); | 115 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); |
116 | do { | 116 | while (true) { |
117 | unsigned long start_jiffies = jiffies; | ||
118 | |||
117 | memset(&trans, 0, sizeof(trans)); | 119 | memset(&trans, 0, sizeof(trans)); |
118 | trans.cs_change = 1; | 120 | trans.cs_change = 1; |
119 | trans.rx_buf = ptr = ec_dev->din; | 121 | trans.rx_buf = ptr = ec_dev->din; |
@@ -134,12 +136,19 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | |||
134 | break; | 136 | break; |
135 | } | 137 | } |
136 | } | 138 | } |
139 | if (ptr != end) | ||
140 | break; | ||
137 | 141 | ||
138 | if (time_after(jiffies, deadline)) { | 142 | /* |
143 | * Use the time at the start of the loop as a timeout. This | ||
144 | * gives us one last shot at getting the transfer and is useful | ||
145 | * in case we got context switched out for a while. | ||
146 | */ | ||
147 | if (time_after(start_jiffies, deadline)) { | ||
139 | dev_warn(ec_dev->dev, "EC failed to respond in time\n"); | 148 | dev_warn(ec_dev->dev, "EC failed to respond in time\n"); |
140 | return -ETIMEDOUT; | 149 | return -ETIMEDOUT; |
141 | } | 150 | } |
142 | } while (ptr == end); | 151 | } |
143 | 152 | ||
144 | /* | 153 | /* |
145 | * ptr now points to the header byte. Copy any valid data to the | 154 | * ptr now points to the header byte. Copy any valid data to the |