pci_link.c revision 4daeaf68379f75dedd120582add5206c7c5ad72e
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>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#define PREFIX "ACPI: "
47a192a9580bcc41692be1f36b77c3b681827f566aLen Brown
481c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas#define _COMPONENT			ACPI_PCI_COMPONENT
49f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("pci_link");
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_INFO		"info"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_PCI_LINK_FILE_STATUS	"state"
541c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas#define ACPI_PCI_LINK_MAX_POSSIBLE	16
551c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas
564daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic int acpi_pci_link_add(struct acpi_device *device,
574daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki			     const struct acpi_device_id *not_used);
584daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic void acpi_pci_link_remove(struct acpi_device *device);
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60c97adf9e7bebf17a86b95e2131bf9ba76c4857c7Márton Némethstatic const struct acpi_device_id link_device_ids[] = {
611ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"PNP0C0F", 0},
621ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"", 0},
631ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger};
641ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger
654daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic struct acpi_scan_handler pci_link_handler = {
661ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	.ids = link_device_ids,
674daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki	.attach = acpi_pci_link_add,
684daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki	.detach = acpi_pci_link_remove,
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/*
7287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * If a link is initialized, we never change its active and initialized
7387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * later even the link is disable. Instead, we just repick the active irq
7487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link_irq {
764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 active;		/* Current IRQ */
7750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	u8 triggering;		/* All IRQs */
781c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	u8 polarity;		/* All IRQs */
794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 resource_type;
804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 possible_count;
814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
824be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 initialized:1;
834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 reserved:7;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link {
875f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas	struct list_head		list;
881c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	struct acpi_device		*device;
891c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	struct acpi_pci_link_irq	irq;
901c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	int				refcnt;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
935f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaasstatic LIST_HEAD(acpi_link_list);
94e5685b9d35c2cc0a98425b05df30cb837dd1e632Adrian Bunkstatic DEFINE_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 */
1031c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasstatic acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
1041c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas						void *context)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10650dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_pci_link *link = context;
107c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	u32 i;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109eca008c8134df15262a0362623edb59902628c95Len Brown	switch (resource->type) {
11050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
1114a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas	case ACPI_RESOURCE_TYPE_END_TAG:
112d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return AE_OK;
11350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_IRQ:
1144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
1154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			struct acpi_resource_irq *p = &resource->data.irq;
11650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
1174a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1184a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas						  "Blank _PRS IRQ resource\n"));
119d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			for (i = 0;
12250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			     (i < p->interrupt_count
1234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
1244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				if (!p->interrupts[i]) {
1254a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					printk(KERN_WARNING PREFIX
1264a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       "Invalid _PRS IRQ %d\n",
1274a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       p->interrupts[i]);
1284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					continue;
1294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				}
1304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible[i] = p->interrupts[i];
1314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible_count++;
1324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
13350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.triggering = p->triggering;
13450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.polarity = p->polarity;
13550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.resource_type = ACPI_RESOURCE_TYPE_IRQ;
1364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
14050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			struct acpi_resource_extended_irq *p =
1414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    &resource->data.extended_irq;
14250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
143cece92969762b8ed7930d4e23008b76b06411deeLen Brown				printk(KERN_WARNING PREFIX
1444a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					      "Blank _PRS EXT IRQ resource\n");
145d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
1464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
1474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			for (i = 0;
14850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			     (i < p->interrupt_count
1494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
1504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				if (!p->interrupts[i]) {
1514a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					printk(KERN_WARNING PREFIX
1524a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       "Invalid _PRS IRQ %d\n",
1534a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       p->interrupts[i]);
1544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					continue;
1554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				}
1564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible[i] = p->interrupts[i];
1574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible_count++;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.triggering = p->triggering;
16050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.polarity = p->polarity;
16150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
1624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1654a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n",
1664a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		       resource->type);
167d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return AE_OK;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
170d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return AE_CTRL_TERMINATE;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_possible(struct acpi_pci_link *link)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17767a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel	status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
1784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				     acpi_pci_link_check_possible, link);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
180a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
181d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  "Found %d possible IRQs\n",
1864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  link->irq.possible_count));
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasstatic acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
1921c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas					       void *context)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
194c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	int *irq = context;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
196eca008c8134df15262a0362623edb59902628c95Len Brown	switch (resource->type) {
1974a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
1984a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas	case ACPI_RESOURCE_TYPE_END_TAG:
1994a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		return AE_OK;
20050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_IRQ:
2014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
2024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			struct acpi_resource_irq *p = &resource->data.irq;
20350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
2044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				/*
2054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * IRQ descriptors may have no IRQ# bits set,
2064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * particularly those those w/ _STA disabled
2074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 */
2084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
2094a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas						  "Blank _CRS IRQ resource\n"));
210d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
2114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
2124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			*irq = p->interrupts[0];
2134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
2164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
21750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			struct acpi_resource_extended_irq *p =
2184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    &resource->data.extended_irq;
21950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
2204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				/*
2214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * extended IRQ descriptors must
2224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * return at least 1 IRQ
2234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 */
224cece92969762b8ed7930d4e23008b76b06411deeLen Brown				printk(KERN_WARNING PREFIX
2254a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					      "Blank _CRS EXT IRQ resource\n");
226d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
2274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
2284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			*irq = p->interrupts[0];
2294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
231d4ec6c7cc9a15a7a529719bc3b84f46812f9842eLen Brown		break;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2334a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n",
2344a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		       resource->type);
235d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return AE_OK;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2374a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas
238d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return AE_CTRL_TERMINATE;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run _CRS and set link->irq.active
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return value:
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 - success
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * !0 - failure
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_current(struct acpi_pci_link *link)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
251c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	acpi_status status;
2524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int irq = 0;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->irq.active = 0;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* in practice, status disabled is meaningless, ignore it */
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_strict) {
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Query _STA, set link->device->status */
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = acpi_bus_get_status(link->device);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result) {
2616468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			printk(KERN_ERR PREFIX "Unable to read status\n");
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto end;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!link->device->status.enabled) {
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
267d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return 0;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Query and parse _CRS to get the current IRQ assignment.
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27567a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel	status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
2764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				     acpi_pci_link_check_current, &irq);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
278a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_strict && !irq) {
2846468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "_CRS returned 0\n");
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->irq.active = irq;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
293d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
298c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	int result;
299c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	acpi_status status;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct {
3014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		struct acpi_resource res;
3024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		struct acpi_resource end;
3034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	} *resource;
3044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_buffer buffer = { 0, NULL };
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3066eca4b4ca168981d7648be371945c2a21f463a45Bjorn Helgaas	if (!irq)
307d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30936bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
3104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	if (!resource)
311d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	buffer.length = sizeof(*resource) + 1;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer.pointer = resource;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	switch (link->irq.resource_type) {
31750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_IRQ:
31850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.type = ACPI_RESOURCE_TYPE_IRQ;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.length = sizeof(struct acpi_resource);
32050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.irq.triggering = link->irq.triggering;
32150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.irq.polarity =
32250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		    link->irq.polarity;
32350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
32450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable =
3254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    ACPI_EXCLUSIVE;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
32750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable = ACPI_SHARED;
32850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.irq.interrupt_count = 1;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.data.irq.interrupts[0] = irq;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
33250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
33350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.length = sizeof(struct acpi_resource);
3354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		resource->res.data.extended_irq.producer_consumer =
3364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    ACPI_CONSUMER;
33750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.extended_irq.triggering =
33850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		    link->irq.triggering;
33950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.extended_irq.polarity =
34050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		    link->irq.polarity;
34150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
34250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable =
3434be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    ACPI_EXCLUSIVE;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
34550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable = ACPI_SHARED;
34650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.extended_irq.interrupt_count = 1;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.data.extended_irq.interrupts[0] = irq;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ignore resource_source, it's optional */
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3516468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -EINVAL;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
35650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attempt to set the resource */
35967a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel	status = acpi_set_current_resources(link->device->handle, &buffer);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for total failure */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
363a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Query _STA, set device->status */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_bus_get_status(link->device);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
3716468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Unable to read status\n");
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link->device->status.enabled) {
375cece92969762b8ed7930d4e23008b76b06411deeLen Brown		printk(KERN_WARNING PREFIX
376cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      "%s [%s] disabled and referenced, BIOS bug\n",
377a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger			      acpi_device_name(link->device),
378cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      acpi_device_bid(link->device));
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Query _CRS, set link->irq.active */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_pci_link_get_current(link);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Is current setting not what we set?
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set link->irq.active
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (link->irq.active != irq) {
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * policy: when _CRS doesn't return what we just _SRS
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * assume _SRS worked and override _CRS value.
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
396cece92969762b8ed7930d4e23008b76b06411deeLen Brown		printk(KERN_WARNING PREFIX
397cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
398a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger			      acpi_device_name(link->device),
399cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      acpi_device_bid(link->device), link->irq.active, irq);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link->irq.active = irq;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
4044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
4054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(resource);
407d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                            PCI Link IRQ Management
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Link Devices to move the PIRQs around to minimize sharing.
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the BIOS has already set to active.  This is necessary because
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI has no automatic means of knowing what ISA IRQs are used.  Note that
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the BIOS doesn't set a Link Device active, ACPI needs to program it
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even if acpi_irq_nobalance is set.
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A tables of penalties avoids directing PCI interrupts to well known
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA IRQs. Boot params are available to over-ride the default table:
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that are free for PCI use.
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_pci=n[,m]
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that should not be used for PCI:
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_isa=n[,m]
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that PCI IRQ routers have a list of possible IRQs,
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which may not include the IRQs this table says are available.
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since this heuristic can't tell the difference between a link
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that no device will attach to, vs. a link which may be shared
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by multiple active devices -- it is not optimal.
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If interrupt performance is that important, get an IO-APIC system
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pin dedicated to each device.  Or for that matter, an MSI
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabled system.
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_IRQS		256
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_ISA_IRQ	16
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_AVAILABLE	(0)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_POSSIBLE	(16*16)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_USING		(16*16*16)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_TYPICAL	(16*16*16*16)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_USED		(16*16*16*16*16)
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_ALWAYS		(16*16*16*16*16*16)
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_penalty[ACPI_MAX_IRQS] = {
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
4594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
4604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ5 sometimes SoundBlaster */
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ6 */
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ7 parallel, spurious */
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ8 rtc, sometimes */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ9  PCI, often acpi */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ10 PCI */
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ11 PCI */
4681c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ12 mouse */
4691c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ13 fpe, sometimes */
4701c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ14 ide0 */
4711c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ15 ide1 */
4724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	/* >IRQ15 */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint __init acpi_irq_penalty_init(void)
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
477c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_pci_link *link;
478c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	int i;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Update penalties to facilitate IRQ balancing.
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4835f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas	list_for_each_entry(link, &acpi_link_list, list) {
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * reflect the possible and active irqs in the penalty table --
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * useful for breaking ties.
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (link->irq.possible_count) {
4904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			int penalty =
4914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    PIRQ_PENALTY_PCI_POSSIBLE /
4924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    link->irq.possible_count;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < link->irq.possible_count; i++) {
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
4964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					acpi_irq_penalty[link->irq.
4974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown							 possible[i]] +=
4984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					    penalty;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (link->irq.active) {
5024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			acpi_irq_penalty[link->irq.active] +=
5034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    PIRQ_PENALTY_PCI_POSSIBLE;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Add a penalty for the SCI */
507cee324b145a1e5488b34191de670e5ed1d346ebbAlexey Starikovskiy	acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
508d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51132836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaasstatic int acpi_irq_balance = -1;	/* 0: static, 1: balance */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_allocate(struct acpi_pci_link *link)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int irq;
5164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int i;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (link->irq.initialized) {
51987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li		if (link->refcnt == 0)
52087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li			/* This means the link is disabled but initialized */
52187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li			acpi_pci_link_set(link, link->irq.active);
522d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
52387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * search for active IRQ in list of possible IRQs.
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < link->irq.possible_count; ++i) {
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (link->irq.active == link->irq.possible[i])
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * forget active IRQ that is not in possible list
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == link->irq.possible_count) {
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (acpi_strict)
537cece92969762b8ed7930d4e23008b76b06411deeLen Brown			printk(KERN_WARNING PREFIX "_CRS %d not found"
538cece92969762b8ed7930d4e23008b76b06411deeLen Brown				      " in _PRS\n", link->irq.active);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link->irq.active = 0;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if active found, use it; else pick entry from end of possible list.
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5451c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	if (link->irq.active)
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = link->irq.active;
5471c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	else
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = link->irq.possible[link->irq.possible_count - 1];
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_irq_balance || !link->irq.active) {
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Select the best IRQ.  This is done in reverse to promote
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the use of IRQs 9, 10, 11, and >15.
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = (link->irq.possible_count - 1); i >= 0; i--) {
5564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			if (acpi_irq_penalty[irq] >
5574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    acpi_irq_penalty[link->irq.possible[i]])
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				irq = link->irq.possible[i];
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attempt to enable the link device at this IRQ. */
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_pci_link_set(link, irq)) {
5646468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
5656468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			    "Try pci=noacpi or acpi=off\n",
566a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger			    acpi_device_name(link->device),
5676468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			    acpi_device_bid(link->device));
568d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
5714d9391557b68475b118ec7626607c37b14ae8c16Frank Seidel		printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
5724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		       acpi_device_name(link->device),
5734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		       acpi_device_bid(link->device), link->irq.active);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->irq.initialized = 1;
577d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
58187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * acpi_pci_link_allocate_irq
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5851c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasint acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
5861c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas			       int *polarity, char **name)
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
588c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	int result;
589c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_device *device;
590c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_pci_link *link;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_bus_get_device(handle, &device);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
5946468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link device\n");
595d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59850dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	link = acpi_driver_data(device);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link) {
6006468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link context\n");
601d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: Support multiple index (IRQ) entries per Link Device */
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (index) {
6066468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid index %d\n", index);
607d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
61187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (acpi_pci_link_allocate(link)) {
61236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar		mutex_unlock(&acpi_link_lock);
613d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
61487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
6154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link->irq.active) {
61736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar		mutex_unlock(&acpi_link_lock);
6186468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Link active IRQ is 0!\n");
619d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	link->refcnt++;
62236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	if (triggering)
62550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		*triggering = link->irq.triggering;
62650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	if (polarity)
62750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		*polarity = link->irq.polarity;
6284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	if (name)
6294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		*name = acpi_device_bid(link->device);
63087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
6314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  "Link %s is referenced\n",
6324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  acpi_device_bid(link->device)));
633d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return (link->irq.active);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/*
63787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * We don't change link's irq information here.  After it is reenabled, we
63887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * continue use the info
63987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */
6404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_link_free_irq(acpi_handle handle)
64187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{
642c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_device *device;
643c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_pci_link *link;
6444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status result;
64587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
64687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	result = acpi_bus_get_device(handle, &device);
64787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (result) {
6486468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link device\n");
649d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
65087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65250dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	link = acpi_driver_data(device);
65387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (!link) {
6546468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link context\n");
655d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
65687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
65787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
65836e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
65987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (!link->irq.initialized) {
66036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar		mutex_unlock(&acpi_link_lock);
6616468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Link isn't initialized\n");
662d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
66387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
664ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#ifdef	FUTURE_USE
665ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	/*
666ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * The Link reference count allows us to _DISable an unused link
667ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * and suspend time, and set it again  on resume.
668ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * However, 2.6.12 still has irq_router.resume
669ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * which blindly restores the link state.
670ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * So we disable the reference count method
671ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * to prevent duplicate acpi_pci_link_set()
672ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * which would harm some systems
673ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 */
6744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	link->refcnt--;
675ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#endif
67687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
6774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  "Link %s is dereferenced\n",
6784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  acpi_device_bid(link->device)));
67987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
6801c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	if (link->refcnt == 0)
681383d7a11c9989205db44c7f1be339e5097062f03donald.d.dugger@intel.com		acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
6821c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas
68336e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
684d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return (link->irq.active);
68587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li}
6864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                 Driver Interface
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6914daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic int acpi_pci_link_add(struct acpi_device *device,
6924daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki			     const struct acpi_device_id *not_used)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
694c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	int result;
695c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_pci_link *link;
696c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	int i;
6974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int found = 0;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69936bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link)
701d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->device = device;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
706db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek	device->driver_data = link;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
70836e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_pci_link_get_possible(link);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* query and set link->irq.active */
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_pci_link_get_current(link);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7160dc070bb0242481a6100c95e5deaa07b267399a8Dan Aloni	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
7174be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	       acpi_device_bid(device));
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < link->irq.possible_count; i++) {
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (link->irq.active == link->irq.possible[i]) {
720be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers			printk(KERN_CONT " *%d", link->irq.possible[i]);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found = 1;
7224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		} else
723be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers			printk(KERN_CONT " %d", link->irq.possible[i]);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
726be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers	printk(KERN_CONT ")");
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!found)
729be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers		printk(KERN_CONT " *%d", link->irq.active);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	if (!link->device->status.enabled)
732be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers		printk(KERN_CONT ", disabled.");
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
734be96447e0d49622fe00b07474f9a86805d389ca7Kay Sievers	printk(KERN_CONT "\n");
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7365f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas	list_add_tail(&link->list, &acpi_link_list);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable all links -- to be activated on use */
740383d7a11c9989205db44c7f1be339e5097062f03donald.d.dugger@intel.com	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
74136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(link);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7464daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki	return result < 0 ? result : 1;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_resume(struct acpi_pci_link *link)
750697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds{
751697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds	if (link->refcnt && link->irq.active && link->irq.initialized)
752d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return (acpi_pci_link_set(link, link->irq.active));
7531c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas
7541c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	return 0;
755697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds}
756697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds
757c3146df2b735912eddd1d7c080c9377d5df0ae94Rafael J. Wysockistatic void irqrouter_resume(void)
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
759c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_pci_link *link;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7615f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas	list_for_each_entry(link, &acpi_link_list, list) {
762697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds		acpi_pci_link_resume(link);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7664daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockistatic void acpi_pci_link_remove(struct acpi_device *device)
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
768c9d6244329c8149312dba27e78dc4a83b35a6ae5Bjorn Helgaas	struct acpi_pci_link *link;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77050dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	link = acpi_driver_data(device);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
7735f0dccaa81e239477413d0def1133850530f1bbeBjorn Helgaas	list_del(&link->list);
77436e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(link);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify acpi_irq_penalty[] from cmdline
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_penalty_update(char *str, int used)
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int retval;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int irq;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		retval = get_option(&str, &irq);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!retval)
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;	/* no number found */
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (irq < 0)
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
7974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
798fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas		if (irq >= ARRAY_SIZE(acpi_irq_penalty))
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (used)
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval != 2)	/* no next number */
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'd like PNP to call this routine for the
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single ISA_USED value for each legacy device.
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But instead it calls us with each POSSIBLE setting.
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is no ISA_POSSIBLE weight, so we simply use
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the (small) PCI_USING penalty.
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
819c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Livoid acpi_penalize_isa_irq(int irq, int active)
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
821fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas	if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
822fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas		if (active)
823fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
824fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas		else
825fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas			acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
826fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas	}
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to reserve additional IRQs for use by ISA
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_isa=5
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Useful for telling ACPI how not to interfere with your ISA sound card.
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_isa(char *str)
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return acpi_irq_penalty_update(str, 1);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_isa=", acpi_irq_isa);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to free additional IRQs for use by PCI
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_pci=7,15
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing.
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_pci(char *str)
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return acpi_irq_penalty_update(str, 0);
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_pci=", acpi_irq_pci);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_nobalance_set(char *str)
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_irq_balance = 0;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8618a383ef0be01e0e6e84c85f8bf35e4e6fcfb8981Roel Kluinstatic int __init acpi_irq_balance_set(char *str)
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_irq_balance = 1;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8674be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown__setup("acpi_irq_balance", acpi_irq_balance_set);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
869c3146df2b735912eddd1d7c080c9377d5df0ae94Rafael J. Wysockistatic struct syscore_ops irqrouter_syscore_ops = {
8704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.resume = irqrouter_resume,
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8734daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysockivoid __init acpi_pci_link_init(void)
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_noirq)
8764daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki		return;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
87832836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas	if (acpi_irq_balance == -1) {
87932836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas		/* no command line switch: enable balancing in IOAPIC mode */
88032836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas		if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
88132836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas			acpi_irq_balance = 1;
88232836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas		else
88332836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas			acpi_irq_balance = 0;
88432836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas	}
8854daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki	register_syscore_ops(&irqrouter_syscore_ops);
8864daeaf68379f75dedd120582add5206c7c5ad72eRafael J. Wysocki	acpi_scan_add_handler(&pci_link_handler);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
888