aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/amd_nb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/amd_nb.c')
-rw-r--r--arch/x86/kernel/amd_nb.c142
1 files changed, 87 insertions, 55 deletions
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 8f6463d8ed0d..0a99f7198bc3 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -12,95 +12,123 @@
12 12
13static u32 *flush_words; 13static u32 *flush_words;
14 14
15struct pci_device_id k8_nb_ids[] = { 15struct pci_device_id amd_nb_misc_ids[] = {
16 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, 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) }, 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_MISC) }, 18 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
19 {} 19 {}
20}; 20};
21EXPORT_SYMBOL(k8_nb_ids); 21EXPORT_SYMBOL(amd_nb_misc_ids);
22 22
23struct k8_northbridge_info k8_northbridges; 23const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
24EXPORT_SYMBOL(k8_northbridges); 24 { 0x00, 0x18, 0x20 },
25 { 0xff, 0x00, 0x20 },
26 { 0xfe, 0x00, 0x20 },
27 { }
28};
29
30struct amd_northbridge_info amd_northbridges;
31EXPORT_SYMBOL(amd_northbridges);
25 32
26static struct pci_dev *next_k8_northbridge(struct pci_dev *dev) 33static struct pci_dev *next_northbridge(struct pci_dev *dev,
34 struct pci_device_id *ids)
27{ 35{
28 do { 36 do {
29 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); 37 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
30 if (!dev) 38 if (!dev)
31 break; 39 break;
32 } while (!pci_match_id(&k8_nb_ids[0], dev)); 40 } while (!pci_match_id(ids, dev));
33 return dev; 41 return dev;
34} 42}
35 43
36int cache_k8_northbridges(void) 44int amd_cache_northbridges(void)
37{ 45{
38 int i; 46 int i = 0;
39 struct pci_dev *dev; 47 struct amd_northbridge *nb;
48 struct pci_dev *misc;
40 49
41 if (k8_northbridges.num) 50 if (amd_nb_num())
42 return 0; 51 return 0;
43 52
44 dev = NULL; 53 misc = NULL;
45 while ((dev = next_k8_northbridge(dev)) != NULL) 54 while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
46 k8_northbridges.num++; 55 i++;
47 56
48 /* some CPU families (e.g. family 0x11) do not support GART */ 57 if (i == 0)
49 if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 || 58 return 0;
50 boot_cpu_data.x86 == 0x15)
51 k8_northbridges.gart_supported = 1;
52 59
53 k8_northbridges.nb_misc = kmalloc((k8_northbridges.num + 1) * 60 nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
54 sizeof(void *), GFP_KERNEL); 61 if (!nb)
55 if (!k8_northbridges.nb_misc)
56 return -ENOMEM; 62 return -ENOMEM;
57 63
58 if (!k8_northbridges.num) { 64 amd_northbridges.nb = nb;
59 k8_northbridges.nb_misc[0] = NULL; 65 amd_northbridges.num = i;
60 return 0;
61 }
62 66
63 if (k8_northbridges.gart_supported) { 67 misc = NULL;
64 flush_words = kmalloc(k8_northbridges.num * sizeof(u32), 68 for (i = 0; i != amd_nb_num(); i++) {
65 GFP_KERNEL); 69 node_to_amd_nb(i)->misc = misc =
66 if (!flush_words) { 70 next_northbridge(misc, amd_nb_misc_ids);
67 kfree(k8_northbridges.nb_misc); 71 }
68 return -ENOMEM; 72
69 } 73 /* some CPU families (e.g. family 0x11) do not support GART */
70 } 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;
77
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;
71 87
72 dev = NULL;
73 i = 0;
74 while ((dev = next_k8_northbridge(dev)) != NULL) {
75 k8_northbridges.nb_misc[i] = dev;
76 if (k8_northbridges.gart_supported)
77 pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
78 }
79 k8_northbridges.nb_misc[i] = NULL;
80 return 0; 88 return 0;
81} 89}
82EXPORT_SYMBOL_GPL(cache_k8_northbridges); 90EXPORT_SYMBOL_GPL(amd_cache_northbridges);
83 91
84/* Ignores subdevice/subvendor but as far as I can figure out 92/* Ignores subdevice/subvendor but as far as I can figure out
85 they're useless anyways */ 93 they're useless anyways */
86int __init early_is_k8_nb(u32 device) 94int __init early_is_amd_nb(u32 device)
87{ 95{
88 struct pci_device_id *id; 96 struct pci_device_id *id;
89 u32 vendor = device & 0xffff; 97 u32 vendor = device & 0xffff;
90 device >>= 16; 98 device >>= 16;
91 for (id = k8_nb_ids; id->vendor; id++) 99 for (id = amd_nb_misc_ids; id->vendor; id++)
92 if (vendor == id->vendor && device == id->device) 100 if (vendor == id->vendor && device == id->device)
93 return 1; 101 return 1;
94 return 0; 102 return 0;
95} 103}
96 104
97void k8_flush_garts(void) 105int amd_cache_gart(void)
106{
107 int i;
108
109 if (!amd_nb_has_feature(AMD_NB_GART))
110 return 0;
111
112 flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
113 if (!flush_words) {
114 amd_northbridges.flags &= ~AMD_NB_GART;
115 return -ENOMEM;
116 }
117
118 for (i = 0; i != amd_nb_num(); i++)
119 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
120 &flush_words[i]);
121
122 return 0;
123}
124
125void amd_flush_garts(void)
98{ 126{
99 int flushed, i; 127 int flushed, i;
100 unsigned long flags; 128 unsigned long flags;
101 static DEFINE_SPINLOCK(gart_lock); 129 static DEFINE_SPINLOCK(gart_lock);
102 130
103 if (!k8_northbridges.gart_supported) 131 if (!amd_nb_has_feature(AMD_NB_GART))
104 return; 132 return;
105 133
106 /* Avoid races between AGP and IOMMU. In theory it's not needed 134 /* Avoid races between AGP and IOMMU. In theory it's not needed
@@ -109,16 +137,16 @@ void k8_flush_garts(void)
109 that it doesn't matter to serialize more. -AK */ 137 that it doesn't matter to serialize more. -AK */
110 spin_lock_irqsave(&gart_lock, flags); 138 spin_lock_irqsave(&gart_lock, flags);
111 flushed = 0; 139 flushed = 0;
112 for (i = 0; i < k8_northbridges.num; i++) { 140 for (i = 0; i < amd_nb_num(); i++) {
113 pci_write_config_dword(k8_northbridges.nb_misc[i], 0x9c, 141 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
114 flush_words[i]|1); 142 flush_words[i] | 1);
115 flushed++; 143 flushed++;
116 } 144 }
117 for (i = 0; i < k8_northbridges.num; i++) { 145 for (i = 0; i < amd_nb_num(); i++) {
118 u32 w; 146 u32 w;
119 /* Make sure the hardware actually executed the flush*/ 147 /* Make sure the hardware actually executed the flush*/
120 for (;;) { 148 for (;;) {
121 pci_read_config_dword(k8_northbridges.nb_misc[i], 149 pci_read_config_dword(node_to_amd_nb(i)->misc,
122 0x9c, &w); 150 0x9c, &w);
123 if (!(w & 1)) 151 if (!(w & 1))
124 break; 152 break;
@@ -129,19 +157,23 @@ void k8_flush_garts(void)
129 if (!flushed) 157 if (!flushed)
130 printk("nothing to flush?\n"); 158 printk("nothing to flush?\n");
131} 159}
132EXPORT_SYMBOL_GPL(k8_flush_garts); 160EXPORT_SYMBOL_GPL(amd_flush_garts);
133 161
134static __init int init_k8_nbs(void) 162static __init int init_amd_nbs(void)
135{ 163{
136 int err = 0; 164 int err = 0;
137 165
138 err = cache_k8_northbridges(); 166 err = amd_cache_northbridges();
139 167
140 if (err < 0) 168 if (err < 0)
141 printk(KERN_NOTICE "K8 NB: Cannot enumerate AMD northbridges.\n"); 169 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
170
171 if (amd_cache_gart() < 0)
172 printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
173 "GART support disabled.\n");
142 174
143 return err; 175 return err;
144} 176}
145 177
146/* This has to go after the PCI subsystem */ 178/* This has to go after the PCI subsystem */
147fs_initcall(init_k8_nbs); 179fs_initcall(init_amd_nbs);