blob: a4f394c8e0558b77d8f12c47f75839418965abef [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
Hans Rosenfeldb453de02011-01-24 16:05:41 +010088 if (boot_cpu_data.x86 == 0x15)
89 amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
90
Andi Kleena32073b2006-06-26 13:56:40 +020091 return 0;
92}
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +020093EXPORT_SYMBOL_GPL(amd_cache_northbridges);
Andi Kleena32073b2006-06-26 13:56:40 +020094
95/* Ignores subdevice/subvendor but as far as I can figure out
96 they're useless anyways */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +020097int __init early_is_amd_nb(u32 device)
Andi Kleena32073b2006-06-26 13:56:40 +020098{
99 struct pci_device_id *id;
100 u32 vendor = device & 0xffff;
101 device >>= 16;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200102 for (id = amd_nb_misc_ids; id->vendor; id++)
Andi Kleena32073b2006-06-26 13:56:40 +0200103 if (vendor == id->vendor && device == id->device)
104 return 1;
105 return 0;
106}
107
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200108int amd_cache_gart(void)
109{
110 int i;
111
112 if (!amd_nb_has_feature(AMD_NB_GART))
113 return 0;
114
115 flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
116 if (!flush_words) {
117 amd_northbridges.flags &= ~AMD_NB_GART;
118 return -ENOMEM;
119 }
120
121 for (i = 0; i != amd_nb_num(); i++)
122 pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
123 &flush_words[i]);
124
125 return 0;
126}
127
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200128void amd_flush_garts(void)
Andi Kleena32073b2006-06-26 13:56:40 +0200129{
130 int flushed, i;
131 unsigned long flags;
132 static DEFINE_SPINLOCK(gart_lock);
133
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200134 if (!amd_nb_has_feature(AMD_NB_GART))
Andreas Herrmann900f9ac2010-09-17 18:02:54 +0200135 return;
136
Andi Kleena32073b2006-06-26 13:56:40 +0200137 /* Avoid races between AGP and IOMMU. In theory it's not needed
138 but I'm not sure if the hardware won't lose flush requests
139 when another is pending. This whole thing is so expensive anyways
140 that it doesn't matter to serialize more. -AK */
141 spin_lock_irqsave(&gart_lock, flags);
142 flushed = 0;
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200143 for (i = 0; i < amd_nb_num(); i++) {
144 pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
145 flush_words[i] | 1);
Andi Kleena32073b2006-06-26 13:56:40 +0200146 flushed++;
147 }
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200148 for (i = 0; i < amd_nb_num(); i++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200149 u32 w;
150 /* Make sure the hardware actually executed the flush*/
151 for (;;) {
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200152 pci_read_config_dword(node_to_amd_nb(i)->misc,
Andi Kleena32073b2006-06-26 13:56:40 +0200153 0x9c, &w);
154 if (!(w & 1))
155 break;
156 cpu_relax();
157 }
158 }
159 spin_unlock_irqrestore(&gart_lock, flags);
160 if (!flushed)
161 printk("nothing to flush?\n");
162}
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200163EXPORT_SYMBOL_GPL(amd_flush_garts);
Andi Kleena32073b2006-06-26 13:56:40 +0200164
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200165static __init int init_amd_nbs(void)
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100166{
167 int err = 0;
168
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200169 err = amd_cache_northbridges();
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100170
171 if (err < 0)
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200172 printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100173
Hans Rosenfeld9653a5c2010-10-29 17:14:31 +0200174 if (amd_cache_gart() < 0)
175 printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
176 "GART support disabled.\n");
177
Borislav Petkov0e152cd2010-03-12 15:43:03 +0100178 return err;
179}
180
181/* This has to go after the PCI subsystem */
Hans Rosenfeldeec1d4f2010-10-29 17:14:30 +0200182fs_initcall(init_amd_nbs);