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