• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Shared support code for AMD K8 northbridges and derivates.
3  * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
4  */
5 #include <linux/types.h>
6 #include <linux/slab.h>
7 #include <linux/init.h>
8 #include <linux/errno.h>
9 #include <linux/module.h>
10 #include <linux/spinlock.h>
11 #include <asm/amd_nb.h>
12 
13 static u32 *flush_words;
14 
15 const struct pci_device_id amd_nb_misc_ids[] = {
16 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
17 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
18 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
19 	{}
20 };
21 EXPORT_SYMBOL(amd_nb_misc_ids);
22 
23 static struct pci_device_id amd_nb_link_ids[] = {
24 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
25 	{}
26 };
27 
28 const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
29 	{ 0x00, 0x18, 0x20 },
30 	{ 0xff, 0x00, 0x20 },
31 	{ 0xfe, 0x00, 0x20 },
32 	{ }
33 };
34 
35 struct amd_northbridge_info amd_northbridges;
36 EXPORT_SYMBOL(amd_northbridges);
37 
next_northbridge(struct pci_dev * dev,const struct pci_device_id * ids)38 static struct pci_dev *next_northbridge(struct pci_dev *dev,
39 					const struct pci_device_id *ids)
40 {
41 	do {
42 		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
43 		if (!dev)
44 			break;
45 	} while (!pci_match_id(ids, dev));
46 	return dev;
47 }
48 
amd_cache_northbridges(void)49 int amd_cache_northbridges(void)
50 {
51 	u16 i = 0;
52 	struct amd_northbridge *nb;
53 	struct pci_dev *misc, *link;
54 
55 	if (amd_nb_num())
56 		return 0;
57 
58 	misc = NULL;
59 	while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
60 		i++;
61 
62 	if (i == 0)
63 		return 0;
64 
65 	nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
66 	if (!nb)
67 		return -ENOMEM;
68 
69 	amd_northbridges.nb = nb;
70 	amd_northbridges.num = i;
71 
72 	link = misc = NULL;
73 	for (i = 0; i != amd_nb_num(); i++) {
74 		node_to_amd_nb(i)->misc = misc =
75 			next_northbridge(misc, amd_nb_misc_ids);
76 		node_to_amd_nb(i)->link = link =
77 			next_northbridge(link, amd_nb_link_ids);
78         }
79 
80 	/* some CPU families (e.g. family 0x11) do not support GART */
81 	if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
82 	    boot_cpu_data.x86 == 0x15)
83 		amd_northbridges.flags |= AMD_NB_GART;
84 
85 	/*
86 	 * Some CPU families support L3 Cache Index Disable. There are some
87 	 * limitations because of E382 and E388 on family 0x10.
88 	 */
89 	if (boot_cpu_data.x86 == 0x10 &&
90 	    boot_cpu_data.x86_model >= 0x8 &&
91 	    (boot_cpu_data.x86_model > 0x9 ||
92 	     boot_cpu_data.x86_mask >= 0x1))
93 		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
94 
95 	if (boot_cpu_data.x86 == 0x15)
96 		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
97 
98 	/* L3 cache partitioning is supported on family 0x15 */
99 	if (boot_cpu_data.x86 == 0x15)
100 		amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
101 
102 	return 0;
103 }
104 EXPORT_SYMBOL_GPL(amd_cache_northbridges);
105 
106 /*
107  * Ignores subdevice/subvendor but as far as I can figure out
108  * they're useless anyways
109  */
early_is_amd_nb(u32 device)110 bool __init early_is_amd_nb(u32 device)
111 {
112 	const struct pci_device_id *id;
113 	u32 vendor = device & 0xffff;
114 
115 	device >>= 16;
116 	for (id = amd_nb_misc_ids; id->vendor; id++)
117 		if (vendor == id->vendor && device == id->device)
118 			return true;
119 	return false;
120 }
121 
amd_get_mmconfig_range(struct resource * res)122 struct resource *amd_get_mmconfig_range(struct resource *res)
123 {
124 	u32 address;
125 	u64 base, msr;
126 	unsigned segn_busn_bits;
127 
128 	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
129 		return NULL;
130 
131 	/* assume all cpus from fam10h have mmconfig */
132         if (boot_cpu_data.x86 < 0x10)
133 		return NULL;
134 
135 	address = MSR_FAM10H_MMIO_CONF_BASE;
136 	rdmsrl(address, msr);
137 
138 	/* mmconfig is not enabled */
139 	if (!(msr & FAM10H_MMIO_CONF_ENABLE))
140 		return NULL;
141 
142 	base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
143 
144 	segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
145 			 FAM10H_MMIO_CONF_BUSRANGE_MASK;
146 
147 	res->flags = IORESOURCE_MEM;
148 	res->start = base;
149 	res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
150 	return res;
151 }
152 
amd_get_subcaches(int cpu)153 int amd_get_subcaches(int cpu)
154 {
155 	struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
156 	unsigned int mask;
157 	int cuid;
158 
159 	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
160 		return 0;
161 
162 	pci_read_config_dword(link, 0x1d4, &mask);
163 
164 	cuid = cpu_data(cpu).compute_unit_id;
165 	return (mask >> (4 * cuid)) & 0xf;
166 }
167 
amd_set_subcaches(int cpu,int mask)168 int amd_set_subcaches(int cpu, int mask)
169 {
170 	static unsigned int reset, ban;
171 	struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
172 	unsigned int reg;
173 	int cuid;
174 
175 	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
176 		return -EINVAL;
177 
178 	/* if necessary, collect reset state of L3 partitioning and BAN mode */
179 	if (reset == 0) {
180 		pci_read_config_dword(nb->link, 0x1d4, &reset);
181 		pci_read_config_dword(nb->misc, 0x1b8, &ban);
182 		ban &= 0x180000;
183 	}
184 
185 	/* deactivate BAN mode if any subcaches are to be disabled */
186 	if (mask != 0xf) {
187 		pci_read_config_dword(nb->misc, 0x1b8, &reg);
188 		pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
189 	}
190 
191 	cuid = cpu_data(cpu).compute_unit_id;
192 	mask <<= 4 * cuid;
193 	mask |= (0xf ^ (1 << cuid)) << 26;
194 
195 	pci_write_config_dword(nb->link, 0x1d4, mask);
196 
197 	/* reset BAN mode if L3 partitioning returned to reset state */
198 	pci_read_config_dword(nb->link, 0x1d4, &reg);
199 	if (reg == reset) {
200 		pci_read_config_dword(nb->misc, 0x1b8, &reg);
201 		reg &= ~0x180000;
202 		pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
203 	}
204 
205 	return 0;
206 }
207 
amd_cache_gart(void)208 static int amd_cache_gart(void)
209 {
210 	u16 i;
211 
212        if (!amd_nb_has_feature(AMD_NB_GART))
213                return 0;
214 
215        flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
216        if (!flush_words) {
217                amd_northbridges.flags &= ~AMD_NB_GART;
218                return -ENOMEM;
219        }
220 
221        for (i = 0; i != amd_nb_num(); i++)
222                pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
223                                      &flush_words[i]);
224 
225        return 0;
226 }
227 
amd_flush_garts(void)228 void amd_flush_garts(void)
229 {
230 	int flushed, i;
231 	unsigned long flags;
232 	static DEFINE_SPINLOCK(gart_lock);
233 
234 	if (!amd_nb_has_feature(AMD_NB_GART))
235 		return;
236 
237 	/* Avoid races between AGP and IOMMU. In theory it's not needed
238 	   but I'm not sure if the hardware won't lose flush requests
239 	   when another is pending. This whole thing is so expensive anyways
240 	   that it doesn't matter to serialize more. -AK */
241 	spin_lock_irqsave(&gart_lock, flags);
242 	flushed = 0;
243 	for (i = 0; i < amd_nb_num(); i++) {
244 		pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
245 				       flush_words[i] | 1);
246 		flushed++;
247 	}
248 	for (i = 0; i < amd_nb_num(); i++) {
249 		u32 w;
250 		/* Make sure the hardware actually executed the flush*/
251 		for (;;) {
252 			pci_read_config_dword(node_to_amd_nb(i)->misc,
253 					      0x9c, &w);
254 			if (!(w & 1))
255 				break;
256 			cpu_relax();
257 		}
258 	}
259 	spin_unlock_irqrestore(&gart_lock, flags);
260 	if (!flushed)
261 		printk("nothing to flush?\n");
262 }
263 EXPORT_SYMBOL_GPL(amd_flush_garts);
264 
init_amd_nbs(void)265 static __init int init_amd_nbs(void)
266 {
267 	int err = 0;
268 
269 	err = amd_cache_northbridges();
270 
271 	if (err < 0)
272 		printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
273 
274 	if (amd_cache_gart() < 0)
275 		printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
276 		       "GART support disabled.\n");
277 
278 	return err;
279 }
280 
281 /* This has to go after the PCI subsystem */
282 fs_initcall(init_amd_nbs);
283