pci_link.c revision e0e4e117d4c898b0df749d5b88c86955151abf53
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 34 $) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Dominik Brodowski <devel@brodo.de> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TBD: 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Support more than one IRQ resource entry per link device (index). 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. Implement start/stop mechanism and use ACPI Bus Driver facilities 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for IRQ management (e.g. start()->_SRS). 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysdev.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pm.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 4136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar#include <linux/mutex.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT ACPI_PCI_COMPONENT 474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen BrownACPI_MODULE_NAME("pci_link") 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_CLASS "pci_irq_routing" 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_HID "PNP0C0F" 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_INFO "info" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_STATUS "state" 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_MAX_POSSIBLE 16 554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_add(struct acpi_device *device); 564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_remove(struct acpi_device *device, int type); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_pci_link_driver = { 594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .name = ACPI_PCI_LINK_DRIVER_NAME, 604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .class = ACPI_PCI_LINK_CLASS, 614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .ids = ACPI_PCI_LINK_HID, 624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .ops = { 634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .add = acpi_pci_link_add, 644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .remove = acpi_pci_link_remove, 654be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown }, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* 6987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * If a link is initialized, we never change its active and initialized 7087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * later even the link is disable. Instead, we just repick the active irq 7187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link_irq { 734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 active; /* Current IRQ */ 7450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore u8 triggering; /* All IRQs */ 7550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore u8 polarity; /* All IRQs */ 764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 resource_type; 774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 possible_count; 784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; 794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 initialized:1; 804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 reserved:7; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link { 844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head node; 854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_pci_link_irq irq; 874be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int refcnt; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct { 914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int count; 924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head entries; 934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown} acpi_link; 9436e430951af0b0d1bdfd50ce22e70079d02646dfIngo MolnarDEFINE_MUTEX(acpi_link_lock); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Link Device Management 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set context (link) possible list from resource list 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_link_check_possible(struct acpi_resource *resource, void *context) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = (struct acpi_pci_link *)context; 1074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u32 i = 0; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 110eca008c8134df15262a0362623edb59902628c95Len Brown switch (resource->type) { 11150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_START_DEPENDENT: 112d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 11350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_IRQ: 1144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 1154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_irq *p = &resource->data.irq; 11650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (!p || !p->interrupt_count) { 117cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Blank IRQ resource\n"); 118d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; 12150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (i < p->interrupt_count 1224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { 1234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p->interrupts[i]) { 124cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Invalid IRQ %d\n", 125cece92969762b8ed7930d4e23008b76b06411deeLen Brown p->interrupts[i]); 1264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown continue; 1274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible[i] = p->interrupts[i]; 1294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count++; 1304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 13150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.triggering = p->triggering; 13250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity = p->polarity; 13350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.resource_type = ACPI_RESOURCE_TYPE_IRQ; 1344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 1374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 13850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore struct acpi_resource_extended_irq *p = 1394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown &resource->data.extended_irq; 14050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (!p || !p->interrupt_count) { 141cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 142cece92969762b8ed7930d4e23008b76b06411deeLen Brown "Blank EXT IRQ resource\n"); 143d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 1444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; 14650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (i < p->interrupt_count 1474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { 1484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p->interrupts[i]) { 149cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Invalid IRQ %d\n", 150cece92969762b8ed7930d4e23008b76b06411deeLen Brown p->interrupts[i]); 1514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown continue; 1524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible[i] = p->interrupts[i]; 1544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count++; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.triggering = p->triggering; 15750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity = p->polarity; 15850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; 1594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1626468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Resource is not an IRQ entry\n"); 163d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 166d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_CTRL_TERMINATE; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_possible(struct acpi_pci_link *link) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) 175d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17767a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS, 1784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_link_check_possible, link); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 180a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS")); 181d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Found %d possible IRQs\n", 1864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count)); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_link_check_current(struct acpi_resource *resource, void *context) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int *irq = (int *)context; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 197eca008c8134df15262a0362623edb59902628c95Len Brown switch (resource->type) { 19850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_IRQ: 1994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 2004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_irq *p = &resource->data.irq; 20150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (!p || !p->interrupt_count) { 2024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* 2034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * IRQ descriptors may have no IRQ# bits set, 2044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * particularly those those w/ _STA disabled 2054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown */ 2064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Blank IRQ resource\n")); 208d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 2094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 2104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *irq = p->interrupts[0]; 2114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 2144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 21550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore struct acpi_resource_extended_irq *p = 2164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown &resource->data.extended_irq; 21750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (!p || !p->interrupt_count) { 2184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* 2194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * extended IRQ descriptors must 2204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * return at least 1 IRQ 2214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown */ 222cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 223cece92969762b8ed7930d4e23008b76b06411deeLen Brown "Blank EXT IRQ resource\n"); 224d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 2254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 2264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *irq = p->interrupts[0]; 2274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 229d4ec6c7cc9a15a7a529719bc3b84f46812f9842eLen Brown break; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2316468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Resource %d isn't an IRQ\n", resource->type); 232d4ec6c7cc9a15a7a529719bc3b84f46812f9842eLen Brown case ACPI_RESOURCE_TYPE_END_TAG: 233d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 235d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_CTRL_TERMINATE; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run _CRS and set link->irq.active 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return value: 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 - success 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * !0 - failure 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_current(struct acpi_pci_link *link) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 2484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 2494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = 0; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251e0e4e117d4c898b0df749d5b88c86955151abf53Patrick Mochel if (!link) 252d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = 0; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* in practice, status disabled is meaningless, ignore it */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict) { 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _STA, set link->device->status */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_status(link->device); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 2616468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Unable to read status\n"); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->device->status.enabled) { 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); 267d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Query and parse _CRS to get the current IRQ assignment. 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27567a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS, 2764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_link_check_current, &irq); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 278a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS")); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict && !irq) { 2846468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "_CRS returned 0\n"); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = irq; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 293d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_set(struct acpi_pci_link *link, int irq) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 2994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 3014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource res; 3024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource end; 3034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } *resource; 3044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { 0, NULL }; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link || !irq) 308d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 310a64882e795cc1d890e3359d0aa143af1cf67e8d4Dave Jones resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC); 3114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!resource) 312d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown memset(resource, 0, sizeof(*resource) + 1); 3154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown buffer.length = sizeof(*resource) + 1; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = resource; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown switch (link->irq.resource_type) { 31950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_IRQ: 32050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.type = ACPI_RESOURCE_TYPE_IRQ; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.length = sizeof(struct acpi_resource); 32250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.triggering = link->irq.triggering; 32350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.polarity = 32450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity; 32550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (link->irq.triggering == ACPI_EDGE_SENSITIVE) 32650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = 3274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_EXCLUSIVE; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 32950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = ACPI_SHARED; 33050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.interrupt_count = 1; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.interrupts[0] = irq; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 33450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 33550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.length = sizeof(struct acpi_resource); 3374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.extended_irq.producer_consumer = 3384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_CONSUMER; 33950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.extended_irq.triggering = 34050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.triggering; 34150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.extended_irq.polarity = 34250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity; 34350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (link->irq.triggering == ACPI_EDGE_SENSITIVE) 34450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = 3454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_EXCLUSIVE; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 34750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = ACPI_SHARED; 34850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.extended_irq.interrupt_count = 1; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.extended_irq.interrupts[0] = irq; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ignore resource_source, it's optional */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3536468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -EINVAL; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to set the resource */ 36167a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel status = acpi_set_current_resources(link->device->handle, &buffer); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for total failure */ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 365a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS")); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _STA, set device->status */ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_status(link->device); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3736468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Unable to read status\n"); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->device->status.enabled) { 377cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 378cece92969762b8ed7930d4e23008b76b06411deeLen Brown "%s [%s] disabled and referenced, BIOS bug\n", 379a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_device_name(link->device), 380cece92969762b8ed7930d4e23008b76b06411deeLen Brown acpi_device_bid(link->device)); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _CRS, set link->irq.active */ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_pci_link_get_current(link); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Is current setting not what we set? 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set link->irq.active 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active != irq) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * policy: when _CRS doesn't return what we just _SRS 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assume _SRS worked and override _CRS value. 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 398cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 399cece92969762b8ed7930d4e23008b76b06411deeLen Brown "%s [%s] BIOS reported IRQ %d, using IRQ %d\n", 400a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_device_name(link->device), 401cece92969762b8ed7930d4e23008b76b06411deeLen Brown acpi_device_bid(link->device), link->irq.active, irq); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = irq; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); 4064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 4074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 409d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Link IRQ Management 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Link Devices to move the PIRQs around to minimize sharing. 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the BIOS has already set to active. This is necessary because 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI has no automatic means of knowing what ISA IRQs are used. Note that 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the BIOS doesn't set a Link Device active, ACPI needs to program it 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even if acpi_irq_nobalance is set. 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A tables of penalties avoids directing PCI interrupts to well known 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA IRQs. Boot params are available to over-ride the default table: 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that are free for PCI use. 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_pci=n[,m] 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that should not be used for PCI: 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_isa=n[,m] 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that PCI IRQ routers have a list of possible IRQs, 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which may not include the IRQs this table says are available. 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since this heuristic can't tell the difference between a link 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that no device will attach to, vs. a link which may be shared 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by multiple active devices -- it is not optimal. 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If interrupt performance is that important, get an IO-APIC system 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pin dedicated to each device. Or for that matter, an MSI 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabled system. 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_IRQS 256 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_ISA_IRQ 16 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_AVAILABLE (0) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_POSSIBLE (16*16) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_USING (16*16*16) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16) 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_penalty[ACPI_MAX_IRQS] = { 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ 4614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ 4624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ 4744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* >IRQ15 */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint __init acpi_irq_penalty_init(void) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head *node = NULL; 4804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 4814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i = 0; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update penalties to facilitate IRQ balancing. 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(node, &acpi_link.entries) { 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = list_entry(node, struct acpi_pci_link, node); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 4916468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link context\n"); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reflect the possible and active irqs in the penalty table -- 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * useful for breaking ties. 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.possible_count) { 5004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int penalty = 5014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_PCI_POSSIBLE / 5024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; i++) { 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) 5064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq. 5074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown possible[i]] += 5084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown penalty; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (link->irq.active) { 5124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq.active] += 5134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_PCI_POSSIBLE; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Add a penalty for the SCI */ 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 519d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_balance; /* 0: static, 1: balance */ 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_allocate(struct acpi_pci_link *link) 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 5274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->irq.initialized) { 53187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->refcnt == 0) 53287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li /* This means the link is disabled but initialized */ 53387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li acpi_pci_link_set(link, link->irq.active); 534d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 53587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search for active IRQ in list of possible IRQs. 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; ++i) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active == link->irq.possible[i]) 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forget active IRQ that is not in possible list 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == link->irq.possible_count) { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict) 549cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "_CRS %d not found" 550cece92969762b8ed7930d4e23008b76b06411deeLen Brown " in _PRS\n", link->irq.active); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = 0; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if active found, use it; else pick entry from end of possible list. 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active) { 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.active; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.possible[link->irq.possible_count - 1]; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_irq_balance || !link->irq.active) { 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select the best IRQ. This is done in reverse to promote 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the use of IRQs 9, 10, 11, and >15. 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = (link->irq.possible_count - 1); i >= 0; i--) { 5694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (acpi_irq_penalty[irq] > 5704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq.possible[i]]) 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.possible[i]; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to enable the link device at this IRQ. */ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_pci_link_set(link, irq)) { 5776468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. " 5786468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown "Try pci=noacpi or acpi=off\n", 579a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_device_name(link->device), 5806468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown acpi_device_bid(link->device)); 581d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; 5844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown printk(PREFIX "%s [%s] enabled at IRQ %d\n", 5854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_name(link->device), 5864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device), link->irq.active); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.initialized = 1; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 59587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * acpi_pci_link_allocate_irq 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 6014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_link_allocate_irq(acpi_handle handle, 6024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int index, 60350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, int *polarity, char **name) 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 6064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device = NULL; 6074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_device(handle, &device); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 6126468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link device\n"); 613d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link = (struct acpi_pci_link *)acpi_driver_data(device); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 6186468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link context\n"); 619d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Support multiple index (IRQ) entries per Link Device */ 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (index) { 6246468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid index %d\n", index); 625d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62836e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 62987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (acpi_pci_link_allocate(link)) { 63036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 631d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 63287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 6334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->irq.active) { 63536e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 6366468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Link active IRQ is 0!\n"); 637d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->refcnt++; 64036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (triggering) 64350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *triggering = link->irq.triggering; 64450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (polarity) 64550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *polarity = link->irq.polarity; 6464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (name) 6474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *name = acpi_device_bid(link->device); 64887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Link %s is referenced\n", 6504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device))); 651d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return (link->irq.active); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* 65587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * We don't change link's irq information here. After it is reenabled, we 65687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * continue use the info 65787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */ 6584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_link_free_irq(acpi_handle handle) 65987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 6604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device = NULL; 6614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 6624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status result; 66387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 66487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 66587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li result = acpi_bus_get_device(handle, &device); 66687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (result) { 6676468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link device\n"); 668d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 66987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link = (struct acpi_pci_link *)acpi_driver_data(device); 67287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (!link) { 6736468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link context\n"); 674d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 67587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 67687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 67736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 67887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (!link->irq.initialized) { 67936e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 6806468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Link isn't initialized\n"); 681d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 68287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 683ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#ifdef FUTURE_USE 684ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li /* 685ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * The Link reference count allows us to _DISable an unused link 686ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * and suspend time, and set it again on resume. 687ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * However, 2.6.12 still has irq_router.resume 688ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * which blindly restores the link state. 689ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * So we disable the reference count method 690ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * to prevent duplicate acpi_pci_link_set() 691ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * which would harm some systems 692ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li */ 6934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->refcnt--; 694ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#endif 69587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Link %s is dereferenced\n", 6974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device))); 69887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 69987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->refcnt == 0) { 70067a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL); 70187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 70236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 703d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return (link->irq.active); 70487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 7054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Driver Interface 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_add(struct acpi_device *device) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 7134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 7144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i = 0; 7154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int found = 0; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device) 719d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) 723d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(link, 0, sizeof(struct acpi_pci_link)); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->device = device; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_driver_data(device) = link; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_pci_link_get_possible(link); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* query and set link->irq.active */ 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_link_get_current(link); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), 7404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(device)); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; i++) { 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active == link->irq.possible[i]) { 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" *%d", link->irq.possible[i]); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 1; 7454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } else 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %d", link->irq.possible[i]); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(")"); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!found) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" *%d", link->irq.active); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!link->device->status.enabled) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", disabled."); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Acquire/release lock */ 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&link->node, &acpi_link.entries); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_link.count++; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable all links -- to be activated on use */ 76567a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel acpi_ut_evaluate_object(device->handle, "_DIS", 0, NULL); 76636e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_resume(struct acpi_pci_link *link) 775697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds{ 776697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds 777697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds if (link->refcnt && link->irq.active && link->irq.initialized) 778d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return (acpi_pci_link_set(link, link->irq.active)); 779697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds else 780d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 781697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds} 782697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds 78311e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li/* 78411e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li * FIXME: this is a workaround to avoid nasty warning. It will be removed 78511e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li * after every device calls pci_disable_device in .resume. 78611e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li */ 78711e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Liint acpi_in_resume; 7884be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int irqrouter_resume(struct sys_device *dev) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head *node = NULL; 7914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7945603509137940f4cbc577281cee62110d4097b1bLinus Torvalds /* Make sure SCI is enabled again (Apple firmware bug?) */ 7955603509137940f4cbc577281cee62110d4097b1bLinus Torvalds acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK); 7965603509137940f4cbc577281cee62110d4097b1bLinus Torvalds 79711e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li acpi_in_resume = 1; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(node, &acpi_link.entries) { 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = list_entry(node, struct acpi_pci_link, node); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 8016468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link context\n"); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 804697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds acpi_pci_link_resume(link); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 80611e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li acpi_in_resume = 0; 807d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_remove(struct acpi_device *device, int type) 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_pci_link *link = NULL; 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device || !acpi_driver_data(device)) 816d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link = (struct acpi_pci_link *)acpi_driver_data(device); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&link->node); 82236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 826d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify acpi_irq_penalty[] from cmdline 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_penalty_update(char *str, int used) 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) { 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown retval = get_option(&str, &irq); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* no number found */ 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq >= ACPI_MAX_IRQS) 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (used) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 2) /* no next number */ 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'd like PNP to call this routine for the 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single ISA_USED value for each legacy device. 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But instead it calls us with each POSSIBLE setting. 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is no ISA_POSSIBLE weight, so we simply use 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the (small) PCI_USING penalty. 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 869c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Livoid acpi_penalize_isa_irq(int irq, int active) 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 871c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li if (active) 872c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; 873c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li else 874c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to reserve additional IRQs for use by ISA 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_isa=5 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Useful for telling ACPI how not to interfere with your ISA sound card. 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_isa(char *str) 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acpi_irq_penalty_update(str, 1); 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_isa=", acpi_irq_isa); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to free additional IRQs for use by PCI 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_pci=7,15 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing. 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_pci(char *str) 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acpi_irq_penalty_update(str, 0); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_pci=", acpi_irq_pci); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_nobalance_set(char *str) 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_balance = 0; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_nobalance", acpi_irq_nobalance_set); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpi_irq_balance_set(char *str) 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_balance = 1; 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown__setup("acpi_irq_balance", acpi_irq_balance_set); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* FIXME: we will remove this interface after all drivers call pci_disable_device */ 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sysdev_class irqrouter_sysdev_class = { 9194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown set_kset_name("irqrouter"), 9204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .resume = irqrouter_resume, 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sys_device device_irqrouter = { 9244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .id = 0, 9254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .cls = &irqrouter_sysdev_class, 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init irqrouter_init_sysfs(void) 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_disabled || acpi_noirq) 934d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = sysdev_class_register(&irqrouter_sysdev_class); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!error) 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = sysdev_register(&device_irqrouter); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 940d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return error; 9414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown} 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_initcall(irqrouter_init_sysfs); 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int __init acpi_pci_link_init(void) 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_noirq) 949d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_link.count = 0; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&acpi_link.entries); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0) 955d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 957d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(acpi_pci_link_init); 961