blob: 020c906f79349548d1d1ed5ddf101e1c83293c85 [file] [log] [blame]
Thomas Gleixnerf9724742019-06-04 10:11:10 +02001// SPDX-License-Identifier: GPL-2.0-only
Andi Kleena32073b2006-06-26 13:56:40 +02002/*
Ingo Molnar163b0992021-03-21 22:28:53 +01003 * Shared support code for AMD K8 northbridges and derivatives.
Thomas Gleixnerf9724742019-06-04 10:11:10 +02004 * Copyright 2006 Andi Kleen, SUSE Labs.
Andi Kleena32073b2006-06-26 13:56:40 +02005 */
Joe Perchesc767a542012-05-21 19:50:07 -07006
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
Andi Kleena32073b2006-06-26 13:56:40 +02009#include <linux/types.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090010#include <linux/slab.h>
Andi Kleena32073b2006-06-26 13:56:40 +020011#include <linux/init.h>
12#include <linux/errno.h>
Paul Gortmaker186f4362016-07-13 20:18:56 -040013#include <linux/export.h>
Andi Kleena32073b2006-06-26 13:56:40 +020014#include <linux/spinlock.h>
Woods, Briandedf7dc2018-11-06 20:08:14 +000015#include <linux/pci_ids.h>
Andreas Herrmann23ac4ae2010-09-17 18:03:43 +020016#include <asm/amd_nb.h>
Andi Kleena32073b2006-06-26 13:56:40 +020017
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060018#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070019#define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0
Woods, Brianbe3518a2018-11-06 20:08:18 +000020#define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480
Alexander Monakova4e918252020-05-10 20:48:40 +000021#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630
Yazen Ghannam4fb0abf2021-11-08 15:51:21 -060022#define PCI_DEVICE_ID_AMD_19H_M10H_ROOT 0x14a4
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060023#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070024#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
Woods, Brianbe3518a2018-11-06 20:08:18 +000025#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
Alexander Monakova4e918252020-05-10 20:48:40 +000026#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F4 0x144c
Marcel Bocuaf4e1c52019-07-22 20:45:10 +030027#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
Yazen Ghannamb3f79ae2020-01-10 01:56:49 +000028#define PCI_DEVICE_ID_AMD_19H_DF_F4 0x1654
Yazen Ghannam4fb0abf2021-11-08 15:51:21 -060029#define PCI_DEVICE_ID_AMD_19H_M10H_DF_F4 0x14b1
Mario Limonciello25572c82021-08-27 15:15:26 -050030#define PCI_DEVICE_ID_AMD_19H_M40H_ROOT 0x14b5
31#define PCI_DEVICE_ID_AMD_19H_M40H_DF_F4 0x167d
David Bartley2ade8fc2021-05-20 10:41:30 -070032#define PCI_DEVICE_ID_AMD_19H_M50H_DF_F4 0x166e
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060033
Yazen Ghannamb3218ae2021-10-28 17:56:57 +000034/* Protect the PCI config register pairs used for SMN. */
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060035static DEFINE_MUTEX(smn_mutex);
36
Andi Kleena32073b2006-06-26 13:56:40 +020037static u32 *flush_words;
38
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060039static const struct pci_device_id amd_root_ids[] = {
40 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_ROOT) },
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070041 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) },
Woods, Brianbe3518a2018-11-06 20:08:18 +000042 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) },
Alexander Monakova4e918252020-05-10 20:48:40 +000043 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_ROOT) },
Yazen Ghannam4fb0abf2021-11-08 15:51:21 -060044 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_ROOT) },
Mario Limonciello25572c82021-08-27 15:15:26 -050045 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_ROOT) },
Yazen Ghannamddfe43c2016-11-10 15:10:56 -060046 {}
47};
48
Borislav Petkovbfc11682017-10-22 12:47:31 +020049#define PCI_DEVICE_ID_AMD_CNB17H_F4 0x1704
50
Borislav Petkov19d33352020-03-16 13:23:21 +010051static const struct pci_device_id amd_nb_misc_ids[] = {
Joerg Roedelcf169702008-09-02 13:13:40 +020052 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
53 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
Borislav Petkovcb293252011-01-19 18:22:11 +010054 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
Borislav Petkov24214442012-05-04 18:28:21 +020055 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -050056 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
Aravind Gopalakrishnan15895a72014-09-18 14:56:45 -050057 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -050058 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -060059 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060060 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070061 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
Woods, Brianbe3518a2018-11-06 20:08:18 +000062 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
Alexander Monakova4e918252020-05-10 20:48:40 +000063 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
Borislav Petkovbfc11682017-10-22 12:47:31 +020064 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
Marcel Bocuaf4e1c52019-07-22 20:45:10 +030065 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
Yazen Ghannamb3f79ae2020-01-10 01:56:49 +000066 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
Yazen Ghannam4fb0abf2021-11-08 15:51:21 -060067 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) },
Mario Limonciello25572c82021-08-27 15:15:26 -050068 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F3) },
David Bartley2ade8fc2021-05-20 10:41:30 -070069 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) },
Andi Kleena32073b2006-06-26 13:56:40 +020070 {}
71};
Andi Kleena32073b2006-06-26 13:56:40 +020072
Jan Beulichc391c782013-03-11 09:56:05 +000073static const struct pci_device_id amd_nb_link_ids[] = {
Borislav Petkovcb6c8522011-03-30 20:34:47 +020074 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -050075 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
Aravind Gopalakrishnan15895a72014-09-18 14:56:45 -050076 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
Aravind Gopalakrishnan94c1acf2013-04-17 14:57:13 -050077 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
Aravind Gopalakrishnan85a88852014-02-20 10:28:46 -060078 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
Yazen Ghannamb791c6b2016-11-10 15:10:55 -060079 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
Guenter Roeckf9bc6b22018-05-04 13:01:32 -070080 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
Woods, Brianbe3518a2018-11-06 20:08:18 +000081 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
Alexander Monakova4e918252020-05-10 20:48:40 +000082 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F4) },
Marcel Bocuaf4e1c52019-07-22 20:45:10 +030083 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) },
Yazen Ghannamb3f79ae2020-01-10 01:56:49 +000084 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F4) },
Yazen Ghannam4fb0abf2021-11-08 15:51:21 -060085 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F4) },
Mario Limonciello25572c82021-08-27 15:15:26 -050086 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F4) },
David Bartley2ade8fc2021-05-20 10:41:30 -070087 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F4) },
Borislav Petkovbfc11682017-10-22 12:47:31 +020088 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
Hans Rosenfeld41b26102011-01-24 16:05:42 +010089 {}
90};
91
Pu Wenc6babb52018-09-25 22:46:11 +080092static const struct pci_device_id hygon_root_ids[] = {
93 { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_ROOT) },
94 {}
95};
96
YueHaibing025e3202019-06-14 23:54:41 +080097static const struct pci_device_id hygon_nb_misc_ids[] = {
Pu Wenc6babb52018-09-25 22:46:11 +080098 { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
99 {}
100};
101
102static const struct pci_device_id hygon_nb_link_ids[] = {
103 { PCI_DEVICE(PCI_VENDOR_ID_HYGON, PCI_DEVICE_ID_AMD_17H_DF_F4) },
104 {}
105};
106
Jan Beulich24d9b702011-01-10 16:20:23 +0000107const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
108 { 0x00, 0x18, 0x20 },
109 { 0xff, 0x00, 0x20 },
110 { 0xfe, 0x00, 0x20 },
111 { }
112};
113
Yazen Ghannamc7993892016-11-10 15:10:53 -0600114static struct amd_northbridge_info amd_northbridges;
115
116u16 amd_nb_num(void)
117{
118 return amd_northbridges.num;
119}
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600120EXPORT_SYMBOL_GPL(amd_nb_num);
Yazen Ghannamc7993892016-11-10 15:10:53 -0600121
122bool amd_nb_has_feature(unsigned int feature)
123{
124 return ((amd_northbridges.flags & feature) == feature);
125}
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600126EXPORT_SYMBOL_GPL(amd_nb_has_feature);
Yazen Ghannamc7993892016-11-10 15:10:53 -0600127
128struct amd_northbridge *node_to_amd_nb(int node)
129{
130 return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL;
131}
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600132EXPORT_SYMBOL_GPL(node_to_amd_nb);
Andi Kleena32073b2006-06-26 13:56:40 +0200133
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200134static struct pci_dev *next_northbridge(struct pci_dev *dev,
Jan Beulich691269f2011-02-09 08:26:53 +0000135 const struct pci_device_id *ids)
Andi Kleena32073b2006-06-26 13:56:40 +0200136{
137 do {
138 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
139 if (!dev)
140 break;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200141 } while (!pci_match_id(ids, dev));
Andi Kleena32073b2006-06-26 13:56:40 +0200142 return dev;
143}
144
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600145static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
146{
147 struct pci_dev *root;
148 int err = -ENODEV;
149
150 if (node >= amd_northbridges.num)
151 goto out;
152
153 root = node_to_amd_nb(node)->root;
154 if (!root)
155 goto out;
156
157 mutex_lock(&smn_mutex);
158
159 err = pci_write_config_dword(root, 0x60, address);
160 if (err) {
161 pr_warn("Error programming SMN address 0x%x.\n", address);
162 goto out_unlock;
163 }
164
165 err = (write ? pci_write_config_dword(root, 0x64, *value)
166 : pci_read_config_dword(root, 0x64, value));
167 if (err)
168 pr_warn("Error %s SMN address 0x%x.\n",
169 (write ? "writing to" : "reading from"), address);
170
171out_unlock:
172 mutex_unlock(&smn_mutex);
173
174out:
175 return err;
176}
177
178int amd_smn_read(u16 node, u32 address, u32 *value)
179{
180 return __amd_smn_rw(node, address, value, false);
181}
182EXPORT_SYMBOL_GPL(amd_smn_read);
183
184int amd_smn_write(u16 node, u32 address, u32 value)
185{
186 return __amd_smn_rw(node, address, &value, true);
187}
188EXPORT_SYMBOL_GPL(amd_smn_write);
189
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600190
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200191int amd_cache_northbridges(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200192{
Pu Wenc6babb52018-09-25 22:46:11 +0800193 const struct pci_device_id *misc_ids = amd_nb_misc_ids;
194 const struct pci_device_id *link_ids = amd_nb_link_ids;
195 const struct pci_device_id *root_ids = amd_root_ids;
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600196 struct pci_dev *root, *misc, *link;
Pu Wenc6babb52018-09-25 22:46:11 +0800197 struct amd_northbridge *nb;
Woods, Brian556e4c622018-11-06 20:08:16 +0000198 u16 roots_per_misc = 0;
199 u16 misc_count = 0;
200 u16 root_count = 0;
201 u16 i, j;
Ben Collins3c6df2a2007-05-23 13:57:43 -0700202
Yazen Ghannamc7993892016-11-10 15:10:53 -0600203 if (amd_northbridges.num)
Andi Kleena32073b2006-06-26 13:56:40 +0200204 return 0;
205
Pu Wenc6babb52018-09-25 22:46:11 +0800206 if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
207 root_ids = hygon_root_ids;
208 misc_ids = hygon_nb_misc_ids;
209 link_ids = hygon_nb_link_ids;
210 }
211
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200212 misc = NULL;
Pu Wenc6babb52018-09-25 22:46:11 +0800213 while ((misc = next_northbridge(misc, misc_ids)) != NULL)
Woods, Brian556e4c622018-11-06 20:08:16 +0000214 misc_count++;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200215
Woods, Brian556e4c622018-11-06 20:08:16 +0000216 if (!misc_count)
Borislav Petkov1ead8522016-06-16 19:13:49 +0200217 return -ENODEV;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200218
Woods, Brian556e4c622018-11-06 20:08:16 +0000219 root = NULL;
220 while ((root = next_northbridge(root, root_ids)) != NULL)
221 root_count++;
222
223 if (root_count) {
224 roots_per_misc = root_count / misc_count;
225
226 /*
227 * There should be _exactly_ N roots for each DF/SMN
228 * interface.
229 */
230 if (!roots_per_misc || (root_count % roots_per_misc)) {
231 pr_info("Unsupported AMD DF/PCI configuration found\n");
232 return -ENODEV;
233 }
234 }
235
236 nb = kcalloc(misc_count, sizeof(struct amd_northbridge), GFP_KERNEL);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200237 if (!nb)
238 return -ENOMEM;
239
240 amd_northbridges.nb = nb;
Woods, Brian556e4c622018-11-06 20:08:16 +0000241 amd_northbridges.num = misc_count;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200242
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600243 link = misc = root = NULL;
Woods, Brian556e4c622018-11-06 20:08:16 +0000244 for (i = 0; i < amd_northbridges.num; i++) {
Yazen Ghannamddfe43c2016-11-10 15:10:56 -0600245 node_to_amd_nb(i)->root = root =
Pu Wenc6babb52018-09-25 22:46:11 +0800246 next_northbridge(root, root_ids);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200247 node_to_amd_nb(i)->misc = misc =
Pu Wenc6babb52018-09-25 22:46:11 +0800248 next_northbridge(misc, misc_ids);
Hans Rosenfeld41b26102011-01-24 16:05:42 +0100249 node_to_amd_nb(i)->link = link =
Pu Wenc6babb52018-09-25 22:46:11 +0800250 next_northbridge(link, link_ids);
Woods, Brian556e4c622018-11-06 20:08:16 +0000251
252 /*
253 * If there are more PCI root devices than data fabric/
254 * system management network interfaces, then the (N)
255 * PCI roots per DF/SMN interface are functionally the
256 * same (for DF/SMN access) and N-1 are redundant. N-1
257 * PCI roots should be skipped per DF/SMN interface so
258 * the following DF/SMN interfaces get mapped to
259 * correct PCI roots.
260 */
261 for (j = 1; j < roots_per_misc; j++)
262 root = next_northbridge(root, root_ids);
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -0500263 }
Andi Kleena32073b2006-06-26 13:56:40 +0200264
Aravind Gopalakrishnan1b457422015-04-07 16:46:37 -0500265 if (amd_gart_present())
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200266 amd_northbridges.flags |= AMD_NB_GART;
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200267
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200268 /*
Aravind Gopalakrishnan7d64ac62013-08-02 17:43:03 -0500269 * Check for L3 cache presence.
270 */
271 if (!cpuid_edx(0x80000006))
272 return 0;
273
274 /*
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200275 * Some CPU families support L3 Cache Index Disable. There are some
276 * limitations because of E382 and E388 on family 0x10.
277 */
278 if (boot_cpu_data.x86 == 0x10 &&
279 boot_cpu_data.x86_model >= 0x8 &&
280 (boot_cpu_data.x86_model > 0x9 ||
Jia Zhangb3991512018-01-01 09:52:10 +0800281 boot_cpu_data.x86_stepping >= 0x1))
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +0200282 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
283
Hans Rosenfeldb453de02011-01-24 16:05:41 +0100284 if (boot_cpu_data.x86 == 0x15)
285 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
286
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100287 /* L3 cache partitioning is supported on family 0x15 */
288 if (boot_cpu_data.x86 == 0x15)
289 amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
290
Andi Kleena32073b2006-06-26 13:56:40 +0200291 return 0;
292}
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200293EXPORT_SYMBOL_GPL(amd_cache_northbridges);
Andi Kleena32073b2006-06-26 13:56:40 +0200294
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100295/*
296 * Ignores subdevice/subvendor but as far as I can figure out
297 * they're useless anyways
298 */
299bool __init early_is_amd_nb(u32 device)
Andi Kleena32073b2006-06-26 13:56:40 +0200300{
Pu Wenc6babb52018-09-25 22:46:11 +0800301 const struct pci_device_id *misc_ids = amd_nb_misc_ids;
Jan Beulich691269f2011-02-09 08:26:53 +0000302 const struct pci_device_id *id;
Andi Kleena32073b2006-06-26 13:56:40 +0200303 u32 vendor = device & 0xffff;
Jan Beulich691269f2011-02-09 08:26:53 +0000304
Pu Wenb7a5cb42018-09-25 22:45:01 +0800305 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
306 boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
307 return false;
308
Pu Wenc6babb52018-09-25 22:46:11 +0800309 if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
310 misc_ids = hygon_nb_misc_ids;
311
Andi Kleena32073b2006-06-26 13:56:40 +0200312 device >>= 16;
Pu Wenc6babb52018-09-25 22:46:11 +0800313 for (id = misc_ids; id->vendor; id++)
Andi Kleena32073b2006-06-26 13:56:40 +0200314 if (vendor == id->vendor && device == id->device)
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100315 return true;
316 return false;
Andi Kleena32073b2006-06-26 13:56:40 +0200317}
318
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700319struct resource *amd_get_mmconfig_range(struct resource *res)
320{
321 u32 address;
322 u64 base, msr;
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600323 unsigned int segn_busn_bits;
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700324
Pu Wenc6babb52018-09-25 22:46:11 +0800325 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
326 boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700327 return NULL;
328
329 /* assume all cpus from fam10h have mmconfig */
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600330 if (boot_cpu_data.x86 < 0x10)
Bjorn Helgaas24d25db2012-01-05 14:27:19 -0700331 return NULL;
332
333 address = MSR_FAM10H_MMIO_CONF_BASE;
334 rdmsrl(address, msr);
335
336 /* mmconfig is not enabled */
337 if (!(msr & FAM10H_MMIO_CONF_ENABLE))
338 return NULL;
339
340 base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
341
342 segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
343 FAM10H_MMIO_CONF_BUSRANGE_MASK;
344
345 res->flags = IORESOURCE_MEM;
346 res->start = base;
347 res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
348 return res;
349}
350
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100351int amd_get_subcaches(int cpu)
352{
Yazen Ghannamdb970bd22020-11-09 21:06:57 +0000353 struct pci_dev *link = node_to_amd_nb(topology_die_id(cpu))->link;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100354 unsigned int mask;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100355
356 if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
357 return 0;
358
359 pci_read_config_dword(link, 0x1d4, &mask);
360
Borislav Petkov8196dab2016-03-25 15:52:36 +0100361 return (mask >> (4 * cpu_data(cpu).cpu_core_id)) & 0xf;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100362}
363
Dan Carpenter2993ae32014-01-21 10:22:09 +0300364int amd_set_subcaches(int cpu, unsigned long mask)
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100365{
366 static unsigned int reset, ban;
Yazen Ghannamdb970bd22020-11-09 21:06:57 +0000367 struct amd_northbridge *nb = node_to_amd_nb(topology_die_id(cpu));
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100368 unsigned int reg;
Kevin Winchester141168c2011-12-20 20:52:22 -0400369 int cuid;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100370
371 if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
372 return -EINVAL;
373
374 /* if necessary, collect reset state of L3 partitioning and BAN mode */
375 if (reset == 0) {
376 pci_read_config_dword(nb->link, 0x1d4, &reset);
377 pci_read_config_dword(nb->misc, 0x1b8, &ban);
378 ban &= 0x180000;
379 }
380
381 /* deactivate BAN mode if any subcaches are to be disabled */
382 if (mask != 0xf) {
383 pci_read_config_dword(nb->misc, 0x1b8, &reg);
384 pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
385 }
386
Borislav Petkov8196dab2016-03-25 15:52:36 +0100387 cuid = cpu_data(cpu).cpu_core_id;
Hans Rosenfeldcabb5bd2011-02-07 18:10:39 +0100388 mask <<= 4 * cuid;
389 mask |= (0xf ^ (1 << cuid)) << 26;
390
391 pci_write_config_dword(nb->link, 0x1d4, mask);
392
393 /* reset BAN mode if L3 partitioning returned to reset state */
394 pci_read_config_dword(nb->link, 0x1d4, &reg);
395 if (reg == reset) {
396 pci_read_config_dword(nb->misc, 0x1b8, &reg);
397 reg &= ~0x180000;
398 pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
399 }
400
401 return 0;
402}
403
Borislav Petkov09c6c302016-06-16 19:13:50 +0200404static void amd_cache_gart(void)
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200405{
Borislav Petkov84fd1d32011-03-03 12:59:32 +0100406 u16 i;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200407
Borislav Petkov09c6c302016-06-16 19:13:50 +0200408 if (!amd_nb_has_feature(AMD_NB_GART))
409 return;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200410
Yazen Ghannamc7993892016-11-10 15:10:53 -0600411 flush_words = kmalloc_array(amd_northbridges.num, sizeof(u32), GFP_KERNEL);
Borislav Petkov09c6c302016-06-16 19:13:50 +0200412 if (!flush_words) {
413 amd_northbridges.flags &= ~AMD_NB_GART;
414 pr_notice("Cannot initialize GART flush words, GART support disabled\n");
415 return;
416 }
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200417
Yazen Ghannamc7993892016-11-10 15:10:53 -0600418 for (i = 0; i != amd_northbridges.num; i++)
Borislav Petkov09c6c302016-06-16 19:13:50 +0200419 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c, &flush_words[i]);
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200420}
421
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200422void amd_flush_garts(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200423{
424 int flushed, i;
425 unsigned long flags;
426 static DEFINE_SPINLOCK(gart_lock);
427
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200428 if (!amd_nb_has_feature(AMD_NB_GART))
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200429 return;
430
Yazen Ghannamde6bd082016-11-10 15:10:54 -0600431 /*
432 * Avoid races between AGP and IOMMU. In theory it's not needed
433 * but I'm not sure if the hardware won't lose flush requests
434 * when another is pending. This whole thing is so expensive anyways
435 * that it doesn't matter to serialize more. -AK
436 */
Andi Kleena32073b2006-06-26 13:56:40 +0200437 spin_lock_irqsave(&gart_lock, flags);
438 flushed = 0;
Yazen Ghannamc7993892016-11-10 15:10:53 -0600439 for (i = 0; i < amd_northbridges.num; i++) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200440 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
441 flush_words[i] | 1);
Andi Kleena32073b2006-06-26 13:56:40 +0200442 flushed++;
443 }
Yazen Ghannamc7993892016-11-10 15:10:53 -0600444 for (i = 0; i < amd_northbridges.num; i++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200445 u32 w;
446 /* Make sure the hardware actually executed the flush*/
447 for (;;) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200448 pci_read_config_dword(node_to_amd_nb(i)->misc,
Andi Kleena32073b2006-06-26 13:56:40 +0200449 0x9c, &w);
450 if (!(w & 1))
451 break;
452 cpu_relax();
453 }
454 }
455 spin_unlock_irqrestore(&gart_lock, flags);
456 if (!flushed)
Joe Perchesc767a542012-05-21 19:50:07 -0700457 pr_notice("nothing to flush?\n");
Andi Kleena32073b2006-06-26 13:56:40 +0200458}
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200459EXPORT_SYMBOL_GPL(amd_flush_garts);
Andi Kleena32073b2006-06-26 13:56:40 +0200460
Borislav Petkovbfc11682017-10-22 12:47:31 +0200461static void __fix_erratum_688(void *info)
462{
463#define MSR_AMD64_IC_CFG 0xC0011021
464
465 msr_set_bit(MSR_AMD64_IC_CFG, 3);
466 msr_set_bit(MSR_AMD64_IC_CFG, 14);
467}
468
469/* Apply erratum 688 fix so machines without a BIOS fix work. */
470static __init void fix_erratum_688(void)
471{
472 struct pci_dev *F4;
473 u32 val;
474
475 if (boot_cpu_data.x86 != 0x14)
476 return;
477
478 if (!amd_northbridges.num)
479 return;
480
481 F4 = node_to_amd_nb(0)->link;
482 if (!F4)
483 return;
484
485 if (pci_read_config_dword(F4, 0x164, &val))
486 return;
487
488 if (val & BIT(2))
489 return;
490
491 on_each_cpu(__fix_erratum_688, NULL, 0);
492
493 pr_info("x86/cpu/AMD: CPU erratum 688 worked around\n");
494}
495
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200496static __init int init_amd_nbs(void)
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100497{
Borislav Petkov09c6c302016-06-16 19:13:50 +0200498 amd_cache_northbridges();
499 amd_cache_gart();
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100500
Borislav Petkovbfc11682017-10-22 12:47:31 +0200501 fix_erratum_688();
502
Borislav Petkov09c6c302016-06-16 19:13:50 +0200503 return 0;
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100504}
505
506/* This has to go after the PCI subsystem */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200507fs_initcall(init_amd_nbs);