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