cregit-Linux how code gets into the kernel

Release 4.7 arch/x86/kernel/amd_nb.c

Directory: arch/x86/kernel
/*
 * 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

PersonTokensPropCommitsCommitProp
andi kleenandi kleen4584.91%133.33%
hans rosenfeldhans rosenfeld713.21%133.33%
jan beulichjan beulich11.89%133.33%
Total53100.00%3100.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

PersonTokensPropCommitsCommitProp
hans rosenfeldhans rosenfeld14659.84%646.15%
andi kleenandi kleen7129.10%17.69%
aravind gopalakrishnanaravind gopalakrishnan145.74%215.38%
andreas herrmannandreas herrmann72.87%17.69%
borislav petkovborislav petkov41.64%215.38%
ben collinsben collins20.82%17.69%
Total244100.00%13100.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

PersonTokensPropCommitsCommitProp
andi kleenandi kleen5389.83%120.00%
borislav petkovborislav petkov35.08%120.00%
hans rosenfeldhans rosenfeld23.39%240.00%
jan beulichjan beulich11.69%120.00%
Total59100.00%5100.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

PersonTokensPropCommitsCommitProp
bjorn helgaasbjorn helgaas123100.00%1100.00%
Total123100.00%1100.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

PersonTokensPropCommitsCommitProp
hans rosenfeldhans rosenfeld6090.91%150.00%
borislav petkovborislav petkov69.09%150.00%
Total66100.00%2100.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, &reg); 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, &reg); if (reg == reset) { pci_read_config_dword(nb->misc, 0x1b8, &reg); reg &= ~0x180000; pci_write_config_dword(nb->misc, 0x1b8, reg | ban); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans rosenfeldhans rosenfeld21898.64%133.33%
dan carpenterdan carpenter20.90%133.33%
borislav petkovborislav petkov10.45%133.33%
Total221100.00%3100.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

PersonTokensPropCommitsCommitProp
hans rosenfeldhans rosenfeld8897.78%150.00%
borislav petkovborislav petkov22.22%150.00%
Total90100.00%2100.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

PersonTokensPropCommitsCommitProp
andi kleenandi kleen13083.87%120.00%
hans rosenfeldhans rosenfeld1912.26%240.00%
andreas herrmannandreas herrmann53.23%120.00%
joe perchesjoe perches10.65%120.00%
Total155100.00%5100.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

PersonTokensPropCommitsCommitProp
borislav petkovborislav petkov2964.44%125.00%
hans rosenfeldhans rosenfeld1226.67%250.00%
joe perchesjoe perches48.89%125.00%
Total45100.00%4100.00%

/* This has to go after the PCI subsystem */ fs_initcall(init_amd_nbs);

Overall Contributors

PersonTokensPropCommitsCommitProp
hans rosenfeldhans rosenfeld57844.67%619.35%
andi kleenandi kleen36227.98%13.23%
bjorn helgaasbjorn helgaas1239.51%13.23%
aravind gopalakrishnanaravind gopalakrishnan866.65%516.13%
borislav petkovborislav petkov624.79%722.58%
jan beulichjan beulich393.01%39.68%
andreas herrmannandreas herrmann211.62%39.68%
joe perchesjoe perches120.93%13.23%
joerg roedeljoerg roedel50.39%13.23%
ben collinsben collins20.15%13.23%
tejun heotejun heo20.15%13.23%
dan carpenterdan carpenter20.15%13.23%
Total1294100.00%31100.00%
Directory: arch/x86/kernel
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}