summaryrefslogtreecommitdiff
path: root/drivers/acpi/pci_link.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/pci_link.c')
-rw-r--r--drivers/acpi/pci_link.c373
1 files changed, 199 insertions, 174 deletions
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 2652a614deeb..bed7dc85612e 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 34 $)
*
@@ -5,30 +6,14 @@
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2002 Dominik Brodowski <devel@brodo.de>
*
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * TBD:
- * 1. Support more than one IRQ resource entry per link device (index).
+ * TBD:
+ * 1. Support more than one IRQ resource entry per link device (index).
* 2. Implement start/stop mechanism and use ACPI Bus Driver facilities
* for IRQ management (e.g. start()->_SRS).
*/
+#define pr_fmt(fmt) "ACPI: PCI: " fmt
+
#include <linux/syscore_ops.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -39,18 +24,13 @@
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/irq.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define PREFIX "ACPI: "
+#include "internal.h"
-#define _COMPONENT ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
-#define ACPI_PCI_LINK_FILE_INFO "info"
-#define ACPI_PCI_LINK_FILE_STATUS "state"
#define ACPI_PCI_LINK_MAX_POSSIBLE 16
static int acpi_pci_link_add(struct acpi_device *device,
@@ -73,12 +53,12 @@ static struct acpi_scan_handler pci_link_handler = {
* later even the link is disable. Instead, we just repick the active irq
*/
struct acpi_pci_link_irq {
- u8 active; /* Current IRQ */
+ u32 active; /* Current IRQ */
u8 triggering; /* All IRQs */
u8 polarity; /* All IRQs */
u8 resource_type;
u8 possible_count;
- u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
+ u32 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
u8 initialized:1;
u8 reserved:7;
};
@@ -92,6 +72,7 @@ struct acpi_pci_link {
static LIST_HEAD(acpi_link_list);
static DEFINE_MUTEX(acpi_link_lock);
+static int sci_irq = -1, sci_penalty;
/* --------------------------------------------------------------------------
PCI Link Device Management
@@ -104,6 +85,7 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
void *context)
{
struct acpi_pci_link *link = context;
+ acpi_handle handle = link->device->handle;
u32 i;
switch (resource->type) {
@@ -113,18 +95,18 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
case ACPI_RESOURCE_TYPE_IRQ:
{
struct acpi_resource_irq *p = &resource->data.irq;
- if (!p || !p->interrupt_count) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Blank _PRS IRQ resource\n"));
+ if (!p->interrupt_count) {
+ acpi_handle_debug(handle,
+ "Blank _PRS IRQ resource\n");
return AE_OK;
}
for (i = 0;
(i < p->interrupt_count
&& i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
if (!p->interrupts[i]) {
- printk(KERN_WARNING PREFIX
- "Invalid _PRS IRQ %d\n",
- p->interrupts[i]);
+ acpi_handle_debug(handle,
+ "Invalid _PRS IRQ %d\n",
+ p->interrupts[i]);
continue;
}
link->irq.possible[i] = p->interrupts[i];
@@ -139,18 +121,18 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
{
struct acpi_resource_extended_irq *p =
&resource->data.extended_irq;
- if (!p || !p->interrupt_count) {
- printk(KERN_WARNING PREFIX
- "Blank _PRS EXT IRQ resource\n");
+ if (!p->interrupt_count) {
+ acpi_handle_debug(handle,
+ "Blank _PRS EXT IRQ resource\n");
return AE_OK;
}
for (i = 0;
(i < p->interrupt_count
&& i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
if (!p->interrupts[i]) {
- printk(KERN_WARNING PREFIX
- "Invalid _PRS IRQ %d\n",
- p->interrupts[i]);
+ acpi_handle_debug(handle,
+ "Invalid _PRS IRQ %d\n",
+ p->interrupts[i]);
continue;
}
link->irq.possible[i] = p->interrupts[i];
@@ -162,8 +144,8 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
break;
}
default:
- printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n",
- resource->type);
+ acpi_handle_debug(handle, "_PRS resource type 0x%x is not IRQ\n",
+ resource->type);
return AE_OK;
}
@@ -172,18 +154,18 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
static int acpi_pci_link_get_possible(struct acpi_pci_link *link)
{
+ acpi_handle handle = link->device->handle;
acpi_status status;
- status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
+ status = acpi_walk_resources(handle, METHOD_NAME__PRS,
acpi_pci_link_check_possible, link);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
- return -ENODEV;
+ acpi_handle_debug(handle, "_PRS not present or invalid");
+ return 0;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found %d possible IRQs\n",
- link->irq.possible_count));
+ acpi_handle_debug(handle, "Found %d possible IRQs\n",
+ link->irq.possible_count);
return 0;
}
@@ -200,13 +182,12 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
case ACPI_RESOURCE_TYPE_IRQ:
{
struct acpi_resource_irq *p = &resource->data.irq;
- if (!p || !p->interrupt_count) {
+ if (!p->interrupt_count) {
/*
* IRQ descriptors may have no IRQ# bits set,
- * particularly those those w/ _STA disabled
+ * particularly those w/ _STA disabled
*/
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Blank _CRS IRQ resource\n"));
+ pr_debug("Blank _CRS IRQ resource\n");
return AE_OK;
}
*irq = p->interrupts[0];
@@ -216,13 +197,12 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
{
struct acpi_resource_extended_irq *p =
&resource->data.extended_irq;
- if (!p || !p->interrupt_count) {
+ if (!p->interrupt_count) {
/*
* extended IRQ descriptors must
* return at least 1 IRQ
*/
- printk(KERN_WARNING PREFIX
- "Blank _CRS EXT IRQ resource\n");
+ pr_debug("Blank _CRS EXT IRQ resource\n");
return AE_OK;
}
*irq = p->interrupts[0];
@@ -230,8 +210,8 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
}
break;
default:
- printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n",
- resource->type);
+ pr_debug("_CRS resource type 0x%x is not IRQ\n",
+ resource->type);
return AE_OK;
}
@@ -247,8 +227,9 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
*/
static int acpi_pci_link_get_current(struct acpi_pci_link *link)
{
- int result = 0;
+ acpi_handle handle = link->device->handle;
acpi_status status;
+ int result = 0;
int irq = 0;
link->irq.active = 0;
@@ -258,36 +239,36 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
/* Query _STA, set link->device->status */
result = acpi_bus_get_status(link->device);
if (result) {
- printk(KERN_ERR PREFIX "Unable to read status\n");
+ acpi_handle_err(handle, "Unable to read status\n");
goto end;
}
if (!link->device->status.enabled) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
+ acpi_handle_debug(handle, "Link disabled\n");
return 0;
}
}
- /*
- * Query and parse _CRS to get the current IRQ assignment.
+ /*
+ * Query and parse _CRS to get the current IRQ assignment.
*/
- status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
acpi_pci_link_check_current, &irq);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
+ acpi_evaluation_failure_warn(handle, "_CRS", status);
result = -ENODEV;
goto end;
}
if (acpi_strict && !irq) {
- printk(KERN_ERR PREFIX "_CRS returned 0\n");
+ acpi_handle_err(handle, "_CRS returned 0\n");
result = -ENODEV;
}
link->irq.active = irq;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
+ acpi_handle_debug(handle, "Link at IRQ %d\n", link->irq.active);
end:
return result;
@@ -295,13 +276,14 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
{
- int result;
- acpi_status status;
struct {
struct acpi_resource res;
struct acpi_resource end;
} *resource;
struct acpi_buffer buffer = { 0, NULL };
+ acpi_handle handle = link->device->handle;
+ acpi_status status;
+ int result;
if (!irq)
return -EINVAL;
@@ -321,10 +303,10 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
resource->res.data.irq.polarity =
link->irq.polarity;
if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
- resource->res.data.irq.sharable =
+ resource->res.data.irq.shareable =
ACPI_EXCLUSIVE;
else
- resource->res.data.irq.sharable = ACPI_SHARED;
+ resource->res.data.irq.shareable = ACPI_SHARED;
resource->res.data.irq.interrupt_count = 1;
resource->res.data.irq.interrupts[0] = irq;
break;
@@ -339,16 +321,17 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
resource->res.data.extended_irq.polarity =
link->irq.polarity;
if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
- resource->res.data.irq.sharable =
+ resource->res.data.extended_irq.shareable =
ACPI_EXCLUSIVE;
else
- resource->res.data.irq.sharable = ACPI_SHARED;
+ resource->res.data.extended_irq.shareable = ACPI_SHARED;
resource->res.data.extended_irq.interrupt_count = 1;
resource->res.data.extended_irq.interrupts[0] = irq;
/* ignore resource_source, it's optional */
break;
default:
- printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type);
+ acpi_handle_err(handle, "Invalid resource type %d\n",
+ link->irq.resource_type);
result = -EINVAL;
goto end;
@@ -361,7 +344,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
/* check for total failure */
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
+ acpi_evaluation_failure_warn(handle, "_SRS", status);
result = -ENODEV;
goto end;
}
@@ -369,15 +352,11 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
/* Query _STA, set device->status */
result = acpi_bus_get_status(link->device);
if (result) {
- printk(KERN_ERR PREFIX "Unable to read status\n");
+ acpi_handle_err(handle, "Unable to read status\n");
goto end;
}
- if (!link->device->status.enabled) {
- printk(KERN_WARNING PREFIX
- "%s [%s] disabled and referenced, BIOS bug\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device));
- }
+ if (!link->device->status.enabled)
+ acpi_handle_warn(handle, "Disabled and referenced, BIOS bug\n");
/* Query _CRS, set link->irq.active */
result = acpi_pci_link_get_current(link);
@@ -394,14 +373,12 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
* policy: when _CRS doesn't return what we just _SRS
* assume _SRS worked and override _CRS value.
*/
- printk(KERN_WARNING PREFIX
- "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device), link->irq.active, irq);
+ acpi_handle_warn(handle, "BIOS reported IRQ %d, using IRQ %d\n",
+ link->irq.active, irq);
link->irq.active = irq;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
+ acpi_handle_debug(handle, "Set IRQ %d\n", link->irq.active);
end:
kfree(resource);
@@ -415,7 +392,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
/*
* "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
* Link Devices to move the PIRQs around to minimize sharing.
- *
+ *
* "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
* that the BIOS has already set to active. This is necessary because
* ACPI has no automatic means of knowing what ISA IRQs are used. Note that
@@ -433,7 +410,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
*
* Note that PCI IRQ routers have a list of possible IRQs,
* which may not include the IRQs this table says are available.
- *
+ *
* Since this heuristic can't tell the difference between a link
* that no device will attach to, vs. a link which may be shared
* by multiple active devices -- it is not optimal.
@@ -443,17 +420,15 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
* enabled system.
*/
-#define ACPI_MAX_IRQS 256
-#define ACPI_MAX_ISA_IRQ 16
+#define ACPI_MAX_ISA_IRQS 16
-#define PIRQ_PENALTY_PCI_AVAILABLE (0)
#define PIRQ_PENALTY_PCI_POSSIBLE (16*16)
#define PIRQ_PENALTY_PCI_USING (16*16*16)
#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16)
#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
-static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
+static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
@@ -463,9 +438,9 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */
- PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */
- PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */
- PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */
+ 0, /* IRQ9 PCI, often acpi */
+ 0, /* IRQ10 PCI */
+ 0, /* IRQ11 PCI */
PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */
PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */
PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */
@@ -473,6 +448,45 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
/* >IRQ15 */
};
+static int acpi_irq_pci_sharing_penalty(int irq)
+{
+ struct acpi_pci_link *link;
+ int penalty = 0;
+ int i;
+
+ list_for_each_entry(link, &acpi_link_list, list) {
+ /*
+ * If a link is active, penalize its IRQ heavily
+ * so we try to choose a different IRQ.
+ */
+ if (link->irq.active && link->irq.active == irq)
+ penalty += PIRQ_PENALTY_PCI_USING;
+
+ /*
+ * penalize the IRQs PCI might use, but not as severely.
+ */
+ for (i = 0; i < link->irq.possible_count; i++)
+ if (link->irq.possible[i] == irq)
+ penalty += PIRQ_PENALTY_PCI_POSSIBLE /
+ link->irq.possible_count;
+ }
+
+ return penalty;
+}
+
+static int acpi_irq_get_penalty(int irq)
+{
+ int penalty = 0;
+
+ if (irq == sci_irq)
+ penalty += sci_penalty;
+
+ if (irq < ACPI_MAX_ISA_IRQS)
+ return penalty + acpi_isa_irq_penalty[irq];
+
+ return penalty + acpi_irq_pci_sharing_penalty(irq);
+}
+
int __init acpi_irq_penalty_init(void)
{
struct acpi_pci_link *link;
@@ -493,19 +507,19 @@ int __init acpi_irq_penalty_init(void)
link->irq.possible_count;
for (i = 0; i < link->irq.possible_count; i++) {
- if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
- acpi_irq_penalty[link->irq.
+ if (link->irq.possible[i] < ACPI_MAX_ISA_IRQS)
+ acpi_isa_irq_penalty[link->irq.
possible[i]] +=
penalty;
}
- } else if (link->irq.active) {
- acpi_irq_penalty[link->irq.active] +=
+ } else if (link->irq.active &&
+ (link->irq.active < ACPI_MAX_ISA_IRQS)) {
+ acpi_isa_irq_penalty[link->irq.active] +=
PIRQ_PENALTY_PCI_POSSIBLE;
}
}
- /* Add a penalty for the SCI */
- acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
+
return 0;
}
@@ -513,6 +527,7 @@ static int acpi_irq_balance = -1; /* 0: static, 1: balance */
static int acpi_pci_link_allocate(struct acpi_pci_link *link)
{
+ acpi_handle handle = link->device->handle;
int irq;
int i;
@@ -535,8 +550,8 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
*/
if (i == link->irq.possible_count) {
if (acpi_strict)
- printk(KERN_WARNING PREFIX "_CRS %d not found"
- " in _PRS\n", link->irq.active);
+ acpi_handle_warn(handle, "_CRS %d not found in _PRS\n",
+ link->irq.active);
link->irq.active = 0;
}
@@ -554,24 +569,29 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
* the use of IRQs 9, 10, 11, and >15.
*/
for (i = (link->irq.possible_count - 1); i >= 0; i--) {
- if (acpi_irq_penalty[irq] >
- acpi_irq_penalty[link->irq.possible[i]])
+ if (acpi_irq_get_penalty(irq) >
+ acpi_irq_get_penalty(link->irq.possible[i]))
irq = link->irq.possible[i];
}
}
+ if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
+ acpi_handle_err(handle,
+ "No IRQ available. Try pci=noacpi or acpi=off\n");
+ return -ENODEV;
+ }
/* Attempt to enable the link device at this IRQ. */
if (acpi_pci_link_set(link, irq)) {
- printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
- "Try pci=noacpi or acpi=off\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device));
+ acpi_handle_err(handle,
+ "Unable to set IRQ. Try pci=noacpi or acpi=off\n");
return -ENODEV;
} else {
- acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
- printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device), link->irq.active);
+ if (link->irq.active < ACPI_MAX_ISA_IRQS)
+ acpi_isa_irq_penalty[link->irq.active] +=
+ PIRQ_PENALTY_PCI_USING;
+
+ acpi_handle_info(handle, "Enabled at IRQ %d\n",
+ link->irq.active);
}
link->irq.initialized = 1;
@@ -586,25 +606,23 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
int *polarity, char **name)
{
- int result;
- struct acpi_device *device;
+ struct acpi_device *device = acpi_fetch_acpi_dev(handle);
struct acpi_pci_link *link;
- result = acpi_bus_get_device(handle, &device);
- if (result) {
- printk(KERN_ERR PREFIX "Invalid link device\n");
+ if (!device) {
+ acpi_handle_err(handle, "Invalid link device\n");
return -1;
}
link = acpi_driver_data(device);
if (!link) {
- printk(KERN_ERR PREFIX "Invalid link context\n");
+ acpi_handle_err(handle, "Invalid link context\n");
return -1;
}
/* TBD: Support multiple index (IRQ) entries per Link Device */
if (index) {
- printk(KERN_ERR PREFIX "Invalid index %d\n", index);
+ acpi_handle_err(handle, "Invalid index %d\n", index);
return -1;
}
@@ -616,7 +634,7 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
if (!link->irq.active) {
mutex_unlock(&acpi_link_lock);
- printk(KERN_ERR PREFIX "Link active IRQ is 0!\n");
+ acpi_handle_err(handle, "Link active IRQ is 0!\n");
return -1;
}
link->refcnt++;
@@ -628,10 +646,8 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
*polarity = link->irq.polarity;
if (name)
*name = acpi_device_bid(link->device);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Link %s is referenced\n",
- acpi_device_bid(link->device)));
- return (link->irq.active);
+ acpi_handle_debug(handle, "Link is referenced\n");
+ return link->irq.active;
}
/*
@@ -640,26 +656,24 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
*/
int acpi_pci_link_free_irq(acpi_handle handle)
{
- struct acpi_device *device;
+ struct acpi_device *device = acpi_fetch_acpi_dev(handle);
struct acpi_pci_link *link;
- acpi_status result;
- result = acpi_bus_get_device(handle, &device);
- if (result) {
- printk(KERN_ERR PREFIX "Invalid link device\n");
+ if (!device) {
+ acpi_handle_err(handle, "Invalid link device\n");
return -1;
}
link = acpi_driver_data(device);
if (!link) {
- printk(KERN_ERR PREFIX "Invalid link context\n");
+ acpi_handle_err(handle, "Invalid link context\n");
return -1;
}
mutex_lock(&acpi_link_lock);
if (!link->irq.initialized) {
mutex_unlock(&acpi_link_lock);
- printk(KERN_ERR PREFIX "Link isn't initialized\n");
+ acpi_handle_err(handle, "Link isn't initialized\n");
return -1;
}
#ifdef FUTURE_USE
@@ -674,15 +688,13 @@ int acpi_pci_link_free_irq(acpi_handle handle)
*/
link->refcnt--;
#endif
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Link %s is dereferenced\n",
- acpi_device_bid(link->device)));
+ acpi_handle_debug(handle, "Link is dereferenced\n");
if (link->refcnt == 0)
acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
mutex_unlock(&acpi_link_lock);
- return (link->irq.active);
+ return link->irq.active;
}
/* --------------------------------------------------------------------------
@@ -692,18 +704,18 @@ int acpi_pci_link_free_irq(acpi_handle handle)
static int acpi_pci_link_add(struct acpi_device *device,
const struct acpi_device_id *not_used)
{
- int result;
+ acpi_handle handle = device->handle;
struct acpi_pci_link *link;
+ int result;
int i;
- int found = 0;
link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
if (!link)
return -ENOMEM;
link->device = device;
- strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
+ strscpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
+ strscpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
device->driver_data = link;
mutex_lock(&acpi_link_lock);
@@ -714,36 +726,30 @@ static int acpi_pci_link_add(struct acpi_device *device,
/* query and set link->irq.active */
acpi_pci_link_get_current(link);
- printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
- acpi_device_bid(device));
+ pr_info("Interrupt link %s configured for IRQ %d\n",
+ acpi_device_bid(device), link->irq.active);
+
for (i = 0; i < link->irq.possible_count; i++) {
- if (link->irq.active == link->irq.possible[i]) {
- printk(KERN_CONT " *%d", link->irq.possible[i]);
- found = 1;
- } else
- printk(KERN_CONT " %d", link->irq.possible[i]);
+ if (link->irq.active != link->irq.possible[i])
+ acpi_handle_debug(handle, "Possible IRQ %d\n",
+ link->irq.possible[i]);
}
- printk(KERN_CONT ")");
-
- if (!found)
- printk(KERN_CONT " *%d", link->irq.active);
-
if (!link->device->status.enabled)
- printk(KERN_CONT ", disabled.");
-
- printk(KERN_CONT "\n");
+ pr_info("Interrupt link %s disabled\n", acpi_device_bid(device));
list_add_tail(&link->list, &acpi_link_list);
end:
/* disable all links -- to be activated on use */
- acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
+ acpi_evaluate_object(handle, "_DIS", NULL, NULL);
mutex_unlock(&acpi_link_lock);
if (result)
kfree(link);
+ acpi_dev_clear_dependencies(device);
+
return result < 0 ? result : 1;
}
@@ -755,7 +761,7 @@ static int acpi_pci_link_resume(struct acpi_pci_link *link)
return 0;
}
-static void irqrouter_resume(void)
+static void irqrouter_resume(void *data)
{
struct acpi_pci_link *link;
@@ -778,7 +784,7 @@ static void acpi_pci_link_remove(struct acpi_device *device)
}
/*
- * modify acpi_irq_penalty[] from cmdline
+ * modify acpi_isa_irq_penalty[] from cmdline
*/
static int __init acpi_irq_penalty_update(char *str, int used)
{
@@ -787,23 +793,24 @@ static int __init acpi_irq_penalty_update(char *str, int used)
for (i = 0; i < 16; i++) {
int retval;
int irq;
+ int new_penalty;
retval = get_option(&str, &irq);
if (!retval)
break; /* no number found */
- if (irq < 0)
- continue;
-
- if (irq >= ARRAY_SIZE(acpi_irq_penalty))
+ /* see if this is a ISA IRQ */
+ if ((irq < 0) || (irq >= ACPI_MAX_ISA_IRQS))
continue;
if (used)
- acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
+ new_penalty = acpi_isa_irq_penalty[irq] +
+ PIRQ_PENALTY_ISA_USED;
else
- acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
+ new_penalty = 0;
+ acpi_isa_irq_penalty[irq] = new_penalty;
if (retval != 2) /* no next number */
break;
}
@@ -819,12 +826,26 @@ static int __init acpi_irq_penalty_update(char *str, int used)
*/
void acpi_penalize_isa_irq(int irq, int active)
{
- if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
- if (active)
- acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
- else
- acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
- }
+ if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty)))
+ acpi_isa_irq_penalty[irq] +=
+ (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
+}
+
+bool acpi_isa_irq_available(int irq)
+{
+ return irq >= 0 && (irq >= ARRAY_SIZE(acpi_isa_irq_penalty) ||
+ acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
+}
+
+void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
+{
+ sci_irq = irq;
+
+ if (trigger == ACPI_MADT_TRIGGER_LEVEL &&
+ polarity == ACPI_MADT_POLARITY_ACTIVE_LOW)
+ sci_penalty = PIRQ_PENALTY_PCI_USING;
+ else
+ sci_penalty = PIRQ_PENALTY_ISA_ALWAYS;
}
/*
@@ -867,10 +888,14 @@ static int __init acpi_irq_balance_set(char *str)
__setup("acpi_irq_balance", acpi_irq_balance_set);
-static struct syscore_ops irqrouter_syscore_ops = {
+static const struct syscore_ops irqrouter_syscore_ops = {
.resume = irqrouter_resume,
};
+static struct syscore irqrouter_syscore = {
+ .ops = &irqrouter_syscore_ops,
+};
+
void __init acpi_pci_link_init(void)
{
if (acpi_noirq)
@@ -883,6 +908,6 @@ void __init acpi_pci_link_init(void)
else
acpi_irq_balance = 0;
}
- register_syscore_ops(&irqrouter_syscore_ops);
+ register_syscore(&irqrouter_syscore);
acpi_scan_add_handler(&pci_link_handler);
}