CHROMIUM: ARM: exynos: Avoid race if multiple thermistor readers at once
authorDoug Anderson <dianders@chromium.org>
Wed, 19 Sep 2012 21:47:08 +0000 (14:47 -0700)
committerGerrit <chrome-bot@google.com>
Thu, 20 Sep 2012 18:12:20 +0000 (11:12 -0700)
The adc code expects one client per process.

BUG=chrome-os-partner:14115
TEST=run the below cmd from 8 shells for 60 mins and saw no crash
  cd /sys/devices/platform/ncp15wb473.0/
  while true; do cat temp1_input; done

Change-Id: Ie34986648cbb7f43597391314719df5976937de0
Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/33645
Tested-by: Abhinav Kochhar <abhinav@chromium.org>
Reviewed-by: Vikas Sajjan <vikas.sajjan@samsung.com>
Reviewed-by: Abhinav Kochhar <abhinav@chromium.org>
Reviewed-by: Grant Grundler <grundler@chromium.org>
arch/arm/mach-exynos/mach-exynos5-dt.c

index 27d61e9..5221fd7 100644 (file)
@@ -693,6 +693,12 @@ static void exynos_wifi_bt_set_power(u32 slot_id, u32 volt)
 
 /* NTC Thermistor. Attached to S3C-ADC in some Samsung SoC Devices */
 struct s3c_adc_client *ntc_adc_clients[4];
+struct mutex ntc_adc_locks[] = {
+       __MUTEX_INITIALIZER(ntc_adc_locks[0]),
+       __MUTEX_INITIALIZER(ntc_adc_locks[1]),
+       __MUTEX_INITIALIZER(ntc_adc_locks[2]),
+       __MUTEX_INITIALIZER(ntc_adc_locks[3]),
+};
 
 static int __init s3c_adc_ntc_init(struct platform_device *pdev)
 {
@@ -718,8 +724,20 @@ static int read_thermistor_uV(struct platform_device *pdev)
        unsigned int port = ntc_adc_ports[pdev->id];
        struct s3c_adc_client *client = ntc_adc_clients[pdev->id];
        struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
+       struct mutex *lock = ntc_adc_locks + pdev->id;
+
+       /* Arrays are sized; make sure we haven't blown over */
+       BUG_ON(pdev->id >= ARRAY_SIZE(ntc_adc_locks));
 
+       /*
+        * s3c_adc_read() assumes two processes aren't using the same client
+        * at the same time (yes, it's a bad design), so grab a per-client
+        * mutex to ensure this is OK.
+        */
+       mutex_lock(lock);
        converted = pdata->pullup_uV * (s64) s3c_adc_read(client, port);
+       mutex_unlock(lock);
+
        converted >>= 12;
 
        return (int) converted;