ARM: SAMSUNG: adc: make waitq part of client structure
Moved local waitq instance from s3c_adc_read function to s3c_adc_client
structure which is global. This makes the ADC operation more robust and
ensure there is no memory corruption.
Occasional cases (during stress test) found src_adc_read function
woke up and exited before completing last action (spinlock restore) in the
__wake_up function which is part of ADC IRQ handler. This caused memory
corruption and found subsequent function crashed due to this.
BUG=chromeos-partner:14648
TEST=Ran ADC stress test for several hours
cd /sys/devices/platform/ncp15wb473.0/
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
while true; do cat temp1_input > /dev/null; done&
Change-Id: I52730669b2537cae32b8f4ef94750d8723c4cd6a
Signed-off-by: Sunil Mazhavanchery <sunilm@samsung.com>
Reviewed-on: https://gerrit.chromium.org/gerrit/34504
Commit-Ready: Doug Anderson <dianders@chromium.org>
Reviewed-by: Doug Anderson <dianders@chromium.org>
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index a049213..15cc07d 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -52,7 +52,7 @@
struct s3c_adc_client {
struct platform_device *pdev;
struct list_head pend;
- wait_queue_head_t *wait;
+ wait_queue_head_t wait;
unsigned int nr_samples;
int result;
@@ -254,7 +254,7 @@
unsigned v, unsigned u, unsigned *left)
{
client->result = v;
- wake_up(client->wait);
+ wake_up(&client->wait);
}
/* Get the result out of the client with locking.
@@ -277,7 +277,6 @@
int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
{
unsigned long flags;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
int ret;
/* Lock around access of client members. Technically all that's really
@@ -287,7 +286,6 @@
*/
spin_lock_irqsave(&adc_dev->lock, flags);
client->convert_cb = s3c_convert_done;
- client->wait = &wake;
client->result = -1;
spin_unlock_irqrestore(&adc_dev->lock, flags);
@@ -295,7 +293,7 @@
if (ret < 0)
goto exit;
- wait_event_timeout(wake, s3c_get_result(client) >= 0, HZ / 2);
+ wait_event_timeout(client->wait, s3c_get_result(client) >= 0, HZ / 2);
ret = s3c_get_result(client);
if (ret < 0) {
@@ -308,7 +306,6 @@
* a pointer to the client anymore.
*/
client->convert_cb = NULL;
- client->wait = NULL;
return ret;
}
@@ -347,6 +344,7 @@
client->is_ts = is_ts;
client->select_cb = select;
client->convert_cb = conv;
+ init_waitqueue_head(&client->wait);
return client;
}