Release 4.7 arch/x86/kernel/amd_nb.c
/*
* Shared support code for AMD K8 northbridges and derivates.
* Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/amd_nb.h>
static u32 *flush_words;
const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{}
};
EXPORT_SYMBOL(amd_nb_misc_ids);
static const struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{}
};
const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
{ 0x00, 0x18, 0x20 },
{ 0xff, 0x00, 0x20 },
{ 0xfe, 0x00, 0x20 },
{ }
};
struct amd_northbridge_info amd_northbridges;
EXPORT_SYMBOL(amd_northbridges);
static struct pci_dev *next_northbridge(struct pci_dev *dev,
const struct pci_device_id *ids)
{
do {
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
if (!dev)
break;
} while (!pci_match_id(ids, dev));
return dev;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| andi kleen | andi kleen | 45 | 84.91% | 1 | 33.33% |
| hans rosenfeld | hans rosenfeld | 7 | 13.21% | 1 | 33.33% |
| jan beulich | jan beulich | 1 | 1.89% | 1 | 33.33% |
| Total | 53 | 100.00% | 3 | 100.00% |
int amd_cache_northbridges(void)
{
u16 i = 0;
struct amd_northbridge *nb;
struct pci_dev *misc, *link;
if (amd_nb_num())
return 0;
misc = NULL;
while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL)
i++;
if (!i)
return -ENODEV;
nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL);
if (!nb)
return -ENOMEM;
amd_northbridges.nb = nb;
amd_northbridges.num = i;
link = misc = NULL;
for (i = 0; i != amd_nb_num(); i++) {
node_to_amd_nb(i)->misc = misc =
next_northbridge(misc, amd_nb_misc_ids);
node_to_amd_nb(i)->link = link =
next_northbridge(link, amd_nb_link_ids);
}
if (amd_gart_present())
amd_northbridges.flags |= AMD_NB_GART;
/*
* Check for L3 cache presence.
*/
if (!cpuid_edx(0x80000006))
return 0;
/*
* Some CPU families support L3 Cache Index Disable. There are some
* limitations because of E382 and E388 on family 0x10.
*/
if (boot_cpu_data.x86 == 0x10 &&
boot_cpu_data.x86_model >= 0x8 &&
(boot_cpu_data.x86_model > 0x9 ||
boot_cpu_data.x86_mask >= 0x1))
amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
if (boot_cpu_data.x86 == 0x15)
amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
/* L3 cache partitioning is supported on family 0x15 */
if (boot_cpu_data.x86 == 0x15)
amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| hans rosenfeld | hans rosenfeld | 146 | 59.84% | 6 | 46.15% |
| andi kleen | andi kleen | 71 | 29.10% | 1 | 7.69% |
| aravind gopalakrishnan | aravind gopalakrishnan | 14 | 5.74% | 2 | 15.38% |
| andreas herrmann | andreas herrmann | 7 | 2.87% | 1 | 7.69% |
| borislav petkov | borislav petkov | 4 | 1.64% | 2 | 15.38% |
| ben collins | ben collins | 2 | 0.82% | 1 | 7.69% |
| Total | 244 | 100.00% | 13 | 100.00% |
EXPORT_SYMBOL_GPL(amd_cache_northbridges);
/*
* Ignores subdevice/subvendor but as far as I can figure out
* they're useless anyways
*/
bool __init early_is_amd_nb(u32 device)
{
const struct pci_device_id *id;
u32 vendor = device & 0xffff;
device >>= 16;
for (id = amd_nb_misc_ids; id->vendor; id++)
if (vendor == id->vendor && device == id->device)
return true;
return false;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| andi kleen | andi kleen | 53 | 89.83% | 1 | 20.00% |
| borislav petkov | borislav petkov | 3 | 5.08% | 1 | 20.00% |
| hans rosenfeld | hans rosenfeld | 2 | 3.39% | 2 | 40.00% |
| jan beulich | jan beulich | 1 | 1.69% | 1 | 20.00% |
| Total | 59 | 100.00% | 5 | 100.00% |
struct resource *amd_get_mmconfig_range(struct resource *res)
{
u32 address;
u64 base, msr;
unsigned segn_busn_bits;
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
return NULL;
/* assume all cpus from fam10h have mmconfig */
if (boot_cpu_data.x86 < 0x10)
return NULL;
address = MSR_FAM10H_MMIO_CONF_BASE;
rdmsrl(address, msr);
/* mmconfig is not enabled */
if (!(msr & FAM10H_MMIO_CONF_ENABLE))
return NULL;
base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
FAM10H_MMIO_CONF_BUSRANGE_MASK;
res->flags = IORESOURCE_MEM;
res->start = base;
res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
return res;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| bjorn helgaas | bjorn helgaas | 123 | 100.00% | 1 | 100.00% |
| Total | 123 | 100.00% | 1 | 100.00% |
int amd_get_subcaches(int cpu)
{
struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
unsigned int mask;
if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
return 0;
pci_read_config_dword(link, 0x1d4, &mask);
return (mask >> (4 * cpu_data(cpu).cpu_core_id)) & 0xf;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| hans rosenfeld | hans rosenfeld | 60 | 90.91% | 1 | 50.00% |
| borislav petkov | borislav petkov | 6 | 9.09% | 1 | 50.00% |
| Total | 66 | 100.00% | 2 | 100.00% |
int amd_set_subcaches(int cpu, unsigned long mask)
{
static unsigned int reset, ban;
struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
unsigned int reg;
int cuid;
if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
return -EINVAL;
/* if necessary, collect reset state of L3 partitioning and BAN mode */
if (reset == 0) {
pci_read_config_dword(nb->link, 0x1d4, &reset);
pci_read_config_dword(nb->misc, 0x1b8, &ban);
ban &= 0x180000;
}
/* deactivate BAN mode if any subcaches are to be disabled */
if (mask != 0xf) {
pci_read_config_dword(nb->misc, 0x1b8, ®);
pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
}
cuid = cpu_data(cpu).cpu_core_id;
mask <<= 4 * cuid;
mask |= (0xf ^ (1 << cuid)) << 26;
pci_write_config_dword(nb->link, 0x1d4, mask);
/* reset BAN mode if L3 partitioning returned to reset state */
pci_read_config_dword(nb->link, 0x1d4, ®);
if (reg == reset) {
pci_read_config_dword(nb->misc, 0x1b8, ®);
reg &= ~0x180000;
pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| hans rosenfeld | hans rosenfeld | 218 | 98.64% | 1 | 33.33% |
| dan carpenter | dan carpenter | 2 | 0.90% | 1 | 33.33% |
| borislav petkov | borislav petkov | 1 | 0.45% | 1 | 33.33% |
| Total | 221 | 100.00% | 3 | 100.00% |
static int amd_cache_gart(void)
{
u16 i;
if (!amd_nb_has_feature(AMD_NB_GART))
return 0;
flush_words = kmalloc(amd_nb_num() * sizeof(u32), GFP_KERNEL);
if (!flush_words) {
amd_northbridges.flags &= ~AMD_NB_GART;
return -ENOMEM;
}
for (i = 0; i != amd_nb_num(); i++)
pci_read_config_dword(node_to_amd_nb(i)->misc, 0x9c,
&flush_words[i]);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| hans rosenfeld | hans rosenfeld | 88 | 97.78% | 1 | 50.00% |
| borislav petkov | borislav petkov | 2 | 2.22% | 1 | 50.00% |
| Total | 90 | 100.00% | 2 | 100.00% |
void amd_flush_garts(void)
{
int flushed, i;
unsigned long flags;
static DEFINE_SPINLOCK(gart_lock);
if (!amd_nb_has_feature(AMD_NB_GART))
return;
/* Avoid races between AGP and IOMMU. In theory it's not needed
but I'm not sure if the hardware won't lose flush requests
when another is pending. This whole thing is so expensive anyways
that it doesn't matter to serialize more. -AK */
spin_lock_irqsave(&gart_lock, flags);
flushed = 0;
for (i = 0; i < amd_nb_num(); i++) {
pci_write_config_dword(node_to_amd_nb(i)->misc, 0x9c,
flush_words[i] | 1);
flushed++;
}
for (i = 0; i < amd_nb_num(); i++) {
u32 w;
/* Make sure the hardware actually executed the flush*/
for (;;) {
pci_read_config_dword(node_to_amd_nb(i)->misc,
0x9c, &w);
if (!(w & 1))
break;
cpu_relax();
}
}
spin_unlock_irqrestore(&gart_lock, flags);
if (!flushed)
pr_notice("nothing to flush?\n");
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| andi kleen | andi kleen | 130 | 83.87% | 1 | 20.00% |
| hans rosenfeld | hans rosenfeld | 19 | 12.26% | 2 | 40.00% |
| andreas herrmann | andreas herrmann | 5 | 3.23% | 1 | 20.00% |
| joe perches | joe perches | 1 | 0.65% | 1 | 20.00% |
| Total | 155 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL_GPL(amd_flush_garts);
static __init int init_amd_nbs(void)
{
int err = 0;
err = amd_cache_northbridges();
if (err < 0)
pr_notice("Cannot enumerate AMD northbridges\n");
if (amd_cache_gart() < 0)
pr_notice("Cannot initialize GART flush words, GART support disabled\n");
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| borislav petkov | borislav petkov | 29 | 64.44% | 1 | 25.00% |
| hans rosenfeld | hans rosenfeld | 12 | 26.67% | 2 | 50.00% |
| joe perches | joe perches | 4 | 8.89% | 1 | 25.00% |
| Total | 45 | 100.00% | 4 | 100.00% |
/* This has to go after the PCI subsystem */
fs_initcall(init_amd_nbs);
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
| hans rosenfeld | hans rosenfeld | 578 | 44.67% | 6 | 19.35% |
| andi kleen | andi kleen | 362 | 27.98% | 1 | 3.23% |
| bjorn helgaas | bjorn helgaas | 123 | 9.51% | 1 | 3.23% |
| aravind gopalakrishnan | aravind gopalakrishnan | 86 | 6.65% | 5 | 16.13% |
| borislav petkov | borislav petkov | 62 | 4.79% | 7 | 22.58% |
| jan beulich | jan beulich | 39 | 3.01% | 3 | 9.68% |
| andreas herrmann | andreas herrmann | 21 | 1.62% | 3 | 9.68% |
| joe perches | joe perches | 12 | 0.93% | 1 | 3.23% |
| joerg roedel | joerg roedel | 5 | 0.39% | 1 | 3.23% |
| ben collins | ben collins | 2 | 0.15% | 1 | 3.23% |
| tejun heo | tejun heo | 2 | 0.15% | 1 | 3.23% |
| dan carpenter | dan carpenter | 2 | 0.15% | 1 | 3.23% |
| Total | 1294 | 100.00% | 31 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.