x86: tsc: Prevent delayed init if initial tsc calibration failed
[GitHub/mt8127/android_kernel_alcatel_ttab.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
eec1d4fa
HR
23struct amd_northbridge_info amd_northbridges;
24EXPORT_SYMBOL(amd_northbridges);
a32073bf 25
9653a5c7
HR
26static struct pci_dev *next_northbridge(struct pci_dev *dev,
27 struct pci_device_id *ids)
a32073bf
AK
28{
29 do {
30 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
31 if (!dev)
32 break;
9653a5c7 33 } while (!pci_match_id(ids, dev));
a32073bf
AK
34 return dev;
35}
36
9653a5c7 37int amd_cache_northbridges(void)
a32073bf 38{
9653a5c7
HR
39 int i = 0;
40 struct amd_northbridge *nb;
41 struct pci_dev *misc;
3c6df2a9 42
9653a5c7 43 if (amd_nb_num())
a32073bf
AK
44 return 0;
45
9653a5c7
HR
46 misc = NULL;
47 while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
48 i++;
900f9ac9 49
9653a5c7
HR
50 if (i == 0)
51 return 0;
a32073bf 52
9653a5c7
HR
53 nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
54 if (!nb)
a32073bf
AK
55 return -ENOMEM;
56
9653a5c7
HR
57 amd_northbridges.nb = nb;
58 amd_northbridges.num = i;
3c6df2a9 59
9653a5c7
HR
60 misc = NULL;
61 for (i = 0; i != amd_nb_num(); i++) {
62 node_to_amd_nb(i)->misc = misc =
63 next_northbridge(misc, amd_nb_misc_ids);
64 }
65
66 /* some CPU families (e.g. family 0x11) do not support GART */
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;
a32073bf 70
f658bcfb
HR
71 /*
72 * Some CPU families support L3 Cache Index Disable. There are some
73 * limitations because of E382 and E388 on family 0x10.
74 */
75 if (boot_cpu_data.x86 == 0x10 &&
76 boot_cpu_data.x86_model >= 0x8 &&
77 (boot_cpu_data.x86_model > 0x9 ||
78 boot_cpu_data.x86_mask >= 0x1))
79 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
80
a32073bf
AK
81 return 0;
82}
9653a5c7 83EXPORT_SYMBOL_GPL(amd_cache_northbridges);
a32073bf
AK
84
85/* Ignores subdevice/subvendor but as far as I can figure out
86 they're useless anyways */
eec1d4fa 87int __init early_is_amd_nb(u32 device)
a32073bf
AK
88{
89 struct pci_device_id *id;
90 u32 vendor = device & 0xffff;
91 device >>= 16;
9653a5c7 92 for (id = amd_nb_misc_ids; id->vendor; id++)
a32073bf
AK
93 if (vendor == id->vendor && device == id->device)
94 return 1;
95 return 0;
96}
97
9653a5c7
HR
98int amd_cache_gart(void)
99{
100 int i;
101
102 if (!amd_nb_has_feature(AMD_NB_GART))
103 return 0;
104
105 flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
106 if (!flush_words) {
107 amd_northbridges.flags &= ~AMD_NB_GART;
108 return -ENOMEM;
109 }
110
111 for (i = 0; i != amd_nb_num(); i++)
112 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
113 &flush_words[i]);
114
115 return 0;
116}
117
eec1d4fa 118void amd_flush_garts(void)
a32073bf
AK
119{
120 int flushed, i;
121 unsigned long flags;
122 static DEFINE_SPINLOCK(gart_lock);
123
9653a5c7 124 if (!amd_nb_has_feature(AMD_NB_GART))
900f9ac9
AH
125 return;
126
a32073bf
AK
127 /* Avoid races between AGP and IOMMU. In theory it's not needed
128 but I'm not sure if the hardware won't lose flush requests
129 when another is pending. This whole thing is so expensive anyways
130 that it doesn't matter to serialize more. -AK */
131 spin_lock_irqsave(&gart_lock, flags);
132 flushed = 0;
9653a5c7
HR
133 for (i = 0; i < amd_nb_num(); i++) {
134 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
135 flush_words[i] | 1);
a32073bf
AK
136 flushed++;
137 }
9653a5c7 138 for (i = 0; i < amd_nb_num(); i++) {
a32073bf
AK
139 u32 w;
140 /* Make sure the hardware actually executed the flush*/
141 for (;;) {
9653a5c7 142 pci_read_config_dword(node_to_amd_nb(i)->misc,
a32073bf
AK
143 0x9c, &w);
144 if (!(w & 1))
145 break;
146 cpu_relax();
147 }
148 }
149 spin_unlock_irqrestore(&gart_lock, flags);
150 if (!flushed)
151 printk("nothing to flush?\n");
152}
eec1d4fa 153EXPORT_SYMBOL_GPL(amd_flush_garts);
a32073bf 154
eec1d4fa 155static __init int init_amd_nbs(void)
0e152cd7
BP
156{
157 int err = 0;
158
9653a5c7 159 err = amd_cache_northbridges();
0e152cd7
BP
160
161 if (err < 0)
eec1d4fa 162 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
0e152cd7 163
9653a5c7
HR
164 if (amd_cache_gart() < 0)
165 printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
166 "GART support disabled.\n");
167
0e152cd7
BP
168 return err;
169}
170
171/* This has to go after the PCI subsystem */
eec1d4fa 172fs_initcall(init_amd_nbs);