blob: 19d489ee2b1ea8bc09f983aa13c03ab7a3407646 [file] [log] [blame]
Andi Kleena32073b2006-06-26 13:56:40 +02001/*
2 * Shared support code for AMD K8 northbridges and derivates.
3 * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
4 */
Joe Perchesc767a542012-05-21 19:50:07 -07005
6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
Andi Kleena32073b2006-06-26 13:56:40 +02008#include <linux/types.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09009#include <linux/slab.h>
Andi Kleena32073b2006-06-26 13:56:40 +020010#include <linux/init.h>
11#include <linux/errno.h>
Paul Gortmaker186f4362016-07-13 20:18:56 -040012#include <linux/export.h>
Andi Kleena32073b2006-06-26 13:56:40 +020013#include <linux/spinlock.h>
Woods, Briandedf7dc2018-11-06 20:08:14 +000014#include <linux/pci_ids.h>
Andreas Herrmann23ac4ae2010-09-17 18:03:43 +020015#include <asm/amd_nb.h>
Andi Kleena32073b2006-06-26 13:56:40 +020016
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060017#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070018#define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060019#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070020#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060021
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060022/* Protect the PCI config register pairs used for SMN and DF indirect access. */
23static DEFINE_MUTEX(smn_mutex);
24
Andi Kleena32073b2006-06-26 13:56:40 +020025static u32 *flush_words;
26
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060027static const struct pci_device_id amd_root_ids[] = {
28 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) },
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070029 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) },
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060030 {}
31};
32
Borislav Petkovbfc11682017-10-22 12:47:31 +020033#define PCI_DEVICE_ID_AMD_CNB17H_F4 0x1704
34
Jan Beulich691269f2011-02-09 08:26:53 +000035const struct pci_device_id amd_nb_misc_ids[] = {
Joerg Roedelcf169702008-09-02 13:13:40 +020036 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
37 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
Borislav Petkovcb293252011-01-19 18:22:11 +010038 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
Borislav Petkov24214442012-05-04 18:28:21 +020039 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -050040 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
Aravind Gopalakrishnan15895a72014-09-18 14:56:45 -050041 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -050042 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -060043 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060044 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070045 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
Borislav Petkovbfc11682017-10-22 12:47:31 +020046 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
Andi Kleena32073b2006-06-26 13:56:40 +020047 {}
48};
Yazen Ghannamde6bd082016-11-10 15:10:54 -060049EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
Andi Kleena32073b2006-06-26 13:56:40 +020050
Jan Beulichc391c782013-03-11 09:56:05 +000051static const struct pci_device_id amd_nb_link_ids[] = {
Borislav Petkovcb6c8522011-03-30 20:34:47 +020052 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -050053 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
Aravind Gopalakrishnan15895a72014-09-18 14:56:45 -050054 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -050055 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -060056 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060057 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070058 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
Borislav Petkovbfc11682017-10-22 12:47:31 +020059 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
Hans Rosenfeld41b26102011-01-24 16:05:42 +010060 {}
61};
62
Pu Wenc6babb52018-09-25 22:46:11 +080063static const struct pci_device_id hygon_root_ids[] = {
64 { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_ROOT) },
65 {}
66};
67
68const struct pci_device_id hygon_nb_misc_ids[] = {
69 { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
70 {}
71};
72
73static const struct pci_device_id hygon_nb_link_ids[] = {
74 { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F4) },
75 {}
76};
77
Jan Beulich24d9b702011-01-10 16:20:23 +000078const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
79 { 0x00, 0x18, 0x20 },
80 { 0xff, 0x00, 0x20 },
81 { 0xfe, 0x00, 0x20 },
82 { }
83};
84
Yazen Ghannamc7993892016-11-10 15:10:53 -060085static struct amd_northbridge_info amd_northbridges;
86
87u16 amd_nb_num(void)
88{
89 return amd_northbridges.num;
90}
Yazen Ghannamde6bd082016-11-10 15:10:54 -060091EXPORT_SYMBOL_GPL(amd_nb_num);
Yazen Ghannamc7993892016-11-10 15:10:53 -060092
93bool amd_nb_has_feature(unsigned int feature)
94{
95 return ((amd_northbridges.flags & feature) == feature);
96}
Yazen Ghannamde6bd082016-11-10 15:10:54 -060097EXPORT_SYMBOL_GPL(amd_nb_has_feature);
Yazen Ghannamc7993892016-11-10 15:10:53 -060098
99struct amd_northbridge *node_to_amd_nb(int node)
100{
101 return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL;
102}
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600103EXPORT_SYMBOL_GPL(node_to_amd_nb);
Andi Kleena32073b2006-06-26 13:56:40 +0200104
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200105static struct pci_dev *next_northbridge(struct pci_dev *dev,
Jan Beulich691269f2011-02-09 08:26:53 +0000106 const struct pci_device_id *ids)
Andi Kleena32073b2006-06-26 13:56:40 +0200107{
108 do {
109 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
110 if (!dev)
111 break;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200112 } while (!pci_match_id(ids, dev));
Andi Kleena32073b2006-06-26 13:56:40 +0200113 return dev;
114}
115
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600116static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
117{
118 struct pci_dev *root;
119 int err = -ENODEV;
120
121 if (node >= amd_northbridges.num)
122 goto out;
123
124 root = node_to_amd_nb(node)->root;
125 if (!root)
126 goto out;
127
128 mutex_lock(&smn_mutex);
129
130 err = pci_write_config_dword(root, 0x60, address);
131 if (err) {
132 pr_warn("Error programming SMN address 0x%x.\n", address);
133 goto out_unlock;
134 }
135
136 err = (write ? pci_write_config_dword(root, 0x64, *value)
137 : pci_read_config_dword(root, 0x64, value));
138 if (err)
139 pr_warn("Error %s SMN address 0x%x.\n",
140 (write ? "writing to" : "reading from"), address);
141
142out_unlock:
143 mutex_unlock(&smn_mutex);
144
145out:
146 return err;
147}
148
149int amd_smn_read(u16 node, u32 address, u32 *value)
150{
151 return __amd_smn_rw(node, address, value, false);
152}
153EXPORT_SYMBOL_GPL(amd_smn_read);
154
155int amd_smn_write(u16 node, u32 address, u32 value)
156{
157 return __amd_smn_rw(node, address, &value, true);
158}
159EXPORT_SYMBOL_GPL(amd_smn_write);
160
161/*
162 * Data Fabric Indirect Access uses FICAA/FICAD.
163 *
164 * Fabric Indirect Configuration Access Address (FICAA): Constructed based
165 * on the device's Instance Id and the PCI function and register offset of
166 * the desired register.
167 *
168 * Fabric Indirect Configuration Access Data (FICAD): There are FICAD LO
169 * and FICAD HI registers but so far we only need the LO register.
170 */
171int amd_df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo)
172{
173 struct pci_dev *F4;
174 u32 ficaa;
175 int err = -ENODEV;
176
177 if (node >= amd_northbridges.num)
178 goto out;
179
180 F4 = node_to_amd_nb(node)->link;
181 if (!F4)
182 goto out;
183
184 ficaa = 1;
185 ficaa |= reg & 0x3FC;
186 ficaa |= (func & 0x7) << 11;
187 ficaa |= instance_id << 16;
188
189 mutex_lock(&smn_mutex);
190
191 err = pci_write_config_dword(F4, 0x5C, ficaa);
192 if (err) {
193 pr_warn("Error writing DF Indirect FICAA, FICAA=0x%x\n", ficaa);
194 goto out_unlock;
195 }
196
197 err = pci_read_config_dword(F4, 0x98, lo);
198 if (err)
199 pr_warn("Error reading DF Indirect FICAD LO, FICAA=0x%x.\n", ficaa);
200
201out_unlock:
202 mutex_unlock(&smn_mutex);
203
204out:
205 return err;
206}
207EXPORT_SYMBOL_GPL(amd_df_indirect_read);
208
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200209int amd_cache_northbridges(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200210{
Pu Wenc6babb52018-09-25 22:46:11 +0800211 const struct pci_device_id *misc_ids = amd_nb_misc_ids;
212 const struct pci_device_id *link_ids = amd_nb_link_ids;
213 const struct pci_device_id *root_ids = amd_root_ids;
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600214 struct pci_dev *root, *misc, *link;
Pu Wenc6babb52018-09-25 22:46:11 +0800215 struct amd_northbridge *nb;
216 u16 i = 0;
Ben Collins3c6df2a2007-05-23 13:57:43 -0700217
Yazen Ghannamc7993892016-11-10 15:10:53 -0600218 if (amd_northbridges.num)
Andi Kleena32073b2006-06-26 13:56:40 +0200219 return 0;
220
Pu Wenc6babb52018-09-25 22:46:11 +0800221 if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
222 root_ids = hygon_root_ids;
223 misc_ids = hygon_nb_misc_ids;
224 link_ids = hygon_nb_link_ids;
225 }
226
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200227 misc = NULL;
Pu Wenc6babb52018-09-25 22:46:11 +0800228 while ((misc = next_northbridge(misc, misc_ids)) != NULL)
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200229 i++;
230
Borislav Petkov1ead8522016-06-16 19:13:49 +0200231 if (!i)
232 return -ENODEV;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200233
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600234 nb = kcalloc(i, sizeof(struct amd_northbridge), GFP_KERNEL);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200235 if (!nb)
236 return -ENOMEM;
237
238 amd_northbridges.nb = nb;
239 amd_northbridges.num = i;
240
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600241 link = misc = root = NULL;
Yazen Ghannamc7993892016-11-10 15:10:53 -0600242 for (i = 0; i != amd_northbridges.num; i++) {
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600243 node_to_amd_nb(i)->root = root =
Pu Wenc6babb52018-09-25 22:46:11 +0800244 next_northbridge(root, root_ids);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200245 node_to_amd_nb(i)->misc = misc =
Pu Wenc6babb52018-09-25 22:46:11 +0800246 next_northbridge(misc, misc_ids);
Hans Rosenfeld41b26102011-01-24 16:05:42 +0100247 node_to_amd_nb(i)->link = link =
Pu Wenc6babb52018-09-25 22:46:11 +0800248 next_northbridge(link, link_ids);
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -0500249 }
Andi Kleena32073b2006-06-26 13:56:40 +0200250
Aravind Gopalakrishnan1b457422015-04-07 16:46:37 -0500251 if (amd_gart_present())
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200252 amd_northbridges.flags |= AMD_NB_GART;
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200253
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200254 /*
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -0500255 * Check for L3 cache presence.
256 */
257 if (!cpuid_edx(0x80000006))
258 return 0;
259
260 /*
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200261 * Some CPU families support L3 Cache Index Disable. There are some
262 * limitations because of E382 and E388 on family 0x10.
263 */
264 if (boot_cpu_data.x86 == 0x10 &&
265 boot_cpu_data.x86_model >= 0x8 &&
266 (boot_cpu_data.x86_model > 0x9 ||
Jia Zhangb3991512018-01-01 09:52:10 +0800267 boot_cpu_data.x86_stepping >= 0x1))
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200268 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
269
Hans Rosenfeldb453de02011-01-24 16:05:41 +0100270 if (boot_cpu_data.x86 == 0x15)
271 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
272
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100273 /* L3 cache partitioning is supported on family 0x15 */
274 if (boot_cpu_data.x86 == 0x15)
275 amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
276
Andi Kleena32073b2006-06-26 13:56:40 +0200277 return 0;
278}
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200279EXPORT_SYMBOL_GPL(amd_cache_northbridges);
Andi Kleena32073b2006-06-26 13:56:40 +0200280
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100281/*
282 * Ignores subdevice/subvendor but as far as I can figure out
283 * they're useless anyways
284 */
285bool __init early_is_amd_nb(u32 device)
Andi Kleena32073b2006-06-26 13:56:40 +0200286{
Pu Wenc6babb52018-09-25 22:46:11 +0800287 const struct pci_device_id *misc_ids = amd_nb_misc_ids;
Jan Beulich691269f2011-02-09 08:26:53 +0000288 const struct pci_device_id *id;
Andi Kleena32073b2006-06-26 13:56:40 +0200289 u32 vendor = device & 0xffff;
Jan Beulich691269f2011-02-09 08:26:53 +0000290
Pu Wenb7a5cb42018-09-25 22:45:01 +0800291 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
292 boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
293 return false;
294
Pu Wenc6babb52018-09-25 22:46:11 +0800295 if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
296 misc_ids = hygon_nb_misc_ids;
297
Andi Kleena32073b2006-06-26 13:56:40 +0200298 device >>= 16;
Pu Wenc6babb52018-09-25 22:46:11 +0800299 for (id = misc_ids; id->vendor; id++)
Andi Kleena32073b2006-06-26 13:56:40 +0200300 if (vendor == id->vendor && device == id->device)
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100301 return true;
302 return false;
Andi Kleena32073b2006-06-26 13:56:40 +0200303}
304
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700305struct resource *amd_get_mmconfig_range(struct resource *res)
306{
307 u32 address;
308 u64 base, msr;
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600309 unsigned int segn_busn_bits;
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700310
Pu Wenc6babb52018-09-25 22:46:11 +0800311 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
312 boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700313 return NULL;
314
315 /* assume all cpus from fam10h have mmconfig */
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600316 if (boot_cpu_data.x86 < 0x10)
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700317 return NULL;
318
319 address = MSR_FAM10H_MMIO_CONF_BASE;
320 rdmsrl(address, msr);
321
322 /* mmconfig is not enabled */
323 if (!(msr & FAM10H_MMIO_CONF_ENABLE))
324 return NULL;
325
326 base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
327
328 segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
329 FAM10H_MMIO_CONF_BUSRANGE_MASK;
330
331 res->flags = IORESOURCE_MEM;
332 res->start = base;
333 res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
334 return res;
335}
336
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100337int amd_get_subcaches(int cpu)
338{
339 struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
340 unsigned int mask;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100341
342 if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
343 return 0;
344
345 pci_read_config_dword(link, 0x1d4, &mask);
346
Borislav Petkov8196dab2016-03-25 15:52:36 +0100347 return (mask >> (4 * cpu_data(cpu).cpu_core_id)) & 0xf;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100348}
349
Dan Carpenter2993ae32014-01-21 10:22:09 +0300350int amd_set_subcaches(int cpu, unsigned long mask)
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100351{
352 static unsigned int reset, ban;
353 struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
354 unsigned int reg;
Kevin Winchester141168c2011-12-20 20:52:22 -0400355 int cuid;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100356
357 if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
358 return -EINVAL;
359
360 /* if necessary, collect reset state of L3 partitioning and BAN mode */
361 if (reset == 0) {
362 pci_read_config_dword(nb->link, 0x1d4, &reset);
363 pci_read_config_dword(nb->misc, 0x1b8, &ban);
364 ban &= 0x180000;
365 }
366
367 /* deactivate BAN mode if any subcaches are to be disabled */
368 if (mask != 0xf) {
369 pci_read_config_dword(nb->misc, 0x1b8, &reg);
370 pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
371 }
372
Borislav Petkov8196dab2016-03-25 15:52:36 +0100373 cuid = cpu_data(cpu).cpu_core_id;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100374 mask <<= 4 * cuid;
375 mask |= (0xf ^ (1 << cuid)) << 26;
376
377 pci_write_config_dword(nb->link, 0x1d4, mask);
378
379 /* reset BAN mode if L3 partitioning returned to reset state */
380 pci_read_config_dword(nb->link, 0x1d4, &reg);
381 if (reg == reset) {
382 pci_read_config_dword(nb->misc, 0x1b8, &reg);
383 reg &= ~0x180000;
384 pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
385 }
386
387 return 0;
388}
389
Borislav Petkov09c6c302016-06-16 19:13:50 +0200390static void amd_cache_gart(void)
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200391{
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100392 u16 i;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200393
Borislav Petkov09c6c302016-06-16 19:13:50 +0200394 if (!amd_nb_has_feature(AMD_NB_GART))
395 return;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200396
Yazen Ghannamc7993892016-11-10 15:10:53 -0600397 flush_words = kmalloc_array(amd_northbridges.num, sizeof(u32), GFP_KERNEL);
Borislav Petkov09c6c302016-06-16 19:13:50 +0200398 if (!flush_words) {
399 amd_northbridges.flags &= ~AMD_NB_GART;
400 pr_notice("Cannot initialize GART flush words, GART support disabled\n");
401 return;
402 }
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200403
Yazen Ghannamc7993892016-11-10 15:10:53 -0600404 for (i = 0; i != amd_northbridges.num; i++)
Borislav Petkov09c6c302016-06-16 19:13:50 +0200405 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c, &flush_words[i]);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200406}
407
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200408void amd_flush_garts(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200409{
410 int flushed, i;
411 unsigned long flags;
412 static DEFINE_SPINLOCK(gart_lock);
413
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200414 if (!amd_nb_has_feature(AMD_NB_GART))
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200415 return;
416
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600417 /*
418 * Avoid races between AGP and IOMMU. In theory it's not needed
419 * but I'm not sure if the hardware won't lose flush requests
420 * when another is pending. This whole thing is so expensive anyways
421 * that it doesn't matter to serialize more. -AK
422 */
Andi Kleena32073b2006-06-26 13:56:40 +0200423 spin_lock_irqsave(&gart_lock, flags);
424 flushed = 0;
Yazen Ghannamc7993892016-11-10 15:10:53 -0600425 for (i = 0; i < amd_northbridges.num; i++) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200426 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
427 flush_words[i] | 1);
Andi Kleena32073b2006-06-26 13:56:40 +0200428 flushed++;
429 }
Yazen Ghannamc7993892016-11-10 15:10:53 -0600430 for (i = 0; i < amd_northbridges.num; i++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200431 u32 w;
432 /* Make sure the hardware actually executed the flush*/
433 for (;;) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200434 pci_read_config_dword(node_to_amd_nb(i)->misc,
Andi Kleena32073b2006-06-26 13:56:40 +0200435 0x9c, &w);
436 if (!(w & 1))
437 break;
438 cpu_relax();
439 }
440 }
441 spin_unlock_irqrestore(&gart_lock, flags);
442 if (!flushed)
Joe Perchesc767a542012-05-21 19:50:07 -0700443 pr_notice("nothing to flush?\n");
Andi Kleena32073b2006-06-26 13:56:40 +0200444}
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200445EXPORT_SYMBOL_GPL(amd_flush_garts);
Andi Kleena32073b2006-06-26 13:56:40 +0200446
Borislav Petkovbfc11682017-10-22 12:47:31 +0200447static void __fix_erratum_688(void *info)
448{
449#define MSR_AMD64_IC_CFG 0xC0011021
450
451 msr_set_bit(MSR_AMD64_IC_CFG, 3);
452 msr_set_bit(MSR_AMD64_IC_CFG, 14);
453}
454
455/* Apply erratum 688 fix so machines without a BIOS fix work. */
456static __init void fix_erratum_688(void)
457{
458 struct pci_dev *F4;
459 u32 val;
460
461 if (boot_cpu_data.x86 != 0x14)
462 return;
463
464 if (!amd_northbridges.num)
465 return;
466
467 F4 = node_to_amd_nb(0)->link;
468 if (!F4)
469 return;
470
471 if (pci_read_config_dword(F4, 0x164, &val))
472 return;
473
474 if (val & BIT(2))
475 return;
476
477 on_each_cpu(__fix_erratum_688, NULL, 0);
478
479 pr_info("x86/cpu/AMD: CPU erratum 688 worked around\n");
480}
481
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200482static __init int init_amd_nbs(void)
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100483{
Borislav Petkov09c6c302016-06-16 19:13:50 +0200484 amd_cache_northbridges();
485 amd_cache_gart();
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100486
Borislav Petkovbfc11682017-10-22 12:47:31 +0200487 fix_erratum_688();
488
Borislav Petkov09c6c302016-06-16 19:13:50 +0200489 return 0;
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100490}
491
492/* This has to go after the PCI subsystem */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200493fs_initcall(init_amd_nbs);