x86, amd: Enable L3 cache index disable on family 0x15
[linux-2.6-block.git] / arch / x86 / kernel / amd_nb.c
CommitLineData
a32073bf
AK
1/*
2 * Shared support code for AMD K8 northbridges and derivates.
3 * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
4 */
a32073bf 5#include <linux/types.h>
5a0e3ad6 6#include <linux/slab.h>
a32073bf
AK
7#include <linux/init.h>
8#include <linux/errno.h>
9#include <linux/module.h>
10#include <linux/spinlock.h>
23ac4ae8 11#include <asm/amd_nb.h>
a32073bf 12
a32073bf
AK
13static u32 *flush_words;
14
9653a5c7 15struct pci_device_id amd_nb_misc_ids[] = {
cf169702
JR
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) },
5c80cc78 18 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
a32073bf
AK
19 {}
20};
9653a5c7 21EXPORT_SYMBOL(amd_nb_misc_ids);
a32073bf 22
24d9b70b
JB
23const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
24 { 0x00, 0x18, 0x20 },
25 { 0xff, 0x00, 0x20 },
26 { 0xfe, 0x00, 0x20 },
27 { }
28};
29
eec1d4fa
HR
30struct amd_northbridge_info amd_northbridges;
31EXPORT_SYMBOL(amd_northbridges);
a32073bf 32
9653a5c7
HR
33static struct pci_dev *next_northbridge(struct pci_dev *dev,
34 struct pci_device_id *ids)
a32073bf
AK
35{
36 do {
37 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
38 if (!dev)
39 break;
9653a5c7 40 } while (!pci_match_id(ids, dev));
a32073bf
AK
41 return dev;
42}
43
9653a5c7 44int amd_cache_northbridges(void)
a32073bf 45{
9653a5c7
HR
46 int i = 0;
47 struct amd_northbridge *nb;
48 struct pci_dev *misc;
3c6df2a9 49
9653a5c7 50 if (amd_nb_num())
a32073bf
AK
51 return 0;
52
9653a5c7
HR
53 misc = NULL;
54 while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
55 i++;
900f9ac9 56
9653a5c7
HR
57 if (i == 0)
58 return 0;
a32073bf 59
9653a5c7
HR
60 nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
61 if (!nb)
a32073bf
AK
62 return -ENOMEM;
63
9653a5c7
HR
64 amd_northbridges.nb = nb;
65 amd_northbridges.num = i;
3c6df2a9 66
9653a5c7
HR
67 misc = NULL;
68 for (i = 0; i != amd_nb_num(); i++) {
69 node_to_amd_nb(i)->misc = misc =
70 next_northbridge(misc, amd_nb_misc_ids);
71 }
72
73 /* some CPU families (e.g. family 0x11) do not support GART */
74 if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
75 boot_cpu_data.x86 == 0x15)
76 amd_northbridges.flags |= AMD_NB_GART;
a32073bf 77
f658bcfb
HR
78 /*
79 * Some CPU families support L3 Cache Index Disable. There are some
80 * limitations because of E382 and E388 on family 0x10.
81 */
82 if (boot_cpu_data.x86 == 0x10 &&
83 boot_cpu_data.x86_model >= 0x8 &&
84 (boot_cpu_data.x86_model > 0x9 ||
85 boot_cpu_data.x86_mask >= 0x1))
86 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
87
b453de02
HR
88 if (boot_cpu_data.x86 == 0x15)
89 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
90
a32073bf
AK
91 return 0;
92}
9653a5c7 93EXPORT_SYMBOL_GPL(amd_cache_northbridges);
a32073bf
AK
94
95/* Ignores subdevice/subvendor but as far as I can figure out
96 they're useless anyways */
eec1d4fa 97int __init early_is_amd_nb(u32 device)
a32073bf
AK
98{
99 struct pci_device_id *id;
100 u32 vendor = device & 0xffff;
101 device >>= 16;
9653a5c7 102 for (id = amd_nb_misc_ids; id->vendor; id++)
a32073bf
AK
103 if (vendor == id->vendor && device == id->device)
104 return 1;
105 return 0;
106}
107
9653a5c7
HR
108int amd_cache_gart(void)
109{
110 int i;
111
112 if (!amd_nb_has_feature(AMD_NB_GART))
113 return 0;
114
115 flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
116 if (!flush_words) {
117 amd_northbridges.flags &= ~AMD_NB_GART;
118 return -ENOMEM;
119 }
120
121 for (i = 0; i != amd_nb_num(); i++)
122 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
123 &flush_words[i]);
124
125 return 0;
126}
127
eec1d4fa 128void amd_flush_garts(void)
a32073bf
AK
129{
130 int flushed, i;
131 unsigned long flags;
132 static DEFINE_SPINLOCK(gart_lock);
133
9653a5c7 134 if (!amd_nb_has_feature(AMD_NB_GART))
900f9ac9
AH
135 return;
136
a32073bf
AK
137 /* Avoid races between AGP and IOMMU. In theory it's not needed
138 but I'm not sure if the hardware won't lose flush requests
139 when another is pending. This whole thing is so expensive anyways
140 that it doesn't matter to serialize more. -AK */
141 spin_lock_irqsave(&gart_lock, flags);
142 flushed = 0;
9653a5c7
HR
143 for (i = 0; i < amd_nb_num(); i++) {
144 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
145 flush_words[i] | 1);
a32073bf
AK
146 flushed++;
147 }
9653a5c7 148 for (i = 0; i < amd_nb_num(); i++) {
a32073bf
AK
149 u32 w;
150 /* Make sure the hardware actually executed the flush*/
151 for (;;) {
9653a5c7 152 pci_read_config_dword(node_to_amd_nb(i)->misc,
a32073bf
AK
153 0x9c, &w);
154 if (!(w & 1))
155 break;
156 cpu_relax();
157 }
158 }
159 spin_unlock_irqrestore(&gart_lock, flags);
160 if (!flushed)
161 printk("nothing to flush?\n");
162}
eec1d4fa 163EXPORT_SYMBOL_GPL(amd_flush_garts);
a32073bf 164
eec1d4fa 165static __init int init_amd_nbs(void)
0e152cd7
BP
166{
167 int err = 0;
168
9653a5c7 169 err = amd_cache_northbridges();
0e152cd7
BP
170
171 if (err < 0)
eec1d4fa 172 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
0e152cd7 173
9653a5c7
HR
174 if (amd_cache_gart() < 0)
175 printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
176 "GART support disabled.\n");
177
0e152cd7
BP
178 return err;
179}
180
181/* This has to go after the PCI subsystem */
eec1d4fa 182fs_initcall(init_amd_nbs);