aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/amd_nb.c
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@amd.com>2010-10-29 11:14:31 -0400
committerBorislav Petkov <borislav.petkov@amd.com>2010-11-18 09:53:05 -0500
commit9653a5c76c8677b05b45b3b999d3b39988d2a064 (patch)
tree9224748c69296fc6ac50beae72f20e6e2ae16aca /arch/x86/kernel/amd_nb.c
parenteec1d4fa00c6552ae2fdf71d59f1eded7c88dd89 (diff)
x86, amd-nb: Cleanup AMD northbridge caching code
Support more than just the "Misc Control" part of the northbridges. Support more flags by turning "gart_supported" into a single bit flag that is stored in a flags member. Clean up related code by using a set of functions (amd_nb_num(), amd_nb_has_feature() and node_to_amd_nb()) instead of accessing the NB data structures directly. Reorder the initialization code and put the GART flush words caching in a separate function. Signed-off-by: Hans Rosenfeld <hans.rosenfeld@amd.com> Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Diffstat (limited to 'arch/x86/kernel/amd_nb.c')
-rw-r--r--arch/x86/kernel/amd_nb.c109
1 files changed, 62 insertions, 47 deletions
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index c46df406a2a..63c8b4f2c1a 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -12,74 +12,65 @@
12 12
13static u32 *flush_words; 13static u32 *flush_words;
14 14
15struct pci_device_id amd_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(amd_nb_ids); 21EXPORT_SYMBOL(amd_nb_misc_ids);
22 22
23struct amd_northbridge_info amd_northbridges; 23struct amd_northbridge_info amd_northbridges;
24EXPORT_SYMBOL(amd_northbridges); 24EXPORT_SYMBOL(amd_northbridges);
25 25
26static struct pci_dev *next_amd_northbridge(struct pci_dev *dev) 26static struct pci_dev *next_northbridge(struct pci_dev *dev,
27 struct pci_device_id *ids)
27{ 28{
28 do { 29 do {
29 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); 30 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
30 if (!dev) 31 if (!dev)
31 break; 32 break;
32 } while (!pci_match_id(&amd_nb_ids[0], dev)); 33 } while (!pci_match_id(ids, dev));
33 return dev; 34 return dev;
34} 35}
35 36
36int cache_amd_northbridges(void) 37int amd_cache_northbridges(void)
37{ 38{
38 int i; 39 int i = 0;
39 struct pci_dev *dev; 40 struct amd_northbridge *nb;
41 struct pci_dev *misc;
40 42
41 if (amd_northbridges.num) 43 if (amd_nb_num())
42 return 0; 44 return 0;
43 45
44 dev = NULL; 46 misc = NULL;
45 while ((dev = next_amd_northbridge(dev)) != NULL) 47 while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
46 amd_northbridges.num++; 48 i++;
47 49
48 /* some CPU families (e.g. family 0x11) do not support GART */ 50 if (i == 0)
49 if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 || 51 return 0;
50 boot_cpu_data.x86 == 0x15)
51 amd_northbridges.gart_supported = 1;
52 52
53 amd_northbridges.nb_misc = kmalloc((amd_northbridges.num + 1) * 53 nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
54 sizeof(void *), GFP_KERNEL); 54 if (!nb)
55 if (!amd_northbridges.nb_misc)
56 return -ENOMEM; 55 return -ENOMEM;
57 56
58 if (!amd_northbridges.num) { 57 amd_northbridges.nb = nb;
59 amd_northbridges.nb_misc[0] = NULL; 58 amd_northbridges.num = i;
60 return 0;
61 }
62 59
63 if (amd_northbridges.gart_supported) { 60 misc = NULL;
64 flush_words = kmalloc(amd_northbridges.num * sizeof(u32), 61 for (i = 0; i != amd_nb_num(); i++) {
65 GFP_KERNEL); 62 node_to_amd_nb(i)->misc = misc =
66 if (!flush_words) { 63 next_northbridge(misc, amd_nb_misc_ids);
67 kfree(amd_northbridges.nb_misc); 64 }
68 return -ENOMEM; 65
69 } 66 /* some CPU families (e.g. family 0x11) do not support GART */
70 } 67 if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
68 boot_cpu_data.x86 == 0x15)
69 amd_northbridges.flags |= AMD_NB_GART;
71 70
72 dev = NULL;
73 i = 0;
74 while ((dev = next_amd_northbridge(dev)) != NULL) {
75 amd_northbridges.nb_misc[i] = dev;
76 if (amd_northbridges.gart_supported)
77 pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
78 }
79 amd_northbridges.nb_misc[i] = NULL;
80 return 0; 71 return 0;
81} 72}
82EXPORT_SYMBOL_GPL(cache_amd_northbridges); 73EXPORT_SYMBOL_GPL(amd_cache_northbridges);
83 74
84/* Ignores subdevice/subvendor but as far as I can figure out 75/* Ignores subdevice/subvendor but as far as I can figure out
85 they're useless anyways */ 76 they're useless anyways */
@@ -88,19 +79,39 @@ int __init early_is_amd_nb(u32 device)
88 struct pci_device_id *id; 79 struct pci_device_id *id;
89 u32 vendor = device & 0xffff; 80 u32 vendor = device & 0xffff;
90 device >>= 16; 81 device >>= 16;
91 for (id = amd_nb_ids; id->vendor; id++) 82 for (id = amd_nb_misc_ids; id->vendor; id++)
92 if (vendor == id->vendor && device == id->device) 83 if (vendor == id->vendor && device == id->device)
93 return 1; 84 return 1;
94 return 0; 85 return 0;
95} 86}
96 87
88int amd_cache_gart(void)
89{
90 int i;
91
92 if (!amd_nb_has_feature(AMD_NB_GART))
93 return 0;
94
95 flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
96 if (!flush_words) {
97 amd_northbridges.flags &= ~AMD_NB_GART;
98 return -ENOMEM;
99 }
100
101 for (i = 0; i != amd_nb_num(); i++)
102 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
103 &flush_words[i]);
104
105 return 0;
106}
107
97void amd_flush_garts(void) 108void amd_flush_garts(void)
98{ 109{
99 int flushed, i; 110 int flushed, i;
100 unsigned long flags; 111 unsigned long flags;
101 static DEFINE_SPINLOCK(gart_lock); 112 static DEFINE_SPINLOCK(gart_lock);
102 113
103 if (!amd_northbridges.gart_supported) 114 if (!amd_nb_has_feature(AMD_NB_GART))
104 return; 115 return;
105 116
106 /* Avoid races between AGP and IOMMU. In theory it's not needed 117 /* Avoid races between AGP and IOMMU. In theory it's not needed
@@ -109,16 +120,16 @@ void amd_flush_garts(void)
109 that it doesn't matter to serialize more. -AK */ 120 that it doesn't matter to serialize more. -AK */
110 spin_lock_irqsave(&gart_lock, flags); 121 spin_lock_irqsave(&gart_lock, flags);
111 flushed = 0; 122 flushed = 0;
112 for (i = 0; i < amd_northbridges.num; i++) { 123 for (i = 0; i < amd_nb_num(); i++) {
113 pci_write_config_dword(amd_northbridges.nb_misc[i], 0x9c, 124 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
114 flush_words[i]|1); 125 flush_words[i] | 1);
115 flushed++; 126 flushed++;
116 } 127 }
117 for (i = 0; i < amd_northbridges.num; i++) { 128 for (i = 0; i < amd_nb_num(); i++) {
118 u32 w; 129 u32 w;
119 /* Make sure the hardware actually executed the flush*/ 130 /* Make sure the hardware actually executed the flush*/
120 for (;;) { 131 for (;;) {
121 pci_read_config_dword(amd_northbridges.nb_misc[i], 132 pci_read_config_dword(node_to_amd_nb(i)->misc,
122 0x9c, &w); 133 0x9c, &w);
123 if (!(w & 1)) 134 if (!(w & 1))
124 break; 135 break;
@@ -135,11 +146,15 @@ static __init int init_amd_nbs(void)
135{ 146{
136 int err = 0; 147 int err = 0;
137 148
138 err = cache_amd_northbridges(); 149 err = amd_cache_northbridges();
139 150
140 if (err < 0) 151 if (err < 0)
141 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n"); 152 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
142 153
154 if (amd_cache_gart() < 0)
155 printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
156 "GART support disabled.\n");
157
143 return err; 158 return err;
144} 159}
145 160