Commit 00250ec90963b7ef6678438888f3244985ecde14

Authored by Andre Przywara
Committed by Guenter Roeck
1 parent e816b57a33

hwmon: fam15h_power: fix bogus values with current BIOSes

Newer BKDG[1] versions recommend a different initialization value for
the running average range register in the northbridge. This improves
the power reading by avoiding counter saturations resulting in bogus
values for anything below about 80% of TDP power consumption.
Updated BIOSes will have this new value set up from the beginning,
but meanwhile we correct this value ourselves.
This needs to be done on all northbridges, even on those where the
driver itself does not register at.

This fixes the driver on all current machines to provide proper
values for idle load.

[1]
http://support.amd.com/us/Processor_TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf
Chapter 3.8: D18F5xE0 Processor TDP Running Average (p. 452)

Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Acked-by: Jean Delvare <khali@linux-fr.org>
[guenter.roeck@ericsson.com: Removed unnecessary return statement]
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Cc: stable@vger.kernel.org # 3.0+

Showing 1 changed file with 39 additions and 0 deletions Side-by-side Diff

drivers/hwmon/fam15h_power.c
... ... @@ -122,6 +122,38 @@
122 122 return true;
123 123 }
124 124  
  125 +/*
  126 + * Newer BKDG versions have an updated recommendation on how to properly
  127 + * initialize the running average range (was: 0xE, now: 0x9). This avoids
  128 + * counter saturations resulting in bogus power readings.
  129 + * We correct this value ourselves to cope with older BIOSes.
  130 + */
  131 +static void __devinit tweak_runavg_range(struct pci_dev *pdev)
  132 +{
  133 + u32 val;
  134 + const struct pci_device_id affected_device = {
  135 + PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) };
  136 +
  137 + /*
  138 + * let this quirk apply only to the current version of the
  139 + * northbridge, since future versions may change the behavior
  140 + */
  141 + if (!pci_match_id(&affected_device, pdev))
  142 + return;
  143 +
  144 + pci_bus_read_config_dword(pdev->bus,
  145 + PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
  146 + REG_TDP_RUNNING_AVERAGE, &val);
  147 + if ((val & 0xf) != 0xe)
  148 + return;
  149 +
  150 + val &= ~0xf;
  151 + val |= 0x9;
  152 + pci_bus_write_config_dword(pdev->bus,
  153 + PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
  154 + REG_TDP_RUNNING_AVERAGE, val);
  155 +}
  156 +
125 157 static void __devinit fam15h_power_init_data(struct pci_dev *f4,
126 158 struct fam15h_power_data *data)
127 159 {
... ... @@ -154,6 +186,13 @@
154 186 struct fam15h_power_data *data;
155 187 struct device *dev;
156 188 int err;
  189 +
  190 + /*
  191 + * though we ignore every other northbridge, we still have to
  192 + * do the tweaking on _each_ node in MCM processors as the counters
  193 + * are working hand-in-hand
  194 + */
  195 + tweak_runavg_range(pdev);
157 196  
158 197 if (!fam15h_power_is_internal_node0(pdev)) {
159 198 err = -ENODEV;