pci_link.c revision eca008c8134df15262a0362623edb59902628c95
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> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT ACPI_PCI_COMPONENT 464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen BrownACPI_MODULE_NAME("pci_link") 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_CLASS "pci_irq_routing" 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_HID "PNP0C0F" 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_INFO "info" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_STATUS "state" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_MAX_POSSIBLE 16 544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_add(struct acpi_device *device); 554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_remove(struct acpi_device *device, int type); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_pci_link_driver = { 584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .name = ACPI_PCI_LINK_DRIVER_NAME, 594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .class = ACPI_PCI_LINK_CLASS, 604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .ids = ACPI_PCI_LINK_HID, 614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .ops = { 624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .add = acpi_pci_link_add, 634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .remove = acpi_pci_link_remove, 644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown }, 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* 6887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * If a link is initialized, we never change its active and initialized 6987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * later even the link is disable. Instead, we just repick the active irq 7087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link_irq { 724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 active; /* Current IRQ */ 734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 edge_level; /* All IRQs */ 744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 active_high_low; /* All IRQs */ 754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 resource_type; 764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 possible_count; 774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; 784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 initialized:1; 794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 reserved:7; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link { 834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head node; 844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device; 854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_handle handle; 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; 9487bec66b9691522414862dd8d41e430b063735efDavid Shaohua LiDECLARE_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 ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible"); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111eca008c8134df15262a0362623edb59902628c95Len Brown switch (resource->type) { 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_START_DPF: 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_ACPI_STATUS(AE_OK); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_IRQ: 1154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 1164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_irq *p = &resource->data.irq; 1174be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p || !p->number_of_interrupts) { 1184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Blank IRQ resource\n")); 1204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown return_ACPI_STATUS(AE_OK); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; 1234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown (i < p->number_of_interrupts 1244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { 1254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p->interrupts[i]) { 1264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Invalid IRQ %d\n", 1284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown p->interrupts[i])); 1294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown continue; 1304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible[i] = p->interrupts[i]; 1324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count++; 1334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.edge_level = p->edge_level; 1354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.active_high_low = p->active_high_low; 1364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.resource_type = ACPI_RSTYPE_IRQ; 1374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_EXT_IRQ: 1404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 1414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_ext_irq *p = 1424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown &resource->data.extended_irq; 1434be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p || !p->number_of_interrupts) { 1444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Blank EXT IRQ resource\n")); 1464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown return_ACPI_STATUS(AE_OK); 1474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; 1494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown (i < p->number_of_interrupts 1504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { 1514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p->interrupts[i]) { 1524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_WARN, 1534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Invalid IRQ %d\n", 1544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown p->interrupts[i])); 1554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown continue; 1564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible[i] = p->interrupts[i]; 1584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count++; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.edge_level = p->edge_level; 1614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.active_high_low = p->active_high_low; 1624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.resource_type = ACPI_RSTYPE_EXT_IRQ; 1634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1664be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1674be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Resource is not an IRQ entry\n")); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_ACPI_STATUS(AE_OK); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_ACPI_STATUS(AE_CTRL_TERMINATE); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_possible(struct acpi_pci_link *link) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible"); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-EINVAL); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_resources(link->handle, METHOD_NAME__PRS, 1844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_link_check_possible, link); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n")); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-ENODEV); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Found %d possible IRQs\n", 1924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count)); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_link_check_current(struct acpi_resource *resource, void *context) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int *irq = (int *)context; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_check_current"); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 204eca008c8134df15262a0362623edb59902628c95Len Brown switch (resource->type) { 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_IRQ: 2064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 2074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_irq *p = &resource->data.irq; 2084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p || !p->number_of_interrupts) { 2094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* 2104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * IRQ descriptors may have no IRQ# bits set, 2114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * particularly those those w/ _STA disabled 2124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown */ 2134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Blank IRQ resource\n")); 2154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown return_ACPI_STATUS(AE_OK); 2164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 2174be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *irq = p->interrupts[0]; 2184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_EXT_IRQ: 2214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 2224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_ext_irq *p = 2234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown &resource->data.extended_irq; 2244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p || !p->number_of_interrupts) { 2254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* 2264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * extended IRQ descriptors must 2274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown * return at least 1 IRQ 2284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown */ 2294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_WARN, 2304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Blank EXT IRQ resource\n")); 2314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown return_ACPI_STATUS(AE_OK); 2324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 2334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *irq = p->interrupts[0]; 2344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Resource isn't an IRQ\n")); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_ACPI_STATUS(AE_OK); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_ACPI_STATUS(AE_CTRL_TERMINATE); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run _CRS and set link->irq.active 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return value: 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 - success 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * !0 - failure 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_current(struct acpi_pci_link *link) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 2534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 2544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = 0; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_get_current"); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link || !link->handle) 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-EINVAL); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = 0; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* in practice, status disabled is meaningless, ignore it */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict) { 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _STA, set link->device->status */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_status(link->device); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 2684be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 2694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Unable to read status\n")); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->device->status.enabled) { 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Query and parse _CRS to get the current IRQ assignment. 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_resources(link->handle, METHOD_NAME__CRS, 2844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_link_check_current, &irq); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n")); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict && !irq) { 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n")); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = irq; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(result); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_set(struct acpi_pci_link *link, int irq) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 3074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 3094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource res; 3104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource end; 3114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } *resource; 3124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { 0, NULL }; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_set"); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link || !irq) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-EINVAL); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource = kmalloc(sizeof(*resource) + 1, GFP_KERNEL); 3204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!resource) 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-ENOMEM); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown memset(resource, 0, sizeof(*resource) + 1); 3244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown buffer.length = sizeof(*resource) + 1; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = resource; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown switch (link->irq.resource_type) { 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_IRQ: 329eca008c8134df15262a0362623edb59902628c95Len Brown resource->res.type = ACPI_RSTYPE_IRQ; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.length = sizeof(struct acpi_resource); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.edge_level = link->irq.edge_level; 3324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.irq.active_high_low = 3334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.active_high_low; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.edge_level == ACPI_EDGE_SENSITIVE) 3354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.irq.shared_exclusive = 3364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_EXCLUSIVE; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.shared_exclusive = ACPI_SHARED; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.number_of_interrupts = 1; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.interrupts[0] = irq; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_RSTYPE_EXT_IRQ: 344eca008c8134df15262a0362623edb59902628c95Len Brown resource->res.type = ACPI_RSTYPE_EXT_IRQ; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.length = sizeof(struct acpi_resource); 3464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.extended_irq.producer_consumer = 3474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_CONSUMER; 3484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.extended_irq.edge_level = 3494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.edge_level; 3504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.extended_irq.active_high_low = 3514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.active_high_low; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.edge_level == ACPI_EDGE_SENSITIVE) 3534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.irq.shared_exclusive = 3544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_EXCLUSIVE; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.shared_exclusive = ACPI_SHARED; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.extended_irq.number_of_interrupts = 1; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.extended_irq.interrupts[0] = irq; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ignore resource_source, it's optional */ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("ACPI BUG: resource_type %d\n", link->irq.resource_type); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -EINVAL; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 367eca008c8134df15262a0362623edb59902628c95Len Brown resource->end.type = ACPI_RSTYPE_END_TAG; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to set the resource */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_set_current_resources(link->handle, &buffer); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for total failure */ 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n")); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _STA, set device->status */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_status(link->device); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->device->status.enabled) { 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING PREFIX 3874be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "%s [%s] disabled and referenced, BIOS bug.\n", 3884be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_name(link->device), 3894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device)); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _CRS, set link->irq.active */ 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_pci_link_get_current(link); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Is current setting not what we set? 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set link->irq.active 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active != irq) { 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * policy: when _CRS doesn't return what we just _SRS 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assume _SRS worked and override _CRS value. 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown printk(KERN_WARNING PREFIX 4084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "%s [%s] BIOS reported IRQ %d, using IRQ %d\n", 4094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_name(link->device), 4104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device), link->irq.active, irq); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = irq; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); 4154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 4164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(result); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Link IRQ Management 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Link Devices to move the PIRQs around to minimize sharing. 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the BIOS has already set to active. This is necessary because 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI has no automatic means of knowing what ISA IRQs are used. Note that 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the BIOS doesn't set a Link Device active, ACPI needs to program it 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even if acpi_irq_nobalance is set. 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A tables of penalties avoids directing PCI interrupts to well known 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA IRQs. Boot params are available to over-ride the default table: 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that are free for PCI use. 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_pci=n[,m] 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that should not be used for PCI: 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_isa=n[,m] 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that PCI IRQ routers have a list of possible IRQs, 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which may not include the IRQs this table says are available. 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since this heuristic can't tell the difference between a link 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that no device will attach to, vs. a link which may be shared 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by multiple active devices -- it is not optimal. 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If interrupt performance is that important, get an IO-APIC system 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pin dedicated to each device. Or for that matter, an MSI 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabled system. 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_IRQS 256 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_ISA_IRQ 16 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_AVAILABLE (0) 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_POSSIBLE (16*16) 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_USING (16*16*16) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_penalty[ACPI_MAX_IRQS] = { 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ 4704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ 4714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ 4834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* >IRQ15 */ 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint __init acpi_irq_penalty_init(void) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4884be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head *node = NULL; 4894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 4904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i = 0; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_irq_penalty_init"); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update penalties to facilitate IRQ balancing. 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(node, &acpi_link.entries) { 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = list_entry(node, struct acpi_pci_link, node); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 5014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 5024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Invalid link context\n")); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reflect the possible and active irqs in the penalty table -- 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * useful for breaking ties. 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.possible_count) { 5114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int penalty = 5124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_PCI_POSSIBLE / 5134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; i++) { 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) 5174be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq. 5184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown possible[i]] += 5194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown penalty; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (link->irq.active) { 5234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq.active] += 5244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_PCI_POSSIBLE; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Add a penalty for the SCI */ 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_balance; /* 0: static, 1: balance */ 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_allocate(struct acpi_pci_link *link) 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 5384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->irq.initialized) { 54387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->refcnt == 0) 54487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li /* This means the link is disabled but initialized */ 54587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li acpi_pci_link_set(link, link->irq.active); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 54787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search for active IRQ in list of possible IRQs. 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; ++i) { 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active == link->irq.possible[i]) 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forget active IRQ that is not in possible list 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == link->irq.possible_count) { 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING PREFIX "_CRS %d not found" 5624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown " in _PRS\n", link->irq.active); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = 0; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if active found, use it; else pick entry from end of possible list. 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active) { 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.active; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.possible[link->irq.possible_count - 1]; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_irq_balance || !link->irq.active) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select the best IRQ. This is done in reverse to promote 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the use of IRQs 9, 10, 11, and >15. 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = (link->irq.possible_count - 1); i >= 0; i--) { 5814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (acpi_irq_penalty[irq] > 5824be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq.possible[i]]) 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.possible[i]; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to enable the link device at this IRQ. */ 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_pci_link_set(link, irq)) { 5894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown printk(PREFIX 5904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n" 5914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Try pci=noacpi or acpi=off\n", 5924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_name(link->device), 5934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device)); 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-ENODEV); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; 5974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown printk(PREFIX "%s [%s] enabled at IRQ %d\n", 5984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_name(link->device), 5994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device), link->irq.active); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.initialized = 1; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 60887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * acpi_pci_link_allocate_irq 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 6144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_link_allocate_irq(acpi_handle handle, 6154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int index, 6164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int *edge_level, int *active_high_low, char **name) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 6194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device = NULL; 6204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_FUNCTION_TRACE("acpi_pci_link_allocate_irq"); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_device(handle, &device); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n")); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-1); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link = (struct acpi_pci_link *)acpi_driver_data(device); 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-1); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Support multiple index (IRQ) entries per Link Device */ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (index) { 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index)); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-1); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li down(&acpi_link_lock); 64387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (acpi_pci_link_allocate(link)) { 64487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-1); 64687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 6474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->irq.active) { 64987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n")); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-1); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->refcnt++; 65487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (edge_level) 6574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *edge_level = link->irq.edge_level; 6584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (active_high_low) 6594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *active_high_low = link->irq.active_high_low; 6604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (name) 6614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *name = acpi_device_bid(link->device); 66287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Link %s is referenced\n", 6644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device))); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(link->irq.active); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* 66987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * We don't change link's irq information here. After it is reenabled, we 67087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * continue use the info 67187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */ 6724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_link_free_irq(acpi_handle handle) 67387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 6744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device = NULL; 6754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 6764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status result; 67787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 67887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_FUNCTION_TRACE("acpi_pci_link_free_irq"); 67987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 68087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li result = acpi_bus_get_device(handle, &device); 68187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (result) { 68287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n")); 68387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li return_VALUE(-1); 68487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link = (struct acpi_pci_link *)acpi_driver_data(device); 68787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (!link) { 68887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); 68987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li return_VALUE(-1); 69087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 69187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 69287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li down(&acpi_link_lock); 69387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (!link->irq.initialized) { 69487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 69587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n")); 69687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li return_VALUE(-1); 69787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 698ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#ifdef FUTURE_USE 699ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li /* 700ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * The Link reference count allows us to _DISable an unused link 701ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * and suspend time, and set it again on resume. 702ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * However, 2.6.12 still has irq_router.resume 703ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * which blindly restores the link state. 704ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * So we disable the reference count method 705ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * to prevent duplicate acpi_pci_link_set() 706ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * which would harm some systems 707ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li */ 7084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->refcnt--; 709ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#endif 71087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, 7114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Link %s is dereferenced\n", 7124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device))); 71387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 71487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->refcnt == 0) { 71587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL); 71687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 71787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 71887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li return_VALUE(link->irq.active); 71987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 7204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Driver Interface 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_add(struct acpi_device *device) 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 7284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 7294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i = 0; 7304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int found = 0; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_add"); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device) 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-EINVAL); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-ENOMEM); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(link, 0, sizeof(struct acpi_pci_link)); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->device = device; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->handle = device->handle; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_driver_data(device) = link; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li down(&acpi_link_lock); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_pci_link_get_possible(link); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* query and set link->irq.active */ 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_link_get_current(link); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), 7574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(device)); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; i++) { 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active == link->irq.possible[i]) { 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" *%d", link->irq.possible[i]); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 1; 7624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } else 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %d", link->irq.possible[i]); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(")"); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!found) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" *%d", link->irq.active); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!link->device->status.enabled) 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", disabled."); 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Acquire/release lock */ 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&link->node, &acpi_link.entries); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_link.count++; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable all links -- to be activated on use */ 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL); 78387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(result); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_resume(struct acpi_pci_link *link) 792697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds{ 793697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); 794697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds 795697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds if (link->refcnt && link->irq.active && link->irq.initialized) 796697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds return_VALUE(acpi_pci_link_set(link, link->irq.active)); 797697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds else 798697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds return_VALUE(0); 799697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds} 800697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds 80111e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li/* 80211e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li * FIXME: this is a workaround to avoid nasty warning. It will be removed 80311e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li * after every device calls pci_disable_device in .resume. 80411e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li */ 80511e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Liint acpi_in_resume; 8064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int irqrouter_resume(struct sys_device *dev) 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head *node = NULL; 8094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_link *link = NULL; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds ACPI_FUNCTION_TRACE("irqrouter_resume"); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81311e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li acpi_in_resume = 1; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(node, &acpi_link.entries) { 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = list_entry(node, struct acpi_pci_link, node); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 81787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 8184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Invalid link context\n")); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 821697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds acpi_pci_link_resume(link); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 82311e981f1e02c2a36465cbb208b21cb8b6480f399David Shaohua Li acpi_in_resume = 0; 824697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds return_VALUE(0); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_remove(struct acpi_device *device, int type) 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_pci_link *link = NULL; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_remove"); 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device || !acpi_driver_data(device)) 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-EINVAL); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link = (struct acpi_pci_link *)acpi_driver_data(device); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li down(&acpi_link_lock); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&link->node); 84087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li up(&acpi_link_lock); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify acpi_irq_penalty[] from cmdline 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_penalty_update(char *str, int used) 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) { 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq; 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown retval = get_option(&str, &irq); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* no number found */ 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8654be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq >= ACPI_MAX_IRQS) 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (used) 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 2) /* no next number */ 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'd like PNP to call this routine for the 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single ISA_USED value for each legacy device. 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But instead it calls us with each POSSIBLE setting. 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is no ISA_POSSIBLE weight, so we simply use 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the (small) PCI_USING penalty. 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 887c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Livoid acpi_penalize_isa_irq(int irq, int active) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 889c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li if (active) 890c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; 891c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li else 892c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Li acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to reserve additional IRQs for use by ISA 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_isa=5 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Useful for telling ACPI how not to interfere with your ISA sound card. 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_isa(char *str) 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acpi_irq_penalty_update(str, 1); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_isa=", acpi_irq_isa); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to free additional IRQs for use by PCI 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_pci=7,15 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing. 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_pci(char *str) 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acpi_irq_penalty_update(str, 0); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_pci=", acpi_irq_pci); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_nobalance_set(char *str) 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_balance = 0; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_nobalance", acpi_irq_nobalance_set); 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpi_irq_balance_set(char *str) 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_balance = 1; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown__setup("acpi_irq_balance", acpi_irq_balance_set); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* FIXME: we will remove this interface after all drivers call pci_disable_device */ 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sysdev_class irqrouter_sysdev_class = { 9374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown set_kset_name("irqrouter"), 9384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .resume = irqrouter_resume, 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sys_device device_irqrouter = { 9424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .id = 0, 9434be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .cls = &irqrouter_sysdev_class, 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init irqrouter_init_sysfs(void) 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("irqrouter_init_sysfs"); 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_disabled || acpi_noirq) 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = sysdev_class_register(&irqrouter_sysdev_class); 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!error) 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = sysdev_register(&device_irqrouter); 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(error); 9604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown} 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_initcall(irqrouter_init_sysfs); 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int __init acpi_pci_link_init(void) 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_FUNCTION_TRACE("acpi_pci_link_init"); 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_noirq) 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_link.count = 0; 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&acpi_link.entries); 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0) 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(-ENODEV); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return_VALUE(0); 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(acpi_pci_link_init); 981