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 32c3146df2b735912eddd1d7c080c9377d5df0ae94Rafael J. Wysocki#include <linux/syscore_ops.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/spinlock.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pm.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 4036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar#include <linux/mutex.h> 415a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 428b48463f89429af408ff695244dc627e1acff4f7Lv Zheng#include <linux/acpi.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44c071b6040c442de247a537c977ea13f97b6df6f8Rashika#include "internal.h" 45c071b6040c442de247a537c977ea13f97b6df6f8Rashika 461c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas#define _COMPONENT ACPI_PCI_COMPONENT 47f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("pci_link"); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_CLASS "pci_irq_routing" 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_INFO "info" 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_STATUS "state" 521c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas#define ACPI_PCI_LINK_MAX_POSSIBLE 16 531c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas 544daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic int acpi_pci_link_add(struct acpi_device *device, 554daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki const struct acpi_device_id *not_used); 564daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic void acpi_pci_link_remove(struct acpi_device *device); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58c97adf9e7bebf17a86b95e2131bf9ba76c4857c7Márton Némethstatic const struct acpi_device_id link_device_ids[] = { 591ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger {"PNP0C0F", 0}, 601ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger {"", 0}, 611ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger}; 621ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger 634daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic struct acpi_scan_handler pci_link_handler = { 641ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger .ids = link_device_ids, 654daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki .attach = acpi_pci_link_add, 664daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki .detach = acpi_pci_link_remove, 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* 7087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * If a link is initialized, we never change its active and initialized 7187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * later even the link is disable. Instead, we just repick the active irq 7287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link_irq { 744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 active; /* Current IRQ */ 7550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore u8 triggering; /* All IRQs */ 761c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas u8 polarity; /* All IRQs */ 774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 resource_type; 784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 possible_count; 794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; 804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 initialized:1; 814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 reserved:7; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link { 855f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas struct list_head list; 861c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas struct acpi_device *device; 871c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas struct acpi_pci_link_irq irq; 881c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas int refcnt; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 915f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaasstatic LIST_HEAD(acpi_link_list); 92e5685b9d35c2cc0a98425b05df30cb837dd1e632Adrian Bunkstatic DEFINE_MUTEX(acpi_link_lock); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Link Device Management 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set context (link) possible list from resource list 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1011c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasstatic acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, 1021c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas void *context) 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10450dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt struct acpi_pci_link *link = context; 105c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas u32 i; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107eca008c8134df15262a0362623edb59902628c95Len Brown switch (resource->type) { 10850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_START_DEPENDENT: 1094a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas case ACPI_RESOURCE_TYPE_END_TAG: 110d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 11150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_IRQ: 1124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown { 1134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource_irq *p = &resource->data.irq; 11450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (!p || !p->interrupt_count) { 1154a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1164a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas "Blank _PRS IRQ resource\n")); 117d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; 12050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (i < p->interrupt_count 1214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) { 1224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!p->interrupts[i]) { 1234a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas printk(KERN_WARNING PREFIX 1244a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas "Invalid _PRS IRQ %d\n", 1254a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas 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 1424a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas "Blank _PRS 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]) { 1494a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas printk(KERN_WARNING PREFIX 1504a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas "Invalid _PRS IRQ %d\n", 1514a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas p->interrupts[i]); 1524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown continue; 1534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 1544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible[i] = p->interrupts[i]; 1554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count++; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.triggering = p->triggering; 15850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity = p->polarity; 15950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; 1604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown break; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1634a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n", 1644a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas resource->type); 165d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 168d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_CTRL_TERMINATE; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_possible(struct acpi_pci_link *link) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17567a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS, 1764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_link_check_possible, link); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 178a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS")); 179d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1824be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Found %d possible IRQs\n", 1844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count)); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 186d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasstatic acpi_status acpi_pci_link_check_current(struct acpi_resource *resource, 1901c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas void *context) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 192c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas int *irq = context; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 194eca008c8134df15262a0362623edb59902628c95Len Brown switch (resource->type) { 1954a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas case ACPI_RESOURCE_TYPE_START_DEPENDENT: 1964a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas case ACPI_RESOURCE_TYPE_END_TAG: 1974a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas return AE_OK; 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, 2074a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas "Blank _CRS 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 2234a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas "Blank _CRS 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: 2314a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n", 2324a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas resource->type); 233d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_OK; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2354a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas 236d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return AE_CTRL_TERMINATE; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run _CRS and set link->irq.active 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return value: 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 - success 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * !0 - failure 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_current(struct acpi_pci_link *link) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 249c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas acpi_status status; 2504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = 0; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = 0; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* in practice, status disabled is meaningless, ignore it */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict) { 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _STA, set link->device->status */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_status(link->device); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 2596468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Unable to read status\n"); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->device->status.enabled) { 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); 265d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Query and parse _CRS to get the current IRQ assignment. 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27367a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS, 2744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_link_check_current, &irq); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 276a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS")); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict && !irq) { 2826468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "_CRS returned 0\n"); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = irq; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 291d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_set(struct acpi_pci_link *link, int irq) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 296c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas int result; 297c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas acpi_status status; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 2994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource res; 3004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_resource end; 3014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } *resource; 3024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { 0, NULL }; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3046eca4b4ca168981d7648be371945c2a21f463a45Bjorn Helgaas if (!irq) 305d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30736bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); 3084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!resource) 309d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown buffer.length = sizeof(*resource) + 1; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = resource; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown switch (link->irq.resource_type) { 31550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_IRQ: 31650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.type = ACPI_RESOURCE_TYPE_IRQ; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.length = sizeof(struct acpi_resource); 31850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.triggering = link->irq.triggering; 31950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.polarity = 32050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity; 32150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (link->irq.triggering == ACPI_EDGE_SENSITIVE) 32250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = 3234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_EXCLUSIVE; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 32550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = ACPI_SHARED; 32650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.interrupt_count = 1; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.irq.interrupts[0] = irq; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 33050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 33150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.length = sizeof(struct acpi_resource); 3334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown resource->res.data.extended_irq.producer_consumer = 3344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_CONSUMER; 33550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.extended_irq.triggering = 33650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.triggering; 33750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.extended_irq.polarity = 33850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore link->irq.polarity; 33950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (link->irq.triggering == ACPI_EDGE_SENSITIVE) 34050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = 3414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_EXCLUSIVE; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 34350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.irq.sharable = ACPI_SHARED; 34450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->res.data.extended_irq.interrupt_count = 1; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->res.data.extended_irq.interrupts[0] = irq; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ignore resource_source, it's optional */ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3496468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -EINVAL; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; 355f084dbb939070281be7c882db63a4a428c51fcf4Yinghai Lu resource->end.length = sizeof(struct acpi_resource); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to set the resource */ 35867a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel status = acpi_set_current_resources(link->device->handle, &buffer); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for total failure */ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 362a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS")); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _STA, set device->status */ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_status(link->device); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3706468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Unable to read status\n"); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->device->status.enabled) { 374cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 375cece92969762b8ed7930d4e23008b76b06411deeLen Brown "%s [%s] disabled and referenced, BIOS bug\n", 376a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_device_name(link->device), 377cece92969762b8ed7930d4e23008b76b06411deeLen Brown acpi_device_bid(link->device)); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Query _CRS, set link->irq.active */ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_pci_link_get_current(link); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Is current setting not what we set? 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set link->irq.active 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active != irq) { 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * policy: when _CRS doesn't return what we just _SRS 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assume _SRS worked and override _CRS value. 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 395cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 396cece92969762b8ed7930d4e23008b76b06411deeLen Brown "%s [%s] BIOS reported IRQ %d, using IRQ %d\n", 397a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_device_name(link->device), 398cece92969762b8ed7930d4e23008b76b06411deeLen Brown acpi_device_bid(link->device), link->irq.active, irq); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = irq; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); 4034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 4044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 406d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Link IRQ Management 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Link Devices to move the PIRQs around to minimize sharing. 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the BIOS has already set to active. This is necessary because 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI has no automatic means of knowing what ISA IRQs are used. Note that 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the BIOS doesn't set a Link Device active, ACPI needs to program it 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even if acpi_irq_nobalance is set. 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A tables of penalties avoids directing PCI interrupts to well known 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA IRQs. Boot params are available to over-ride the default table: 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that are free for PCI use. 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_pci=n[,m] 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that should not be used for PCI: 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_isa=n[,m] 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that PCI IRQ routers have a list of possible IRQs, 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which may not include the IRQs this table says are available. 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since this heuristic can't tell the difference between a link 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that no device will attach to, vs. a link which may be shared 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by multiple active devices -- it is not optimal. 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If interrupt performance is that important, get an IO-APIC system 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pin dedicated to each device. Or for that matter, an MSI 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabled system. 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_IRQS 256 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_ISA_IRQ 16 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_AVAILABLE (0) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_POSSIBLE (16*16) 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_USING (16*16*16) 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_penalty[ACPI_MAX_IRQS] = { 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ 4584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ 4594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */ 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ 4671c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ 4681c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ 4691c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ 4701c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ 4714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown /* >IRQ15 */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint __init acpi_irq_penalty_init(void) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 476c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_pci_link *link; 477c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas int i; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update penalties to facilitate IRQ balancing. 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4825f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas list_for_each_entry(link, &acpi_link_list, list) { 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reflect the possible and active irqs in the penalty table -- 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * useful for breaking ties. 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.possible_count) { 4894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int penalty = 4904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_PCI_POSSIBLE / 4914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->irq.possible_count; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; i++) { 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) 4954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq. 4964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown possible[i]] += 4974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown penalty; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (link->irq.active) { 5014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq.active] += 5024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown PIRQ_PENALTY_PCI_POSSIBLE; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Add a penalty for the SCI */ 506cee324b145a1e5488b34191de670e5ed1d346ebbAlexey Starikovskiy acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING; 507d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51032836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaasstatic int acpi_irq_balance = -1; /* 0: static, 1: balance */ 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_allocate(struct acpi_pci_link *link) 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 5154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->irq.initialized) { 51887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (link->refcnt == 0) 51987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li /* This means the link is disabled but initialized */ 52087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li acpi_pci_link_set(link, link->irq.active); 521d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 52287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search for active IRQ in list of possible IRQs. 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; ++i) { 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active == link->irq.possible[i]) 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forget active IRQ that is not in possible list 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == link->irq.possible_count) { 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_strict) 536cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "_CRS %d not found" 537cece92969762b8ed7930d4e23008b76b06411deeLen Brown " in _PRS\n", link->irq.active); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.active = 0; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if active found, use it; else pick entry from end of possible list. 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5441c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas if (link->irq.active) 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.active; 5461c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas else 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.possible[link->irq.possible_count - 1]; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_irq_balance || !link->irq.active) { 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select the best IRQ. This is done in reverse to promote 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the use of IRQs 9, 10, 11, and >15. 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = (link->irq.possible_count - 1); i >= 0; i--) { 5554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (acpi_irq_penalty[irq] > 5564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_irq_penalty[link->irq.possible[i]]) 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = link->irq.possible[i]; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to enable the link device at this IRQ. */ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_pci_link_set(link, irq)) { 5636468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. " 5646468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown "Try pci=noacpi or acpi=off\n", 565a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_device_name(link->device), 5666468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown acpi_device_bid(link->device)); 567d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; 5704d9391557b68475b118ec7626607c37b14ae8c16Frank Seidel printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", 5714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_name(link->device), 5724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device), link->irq.active); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.initialized = 1; 576d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 58087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * acpi_pci_link_allocate_irq 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5841c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasint acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, 5851c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas int *polarity, char **name) 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 587c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas int result; 588c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_device *device; 589c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_pci_link *link; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_device(handle, &device); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 5936468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link device\n"); 594d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59750dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt link = acpi_driver_data(device); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) { 5996468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link context\n"); 600d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Support multiple index (IRQ) entries per Link Device */ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (index) { 6056468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid index %d\n", index); 606d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60936e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 61087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (acpi_pci_link_allocate(link)) { 61136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 612d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 61387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 6144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link->irq.active) { 61636e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 6176468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Link active IRQ is 0!\n"); 618d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->refcnt++; 62136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (triggering) 62450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *triggering = link->irq.triggering; 62550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore if (polarity) 62650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *polarity = link->irq.polarity; 6274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (name) 6284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown *name = acpi_device_bid(link->device); 62987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Link %s is referenced\n", 6314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device))); 632d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return (link->irq.active); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* 63687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * We don't change link's irq information here. After it is reenabled, we 63787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * continue use the info 63887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */ 6394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_link_free_irq(acpi_handle handle) 64087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 641c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_device *device; 642c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_pci_link *link; 6434be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status result; 64487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 64587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li result = acpi_bus_get_device(handle, &device); 64687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (result) { 6476468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link device\n"); 648d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 64987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65150dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt link = acpi_driver_data(device); 65287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (!link) { 6536468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid link context\n"); 654d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 65587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 65687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 65736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 65887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (!link->irq.initialized) { 65936e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 6606468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Link isn't initialized\n"); 661d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 66287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 663ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#ifdef FUTURE_USE 664ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li /* 665ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * The Link reference count allows us to _DISable an unused link 666ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * and suspend time, and set it again on resume. 667ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * However, 2.6.12 still has irq_router.resume 668ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * which blindly restores the link state. 669ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * So we disable the reference count method 670ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * to prevent duplicate acpi_pci_link_set() 671ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li * which would harm some systems 672ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li */ 6734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link->refcnt--; 674ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#endif 67587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Link %s is dereferenced\n", 6774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(link->device))); 67887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 6791c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas if (link->refcnt == 0) 680383d7a11c9989205db44c7f1be339e5097062f03donald.d.dugger@intel.com acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL); 6811c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas 68236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 683d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return (link->irq.active); 68487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 6854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Driver Interface 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6904daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic int acpi_pci_link_add(struct acpi_device *device, 6914daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki const struct acpi_device_id *not_used) 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 693c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas int result; 694c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_pci_link *link; 695c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas int i; 6964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int found = 0; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69836bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) 700d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->device = device; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); 705db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek device->driver_data = link; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_pci_link_get_possible(link); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* query and set link->irq.active */ 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_link_get_current(link); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7150dc070bb0242481a6100c95e5deaa07b267399a8Dan Aloni printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device), 7164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_device_bid(device)); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < link->irq.possible_count; i++) { 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link->irq.active == link->irq.possible[i]) { 719be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers printk(KERN_CONT " *%d", link->irq.possible[i]); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 1; 7214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } else 722be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers printk(KERN_CONT " %d", link->irq.possible[i]); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 725be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers printk(KERN_CONT ")"); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!found) 728be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers printk(KERN_CONT " *%d", link->irq.active); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!link->device->status.enabled) 731be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers printk(KERN_CONT ", disabled."); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 733be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers printk(KERN_CONT "\n"); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7355f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas list_add_tail(&link->list, &acpi_link_list); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable all links -- to be activated on use */ 739383d7a11c9989205db44c7f1be339e5097062f03donald.d.dugger@intel.com acpi_evaluate_object(device->handle, "_DIS", NULL, NULL); 74036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7454daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki return result < 0 ? result : 1; 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_resume(struct acpi_pci_link *link) 749697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds{ 750697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds if (link->refcnt && link->irq.active && link->irq.initialized) 751d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return (acpi_pci_link_set(link, link->irq.active)); 7521c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas 7531c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas return 0; 754697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds} 755697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds 756c3146df2b735912eddd1d7c080c9377d5df0ae94Rafael J. Wysockistatic void irqrouter_resume(void) 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 758c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_pci_link *link; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7605f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas list_for_each_entry(link, &acpi_link_list, list) { 761697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds acpi_pci_link_resume(link); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7654daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic void acpi_pci_link_remove(struct acpi_device *device) 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 767c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas struct acpi_pci_link *link; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76950dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt link = acpi_driver_data(device); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_lock(&acpi_link_lock); 7725f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas list_del(&link->list); 77336e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar mutex_unlock(&acpi_link_lock); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify acpi_irq_penalty[] from cmdline 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_penalty_update(char *str, int used) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) { 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown retval = get_option(&str, &irq); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* no number found */ 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 7964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 797fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas if (irq >= ARRAY_SIZE(acpi_irq_penalty)) 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (used) 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 2) /* no next number */ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'd like PNP to call this routine for the 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single ISA_USED value for each legacy device. 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But instead it calls us with each POSSIBLE setting. 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is no ISA_POSSIBLE weight, so we simply use 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the (small) PCI_USING penalty. 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 818c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Livoid acpi_penalize_isa_irq(int irq, int active) 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 820fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) { 821fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas if (active) 822fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; 823fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas else 824fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; 825fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas } 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to reserve additional IRQs for use by ISA 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_isa=5 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Useful for telling ACPI how not to interfere with your ISA sound card. 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_isa(char *str) 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acpi_irq_penalty_update(str, 1); 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_isa=", acpi_irq_isa); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to free additional IRQs for use by PCI 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_pci=7,15 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing. 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_pci(char *str) 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acpi_irq_penalty_update(str, 0); 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_pci=", acpi_irq_pci); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_nobalance_set(char *str) 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_balance = 0; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_nobalance", acpi_irq_nobalance_set); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8608a383ef0be01e0e6e84c85f8bf35e4e6fcfb8981Roel Kluinstatic int __init acpi_irq_balance_set(char *str) 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_irq_balance = 1; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8664be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown__setup("acpi_irq_balance", acpi_irq_balance_set); 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 868c3146df2b735912eddd1d7c080c9377d5df0ae94Rafael J. Wysockistatic struct syscore_ops irqrouter_syscore_ops = { 8694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .resume = irqrouter_resume, 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8724daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockivoid __init acpi_pci_link_init(void) 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_noirq) 8754daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki return; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87732836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas if (acpi_irq_balance == -1) { 87832836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas /* no command line switch: enable balancing in IOAPIC mode */ 87932836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) 88032836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas acpi_irq_balance = 1; 88132836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas else 88232836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas acpi_irq_balance = 0; 88332836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas } 8844daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki register_syscore_ops(&irqrouter_syscore_ops); 8854daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki acpi_scan_add_handler(&pci_link_handler); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 887