pci_irq.c revision d550d98d3317378d93a4869db204725d270ec812
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#include <linux/config.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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 424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen 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 list_head *node = NULL; 564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!acpi_prt.count) 60d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return NULL; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse through all PRT entries looking for a match on the specified 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI device's segment, bus, device, and pin (don't care about func). 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&acpi_prt_lock); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(node, &acpi_prt.entries) { 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = list_entry(node, struct acpi_prt_entry, node); 704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if ((segment == entry->id.segment) 714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && (bus == entry->id.bus) 724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && (device == entry->id.device) 734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown && (pin == entry->pin)) { 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 75d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return entry; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 80d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return NULL; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_add_entry(acpi_handle handle, 854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int segment, int bus, struct acpi_pci_routing_table *prt) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 874be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!prt) 91d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) 95d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(entry, 0, sizeof(struct acpi_prt_entry)); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.segment = segment; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.bus = bus; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.device = (prt->address >> 16) & 0xFFFF; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->id.function = prt->address & 0xFFFF; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->pin = prt->pin; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Type 1: Dynamic 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * --------------- 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 'source' field specifies the PCI interrupt link device used to 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configure the IRQ assigned to this slot|dev|pin. The 'source_index' 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indicates which resource descriptor in the resource template (of 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the link device) this interrupt is allocated from. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: Don't query the Link Device for IRQ information at this time 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * because Link Device enumeration may not have occurred yet 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (e.g. exists somewhere 'below' this _PRT entry in the ACPI 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * namespace). 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (prt->source[0]) { 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_handle(handle, prt->source, &entry->link.handle); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->link.index = prt->source_index; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Type 2: Static 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -------------- 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 'source' field is NULL, and the 'source_index' field specifies 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IRQ value, which is hardwired to specific interrupt inputs on 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the interrupt controller. 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->link.index = prt->source_index; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, 1324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown " %02X:%02X:%02X[%c] -> %s[%d]\n", 1334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry->id.segment, entry->id.bus, 1344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry->id.device, ('A' + entry->pin), prt->source, 1354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry->link.index)); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&acpi_prt_lock); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&entry->node, &acpi_prt.entries); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_prt.count++; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1484be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (segment == entry->id.segment && bus == entry->id.bus) { 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_prt.count--; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&entry->node); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(entry); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1574be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 1584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown char *pathname = NULL; 1594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { 0, NULL }; 1604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_routing_table *prt = NULL; 1614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_pci_routing_table *entry = NULL; 1624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown static int first_time = 1; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1654be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); 1664be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!pathname) 167d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(pathname, 0, ACPI_PATHNAME_MAX); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (first_time) { 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_prt.count = 0; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&acpi_prt.entries); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_time = 0; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: We're given a 'handle' to the _PRT object's parent device 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (either a PCI root bridge or PCI-PCI bridge). 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.length = ACPI_PATHNAME_MAX; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = pathname; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", 1864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pathname); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Evaluate this _PRT and add its entries to our global list (acpi_prt). 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.length = 0; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = NULL; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pathname); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_irq_routing_table(handle, &buffer); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != AE_BUFFER_OVERFLOW) { 197a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", 198a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_format_exception(status))); 199d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prt = kmalloc(buffer.length, GFP_KERNEL); 2034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!prt) { 204d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(prt, 0, buffer.length); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer.pointer = prt; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_irq_routing_table(handle, &buffer); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 211a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", 212a6fc67202e0224e6c9d1d285cc0b444bce887ed5Thomas Renninger acpi_format_exception(status))); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buffer.pointer); 214d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = prt; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (entry && (entry->length > 0)) { 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_irq_add_entry(handle, segment, bus, entry); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = (struct acpi_pci_routing_table *) 2224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ((unsigned long)entry + entry->length); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(prt); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 227d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid acpi_pci_irq_del_prt(int segment, int bus) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct list_head *node = NULL, *n = NULL; 2334be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if (!acpi_prt.count) { 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown printk(KERN_DEBUG 2404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", segment, 2414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown bus); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&acpi_prt_lock); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(node, n, &acpi_prt.entries) { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = list_entry(node, struct acpi_prt_entry, node); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_irq_del_entry(segment, bus, entry); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&acpi_prt_lock); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI Interrupt Routing Support 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 2544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Browntypedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Listatic int 25787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Liacpi_pci_allocate_irq(struct acpi_prt_entry *entry, 25850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, int *polarity, char **link) 25987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 2604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 26187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 26287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 26387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (entry->link.handle) { 26487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = acpi_pci_link_allocate_irq(entry->link.handle, 26550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore entry->link.index, triggering, 26650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore polarity, link); 26787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (irq < 0) { 268cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX 269cece92969762b8ed7930d4e23008b76b06411deeLen Brown "Invalid IRQ link routing entry\n"); 270d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 27187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 27287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } else { 27387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = entry->link.index; 27450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *triggering = ACPI_LEVEL_SENSITIVE; 27550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore *polarity = ACPI_ACTIVE_LOW; 27687bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 27787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 27887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq)); 279d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return irq; 28087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 28187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 28287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Listatic int 28387bec66b9691522414862dd8d41e430b063735efDavid Shaohua Liacpi_pci_free_irq(struct acpi_prt_entry *entry, 28450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, int *polarity, char **link) 28587bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li{ 2864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq; 28787bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 28887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li if (entry->link.handle) { 28987bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = acpi_pci_link_free_irq(entry->link.handle); 29087bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } else { 29187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li irq = entry->link.index; 29287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li } 293d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return irq; 29487bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li} 2954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_pci_irq_lookup 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return -1 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_lookup(struct pci_bus *bus, 3034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int device, 3044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int pin, 30550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, 30650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *polarity, char **link, irq_lookup_func func) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_prt_entry *entry = NULL; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int segment = pci_domain_nr(bus); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bus_nr = bus->number; 31187bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li int ret; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3144be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 3154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "Searching for PRT entry for %02x:%02x:%02x[%c]\n", 3164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown segment, bus_nr, device, ('A' + pin))); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) { 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n")); 321d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 32450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore ret = func(entry, triggering, polarity, link); 325d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return ret; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_pci_irq_derive 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return IRQ >= 0 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return < 0 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_pci_irq_derive(struct pci_dev *dev, 3354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int pin, 33650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *triggering, 33750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int *polarity, char **link, irq_lookup_func func) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3394be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct pci_dev *bridge = dev; 3404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = -1; 3414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 bridge_pin = 0; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 345d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attempt to derive an IRQ for this device from a parent bridge's 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (irq < 0 && bridge->bus->self) { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin = (pin + PCI_SLOT(bridge->devfn)) % 4; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = bridge->bus->self; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PC card has the same IRQ as its cardbridge */ 3578015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi bridge_pin = bridge->pin; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bridge_pin) { 3594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 3604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "No interrupt pin configured for device %s\n", 3614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(bridge))); 362d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Pin is from 0 to 3 */ 3654be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown bridge_pin--; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin = bridge_pin; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn), 37050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore pin, triggering, polarity, 3714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown link, func); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) { 375cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Unable to derive IRQ for device %s\n", 376cece92969762b8ed7930d4e23008b76b06411deeLen Brown pci_name(dev)); 377d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -1; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n", 3814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown irq, pci_name(dev), pci_name(bridge))); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 383d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return irq; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_pci_irq_enable 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * success: return 0 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * failure: return < 0 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_pci_irq_enable(struct pci_dev *dev) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int irq = 0; 3954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 pin = 0; 39650eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int triggering = ACPI_LEVEL_SENSITIVE; 39750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int polarity = ACPI_ACTIVE_LOW; 3984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown char *link = NULL; 3994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int rc; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 403d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 4044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 4058015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi pin = dev->pin; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pin) { 4074be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, 4084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown "No interrupt pin configured for device %s\n", 4094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(dev))); 410d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin--; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev->bus) { 4156468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Invalid (NULL) 'bus' field\n"); 416d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * values override any BIOS-assigned IRQs set during boot. 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, 42450eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &triggering, &polarity, &link, 4254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_allocate_irq); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no PRT entry was found, we'll try to derive an IRQ from the 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's parent bridge. 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) 43250eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore irq = acpi_pci_irq_derive(dev, pin, &triggering, 43350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &polarity, &link, 4344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_allocate_irq); 4354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No IRQ known to the ACPI subsystem - maybe the BIOS / 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver reported one, then use it. Exit in any case. 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq < 0) { 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI", 4424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(dev), ('A' + pin)); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interrupt Line values above 0xF are forbidden */ 44444f8e1a20cf3afe10a3744bd9317808a39a242bbLinus Torvalds if (dev->irq > 0 && (dev->irq <= 0xF)) { 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" - using IRQ %d\n", dev->irq); 4464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, 4474be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown ACPI_ACTIVE_LOW); 448d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 4494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } else { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 451d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown } 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45550eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore rc = acpi_register_gsi(irq, triggering, polarity); 456349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige if (rc < 0) { 457349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed " 458349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige "to register GSI\n", pci_name(dev), ('A' + pin)); 459d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return rc; 460349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige } 461349f0d5640c18db09a646f9da51a97f1da908660Kenji Kaneshige dev->irq = rc; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ", 4644be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown pci_name(dev), 'A' + pin); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (link) 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Link [%s] -> ", link); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("GSI %u (%s, %s) -> IRQ %d\n", irq, 47050eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", 47150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 473d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen BrownEXPORT_SYMBOL(acpi_pci_irq_enable); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47887bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li/* FIXME: implement x86/x86_64 version */ 4794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid __attribute__ ((weak)) acpi_unregister_gsi(u32 i) 4804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown{ 4814be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown} 48287bec66b9691522414862dd8d41e430b063735efDavid Shaohua Li 4834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownvoid acpi_pci_irq_disable(struct pci_dev *dev) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4854be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int gsi = 0; 4864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u8 pin = 0; 48750eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int triggering = ACPI_LEVEL_SENSITIVE; 48850eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore int polarity = ACPI_ACTIVE_LOW; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4915f0110f2a716376f3b260703835f527ca8900946Kenji Kaneshige if (!dev || !dev->bus) 492d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4948015a01486a0f789c9e98e8bf1f12a3ccb535b30Kristen Accardi pin = dev->pin; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pin) 496d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin--; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we check the PCI IRQ routing table (PRT) for an IRQ. 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5024be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, 50350eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &triggering, &polarity, NULL, 5044be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_free_irq); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no PRT entry was found, we'll try to derive an IRQ from the 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device's parent bridge. 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gsi < 0) 5104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown gsi = acpi_pci_irq_derive(dev, pin, 51150eca3eb89d73d9f0aa070b126c7ee6a616016abBob Moore &triggering, &polarity, NULL, 5124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_pci_free_irq); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gsi < 0) 514d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TBD: It might be worth clearing dev->irq by magic constant 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (e.g. PCI_UNDEFINED_IRQ). 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n", 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_name(dev)); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_unregister_gsi(gsi); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 526d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 528