Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * Shared support code for AMD K8 northbridges and derivates.
  3 * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
  4 */
  5#include <linux/types.h>
  6#include <linux/slab.h>
  7#include <linux/init.h>
  8#include <linux/errno.h>
  9#include <linux/module.h>
 10#include <linux/spinlock.h>
 11#include <asm/amd_nb.h>
 12
 13static u32 *flush_words;
 14
 15const struct pci_device_id amd_nb_misc_ids[] = {
 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) },
 18	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
 19	{}
 20};
 21EXPORT_SYMBOL(amd_nb_misc_ids);
 22
 23static struct pci_device_id amd_nb_link_ids[] = {
 24	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
 25	{}
 26};
 27
 28const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
 29	{ 0x00, 0x18, 0x20 },
 30	{ 0xff, 0x00, 0x20 },
 31	{ 0xfe, 0x00, 0x20 },
 32	{ }
 33};
 34
 35struct amd_northbridge_info amd_northbridges;
 36EXPORT_SYMBOL(amd_northbridges);
 37
 38static struct pci_dev *next_northbridge(struct pci_dev *dev,
 39					const struct pci_device_id *ids)
 40{
 41	do {
 42		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
 43		if (!dev)
 44			break;
 45	} while (!pci_match_id(ids, dev));
 46	return dev;
 47}
 48
 49int amd_cache_northbridges(void)
 50{
 51	u16 i = 0;
 52	struct amd_northbridge *nb;
 53	struct pci_dev *misc, *link;
 54
 55	if (amd_nb_num())
 56		return 0;
 57
 58	misc = NULL;
 59	while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
 60		i++;
 61
 62	if (i == 0)
 63		return 0;
 64
 65	nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
 66	if (!nb)
 67		return -ENOMEM;
 68
 69	amd_northbridges.nb = nb;
 70	amd_northbridges.num = i;
 71
 72	link = misc = NULL;
 73	for (i = 0; i != amd_nb_num(); i++) {
 74		node_to_amd_nb(i)->misc = misc =
 75			next_northbridge(misc, amd_nb_misc_ids);
 76		node_to_amd_nb(i)->link = link =
 77			next_northbridge(link, amd_nb_link_ids);
 78        }
 79
 80	/* some CPU families (e.g. family 0x11) do not support GART */
 81	if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
 82	    boot_cpu_data.x86 == 0x15)
 83		amd_northbridges.flags |= AMD_NB_GART;
 84
 85	/*
 86	 * Some CPU families support L3 Cache Index Disable. There are some
 87	 * limitations because of E382 and E388 on family 0x10.
 88	 */
 89	if (boot_cpu_data.x86 == 0x10 &&
 90	    boot_cpu_data.x86_model >= 0x8 &&
 91	    (boot_cpu_data.x86_model > 0x9 ||
 92	     boot_cpu_data.x86_mask >= 0x1))
 93		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 94
 95	if (boot_cpu_data.x86 == 0x15)
 96		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 97
 98	/* L3 cache partitioning is supported on family 0x15 */
 99	if (boot_cpu_data.x86 == 0x15)
100		amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
101
102	return 0;
103}
104EXPORT_SYMBOL_GPL(amd_cache_northbridges);
105
106/*
107 * Ignores subdevice/subvendor but as far as I can figure out
108 * they're useless anyways
109 */
110bool __init early_is_amd_nb(u32 device)
111{
112	const struct pci_device_id *id;
113	u32 vendor = device & 0xffff;
114
115	device >>= 16;
116	for (id = amd_nb_misc_ids; id->vendor; id++)
117		if (vendor == id->vendor && device == id->device)
118			return true;
119	return false;
120}
121
122int amd_get_subcaches(int cpu)
123{
124	struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
125	unsigned int mask;
126	int cuid = 0;
127
128	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
129		return 0;
130
131	pci_read_config_dword(link, 0x1d4, &mask);
132
133#ifdef CONFIG_SMP
134	cuid = cpu_data(cpu).compute_unit_id;
135#endif
136	return (mask >> (4 * cuid)) & 0xf;
137}
138
139int amd_set_subcaches(int cpu, int mask)
140{
141	static unsigned int reset, ban;
142	struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
143	unsigned int reg;
144	int cuid = 0;
145
146	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
147		return -EINVAL;
148
149	/* if necessary, collect reset state of L3 partitioning and BAN mode */
150	if (reset == 0) {
151		pci_read_config_dword(nb->link, 0x1d4, &reset);
152		pci_read_config_dword(nb->misc, 0x1b8, &ban);
153		ban &= 0x180000;
154	}
155
156	/* deactivate BAN mode if any subcaches are to be disabled */
157	if (mask != 0xf) {
158		pci_read_config_dword(nb->misc, 0x1b8, &reg);
159		pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
160	}
161
162#ifdef CONFIG_SMP
163	cuid = cpu_data(cpu).compute_unit_id;
164#endif
165	mask <<= 4 * cuid;
166	mask |= (0xf ^ (1 << cuid)) << 26;
167
168	pci_write_config_dword(nb->link, 0x1d4, mask);
169
170	/* reset BAN mode if L3 partitioning returned to reset state */
171	pci_read_config_dword(nb->link, 0x1d4, &reg);
172	if (reg == reset) {
173		pci_read_config_dword(nb->misc, 0x1b8, &reg);
174		reg &= ~0x180000;
175		pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
176	}
177
178	return 0;
179}
180
181static int amd_cache_gart(void)
182{
183	u16 i;
184
185       if (!amd_nb_has_feature(AMD_NB_GART))
186               return 0;
187
188       flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
189       if (!flush_words) {
190               amd_northbridges.flags &= ~AMD_NB_GART;
191               return -ENOMEM;
192       }
193
194       for (i = 0; i != amd_nb_num(); i++)
195               pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
196                                     &flush_words[i]);
197
198       return 0;
199}
200
201void amd_flush_garts(void)
202{
203	int flushed, i;
204	unsigned long flags;
205	static DEFINE_SPINLOCK(gart_lock);
206
207	if (!amd_nb_has_feature(AMD_NB_GART))
208		return;
209
210	/* Avoid races between AGP and IOMMU. In theory it's not needed
211	   but I'm not sure if the hardware won't lose flush requests
212	   when another is pending. This whole thing is so expensive anyways
213	   that it doesn't matter to serialize more. -AK */
214	spin_lock_irqsave(&gart_lock, flags);
215	flushed = 0;
216	for (i = 0; i < amd_nb_num(); i++) {
217		pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
218				       flush_words[i] | 1);
219		flushed++;
220	}
221	for (i = 0; i < amd_nb_num(); i++) {
222		u32 w;
223		/* Make sure the hardware actually executed the flush*/
224		for (;;) {
225			pci_read_config_dword(node_to_amd_nb(i)->misc,
226					      0x9c, &w);
227			if (!(w & 1))
228				break;
229			cpu_relax();
230		}
231	}
232	spin_unlock_irqrestore(&gart_lock, flags);
233	if (!flushed)
234		printk("nothing to flush?\n");
235}
236EXPORT_SYMBOL_GPL(amd_flush_garts);
237
238static __init int init_amd_nbs(void)
239{
240	int err = 0;
241
242	err = amd_cache_northbridges();
243
244	if (err < 0)
245		printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
246
247	if (amd_cache_gart() < 0)
248		printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
249		       "GART support disabled.\n");
250
251	return err;
252}
253
254/* This has to go after the PCI subsystem */
255fs_initcall(init_amd_nbs);
v3.1
  1/*
  2 * Shared support code for AMD K8 northbridges and derivates.
  3 * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
  4 */
  5#include <linux/types.h>
  6#include <linux/slab.h>
  7#include <linux/init.h>
  8#include <linux/errno.h>
  9#include <linux/module.h>
 10#include <linux/spinlock.h>
 11#include <asm/amd_nb.h>
 12
 13static u32 *flush_words;
 14
 15const struct pci_device_id amd_nb_misc_ids[] = {
 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) },
 18	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
 19	{}
 20};
 21EXPORT_SYMBOL(amd_nb_misc_ids);
 22
 23static struct pci_device_id amd_nb_link_ids[] = {
 24	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
 25	{}
 26};
 27
 28const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
 29	{ 0x00, 0x18, 0x20 },
 30	{ 0xff, 0x00, 0x20 },
 31	{ 0xfe, 0x00, 0x20 },
 32	{ }
 33};
 34
 35struct amd_northbridge_info amd_northbridges;
 36EXPORT_SYMBOL(amd_northbridges);
 37
 38static struct pci_dev *next_northbridge(struct pci_dev *dev,
 39					const struct pci_device_id *ids)
 40{
 41	do {
 42		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
 43		if (!dev)
 44			break;
 45	} while (!pci_match_id(ids, dev));
 46	return dev;
 47}
 48
 49int amd_cache_northbridges(void)
 50{
 51	u16 i = 0;
 52	struct amd_northbridge *nb;
 53	struct pci_dev *misc, *link;
 54
 55	if (amd_nb_num())
 56		return 0;
 57
 58	misc = NULL;
 59	while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
 60		i++;
 61
 62	if (i == 0)
 63		return 0;
 64
 65	nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
 66	if (!nb)
 67		return -ENOMEM;
 68
 69	amd_northbridges.nb = nb;
 70	amd_northbridges.num = i;
 71
 72	link = misc = NULL;
 73	for (i = 0; i != amd_nb_num(); i++) {
 74		node_to_amd_nb(i)->misc = misc =
 75			next_northbridge(misc, amd_nb_misc_ids);
 76		node_to_amd_nb(i)->link = link =
 77			next_northbridge(link, amd_nb_link_ids);
 78        }
 79
 80	/* some CPU families (e.g. family 0x11) do not support GART */
 81	if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
 82	    boot_cpu_data.x86 == 0x15)
 83		amd_northbridges.flags |= AMD_NB_GART;
 84
 85	/*
 86	 * Some CPU families support L3 Cache Index Disable. There are some
 87	 * limitations because of E382 and E388 on family 0x10.
 88	 */
 89	if (boot_cpu_data.x86 == 0x10 &&
 90	    boot_cpu_data.x86_model >= 0x8 &&
 91	    (boot_cpu_data.x86_model > 0x9 ||
 92	     boot_cpu_data.x86_mask >= 0x1))
 93		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 94
 95	if (boot_cpu_data.x86 == 0x15)
 96		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 97
 98	/* L3 cache partitioning is supported on family 0x15 */
 99	if (boot_cpu_data.x86 == 0x15)
100		amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
101
102	return 0;
103}
104EXPORT_SYMBOL_GPL(amd_cache_northbridges);
105
106/*
107 * Ignores subdevice/subvendor but as far as I can figure out
108 * they're useless anyways
109 */
110bool __init early_is_amd_nb(u32 device)
111{
112	const struct pci_device_id *id;
113	u32 vendor = device & 0xffff;
114
115	device >>= 16;
116	for (id = amd_nb_misc_ids; id->vendor; id++)
117		if (vendor == id->vendor && device == id->device)
118			return true;
119	return false;
120}
121
122int amd_get_subcaches(int cpu)
123{
124	struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
125	unsigned int mask;
126	int cuid = 0;
127
128	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
129		return 0;
130
131	pci_read_config_dword(link, 0x1d4, &mask);
132
133#ifdef CONFIG_SMP
134	cuid = cpu_data(cpu).compute_unit_id;
135#endif
136	return (mask >> (4 * cuid)) & 0xf;
137}
138
139int amd_set_subcaches(int cpu, int mask)
140{
141	static unsigned int reset, ban;
142	struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
143	unsigned int reg;
144	int cuid = 0;
145
146	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
147		return -EINVAL;
148
149	/* if necessary, collect reset state of L3 partitioning and BAN mode */
150	if (reset == 0) {
151		pci_read_config_dword(nb->link, 0x1d4, &reset);
152		pci_read_config_dword(nb->misc, 0x1b8, &ban);
153		ban &= 0x180000;
154	}
155
156	/* deactivate BAN mode if any subcaches are to be disabled */
157	if (mask != 0xf) {
158		pci_read_config_dword(nb->misc, 0x1b8, &reg);
159		pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
160	}
161
162#ifdef CONFIG_SMP
163	cuid = cpu_data(cpu).compute_unit_id;
164#endif
165	mask <<= 4 * cuid;
166	mask |= (0xf ^ (1 << cuid)) << 26;
167
168	pci_write_config_dword(nb->link, 0x1d4, mask);
169
170	/* reset BAN mode if L3 partitioning returned to reset state */
171	pci_read_config_dword(nb->link, 0x1d4, &reg);
172	if (reg == reset) {
173		pci_read_config_dword(nb->misc, 0x1b8, &reg);
174		reg &= ~0x180000;
175		pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
176	}
177
178	return 0;
179}
180
181static int amd_cache_gart(void)
182{
183	u16 i;
184
185       if (!amd_nb_has_feature(AMD_NB_GART))
186               return 0;
187
188       flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
189       if (!flush_words) {
190               amd_northbridges.flags &= ~AMD_NB_GART;
191               return -ENOMEM;
192       }
193
194       for (i = 0; i != amd_nb_num(); i++)
195               pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
196                                     &flush_words[i]);
197
198       return 0;
199}
200
201void amd_flush_garts(void)
202{
203	int flushed, i;
204	unsigned long flags;
205	static DEFINE_SPINLOCK(gart_lock);
206
207	if (!amd_nb_has_feature(AMD_NB_GART))
208		return;
209
210	/* Avoid races between AGP and IOMMU. In theory it's not needed
211	   but I'm not sure if the hardware won't lose flush requests
212	   when another is pending. This whole thing is so expensive anyways
213	   that it doesn't matter to serialize more. -AK */
214	spin_lock_irqsave(&gart_lock, flags);
215	flushed = 0;
216	for (i = 0; i < amd_nb_num(); i++) {
217		pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
218				       flush_words[i] | 1);
219		flushed++;
220	}
221	for (i = 0; i < amd_nb_num(); i++) {
222		u32 w;
223		/* Make sure the hardware actually executed the flush*/
224		for (;;) {
225			pci_read_config_dword(node_to_amd_nb(i)->misc,
226					      0x9c, &w);
227			if (!(w & 1))
228				break;
229			cpu_relax();
230		}
231	}
232	spin_unlock_irqrestore(&gart_lock, flags);
233	if (!flushed)
234		printk("nothing to flush?\n");
235}
236EXPORT_SYMBOL_GPL(amd_flush_garts);
237
238static __init int init_amd_nbs(void)
239{
240	int err = 0;
241
242	err = amd_cache_northbridges();
243
244	if (err < 0)
245		printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
246
247	if (amd_cache_gart() < 0)
248		printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
249		       "GART support disabled.\n");
250
251	return err;
252}
253
254/* This has to go after the PCI subsystem */
255fs_initcall(init_amd_nbs);