11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 11 $)
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>
739488b041e2fdc206b3de4517b8f220ae07b2a20Bjorn Helgaas *  (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
839488b041e2fdc206b3de4517b8f220ae07b2a20Bjorn Helgaas *	Bjorn Helgaas <bjorn.helgaas@hp.com>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is free software; you can redistribute it and/or modify
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  it under the terms of the GNU General Public License as published by
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the Free Software Foundation; either version 2 of the License, or (at
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  your option) any later version.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is distributed in the hope that it will be useful, but
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  WITHOUT ANY WARRANTY; without even the implied warranty of
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  General Public License for more details.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  You should have received a copy of the GNU General Public License along
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  with this program; if not, write to the Free Software Foundation, Inc.,
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas#include <linux/dmi.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pm.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/acpi.h>
395a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#define PREFIX "ACPI: "
44a192a9580bcc41692be1f36b77c3b681827f566aLen Brown
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT		ACPI_PCI_COMPONENT
46f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("pci_irq");
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48f748bafa3ca1fb056e63afdeecacc1c68d8104dfBjorn Helgaasstruct acpi_prt_entry {
493604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	struct list_head	list;
50f748bafa3ca1fb056e63afdeecacc1c68d8104dfBjorn Helgaas	struct acpi_pci_id	id;
51f748bafa3ca1fb056e63afdeecacc1c68d8104dfBjorn Helgaas	u8			pin;
524eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas	acpi_handle		link;
534eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas	u32			index;		/* GSI, or link _CRS index */
54f748bafa3ca1fb056e63afdeecacc1c68d8104dfBjorn Helgaas};
55f748bafa3ca1fb056e63afdeecacc1c68d8104dfBjorn Helgaas
563604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaasstatic LIST_HEAD(acpi_prt_list);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(acpi_prt_lock);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaasstatic inline char pin_name(int pin)
60cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas{
61e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	return 'A' + pin - 1;
62cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas}
63cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                         PCI IRQ Routing Table (PRT) Support
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
68063563b4b8f87e2be0e127ccf3a8e6eef6309ff4Bjorn Helgaasstatic struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
69063563b4b8f87e2be0e127ccf3a8e6eef6309ff4Bjorn Helgaas							  int pin)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
713604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	struct acpi_prt_entry *entry;
72063563b4b8f87e2be0e127ccf3a8e6eef6309ff4Bjorn Helgaas	int segment = pci_domain_nr(dev->bus);
73063563b4b8f87e2be0e127ccf3a8e6eef6309ff4Bjorn Helgaas	int bus = dev->bus->number;
74063563b4b8f87e2be0e127ccf3a8e6eef6309ff4Bjorn Helgaas	int device = PCI_SLOT(dev->devfn);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&acpi_prt_lock);
773604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	list_for_each_entry(entry, &acpi_prt_list, list) {
784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		if ((segment == entry->id.segment)
794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    && (bus == entry->id.bus)
804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    && (device == entry->id.device)
814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    && (pin == entry->pin)) {
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock(&acpi_prt_lock);
83d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return entry;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&acpi_prt_lock);
87d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return NULL;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */
91609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulichstatic const struct dmi_system_id medion_md9580[] = {
92391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	{
93391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		.ident = "Medion MD9580-F laptop",
94391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		.matches = {
95391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
96391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_PRODUCT_NAME, "A555"),
97391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		},
98391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	},
99391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	{ }
100391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas};
101391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
102391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* http://bugzilla.kernel.org/show_bug.cgi?id=5044 */
103609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulichstatic const struct dmi_system_id dell_optiplex[] = {
104391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	{
105391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		.ident = "Dell Optiplex GX1",
106391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		.matches = {
107391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
108391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX1 600S+"),
109391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		},
110391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	},
111391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	{ }
112391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas};
113391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
114391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* http://bugzilla.kernel.org/show_bug.cgi?id=10138 */
115609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulichstatic const struct dmi_system_id hp_t5710[] = {
116391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	{
117391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		.ident = "HP t5710",
118391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		.matches = {
119391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
120391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_PRODUCT_NAME, "hp t5000 series"),
121391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			DMI_MATCH(DMI_BOARD_NAME, "098Ch"),
122391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		},
123391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	},
124391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	{ }
125391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas};
126391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
127391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstruct prt_quirk {
128609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulich	const struct dmi_system_id *system;
129391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	unsigned int		segment;
130391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	unsigned int		bus;
131391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	unsigned int		device;
132391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	unsigned char		pin;
133609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulich	const char		*source;	/* according to BIOS */
134609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulich	const char		*actual_source;
135391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas};
136391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
137c458033c9b72a81b890d97ec6339694bab252383Bjorn Helgaas#define PCI_INTX_PIN(c)		(c - 'A' + 1)
138c458033c9b72a81b890d97ec6339694bab252383Bjorn Helgaas
139391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/*
140391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas * These systems have incorrect _PRT entries.  The BIOS claims the PCI
141391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas * interrupt at the listed segment/bus/device/pin is connected to the first
142391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas * link device, but it is actually connected to the second.
143391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas */
144609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulichstatic const struct prt_quirk prt_quirks[] = {
145c458033c9b72a81b890d97ec6339694bab252383Bjorn Helgaas	{ medion_md9580, 0, 0, 9, PCI_INTX_PIN('A'),
146b97d4803400a4442b0e4ae14d0bd8e83994b9004Bjorn Helgaas		"\\_SB_.PCI0.ISA_.LNKA",
147b97d4803400a4442b0e4ae14d0bd8e83994b9004Bjorn Helgaas		"\\_SB_.PCI0.ISA_.LNKB"},
148c458033c9b72a81b890d97ec6339694bab252383Bjorn Helgaas	{ dell_optiplex, 0, 0, 0xd, PCI_INTX_PIN('A'),
149391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		"\\_SB_.LNKB",
150391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		"\\_SB_.LNKA"},
151c458033c9b72a81b890d97ec6339694bab252383Bjorn Helgaas	{ hp_t5710, 0, 0, 1, PCI_INTX_PIN('A'),
152391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		"\\_SB_.PCI0.LNK1",
153391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		"\\_SB_.PCI0.LNK3"},
154391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas};
155391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
1563f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaasstatic void do_prt_fixups(struct acpi_prt_entry *entry,
1573f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaas			  struct acpi_pci_routing_table *prt)
158391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas{
159391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	int i;
160609d4bc949a9175a6c8ba9dc1b6fdb4d9dab0427Jan Beulich	const struct prt_quirk *quirk;
161391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
162391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	for (i = 0; i < ARRAY_SIZE(prt_quirks); i++) {
163391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		quirk = &prt_quirks[i];
164391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
165391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		/* All current quirks involve link devices, not GSIs */
166391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		if (!prt->source)
167391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			continue;
168391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
169391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		if (dmi_check_system(quirk->system) &&
170391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		    entry->id.segment == quirk->segment &&
171391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		    entry->id.bus == quirk->bus &&
172391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		    entry->id.device == quirk->device &&
173c458033c9b72a81b890d97ec6339694bab252383Bjorn Helgaas		    entry->pin == quirk->pin &&
174391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		    !strcmp(prt->source, quirk->source) &&
175391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		    strlen(prt->source) >= strlen(quirk->actual_source)) {
176391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			printk(KERN_WARNING PREFIX "firmware reports "
177c83642d5123225a22cccd75adea6e97c245714cbBjorn Helgaas				"%04x:%02x:%02x PCI INT %c connected to %s; "
178391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas				"changing to %s\n",
179391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas				entry->id.segment, entry->id.bus,
180cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas				entry->id.device, pin_name(entry->pin),
181391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas				prt->source, quirk->actual_source);
182391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas			strcpy(prt->source, quirk->actual_source);
183391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas		}
184391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	}
185391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas}
186391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
187859a3f86ca83346f4097e956d0b27d96aa7a1cffAlexander Chiangstatic int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus,
1883f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaas				  struct acpi_pci_routing_table *prt)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1903604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	struct acpi_prt_entry *entry;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19236bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!entry)
194d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENOMEM;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
196e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	/*
197e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	 * Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses
198e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	 * 1=INTA, 2=INTB.  We use the PCI encoding throughout, so convert
199e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	 * it here.
200e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	 */
201859a3f86ca83346f4097e956d0b27d96aa7a1cffAlexander Chiang	entry->id.segment = pci_domain_nr(bus);
202859a3f86ca83346f4097e956d0b27d96aa7a1cffAlexander Chiang	entry->id.bus = bus->number;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->id.device = (prt->address >> 16) & 0xFFFF;
204e64e9db53ab78d20dff4cc1aec8a6b0e4e70ce8cBjorn Helgaas	entry->pin = prt->pin + 1;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
206391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas	do_prt_fixups(entry, prt);
207391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas
2084eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas	entry->index = prt->source_index;
2094eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Type 1: Dynamic
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ---------------
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The 'source' field specifies the PCI interrupt link device used to
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * configure the IRQ assigned to this slot|dev|pin.  The 'source_index'
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * indicates which resource descriptor in the resource template (of
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the link device) this interrupt is allocated from.
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * NOTE: Don't query the Link Device for IRQ information at this time
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *       because Link Device enumeration may not have occurred yet
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *       (e.g. exists somewhere 'below' this _PRT entry in the ACPI
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *       namespace).
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2234eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas	if (prt->source[0])
2244eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas		acpi_get_handle(handle, prt->source, &entry->link);
2254eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Type 2: Static
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * --------------
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The 'source' field is NULL, and the 'source_index' field specifies
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the IRQ value, which is hardwired to specific interrupt inputs on
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the interrupt controller.
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
23521a53283a012f21764f2aaaac9414849e1153d93Bjorn Helgaas			      "      %04x:%02x:%02x[%c] -> %s[%d]\n",
2364be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			      entry->id.segment, entry->id.bus,
237cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas			      entry->id.device, pin_name(entry->pin),
2384eaf6db3ea0edf7e011a613b5a15360444e58fecBjorn Helgaas			      prt->source, entry->index));
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&acpi_prt_lock);
2413604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	list_add_tail(&entry->list, &acpi_prt_list);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&acpi_prt_lock);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
247859a3f86ca83346f4097e956d0b27d96aa7a1cffAlexander Chiangint acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus)
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2492320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	acpi_status status;
2502320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
2512320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	struct acpi_pci_routing_table *entry;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2532320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
2542320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
2552320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	if (ACPI_FAILURE(status))
2562320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas		return -ENODEV;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
2592320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	       (char *) buffer.pointer);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2612320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	kfree(buffer.pointer);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2632320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	buffer.length = ACPI_ALLOCATE_BUFFER;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer.pointer = NULL;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = acpi_get_irq_routing_table(handle, &buffer);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status)) {
268a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
269a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger				acpi_format_exception(status)));
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(buffer.pointer);
271d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -ENODEV;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2742320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	entry = buffer.pointer;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (entry && (entry->length > 0)) {
276859a3f86ca83346f4097e956d0b27d96aa7a1cffAlexander Chiang		acpi_pci_irq_add_entry(handle, bus, entry);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = (struct acpi_pci_routing_table *)
2784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    ((unsigned long)entry + entry->length);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2812320ac6cb078eec77bf93742895dc35e64fae124Bjorn Helgaas	kfree(buffer.pointer);
282d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285d9efae3688addb15994c9ad9761dada6f988bc14Alexander Chiangvoid acpi_pci_irq_del_prt(struct pci_bus *bus)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2873604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	struct acpi_prt_entry *entry, *tmp;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	printk(KERN_DEBUG
29021a53283a012f21764f2aaaac9414849e1153d93Bjorn Helgaas	       "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
291d9efae3688addb15994c9ad9761dada6f988bc14Alexander Chiang	       pci_domain_nr(bus), bus->number);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&acpi_prt_lock);
2933604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas	list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) {
294d9efae3688addb15994c9ad9761dada6f988bc14Alexander Chiang		if (pci_domain_nr(bus) == entry->id.segment
295d9efae3688addb15994c9ad9761dada6f988bc14Alexander Chiang			&& bus->number == entry->id.bus) {
2963604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas			list_del(&entry->list);
2973604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas			kfree(entry);
2983604a9f445afde2801b8c24b63dd289c33e290a6Bjorn Helgaas		}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&acpi_prt_lock);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* --------------------------------------------------------------------------
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                          PCI Interrupt Routing Support
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------------------------------------------------------------------- */
306d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann#ifdef CONFIG_X86_IO_APIC
307d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmannextern int noioapicquirk;
308d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmannextern int noioapicreroute;
309d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann
310d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmannstatic int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
311d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann{
312d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	struct pci_bus *bus_it;
313d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann
314d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
315d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		if (!bus_it->self)
316d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			return 0;
317d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		if (bus_it->self->irq_reroute_variant)
318d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			return bus_it->self->irq_reroute_variant;
319d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	}
320d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	return 0;
321d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann}
322d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann
323d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann/*
324d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann * Some chipsets (e.g. Intel 6700PXH) generate a legacy INTx when the IRQ
325d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann * entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel does
326d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann * during interrupt handling). When this INTx generation cannot be disabled,
327d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann * we reroute these interrupts to their legacy equivalent to get rid of
328d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann * spurious interrupts.
329d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann */
330d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmannstatic int acpi_reroute_boot_interrupt(struct pci_dev *dev,
331d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann				       struct acpi_prt_entry *entry)
332d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann{
333d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	if (noioapicquirk || noioapicreroute) {
334d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		return 0;
335d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	} else {
336d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		switch (bridge_has_boot_interrupt_variant(dev->bus)) {
337d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		case 0:
338d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			/* no rerouting necessary */
339d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			return 0;
340d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		case INTEL_IRQ_REROUTE_VARIANT:
341d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			/*
342d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			 * Remap according to INTx routing table in 6700PXH
343d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			 * specs, intel order number 302628-002, section
344d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			 * 2.15.2. Other chipsets (80332, ...) have the same
345d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			 * mapping and are handled here as well.
346d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			 */
347d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			dev_info(&dev->dev, "PCI IRQ %d -> rerouted to legacy "
348d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann				 "IRQ %d\n", entry->index,
349d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann				 (entry->index % 4) + 16);
350d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			entry->index = (entry->index % 4) + 16;
351d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			return 1;
352d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		default:
353d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			dev_warn(&dev->dev, "Cannot reroute IRQ %d to legacy "
354d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann				 "IRQ: unknown mapping\n", entry->index);
355d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann			return -1;
356d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		}
357d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann	}
358d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann}
359d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann#endif /* CONFIG_X86_IO_APIC */
360d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann
3613f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaasstatic struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
363beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas	struct acpi_prt_entry *entry;
3645697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas	struct pci_dev *bridge;
3655697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas	u8 bridge_pin, orig_pin = pin;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
367063563b4b8f87e2be0e127ccf3a8e6eef6309ff4Bjorn Helgaas	entry = acpi_pci_irq_find_prt_entry(dev, pin);
3683b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas	if (entry) {
369d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann#ifdef CONFIG_X86_IO_APIC
370d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann		acpi_reroute_boot_interrupt(dev, entry);
371d7f6169a0d32002657886fee561c641acddb9a75Stefan Assmann#endif /* CONFIG_X86_IO_APIC */
3723b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n",
3731350487eeb616889f589e9b8c06bd5077452b7e3Bjorn Helgaas				  pci_name(dev), pin_name(pin)));
3743b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas		return entry;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Attempt to derive an IRQ for this device from a parent bridge's
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge).
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
381ee40136313323db1096b17df7b436d22a24ef2beBjorn Helgaas	bridge = dev->bus->self;
382ee40136313323db1096b17df7b436d22a24ef2beBjorn Helgaas	while (bridge) {
383c686d141c7c668ac186015841a1ccd285a1f3362Bjorn Helgaas		pin = pci_swizzle_interrupt_pin(dev, pin);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* PC card has the same IRQ as its cardbridge */
3878015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi			bridge_pin = bridge->pin;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bridge_pin) {
3894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
3904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown						  "No interrupt pin configured for device %s\n",
3914be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown						  pci_name(bridge)));
392beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas				return NULL;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pin = bridge_pin;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3975697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas		entry = acpi_pci_irq_find_prt_entry(bridge, pin);
3983b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas		if (entry) {
3993b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4003b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas					 "Derived GSI for %s INT %c from %s\n",
4013b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas					 pci_name(dev), pin_name(orig_pin),
4023b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas					 pci_name(bridge)));
4033b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas			return entry;
4043b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas		}
405ee40136313323db1096b17df7b436d22a24ef2beBjorn Helgaas
406ee40136313323db1096b17df7b436d22a24ef2beBjorn Helgaas		dev = bridge;
407ee40136313323db1096b17df7b436d22a24ef2beBjorn Helgaas		bridge = dev->bus->self;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4103b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas	dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
4113b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas		 pin_name(orig_pin));
4123b1ea18d3b3542b55861d7f968ded705e3bc2aa6Bjorn Helgaas	return NULL;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_irq_enable(struct pci_dev *dev)
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
417beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas	struct acpi_prt_entry *entry;
4183f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaas	int gsi;
4193f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaas	u8 pin;
42050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	int triggering = ACPI_LEVEL_SENSITIVE;
42150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore	int polarity = ACPI_ACTIVE_LOW;
4224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	char *link = NULL;
423c83642d5123225a22cccd75adea6e97c245714cbBjorn Helgaas	char link_desc[16];
4244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int rc;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4268015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi	pin = dev->pin;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pin) {
4284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				  "No interrupt pin configured for device %s\n",
4304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				  pci_name(dev)));
431d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
434beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas	entry = acpi_pci_irq_lookup(dev, pin);
4355697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas	if (!entry) {
43696c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox		/*
43796c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox		 * IDE legacy mode controller IRQs are magic. Why do compat
43896c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox		 * extensions always make such a nasty mess.
43996c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox		 */
44096c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE &&
44196c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox				(dev->class & 0x05) == 0)
44296c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox			return 0;
44396c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox	}
4445697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas
44574f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas	if (entry) {
44674f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas		if (entry->link)
44774f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas			gsi = acpi_pci_link_allocate_irq(entry->link,
44874f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas							 entry->index,
44974f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas							 &triggering, &polarity,
45074f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas							 &link);
45174f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas		else
45274f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas			gsi = entry->index;
45374f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas	} else
4545697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas		gsi = -1;
4555697b7ca406b4ee0afeef6d9a29b823767716cabBjorn Helgaas
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * No IRQ known to the ACPI subsystem - maybe the BIOS /
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * driver reported one, then use it. Exit in any case.
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
460c13f889a24e6ced50abb582dab3ee4b7c79b038eBjorn Helgaas	if (gsi < 0) {
461414d3448dbcb40807a1265ace64b2576ef919fbeEric W. Biederman		u32 dev_gsi;
462cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas		dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin));
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Interrupt Line values above 0xF are forbidden */
464414d3448dbcb40807a1265ace64b2576ef919fbeEric W. Biederman		if (dev->irq > 0 && (dev->irq <= 0xF) &&
465414d3448dbcb40807a1265ace64b2576ef919fbeEric W. Biederman		    (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
466414d3448dbcb40807a1265ace64b2576ef919fbeEric W. Biederman			printk(" - using ISA IRQ %d\n", dev->irq);
467414d3448dbcb40807a1265ace64b2576ef919fbeEric W. Biederman			acpi_register_gsi(&dev->dev, dev_gsi,
468a2f809b08ae4dddc1015c7dcd8659e5729e45b3eYinghai Lu					  ACPI_LEVEL_SENSITIVE,
4694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					  ACPI_ACTIVE_LOW);
470d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return 0;
4714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		} else {
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("\n");
473d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return 0;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
477a2f809b08ae4dddc1015c7dcd8659e5729e45b3eYinghai Lu	rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
478349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige	if (rc < 0) {
479c83642d5123225a22cccd75adea6e97c245714cbBjorn Helgaas		dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
480cf68b80b0e0cbc6a0d7bbb36b07ce94779ef5f1fBjorn Helgaas			 pin_name(pin));
481d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return rc;
482349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige	}
483349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige	dev->irq = rc;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (link)
486c83642d5123225a22cccd75adea6e97c245714cbBjorn Helgaas		snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
487c83642d5123225a22cccd75adea6e97c245714cbBjorn Helgaas	else
488c83642d5123225a22cccd75adea6e97c245714cbBjorn Helgaas		link_desc[0] = '\0';
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49085b8582d7ca516030efb84d94fa29a73c1d9a125Vincent Palatin	dev_dbg(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
49185b8582d7ca516030efb84d94fa29a73c1d9a125Vincent Palatin		pin_name(pin), link_desc, gsi,
49285b8582d7ca516030efb84d94fa29a73c1d9a125Vincent Palatin		(triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
49385b8582d7ca516030efb84d94fa29a73c1d9a125Vincent Palatin		(polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
495d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return 0;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* FIXME: implement x86/x86_64 version */
4994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
5004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown{
5014be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown}
50287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li
5034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid acpi_pci_irq_disable(struct pci_dev *dev)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
505beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas	struct acpi_prt_entry *entry;
5063f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaas	int gsi;
5073f0f3c27be19d390f23af1075d9948d0310e2673Bjorn Helgaas	u8 pin;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5098015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi	pin = dev->pin;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pin)
511d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
513beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas	entry = acpi_pci_irq_lookup(dev, pin);
514beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas	if (!entry)
515d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51774f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas	if (entry->link)
51874f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas		gsi = acpi_pci_link_free_irq(entry->link);
51974f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas	else
52074f82af1eda39c26c17f8030e4f60c00929ec9dfBjorn Helgaas		gsi = entry->index;
521beba8a643d7f774cf27c3c92a51b99cebf787415Bjorn Helgaas
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * TBD: It might be worth clearing dev->irq by magic constant
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (e.g. PCI_UNDEFINED_IRQ).
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52785b8582d7ca516030efb84d94fa29a73c1d9a125Vincent Palatin	dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_unregister_gsi(gsi);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
530