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