summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-09-18 10:27:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-09-18 10:27:23 -0700
commitd24e3bf4c5484b29432837269ded253480fa8928 (patch)
treec386f263907bdd0c0a024290e8fc5689cbb4f26b
parent928ba50514ac0a7b20ac83e6681583c2584c528d (diff)
parent92b68492eae701e5b0e9d142ffe229921af7b1fa (diff)
downloadlwn-d24e3bf4c5484b29432837269ded253480fa8928.tar.gz
lwn-d24e3bf4c5484b29432837269ded253480fa8928.zip
Merge tag 'hwmon-for-v7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon fixes from Guenter Roeck: - Add missing sensors, and fix current sensors ID lookup (cgbc-hwmon) - Return IRQ_HANDLED from the shared alarm IRQ handler to fix possible interrupt storm (gpioufan) - Improve raw WMI string handling, and fix UaF in show function (hp-wmi-sensors) - Fix k10temp model id range of Zen5 Turin to stop reporting temperature data for non-existing CCDs - pmbus: - Increase number of phases to fix UaF problems - Fix TPS53676 phase page decoding, and select page 0 for single-page applications - Stop pwm-fan RPM timer before freeing tach data to fix UaF - Release w83793 probe data through kref to fix UaF - Remove w83791d fan/pwm 4-5 sysfs group on remove to fix UaF * tag 'hwmon-for-v7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: hwmon: (hp-wmi-sensors) Improve raw WMI string handling hwmon: (pmbus/tps53679) Select page 0 for single-page TPS53676 hwmon: (pmbus/tps53679) Fix TPS53676 phase page decoding hwmon: (hp-wmi-sensors) Fix use-after-free in fungible_show() hwmon: (w83793) release probe data through kref hwmon: (w83791d) remove fan/pwm 4-5 sysfs group on remove hwmon: (gpio-fan) return IRQ_HANDLED from the shared alarm IRQ handler hwmon: (pmbus/core) increase number of phases and add new mask hwmon: (cgbc-hwmon) Add missing sensors hwmon: (cgbc-hwmon) Fix current sensors ID lookup hwmon: (pwm-fan) Stop RPM timer before freeing tach data hwmon: (k10temp) Fix model id range of Zen5 Turin
-rw-r--r--Documentation/hwmon/cgbc-hwmon.rst42
-rw-r--r--drivers/hwmon/cgbc-hwmon.c129
-rw-r--r--drivers/hwmon/gpio-fan.c4
-rw-r--r--drivers/hwmon/hp-wmi-sensors.c32
-rw-r--r--drivers/hwmon/k10temp.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus.h3
-rw-r--r--drivers/hwmon/pmbus/tps53679.c11
-rw-r--r--drivers/hwmon/pwm-fan.c13
-rw-r--r--drivers/hwmon/w83791d.c1
-rw-r--r--drivers/hwmon/w83793.c4
10 files changed, 161 insertions, 80 deletions
diff --git a/Documentation/hwmon/cgbc-hwmon.rst b/Documentation/hwmon/cgbc-hwmon.rst
index 3a5e6e6e8639..c6d09232392a 100644
--- a/Documentation/hwmon/cgbc-hwmon.rst
+++ b/Documentation/hwmon/cgbc-hwmon.rst
@@ -28,34 +28,44 @@ system.
Name Description
============= ======================
temp1_input CPU temperature
-temp2_input Box temperature
+temp2_input Case temperature
temp3_input Ambient temperature
-temp4_input Board temperature
-temp5_input Carrier temperature
-temp6_input Chipset temperature
-temp7_input Video temperature
+temp4_input CPU Board temperature
+temp5_input Carrier Board temperature
+temp6_input System Chipset temperature
+temp7_input Video Controller/Board temperature
temp8_input Other temperature
-temp9_input TOPDIM temperature
-temp10_input BOTTOMDIM temperature
-in0_input CPU voltage
+temp9_input Top DIMM 0 temperature
+temp10_input Bottom DIMM 0 temperature
+temp11_input Alternate Board temperature
+temp12_input Top DIMM 1 temperature
+temp13_input Top DIMM 2 temperature
+temp14_input Top DIMM 3 temperature
+temp15_input Top DIMM 4 temperature
+temp16_input Top DIMM 5 temperature
+temp17_input Top DIMM 6 temperature
+temp18_input Top DIMM 7 temperature
+temp19_input Bottom DIMM 1 temperature
+in0_input CPU Core voltage
in1_input DC Runtime voltage
in2_input DC Standby voltage
in3_input CMOS Battery voltage
-in4_input Battery voltage
+in4_input Battery Supply voltage
in5_input AC voltage
in6_input Other voltage
-in7_input 5V voltage
+in7_input 5V Runtime voltage
in8_input 5V Standby voltage
-in9_input 3V3 voltage
+in9_input 3V3 Runtime voltage
in10_input 3V3 Standby voltage
in11_input VCore A voltage
in12_input VCore B voltage
-in13_input 12V voltage
-curr1_input DC current
-curr2_input 5V current
-curr3_input 12V current
+in13_input 12V Runtime voltage
+in14_input 12V Standby voltage
+curr1_input DC Runtime current
+curr2_input 5V Runtime current
+curr3_input 12V Runtime current
fan1_input CPU fan
-fan2_input Box fan
+fan2_input Case fan
fan3_input Ambient fan
fan4_input Chiptset fan
fan5_input Video fan
diff --git a/drivers/hwmon/cgbc-hwmon.c b/drivers/hwmon/cgbc-hwmon.c
index 3aff4e092132..230062a46907 100644
--- a/drivers/hwmon/cgbc-hwmon.c
+++ b/drivers/hwmon/cgbc-hwmon.c
@@ -41,45 +41,60 @@ enum cgbc_sensor_types {
static const char * const cgbc_hwmon_labels_temp[] = {
"CPU Temperature",
- "Box Temperature",
+ "Case Temperature",
"Ambient Temperature",
- "Board Temperature",
- "Carrier Temperature",
- "Chipset Temperature",
- "Video Temperature",
+ "CPU Board Temperature",
+ "Carrier Board Temperature",
+ "System Chipset Temperature",
+ "Video Controller/Board Temperature",
"Other Temperature",
- "TOPDIM Temperature",
- "BOTTOMDIM Temperature",
+ "Top DIMM 0 Temperature",
+ "Bottom DIMM 0 Temperature",
+ "Alternate Board Temperature",
+ "Top DIMM 1 Temperature",
+ "Top DIMM 2 Temperature",
+ "Top DIMM 3 Temperature",
+ "Top DIMM 4 Temperature",
+ "Top DIMM 5 Temperature",
+ "Top DIMM 6 Temperature",
+ "Top DIMM 7 Temperature",
+ "Bottom DIMM 1 Temperature",
};
+static const char * const cgbc_hwmon_labels_in[] = {
+ "CPU Core Voltage",
+ "DC Runtime Voltage",
+ "DC Standby Voltage",
+ "CMOS Battery Voltage",
+ "Battery Supply Voltage",
+ "AC Voltage",
+ "Other Voltage",
+ "5V Runtime Voltage",
+ "5V Standby Voltage",
+ "3V3 Runtime Voltage",
+ "3V3 Standby Voltage",
+ "VCore A Voltage",
+ "VCore B Voltage",
+ "12V Runtime Voltage",
+ "12V Standby Voltage",
+};
+
+/*
+ * Current sensors are a bit special, they don't have consecutive IDs like
+ * other types of sensors. So they need to be defined explicitly.
+ */
static const struct {
- enum hwmon_sensor_types type;
const char *label;
-} cgbc_hwmon_labels_in[] = {
- { hwmon_in, "CPU Voltage" },
- { hwmon_in, "DC Runtime Voltage" },
- { hwmon_in, "DC Standby Voltage" },
- { hwmon_in, "CMOS Battery Voltage" },
- { hwmon_in, "Battery Voltage" },
- { hwmon_in, "AC Voltage" },
- { hwmon_in, "Other Voltage" },
- { hwmon_in, "5V Voltage" },
- { hwmon_in, "5V Standby Voltage" },
- { hwmon_in, "3V3 Voltage" },
- { hwmon_in, "3V3 Standby Voltage" },
- { hwmon_in, "VCore A Voltage" },
- { hwmon_in, "VCore B Voltage" },
- { hwmon_in, "12V Voltage" },
- { hwmon_curr, "DC Current" },
- { hwmon_curr, "5V Current" },
- { hwmon_curr, "12V Current" },
+ int id;
+} cgbc_hwmon_labels_curr[] = {
+ { "DC Runtime Current", 0x12 },
+ { "5V Runtime Current", 0x18 },
+ { "12V Runtime Current", 0x1E },
};
-#define CGBC_HWMON_NB_IN_SENSORS 14
-
static const char * const cgbc_hwmon_labels_fan[] = {
"CPU Fan",
- "Box Fan",
+ "Case Fan",
"Ambient Fan",
"Chipset Fan",
"Video Fan",
@@ -114,7 +129,8 @@ static int cgbc_hwmon_probe_sensors(struct device *dev, struct cgbc_hwmon_data *
for (i = 0; i < nb_sensors; i++) {
enum cgbc_sensor_types type;
- unsigned int channel;
+ unsigned int channel, id;
+ int j;
/*
* No need to request data for the first sensor.
@@ -128,32 +144,49 @@ static int cgbc_hwmon_probe_sensors(struct device *dev, struct cgbc_hwmon_data *
}
type = FIELD_GET(CGBC_HWMON_TYPE_MASK, data[1]);
- channel = FIELD_GET(CGBC_HWMON_ID_MASK, data[1]) - 1;
+ id = FIELD_GET(CGBC_HWMON_ID_MASK, data[1]);
+ channel = id - 1;
if (type == CGBC_HWMON_TYPE_TEMP && channel < ARRAY_SIZE(cgbc_hwmon_labels_temp)) {
sensor->type = hwmon_temp;
sensor->label = cgbc_hwmon_labels_temp[channel];
- } else if (type == CGBC_HWMON_TYPE_IN &&
- channel < ARRAY_SIZE(cgbc_hwmon_labels_in)) {
+ } else if (type == CGBC_HWMON_TYPE_IN) {
/*
* The Board Controller doesn't differentiate current and voltage sensors.
- * Get the sensor type from cgbc_hwmon_labels_in[channel].type instead.
+ * First check if it is a current sensor.
*/
- sensor->type = cgbc_hwmon_labels_in[channel].type;
- sensor->label = cgbc_hwmon_labels_in[channel].label;
+ for (j = 0; j < ARRAY_SIZE(cgbc_hwmon_labels_curr); j++) {
+ if (id == cgbc_hwmon_labels_curr[j].id) {
+ sensor->type = hwmon_curr;
+ sensor->label = cgbc_hwmon_labels_curr[j].label;
+ channel = j;
+ }
+ }
+
+ /* If it's not a current sensor, it may be a voltage sensor. */
+ if (!sensor->label && channel < ARRAY_SIZE(cgbc_hwmon_labels_in)) {
+ sensor->type = hwmon_in;
+ sensor->label = cgbc_hwmon_labels_in[channel];
+ }
} else if (type == CGBC_HWMON_TYPE_FAN &&
channel < ARRAY_SIZE(cgbc_hwmon_labels_fan)) {
sensor->type = hwmon_fan;
sensor->label = cgbc_hwmon_labels_fan[channel];
- } else {
- dev_warn(dev, "Board Controller returned an unknown sensor (type=%d, channel=%d), ignore it",
- type, channel);
+ }
+
+ if (!sensor->label) {
+ dev_warn(dev, "Board Controller returned an unknown sensor (bc_type=%d, bc_id=%d), ignore it",
+ type, id);
continue;
}
sensor->active = FIELD_GET(CGBC_HWMON_ACTIVE_BIT, data[1]);
sensor->channel = channel;
sensor->index = i;
+
+ dev_dbg(dev, "Found sensor: bc_type=%d, bc_id=%d, hwmon_type=%d, hwmon_channel=%d, hwmon_label='%s', active=%d\n",
+ type, id, sensor->type, sensor->channel, sensor->label, sensor->active);
+
sensor++;
hwmon->nb_sensors++;
}
@@ -167,14 +200,6 @@ static struct cgbc_hwmon_sensor *cgbc_hwmon_find_sensor(struct cgbc_hwmon_data *
struct cgbc_hwmon_sensor *sensor = NULL;
int i;
- /*
- * The Board Controller doesn't differentiate current and voltage sensors.
- * The channel value (from the Board Controller point of view) shall be computed for current
- * sensors.
- */
- if (type == hwmon_curr)
- channel += CGBC_HWMON_NB_IN_SENSORS;
-
for (i = 0; i < hwmon->nb_sensors; i++) {
if (hwmon->sensors[i].type == type && hwmon->sensors[i].channel == channel) {
sensor = &hwmon->sensors[i];
@@ -240,7 +265,12 @@ static const struct hwmon_channel_info * const cgbc_hwmon_info[] = {
HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
- HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL),
+ HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL,
@@ -248,7 +278,8 @@ static const struct hwmon_channel_info * const cgbc_hwmon_info[] = {
HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL),
+ HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL),
HWMON_CHANNEL_INFO(curr,
HWMON_C_INPUT | HWMON_C_LABEL, HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL),
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index df8bd9707605..3f78375eeb44 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -68,7 +68,7 @@ static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
schedule_work(&fan_data->alarm_work);
- return IRQ_NONE;
+ return IRQ_HANDLED;
}
static ssize_t fan1_alarm_show(struct device *dev,
@@ -103,7 +103,7 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data)
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
- IRQF_SHARED, "GPIO fan alarm", fan_data);
+ 0, "GPIO fan alarm", fan_data);
}
/*
diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c
index 03c684ba83bd..cfa0d6ad0fb3 100644
--- a/drivers/hwmon/hp-wmi-sensors.c
+++ b/drivers/hwmon/hp-wmi-sensors.c
@@ -526,14 +526,12 @@ static int check_wobj(const union acpi_object *wobj,
for (prop = 0; prop <= last_prop; prop++) {
type = elements[prop].type;
valid_type = property_map[prop];
- if (type != valid_type) {
- if (type == ACPI_TYPE_BUFFER &&
- valid_type == ACPI_TYPE_STRING &&
- is_raw_wmi_string(elements[prop].buffer.pointer,
- elements[prop].buffer.length))
- continue;
+ if (type == ACPI_TYPE_BUFFER &&
+ is_raw_wmi_string(elements[prop].buffer.pointer,
+ elements[prop].buffer.length))
+ type = ACPI_TYPE_STRING;
+ if (type != valid_type)
return -EINVAL;
- }
}
return 0;
@@ -579,6 +577,7 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj,
int prop = HP_WMI_PROPERTY_NAME;
acpi_object_type valid_type;
union acpi_object *elements;
+ union acpi_object *element;
u32 elem_count;
int last_prop;
bool is_new;
@@ -602,13 +601,20 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj,
elem_count > HP_WMI_MAX_PROPERTIES)
return -EINVAL;
- type = elements[HP_WMI_PROPERTY_SIZE].type;
+ element = &elements[HP_WMI_PROPERTY_SIZE];
+ type = element->type;
switch (type) {
case ACPI_TYPE_INTEGER:
is_new = true;
last_prop = HP_WMI_PROPERTY_RATE_UNITS;
break;
+ case ACPI_TYPE_BUFFER:
+ if (!is_raw_wmi_string(element->buffer.pointer,
+ element->buffer.length))
+ return -EINVAL;
+ fallthrough;
+
case ACPI_TYPE_STRING:
is_new = false;
last_prop = HP_WMI_PROPERTY_CURRENT_READING;
@@ -631,6 +637,10 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj,
for (i = 0; i < elem_count && prop <= last_prop; i++, prop++) {
type = elements[i].type;
valid_type = hp_wmi_property_map[prop];
+ if (type == ACPI_TYPE_BUFFER &&
+ is_raw_wmi_string(elements[i].buffer.pointer,
+ elements[i].buffer.length))
+ type = ACPI_TYPE_STRING;
if (type != valid_type)
return -EINVAL;
@@ -651,6 +661,10 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj,
/* PossibleStates[0] has already been type-checked. */
for (j = 0; i + 1 < elem_count && j + 1 < count; j++) {
type = elements[++i].type;
+ if (type == ACPI_TYPE_BUFFER &&
+ is_raw_wmi_string(elements[i].buffer.pointer,
+ elements[i].buffer.length))
+ type = ACPI_TYPE_STRING;
if (type != valid_type)
return -EINVAL;
}
@@ -1247,7 +1261,9 @@ static int fungible_show(struct seq_file *seqf, enum hp_wmi_property prop)
break;
case HP_WMI_PROPERTY_CURRENT_STATE:
+ mutex_lock(&state->lock);
seq_printf(seqf, "%s\n", nsensor->current_state);
+ mutex_unlock(&state->lock);
break;
case HP_WMI_PROPERTY_UNIT_MODIFIER:
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 75a45010d687..3e7e63edc6a3 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -523,7 +523,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
} else if (boot_cpu_data.x86 == 0x1a) {
switch (boot_cpu_data.x86_model) {
- case 0x00 ... 0x2f: /* Zen5 Turin */
+ case 0x00 ... 0x1f: /* Zen5 Turin */
data->ccd_offset = 0x1F0;
k10temp_get_ccd_support(data, 16);
break;
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 2cd3216b3cd9..920c1102ab6d 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -242,6 +242,7 @@ enum pmbus_regs {
/*
* OPERATION
*/
+#define PB_OPERATION_CONTROL_V_SRC GENMASK(5, 4)
#define PB_OPERATION_CONTROL_ON BIT(7)
/*
@@ -386,7 +387,7 @@ enum pmbus_sensor_classes {
};
#define PMBUS_PAGES 32 /* Per PMBus specification */
-#define PMBUS_PHASES 10 /* Maximum number of phases per page */
+#define PMBUS_PHASES 16 /* Maximum number of phases per page */
/* Functionality bit mask */
#define PMBUS_HAVE_VIN BIT(0)
diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c
index 31e54608b3c9..6c25701b36fc 100644
--- a/drivers/hwmon/pmbus/tps53679.c
+++ b/drivers/hwmon/pmbus/tps53679.c
@@ -187,7 +187,7 @@ static int tps53676_identify(struct i2c_client *client,
return -EIO;
for (i = 0; i < 2 * TPS53676_MAX_PHASES; i += 2) {
if (buf[i + 1] & 0x80) {
- if (buf[i] & 0x08)
+ if (buf[i] & BIT(4))
phases_b++;
else
phases_a++;
@@ -200,6 +200,15 @@ static int tps53676_identify(struct i2c_client *client,
if (phases_b > 0) {
info->pages = 2;
info->phases[1] = phases_b;
+ } else {
+ /*
+ * pmbus_set_page() does not update the PAGE register on
+ * single-page devices, so select page 0 explicitly in case
+ * the boot firmware left the device on another page.
+ */
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+ if (ret < 0)
+ return ret;
}
return 0;
}
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 3b87f65bae05..c633d7f6464c 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -483,7 +483,6 @@ static void pwm_fan_cleanup(void *__ctx)
{
struct pwm_fan_ctx *ctx = __ctx;
- timer_delete_sync(&ctx->rpm_timer);
if (ctx->pwm_shutdown) {
ctx->enable_mode = pwm_enable_reg_enable;
__set_pwm(ctx, ctx->pwm_shutdown);
@@ -494,6 +493,13 @@ static void pwm_fan_cleanup(void *__ctx)
}
}
+static void pwm_fan_timer_cleanup(void *__ctx)
+{
+ struct pwm_fan_ctx *ctx = __ctx;
+
+ timer_shutdown_sync(&ctx->rpm_timer);
+}
+
static int pwm_fan_probe(struct platform_device *pdev)
{
struct thermal_cooling_device *cdev;
@@ -644,6 +650,10 @@ static int pwm_fan_probe(struct platform_device *pdev)
}
if (ctx->tach_count > 0) {
+ ret = devm_add_action_or_reset(dev, pwm_fan_timer_cleanup, ctx);
+ if (ret)
+ return ret;
+
ctx->sample_start = ktime_get();
mod_timer(&ctx->rpm_timer, jiffies + HZ);
@@ -700,6 +710,7 @@ static void pwm_fan_shutdown(struct platform_device *pdev)
{
struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
+ pwm_fan_timer_cleanup(ctx);
pwm_fan_cleanup(ctx);
}
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 4a777430af5c..4b07a25ae59e 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -1415,6 +1415,7 @@ static void w83791d_remove(struct i2c_client *client)
struct w83791d_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
}
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index a548586369e1..c6ef04c69856 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -1928,7 +1928,9 @@ exit_remove:
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
device_remove_file(dev, &w83793_temp[i].dev_attr);
free_mem:
- kfree(data);
+ mutex_lock(&watchdog_data_mutex);
+ kref_put(&data->kref, w83793_release_resources);
+ mutex_unlock(&watchdog_data_mutex);
exit:
return err;
}