linux/arch/x86/pci/acpi.c
<<
>>
Prefs
   1#include <linux/pci.h>
   2#include <linux/acpi.h>
   3#include <linux/init.h>
   4#include <linux/irq.h>
   5#include <linux/dmi.h>
   6#include <linux/slab.h>
   7#include <asm/numa.h>
   8#include <asm/pci_x86.h>
   9
  10struct pci_root_info {
  11        struct acpi_device *bridge;
  12        char *name;
  13        unsigned int res_num;
  14        struct resource *res;
  15        struct pci_bus *bus;
  16        int busnum;
  17};
  18
  19static bool pci_use_crs = true;
  20
  21static int __init set_use_crs(const struct dmi_system_id *id)
  22{
  23        pci_use_crs = true;
  24        return 0;
  25}
  26
  27static const struct dmi_system_id pci_use_crs_table[] __initconst = {
  28        /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
  29        {
  30                .callback = set_use_crs,
  31                .ident = "IBM System x3800",
  32                .matches = {
  33                        DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
  34                        DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
  35                },
  36        },
  37        /* https://bugzilla.kernel.org/show_bug.cgi?id=16007 */
  38        /* 2006 AMD HT/VIA system with two host bridges */
  39        {
  40                .callback = set_use_crs,
  41                .ident = "ASRock ALiveSATA2-GLAN",
  42                .matches = {
  43                        DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
  44                },
  45        },
  46        /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
  47        /* 2006 AMD HT/VIA system with two host bridges */
  48        {
  49                .callback = set_use_crs,
  50                .ident = "ASUS M2V-MX SE",
  51                .matches = {
  52                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
  53                        DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
  54                        DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
  55                },
  56        },
  57        {}
  58};
  59
  60void __init pci_acpi_crs_quirks(void)
  61{
  62        int year;
  63
  64        if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
  65                pci_use_crs = false;
  66
  67        dmi_check_system(pci_use_crs_table);
  68
  69        /*
  70         * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that
  71         * takes precedence over anything we figured out above.
  72         */
  73        if (pci_probe & PCI_ROOT_NO_CRS)
  74                pci_use_crs = false;
  75        else if (pci_probe & PCI_USE__CRS)
  76                pci_use_crs = true;
  77
  78        printk(KERN_INFO "PCI: %s host bridge windows from ACPI; "
  79               "if necessary, use \"pci=%s\" and report a bug\n",
  80               pci_use_crs ? "Using" : "Ignoring",
  81               pci_use_crs ? "nocrs" : "use_crs");
  82}
  83
  84static acpi_status
  85resource_to_addr(struct acpi_resource *resource,
  86                        struct acpi_resource_address64 *addr)
  87{
  88        acpi_status status;
  89        struct acpi_resource_memory24 *memory24;
  90        struct acpi_resource_memory32 *memory32;
  91        struct acpi_resource_fixed_memory32 *fixed_memory32;
  92
  93        memset(addr, 0, sizeof(*addr));
  94        switch (resource->type) {
  95        case ACPI_RESOURCE_TYPE_MEMORY24:
  96                memory24 = &resource->data.memory24;
  97                addr->resource_type = ACPI_MEMORY_RANGE;
  98                addr->minimum = memory24->minimum;
  99                addr->address_length = memory24->address_length;
 100                addr->maximum = addr->minimum + addr->address_length - 1;
 101                return AE_OK;
 102        case ACPI_RESOURCE_TYPE_MEMORY32:
 103                memory32 = &resource->data.memory32;
 104                addr->resource_type = ACPI_MEMORY_RANGE;
 105                addr->minimum = memory32->minimum;
 106                addr->address_length = memory32->address_length;
 107                addr->maximum = addr->minimum + addr->address_length - 1;
 108                return AE_OK;
 109        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
 110                fixed_memory32 = &resource->data.fixed_memory32;
 111                addr->resource_type = ACPI_MEMORY_RANGE;
 112                addr->minimum = fixed_memory32->address;
 113                addr->address_length = fixed_memory32->address_length;
 114                addr->maximum = addr->minimum + addr->address_length - 1;
 115                return AE_OK;
 116        case ACPI_RESOURCE_TYPE_ADDRESS16:
 117        case ACPI_RESOURCE_TYPE_ADDRESS32:
 118        case ACPI_RESOURCE_TYPE_ADDRESS64:
 119                status = acpi_resource_to_address64(resource, addr);
 120                if (ACPI_SUCCESS(status) &&
 121                    (addr->resource_type == ACPI_MEMORY_RANGE ||
 122                    addr->resource_type == ACPI_IO_RANGE) &&
 123                    addr->address_length > 0) {
 124                        return AE_OK;
 125                }
 126                break;
 127        }
 128        return AE_ERROR;
 129}
 130
 131static acpi_status
 132count_resource(struct acpi_resource *acpi_res, void *data)
 133{
 134        struct pci_root_info *info = data;
 135        struct acpi_resource_address64 addr;
 136        acpi_status status;
 137
 138        status = resource_to_addr(acpi_res, &addr);
 139        if (ACPI_SUCCESS(status))
 140                info->res_num++;
 141        return AE_OK;
 142}
 143
 144static acpi_status
 145setup_resource(struct acpi_resource *acpi_res, void *data)
 146{
 147        struct pci_root_info *info = data;
 148        struct resource *res;
 149        struct acpi_resource_address64 addr;
 150        acpi_status status;
 151        unsigned long flags;
 152        u64 start, end;
 153
 154        status = resource_to_addr(acpi_res, &addr);
 155        if (!ACPI_SUCCESS(status))
 156                return AE_OK;
 157
 158        if (addr.resource_type == ACPI_MEMORY_RANGE) {
 159                flags = IORESOURCE_MEM;
 160                if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
 161                        flags |= IORESOURCE_PREFETCH;
 162        } else if (addr.resource_type == ACPI_IO_RANGE) {
 163                flags = IORESOURCE_IO;
 164        } else
 165                return AE_OK;
 166
 167        start = addr.minimum + addr.translation_offset;
 168        end = addr.maximum + addr.translation_offset;
 169
 170        res = &info->res[info->res_num];
 171        res->name = info->name;
 172        res->flags = flags;
 173        res->start = start;
 174        res->end = end;
 175        res->child = NULL;
 176
 177        if (!pci_use_crs) {
 178                dev_printk(KERN_DEBUG, &info->bridge->dev,
 179                           "host bridge window %pR (ignored)\n", res);
 180                return AE_OK;
 181        }
 182
 183        info->res_num++;
 184        if (addr.translation_offset)
 185                dev_info(&info->bridge->dev, "host bridge window %pR "
 186                         "(PCI address [%#llx-%#llx])\n",
 187                         res, res->start - addr.translation_offset,
 188                         res->end - addr.translation_offset);
 189        else
 190                dev_info(&info->bridge->dev, "host bridge window %pR\n", res);
 191
 192        return AE_OK;
 193}
 194
 195static bool resource_contains(struct resource *res, resource_size_t point)
 196{
 197        if (res->start <= point && point <= res->end)
 198                return true;
 199        return false;
 200}
 201
 202static void coalesce_windows(struct pci_root_info *info, unsigned long type)
 203{
 204        int i, j;
 205        struct resource *res1, *res2;
 206
 207        for (i = 0; i < info->res_num; i++) {
 208                res1 = &info->res[i];
 209                if (!(res1->flags & type))
 210                        continue;
 211
 212                for (j = i + 1; j < info->res_num; j++) {
 213                        res2 = &info->res[j];
 214                        if (!(res2->flags & type))
 215                                continue;
 216
 217                        /*
 218                         * I don't like throwing away windows because then
 219                         * our resources no longer match the ACPI _CRS, but
 220                         * the kernel resource tree doesn't allow overlaps.
 221                         */
 222                        if (resource_contains(res1, res2->start) ||
 223                            resource_contains(res1, res2->end) ||
 224                            resource_contains(res2, res1->start) ||
 225                            resource_contains(res2, res1->end)) {
 226                                res1->start = min(res1->start, res2->start);
 227                                res1->end = max(res1->end, res2->end);
 228                                dev_info(&info->bridge->dev,
 229                                         "host bridge window expanded to %pR; %pR ignored\n",
 230                                         res1, res2);
 231                                res2->flags = 0;
 232                        }
 233                }
 234        }
 235}
 236
 237static void add_resources(struct pci_root_info *info)
 238{
 239        int i;
 240        struct resource *res, *root, *conflict;
 241
 242        if (!pci_use_crs)
 243                return;
 244
 245        coalesce_windows(info, IORESOURCE_MEM);
 246        coalesce_windows(info, IORESOURCE_IO);
 247
 248        for (i = 0; i < info->res_num; i++) {
 249                res = &info->res[i];
 250
 251                if (res->flags & IORESOURCE_MEM)
 252                        root = &iomem_resource;
 253                else if (res->flags & IORESOURCE_IO)
 254                        root = &ioport_resource;
 255                else
 256                        continue;
 257
 258                conflict = insert_resource_conflict(root, res);
 259                if (conflict)
 260                        dev_info(&info->bridge->dev,
 261                                 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
 262                                 res, conflict->name, conflict);
 263                else
 264                        pci_bus_add_resource(info->bus, res, 0);
 265        }
 266}
 267
 268static void
 269get_current_resources(struct acpi_device *device, int busnum,
 270                        int domain, struct pci_bus *bus)
 271{
 272        struct pci_root_info info;
 273        size_t size;
 274
 275        if (pci_use_crs)
 276                pci_bus_remove_resources(bus);
 277
 278        info.bridge = device;
 279        info.bus = bus;
 280        info.res_num = 0;
 281        acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
 282                                &info);
 283        if (!info.res_num)
 284                return;
 285
 286        size = sizeof(*info.res) * info.res_num;
 287        info.res = kmalloc(size, GFP_KERNEL);
 288        if (!info.res)
 289                goto res_alloc_fail;
 290
 291        info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
 292        if (!info.name)
 293                goto name_alloc_fail;
 294
 295        info.res_num = 0;
 296        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
 297                                &info);
 298
 299        add_resources(&info);
 300        return;
 301
 302name_alloc_fail:
 303        kfree(info.res);
 304res_alloc_fail:
 305        return;
 306}
 307
 308struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 309{
 310        struct acpi_device *device = root->device;
 311        int domain = root->segment;
 312        int busnum = root->secondary.start;
 313        struct pci_bus *bus;
 314        struct pci_sysdata *sd;
 315        int node;
 316#ifdef CONFIG_ACPI_NUMA
 317        int pxm;
 318#endif
 319
 320        if (domain && !pci_domains_supported) {
 321                printk(KERN_WARNING "pci_bus %04x:%02x: "
 322                       "ignored (multiple domains not supported)\n",
 323                       domain, busnum);
 324                return NULL;
 325        }
 326
 327        node = -1;
 328#ifdef CONFIG_ACPI_NUMA
 329        pxm = acpi_get_pxm(device->handle);
 330        if (pxm >= 0)
 331                node = pxm_to_node(pxm);
 332        if (node != -1)
 333                set_mp_bus_to_node(busnum, node);
 334        else
 335#endif
 336                node = get_mp_bus_to_node(busnum);
 337
 338        if (node != -1 && !node_online(node))
 339                node = -1;
 340
 341        /* Allocate per-root-bus (not per bus) arch-specific data.
 342         * TODO: leak; this memory is never freed.
 343         * It's arguable whether it's worth the trouble to care.
 344         */
 345        sd = kzalloc(sizeof(*sd), GFP_KERNEL);
 346        if (!sd) {
 347                printk(KERN_WARNING "pci_bus %04x:%02x: "
 348                       "ignored (out of memory)\n", domain, busnum);
 349                return NULL;
 350        }
 351
 352        sd->domain = domain;
 353        sd->node = node;
 354        /*
 355         * Maybe the desired pci bus has been already scanned. In such case
 356         * it is unnecessary to scan the pci bus with the given domain,busnum.
 357         */
 358        bus = pci_find_bus(domain, busnum);
 359        if (bus) {
 360                /*
 361                 * If the desired bus exits, the content of bus->sysdata will
 362                 * be replaced by sd.
 363                 */
 364                memcpy(bus->sysdata, sd, sizeof(*sd));
 365                kfree(sd);
 366        } else {
 367                bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
 368                if (bus) {
 369                        get_current_resources(device, busnum, domain, bus);
 370                        bus->subordinate = pci_scan_child_bus(bus);
 371                }
 372        }
 373
 374        /* After the PCI-E bus has been walked and all devices discovered,
 375         * configure any settings of the fabric that might be necessary.
 376         */
 377        if (bus) {
 378                struct pci_bus *child;
 379                list_for_each_entry(child, &bus->children, node) {
 380                        struct pci_dev *self = child->self;
 381                        if (!self)
 382                                continue;
 383
 384                        pcie_bus_configure_settings(child, self->pcie_mpss);
 385                }
 386        }
 387
 388        if (!bus)
 389                kfree(sd);
 390
 391        if (bus && node != -1) {
 392#ifdef CONFIG_ACPI_NUMA
 393                if (pxm >= 0)
 394                        dev_printk(KERN_DEBUG, &bus->dev,
 395                                   "on NUMA node %d (pxm %d)\n", node, pxm);
 396#else
 397                dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
 398#endif
 399        }
 400
 401        return bus;
 402}
 403
 404int __init pci_acpi_init(void)
 405{
 406        struct pci_dev *dev = NULL;
 407
 408        if (acpi_noirq)
 409                return -ENODEV;
 410
 411        printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
 412        acpi_irq_penalty_init();
 413        pcibios_enable_irq = acpi_pci_irq_enable;
 414        pcibios_disable_irq = acpi_pci_irq_disable;
 415        x86_init.pci.init_irq = x86_init_noop;
 416
 417        if (pci_routeirq) {
 418                /*
 419                 * PCI IRQ routing is set up by pci_enable_device(), but we
 420                 * also do it here in case there are still broken drivers that
 421                 * don't use pci_enable_device().
 422                 */
 423                printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
 424                for_each_pci_dev(dev)
 425                        acpi_pci_irq_enable(dev);
 426        }
 427
 428        return 0;
 429}
 430