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.
このコミットが含まれているのは:
@@ -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;
|
||||
}
|
||||
|
23
arch/x86/pci/mp_bus_to_node.c
ノーマルファイル
23
arch/x86/pci/mp_bus_to_node.c
ノーマルファイル
@@ -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
|
||||
|
新しいイシューから参照
ユーザーをブロックする