mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci: x86: add pci=check_enable_amd_mmconf and dmi check x86: work around io allocation overlap of HT links acpi: get boot_cpu_id as early for k8_scan_nodes x86_64: don't need set default res if only have one root bus x86: double check the multi root bus with fam10h mmconf x86: multi pci root bus with different io resource range, on 64-bit x86: use bus conf in NB conf fun1 to get bus range on, on 64-bit x86: get mp_bus_to_node early x86 pci: remove checking type for mmconfig probe x86: remove unneeded check in mmconf reject driver core: try parent numa_node at first before using default x86: seperate mmconf for fam10h out from setup_64.c x86: if acpi=off, force setting the mmconf for fam10h x86_64: check MSR to get MMCONFIG for AMD Family 10h x86_64: check and enable MMCONFIG for AMD Family 10h x86_64: set cfg_size for AMD Family 10h in case MMCONFIG x86: mmconf enable mcfg early x86: clear pci_mmcfg_virt when mmcfg get rejected x86: validate against acpi motherboard resources Fixed up fairly trivial conflicts in arch/x86/pci/{init.c,pci.h} due to OLPC support manually.
This commit is contained in:
commit
5f78e4d339
|
@ -103,4 +103,6 @@ ifeq ($(CONFIG_X86_64),y)
|
|||
obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o
|
||||
obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o
|
||||
obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o
|
||||
|
||||
obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o
|
||||
endif
|
||||
|
|
|
@ -771,6 +771,32 @@ static void __init acpi_register_lapic_address(unsigned long address)
|
|||
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
|
||||
}
|
||||
|
||||
static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (!cpu_has_apic)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Note that the LAPIC address is obtained from the MADT (32-bit value)
|
||||
* and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
|
||||
*/
|
||||
|
||||
count =
|
||||
acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
|
||||
acpi_parse_lapic_addr_ovr, 0);
|
||||
if (count < 0) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Error parsing LAPIC address override entry\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
acpi_register_lapic_address(acpi_lapic_addr);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int __init acpi_parse_madt_lapic_entries(void)
|
||||
{
|
||||
int count;
|
||||
|
@ -901,6 +927,33 @@ static inline int acpi_parse_madt_ioapic_entries(void)
|
|||
}
|
||||
#endif /* !CONFIG_X86_IO_APIC */
|
||||
|
||||
static void __init early_acpi_process_madt(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
int error;
|
||||
|
||||
if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
|
||||
|
||||
/*
|
||||
* Parse MADT LAPIC entries
|
||||
*/
|
||||
error = early_acpi_parse_madt_lapic_addr_ovr();
|
||||
if (!error) {
|
||||
acpi_lapic = 1;
|
||||
smp_found_config = 1;
|
||||
}
|
||||
if (error == -EINVAL) {
|
||||
/*
|
||||
* Dell Precision Workstation 410, 610 come here.
|
||||
*/
|
||||
printk(KERN_ERR PREFIX
|
||||
"Invalid BIOS MADT, disabling ACPI\n");
|
||||
disable_acpi();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init acpi_process_madt(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
|
@ -1233,6 +1286,23 @@ int __init acpi_boot_table_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init early_acpi_boot_init(void)
|
||||
{
|
||||
/*
|
||||
* If acpi_disabled, bail out
|
||||
* One exception: acpi=ht continues far enough to enumerate LAPICs
|
||||
*/
|
||||
if (acpi_disabled && !acpi_ht)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Process the Multiple APIC Description Table (MADT), if present
|
||||
*/
|
||||
early_acpi_process_madt();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init acpi_boot_init(void)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* AMD Family 10h mmconfig enablement
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <linux/sort.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/acpi.h>
|
||||
|
||||
#include "../pci/pci.h"
|
||||
|
||||
struct pci_hostbridge_probe {
|
||||
u32 bus;
|
||||
u32 slot;
|
||||
u32 vendor;
|
||||
u32 device;
|
||||
};
|
||||
|
||||
static u64 __cpuinitdata fam10h_pci_mmconf_base;
|
||||
static int __cpuinitdata fam10h_pci_mmconf_base_status;
|
||||
|
||||
static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = {
|
||||
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
|
||||
{ 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
|
||||
};
|
||||
|
||||
struct range {
|
||||
u64 start;
|
||||
u64 end;
|
||||
};
|
||||
|
||||
static int __cpuinit cmp_range(const void *x1, const void *x2)
|
||||
{
|
||||
const struct range *r1 = x1;
|
||||
const struct range *r2 = x2;
|
||||
int start1, start2;
|
||||
|
||||
start1 = r1->start >> 32;
|
||||
start2 = r2->start >> 32;
|
||||
|
||||
return start1 - start2;
|
||||
}
|
||||
|
||||
/*[47:0] */
|
||||
/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
|
||||
#define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
|
||||
#define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
|
||||
static void __cpuinit get_fam10h_pci_mmconf_base(void)
|
||||
{
|
||||
int i;
|
||||
unsigned bus;
|
||||
unsigned slot;
|
||||
int found;
|
||||
|
||||
u64 val;
|
||||
u32 address;
|
||||
u64 tom2;
|
||||
u64 base = FAM10H_PCI_MMCONF_BASE;
|
||||
|
||||
int hi_mmio_num;
|
||||
struct range range[8];
|
||||
|
||||
/* only try to get setting from BSP */
|
||||
/* -1 or 1 */
|
||||
if (fam10h_pci_mmconf_base_status)
|
||||
return;
|
||||
|
||||
if (!early_pci_allowed())
|
||||
goto fail;
|
||||
|
||||
found = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
|
||||
u32 id;
|
||||
u16 device;
|
||||
u16 vendor;
|
||||
|
||||
bus = pci_probes[i].bus;
|
||||
slot = pci_probes[i].slot;
|
||||
id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
|
||||
|
||||
vendor = id & 0xffff;
|
||||
device = (id>>16) & 0xffff;
|
||||
if (pci_probes[i].vendor == vendor &&
|
||||
pci_probes[i].device == device) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto fail;
|
||||
|
||||
/* SYS_CFG */
|
||||
address = MSR_K8_SYSCFG;
|
||||
rdmsrl(address, val);
|
||||
|
||||
/* TOP_MEM2 is not enabled? */
|
||||
if (!(val & (1<<21))) {
|
||||
tom2 = 0;
|
||||
} else {
|
||||
/* TOP_MEM2 */
|
||||
address = MSR_K8_TOP_MEM2;
|
||||
rdmsrl(address, val);
|
||||
tom2 = val & (0xffffULL<<32);
|
||||
}
|
||||
|
||||
if (base <= tom2)
|
||||
base = tom2 + (1ULL<<32);
|
||||
|
||||
/*
|
||||
* need to check if the range is in the high mmio range that is
|
||||
* above 4G
|
||||
*/
|
||||
hi_mmio_num = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
u32 reg;
|
||||
u64 start;
|
||||
u64 end;
|
||||
reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
|
||||
if (!(reg & 3))
|
||||
continue;
|
||||
|
||||
start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
|
||||
reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
|
||||
end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
|
||||
|
||||
if (!end)
|
||||
continue;
|
||||
|
||||
range[hi_mmio_num].start = start;
|
||||
range[hi_mmio_num].end = end;
|
||||
hi_mmio_num++;
|
||||
}
|
||||
|
||||
if (!hi_mmio_num)
|
||||
goto out;
|
||||
|
||||
/* sort the range */
|
||||
sort(range, hi_mmio_num, sizeof(struct range), cmp_range, NULL);
|
||||
|
||||
if (range[hi_mmio_num - 1].end < base)
|
||||
goto out;
|
||||
if (range[0].start > base)
|
||||
goto out;
|
||||
|
||||
/* need to find one window */
|
||||
base = range[0].start - (1ULL << 32);
|
||||
if ((base > tom2) && BASE_VALID(base))
|
||||
goto out;
|
||||
base = range[hi_mmio_num - 1].end + (1ULL << 32);
|
||||
if ((base > tom2) && BASE_VALID(base))
|
||||
goto out;
|
||||
/* need to find window between ranges */
|
||||
if (hi_mmio_num > 1)
|
||||
for (i = 0; i < hi_mmio_num - 1; i++) {
|
||||
if (range[i + 1].start > (range[i].end + (1ULL << 32))) {
|
||||
base = range[i].end + (1ULL << 32);
|
||||
if ((base > tom2) && BASE_VALID(base))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
fam10h_pci_mmconf_base_status = -1;
|
||||
return;
|
||||
out:
|
||||
fam10h_pci_mmconf_base = base;
|
||||
fam10h_pci_mmconf_base_status = 1;
|
||||
}
|
||||
|
||||
void __cpuinit fam10h_check_enable_mmcfg(void)
|
||||
{
|
||||
u64 val;
|
||||
u32 address;
|
||||
|
||||
if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
|
||||
return;
|
||||
|
||||
address = MSR_FAM10H_MMIO_CONF_BASE;
|
||||
rdmsrl(address, val);
|
||||
|
||||
/* try to make sure that AP's setting is identical to BSP setting */
|
||||
if (val & FAM10H_MMIO_CONF_ENABLE) {
|
||||
unsigned busnbits;
|
||||
busnbits = (val >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
|
||||
FAM10H_MMIO_CONF_BUSRANGE_MASK;
|
||||
|
||||
/* only trust the one handle 256 buses, if acpi=off */
|
||||
if (!acpi_pci_disabled || busnbits >= 8) {
|
||||
u64 base;
|
||||
base = val & (0xffffULL << 32);
|
||||
if (fam10h_pci_mmconf_base_status <= 0) {
|
||||
fam10h_pci_mmconf_base = base;
|
||||
fam10h_pci_mmconf_base_status = 1;
|
||||
return;
|
||||
} else if (fam10h_pci_mmconf_base == base)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if it is not enabled, try to enable it and assume only one segment
|
||||
* with 256 buses
|
||||
*/
|
||||
get_fam10h_pci_mmconf_base();
|
||||
if (fam10h_pci_mmconf_base_status <= 0)
|
||||
return;
|
||||
|
||||
printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n");
|
||||
val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
|
||||
(FAM10H_MMIO_CONF_BUSRANGE_MASK<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT));
|
||||
val |= fam10h_pci_mmconf_base | (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
|
||||
FAM10H_MMIO_CONF_ENABLE;
|
||||
wrmsrl(address, val);
|
||||
}
|
||||
|
||||
static int __devinit set_check_enable_amd_mmconf(const struct dmi_system_id *d)
|
||||
{
|
||||
pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dmi_system_id __devinitdata mmconf_dmi_table[] = {
|
||||
{
|
||||
.callback = set_check_enable_amd_mmconf,
|
||||
.ident = "Sun Microsystems Machine",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Sun Microsystems"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
void __init check_enable_amd_mmconf_dmi(void)
|
||||
{
|
||||
dmi_check_system(mmconf_dmi_table);
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/crash_dump.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/kallsyms.h>
|
||||
|
@ -40,6 +41,7 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/init_ohci1394_dma.h>
|
||||
#include <linux/kvm_para.h>
|
||||
|
@ -288,6 +290,18 @@ static void __init parse_setup_data(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MMCONFIG
|
||||
extern void __cpuinit fam10h_check_enable_mmcfg(void);
|
||||
extern void __init check_enable_amd_mmconf_dmi(void);
|
||||
#else
|
||||
void __cpuinit fam10h_check_enable_mmcfg(void)
|
||||
{
|
||||
}
|
||||
void __init check_enable_amd_mmconf_dmi(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* setup_arch - architecture-specific boot-time initializations
|
||||
*
|
||||
|
@ -515,6 +529,9 @@ void __init setup_arch(char **cmdline_p)
|
|||
conswitchp = &dummy_con;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* do this before identify_cpu for boot cpu */
|
||||
check_enable_amd_mmconf_dmi();
|
||||
}
|
||||
|
||||
static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
|
||||
|
@ -767,6 +784,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
|||
/* MFENCE stops RDTSC speculation */
|
||||
set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
|
||||
|
||||
if (c->x86 == 0x10)
|
||||
fam10h_check_enable_mmcfg();
|
||||
|
||||
if (amd_apic_timer_broken())
|
||||
disable_apic_timer = 1;
|
||||
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
#include <linux/nodemask.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <asm/proto.h>
|
||||
#include <asm/e820.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/apic.h>
|
||||
|
||||
static __init int find_northbridge(void)
|
||||
{
|
||||
|
@ -44,6 +47,30 @@ static __init int find_northbridge(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static __init void early_get_boot_cpu_id(void)
|
||||
{
|
||||
/*
|
||||
* need to get boot_cpu_id so can use that to create apicid_to_node
|
||||
* in k8_scan_nodes()
|
||||
*/
|
||||
/*
|
||||
* Find possible boot-time SMP configuration:
|
||||
*/
|
||||
early_find_smp_config();
|
||||
#ifdef CONFIG_ACPI
|
||||
/*
|
||||
* Read APIC information from ACPI tables.
|
||||
*/
|
||||
early_acpi_boot_init();
|
||||
#endif
|
||||
/*
|
||||
* get boot-time SMP configuration:
|
||||
*/
|
||||
if (smp_found_config)
|
||||
early_get_smp_config();
|
||||
early_init_lapic_mapping();
|
||||
}
|
||||
|
||||
int __init k8_scan_nodes(unsigned long start, unsigned long end)
|
||||
{
|
||||
unsigned long prevbase;
|
||||
|
@ -56,6 +83,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
|
|||
unsigned cores;
|
||||
unsigned bits;
|
||||
int j;
|
||||
unsigned apicid_base;
|
||||
|
||||
if (!early_pci_allowed())
|
||||
return -1;
|
||||
|
@ -174,11 +202,19 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
|
|||
/* use the coreid bits from early_identify_cpu */
|
||||
bits = boot_cpu_data.x86_coreid_bits;
|
||||
cores = (1<<bits);
|
||||
apicid_base = 0;
|
||||
/* need to get boot_cpu_id early for system with apicid lifting */
|
||||
early_get_boot_cpu_id();
|
||||
if (boot_cpu_physical_apicid > 0) {
|
||||
printk(KERN_INFO "BSP APIC ID: %02x\n",
|
||||
boot_cpu_physical_apicid);
|
||||
apicid_base = boot_cpu_physical_apicid;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (nodes[i].start != nodes[i].end) {
|
||||
nodeid = nodeids[i];
|
||||
for (j = 0; j < cores; j++)
|
||||
for (j = apicid_base; j < cores + apicid_base; j++)
|
||||
apicid_to_node[(nodeid << bits) + j] = i;
|
||||
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
|
||||
}
|
||||
|
|
|
@ -11,5 +11,6 @@ pci-y += legacy.o irq.o
|
|||
|
||||
pci-$(CONFIG_X86_VISWS) := visws.o fixup.o
|
||||
pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o
|
||||
pci-$(CONFIG_NUMA) += mp_bus_to_node.o
|
||||
|
||||
obj-y += $(pci-y) common.o early.o
|
||||
|
|
|
@ -13,5 +13,5 @@ obj-y += legacy.o irq.o common.o early.o
|
|||
# mmconfig has a 64bit special
|
||||
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o
|
||||
|
||||
obj-$(CONFIG_NUMA) += k8-bus_64.o
|
||||
obj-y += k8-bus_64.o
|
||||
|
||||
|
|
|
@ -191,7 +191,10 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
|
|||
{
|
||||
struct pci_bus *bus;
|
||||
struct pci_sysdata *sd;
|
||||
int node;
|
||||
#ifdef CONFIG_ACPI_NUMA
|
||||
int pxm;
|
||||
#endif
|
||||
|
||||
dmi_check_system(acpi_pciprobe_dmi_table);
|
||||
|
||||
|
@ -201,6 +204,17 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
|
|||
return NULL;
|
||||
}
|
||||
|
||||
node = -1;
|
||||
#ifdef CONFIG_ACPI_NUMA
|
||||
pxm = acpi_get_pxm(device->handle);
|
||||
if (pxm >= 0)
|
||||
node = pxm_to_node(pxm);
|
||||
if (node != -1)
|
||||
set_mp_bus_to_node(busnum, node);
|
||||
else
|
||||
node = get_mp_bus_to_node(busnum);
|
||||
#endif
|
||||
|
||||
/* Allocate per-root-bus (not per bus) arch-specific data.
|
||||
* TODO: leak; this memory is never freed.
|
||||
* It's arguable whether it's worth the trouble to care.
|
||||
|
@ -212,13 +226,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
|
|||
}
|
||||
|
||||
sd->domain = domain;
|
||||
sd->node = -1;
|
||||
|
||||
pxm = acpi_get_pxm(device->handle);
|
||||
#ifdef CONFIG_ACPI_NUMA
|
||||
if (pxm >= 0)
|
||||
sd->node = pxm_to_node(pxm);
|
||||
#endif
|
||||
sd->node = node;
|
||||
/*
|
||||
* Maybe the desired pci bus has been already scanned. In such case
|
||||
* it is unnecessary to scan the pci bus with the given domain,busnum.
|
||||
|
@ -238,9 +246,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
|
|||
kfree(sd);
|
||||
|
||||
#ifdef CONFIG_ACPI_NUMA
|
||||
if (bus != NULL) {
|
||||
if (bus) {
|
||||
if (pxm >= 0) {
|
||||
printk("bus %d -> pxm %d -> node %d\n",
|
||||
printk(KERN_DEBUG "bus %02x -> pxm %d -> node %d\n",
|
||||
busnum, pxm, pxm_to_node(pxm));
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +256,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
|
|||
|
||||
if (bus && (pci_probe & PCI_USE__CRS))
|
||||
get_current_resources(device, busnum, domain, bus);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
||||
|
|
|
@ -342,9 +342,14 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
|
||||
sd->node = get_mp_bus_to_node(busnum);
|
||||
|
||||
return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
|
||||
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
|
||||
bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
|
||||
if (!bus)
|
||||
kfree(sd);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
||||
extern u8 pci_cache_line_size;
|
||||
|
@ -420,6 +425,10 @@ char * __devinit pcibios_setup(char *str)
|
|||
pci_probe &= ~PCI_PROBE_MMCONF;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(str, "check_enable_amd_mmconf")) {
|
||||
pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(str, "noacpi")) {
|
||||
acpi_noirq_set();
|
||||
|
@ -480,7 +489,7 @@ void pcibios_disable_device (struct pci_dev *dev)
|
|||
pcibios_disable_irq(dev);
|
||||
}
|
||||
|
||||
struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno)
|
||||
struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
|
||||
{
|
||||
struct pci_bus *bus = NULL;
|
||||
struct pci_sysdata *sd;
|
||||
|
@ -495,10 +504,15 @@ struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno)
|
|||
printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
|
||||
return NULL;
|
||||
}
|
||||
sd->node = -1;
|
||||
bus = pci_scan_bus(busno, &pci_root_ops, sd);
|
||||
sd->node = node;
|
||||
bus = pci_scan_bus(busno, ops, sd);
|
||||
if (!bus)
|
||||
kfree(sd);
|
||||
|
||||
return bus;
|
||||
}
|
||||
|
||||
struct pci_bus *pci_scan_bus_with_sysdata(int busno)
|
||||
{
|
||||
return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
|
||||
}
|
||||
|
|
|
@ -258,7 +258,8 @@ void __init pci_direct_init(int type)
|
|||
{
|
||||
if (type == 0)
|
||||
return;
|
||||
printk(KERN_INFO "PCI: Using configuration type %d\n", type);
|
||||
printk(KERN_INFO "PCI: Using configuration type %d for base access\n",
|
||||
type);
|
||||
if (type == 1)
|
||||
raw_pci_ops = &pci_direct_conf1;
|
||||
else
|
||||
|
@ -275,8 +276,10 @@ int __init pci_direct_probe(void)
|
|||
if (!region)
|
||||
goto type2;
|
||||
|
||||
if (pci_check_type1())
|
||||
if (pci_check_type1()) {
|
||||
raw_pci_ops = &pci_direct_conf1;
|
||||
return 1;
|
||||
}
|
||||
release_resource(region);
|
||||
|
||||
type2:
|
||||
|
@ -290,7 +293,6 @@ int __init pci_direct_probe(void)
|
|||
goto fail2;
|
||||
|
||||
if (pci_check_type2()) {
|
||||
printk(KERN_INFO "PCI: Using configuration type 2\n");
|
||||
raw_pci_ops = &pci_direct_conf2;
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -493,3 +493,20 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev)
|
|||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015,
|
||||
pci_siemens_interrupt_controller);
|
||||
|
||||
/*
|
||||
* Regular PCI devices have 256 bytes, but AMD Family 10h Opteron ext config
|
||||
* have 4096 bytes. Even if the device is capable, that doesn't mean we can
|
||||
* access it. Maybe we don't have a way to generate extended config space
|
||||
* accesses. So check it
|
||||
*/
|
||||
static void fam10h_pci_cfg_space_size(struct pci_dev *dev)
|
||||
{
|
||||
dev->cfg_size = pci_cfg_space_size_ext(dev, 0);
|
||||
}
|
||||
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, fam10h_pci_cfg_space_size);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size);
|
||||
|
|
|
@ -6,19 +6,17 @@
|
|||
in the right sequence from here. */
|
||||
static __init int pci_access_init(void)
|
||||
{
|
||||
int type __maybe_unused = 0;
|
||||
|
||||
#ifdef CONFIG_PCI_DIRECT
|
||||
int type = 0;
|
||||
|
||||
type = pci_direct_probe();
|
||||
#endif
|
||||
#ifdef CONFIG_PCI_MMCONFIG
|
||||
pci_mmcfg_init(type);
|
||||
#endif
|
||||
|
||||
pci_mmcfg_early_init();
|
||||
|
||||
#ifdef CONFIG_PCI_OLPC
|
||||
pci_olpc_init();
|
||||
#endif
|
||||
if (raw_pci_ops)
|
||||
return 0;
|
||||
#ifdef CONFIG_PCI_BIOS
|
||||
pci_pcbios_init();
|
||||
#endif
|
||||
|
@ -31,7 +29,7 @@ static __init int pci_access_init(void)
|
|||
#ifdef CONFIG_PCI_DIRECT
|
||||
pci_direct_init(type);
|
||||
#endif
|
||||
if (!raw_pci_ops)
|
||||
if (!raw_pci_ops && !raw_pci_ext_ops)
|
||||
printk(KERN_ERR
|
||||
"PCI: Fatal: No config space access function found\n");
|
||||
|
||||
|
|
|
@ -136,9 +136,11 @@ static void __init pirq_peer_trick(void)
|
|||
busmap[e->bus] = 1;
|
||||
}
|
||||
for(i = 1; i < 256; i++) {
|
||||
int node;
|
||||
if (!busmap[i] || pci_find_bus(0, i))
|
||||
continue;
|
||||
if (pci_scan_bus_with_sysdata(i))
|
||||
node = get_mp_bus_to_node(i);
|
||||
if (pci_scan_bus_on_node(i, &pci_root_ops, node))
|
||||
printk(KERN_INFO "PCI: Discovered primary peer "
|
||||
"bus %02x [IRQ]\n", i);
|
||||
}
|
||||
|
|
|
@ -1,83 +1,536 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/topology.h>
|
||||
|
||||
/*
|
||||
* This discovers the pcibus <-> node mapping on AMD K8.
|
||||
*
|
||||
* RED-PEN need to call this again on PCI hotplug
|
||||
* RED-PEN empty cpus get reported wrong
|
||||
* also get peer root bus resource for io,mmio
|
||||
*/
|
||||
|
||||
#define NODE_ID_REGISTER 0x60
|
||||
#define NODE_ID(dword) (dword & 0x07)
|
||||
#define LDT_BUS_NUMBER_REGISTER_0 0x94
|
||||
#define LDT_BUS_NUMBER_REGISTER_1 0xB4
|
||||
#define LDT_BUS_NUMBER_REGISTER_2 0xD4
|
||||
#define NR_LDT_BUS_NUMBER_REGISTERS 3
|
||||
#define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
|
||||
#define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
|
||||
#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
|
||||
|
||||
/*
|
||||
* sub bus (transparent) will use entres from 3 to store extra from root,
|
||||
* so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
|
||||
*/
|
||||
#define RES_NUM 16
|
||||
struct pci_root_info {
|
||||
char name[12];
|
||||
unsigned int res_num;
|
||||
struct resource res[RES_NUM];
|
||||
int bus_min;
|
||||
int bus_max;
|
||||
int node;
|
||||
int link;
|
||||
};
|
||||
|
||||
/* 4 at this time, it may become to 32 */
|
||||
#define PCI_ROOT_NR 4
|
||||
static int pci_root_num;
|
||||
static struct pci_root_info pci_root_info[PCI_ROOT_NR];
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
#define BUS_NR 256
|
||||
|
||||
static int mp_bus_to_node[BUS_NR];
|
||||
|
||||
void set_mp_bus_to_node(int busnum, int node)
|
||||
{
|
||||
if (busnum >= 0 && busnum < BUS_NR)
|
||||
mp_bus_to_node[busnum] = node;
|
||||
}
|
||||
|
||||
int get_mp_bus_to_node(int busnum)
|
||||
{
|
||||
int node = -1;
|
||||
|
||||
if (busnum < 0 || busnum > (BUS_NR - 1))
|
||||
return node;
|
||||
|
||||
node = mp_bus_to_node[busnum];
|
||||
|
||||
/*
|
||||
* let numa_node_id to decide it later in dma_alloc_pages
|
||||
* if there is no ram on that node
|
||||
*/
|
||||
if (node != -1 && !node_online(node))
|
||||
node = -1;
|
||||
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_pci_bus_resources_arch_default(struct pci_bus *b)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
struct pci_root_info *info;
|
||||
|
||||
/* if only one root bus, don't need to anything */
|
||||
if (pci_root_num < 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pci_root_num; i++) {
|
||||
if (pci_root_info[i].bus_min == b->number)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == pci_root_num)
|
||||
return;
|
||||
|
||||
info = &pci_root_info[i];
|
||||
for (j = 0; j < info->res_num; j++) {
|
||||
struct resource *res;
|
||||
struct resource *root;
|
||||
|
||||
res = &info->res[j];
|
||||
b->resource[j] = res;
|
||||
if (res->flags & IORESOURCE_IO)
|
||||
root = &ioport_resource;
|
||||
else
|
||||
root = &iomem_resource;
|
||||
insert_resource(root, res);
|
||||
}
|
||||
}
|
||||
|
||||
#define RANGE_NUM 16
|
||||
|
||||
struct res_range {
|
||||
size_t start;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
static void __init update_range(struct res_range *range, size_t start,
|
||||
size_t end)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < RANGE_NUM; j++) {
|
||||
if (!range[j].end)
|
||||
continue;
|
||||
|
||||
if (start <= range[j].start && end >= range[j].end) {
|
||||
range[j].start = 0;
|
||||
range[j].end = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) {
|
||||
range[j].start = end + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) {
|
||||
range[j].end = start - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start > range[j].start && end < range[j].end) {
|
||||
/* find the new spare */
|
||||
for (i = 0; i < RANGE_NUM; i++) {
|
||||
if (range[i].end == 0)
|
||||
break;
|
||||
}
|
||||
if (i < RANGE_NUM) {
|
||||
range[i].end = range[j].end;
|
||||
range[i].start = end + 1;
|
||||
} else {
|
||||
printk(KERN_ERR "run of slot in ranges\n");
|
||||
}
|
||||
range[j].end = start - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init update_res(struct pci_root_info *info, size_t start,
|
||||
size_t end, unsigned long flags, int merge)
|
||||
{
|
||||
int i;
|
||||
struct resource *res;
|
||||
|
||||
if (!merge)
|
||||
goto addit;
|
||||
|
||||
/* try to merge it with old one */
|
||||
for (i = 0; i < info->res_num; i++) {
|
||||
size_t final_start, final_end;
|
||||
size_t common_start, common_end;
|
||||
|
||||
res = &info->res[i];
|
||||
if (res->flags != flags)
|
||||
continue;
|
||||
|
||||
common_start = max((size_t)res->start, start);
|
||||
common_end = min((size_t)res->end, end);
|
||||
if (common_start > common_end + 1)
|
||||
continue;
|
||||
|
||||
final_start = min((size_t)res->start, start);
|
||||
final_end = max((size_t)res->end, end);
|
||||
|
||||
res->start = final_start;
|
||||
res->end = final_end;
|
||||
return;
|
||||
}
|
||||
|
||||
addit:
|
||||
|
||||
/* need to add that */
|
||||
if (info->res_num >= RES_NUM)
|
||||
return;
|
||||
|
||||
res = &info->res[info->res_num];
|
||||
res->name = info->name;
|
||||
res->flags = flags;
|
||||
res->start = start;
|
||||
res->end = end;
|
||||
res->child = NULL;
|
||||
info->res_num++;
|
||||
}
|
||||
|
||||
struct pci_hostbridge_probe {
|
||||
u32 bus;
|
||||
u32 slot;
|
||||
u32 vendor;
|
||||
u32 device;
|
||||
};
|
||||
|
||||
static struct pci_hostbridge_probe pci_probes[] __initdata = {
|
||||
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 },
|
||||
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
|
||||
{ 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
|
||||
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
|
||||
};
|
||||
|
||||
static u64 __initdata fam10h_mmconf_start;
|
||||
static u64 __initdata fam10h_mmconf_end;
|
||||
static void __init get_pci_mmcfg_amd_fam10h_range(void)
|
||||
{
|
||||
u32 address;
|
||||
u64 base, msr;
|
||||
unsigned segn_busn_bits;
|
||||
|
||||
/* assume all cpus from fam10h have mmconf */
|
||||
if (boot_cpu_data.x86 < 0x10)
|
||||
return;
|
||||
|
||||
address = MSR_FAM10H_MMIO_CONF_BASE;
|
||||
rdmsrl(address, msr);
|
||||
|
||||
/* mmconfig is not enable */
|
||||
if (!(msr & FAM10H_MMIO_CONF_ENABLE))
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
fam10h_mmconf_start = base;
|
||||
fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_mp_bus_to_cpumask()
|
||||
* early_fill_mp_bus_to_node()
|
||||
* called before pcibios_scan_root and pci_scan_bus
|
||||
* fills the mp_bus_to_cpumask array based according to the LDT Bus Number
|
||||
* Registers found in the K8 northbridge
|
||||
*/
|
||||
__init static int
|
||||
fill_mp_bus_to_cpumask(void)
|
||||
static int __init early_fill_mp_bus_info(void)
|
||||
{
|
||||
struct pci_dev *nb_dev = NULL;
|
||||
int i, j;
|
||||
u32 ldtbus, nid;
|
||||
static int lbnr[3] = {
|
||||
LDT_BUS_NUMBER_REGISTER_0,
|
||||
LDT_BUS_NUMBER_REGISTER_1,
|
||||
LDT_BUS_NUMBER_REGISTER_2
|
||||
};
|
||||
int i;
|
||||
int j;
|
||||
unsigned bus;
|
||||
unsigned slot;
|
||||
int found;
|
||||
int node;
|
||||
int link;
|
||||
int def_node;
|
||||
int def_link;
|
||||
struct pci_root_info *info;
|
||||
u32 reg;
|
||||
struct resource *res;
|
||||
size_t start;
|
||||
size_t end;
|
||||
struct res_range range[RANGE_NUM];
|
||||
u64 val;
|
||||
u32 address;
|
||||
|
||||
while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
|
||||
PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
|
||||
pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
|
||||
#ifdef CONFIG_NUMA
|
||||
for (i = 0; i < BUS_NR; i++)
|
||||
mp_bus_to_node[i] = -1;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
|
||||
pci_read_config_dword(nb_dev, lbnr[i], &ldtbus);
|
||||
/*
|
||||
* if there are no busses hanging off of the current
|
||||
* ldt link then both the secondary and subordinate
|
||||
* bus number fields are set to 0.
|
||||
*
|
||||
* RED-PEN
|
||||
* This is slightly broken because it assumes
|
||||
* HT node IDs == Linux node ids, which is not always
|
||||
* true. However it is probably mostly true.
|
||||
*/
|
||||
if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
|
||||
&& SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
|
||||
for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
|
||||
j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
|
||||
j++) {
|
||||
struct pci_bus *bus;
|
||||
struct pci_sysdata *sd;
|
||||
if (!early_pci_allowed())
|
||||
return -1;
|
||||
|
||||
long node = NODE_ID(nid);
|
||||
/* Algorithm a bit dumb, but
|
||||
it shouldn't matter here */
|
||||
bus = pci_find_bus(0, j);
|
||||
if (!bus)
|
||||
continue;
|
||||
if (!node_online(node))
|
||||
node = 0;
|
||||
found = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
|
||||
u32 id;
|
||||
u16 device;
|
||||
u16 vendor;
|
||||
|
||||
sd = bus->sysdata;
|
||||
sd->node = node;
|
||||
}
|
||||
bus = pci_probes[i].bus;
|
||||
slot = pci_probes[i].slot;
|
||||
id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
|
||||
|
||||
vendor = id & 0xffff;
|
||||
device = (id>>16) & 0xffff;
|
||||
if (pci_probes[i].vendor == vendor &&
|
||||
pci_probes[i].device == device) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return 0;
|
||||
|
||||
pci_root_num = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
int min_bus;
|
||||
int max_bus;
|
||||
reg = read_pci_config(bus, slot, 1, 0xe0 + (i << 2));
|
||||
|
||||
/* Check if that register is enabled for bus range */
|
||||
if ((reg & 7) != 3)
|
||||
continue;
|
||||
|
||||
min_bus = (reg >> 16) & 0xff;
|
||||
max_bus = (reg >> 24) & 0xff;
|
||||
node = (reg >> 4) & 0x07;
|
||||
#ifdef CONFIG_NUMA
|
||||
for (j = min_bus; j <= max_bus; j++)
|
||||
mp_bus_to_node[j] = (unsigned char) node;
|
||||
#endif
|
||||
link = (reg >> 8) & 0x03;
|
||||
|
||||
info = &pci_root_info[pci_root_num];
|
||||
info->bus_min = min_bus;
|
||||
info->bus_max = max_bus;
|
||||
info->node = node;
|
||||
info->link = link;
|
||||
sprintf(info->name, "PCI Bus #%02x", min_bus);
|
||||
pci_root_num++;
|
||||
}
|
||||
|
||||
/* get the default node and link for left over res */
|
||||
reg = read_pci_config(bus, slot, 0, 0x60);
|
||||
def_node = (reg >> 8) & 0x07;
|
||||
reg = read_pci_config(bus, slot, 0, 0x64);
|
||||
def_link = (reg >> 8) & 0x03;
|
||||
|
||||
memset(range, 0, sizeof(range));
|
||||
range[0].end = 0xffff;
|
||||
/* io port resource */
|
||||
for (i = 0; i < 4; i++) {
|
||||
reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3));
|
||||
if (!(reg & 3))
|
||||
continue;
|
||||
|
||||
start = reg & 0xfff000;
|
||||
reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3));
|
||||
node = reg & 0x07;
|
||||
link = (reg >> 4) & 0x03;
|
||||
end = (reg & 0xfff000) | 0xfff;
|
||||
|
||||
/* find the position */
|
||||
for (j = 0; j < pci_root_num; j++) {
|
||||
info = &pci_root_info[j];
|
||||
if (info->node == node && info->link == link)
|
||||
break;
|
||||
}
|
||||
if (j == pci_root_num)
|
||||
continue; /* not found */
|
||||
|
||||
info = &pci_root_info[j];
|
||||
printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
|
||||
node, link, (u64)start, (u64)end);
|
||||
|
||||
/* kernel only handle 16 bit only */
|
||||
if (end > 0xffff)
|
||||
end = 0xffff;
|
||||
update_res(info, start, end, IORESOURCE_IO, 1);
|
||||
update_range(range, start, end);
|
||||
}
|
||||
/* add left over io port range to def node/link, [0, 0xffff] */
|
||||
/* find the position */
|
||||
for (j = 0; j < pci_root_num; j++) {
|
||||
info = &pci_root_info[j];
|
||||
if (info->node == def_node && info->link == def_link)
|
||||
break;
|
||||
}
|
||||
if (j < pci_root_num) {
|
||||
info = &pci_root_info[j];
|
||||
for (i = 0; i < RANGE_NUM; i++) {
|
||||
if (!range[i].end)
|
||||
continue;
|
||||
|
||||
update_res(info, range[i].start, range[i].end,
|
||||
IORESOURCE_IO, 1);
|
||||
}
|
||||
}
|
||||
|
||||
memset(range, 0, sizeof(range));
|
||||
/* 0xfd00000000-0xffffffffff for HT */
|
||||
range[0].end = (0xfdULL<<32) - 1;
|
||||
|
||||
/* need to take out [0, TOM) for RAM*/
|
||||
address = MSR_K8_TOP_MEM1;
|
||||
rdmsrl(address, val);
|
||||
end = (val & 0xffffff8000000ULL);
|
||||
printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20);
|
||||
if (end < (1ULL<<32))
|
||||
update_range(range, 0, end - 1);
|
||||
|
||||
/* get mmconfig */
|
||||
get_pci_mmcfg_amd_fam10h_range();
|
||||
/* need to take out mmconf range */
|
||||
if (fam10h_mmconf_end) {
|
||||
printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end);
|
||||
update_range(range, fam10h_mmconf_start, fam10h_mmconf_end);
|
||||
}
|
||||
|
||||
/* mmio resource */
|
||||
for (i = 0; i < 8; i++) {
|
||||
reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
|
||||
if (!(reg & 3))
|
||||
continue;
|
||||
|
||||
start = reg & 0xffffff00; /* 39:16 on 31:8*/
|
||||
start <<= 8;
|
||||
reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
|
||||
node = reg & 0x07;
|
||||
link = (reg >> 4) & 0x03;
|
||||
end = (reg & 0xffffff00);
|
||||
end <<= 8;
|
||||
end |= 0xffff;
|
||||
|
||||
/* find the position */
|
||||
for (j = 0; j < pci_root_num; j++) {
|
||||
info = &pci_root_info[j];
|
||||
if (info->node == node && info->link == link)
|
||||
break;
|
||||
}
|
||||
if (j == pci_root_num)
|
||||
continue; /* not found */
|
||||
|
||||
info = &pci_root_info[j];
|
||||
|
||||
printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]",
|
||||
node, link, (u64)start, (u64)end);
|
||||
/*
|
||||
* some sick allocation would have range overlap with fam10h
|
||||
* mmconf range, so need to update start and end.
|
||||
*/
|
||||
if (fam10h_mmconf_end) {
|
||||
int changed = 0;
|
||||
u64 endx = 0;
|
||||
if (start >= fam10h_mmconf_start &&
|
||||
start <= fam10h_mmconf_end) {
|
||||
start = fam10h_mmconf_end + 1;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (end >= fam10h_mmconf_start &&
|
||||
end <= fam10h_mmconf_end) {
|
||||
end = fam10h_mmconf_start - 1;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (start < fam10h_mmconf_start &&
|
||||
end > fam10h_mmconf_end) {
|
||||
/* we got a hole */
|
||||
endx = fam10h_mmconf_start - 1;
|
||||
update_res(info, start, endx, IORESOURCE_MEM, 0);
|
||||
update_range(range, start, endx);
|
||||
printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx);
|
||||
start = fam10h_mmconf_end + 1;
|
||||
changed = 1;
|
||||
}
|
||||
if (changed) {
|
||||
if (start <= end) {
|
||||
printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end);
|
||||
} else {
|
||||
printk(KERN_CONT "%s\n", endx?"":" ==> none");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_res(info, start, end, IORESOURCE_MEM, 1);
|
||||
update_range(range, start, end);
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
/* need to take out [4G, TOM2) for RAM*/
|
||||
/* SYS_CFG */
|
||||
address = MSR_K8_SYSCFG;
|
||||
rdmsrl(address, val);
|
||||
/* TOP_MEM2 is enabled? */
|
||||
if (val & (1<<21)) {
|
||||
/* TOP_MEM2 */
|
||||
address = MSR_K8_TOP_MEM2;
|
||||
rdmsrl(address, val);
|
||||
end = (val & 0xffffff8000000ULL);
|
||||
printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20);
|
||||
update_range(range, 1ULL<<32, end - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* add left over mmio range to def node/link ?
|
||||
* that is tricky, just record range in from start_min to 4G
|
||||
*/
|
||||
for (j = 0; j < pci_root_num; j++) {
|
||||
info = &pci_root_info[j];
|
||||
if (info->node == def_node && info->link == def_link)
|
||||
break;
|
||||
}
|
||||
if (j < pci_root_num) {
|
||||
info = &pci_root_info[j];
|
||||
|
||||
for (i = 0; i < RANGE_NUM; i++) {
|
||||
if (!range[i].end)
|
||||
continue;
|
||||
|
||||
update_res(info, range[i].start, range[i].end,
|
||||
IORESOURCE_MEM, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
for (i = 0; i < BUS_NR; i++) {
|
||||
node = mp_bus_to_node[i];
|
||||
if (node >= 0)
|
||||
printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < pci_root_num; i++) {
|
||||
int res_num;
|
||||
int busnum;
|
||||
|
||||
info = &pci_root_info[i];
|
||||
res_num = info->res_num;
|
||||
busnum = info->bus_min;
|
||||
printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n",
|
||||
info->bus_min, info->bus_max, info->node, info->link);
|
||||
for (j = 0; j < res_num; j++) {
|
||||
res = &info->res[j];
|
||||
printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n",
|
||||
busnum, j,
|
||||
(res->flags & IORESOURCE_IO)?"io port":"mmio",
|
||||
res->start, res->end);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs_initcall(fill_mp_bus_to_cpumask);
|
||||
postcore_initcall(early_fill_mp_bus_info);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
static void __devinit pcibios_fixup_peer_bridges(void)
|
||||
{
|
||||
int n, devfn;
|
||||
long node;
|
||||
|
||||
if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
|
||||
return;
|
||||
|
@ -21,12 +22,13 @@ static void __devinit pcibios_fixup_peer_bridges(void)
|
|||
u32 l;
|
||||
if (pci_find_bus(0, n))
|
||||
continue;
|
||||
node = get_mp_bus_to_node(n);
|
||||
for (devfn = 0; devfn < 256; devfn += 8) {
|
||||
if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) &&
|
||||
l != 0x0000 && l != 0xffff) {
|
||||
DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
|
||||
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
|
||||
pci_scan_bus_with_sysdata(n);
|
||||
pci_scan_bus_on_node(n, &pci_root_ops, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ static int __initdata pci_mmcfg_resources_inserted;
|
|||
static const char __init *pci_mmcfg_e7520(void)
|
||||
{
|
||||
u32 win;
|
||||
pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
|
||||
raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
|
||||
|
||||
win = win & 0xf000;
|
||||
if(win == 0x0000 || win == 0xf000)
|
||||
|
@ -53,7 +53,7 @@ static const char __init *pci_mmcfg_intel_945(void)
|
|||
|
||||
pci_mmcfg_config_num = 1;
|
||||
|
||||
pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
|
||||
raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
|
||||
|
||||
/* Enable bit */
|
||||
if (!(pciexbar & 1))
|
||||
|
@ -100,33 +100,102 @@ static const char __init *pci_mmcfg_intel_945(void)
|
|||
return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
|
||||
}
|
||||
|
||||
static const char __init *pci_mmcfg_amd_fam10h(void)
|
||||
{
|
||||
u32 low, high, address;
|
||||
u64 base, msr;
|
||||
int i;
|
||||
unsigned segnbits = 0, busnbits;
|
||||
|
||||
if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
|
||||
return NULL;
|
||||
|
||||
address = MSR_FAM10H_MMIO_CONF_BASE;
|
||||
if (rdmsr_safe(address, &low, &high))
|
||||
return NULL;
|
||||
|
||||
msr = high;
|
||||
msr <<= 32;
|
||||
msr |= low;
|
||||
|
||||
/* mmconfig is not enable */
|
||||
if (!(msr & FAM10H_MMIO_CONF_ENABLE))
|
||||
return NULL;
|
||||
|
||||
base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
|
||||
|
||||
busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
|
||||
FAM10H_MMIO_CONF_BUSRANGE_MASK;
|
||||
|
||||
/*
|
||||
* only handle bus 0 ?
|
||||
* need to skip it
|
||||
*/
|
||||
if (!busnbits)
|
||||
return NULL;
|
||||
|
||||
if (busnbits > 8) {
|
||||
segnbits = busnbits - 8;
|
||||
busnbits = 8;
|
||||
}
|
||||
|
||||
pci_mmcfg_config_num = (1 << segnbits);
|
||||
pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) *
|
||||
pci_mmcfg_config_num, GFP_KERNEL);
|
||||
if (!pci_mmcfg_config)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < (1 << segnbits); i++) {
|
||||
pci_mmcfg_config[i].address = base + (1<<28) * i;
|
||||
pci_mmcfg_config[i].pci_segment = i;
|
||||
pci_mmcfg_config[i].start_bus_number = 0;
|
||||
pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
|
||||
}
|
||||
|
||||
return "AMD Family 10h NB";
|
||||
}
|
||||
|
||||
struct pci_mmcfg_hostbridge_probe {
|
||||
u32 bus;
|
||||
u32 devfn;
|
||||
u32 vendor;
|
||||
u32 device;
|
||||
const char *(*probe)(void);
|
||||
};
|
||||
|
||||
static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
|
||||
{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
|
||||
PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
|
||||
{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
|
||||
PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
|
||||
{ 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
|
||||
0x1200, pci_mmcfg_amd_fam10h },
|
||||
{ 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
|
||||
0x1200, pci_mmcfg_amd_fam10h },
|
||||
};
|
||||
|
||||
static int __init pci_mmcfg_check_hostbridge(void)
|
||||
{
|
||||
u32 l;
|
||||
u32 bus, devfn;
|
||||
u16 vendor, device;
|
||||
int i;
|
||||
const char *name;
|
||||
|
||||
pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
|
||||
vendor = l & 0xffff;
|
||||
device = (l >> 16) & 0xffff;
|
||||
if (!raw_pci_ops)
|
||||
return 0;
|
||||
|
||||
pci_mmcfg_config_num = 0;
|
||||
pci_mmcfg_config = NULL;
|
||||
name = NULL;
|
||||
|
||||
for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
|
||||
bus = pci_mmcfg_probes[i].bus;
|
||||
devfn = pci_mmcfg_probes[i].devfn;
|
||||
raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
|
||||
vendor = l & 0xffff;
|
||||
device = (l >> 16) & 0xffff;
|
||||
|
||||
if (pci_mmcfg_probes[i].vendor == vendor &&
|
||||
pci_mmcfg_probes[i].device == device)
|
||||
name = pci_mmcfg_probes[i].probe();
|
||||
|
@ -173,9 +242,78 @@ static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
|
|||
pci_mmcfg_resources_inserted = 1;
|
||||
}
|
||||
|
||||
static void __init pci_mmcfg_reject_broken(int type)
|
||||
static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
|
||||
void *data)
|
||||
{
|
||||
struct resource *mcfg_res = data;
|
||||
struct acpi_resource_address64 address;
|
||||
acpi_status status;
|
||||
|
||||
if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
|
||||
struct acpi_resource_fixed_memory32 *fixmem32 =
|
||||
&res->data.fixed_memory32;
|
||||
if (!fixmem32)
|
||||
return AE_OK;
|
||||
if ((mcfg_res->start >= fixmem32->address) &&
|
||||
(mcfg_res->end < (fixmem32->address +
|
||||
fixmem32->address_length))) {
|
||||
mcfg_res->flags = 1;
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
}
|
||||
if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
|
||||
(res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
|
||||
return AE_OK;
|
||||
|
||||
status = acpi_resource_to_address64(res, &address);
|
||||
if (ACPI_FAILURE(status) ||
|
||||
(address.address_length <= 0) ||
|
||||
(address.resource_type != ACPI_MEMORY_RANGE))
|
||||
return AE_OK;
|
||||
|
||||
if ((mcfg_res->start >= address.minimum) &&
|
||||
(mcfg_res->end < (address.minimum + address.address_length))) {
|
||||
mcfg_res->flags = 1;
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
|
||||
void *context, void **rv)
|
||||
{
|
||||
struct resource *mcfg_res = context;
|
||||
|
||||
acpi_walk_resources(handle, METHOD_NAME__CRS,
|
||||
check_mcfg_resource, context);
|
||||
|
||||
if (mcfg_res->flags)
|
||||
return AE_CTRL_TERMINATE;
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int __init is_acpi_reserved(unsigned long start, unsigned long end)
|
||||
{
|
||||
struct resource mcfg_res;
|
||||
|
||||
mcfg_res.start = start;
|
||||
mcfg_res.end = end;
|
||||
mcfg_res.flags = 0;
|
||||
|
||||
acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL);
|
||||
|
||||
if (!mcfg_res.flags)
|
||||
acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res,
|
||||
NULL);
|
||||
|
||||
return mcfg_res.flags;
|
||||
}
|
||||
|
||||
static void __init pci_mmcfg_reject_broken(int early)
|
||||
{
|
||||
typeof(pci_mmcfg_config[0]) *cfg;
|
||||
int i;
|
||||
|
||||
if ((pci_mmcfg_config_num == 0) ||
|
||||
(pci_mmcfg_config == NULL) ||
|
||||
|
@ -184,51 +322,80 @@ static void __init pci_mmcfg_reject_broken(int type)
|
|||
|
||||
cfg = &pci_mmcfg_config[0];
|
||||
|
||||
/*
|
||||
* Handle more broken MCFG tables on Asus etc.
|
||||
* They only contain a single entry for bus 0-0.
|
||||
*/
|
||||
if (pci_mmcfg_config_num == 1 &&
|
||||
cfg->pci_segment == 0 &&
|
||||
(cfg->start_bus_number | cfg->end_bus_number) == 0) {
|
||||
printk(KERN_ERR "PCI: start and end of bus number is 0. "
|
||||
"Rejected as broken MCFG.\n");
|
||||
goto reject;
|
||||
for (i = 0; i < pci_mmcfg_config_num; i++) {
|
||||
int valid = 0;
|
||||
u32 size = (cfg->end_bus_number + 1) << 20;
|
||||
cfg = &pci_mmcfg_config[i];
|
||||
printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
|
||||
"segment %hu buses %u - %u\n",
|
||||
i, (unsigned long)cfg->address, cfg->pci_segment,
|
||||
(unsigned int)cfg->start_bus_number,
|
||||
(unsigned int)cfg->end_bus_number);
|
||||
|
||||
if (!early &&
|
||||
is_acpi_reserved(cfg->address, cfg->address + size - 1)) {
|
||||
printk(KERN_NOTICE "PCI: MCFG area at %Lx reserved "
|
||||
"in ACPI motherboard resources\n",
|
||||
cfg->address);
|
||||
valid = 1;
|
||||
}
|
||||
|
||||
if (valid)
|
||||
continue;
|
||||
|
||||
if (!early)
|
||||
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
|
||||
" reserved in ACPI motherboard resources\n",
|
||||
cfg->address);
|
||||
/* Don't try to do this check unless configuration
|
||||
type 1 is available. how about type 2 ?*/
|
||||
if (raw_pci_ops && e820_all_mapped(cfg->address,
|
||||
cfg->address + size - 1,
|
||||
E820_RESERVED)) {
|
||||
printk(KERN_NOTICE
|
||||
"PCI: MCFG area at %Lx reserved in E820\n",
|
||||
cfg->address);
|
||||
valid = 1;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
goto reject;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only do this check when type 1 works. If it doesn't work
|
||||
* assume we run on a Mac and always use MCFG
|
||||
*/
|
||||
if (type == 1 && !e820_all_mapped(cfg->address,
|
||||
cfg->address + MMCONFIG_APER_MIN,
|
||||
E820_RESERVED)) {
|
||||
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
|
||||
" E820-reserved\n", cfg->address);
|
||||
goto reject;
|
||||
}
|
||||
return;
|
||||
|
||||
reject:
|
||||
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
|
||||
pci_mmcfg_arch_free();
|
||||
kfree(pci_mmcfg_config);
|
||||
pci_mmcfg_config = NULL;
|
||||
pci_mmcfg_config_num = 0;
|
||||
}
|
||||
|
||||
void __init pci_mmcfg_init(int type)
|
||||
{
|
||||
int known_bridge = 0;
|
||||
static int __initdata known_bridge;
|
||||
|
||||
void __init __pci_mmcfg_init(int early)
|
||||
{
|
||||
/* MMCONFIG disabled */
|
||||
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
|
||||
return;
|
||||
|
||||
if (type == 1 && pci_mmcfg_check_hostbridge())
|
||||
known_bridge = 1;
|
||||
/* MMCONFIG already enabled */
|
||||
if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
|
||||
return;
|
||||
|
||||
/* for late to exit */
|
||||
if (known_bridge)
|
||||
return;
|
||||
|
||||
if (early) {
|
||||
if (pci_mmcfg_check_hostbridge())
|
||||
known_bridge = 1;
|
||||
}
|
||||
|
||||
if (!known_bridge) {
|
||||
acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
|
||||
pci_mmcfg_reject_broken(type);
|
||||
pci_mmcfg_reject_broken(early);
|
||||
}
|
||||
|
||||
if ((pci_mmcfg_config_num == 0) ||
|
||||
|
@ -249,6 +416,16 @@ void __init pci_mmcfg_init(int type)
|
|||
}
|
||||
}
|
||||
|
||||
void __init pci_mmcfg_early_init(void)
|
||||
{
|
||||
__pci_mmcfg_init(1);
|
||||
}
|
||||
|
||||
void __init pci_mmcfg_late_init(void)
|
||||
{
|
||||
__pci_mmcfg_init(0);
|
||||
}
|
||||
|
||||
static int __init pci_mmcfg_late_insert_resources(void)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -136,3 +136,7 @@ int __init pci_mmcfg_arch_init(void)
|
|||
raw_pci_ext_ops = &pci_mmcfg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __init pci_mmcfg_arch_free(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
|
|||
int __init pci_mmcfg_arch_init(void)
|
||||
{
|
||||
int i;
|
||||
pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) *
|
||||
pci_mmcfg_virt = kzalloc(sizeof(*pci_mmcfg_virt) *
|
||||
pci_mmcfg_config_num, GFP_KERNEL);
|
||||
if (pci_mmcfg_virt == NULL) {
|
||||
printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
|
||||
|
@ -141,9 +141,29 @@ int __init pci_mmcfg_arch_init(void)
|
|||
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
|
||||
"segment %d\n",
|
||||
pci_mmcfg_config[i].pci_segment);
|
||||
pci_mmcfg_arch_free();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
raw_pci_ext_ops = &pci_mmcfg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __init pci_mmcfg_arch_free(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (pci_mmcfg_virt == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pci_mmcfg_config_num; ++i) {
|
||||
if (pci_mmcfg_virt[i].virt) {
|
||||
iounmap(pci_mmcfg_virt[i].virt);
|
||||
pci_mmcfg_virt[i].virt = NULL;
|
||||
pci_mmcfg_virt[i].cfg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(pci_mmcfg_virt);
|
||||
pci_mmcfg_virt = NULL;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/topology.h>
|
||||
|
||||
#define BUS_NR 256
|
||||
|
||||
static unsigned char mp_bus_to_node[BUS_NR];
|
||||
|
||||
void set_mp_bus_to_node(int busnum, int node)
|
||||
{
|
||||
if (busnum >= 0 && busnum < BUS_NR)
|
||||
mp_bus_to_node[busnum] = (unsigned char) node;
|
||||
}
|
||||
|
||||
int get_mp_bus_to_node(int busnum)
|
||||
{
|
||||
int node;
|
||||
|
||||
if (busnum < 0 || busnum > (BUS_NR - 1))
|
||||
return 0;
|
||||
node = mp_bus_to_node[busnum];
|
||||
return node;
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
#define PCI_ASSIGN_ALL_BUSSES 0x4000
|
||||
#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
|
||||
#define PCI_USE__CRS 0x10000
|
||||
#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
|
||||
|
||||
extern unsigned int pci_probe;
|
||||
extern unsigned long pirq_table_addr;
|
||||
|
@ -97,12 +98,12 @@ extern struct pci_raw_ops pci_direct_conf1;
|
|||
extern int pci_direct_probe(void);
|
||||
extern void pci_direct_init(int type);
|
||||
extern void pci_pcbios_init(void);
|
||||
extern void pci_mmcfg_init(int type);
|
||||
extern void pci_olpc_init(void);
|
||||
|
||||
/* pci-mmconfig.c */
|
||||
|
||||
extern int __init pci_mmcfg_arch_init(void);
|
||||
extern void __init pci_mmcfg_arch_free(void);
|
||||
|
||||
/*
|
||||
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#ifdef CONFIG_X86
|
||||
#include <asm/mpspec.h>
|
||||
#endif
|
||||
#include <linux/pci.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
|
@ -784,6 +785,7 @@ static int __init acpi_init(void)
|
|||
result = acpi_bus_init();
|
||||
|
||||
if (!result) {
|
||||
pci_mmcfg_late_init();
|
||||
if (!(pm_flags & PM_APM))
|
||||
pm_flags |= PM_ACPI;
|
||||
else {
|
||||
|
|
|
@ -787,6 +787,10 @@ int device_add(struct device *dev)
|
|||
parent = get_device(dev->parent);
|
||||
setup_parent(dev, parent);
|
||||
|
||||
/* use parent numa_node */
|
||||
if (parent)
|
||||
set_dev_node(dev, dev_to_node(parent));
|
||||
|
||||
/* first, register with generic layer. */
|
||||
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
|
||||
if (error)
|
||||
|
@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent)
|
|||
dev->parent = new_parent;
|
||||
if (old_parent)
|
||||
klist_remove(&dev->knode_parent);
|
||||
if (new_parent)
|
||||
if (new_parent) {
|
||||
klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
|
||||
set_dev_node(dev, dev_to_node(new_parent));
|
||||
}
|
||||
|
||||
if (!dev->class)
|
||||
goto out_put;
|
||||
error = device_move_class_links(dev, old_parent, new_parent);
|
||||
|
@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent)
|
|||
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
|
||||
if (new_parent)
|
||||
klist_remove(&dev->knode_parent);
|
||||
if (old_parent)
|
||||
dev->parent = old_parent;
|
||||
if (old_parent) {
|
||||
klist_add_tail(&dev->knode_parent,
|
||||
&old_parent->klist_children);
|
||||
set_dev_node(dev, dev_to_node(old_parent));
|
||||
}
|
||||
}
|
||||
cleanup_glue_dir(dev, new_parent_kobj);
|
||||
put_device(new_parent);
|
||||
|
|
|
@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev)
|
|||
* reading the dword at 0x100 which must either be 0 or a valid extended
|
||||
* capability header.
|
||||
*/
|
||||
int pci_cfg_space_size(struct pci_dev *dev)
|
||||
int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix)
|
||||
{
|
||||
int pos;
|
||||
u32 status;
|
||||
|
||||
if (!check_exp_pcix)
|
||||
goto skip;
|
||||
|
||||
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||
if (!pos) {
|
||||
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
|
||||
|
@ -858,6 +861,7 @@ int pci_cfg_space_size(struct pci_dev *dev)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
skip:
|
||||
if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL)
|
||||
goto fail;
|
||||
if (status == 0xffffffff)
|
||||
|
@ -869,6 +873,11 @@ int pci_cfg_space_size(struct pci_dev *dev)
|
|||
return PCI_CFG_SPACE_SIZE;
|
||||
}
|
||||
|
||||
int pci_cfg_space_size(struct pci_dev *dev)
|
||||
{
|
||||
return pci_cfg_space_size_ext(dev, 1);
|
||||
}
|
||||
|
||||
static void pci_release_bus_bridge_dev(struct device *dev)
|
||||
{
|
||||
kfree(dev);
|
||||
|
@ -964,7 +973,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
|
|||
dev->dev.release = pci_release_dev;
|
||||
pci_dev_get(dev);
|
||||
|
||||
set_dev_node(&dev->dev, pcibus_to_node(bus));
|
||||
dev->dev.dma_mask = &dev->dma_mask;
|
||||
dev->dev.dma_parms = &dev->dma_parms;
|
||||
dev->dev.coherent_dma_mask = 0xffffffffull;
|
||||
|
@ -1080,6 +1088,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
|
|||
return max;
|
||||
}
|
||||
|
||||
void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b)
|
||||
{
|
||||
}
|
||||
|
||||
struct pci_bus * pci_create_bus(struct device *parent,
|
||||
int bus, struct pci_ops *ops, void *sysdata)
|
||||
{
|
||||
|
@ -1119,6 +1131,9 @@ struct pci_bus * pci_create_bus(struct device *parent,
|
|||
goto dev_reg_err;
|
||||
b->bridge = get_device(dev);
|
||||
|
||||
if (!parent)
|
||||
set_dev_node(b->bridge, pcibus_to_node(b));
|
||||
|
||||
b->dev.class = &pcibus_class;
|
||||
b->dev.parent = b->bridge;
|
||||
sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
|
||||
|
@ -1136,6 +1151,8 @@ struct pci_bus * pci_create_bus(struct device *parent,
|
|||
b->resource[0] = &ioport_resource;
|
||||
b->resource[1] = &iomem_resource;
|
||||
|
||||
set_pci_bus_resources_arch_default(b);
|
||||
|
||||
return b;
|
||||
|
||||
dev_create_file_err:
|
||||
|
|
|
@ -19,6 +19,8 @@ struct pci_sysdata {
|
|||
};
|
||||
|
||||
/* scan a bus after allocating a pci_sysdata for it */
|
||||
extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
|
||||
int node);
|
||||
extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
|
||||
|
||||
static inline int pci_domain_nr(struct pci_bus *bus)
|
||||
|
|
|
@ -193,9 +193,25 @@ extern cpumask_t cpu_coregroup_map(int cpu);
|
|||
#define topology_thread_siblings(cpu) (per_cpu(cpu_sibling_map, cpu))
|
||||
#endif
|
||||
|
||||
struct pci_bus;
|
||||
void set_pci_bus_resources_arch_default(struct pci_bus *b);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#define mc_capable() (boot_cpu_data.x86_max_cores > 1)
|
||||
#define smt_capable() (smp_num_siblings > 1)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
extern int get_mp_bus_to_node(int busnum);
|
||||
extern void set_mp_bus_to_node(int busnum, int node);
|
||||
#else
|
||||
static inline int get_mp_bus_to_node(int busnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void set_mp_bus_to_node(int busnum, int node)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table);
|
|||
typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
|
||||
|
||||
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
|
||||
int early_acpi_boot_init(void);
|
||||
int acpi_boot_init (void);
|
||||
int acpi_boot_table_init (void);
|
||||
int acpi_numa_init (void);
|
||||
|
@ -235,6 +236,10 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
|
|||
|
||||
#else /* CONFIG_ACPI */
|
||||
|
||||
static inline int early_acpi_boot_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int acpi_boot_init(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -254,7 +254,7 @@ static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
|
|||
#define PCI_NUM_RESOURCES 11
|
||||
|
||||
#ifndef PCI_BUS_NUM_RESOURCES
|
||||
#define PCI_BUS_NUM_RESOURCES 8
|
||||
#define PCI_BUS_NUM_RESOURCES 16
|
||||
#endif
|
||||
|
||||
#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */
|
||||
|
@ -666,6 +666,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
|
|||
|
||||
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
|
||||
void *userdata);
|
||||
int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix);
|
||||
int pci_cfg_space_size(struct pci_dev *dev);
|
||||
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
||||
|
||||
|
@ -1053,5 +1054,13 @@ extern unsigned long pci_cardbus_mem_size;
|
|||
|
||||
extern int pcibios_add_platform_entries(struct pci_dev *dev);
|
||||
|
||||
#ifdef CONFIG_PCI_MMCONFIG
|
||||
extern void __init pci_mmcfg_early_init(void);
|
||||
extern void __init pci_mmcfg_late_init(void);
|
||||
#else
|
||||
static inline void pci_mmcfg_early_init(void) { }
|
||||
static inline void pci_mmcfg_late_init(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* LINUX_PCI_H */
|
||||
|
|
Loading…
Reference in New Issue