lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <000001dc5d2a$0697bf10$13c73d30$@samsung.com>
Date: Mon, 24 Nov 2025 19:06:33 +0900
From: 손신 <shin.son@...sung.com>
To: "'Daniel Lezcano'" <daniel.lezcano@...aro.org>, "'Bartlomiej
 Zolnierkiewicz'" <bzolnier@...il.com>, "'Krzysztof Kozlowski'"
	<krzk@...nel.org>, "'Rafael J . Wysocki'" <rafael@...nel.org>, "'Zhang Rui'"
	<rui.zhang@...el.com>, "'Lukasz Luba'" <lukasz.luba@....com>, "'Rob
	Herring'" <robh@...nel.org>, "'Conor Dooley'" <conor+dt@...nel.org>, "'Alim
	Akhtar'" <alim.akhtar@...sung.com>
Cc: "'Henrik Grimler'" <henrik@...mler.se>, <linux-pm@...r.kernel.org>,
	<linux-samsung-soc@...r.kernel.org>, <devicetree@...r.kernel.org>,
	<linux-arm-kernel@...ts.infradead.org>, <linux-kernel@...r.kernel.org>,
	<shin.son@...sung.com>
Subject: RE: [PATCH v7 RESEND 2/3] thermal: exynos_tmu: Support new hardware
 and update TMU interface

Hello, Daniel Lezcano

> On 11/13/25 07:40, Shin Son wrote:
> > +	if (data->soc == SOC_ARCH_EXYNOSAUTOV920 && code_diff < 0)
> > +		temp = temp * 65 / (57 + data->slope_comp);
> 
> No litterals, comments, etc ...

I'll move those fomulas into the variant data via the .data field in the of_device_id match table.

> > +static void update_con_reg(struct exynos_tmu_data *data) {
> > +	u32 val, t_buf_vref_sel, t_buf_slope_sel;
> > +
> > +	val = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
> > +	t_buf_vref_sel = (val >> EXYNOSAUTOV920_TMU_T_BUF_VREF_SEL_SHIFT)
> > +				& EXYNOSAUTOV920_TMU_T_BUF_VREF_SEL_MASK;
> > +	t_buf_slope_sel = (val >> EXYNOSAUTOV920_TMU_T_BUF_SLOPE_SEL_SHIFT)
> > +				& EXYNOSAUTOV920_TMU_T_BUF_SLOPE_SEL_MASK;
> > +
> > +	val = readl(data->base +  EXYNOSAUTOV920_TMU_REG_CONTROL);
> > +	val &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK <<
> EXYNOS_TMU_REF_VOLTAGE_SHIFT);
> > +	val |= (t_buf_vref_sel << EXYNOS_TMU_REF_VOLTAGE_SHIFT);
> > +	val &= ~(EXYNOS_TMU_BUF_SLOPE_SEL_MASK <<
> EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
> > +	val |= (t_buf_slope_sel << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
> > +	writel(val, data->base + EXYNOSAUTOV920_TMU_REG_CONTROL);
> > +
> > +	val = readl(data->base + EXYNOSAUTOV920_TMU_REG_CONTROL1);
> > +	val &= ~(EXYNOSAUTOV920_TMU_NUM_PROBE_MASK <<
> EXYNOSAUTOV920_TMU_NUM_PROBE_SHIFT);
> > +	val &= ~(EXYNOSAUTOV920_TMU_LPI_MODE_MASK <<
> EXYNOSAUTOV920_TMU_LPI_MODE_SHIFT);
> > +	val |= (data->sensor_count << EXYNOSAUTOV920_TMU_NUM_PROBE_SHIFT);
> > +	writel(val, data->base + EXYNOSAUTOV920_TMU_REG_CONTROL1);
> > +
> > +	writel(1, data->base + EXYNOSAUTOV920_TMU_SAMPLING_INTERVAL);
> > +	writel(EXYNOSAUTOV920_TMU_AVG_CON_UPDATE, data->base +
> EXYNOSAUTOV920_TMU_REG_AVG_CONTROL);
> > +	writel(EXYNOSAUTOV920_TMU_COUNTER_VALUE0_UPDATE,
> > +	       data->base + EXYNOSAUTOV920_TMU_REG_COUNTER_VALUE0);
> > +	writel(EXYNOSAUTOV920_TMU_COUNTER_VALUE1_UPDATE,
> > +	       data->base + EXYNOSAUTOV920_TMU_REG_COUNTER_VALUE1);
> > +}
> > +
> 
> This is unreadable; please make it understandable for those who don’t have
> the documentation (explicit static inline functions, comments, etc ...).

I'll restructure this code by introducing explicit static inline helper functions and proper comments to improve readability.

> > +static void exynosautov920_tmu_disable_high(struct exynos_tmu_data
> > +*data) {
> > +	/* Again, this is handled by polling. */ }
> 
> The driver would deserve some cleanups. Instead of having empty callbacks,
> check in exynos_set_trips() if the ops is !NULL. Then remove all no-op ops.

Ok, I'll update exynos_set_trips() to check for NULL ops and remove the no-op callbacks accordingly.

> > +static void exynosautov920_tmu_set_crit_temp(struct exynos_tmu_data
> > +*data, u8 temp) {
> > +	unsigned int idx;
> > +
> > +	for (idx = 0; idx < data->sensor_count; idx++) {
> > +		if (!data->tzd_array[idx])
> > +			continue;
> > +
> > +		exynos_tmu_update_temp(data,
> EXYNOSAUTOV920_TMU_REG_THRESHOLD(idx), 16, temp);
> > +		exynos_tmu_update_bit(data,
> EXYNOSAUTOV920_TMU_REG_INTEN(idx), 7, true);
> > +	}
> > +}
> 
> There is something wrong in the driver design.
> 
> exynosautov920_tmu_set_crit_temp() is called from
> exynos_thermal_zone_configure() and the routine above sets the temperature
> on all the thermal zone while this one is retrieved from one thermal zone.
> 
> Which results in:
> 
> 	for all tz do;
> 		for all tz do;
> 			if !tz then continue;
> 			set_crit_temp(tz)
> 
> No, this driver needs to be revisited and cleanup before sending changes
> for multiple sensors support.
> 
> What percentage of code sharing is there with the existing driver ?

Overall, I would say that roughly 60% of the logic can be shared.
The temperature reading and emulation paths are similar, but the initialization sequence differs significantly.

Given this level of divergence, would introducing a separate driver 
(instead of extending the current one with many special-case paths) be acceptable?

> > +static void exynosautov920_tmu_initialize(struct platform_device
> > +*pdev) {
> > +	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > +	unsigned int val;
> > +
> > +	data->tmu_control(pdev, false);
> > +
> > +	update_con_reg(data);
> > +
> > +	val = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
> > +	data->cal_type = TYPE_TWO_POINT_TRIMMING;
> > +	data->slope_comp = (val >> EXYNOSAUTOV920_SLOPE_COMP) &
> > +EXYNOSAUTOV920_SLOPE_COMP_MASK;
> > +
> > +	val = readl(data->base + EXYNOSAUTOV920_SENSOR0_TRIM_INFO);
> > +	data->temp_error1 = (val >> EXYNOSAUTOV920_TRIMINFO_25_SHIFT) &
> EXYNOSAUTOV920_TRIM_MASK;
> > +	data->temp_error2 = (val >> EXYNOSAUTOV920_TRIMINFO_85_SHIFT) &
> > +EXYNOSAUTOV920_TRIM_MASK;
> > +
> > +	val = readl(data->base + EXYNOSAUTOV920_TMU_REG_TRIMINFO2);
> > +	val = (val >> EXYNOSAUTOV920_CALIB_SEL_TEMP) &
> > +EXYNOSAUTOV920_CALIB_SEL_TEMP_MASK;
> > +
> > +	data->calib_temp = (EXYNOS_SECOND_POINT_TRIM + (20 * val)); }
> > +
> 
> This is unreadable; please make it understandable for those who don’t have
> the documentation (explicit static inline functions, comments, etc ...).

Ok, I'll refactor this code using explicit static inline helpers and comments.

> > +static void exynosautov920_tmu_control(struct platform_device *pdev,
> > +bool on) {
> > +	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > +	unsigned int con;
> > +
> > +	con = readl(data->base + EXYNOSAUTOV920_TMU_REG_CONTROL);
> > +
> > +	if (on) {
> > +		con |= BIT(EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > +		con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
> > +	} else {
> > +		con &= ~BIT(EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > +		con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT);
> > +	}
> > +
> > +	writel(con, data->base + EXYNOSAUTOV920_TMU_REG_CONTROL); }
> 
> Document a bit the code please.

Sure, I’ll document this part properly by adding clear comments and splitting the register options into explicit helper functions.

> >   static irqreturn_t exynos_tmu_threaded_irq(int irq, void *id)
> >   {
> >   	struct exynos_tmu_data *data = id;
> > +	int idx;
> >
> > -	thermal_zone_device_update(data->tzd, THERMAL_EVENT_UNSPECIFIED);
> > +	for (idx = 0; idx < data->sensor_count; idx++) {
> > +		if (!data->tzd_array[idx])
> > +			continue;
> > +
> > +		thermal_zone_device_update(data->tzd_array[idx],
> > +THERMAL_EVENT_UNSPECIFIED);
> I understand the main reason is to keep a common isr but you should
> *not* update all the thermal zones. There is an amount of processing
> behind this function adding a significant overhead.
> 
> So somehow readl(data->base + EXYNOSAUTOV920_TMU_REG_INT_PEND(idx));
> should be used here to know if the thermal zone has to be updated or not.

OK, I'll update the ISR so that it checks the pending register before calling 'thermal_zone_device_update()',
And only update the relevant thermal zones. 

> >   static const struct of_device_id exynos_tmu_match[] = {
> >   	{
> >   		.compatible = "samsung,exynos3250-tmu", @@ -833,6 +1044,9 @@
> > static const struct of_device_id exynos_tmu_match[] = {
> >   	}, {
> >   		.compatible = "samsung,exynos7-tmu",
> >   		.data = (const void *)SOC_ARCH_EXYNOS7,
> > +	}, {
> > +		.compatible = "samsung,exynosautov920-tmu",
> > +		.data = (const void *)SOC_ARCH_EXYNOSAUTOV920,
> 
> Time to do cleanups in the driver. Use at your advantage the .data to
> store the relevant info instead of a awful else-if in the different
> functions above.

OK, I'll refactor this by using the .data field.
However, since ExynosAutov920 diverges significantly from the existing driver,
Would introducing a separate driver instead of unifying everything be acceptable?

> >   	},
> >   	{ },
> >   };
> > @@ -865,6 +1079,10 @@ static int exynos_map_dt_data(struct
> > platform_device *pdev)
> >
> >   	data->soc = (uintptr_t)of_device_get_match_data(&pdev->dev);
> >
> > +	data->sensor_count = EXYNOS_DEFAULT_SENSOR_COUNT;
> > +
> > +	data->calib_temp = EXYNOS_SECOND_POINT_TRIM;
> > +
> >   	switch (data->soc) {
> >   	case SOC_ARCH_EXYNOS4210:
> >   		data->tmu_set_low_temp = exynos4210_tmu_set_low_temp; @@ -
> 945,6
> > +1163,19 @@ static int exynos_map_dt_data(struct platform_device *pdev)
> >   		data->min_efuse_value = 15;
> >   		data->max_efuse_value = 100;
> >   		break;
> > +	case SOC_ARCH_EXYNOSAUTOV920:
> > +		data->tmu_set_low_temp = exynosautov920_tmu_set_low_temp;
> > +		data->tmu_set_high_temp = exynosautov920_tmu_set_high_temp;
> > +		data->tmu_disable_low = exynosautov920_tmu_disable_low;
> > +		data->tmu_disable_high = exynosautov920_tmu_disable_high;
> > +		data->tmu_set_crit_temp = exynosautov920_tmu_set_crit_temp;
> > +		data->tmu_initialize = exynosautov920_tmu_initialize;
> > +		data->tmu_control = exynosautov920_tmu_control;
> > +		data->tmu_read = exynosautov920_tmu_read;
> > +		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
> > +		data->tmu_clear_irqs = exynosautov920_tmu_clear_irqs;
> > +		data->sensor_count = EXYNOS_MAX_SENSOR_COUNT;
> > +		break;
> 
> Same comment as above.

Ok, I'll refactor this by using the .data field to move the SoC-specific callbacks into a proper
variant structure.

> --

Thank you for your detailed feedback. I appreciate it.




Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ