Re: [PATCH] adm1026: fix setting fan_div

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Gabriele,

On Mon, 29 Nov 2010 17:49:38 -0800, Gabriele Gorla wrote:
> Prevent setting fan_div from stomping on other fans that share the same i2c register. 
> Also allow div=1 (this is allowed in the ADM1026 datasheet) and prevent the mutex lock 
> when no update is necessary.
> 
> Signed-off-by: Gabriele Gorla <gorlik at penguintown.net>

Thanks for the patch. It's hard to believe the code has been broken for
so long and nobody complained...

Please run your patch through scripts/checkpatch.pl, and fix all the
style errors before you resubmit.

> ---
> 
> 
> diff -r -U 5 linux-source-2.6.26_orig/drivers/hwmon/adm1026.c linux-source-2.6.26/drivers/hwmon/adm1026.c
> --- linux-source-2.6.26_orig/drivers/hwmon/adm1026.c	2008-07-13 14:51:29.000000000 -0700
> +++ linux-source-2.6.26/drivers/hwmon/adm1026.c	2010-11-29 17:21:06.000000000 -0800
> @@ -918,37 +918,42 @@
>  {
>  	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
>  	int nr = sensor_attr->index;
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct adm1026_data *data = i2c_get_clientdata(client);
> -	int val, orig_div, new_div, shift;
> +	int val, orig_div, new_div;
>  
>  	val = simple_strtol(buf, NULL, 10);
> -	new_div = DIV_TO_REG(val);
> -	if (new_div == 0) {
> -		return -EINVAL;
> -	}
> -	mutex_lock(&data->update_lock);
> -	orig_div = data->fan_div[nr];
> -	data->fan_div[nr] = DIV_FROM_REG(new_div);
>  
> -	if (nr < 4) { /* 0 <= nr < 4 */
> -		shift = 2 * nr;
> -		adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
> -			((DIV_TO_REG(orig_div) & (~(0x03 << shift))) |
> -			(new_div << shift)));
> -	} else { /* 3 < nr < 8 */
> -		shift = 2 * (nr - 4);
> -		adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
> -			((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) |
> -			(new_div << shift)));
> +	if(val<1 || val>8) {
> +	        return -EINVAL;

As underlined by Phil already, this is a little inconsistent. You
should reject all invalid values, as documented at the end of
Documentation/hwmon/sysfs-interface. But this should be done in a
separate patch, as this isn't really a bug fix and changes the driver's
behavior on invalid input.

>  	}
>  
> -	if (data->fan_div[nr] != orig_div) {
> +	new_div = DIV_TO_REG(val);
> +	if(data->fan_div[nr]!=DIV_FROM_REG(new_div)) {
> +

Undue blank line.

> +	        mutex_lock(&data->update_lock);
> +		orig_div = data->fan_div[nr];
> +		data->fan_div[nr] = DIV_FROM_REG(new_div);
> +
> +		if (nr < 4) { /* 0 <= nr < 4 */
> +		        adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
> +				    (DIV_TO_REG(data->fan_div[0]) << 0) |
> +				    (DIV_TO_REG(data->fan_div[1]) << 2) |
> +				    (DIV_TO_REG(data->fan_div[2]) << 4) |
> +				    (DIV_TO_REG(data->fan_div[3]) << 6) );
> +		} else { /* 3 < nr < 8 */
> +		        adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
> +				    (DIV_TO_REG(data->fan_div[4]) << 0) |
> +				    (DIV_TO_REG(data->fan_div[5]) << 2) |
> +				    (DIV_TO_REG(data->fan_div[6]) << 4) |
> +				    (DIV_TO_REG(data->fan_div[7]) << 6) );
> +		}

Note: this is horribly inefficient. In my opinion, data->fan_div should
hold split but un-decoded register values. Calling DIV_FROM_REG() is
cheap, calling DIV_TO_REG() is expensive. In fact DIV_TO_REG()
shouldn't exist in the first place, as the conversion should happen in
a single place. Again, this is material for a separate patch.

> +		
>  		fixup_fan_min(dev, nr, orig_div);
> +		mutex_unlock(&data->update_lock);
>  	}
> -	mutex_unlock(&data->update_lock);
>  	return count;
>  }
>  
>  #define fan_offset_div(offset)						\
>  static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux