From: Ansuel Smith Date: Thu, 19 Dec 2019 03:01:28 +0000 (+0100) Subject: ipq806x: rework ipq806x specific tsense temp driver X-Git-Tag: v21.02.0-rc1~4238 X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=77f4d5c6bb8323ec67248176a5a2907475041a79;p=openwrt%2Fstaging%2Fhauke.git ipq806x: rework ipq806x specific tsense temp driver Tsense driver for ipq806x have various problem. - Emit wrong error. On probing of this driver, nvmem driver can be not ready and this cause a EDEFER error. Actually this is not an error as the kernel will retry to probe the driver after the nvmem driver is loaded. - Use uninitialized value on trigger of critical temp - Doesn't free allocated memory Because of this, rework the driver and improve it by removing extra load of data. Change the logic of loading data. Use the backup calib data only when the calib data is not present. As the calibration is only needed to set the temp offset, we don't really need to read both calib data and set the offset based only on the backup one. Also change how the notifier function work. At times when we output the trigger message, we already have read the temp so remove the extra read and the wrong uninitialized data that probably caused a kernel panic for null pointer exception. (Think we never experience this bug because the router never reached that temp ever... So just lucky) Tested-by: Stefan Lippers-Hollmann [nbg6817/ipq8065] Signed-off-by: Ansuel Smith --- diff --git a/target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch b/target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch new file mode 100644 index 0000000000..7092552559 --- /dev/null +++ b/target/linux/ipq806x/patches-4.19/0063-4-ip806x-tsense-rework-driver.patch @@ -0,0 +1,107 @@ +--- a/drivers/thermal/qcom/tsens-ipq8064.c ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -13,10 +13,12 @@ + */ + + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -210,9 +212,8 @@ + struct tsens_device *tmdev = container_of(work, struct tsens_device, + tsens_work); + unsigned int threshold, threshold_low, code, reg, sensor, mask; +- unsigned int sensor_addr; + bool upper_th_x, lower_th_x; +- int adc_code, ret; ++ int ret; + + ret = regmap_read(tmdev->map, STATUS_CNTL_8064, ®); + if (ret) +@@ -261,9 +262,8 @@ + if (upper_th_x || lower_th_x) { + /* Notify user space */ + schedule_work(&tmdev->sensor[0].notify_work); +- regmap_read(tmdev->map, sensor_addr, &adc_code); + pr_debug("Trigger (%d degrees) for sensor %d\n", +- code_to_degC(adc_code, &tmdev->sensor[0]), 0); ++ code_to_degC(code, &tmdev->sensor[0]), 0); + } + } + regmap_write(tmdev->map, STATUS_CNTL_8064, reg & mask); +@@ -372,40 +372,55 @@ + static int calibrate_ipq8064(struct tsens_device *tmdev) + { + int i; +- char *data, *data_backup; +- ++ int ret = 0; ++ u8 *data, *data_backup; ++ struct device *dev = tmdev->dev; + ssize_t num_read = tmdev->num_sensors; + struct tsens_sensor *s = tmdev->sensor; + +- data = qfprom_read(tmdev->dev, "calib"); ++ data = qfprom_read(dev, "calib"); + if (IS_ERR(data)) { +- pr_err("Calibration not found.\n"); +- return PTR_ERR(data); ++ ret = PTR_ERR(data); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Calibration not found."); ++ goto exit; + } + +- data_backup = qfprom_read(tmdev->dev, "calib_backup"); ++ data_backup = qfprom_read(dev, "calib_backup"); + if (IS_ERR(data_backup)) { +- pr_err("Backup calibration not found.\n"); +- return PTR_ERR(data_backup); ++ ret = PTR_ERR(data_backup); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Backup Calibration not found."); ++ goto free_data; + } + + for (i = 0; i < num_read; i++) { + s[i].calib_data = readb_relaxed(data + i); +- s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data) { ++ s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data_backup) { ++ dev_err(dev, "QFPROM TSENS calibration data not present"); ++ ret = -ENODEV; ++ goto free_backup; ++ } + +- if (s[i].calib_data_backup) + s[i].calib_data = s[i].calib_data_backup; +- if (!s[i].calib_data) { +- pr_err("QFPROM TSENS calibration data not present\n"); +- return -ENODEV; + } ++ + s[i].slope = tsens_8064_slope[i]; + s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); + } + + hw_init(tmdev); + +- return 0; ++free_backup: ++ kfree(data_backup); ++free_data: ++ kfree(data); ++exit: ++ return ret; + } + + static int get_temp_ipq8064(struct tsens_device *tmdev, int id, int *temp)