Skip to content

Commit 63ca5b4

Browse files
yghannamgregkh
authored andcommitted
hwmon: (k10temp) Check return value of amd_smn_read()
[ Upstream commit c2d79cc ] Check the return value of amd_smn_read() before saving a value. This ensures invalid values aren't saved or used. There are three cases here with slightly different behavior: 1) read_tempreg_nb_zen(): This is a function pointer which does not include a return code. In this case, set the register value to 0 on failure. This enforces Read-as-Zero behavior. 2) k10temp_read_temp(): This function does have return codes, so return the error code from the failed register read. Continued operation is not necessary, since there is no valid data from the register. Furthermore, if the register value was set to 0, then the following operation would underflow. 3) k10temp_get_ccd_support(): This function reads the same register from multiple CCD instances in a loop. And a bitmask is formed if a specific bit is set in each register instance. The loop should continue on a failed register read, skipping the bit check. Signed-off-by: Yazen Ghannam <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Mario Limonciello <[email protected]> Acked-by: Guenter Roeck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent 20bf292 commit 63ca5b4

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

drivers/hwmon/k10temp.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
153153

154154
static void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval)
155155
{
156-
amd_smn_read(amd_pci_dev_to_node_id(pdev),
157-
ZEN_REPORTED_TEMP_CTRL_BASE, regval);
156+
if (amd_smn_read(amd_pci_dev_to_node_id(pdev),
157+
ZEN_REPORTED_TEMP_CTRL_BASE, regval))
158+
*regval = 0;
158159
}
159160

160161
static long get_raw_temp(struct k10temp_data *data)
@@ -205,6 +206,7 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
205206
long *val)
206207
{
207208
struct k10temp_data *data = dev_get_drvdata(dev);
209+
int ret = -EOPNOTSUPP;
208210
u32 regval;
209211

210212
switch (attr) {
@@ -221,13 +223,17 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
221223
*val = 0;
222224
break;
223225
case 2 ... 13: /* Tccd{1-12} */
224-
amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
225-
ZEN_CCD_TEMP(data->ccd_offset, channel - 2),
226-
&regval);
226+
ret = amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
227+
ZEN_CCD_TEMP(data->ccd_offset, channel - 2),
228+
&regval);
229+
230+
if (ret)
231+
return ret;
232+
227233
*val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000;
228234
break;
229235
default:
230-
return -EOPNOTSUPP;
236+
return ret;
231237
}
232238
break;
233239
case hwmon_temp_max:
@@ -243,7 +249,7 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
243249
- ((regval >> 24) & 0xf)) * 500 + 52000;
244250
break;
245251
default:
246-
return -EOPNOTSUPP;
252+
return ret;
247253
}
248254
return 0;
249255
}
@@ -381,8 +387,20 @@ static void k10temp_get_ccd_support(struct pci_dev *pdev,
381387
int i;
382388

383389
for (i = 0; i < limit; i++) {
384-
amd_smn_read(amd_pci_dev_to_node_id(pdev),
385-
ZEN_CCD_TEMP(data->ccd_offset, i), &regval);
390+
/*
391+
* Ignore inaccessible CCDs.
392+
*
393+
* Some systems will return a register value of 0, and the TEMP_VALID
394+
* bit check below will naturally fail.
395+
*
396+
* Other systems will return a PCI_ERROR_RESPONSE (0xFFFFFFFF) for
397+
* the register value. And this will incorrectly pass the TEMP_VALID
398+
* bit check.
399+
*/
400+
if (amd_smn_read(amd_pci_dev_to_node_id(pdev),
401+
ZEN_CCD_TEMP(data->ccd_offset, i), &regval))
402+
continue;
403+
386404
if (regval & ZEN_CCD_TEMP_VALID)
387405
data->show_temp |= BIT(TCCD_BIT(i));
388406
}

0 commit comments

Comments
 (0)