blob: 0a99f7198bc373a8a2b45da3518234823786a590 [file] [log] [blame]
Andi Kleena32073b2006-06-26 13:56:40 +02001/*
2 * Shared support code for AMD K8 northbridges and derivates.
3 * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
4 */
Andi Kleena32073b2006-06-26 13:56:40 +02005#include <linux/types.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09006#include <linux/slab.h>
Andi Kleena32073b2006-06-26 13:56:40 +02007#include <linux/init.h>
8#include <linux/errno.h>
9#include <linux/module.h>
10#include <linux/spinlock.h>
Andreas Herrmann23ac4ae2010-09-17 18:03:43 +020011#include <asm/amd_nb.h>
Andi Kleena32073b2006-06-26 13:56:40 +020012
Andi Kleena32073b2006-06-26 13:56:40 +020013static u32 *flush_words;
14
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020015struct pci_device_id amd_nb_misc_ids[] = {
Joerg Roedelcf169702008-09-02 13:13:40 +020016 { 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) },
Andreas Herrmann5c80cc72010-09-30 14:43:16 +020018 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
Andi Kleena32073b2006-06-26 13:56:40 +020019 {}
20};
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020021EXPORT_SYMBOL(amd_nb_misc_ids);
Andi Kleena32073b2006-06-26 13:56:40 +020022
Jan Beulich24d9b702011-01-10 16:20:23 +000023const 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
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +020030struct amd_northbridge_info amd_northbridges;
31EXPORT_SYMBOL(amd_northbridges);
Andi Kleena32073b2006-06-26 13:56:40 +020032
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020033static struct pci_dev *next_northbridge(struct pci_dev *dev,
34 struct pci_device_id *ids)
Andi Kleena32073b2006-06-26 13:56:40 +020035{
36 do {
37 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
38 if (!dev)
39 break;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020040 } while (!pci_match_id(ids, dev));
Andi Kleena32073b2006-06-26 13:56:40 +020041 return dev;
42}
43
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020044int amd_cache_northbridges(void)
Andi Kleena32073b2006-06-26 13:56:40 +020045{
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020046 int i = 0;
47 struct amd_northbridge *nb;
48 struct pci_dev *misc;
Ben Collins3c6df2a2007-05-23 13:57:43 -070049
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020050 if (amd_nb_num())
Andi Kleena32073b2006-06-26 13:56:40 +020051 return 0;
52
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020053 misc = NULL;
54 while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
55 i++;
56
57 if (i == 0)
58 return 0;
59
60 nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
61 if (!nb)
62 return -ENOMEM;
63
64 amd_northbridges.nb = nb;
65 amd_northbridges.num = i;
66
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 }
Andi Kleena32073b2006-06-26 13:56:40 +020072
Andreas Herrmann900f9ac2010-09-17 18:02:54 +020073 /* some CPU families (e.g. family 0x11) do not support GART */
Andreas Herrmann5c80cc72010-09-30 14:43:16 +020074 if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
75 boot_cpu_data.x86 == 0x15)
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020076 amd_northbridges.flags |= AMD_NB_GART;
Andreas Herrmann900f9ac2010-09-17 18:02:54 +020077
Hans Rosenfeldf658bcf2010-10-29 17:14:32 +020078 /*
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
Andi Kleena32073b2006-06-26 13:56:40 +020088 return 0;
89}
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020090EXPORT_SYMBOL_GPL(amd_cache_northbridges);
Andi Kleena32073b2006-06-26 13:56:40 +020091
92/* Ignores subdevice/subvendor but as far as I can figure out
93 they're useless anyways */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +020094int __init early_is_amd_nb(u32 device)
Andi Kleena32073b2006-06-26 13:56:40 +020095{
96 struct pci_device_id *id;
97 u32 vendor = device & 0xffff;
98 device >>= 16;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020099 for (id = amd_nb_misc_ids; id->vendor; id++)
Andi Kleena32073b2006-06-26 13:56:40 +0200100 if (vendor == id->vendor && device == id->device)
101 return 1;
102 return 0;
103}
104
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200105int 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
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200125void amd_flush_garts(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200126{
127 int flushed, i;
128 unsigned long flags;
129 static DEFINE_SPINLOCK(gart_lock);
130
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200131 if (!amd_nb_has_feature(AMD_NB_GART))
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200132 return;
133
Andi Kleena32073b2006-06-26 13:56:40 +0200134 /* Avoid races between AGP and IOMMU. In theory it's not needed
135 but I'm not sure if the hardware won't lose flush requests
136 when another is pending. This whole thing is so expensive anyways
137 that it doesn't matter to serialize more. -AK */
138 spin_lock_irqsave(&gart_lock, flags);
139 flushed = 0;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200140 for (i = 0; i < amd_nb_num(); i++) {
141 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
142 flush_words[i] | 1);
Andi Kleena32073b2006-06-26 13:56:40 +0200143 flushed++;
144 }
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200145 for (i = 0; i < amd_nb_num(); i++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200146 u32 w;
147 /* Make sure the hardware actually executed the flush*/
148 for (;;) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200149 pci_read_config_dword(node_to_amd_nb(i)->misc,
Andi Kleena32073b2006-06-26 13:56:40 +0200150 0x9c, &w);
151 if (!(w & 1))
152 break;
153 cpu_relax();
154 }
155 }
156 spin_unlock_irqrestore(&gart_lock, flags);
157 if (!flushed)
158 printk("nothing to flush?\n");
159}
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200160EXPORT_SYMBOL_GPL(amd_flush_garts);
Andi Kleena32073b2006-06-26 13:56:40 +0200161
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200162static __init int init_amd_nbs(void)
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100163{
164 int err = 0;
165
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200166 err = amd_cache_northbridges();
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100167
168 if (err < 0)
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200169 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100170
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200171 if (amd_cache_gart() < 0)
172 printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
173 "GART support disabled.\n");
174
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100175 return err;
176}
177
178/* This has to go after the PCI subsystem */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200179fs_initcall(init_amd_nbs);