Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: (bt1-pvt) Cache current update timeout

Instead of converting the update timeout data to the milliseconds each
time on the read procedure let's preserve the currently set timeout in the
dedicated driver private data cache. The cached value will be then used in
the timeout read method and in the alarm-less data conversion to prevent
the caller task hanging up in case if the PVT sensor is suddenly powered
down.

Fixes: 87976ce2825d ("hwmon: Add Baikal-T1 PVT sensor driver")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Link: https://lore.kernel.org/r/20200920110924.19741-3-Sergey.Semin@baikalelectronics.ru
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Serge Semin and committed by
Guenter Roeck
0015503e a6db1561

+49 -39
+46 -39
drivers/hwmon/bt1-pvt.c
··· 655 655 656 656 static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val) 657 657 { 658 - unsigned long rate; 659 - ktime_t kt; 660 - u32 data; 658 + int ret; 661 659 662 - rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); 663 - if (!rate) 664 - return -ENODEV; 665 - 666 - /* 667 - * Don't bother with mutex here, since we just read data from MMIO. 668 - * We also have to scale the ticks timeout up to compensate the 669 - * ms-ns-data translations. 670 - */ 671 - data = readl(pvt->regs + PVT_TTIMEOUT) + 1; 672 - 673 - /* 674 - * Calculate ref-clock based delay (Ttotal) between two consecutive 675 - * data samples of the same sensor. So we first must calculate the 676 - * delay introduced by the internal ref-clock timer (Tref * Fclk). 677 - * Then add the constant timeout cuased by each conversion latency 678 - * (Tmin). The basic formulae for each conversion is following: 679 - * Ttotal = Tref * Fclk + Tmin 680 - * Note if alarms are enabled the sensors are polled one after 681 - * another, so in order to have the delay being applicable for each 682 - * sensor the requested value must be equally redistirbuted. 683 - */ 684 - #if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) 685 - kt = ktime_set(PVT_SENSORS_NUM * (u64)data, 0); 686 - kt = ktime_divns(kt, rate); 687 - kt = ktime_add_ns(kt, PVT_SENSORS_NUM * PVT_TOUT_MIN); 688 - #else 689 - kt = ktime_set(data, 0); 690 - kt = ktime_divns(kt, rate); 691 - kt = ktime_add_ns(kt, PVT_TOUT_MIN); 692 - #endif 660 + ret = mutex_lock_interruptible(&pvt->iface_mtx); 661 + if (ret) 662 + return ret; 693 663 694 664 /* Return the result in msec as hwmon sysfs interface requires. */ 695 - *val = ktime_to_ms(kt); 665 + *val = ktime_to_ms(pvt->timeout); 666 + 667 + mutex_unlock(&pvt->iface_mtx); 696 668 697 669 return 0; 698 670 } ··· 672 700 static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) 673 701 { 674 702 unsigned long rate; 675 - ktime_t kt; 703 + ktime_t kt, cache; 676 704 u32 data; 677 705 int ret; 678 706 ··· 685 713 * between all available sensors to have the requested delay 686 714 * applicable to each individual sensor. 687 715 */ 688 - kt = ms_to_ktime(val); 716 + cache = kt = ms_to_ktime(val); 689 717 #if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) 690 718 kt = ktime_divns(kt, PVT_SENSORS_NUM); 691 719 #endif ··· 714 742 return ret; 715 743 716 744 pvt_set_tout(pvt, data); 745 + pvt->timeout = cache; 717 746 718 747 mutex_unlock(&pvt->iface_mtx); 719 748 ··· 991 1018 return ret; 992 1019 } 993 1020 994 - static void pvt_init_iface(struct pvt_hwmon *pvt) 1021 + static int pvt_init_iface(struct pvt_hwmon *pvt) 995 1022 { 1023 + unsigned long rate; 996 1024 u32 trim, temp; 1025 + 1026 + rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); 1027 + if (!rate) { 1028 + dev_err(pvt->dev, "Invalid reference clock rate\n"); 1029 + return -ENODEV; 1030 + } 997 1031 998 1032 /* 999 1033 * Make sure all interrupts and controller are disabled so not to ··· 1016 1036 pvt_set_mode(pvt, pvt_info[pvt->sensor].mode); 1017 1037 pvt_set_tout(pvt, PVT_TOUT_DEF); 1018 1038 1039 + /* 1040 + * Preserve the current ref-clock based delay (Ttotal) between the 1041 + * sensors data samples in the driver data so not to recalculate it 1042 + * each time on the data requests and timeout reads. It consists of the 1043 + * delay introduced by the internal ref-clock timer (N / Fclk) and the 1044 + * constant timeout caused by each conversion latency (Tmin): 1045 + * Ttotal = N / Fclk + Tmin 1046 + * If alarms are enabled the sensors are polled one after another and 1047 + * in order to get the next measurement of a particular sensor the 1048 + * caller will have to wait for at most until all the others are 1049 + * polled. In that case the formulae will look a bit different: 1050 + * Ttotal = 5 * (N / Fclk + Tmin) 1051 + */ 1052 + #if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) 1053 + pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0); 1054 + pvt->timeout = ktime_divns(pvt->timeout, rate); 1055 + pvt->timeout = ktime_add_ns(pvt->timeout, PVT_SENSORS_NUM * PVT_TOUT_MIN); 1056 + #else 1057 + pvt->timeout = ktime_set(PVT_TOUT_DEF, 0); 1058 + pvt->timeout = ktime_divns(pvt->timeout, rate); 1059 + pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN); 1060 + #endif 1061 + 1019 1062 trim = PVT_TRIM_DEF; 1020 1063 if (!of_property_read_u32(pvt->dev->of_node, 1021 1064 "baikal,pvt-temp-offset-millicelsius", &temp)) 1022 1065 trim = pvt_calc_trim(temp); 1023 1066 1024 1067 pvt_set_trim(pvt, trim); 1068 + 1069 + return 0; 1025 1070 } 1026 1071 1027 1072 static int pvt_request_irq(struct pvt_hwmon *pvt) ··· 1154 1149 if (ret) 1155 1150 return ret; 1156 1151 1157 - pvt_init_iface(pvt); 1152 + ret = pvt_init_iface(pvt); 1153 + if (ret) 1154 + return ret; 1158 1155 1159 1156 ret = pvt_request_irq(pvt); 1160 1157 if (ret)
+3
drivers/hwmon/bt1-pvt.h
··· 10 10 #include <linux/completion.h> 11 11 #include <linux/hwmon.h> 12 12 #include <linux/kernel.h> 13 + #include <linux/ktime.h> 13 14 #include <linux/mutex.h> 14 15 #include <linux/seqlock.h> 15 16 ··· 202 201 * if alarms are disabled). 203 202 * @sensor: current PVT sensor the data conversion is being performed for. 204 203 * @cache: data cache descriptor. 204 + * @timeout: conversion timeout cache. 205 205 */ 206 206 struct pvt_hwmon { 207 207 struct device *dev; ··· 216 214 struct mutex iface_mtx; 217 215 enum pvt_sensor_type sensor; 218 216 struct pvt_cache cache[PVT_SENSORS_NUM]; 217 + ktime_t timeout; 219 218 }; 220 219 221 220 /*