x86, amd-nb: Complete the rename of AMD NB and related code
[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
eec1d4fa 15struct pci_device_id amd_nb_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};
eec1d4fa 21EXPORT_SYMBOL(amd_nb_ids);
a32073bf 22
eec1d4fa
HR
23struct amd_northbridge_info amd_northbridges;
24EXPORT_SYMBOL(amd_northbridges);
a32073bf 25
eec1d4fa 26static struct pci_dev *next_amd_northbridge(struct pci_dev *dev)
a32073bf
AK
27{
28 do {
29 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
30 if (!dev)
31 break;
eec1d4fa 32 } while (!pci_match_id(&amd_nb_ids[0], dev));
a32073bf
AK
33 return dev;
34}
35
eec1d4fa 36int cache_amd_northbridges(void)
a32073bf
AK
37{
38 int i;
39 struct pci_dev *dev;
3c6df2a9 40
eec1d4fa 41 if (amd_northbridges.num)
a32073bf
AK
42 return 0;
43
a32073bf 44 dev = NULL;
eec1d4fa
HR
45 while ((dev = next_amd_northbridge(dev)) != NULL)
46 amd_northbridges.num++;
900f9ac9
AH
47
48 /* some CPU families (e.g. family 0x11) do not support GART */
5c80cc78
AH
49 if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
50 boot_cpu_data.x86 == 0x15)
eec1d4fa 51 amd_northbridges.gart_supported = 1;
a32073bf 52
eec1d4fa 53 amd_northbridges.nb_misc = kmalloc((amd_northbridges.num + 1) *
900f9ac9 54 sizeof(void *), GFP_KERNEL);
eec1d4fa 55 if (!amd_northbridges.nb_misc)
a32073bf
AK
56 return -ENOMEM;
57
eec1d4fa
HR
58 if (!amd_northbridges.num) {
59 amd_northbridges.nb_misc[0] = NULL;
3c6df2a9
BC
60 return 0;
61 }
62
eec1d4fa
HR
63 if (amd_northbridges.gart_supported) {
64 flush_words = kmalloc(amd_northbridges.num * sizeof(u32),
900f9ac9
AH
65 GFP_KERNEL);
66 if (!flush_words) {
eec1d4fa 67 kfree(amd_northbridges.nb_misc);
900f9ac9
AH
68 return -ENOMEM;
69 }
a32073bf
AK
70 }
71
72 dev = NULL;
73 i = 0;
eec1d4fa
HR
74 while ((dev = next_amd_northbridge(dev)) != NULL) {
75 amd_northbridges.nb_misc[i] = dev;
76 if (amd_northbridges.gart_supported)
900f9ac9 77 pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
a32073bf 78 }
eec1d4fa 79 amd_northbridges.nb_misc[i] = NULL;
a32073bf
AK
80 return 0;
81}
eec1d4fa 82EXPORT_SYMBOL_GPL(cache_amd_northbridges);
a32073bf
AK
83
84/* Ignores subdevice/subvendor but as far as I can figure out
85 they're useless anyways */
eec1d4fa 86int __init early_is_amd_nb(u32 device)
a32073bf
AK
87{
88 struct pci_device_id *id;
89 u32 vendor = device & 0xffff;
90 device >>= 16;
eec1d4fa 91 for (id = amd_nb_ids; id->vendor; id++)
a32073bf
AK
92 if (vendor == id->vendor && device == id->device)
93 return 1;
94 return 0;
95}
96
eec1d4fa 97void amd_flush_garts(void)
a32073bf
AK
98{
99 int flushed, i;
100 unsigned long flags;
101 static DEFINE_SPINLOCK(gart_lock);
102
eec1d4fa 103 if (!amd_northbridges.gart_supported)
900f9ac9
AH
104 return;
105
a32073bf
AK
106 /* Avoid races between AGP and IOMMU. In theory it's not needed
107 but I'm not sure if the hardware won't lose flush requests
108 when another is pending. This whole thing is so expensive anyways
109 that it doesn't matter to serialize more. -AK */
110 spin_lock_irqsave(&gart_lock, flags);
111 flushed = 0;
eec1d4fa
HR
112 for (i = 0; i < amd_northbridges.num; i++) {
113 pci_write_config_dword(amd_northbridges.nb_misc[i], 0x9c,
a32073bf
AK
114 flush_words[i]|1);
115 flushed++;
116 }
eec1d4fa 117 for (i = 0; i < amd_northbridges.num; i++) {
a32073bf
AK
118 u32 w;
119 /* Make sure the hardware actually executed the flush*/
120 for (;;) {
eec1d4fa 121 pci_read_config_dword(amd_northbridges.nb_misc[i],
a32073bf
AK
122 0x9c, &w);
123 if (!(w & 1))
124 break;
125 cpu_relax();
126 }
127 }
128 spin_unlock_irqrestore(&gart_lock, flags);
129 if (!flushed)
130 printk("nothing to flush?\n");
131}
eec1d4fa 132EXPORT_SYMBOL_GPL(amd_flush_garts);
a32073bf 133
eec1d4fa 134static __init int init_amd_nbs(void)
0e152cd7
BP
135{
136 int err = 0;
137
eec1d4fa 138 err = cache_amd_northbridges();
0e152cd7
BP
139
140 if (err < 0)
eec1d4fa 141 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
0e152cd7
BP
142
143 return err;
144}
145
146/* This has to go after the PCI subsystem */
eec1d4fa 147fs_initcall(init_amd_nbs);