pci_link.c revision 1c9ca3a7d41b5db884033900b539b9aeb61a399e
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 34 $)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2002       Dominik Brodowski <devel@brodo.de>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is free software; you can redistribute it and/or modify
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  it under the terms of the GNU General Public License as published by
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the Free Software Foundation; either version 2 of the License, or (at
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  your option) any later version.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is distributed in the hope that it will be useful, but
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  General Public License for more details.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  You should have received a copy of the GNU General Public License along
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  with this program; if not, write to the Free Software Foundation, Inc.,
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TBD:
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      1. Support more than one IRQ resource entry per link device (index).
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2. Implement start/stop mechanism and use ACPI Bus Driver facilities
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	   for IRQ management (e.g. start()->_SRS).
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysdev.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pm.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
4136e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar#include <linux/mutex.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
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
544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_add(struct acpi_device *device);
554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_remove(struct acpi_device *device, int type);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renningerstatic struct acpi_device_id link_device_ids[] = {
581ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"PNP0C0F", 0},
591ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"", 0},
601ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger};
611ba90e3a87c46500623afdc3898573e4a5ebb21bThomas RenningerMODULE_DEVICE_TABLE(acpi, link_device_ids);
621ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_pci_link_driver = {
64c2b6705b75d9c7aff98a4602a32230639e10891cLen Brown	.name = "pci_link",
654be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.class = ACPI_PCI_LINK_CLASS,
661ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	.ids = link_device_ids,
674be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.ops = {
684be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		.add = acpi_pci_link_add,
694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		.remove = acpi_pci_link_remove,
701c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	},
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/*
7487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * If a link is initialized, we never change its active and initialized
7587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * later even the link is disable. Instead, we just repick the active irq
7687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link_irq {
784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 active;		/* Current IRQ */
7950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	u8 triggering;		/* All IRQs */
801c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	u8 polarity;		/* All IRQs */
814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 resource_type;
824be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 possible_count;
834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 initialized:1;
854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u8 reserved:7;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpi_pci_link {
891c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	struct list_head		node;
901c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	struct acpi_device		*device;
911c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	struct acpi_pci_link_irq	irq;
921c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	int				refcnt;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct {
961c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	int			count;
971c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	struct list_head	entries;
984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown} acpi_link;
99e5685b9d35c2cc0a98425b05df30cb837dd1e632Adrian Bunkstatic DEFINE_MUTEX(acpi_link_lock);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                            PCI Link Device Management
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set context (link) possible list from resource list
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1081c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasstatic acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
1091c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas						void *context)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11150dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_pci_link *link = context;
1124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	u32 i = 0;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114eca008c8134df15262a0362623edb59902628c95Len Brown	switch (resource->type) {
11550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
1164a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas	case ACPI_RESOURCE_TYPE_END_TAG:
117d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return AE_OK;
11850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_IRQ:
1194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
1204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			struct acpi_resource_irq *p = &resource->data.irq;
12150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
1224a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1234a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas						  "Blank _PRS IRQ resource\n"));
124d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			for (i = 0;
12750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			     (i < p->interrupt_count
1284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
1294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				if (!p->interrupts[i]) {
1304a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					printk(KERN_WARNING PREFIX
1314a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       "Invalid _PRS IRQ %d\n",
1324a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       p->interrupts[i]);
1334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					continue;
1344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				}
1354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible[i] = p->interrupts[i];
1364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible_count++;
1374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
13850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.triggering = p->triggering;
13950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.polarity = p->polarity;
14050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.resource_type = ACPI_RESOURCE_TYPE_IRQ;
1414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
14550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			struct acpi_resource_extended_irq *p =
1464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    &resource->data.extended_irq;
14750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
148cece92969762b8ed7930d4e23008b76b06411deeLen Brown				printk(KERN_WARNING PREFIX
1494a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					      "Blank _PRS EXT IRQ resource\n");
150d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
1514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
1524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			for (i = 0;
15350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			     (i < p->interrupt_count
1544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
1554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				if (!p->interrupts[i]) {
1564a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					printk(KERN_WARNING PREFIX
1574a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       "Invalid _PRS IRQ %d\n",
1584a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					       p->interrupts[i]);
1594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					continue;
1604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				}
1614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible[i] = p->interrupts[i];
1624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				link->irq.possible_count++;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.triggering = p->triggering;
16550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.polarity = p->polarity;
16650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
1674be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1704a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n",
1714a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		       resource->type);
172d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return AE_OK;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return AE_CTRL_TERMINATE;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_possible(struct acpi_pci_link *link)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link)
183d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18567a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel	status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
1864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				     acpi_pci_link_check_possible, link);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
188a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
189d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  "Found %d possible IRQs\n",
1944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  link->irq.possible_count));
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
196d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasstatic acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
2001c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas					       void *context)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int *irq = (int *)context;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
204eca008c8134df15262a0362623edb59902628c95Len Brown	switch (resource->type) {
2054a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2064a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas	case ACPI_RESOURCE_TYPE_END_TAG:
2074a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		return AE_OK;
20850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_IRQ:
2094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
2104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			struct acpi_resource_irq *p = &resource->data.irq;
21150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
2124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				/*
2134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * IRQ descriptors may have no IRQ# bits set,
2144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * particularly those those w/ _STA disabled
2154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 */
2164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
2174a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas						  "Blank _CRS IRQ resource\n"));
218d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
2194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
2204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			*irq = p->interrupts[0];
2214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
22350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
2244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		{
22550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			struct acpi_resource_extended_irq *p =
2264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    &resource->data.extended_irq;
22750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			if (!p || !p->interrupt_count) {
2284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				/*
2294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * extended IRQ descriptors must
2304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 * return at least 1 IRQ
2314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				 */
232cece92969762b8ed7930d4e23008b76b06411deeLen Brown				printk(KERN_WARNING PREFIX
2334a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas					      "Blank _CRS EXT IRQ resource\n");
234d550d98d3317378d93a4869db204725d270ec812Patrick Mochel				return AE_OK;
2354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			}
2364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			*irq = p->interrupts[0];
2374be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			break;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
239d4ec6c7cc9a15a7a529719bc3b84f46812f9842eLen Brown		break;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2414a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n",
2424a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas		       resource->type);
243d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return AE_OK;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2454a5e3638b11978262ab76bbb2062e57fefaaedbaBjorn Helgaas
246d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return AE_CTRL_TERMINATE;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run _CRS and set link->irq.active
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return value:
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 - success
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * !0 - failure
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_get_current(struct acpi_pci_link *link)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
2594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
2604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int irq = 0;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262e0e4e117d4c898b0df749d5b88c86955151abf53Patrick Mochel	if (!link)
263d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->irq.active = 0;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* in practice, status disabled is meaningless, ignore it */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_strict) {
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Query _STA, set link->device->status */
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = acpi_bus_get_status(link->device);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result) {
2726468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			printk(KERN_ERR PREFIX "Unable to read status\n");
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto end;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!link->device->status.enabled) {
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
278d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return 0;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Query and parse _CRS to get the current IRQ assignment.
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28667a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel	status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
2874be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				     acpi_pci_link_check_current, &irq);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
289a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_strict && !irq) {
2956468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "_CRS returned 0\n");
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->irq.active = irq;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
304d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
3104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status status = AE_OK;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct {
3124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		struct acpi_resource res;
3134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		struct acpi_resource end;
3144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	} *resource;
3154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_buffer buffer = { 0, NULL };
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link || !irq)
318d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32036bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
3214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	if (!resource)
322d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	buffer.length = sizeof(*resource) + 1;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer.pointer = resource;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	switch (link->irq.resource_type) {
32850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_IRQ:
32950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.type = ACPI_RESOURCE_TYPE_IRQ;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.length = sizeof(struct acpi_resource);
33150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.irq.triggering = link->irq.triggering;
33250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.irq.polarity =
33350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		    link->irq.polarity;
33450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
33550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable =
3364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    ACPI_EXCLUSIVE;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
33850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable = ACPI_SHARED;
33950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.irq.interrupt_count = 1;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.data.irq.interrupts[0] = irq;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
34350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
34450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.length = sizeof(struct acpi_resource);
3464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		resource->res.data.extended_irq.producer_consumer =
3474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    ACPI_CONSUMER;
34850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.extended_irq.triggering =
34950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		    link->irq.triggering;
35050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.extended_irq.polarity =
35150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		    link->irq.polarity;
35250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
35350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable =
3544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    ACPI_EXCLUSIVE;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
35650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore			resource->res.data.irq.sharable = ACPI_SHARED;
35750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		resource->res.data.extended_irq.interrupt_count = 1;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resource->res.data.extended_irq.interrupts[0] = irq;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ignore resource_source, it's optional */
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3626468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -EINVAL;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
36750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attempt to set the resource */
37067a7136573b24a0d1f85a4aab131558a02910d25Patrick Mochel	status = acpi_set_current_resources(link->device->handle, &buffer);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for total failure */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
374a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -ENODEV;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Query _STA, set device->status */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_bus_get_status(link->device);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
3826468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Unable to read status\n");
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link->device->status.enabled) {
386cece92969762b8ed7930d4e23008b76b06411deeLen Brown		printk(KERN_WARNING PREFIX
387cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      "%s [%s] disabled and referenced, BIOS bug\n",
388a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger			      acpi_device_name(link->device),
389cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      acpi_device_bid(link->device));
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Query _CRS, set link->irq.active */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_pci_link_get_current(link);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Is current setting not what we set?
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set link->irq.active
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (link->irq.active != irq) {
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * policy: when _CRS doesn't return what we just _SRS
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * assume _SRS worked and override _CRS value.
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
407cece92969762b8ed7930d4e23008b76b06411deeLen Brown		printk(KERN_WARNING PREFIX
408cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
409a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger			      acpi_device_name(link->device),
410cece92969762b8ed7930d4e23008b76b06411deeLen Brown			      acpi_device_bid(link->device), link->irq.active, irq);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link->irq.active = irq;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
4154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
4164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(resource);
418d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                            PCI Link IRQ Management
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Link Devices to move the PIRQs around to minimize sharing.
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that the BIOS has already set to active.  This is necessary because
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI has no automatic means of knowing what ISA IRQs are used.  Note that
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the BIOS doesn't set a Link Device active, ACPI needs to program it
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even if acpi_irq_nobalance is set.
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A tables of penalties avoids directing PCI interrupts to well known
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISA IRQs. Boot params are available to over-ride the default table:
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that are free for PCI use.
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_pci=n[,m]
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List interrupts that should not be used for PCI:
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_irq_isa=n[,m]
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that PCI IRQ routers have a list of possible IRQs,
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which may not include the IRQs this table says are available.
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since this heuristic can't tell the difference between a link
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that no device will attach to, vs. a link which may be shared
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by multiple active devices -- it is not optimal.
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If interrupt performance is that important, get an IO-APIC system
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pin dedicated to each device.  Or for that matter, an MSI
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enabled system.
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_IRQS		256
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_MAX_ISA_IRQ	16
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_AVAILABLE	(0)
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_POSSIBLE	(16*16)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_PCI_USING		(16*16*16)
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_TYPICAL	(16*16*16*16)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_USED		(16*16*16*16*16)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PIRQ_PENALTY_ISA_ALWAYS		(16*16*16*16*16*16)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_irq_penalty[ACPI_MAX_IRQS] = {
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
4704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
4714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ5 sometimes SoundBlaster */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ6 */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ7 parallel, spurious */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ8 rtc, sometimes */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ9  PCI, often acpi */
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ10 PCI */
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ11 PCI */
4791c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ12 mouse */
4801c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ13 fpe, sometimes */
4811c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ14 ide0 */
4821c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	PIRQ_PENALTY_ISA_USED,		/* IRQ15 ide1 */
4834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	/* >IRQ15 */
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint __init acpi_irq_penalty_init(void)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4884be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct list_head *node = NULL;
4894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_pci_link *link = NULL;
4904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int i = 0;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Update penalties to facilitate IRQ balancing.
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each(node, &acpi_link.entries) {
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link = list_entry(node, struct acpi_pci_link, node);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!link) {
4986468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			printk(KERN_ERR PREFIX "Invalid link context\n");
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * reflect the possible and active irqs in the penalty table --
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * useful for breaking ties.
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (link->irq.possible_count) {
5074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			int penalty =
5084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    PIRQ_PENALTY_PCI_POSSIBLE /
5094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    link->irq.possible_count;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < link->irq.possible_count; i++) {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
5134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					acpi_irq_penalty[link->irq.
5144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown							 possible[i]] +=
5154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					    penalty;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (link->irq.active) {
5194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			acpi_irq_penalty[link->irq.active] +=
5204be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    PIRQ_PENALTY_PCI_POSSIBLE;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Add a penalty for the SCI */
524cee324b145a1e5488b34191de670e5ed1d346ebbAlexey Starikovskiy	acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
525d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52832836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaasstatic int acpi_irq_balance = -1;	/* 0: static, 1: balance */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_allocate(struct acpi_pci_link *link)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int irq;
5334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int i;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (link->irq.initialized) {
53687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li		if (link->refcnt == 0)
53787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li			/* This means the link is disabled but initialized */
53887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li			acpi_pci_link_set(link, link->irq.active);
539d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
54087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * search for active IRQ in list of possible IRQs.
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < link->irq.possible_count; ++i) {
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (link->irq.active == link->irq.possible[i])
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * forget active IRQ that is not in possible list
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == link->irq.possible_count) {
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (acpi_strict)
554cece92969762b8ed7930d4e23008b76b06411deeLen Brown			printk(KERN_WARNING PREFIX "_CRS %d not found"
555cece92969762b8ed7930d4e23008b76b06411deeLen Brown				      " in _PRS\n", link->irq.active);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link->irq.active = 0;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if active found, use it; else pick entry from end of possible list.
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5621c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	if (link->irq.active)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = link->irq.active;
5641c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	else
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = link->irq.possible[link->irq.possible_count - 1];
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_irq_balance || !link->irq.active) {
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Select the best IRQ.  This is done in reverse to promote
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the use of IRQs 9, 10, 11, and >15.
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = (link->irq.possible_count - 1); i >= 0; i--) {
5734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			if (acpi_irq_penalty[irq] >
5744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			    acpi_irq_penalty[link->irq.possible[i]])
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				irq = link->irq.possible[i];
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attempt to enable the link device at this IRQ. */
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_pci_link_set(link, irq)) {
5816468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
5826468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			    "Try pci=noacpi or acpi=off\n",
583a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger			    acpi_device_name(link->device),
5846468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			    acpi_device_bid(link->device));
585d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
5884d9391557b68475b118ec7626607c37b14ae8c16Frank Seidel		printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
5894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		       acpi_device_name(link->device),
5904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		       acpi_device_bid(link->device), link->irq.active);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->irq.initialized = 1;
594d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
59887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * acpi_pci_link_allocate_irq
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6021c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaasint acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
6031c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas			       int *polarity, char **name)
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
6064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_device *device = NULL;
6074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_pci_link *link = NULL;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_bus_get_device(handle, &device);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
6116468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link device\n");
612d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61550dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	link = acpi_driver_data(device);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link) {
6176468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link context\n");
618d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: Support multiple index (IRQ) entries per Link Device */
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (index) {
6236468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid index %d\n", index);
624d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
62887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (acpi_pci_link_allocate(link)) {
62936e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar		mutex_unlock(&acpi_link_lock);
630d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
63187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
6324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link->irq.active) {
63436e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar		mutex_unlock(&acpi_link_lock);
6356468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Link active IRQ is 0!\n");
636d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	link->refcnt++;
63936e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	if (triggering)
64250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		*triggering = link->irq.triggering;
64350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	if (polarity)
64450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore		*polarity = link->irq.polarity;
6454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	if (name)
6464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		*name = acpi_device_bid(link->device);
64787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
6484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  "Link %s is referenced\n",
6494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  acpi_device_bid(link->device)));
650d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return (link->irq.active);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/*
65487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * We don't change link's irq information here.  After it is reenabled, we
65587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li * continue use the info
65687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li */
6574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_link_free_irq(acpi_handle handle)
65887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{
6594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_device *device = NULL;
6604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_pci_link *link = NULL;
6614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	acpi_status result;
66287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
66387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	result = acpi_bus_get_device(handle, &device);
66487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (result) {
6656468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link device\n");
666d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
66787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66950dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	link = acpi_driver_data(device);
67087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (!link) {
6716468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Invalid link context\n");
672d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
67387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
67487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
67536e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
67687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	if (!link->irq.initialized) {
67736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar		mutex_unlock(&acpi_link_lock);
6786468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown		printk(KERN_ERR PREFIX "Link isn't initialized\n");
679d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -1;
68087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	}
681ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#ifdef	FUTURE_USE
682ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	/*
683ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * The Link reference count allows us to _DISable an unused link
684ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * and suspend time, and set it again  on resume.
685ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * However, 2.6.12 still has irq_router.resume
686ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * which blindly restores the link state.
687ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * So we disable the reference count method
688ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * to prevent duplicate acpi_pci_link_set()
689ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 * which would harm some systems
690ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li	 */
6914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	link->refcnt--;
692ecc21ebe603af31f172c43b8b261df79040790efDavid Shaohua Li#endif
69387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
6944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  "Link %s is dereferenced\n",
6954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			  acpi_device_bid(link->device)));
69687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
6971c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	if (link->refcnt == 0)
698383d7a11c9989205db44c7f1be339e5097062f03donald.d.dugger@intel.com		acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
6991c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas
70036e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
701d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return (link->irq.active);
70287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li}
7034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                 Driver Interface
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_add(struct acpi_device *device)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
7114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_pci_link *link = NULL;
7124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int i = 0;
7134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int found = 0;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!device)
716d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71836bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!link)
720d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	link->device = device;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
725db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek	device->driver_data = link;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72736e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = acpi_pci_link_get_possible(link);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto end;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* query and set link->irq.active */
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_pci_link_get_current(link);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7350dc070bb0242481a6100c95e5deaa07b267399a8Dan Aloni	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
7364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	       acpi_device_bid(device));
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < link->irq.possible_count; i++) {
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (link->irq.active == link->irq.possible[i]) {
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" *%d", link->irq.possible[i]);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found = 1;
7414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		} else
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" %d", link->irq.possible[i]);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(")");
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!found)
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" *%d", link->irq.active);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	if (!link->device->status.enabled)
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(", disabled.");
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n");
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: Acquire/release lock */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&link->node, &acpi_link.entries);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_link.count++;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      end:
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable all links -- to be activated on use */
761383d7a11c9989205db44c7f1be339e5097062f03donald.d.dugger@intel.com	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
76236e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(link);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
767d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return result;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_resume(struct acpi_pci_link *link)
771697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds{
772697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds	if (link->refcnt && link->irq.active && link->irq.initialized)
773d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return (acpi_pci_link_set(link, link->irq.active));
7741c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas
7751c9ca3a7d41b5db884033900b539b9aeb61a399eBjorn Helgaas	return 0;
776697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds}
777697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds
7784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int irqrouter_resume(struct sys_device *dev)
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct list_head *node = NULL;
7814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_pci_link *link = NULL;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each(node, &acpi_link.entries) {
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		link = list_entry(node, struct acpi_pci_link, node);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!link) {
7866468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown			printk(KERN_ERR PREFIX "Invalid link context\n");
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
789697a2d63a3844caaa2b6565ab7f3d69086af94d4Linus Torvalds		acpi_pci_link_resume(link);
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
791d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_pci_link_remove(struct acpi_device *device, int type)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpi_pci_link *link = NULL;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!device || !acpi_driver_data(device))
799d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EINVAL;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80150dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	link = acpi_driver_data(device);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80336e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_lock(&acpi_link_lock);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&link->node);
80536e430951af0b0d1bdfd50ce22e70079d02646dfIngo Molnar	mutex_unlock(&acpi_link_lock);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(link);
808d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify acpi_irq_penalty[] from cmdline
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_penalty_update(char *str, int used)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int retval;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int irq;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		retval = get_option(&str, &irq);
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!retval)
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;	/* no number found */
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (irq < 0)
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
830fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas		if (irq >= ARRAY_SIZE(acpi_irq_penalty))
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (used)
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval != 2)	/* no next number */
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'd like PNP to call this routine for the
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single ISA_USED value for each legacy device.
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But instead it calls us with each POSSIBLE setting.
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is no ISA_POSSIBLE weight, so we simply use
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the (small) PCI_USING penalty.
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
851c9c3e457de24cca2ca688fa397d93a241f472048David Shaohua Livoid acpi_penalize_isa_irq(int irq, int active)
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
853fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas	if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
854fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas		if (active)
855fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
856fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas		else
857fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas			acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
858fa46d3526461e8aa7c0fb39cc1b98ac656695a43Bjorn Helgaas	}
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to reserve additional IRQs for use by ISA
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_isa=5
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Useful for telling ACPI how not to interfere with your ISA sound card.
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_isa(char *str)
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return acpi_irq_penalty_update(str, 1);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_isa=", acpi_irq_isa);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Over-ride default table to free additional IRQs for use by PCI
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e.g. acpi_irq_pci=7,15
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing.
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_pci(char *str)
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return acpi_irq_penalty_update(str, 0);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8824be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_pci=", acpi_irq_pci);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_irq_nobalance_set(char *str)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_irq_balance = 0;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8938a383ef0be01e0e6e84c85f8bf35e4e6fcfb8981Roel Kluinstatic int __init acpi_irq_balance_set(char *str)
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_irq_balance = 1;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown__setup("acpi_irq_balance", acpi_irq_balance_set);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* FIXME: we will remove this interface after all drivers call pci_disable_device */
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sysdev_class irqrouter_sysdev_class = {
903af5ca3f4ec5cc4432a42a73b050dd8898ce8fd00Kay Sievers	.name = "irqrouter",
9044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.resume = irqrouter_resume,
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sys_device device_irqrouter = {
9084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.id = 0,
9094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.cls = &irqrouter_sysdev_class,
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init irqrouter_init_sysfs(void)
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_disabled || acpi_noirq)
917d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = sysdev_class_register(&irqrouter_sysdev_class);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!error)
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = sysdev_register(&device_irqrouter);
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
923d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return error;
9244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown}
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_initcall(irqrouter_init_sysfs);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int __init acpi_pci_link_init(void)
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_noirq)
931d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
93332836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas	if (acpi_irq_balance == -1) {
93432836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas		/* no command line switch: enable balancing in IOAPIC mode */
93532836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas		if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
93632836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas			acpi_irq_balance = 1;
93732836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas		else
93832836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas			acpi_irq_balance = 0;
93932836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas	}
94032836259ff25ce97010569706cd33ba94de81d62Bjorn Helgaas
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_link.count = 0;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&acpi_link.entries);
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
945d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
947d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(acpi_pci_link_init);
951