blob: 86c2cec9e6cc7e5a45b09e7e760723f91a29d090 [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>
Andreas Herrmann23ac4ae2010-09-17 18:03:43 +020014#include <asm/amd_nb.h>
Andi Kleena32073b2006-06-26 13:56:40 +020015
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060016#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
17#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
18
Andi Kleena32073b2006-06-26 13:56:40 +020019static u32 *flush_words;
20
Jan Beulich691269f2011-02-09 08:26:53 +000021const struct pci_device_id amd_nb_misc_ids[] = {
Joerg Roedelcf169702008-09-02 13:13:40 +020022 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
23 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
Borislav Petkovcb293252011-01-19 18:22:11 +010024 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
Borislav Petkov24214442012-05-04 18:28:21 +020025 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -050026 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
Aravind Gopalakrishnan15895a72014-09-18 14:56:45 -050027 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -050028 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -060029 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060030 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
Andi Kleena32073b2006-06-26 13:56:40 +020031 {}
32};
Yazen Ghannamde6bd082016-11-10 15:10:54 -060033EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
Andi Kleena32073b2006-06-26 13:56:40 +020034
Jan Beulichc391c782013-03-11 09:56:05 +000035static const struct pci_device_id amd_nb_link_ids[] = {
Borislav Petkovcb6c8522011-03-30 20:34:47 +020036 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -050037 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
Aravind Gopalakrishnan15895a72014-09-18 14:56:45 -050038 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -050039 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -060040 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060041 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
Hans Rosenfeld41b26102011-01-24 16:05:42 +010042 {}
43};
44
Jan Beulich24d9b702011-01-10 16:20:23 +000045const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
46 { 0x00, 0x18, 0x20 },
47 { 0xff, 0x00, 0x20 },
48 { 0xfe, 0x00, 0x20 },
49 { }
50};
51
Yazen Ghannamc7993892016-11-10 15:10:53 -060052static struct amd_northbridge_info amd_northbridges;
53
54u16 amd_nb_num(void)
55{
56 return amd_northbridges.num;
57}
Yazen Ghannamde6bd082016-11-10 15:10:54 -060058EXPORT_SYMBOL_GPL(amd_nb_num);
Yazen Ghannamc7993892016-11-10 15:10:53 -060059
60bool amd_nb_has_feature(unsigned int feature)
61{
62 return ((amd_northbridges.flags & feature) == feature);
63}
Yazen Ghannamde6bd082016-11-10 15:10:54 -060064EXPORT_SYMBOL_GPL(amd_nb_has_feature);
Yazen Ghannamc7993892016-11-10 15:10:53 -060065
66struct amd_northbridge *node_to_amd_nb(int node)
67{
68 return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL;
69}
Yazen Ghannamde6bd082016-11-10 15:10:54 -060070EXPORT_SYMBOL_GPL(node_to_amd_nb);
Andi Kleena32073b2006-06-26 13:56:40 +020071
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020072static struct pci_dev *next_northbridge(struct pci_dev *dev,
Jan Beulich691269f2011-02-09 08:26:53 +000073 const struct pci_device_id *ids)
Andi Kleena32073b2006-06-26 13:56:40 +020074{
75 do {
76 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
77 if (!dev)
78 break;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020079 } while (!pci_match_id(ids, dev));
Andi Kleena32073b2006-06-26 13:56:40 +020080 return dev;
81}
82
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020083int amd_cache_northbridges(void)
Andi Kleena32073b2006-06-26 13:56:40 +020084{
Borislav Petkov84fd1d32011-03-03 12:59:32 +010085 u16 i = 0;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020086 struct amd_northbridge *nb;
Hans Rosenfeld41b26102011-01-24 16:05:42 +010087 struct pci_dev *misc, *link;
Ben Collins3c6df2a2007-05-23 13:57:43 -070088
Yazen Ghannamc7993892016-11-10 15:10:53 -060089 if (amd_northbridges.num)
Andi Kleena32073b2006-06-26 13:56:40 +020090 return 0;
91
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020092 misc = NULL;
93 while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
94 i++;
95
Borislav Petkov1ead8522016-06-16 19:13:49 +020096 if (!i)
97 return -ENODEV;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020098
Yazen Ghannamde6bd082016-11-10 15:10:54 -060099 nb = kcalloc(i, sizeof(struct amd_northbridge), GFP_KERNEL);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200100 if (!nb)
101 return -ENOMEM;
102
103 amd_northbridges.nb = nb;
104 amd_northbridges.num = i;
105
Hans Rosenfeld41b26102011-01-24 16:05:42 +0100106 link = misc = NULL;
Yazen Ghannamc7993892016-11-10 15:10:53 -0600107 for (i = 0; i != amd_northbridges.num; i++) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200108 node_to_amd_nb(i)->misc = misc =
109 next_northbridge(misc, amd_nb_misc_ids);
Hans Rosenfeld41b26102011-01-24 16:05:42 +0100110 node_to_amd_nb(i)->link = link =
111 next_northbridge(link, amd_nb_link_ids);
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -0500112 }
Andi Kleena32073b2006-06-26 13:56:40 +0200113
Aravind Gopalakrishnan1b457422015-04-07 16:46:37 -0500114 if (amd_gart_present())
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200115 amd_northbridges.flags |= AMD_NB_GART;
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200116
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200117 /*
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -0500118 * Check for L3 cache presence.
119 */
120 if (!cpuid_edx(0x80000006))
121 return 0;
122
123 /*
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200124 * Some CPU families support L3 Cache Index Disable. There are some
125 * limitations because of E382 and E388 on family 0x10.
126 */
127 if (boot_cpu_data.x86 == 0x10 &&
128 boot_cpu_data.x86_model >= 0x8 &&
129 (boot_cpu_data.x86_model > 0x9 ||
130 boot_cpu_data.x86_mask >= 0x1))
131 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
132
Hans Rosenfeldb453de02011-01-24 16:05:41 +0100133 if (boot_cpu_data.x86 == 0x15)
134 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
135
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100136 /* L3 cache partitioning is supported on family 0x15 */
137 if (boot_cpu_data.x86 == 0x15)
138 amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
139
Andi Kleena32073b2006-06-26 13:56:40 +0200140 return 0;
141}
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200142EXPORT_SYMBOL_GPL(amd_cache_northbridges);
Andi Kleena32073b2006-06-26 13:56:40 +0200143
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100144/*
145 * Ignores subdevice/subvendor but as far as I can figure out
146 * they're useless anyways
147 */
148bool __init early_is_amd_nb(u32 device)
Andi Kleena32073b2006-06-26 13:56:40 +0200149{
Jan Beulich691269f2011-02-09 08:26:53 +0000150 const struct pci_device_id *id;
Andi Kleena32073b2006-06-26 13:56:40 +0200151 u32 vendor = device & 0xffff;
Jan Beulich691269f2011-02-09 08:26:53 +0000152
Andi Kleena32073b2006-06-26 13:56:40 +0200153 device >>= 16;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200154 for (id = amd_nb_misc_ids; id->vendor; id++)
Andi Kleena32073b2006-06-26 13:56:40 +0200155 if (vendor == id->vendor && device == id->device)
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100156 return true;
157 return false;
Andi Kleena32073b2006-06-26 13:56:40 +0200158}
159
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700160struct resource *amd_get_mmconfig_range(struct resource *res)
161{
162 u32 address;
163 u64 base, msr;
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600164 unsigned int segn_busn_bits;
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700165
166 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
167 return NULL;
168
169 /* assume all cpus from fam10h have mmconfig */
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600170 if (boot_cpu_data.x86 < 0x10)
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700171 return NULL;
172
173 address = MSR_FAM10H_MMIO_CONF_BASE;
174 rdmsrl(address, msr);
175
176 /* mmconfig is not enabled */
177 if (!(msr & FAM10H_MMIO_CONF_ENABLE))
178 return NULL;
179
180 base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
181
182 segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
183 FAM10H_MMIO_CONF_BUSRANGE_MASK;
184
185 res->flags = IORESOURCE_MEM;
186 res->start = base;
187 res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
188 return res;
189}
190
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100191int amd_get_subcaches(int cpu)
192{
193 struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
194 unsigned int mask;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100195
196 if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
197 return 0;
198
199 pci_read_config_dword(link, 0x1d4, &mask);
200
Borislav Petkov8196dab2016-03-25 15:52:36 +0100201 return (mask >> (4 * cpu_data(cpu).cpu_core_id)) & 0xf;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100202}
203
Dan Carpenter2993ae32014-01-21 10:22:09 +0300204int amd_set_subcaches(int cpu, unsigned long mask)
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100205{
206 static unsigned int reset, ban;
207 struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
208 unsigned int reg;
Kevin Winchester141168c2011-12-20 20:52:22 -0400209 int cuid;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100210
211 if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
212 return -EINVAL;
213
214 /* if necessary, collect reset state of L3 partitioning and BAN mode */
215 if (reset == 0) {
216 pci_read_config_dword(nb->link, 0x1d4, &reset);
217 pci_read_config_dword(nb->misc, 0x1b8, &ban);
218 ban &= 0x180000;
219 }
220
221 /* deactivate BAN mode if any subcaches are to be disabled */
222 if (mask != 0xf) {
223 pci_read_config_dword(nb->misc, 0x1b8, &reg);
224 pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
225 }
226
Borislav Petkov8196dab2016-03-25 15:52:36 +0100227 cuid = cpu_data(cpu).cpu_core_id;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100228 mask <<= 4 * cuid;
229 mask |= (0xf ^ (1 << cuid)) << 26;
230
231 pci_write_config_dword(nb->link, 0x1d4, mask);
232
233 /* reset BAN mode if L3 partitioning returned to reset state */
234 pci_read_config_dword(nb->link, 0x1d4, &reg);
235 if (reg == reset) {
236 pci_read_config_dword(nb->misc, 0x1b8, &reg);
237 reg &= ~0x180000;
238 pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
239 }
240
241 return 0;
242}
243
Borislav Petkov09c6c302016-06-16 19:13:50 +0200244static void amd_cache_gart(void)
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200245{
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100246 u16 i;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200247
Borislav Petkov09c6c302016-06-16 19:13:50 +0200248 if (!amd_nb_has_feature(AMD_NB_GART))
249 return;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200250
Yazen Ghannamc7993892016-11-10 15:10:53 -0600251 flush_words = kmalloc_array(amd_northbridges.num, sizeof(u32), GFP_KERNEL);
Borislav Petkov09c6c302016-06-16 19:13:50 +0200252 if (!flush_words) {
253 amd_northbridges.flags &= ~AMD_NB_GART;
254 pr_notice("Cannot initialize GART flush words, GART support disabled\n");
255 return;
256 }
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200257
Yazen Ghannamc7993892016-11-10 15:10:53 -0600258 for (i = 0; i != amd_northbridges.num; i++)
Borislav Petkov09c6c302016-06-16 19:13:50 +0200259 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c, &flush_words[i]);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200260}
261
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200262void amd_flush_garts(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200263{
264 int flushed, i;
265 unsigned long flags;
266 static DEFINE_SPINLOCK(gart_lock);
267
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200268 if (!amd_nb_has_feature(AMD_NB_GART))
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200269 return;
270
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600271 /*
272 * Avoid races between AGP and IOMMU. In theory it's not needed
273 * but I'm not sure if the hardware won't lose flush requests
274 * when another is pending. This whole thing is so expensive anyways
275 * that it doesn't matter to serialize more. -AK
276 */
Andi Kleena32073b2006-06-26 13:56:40 +0200277 spin_lock_irqsave(&gart_lock, flags);
278 flushed = 0;
Yazen Ghannamc7993892016-11-10 15:10:53 -0600279 for (i = 0; i < amd_northbridges.num; i++) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200280 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
281 flush_words[i] | 1);
Andi Kleena32073b2006-06-26 13:56:40 +0200282 flushed++;
283 }
Yazen Ghannamc7993892016-11-10 15:10:53 -0600284 for (i = 0; i < amd_northbridges.num; i++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200285 u32 w;
286 /* Make sure the hardware actually executed the flush*/
287 for (;;) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200288 pci_read_config_dword(node_to_amd_nb(i)->misc,
Andi Kleena32073b2006-06-26 13:56:40 +0200289 0x9c, &w);
290 if (!(w & 1))
291 break;
292 cpu_relax();
293 }
294 }
295 spin_unlock_irqrestore(&gart_lock, flags);
296 if (!flushed)
Joe Perchesc767a542012-05-21 19:50:07 -0700297 pr_notice("nothing to flush?\n");
Andi Kleena32073b2006-06-26 13:56:40 +0200298}
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200299EXPORT_SYMBOL_GPL(amd_flush_garts);
Andi Kleena32073b2006-06-26 13:56:40 +0200300
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200301static __init int init_amd_nbs(void)
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100302{
Borislav Petkov09c6c302016-06-16 19:13:50 +0200303 amd_cache_northbridges();
304 amd_cache_gart();
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100305
Borislav Petkov09c6c302016-06-16 19:13:50 +0200306 return 0;
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100307}
308
309/* This has to go after the PCI subsystem */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200310fs_initcall(init_amd_nbs);