pci_irq.c revision 391df5dce30a5aab477b9e55ea65a3e83bae96b1
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> 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 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas#include <linux/dmi.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pm.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/acpi.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT ACPI_PCI_COMPONENT 42f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("pci_irq"); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic struct acpi_prt_list acpi_prt; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(acpi_prt_lock); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI IRQ Routing Table (PRT) Support 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, 524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int bus, 534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int device, int pin) 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!acpi_prt.count) 58d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return NULL; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse through all PRT entries looking for a match on the specified 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI device's segment, bus, device, and pin (don't care about func). 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&acpi_prt_lock); 661a3b77ae60f19fa85f4cdc34b6c09efb1a18372cMatthias Kaehlcke list_for_each_entry(entry, &acpi_prt.entries, node) { 674be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if ((segment == entry->id.segment) 684be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && (bus == entry->id.bus) 694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && (device == entry->id.device) 704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && (pin == entry->pin)) { 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 72d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return entry; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 77d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return NULL; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ 81391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstatic struct dmi_system_id medion_md9580[] = { 82391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { 83391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas .ident = "Medion MD9580-F laptop", 84391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas .matches = { 85391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 86391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_PRODUCT_NAME, "A555"), 87391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas }, 88391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas }, 89391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { } 90391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas}; 91391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 92391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* http://bugzilla.kernel.org/show_bug.cgi?id=5044 */ 93391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstatic struct dmi_system_id dell_optiplex[] = { 94391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { 95391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas .ident = "Dell Optiplex GX1", 96391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas .matches = { 97391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 98391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX1 600S+"), 99391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas }, 100391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas }, 101391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { } 102391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas}; 103391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 104391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* http://bugzilla.kernel.org/show_bug.cgi?id=10138 */ 105391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstatic struct dmi_system_id hp_t5710[] = { 106391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { 107391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas .ident = "HP t5710", 108391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas .matches = { 109391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 110391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_PRODUCT_NAME, "hp t5000 series"), 111391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas DMI_MATCH(DMI_BOARD_NAME, "098Ch"), 112391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas }, 113391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas }, 114391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { } 115391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas}; 116391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 117391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstruct prt_quirk { 118391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas struct dmi_system_id *system; 119391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas unsigned int segment; 120391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas unsigned int bus; 121391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas unsigned int device; 122391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas unsigned char pin; 123391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas char *source; /* according to BIOS */ 124391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas char *actual_source; 125391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas}; 126391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 127391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas/* 128391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas * These systems have incorrect _PRT entries. The BIOS claims the PCI 129391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas * interrupt at the listed segment/bus/device/pin is connected to the first 130391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas * link device, but it is actually connected to the second. 131391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas */ 132391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstatic struct prt_quirk prt_quirks[] = { 133391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { medion_md9580, 0, 0, 9, 'A', 134391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "\\_SB_.PCI0.ISA.LNKA", 135391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "\\_SB_.PCI0.ISA.LNKB"}, 136391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { dell_optiplex, 0, 0, 0xd, 'A', 137391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "\\_SB_.LNKB", 138391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "\\_SB_.LNKA"}, 139391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas { hp_t5710, 0, 0, 1, 'A', 140391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "\\_SB_.PCI0.LNK1", 141391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "\\_SB_.PCI0.LNK3"}, 142391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas}; 143391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 144391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasstatic void 145391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaasdo_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) 146391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas{ 147391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas int i; 148391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas struct prt_quirk *quirk; 149391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 150391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas for (i = 0; i < ARRAY_SIZE(prt_quirks); i++) { 151391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas quirk = &prt_quirks[i]; 152391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 153391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas /* All current quirks involve link devices, not GSIs */ 154391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas if (!prt->source) 155391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas continue; 156391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 157391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas if (dmi_check_system(quirk->system) && 158391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas entry->id.segment == quirk->segment && 159391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas entry->id.bus == quirk->bus && 160391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas entry->id.device == quirk->device && 161391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas entry->pin + 'A' == quirk->pin && 162391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas !strcmp(prt->source, quirk->source) && 163391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas strlen(prt->source) >= strlen(quirk->actual_source)) { 164391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas printk(KERN_WARNING PREFIX "firmware reports " 165391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "%04x:%02x:%02x[%c] connected to %s; " 166391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas "changing to %s\n", 167391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas entry->id.segment, entry->id.bus, 168391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas entry->id.device, 'A' + entry->pin, 169391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas prt->source, quirk->actual_source); 170391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas strcpy(prt->source, quirk->actual_source); 171391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas } 172391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas } 173391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas} 174391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_add_entry(acpi_handle handle, 1774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int segment, int bus, struct acpi_pci_routing_table *prt) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!prt) 183d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18536bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) 187d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.segment = segment; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.bus = bus; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.device = (prt->address >> 16) & 0xFFFF; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.function = prt->address & 0xFFFF; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->pin = prt->pin; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 195391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas do_prt_fixups(entry, prt); 196391df5dce30a5aab477b9e55ea65a3e83bae96b1Bjorn Helgaas 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Type 1: Dynamic 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * --------------- 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 'source' field specifies the PCI interrupt link device used to 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configure the IRQ assigned to this slot|dev|pin. The 'source_index' 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indicates which resource descriptor in the resource template (of 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the link device) this interrupt is allocated from. 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: Don't query the Link Device for IRQ information at this time 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * because Link Device enumeration may not have occurred yet 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (e.g. exists somewhere 'below' this _PRT entry in the ACPI 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * namespace). 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (prt->source[0]) { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_handle(handle, prt->source, &entry->link.handle); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->link.index = prt->source_index; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Type 2: Static 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -------------- 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 'source' field is NULL, and the 'source_index' field specifies 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IRQ value, which is hardwired to specific interrupt inputs on 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the interrupt controller. 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->link.index = prt->source_index; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, 2254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown " %02X:%02X:%02X[%c] -> %s[%d]\n", 2264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry->id.segment, entry->id.bus, 2274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry->id.device, ('A' + entry->pin), prt->source, 2284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry->link.index)); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&acpi_prt_lock); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&entry->node, &acpi_prt.entries); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_prt.count++; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 235d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (segment == entry->id.segment && bus == entry->id.bus) { 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_prt.count--; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&entry->node); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(entry); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 2514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown char *pathname = NULL; 2524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { 0, NULL }; 2534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_routing_table *prt = NULL; 2544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_routing_table *entry = NULL; 2554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown static int first_time = 1; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25836bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); 2594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!pathname) 260d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (first_time) { 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_prt.count = 0; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&acpi_prt.entries); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_time = 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: We're given a 'handle' to the _PRT object's parent device 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (either a PCI root bridge or PCI-PCI bridge). 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.length = ACPI_PATHNAME_MAX; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = pathname; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", 2784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pathname); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Evaluate this _PRT and add its entries to our global list (acpi_prt). 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.length = 0; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = NULL; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pathname); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_irq_routing_table(handle, &buffer); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != AE_BUFFER_OVERFLOW) { 289a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", 290a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_format_exception(status))); 291d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29436bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan prt = kzalloc(buffer.length, GFP_KERNEL); 2954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!prt) { 296d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = prt; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_irq_routing_table(handle, &buffer); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 302a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", 303a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_format_exception(status))); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buffer.pointer); 305d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = prt; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (entry && (entry->length > 0)) { 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_irq_add_entry(handle, segment, bus, entry); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = (struct acpi_pci_routing_table *) 3134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ((unsigned long)entry + entry->length); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(prt); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 318d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid acpi_pci_irq_del_prt(int segment, int bus) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head *node = NULL, *n = NULL; 3244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!acpi_prt.count) { 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown printk(KERN_DEBUG 3314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", segment, 3324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown bus); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&acpi_prt_lock); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(node, n, &acpi_prt.entries) { 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = list_entry(node, struct acpi_prt_entry, node); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_irq_del_entry(segment, bus, entry); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Interrupt Routing Support 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 3454be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Browntypedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Listatic int 34887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Liacpi_pci_allocate_irq(struct acpi_prt_entry *entry, 34950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, int *polarity, char **link) 35087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 3514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 35287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 35387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 35487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (entry->link.handle) { 35587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = acpi_pci_link_allocate_irq(entry->link.handle, 35650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore entry->link.index, triggering, 35750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore polarity, link); 35887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (irq < 0) { 359cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 360cece92969762b8ed7930d4e23008b76b06411deeLen Brown "Invalid IRQ link routing entry\n"); 361d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 36287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 36387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } else { 36487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = entry->link.index; 36550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *triggering = ACPI_LEVEL_SENSITIVE; 36650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *polarity = ACPI_ACTIVE_LOW; 36787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 36887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 36987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq)); 370d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return irq; 37187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 37287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 37387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Listatic int 37487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Liacpi_pci_free_irq(struct acpi_prt_entry *entry, 37550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, int *polarity, char **link) 37687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 3774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 37887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 37987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (entry->link.handle) { 38087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = acpi_pci_link_free_irq(entry->link.handle); 38187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } else { 38287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = entry->link.index; 38387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 384d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return irq; 38587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 3864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_pci_irq_lookup 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_lookup(struct pci_bus *bus, 3944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int device, 3954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int pin, 39650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, 39750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *polarity, char **link, irq_lookup_func func) 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int segment = pci_domain_nr(bus); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bus_nr = bus->number; 40287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li int ret; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 4064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Searching for PRT entry for %02x:%02x:%02x[%c]\n", 4074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown segment, bus_nr, device, ('A' + pin))); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) { 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n")); 412d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 41550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore ret = func(entry, triggering, polarity, link); 416d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return ret; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_pci_irq_derive 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return < 0 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_derive(struct pci_dev *dev, 4264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int pin, 42750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, 42850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *polarity, char **link, irq_lookup_func func) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct pci_dev *bridge = dev; 4314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = -1; 4324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 bridge_pin = 0; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 436d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attempt to derive an IRQ for this device from a parent bridge's 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (irq < 0 && bridge->bus->self) { 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin = (pin + PCI_SLOT(bridge->devfn)) % 4; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = bridge->bus->self; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PC card has the same IRQ as its cardbridge */ 4488015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi bridge_pin = bridge->pin; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bridge_pin) { 4504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 4514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "No interrupt pin configured for device %s\n", 4524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(bridge))); 453d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Pin is from 0 to 3 */ 4564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown bridge_pin--; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin = bridge_pin; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn), 46150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore pin, triggering, polarity, 4624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link, func); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) { 466cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Unable to derive IRQ for device %s\n", 467cece92969762b8ed7930d4e23008b76b06411deeLen Brown pci_name(dev)); 468d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n", 4724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown irq, pci_name(dev), pci_name(bridge))); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 474d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return irq; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_pci_irq_enable 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return 0 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return < 0 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_irq_enable(struct pci_dev *dev) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = 0; 4864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 pin = 0; 48750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int triggering = ACPI_LEVEL_SENSITIVE; 48850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int polarity = ACPI_ACTIVE_LOW; 4894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown char *link = NULL; 4904be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int rc; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 494d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 4954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 4968015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi pin = dev->pin; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pin) { 4984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 4994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "No interrupt pin configured for device %s\n", 5004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(dev))); 501d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin--; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev->bus) { 5066468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid (NULL) 'bus' field\n"); 507d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * values override any BIOS-assigned IRQs set during boot. 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, 51550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &triggering, &polarity, &link, 5164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_allocate_irq); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no PRT entry was found, we'll try to derive an IRQ from the 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's parent bridge. 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) 52350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore irq = acpi_pci_irq_derive(dev, pin, &triggering, 52450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &polarity, &link, 5254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_allocate_irq); 5264be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 52796c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox if (irq < 0) { 52896c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox /* 52996c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox * IDE legacy mode controller IRQs are magic. Why do compat 53096c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox * extensions always make such a nasty mess. 53196c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox */ 53296c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && 53396c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox (dev->class & 0x05) == 0) 53496c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox return 0; 53596c2a8766bf4fe91abac863749c11637fabcc64fAlan Cox } 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No IRQ known to the ACPI subsystem - maybe the BIOS / 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver reported one, then use it. Exit in any case. 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI", 5424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(dev), ('A' + pin)); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interrupt Line values above 0xF are forbidden */ 54444f8e1a20cf3afe10a3744bd9317808a39a242bbLinus Torvalds if (dev->irq > 0 && (dev->irq <= 0xF)) { 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" - using IRQ %d\n", dev->irq); 5464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, 5474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_ACTIVE_LOW); 548d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } else { 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 551d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore rc = acpi_register_gsi(irq, triggering, polarity); 556349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige if (rc < 0) { 557349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed " 558349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige "to register GSI\n", pci_name(dev), ('A' + pin)); 559d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return rc; 560349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige } 561349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige dev->irq = rc; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ", 5644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(dev), 'A' + pin); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link) 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Link [%s] -> ", link); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("GSI %u (%s, %s) -> IRQ %d\n", irq, 57050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", 57150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 573d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* FIXME: implement x86/x86_64 version */ 5774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid __attribute__ ((weak)) acpi_unregister_gsi(u32 i) 5784be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown{ 5794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown} 58087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 5814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid acpi_pci_irq_disable(struct pci_dev *dev) 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int gsi = 0; 5844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 pin = 0; 58550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int triggering = ACPI_LEVEL_SENSITIVE; 58650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int polarity = ACPI_ACTIVE_LOW; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5895f0110f2a716376f3b260703835f527ca8900946Kenji Kaneshige if (!dev || !dev->bus) 590d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5928015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi pin = dev->pin; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pin) 594d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin--; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we check the PCI IRQ routing table (PRT) for an IRQ. 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, 60150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &triggering, &polarity, NULL, 6024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_free_irq); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no PRT entry was found, we'll try to derive an IRQ from the 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's parent bridge. 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gsi < 0) 6084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown gsi = acpi_pci_irq_derive(dev, pin, 60950eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &triggering, &polarity, NULL, 6104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_free_irq); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gsi < 0) 612d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TBD: It might be worth clearing dev->irq by magic constant 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (e.g. PCI_UNDEFINED_IRQ). 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n", 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_name(dev)); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_unregister_gsi(gsi); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 624d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 626