aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/fam15h_power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/fam15h_power.c')
-rw-r--r--drivers/hwmon/fam15h_power.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index b7494af1e4a9..e8e18cab1fb8 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -122,6 +122,41 @@ static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4)
122 return true; 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 */
131static DEFINE_PCI_DEVICE_TABLE(affected_device) = {
132 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
133 { 0 }
134};
135
136static void __devinit tweak_runavg_range(struct pci_dev *pdev)
137{
138 u32 val;
139
140 /*
141 * let this quirk apply only to the current version of the
142 * northbridge, since future versions may change the behavior
143 */
144 if (!pci_match_id(affected_device, pdev))
145 return;
146
147 pci_bus_read_config_dword(pdev->bus,
148 PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
149 REG_TDP_RUNNING_AVERAGE, &val);
150 if ((val & 0xf) != 0xe)
151 return;
152
153 val &= ~0xf;
154 val |= 0x9;
155 pci_bus_write_config_dword(pdev->bus,
156 PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
157 REG_TDP_RUNNING_AVERAGE, val);
158}
159
125static void __devinit fam15h_power_init_data(struct pci_dev *f4, 160static void __devinit fam15h_power_init_data(struct pci_dev *f4,
126 struct fam15h_power_data *data) 161 struct fam15h_power_data *data)
127{ 162{
@@ -155,6 +190,13 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
155 struct device *dev; 190 struct device *dev;
156 int err; 191 int err;
157 192
193 /*
194 * though we ignore every other northbridge, we still have to
195 * do the tweaking on _each_ node in MCM processors as the counters
196 * are working hand-in-hand
197 */
198 tweak_runavg_range(pdev);
199
158 if (!fam15h_power_is_internal_node0(pdev)) { 200 if (!fam15h_power_is_internal_node0(pdev)) {
159 err = -ENODEV; 201 err = -ENODEV;
160 goto exit; 202 goto exit;