linux/arch/i386/pci/mmconfig-shared.c
<<
>>
Prefs
   1/*
   2 * mmconfig-shared.c - Low-level direct PCI config space access via
   3 *                     MMCONFIG - common code between i386 and x86-64.
   4 *
   5 * This code does:
   6 * - known chipset handling
   7 * - ACPI decoding and validation
   8 *
   9 * Per-architecture code takes care of the mappings and accesses
  10 * themselves.
  11 */
  12
  13#include <linux/pci.h>
  14#include <linux/init.h>
  15#include <linux/acpi.h>
  16#include <linux/bitmap.h>
  17#include <asm/e820.h>
  18
  19#include "pci.h"
  20
  21/* aperture is up to 256MB but BIOS may reserve less */
  22#define MMCONFIG_APER_MIN       (2 * 1024*1024)
  23#define MMCONFIG_APER_MAX       (256 * 1024*1024)
  24
  25DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
  26
  27/* K8 systems have some devices (typically in the builtin northbridge)
  28   that are only accessible using type1
  29   Normally this can be expressed in the MCFG by not listing them
  30   and assigning suitable _SEGs, but this isn't implemented in some BIOS.
  31   Instead try to discover all devices on bus 0 that are unreachable using MM
  32   and fallback for them. */
  33static void __init unreachable_devices(void)
  34{
  35        int i, bus;
  36        /* Use the max bus number from ACPI here? */
  37        for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) {
  38                for (i = 0; i < 32; i++) {
  39                        unsigned int devfn = PCI_DEVFN(i, 0);
  40                        u32 val1, val2;
  41
  42                        pci_conf1_read(0, bus, devfn, 0, 4, &val1);
  43                        if (val1 == 0xffffffff)
  44                                continue;
  45
  46                        if (pci_mmcfg_arch_reachable(0, bus, devfn)) {
  47                                raw_pci_ops->read(0, bus, devfn, 0, 4, &val2);
  48                                if (val1 == val2)
  49                                        continue;
  50                        }
  51                        set_bit(i + 32 * bus, pci_mmcfg_fallback_slots);
  52                        printk(KERN_NOTICE "PCI: No mmconfig possible on device"
  53                               " %02x:%02x\n", bus, i);
  54                }
  55        }
  56}
  57
  58static const char __init *pci_mmcfg_e7520(void)
  59{
  60        u32 win;
  61        pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
  62
  63        win = win & 0xf000;
  64        if(win == 0x0000 || win == 0xf000)
  65                pci_mmcfg_config_num = 0;
  66        else {
  67                pci_mmcfg_config_num = 1;
  68                pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
  69                if (!pci_mmcfg_config)
  70                        return NULL;
  71                pci_mmcfg_config[0].address = win << 16;
  72                pci_mmcfg_config[0].pci_segment = 0;
  73                pci_mmcfg_config[0].start_bus_number = 0;
  74                pci_mmcfg_config[0].end_bus_number = 255;
  75        }
  76
  77        return "Intel Corporation E7520 Memory Controller Hub";
  78}
  79
  80static const char __init *pci_mmcfg_intel_945(void)
  81{
  82        u32 pciexbar, mask = 0, len = 0;
  83
  84        pci_mmcfg_config_num = 1;
  85
  86        pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
  87
  88        /* Enable bit */
  89        if (!(pciexbar & 1))
  90                pci_mmcfg_config_num = 0;
  91
  92        /* Size bits */
  93        switch ((pciexbar >> 1) & 3) {
  94        case 0:
  95                mask = 0xf0000000U;
  96                len  = 0x10000000U;
  97                break;
  98        case 1:
  99                mask = 0xf8000000U;
 100                len  = 0x08000000U;
 101                break;
 102        case 2:
 103                mask = 0xfc000000U;
 104                len  = 0x04000000U;
 105                break;
 106        default:
 107                pci_mmcfg_config_num = 0;
 108        }
 109
 110        /* Errata #2, things break when not aligned on a 256Mb boundary */
 111        /* Can only happen in 64M/128M mode */
 112
 113        if ((pciexbar & mask) & 0x0fffffffU)
 114                pci_mmcfg_config_num = 0;
 115
 116        /* Don't hit the APIC registers and their friends */
 117        if ((pciexbar & mask) >= 0xf0000000U)
 118                pci_mmcfg_config_num = 0;
 119
 120        if (pci_mmcfg_config_num) {
 121                pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
 122                if (!pci_mmcfg_config)
 123                        return NULL;
 124                pci_mmcfg_config[0].address = pciexbar & mask;
 125                pci_mmcfg_config[0].pci_segment = 0;
 126                pci_mmcfg_config[0].start_bus_number = 0;
 127                pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
 128        }
 129
 130        return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
 131}
 132
 133struct pci_mmcfg_hostbridge_probe {
 134        u32 vendor;
 135        u32 device;
 136        const char *(*probe)(void);
 137};
 138
 139static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
 140        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
 141        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
 142};
 143
 144static int __init pci_mmcfg_check_hostbridge(void)
 145{
 146        u32 l;
 147        u16 vendor, device;
 148        int i;
 149        const char *name;
 150
 151        pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
 152        vendor = l & 0xffff;
 153        device = (l >> 16) & 0xffff;
 154
 155        pci_mmcfg_config_num = 0;
 156        pci_mmcfg_config = NULL;
 157        name = NULL;
 158
 159        for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
 160                if (pci_mmcfg_probes[i].vendor == vendor &&
 161                    pci_mmcfg_probes[i].device == device)
 162                        name = pci_mmcfg_probes[i].probe();
 163        }
 164
 165        if (name) {
 166                printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
 167                       name, pci_mmcfg_config_num ? "with" : "without");
 168        }
 169
 170        return name != NULL;
 171}
 172
 173static void __init pci_mmcfg_insert_resources(void)
 174{
 175#define PCI_MMCFG_RESOURCE_NAME_LEN 19
 176        int i;
 177        struct resource *res;
 178        char *names;
 179        unsigned num_buses;
 180
 181        res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
 182                        pci_mmcfg_config_num, GFP_KERNEL);
 183        if (!res) {
 184                printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
 185                return;
 186        }
 187
 188        names = (void *)&res[pci_mmcfg_config_num];
 189        for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
 190                struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
 191                num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
 192                res->name = names;
 193                snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
 194                         cfg->pci_segment);
 195                res->start = cfg->address;
 196                res->end = res->start + (num_buses << 20) - 1;
 197                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 198                insert_resource(&iomem_resource, res);
 199                names += PCI_MMCFG_RESOURCE_NAME_LEN;
 200        }
 201}
 202
 203static void __init pci_mmcfg_reject_broken(int type)
 204{
 205        typeof(pci_mmcfg_config[0]) *cfg;
 206
 207        if ((pci_mmcfg_config_num == 0) ||
 208            (pci_mmcfg_config == NULL) ||
 209            (pci_mmcfg_config[0].address == 0))
 210                return;
 211
 212        cfg = &pci_mmcfg_config[0];
 213
 214        /*
 215         * Handle more broken MCFG tables on Asus etc.
 216         * They only contain a single entry for bus 0-0.
 217         */
 218        if (pci_mmcfg_config_num == 1 &&
 219            cfg->pci_segment == 0 &&
 220            (cfg->start_bus_number | cfg->end_bus_number) == 0) {
 221                printk(KERN_ERR "PCI: start and end of bus number is 0. "
 222                       "Rejected as broken MCFG.\n");
 223                goto reject;
 224        }
 225
 226        /*
 227         * Only do this check when type 1 works. If it doesn't work
 228         * assume we run on a Mac and always use MCFG
 229         */
 230        if (type == 1 && !e820_all_mapped(cfg->address,
 231                                          cfg->address + MMCONFIG_APER_MIN,
 232                                          E820_RESERVED)) {
 233                printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
 234                       " E820-reserved\n", cfg->address);
 235                goto reject;
 236        }
 237        return;
 238
 239reject:
 240        printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
 241        kfree(pci_mmcfg_config);
 242        pci_mmcfg_config = NULL;
 243        pci_mmcfg_config_num = 0;
 244}
 245
 246void __init pci_mmcfg_init(int type)
 247{
 248        int known_bridge = 0;
 249
 250        if ((pci_probe & PCI_PROBE_MMCONF) == 0)
 251                return;
 252
 253        if (type == 1 && pci_mmcfg_check_hostbridge())
 254                known_bridge = 1;
 255
 256        if (!known_bridge) {
 257                acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
 258                pci_mmcfg_reject_broken(type);
 259        }
 260
 261        if ((pci_mmcfg_config_num == 0) ||
 262            (pci_mmcfg_config == NULL) ||
 263            (pci_mmcfg_config[0].address == 0))
 264                return;
 265
 266        if (pci_mmcfg_arch_init()) {
 267                if (type == 1)
 268                        unreachable_devices();
 269                if (known_bridge)
 270                        pci_mmcfg_insert_resources();
 271                pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
 272        }
 273}
 274
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.