kernel-fxtec-pro1x/arch/x86_64/pci/mmconfig.c
Andi Kleen 928cf8c627 [PATCH] i386/x86-64 Fall back to type 1 access when no entry found
When there is no entry for a bus in MCFG fall back to type1.  This is
especially important on K8 systems where always some devices can't be accessed
using mmconfig (in particular the builtin northbridge doesn't support it for
its own devices)

Cc: <gregkh@suse.de>
Cc: <jgarzik@pobox.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-12-12 22:31:16 -08:00

148 lines
3.5 KiB
C

/*
* mmconfig.c - Low-level direct PCI config space access via MMCONFIG
*
* This is an 64bit optimized version that always keeps the full mmconfig
* space mapped. This allows lockless config space operation.
*/
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include "pci.h"
#define MMCONFIG_APER_SIZE (256*1024*1024)
/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
struct acpi_table_mcfg_config *cfg;
char *virt;
};
static struct mmcfg_virt *pci_mmcfg_virt;
static char *get_virt(unsigned int seg, unsigned bus)
{
int cfg_num = -1;
struct acpi_table_mcfg_config *cfg;
while (1) {
++cfg_num;
if (cfg_num >= pci_mmcfg_config_num) {
/* Not found - fall back to type 1. This happens
e.g. on the internal devices of a K8 northbridge. */
return NULL;
}
cfg = pci_mmcfg_virt[cfg_num].cfg;
if (cfg->pci_segment_group_number != seg)
continue;
if ((cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
return pci_mmcfg_virt[cfg_num].virt;
}
}
static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
char *addr = get_virt(seg, bus);
if (!addr)
return NULL;
return addr + ((bus << 20) | (devfn << 12));
}
static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
char *addr;
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
addr = pci_dev_base(seg, bus, devfn);
if (!addr)
return pci_conf1_read(seg,bus,devfn,reg,len,value);
switch (len) {
case 1:
*value = readb(addr + reg);
break;
case 2:
*value = readw(addr + reg);
break;
case 4:
*value = readl(addr + reg);
break;
}
return 0;
}
static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
char *addr;
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
addr = pci_dev_base(seg, bus, devfn);
if (!addr)
return pci_conf1_write(seg,bus,devfn,reg,len,value);
switch (len) {
case 1:
writeb(value, addr + reg);
break;
case 2:
writew(value, addr + reg);
break;
case 4:
writel(value, addr + reg);
break;
}
return 0;
}
static struct pci_raw_ops pci_mmcfg = {
.read = pci_mmcfg_read,
.write = pci_mmcfg_write,
};
static int __init pci_mmcfg_init(void)
{
int i;
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return 0;
acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].base_address == 0))
return 0;
/* RED-PEN i386 doesn't do _nocache right now */
pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
if (pci_mmcfg_virt == NULL) {
printk("PCI: Can not allocate memory for mmconfig structures\n");
return 0;
}
for (i = 0; i < pci_mmcfg_config_num; ++i) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
if (!pci_mmcfg_virt[i].virt) {
printk("PCI: Cannot map mmconfig aperture for segment %d\n",
pci_mmcfg_config[i].pci_segment_group_number);
return 0;
}
printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
}
raw_pci_ops = &pci_mmcfg;
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
return 0;
}
arch_initcall(pci_mmcfg_init);