diff options
Diffstat (limited to 'drivers/acpi/pci_link.c')
| -rw-r--r-- | drivers/acpi/pci_link.c | 840 |
1 files changed, 370 insertions, 470 deletions
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 834c2ceff1a..cfd7581cc19 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -29,43 +29,41 @@ * for IRQ management (e.g. start()->_SRS). */ -#include <linux/sysdev.h> +#include <linux/syscore_ops.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/pm.h> #include <linux/pci.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> - - -#define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME ("pci_link") +#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_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" #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 -#define ACPI_PCI_LINK_MAX_POSSIBLE 16 +static int acpi_pci_link_add(struct acpi_device *device, + const struct acpi_device_id *not_used); +static void acpi_pci_link_remove(struct acpi_device *device); -static int acpi_pci_link_add (struct acpi_device *device); -static int acpi_pci_link_remove (struct acpi_device *device, int type); +static const struct acpi_device_id link_device_ids[] = { + {"PNP0C0F", 0}, + {"", 0}, +}; -static struct acpi_driver acpi_pci_link_driver = { - .name = ACPI_PCI_LINK_DRIVER_NAME, - .class = ACPI_PCI_LINK_CLASS, - .ids = ACPI_PCI_LINK_HID, - .ops = { - .add = acpi_pci_link_add, - .remove = acpi_pci_link_remove, - }, +static struct acpi_scan_handler pci_link_handler = { + .ids = link_device_ids, + .attach = acpi_pci_link_add, + .detach = acpi_pci_link_remove, }; /* @@ -73,30 +71,25 @@ static struct acpi_driver acpi_pci_link_driver = { * later even the link is disable. Instead, we just repick the active irq */ struct acpi_pci_link_irq { - u8 active; /* Current IRQ */ - u8 edge_level; /* All IRQs */ - u8 active_high_low; /* All IRQs */ - u8 resource_type; - u8 possible_count; - u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; - u8 initialized:1; - u8 reserved:7; + u8 active; /* Current IRQ */ + u8 triggering; /* All IRQs */ + u8 polarity; /* All IRQs */ + u8 resource_type; + u8 possible_count; + u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; + u8 initialized:1; + u8 reserved:7; }; struct acpi_pci_link { - struct list_head node; - struct acpi_device *device; - acpi_handle handle; - struct acpi_pci_link_irq irq; - int refcnt; + struct list_head list; + struct acpi_device *device; + struct acpi_pci_link_irq irq; + int refcnt; }; -static struct { - int count; - struct list_head entries; -} acpi_link; -DECLARE_MUTEX(acpi_link_lock); - +static LIST_HEAD(acpi_link_list); +static DEFINE_MUTEX(acpi_link_lock); /* -------------------------------------------------------------------------- PCI Link Device Management @@ -105,141 +98,142 @@ DECLARE_MUTEX(acpi_link_lock); /* * set context (link) possible list from resource list */ -static acpi_status -acpi_pci_link_check_possible ( - struct acpi_resource *resource, - void *context) +static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource, + void *context) { - struct acpi_pci_link *link = (struct acpi_pci_link *) context; - u32 i = 0; - - ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible"); - - switch (resource->id) { - case ACPI_RSTYPE_START_DPF: - return_ACPI_STATUS(AE_OK); - case ACPI_RSTYPE_IRQ: - { - struct acpi_resource_irq *p = &resource->data.irq; - if (!p || !p->number_of_interrupts) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n")); - return_ACPI_STATUS(AE_OK); - } - for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) { - if (!p->interrupts[i]) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i])); - continue; + struct acpi_pci_link *link = context; + u32 i; + + switch (resource->type) { + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + case ACPI_RESOURCE_TYPE_END_TAG: + return AE_OK; + 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")); + return AE_OK; } - link->irq.possible[i] = p->interrupts[i]; - link->irq.possible_count++; - } - link->irq.edge_level = p->edge_level; - link->irq.active_high_low = p->active_high_low; - link->irq.resource_type = ACPI_RSTYPE_IRQ; - break; - } - case ACPI_RSTYPE_EXT_IRQ: - { - struct acpi_resource_ext_irq *p = &resource->data.extended_irq; - if (!p || !p->number_of_interrupts) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Blank EXT IRQ resource\n")); - return_ACPI_STATUS(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]); + continue; + } + link->irq.possible[i] = p->interrupts[i]; + link->irq.possible_count++; + } + link->irq.triggering = p->triggering; + link->irq.polarity = p->polarity; + link->irq.resource_type = ACPI_RESOURCE_TYPE_IRQ; + break; } - for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) { - if (!p->interrupts[i]) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i])); - continue; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + 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"); + return AE_OK; } - link->irq.possible[i] = p->interrupts[i]; - link->irq.possible_count++; + 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]); + continue; + } + link->irq.possible[i] = p->interrupts[i]; + link->irq.possible_count++; + } + link->irq.triggering = p->triggering; + link->irq.polarity = p->polarity; + link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; + break; } - link->irq.edge_level = p->edge_level; - link->irq.active_high_low = p->active_high_low; - link->irq.resource_type = ACPI_RSTYPE_EXT_IRQ; - break; - } default: - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Resource is not an IRQ entry\n")); - return_ACPI_STATUS(AE_OK); + printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n", + resource->type); + return AE_OK; } - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return AE_CTRL_TERMINATE; } - -static int -acpi_pci_link_get_possible ( - struct acpi_pci_link *link) +static int acpi_pci_link_get_possible(struct acpi_pci_link *link) { - acpi_status status; + acpi_status status; - ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible"); - - if (!link) - return_VALUE(-EINVAL); - - status = acpi_walk_resources(link->handle, METHOD_NAME__PRS, - acpi_pci_link_check_possible, link); + status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS, + acpi_pci_link_check_possible, link); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n")); - return_VALUE(-ENODEV); + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS")); + return -ENODEV; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found %d possible IRQs\n", link->irq.possible_count)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found %d possible IRQs\n", + link->irq.possible_count)); - return_VALUE(0); + return 0; } - -static acpi_status -acpi_pci_link_check_current ( - struct acpi_resource *resource, - void *context) +static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource, + void *context) { - int *irq = (int *) context; - - ACPI_FUNCTION_TRACE("acpi_pci_link_check_current"); - - switch (resource->id) { - case ACPI_RSTYPE_IRQ: - { - struct acpi_resource_irq *p = &resource->data.irq; - if (!p || !p->number_of_interrupts) { - /* - * IRQ descriptors may have no IRQ# bits set, - * particularly those those w/ _STA disabled - */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Blank IRQ resource\n")); - return_ACPI_STATUS(AE_OK); + int *irq = context; + + switch (resource->type) { + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + case ACPI_RESOURCE_TYPE_END_TAG: + return AE_OK; + case ACPI_RESOURCE_TYPE_IRQ: + { + struct acpi_resource_irq *p = &resource->data.irq; + if (!p || !p->interrupt_count) { + /* + * IRQ descriptors may have no IRQ# bits set, + * particularly those those w/ _STA disabled + */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Blank _CRS IRQ resource\n")); + return AE_OK; + } + *irq = p->interrupts[0]; + break; } - *irq = p->interrupts[0]; - break; - } - case ACPI_RSTYPE_EXT_IRQ: - { - struct acpi_resource_ext_irq *p = &resource->data.extended_irq; - if (!p || !p->number_of_interrupts) { - /* - * extended IRQ descriptors must - * return at least 1 IRQ - */ - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Blank EXT IRQ resource\n")); - return_ACPI_STATUS(AE_OK); + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + { + struct acpi_resource_extended_irq *p = + &resource->data.extended_irq; + if (!p || !p->interrupt_count) { + /* + * extended IRQ descriptors must + * return at least 1 IRQ + */ + printk(KERN_WARNING PREFIX + "Blank _CRS EXT IRQ resource\n"); + return AE_OK; + } + *irq = p->interrupts[0]; + break; } - *irq = p->interrupts[0]; break; - } default: - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Resource isn't an IRQ\n")); - return_ACPI_STATUS(AE_OK); + printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n", + resource->type); + return AE_OK; } - return_ACPI_STATUS(AE_CTRL_TERMINATE); + + return AE_CTRL_TERMINATE; } /* @@ -249,18 +243,11 @@ acpi_pci_link_check_current ( * 0 - success * !0 - failure */ -static int -acpi_pci_link_get_current ( - struct acpi_pci_link *link) +static int acpi_pci_link_get_current(struct acpi_pci_link *link) { - int result = 0; - acpi_status status = AE_OK; - int irq = 0; - - ACPI_FUNCTION_TRACE("acpi_pci_link_get_current"); - - if (!link || !link->handle) - return_VALUE(-EINVAL); + int result = 0; + acpi_status status; + int irq = 0; link->irq.active = 0; @@ -269,13 +256,13 @@ acpi_pci_link_get_current ( /* Query _STA, set link->device->status */ result = acpi_bus_get_status(link->device); if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); + printk(KERN_ERR PREFIX "Unable to read status\n"); goto end; } if (!link->device->status.enabled) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); - return_VALUE(0); + return 0; } } @@ -283,16 +270,16 @@ acpi_pci_link_get_current ( * Query and parse _CRS to get the current IRQ assignment. */ - status = acpi_walk_resources(link->handle, METHOD_NAME__CRS, - acpi_pci_link_check_current, &irq); + status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS, + acpi_pci_link_check_current, &irq); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n")); + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS")); result = -ENODEV; goto end; } if (acpi_strict && !irq) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n")); + printk(KERN_ERR PREFIX "_CRS returned 0\n"); result = -ENODEV; } @@ -300,78 +287,79 @@ acpi_pci_link_get_current ( ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); -end: - return_VALUE(result); + end: + return result; } -static int -acpi_pci_link_set ( - struct acpi_pci_link *link, - int irq) +static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) { - int result = 0; - acpi_status status = AE_OK; + int result; + acpi_status status; struct { - struct acpi_resource res; - struct acpi_resource end; - } *resource; - struct acpi_buffer buffer = {0, NULL}; + struct acpi_resource res; + struct acpi_resource end; + } *resource; + struct acpi_buffer buffer = { 0, NULL }; - ACPI_FUNCTION_TRACE("acpi_pci_link_set"); + if (!irq) + return -EINVAL; - if (!link || !irq) - return_VALUE(-EINVAL); + resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); + if (!resource) + return -ENOMEM; - resource = kmalloc( sizeof(*resource)+1, GFP_KERNEL); - if(!resource) - return_VALUE(-ENOMEM); - - memset(resource, 0, sizeof(*resource)+1); - buffer.length = sizeof(*resource) +1; + buffer.length = sizeof(*resource) + 1; buffer.pointer = resource; - switch(link->irq.resource_type) { - case ACPI_RSTYPE_IRQ: - resource->res.id = ACPI_RSTYPE_IRQ; + switch (link->irq.resource_type) { + case ACPI_RESOURCE_TYPE_IRQ: + resource->res.type = ACPI_RESOURCE_TYPE_IRQ; resource->res.length = sizeof(struct acpi_resource); - resource->res.data.irq.edge_level = link->irq.edge_level; - resource->res.data.irq.active_high_low = link->irq.active_high_low; - if (link->irq.edge_level == ACPI_EDGE_SENSITIVE) - resource->res.data.irq.shared_exclusive = ACPI_EXCLUSIVE; + resource->res.data.irq.triggering = link->irq.triggering; + resource->res.data.irq.polarity = + link->irq.polarity; + if (link->irq.triggering == ACPI_EDGE_SENSITIVE) + resource->res.data.irq.sharable = + ACPI_EXCLUSIVE; else - resource->res.data.irq.shared_exclusive = ACPI_SHARED; - resource->res.data.irq.number_of_interrupts = 1; + resource->res.data.irq.sharable = ACPI_SHARED; + resource->res.data.irq.interrupt_count = 1; resource->res.data.irq.interrupts[0] = irq; break; - - case ACPI_RSTYPE_EXT_IRQ: - resource->res.id = ACPI_RSTYPE_EXT_IRQ; + + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; resource->res.length = sizeof(struct acpi_resource); - resource->res.data.extended_irq.producer_consumer = ACPI_CONSUMER; - resource->res.data.extended_irq.edge_level = link->irq.edge_level; - resource->res.data.extended_irq.active_high_low = link->irq.active_high_low; - if (link->irq.edge_level == ACPI_EDGE_SENSITIVE) - resource->res.data.irq.shared_exclusive = ACPI_EXCLUSIVE; + resource->res.data.extended_irq.producer_consumer = + ACPI_CONSUMER; + resource->res.data.extended_irq.triggering = + link->irq.triggering; + resource->res.data.extended_irq.polarity = + link->irq.polarity; + if (link->irq.triggering == ACPI_EDGE_SENSITIVE) + resource->res.data.irq.sharable = + ACPI_EXCLUSIVE; else - resource->res.data.irq.shared_exclusive = ACPI_SHARED; - resource->res.data.extended_irq.number_of_interrupts = 1; + resource->res.data.irq.sharable = 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("ACPI BUG: resource_type %d\n", link->irq.resource_type); + printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type); result = -EINVAL; goto end; } - resource->end.id = ACPI_RSTYPE_END_TAG; + resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; + resource->end.length = sizeof(struct acpi_resource); /* Attempt to set the resource */ - status = acpi_set_current_resources(link->handle, &buffer); + status = acpi_set_current_resources(link->device->handle, &buffer); /* check for total failure */ if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n")); + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS")); result = -ENODEV; goto end; } @@ -379,14 +367,14 @@ acpi_pci_link_set ( /* Query _STA, set device->status */ result = acpi_bus_get_status(link->device); if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); + printk(KERN_ERR PREFIX "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)); + "%s [%s] disabled and referenced, BIOS bug\n", + acpi_device_name(link->device), + acpi_device_bid(link->device)); } /* Query _CRS, set link->irq.active */ @@ -404,22 +392,20 @@ acpi_pci_link_set ( * 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); + 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); link->irq.active = irq; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); - -end: + + end: kfree(resource); - return_VALUE(result); + return result; } - /* -------------------------------------------------------------------------- PCI Link IRQ Management -------------------------------------------------------------------------- */ @@ -469,8 +455,8 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = { PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ - PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ - PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ + PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */ @@ -478,70 +464,61 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = { PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ - PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ - PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ - PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ - PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ - /* >IRQ15 */ + PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ + PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ + PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ + PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ + /* >IRQ15 */ }; -int __init -acpi_irq_penalty_init(void) +int __init acpi_irq_penalty_init(void) { - struct list_head *node = NULL; - struct acpi_pci_link *link = NULL; - int i = 0; - - ACPI_FUNCTION_TRACE("acpi_irq_penalty_init"); + struct acpi_pci_link *link; + int i; /* * Update penalties to facilitate IRQ balancing. */ - list_for_each(node, &acpi_link.entries) { - - link = list_entry(node, struct acpi_pci_link, node); - if (!link) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); - continue; - } + list_for_each_entry(link, &acpi_link_list, list) { /* * reflect the possible and active irqs in the penalty table -- * useful for breaking ties. */ if (link->irq.possible_count) { - int penalty = PIRQ_PENALTY_PCI_POSSIBLE / link->irq.possible_count; + int penalty = + PIRQ_PENALTY_PCI_POSSIBLE / + 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.possible[i]] += penalty; + acpi_irq_penalty[link->irq. + possible[i]] += + penalty; } } else if (link->irq.active) { - acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_POSSIBLE; + acpi_irq_penalty[link->irq.active] += + PIRQ_PENALTY_PCI_POSSIBLE; } } /* Add a penalty for the SCI */ - acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING; - - return_VALUE(0); + acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING; + return 0; } -static int acpi_irq_balance; /* 0: static, 1: balance */ +static int acpi_irq_balance = -1; /* 0: static, 1: balance */ -static int acpi_pci_link_allocate( - struct acpi_pci_link *link) +static int acpi_pci_link_allocate(struct acpi_pci_link *link) { - int irq; - int i; - - ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); + int irq; + int i; if (link->irq.initialized) { if (link->refcnt == 0) /* This means the link is disabled but initialized */ acpi_pci_link_set(link, link->irq.active); - return_VALUE(0); + return 0; } /* @@ -557,18 +534,17 @@ static int acpi_pci_link_allocate( if (i == link->irq.possible_count) { if (acpi_strict) printk(KERN_WARNING PREFIX "_CRS %d not found" - " in _PRS\n", link->irq.active); + " in _PRS\n", link->irq.active); link->irq.active = 0; } /* * if active found, use it; else pick entry from end of possible list. */ - if (link->irq.active) { + if (link->irq.active) irq = link->irq.active; - } else { + else irq = link->irq.possible[link->irq.possible_count - 1]; - } if (acpi_irq_balance || !link->irq.active) { /* @@ -576,28 +552,28 @@ static int acpi_pci_link_allocate( * 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_penalty[irq] > + acpi_irq_penalty[link->irq.possible[i]]) irq = link->irq.possible[i]; } } /* Attempt to enable the link device at this IRQ. */ if (acpi_pci_link_set(link, irq)) { - printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n" - "Try pci=noacpi or acpi=off\n", - acpi_device_name(link->device), - acpi_device_bid(link->device)); - return_VALUE(-ENODEV); + 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)); + return -ENODEV; } else { acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; - printk(PREFIX "%s [%s] enabled at IRQ %d\n", - acpi_device_name(link->device), - acpi_device_bid(link->device), link->irq.active); + printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", + acpi_device_name(link->device), + acpi_device_bid(link->device), link->irq.active); } link->irq.initialized = 1; - - return_VALUE(0); + return 0; } /* @@ -605,93 +581,85 @@ static int acpi_pci_link_allocate( * success: return IRQ >= 0 * failure: return -1 */ - -int -acpi_pci_link_allocate_irq ( - acpi_handle handle, - int index, - int *edge_level, - int *active_high_low, - char **name) +int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, + int *polarity, char **name) { - int result = 0; - struct acpi_device *device = NULL; - struct acpi_pci_link *link = NULL; - - ACPI_FUNCTION_TRACE("acpi_pci_link_allocate_irq"); + int result; + struct acpi_device *device; + struct acpi_pci_link *link; result = acpi_bus_get_device(handle, &device); if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n")); - return_VALUE(-1); + printk(KERN_ERR PREFIX "Invalid link device\n"); + return -1; } - link = (struct acpi_pci_link *) acpi_driver_data(device); + link = acpi_driver_data(device); if (!link) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); - return_VALUE(-1); + printk(KERN_ERR PREFIX "Invalid link context\n"); + return -1; } /* TBD: Support multiple index (IRQ) entries per Link Device */ if (index) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index)); - return_VALUE(-1); + printk(KERN_ERR PREFIX "Invalid index %d\n", index); + return -1; } - down(&acpi_link_lock); + mutex_lock(&acpi_link_lock); if (acpi_pci_link_allocate(link)) { - up(&acpi_link_lock); - return_VALUE(-1); - } - - if (!link->irq.active) { - up(&acpi_link_lock); - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n")); - return_VALUE(-1); + mutex_unlock(&acpi_link_lock); + return -1; } - link->refcnt ++; - up(&acpi_link_lock); - if (edge_level) *edge_level = link->irq.edge_level; - if (active_high_low) *active_high_low = link->irq.active_high_low; - if (name) *name = acpi_device_bid(link->device); + if (!link->irq.active) { + mutex_unlock(&acpi_link_lock); + printk(KERN_ERR PREFIX "Link active IRQ is 0!\n"); + return -1; + } + link->refcnt++; + mutex_unlock(&acpi_link_lock); + + if (triggering) + *triggering = link->irq.triggering; + if (polarity) + *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_VALUE(link->irq.active); + "Link %s is referenced\n", + acpi_device_bid(link->device))); + return (link->irq.active); } /* * We don't change link's irq information here. After it is reenabled, we * continue use the info */ -int -acpi_pci_link_free_irq(acpi_handle handle) +int acpi_pci_link_free_irq(acpi_handle handle) { - struct acpi_device *device = NULL; - struct acpi_pci_link *link = NULL; - acpi_status result; - - ACPI_FUNCTION_TRACE("acpi_pci_link_free_irq"); + struct acpi_device *device; + struct acpi_pci_link *link; + acpi_status result; result = acpi_bus_get_device(handle, &device); if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n")); - return_VALUE(-1); + printk(KERN_ERR PREFIX "Invalid link device\n"); + return -1; } - link = (struct acpi_pci_link *) acpi_driver_data(device); + link = acpi_driver_data(device); if (!link) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); - return_VALUE(-1); + printk(KERN_ERR PREFIX "Invalid link context\n"); + return -1; } - down(&acpi_link_lock); + mutex_lock(&acpi_link_lock); if (!link->irq.initialized) { - up(&acpi_link_lock); - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n")); - return_VALUE(-1); + mutex_unlock(&acpi_link_lock); + printk(KERN_ERR PREFIX "Link isn't initialized\n"); + return -1; } - #ifdef FUTURE_USE /* * The Link reference count allows us to _DISable an unused link @@ -702,47 +670,41 @@ acpi_pci_link_free_irq(acpi_handle handle) * to prevent duplicate acpi_pci_link_set() * which would harm some systems */ - link->refcnt --; + link->refcnt--; #endif ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Link %s is dereferenced\n", acpi_device_bid(link->device))); + "Link %s is dereferenced\n", + acpi_device_bid(link->device))); - if (link->refcnt == 0) { - acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL); - } - up(&acpi_link_lock); - return_VALUE(link->irq.active); + if (link->refcnt == 0) + acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL); + + mutex_unlock(&acpi_link_lock); + return (link->irq.active); } + /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ -static int -acpi_pci_link_add ( - struct acpi_device *device) +static int acpi_pci_link_add(struct acpi_device *device, + const struct acpi_device_id *not_used) { - int result = 0; - struct acpi_pci_link *link = NULL; - int i = 0; - int found = 0; - - ACPI_FUNCTION_TRACE("acpi_pci_link_add"); - - if (!device) - return_VALUE(-EINVAL); + int result; + struct acpi_pci_link *link; + int i; + int found = 0; - link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); + link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); if (!link) - return_VALUE(-ENOMEM); - memset(link, 0, sizeof(struct acpi_pci_link)); + return -ENOMEM; link->device = device; - link->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); - acpi_driver_data(device) = link; + device->driver_data = link; - down(&acpi_link_lock); + mutex_lock(&acpi_link_lock); result = acpi_pci_link_get_possible(link); if (result) goto end; @@ -750,104 +712,67 @@ acpi_pci_link_add ( /* query and set link->irq.active */ acpi_pci_link_get_current(link); - printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), - acpi_device_bid(device)); + printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device), + acpi_device_bid(device)); for (i = 0; i < link->irq.possible_count; i++) { if (link->irq.active == link->irq.possible[i]) { - printk(" *%d", link->irq.possible[i]); + printk(KERN_CONT " *%d", link->irq.possible[i]); found = 1; - } - else - printk(" %d", link->irq.possible[i]); + } else + printk(KERN_CONT " %d", link->irq.possible[i]); } - printk(")"); + printk(KERN_CONT ")"); if (!found) - printk(" *%d", link->irq.active); + printk(KERN_CONT " *%d", link->irq.active); - if(!link->device->status.enabled) - printk(", disabled."); + if (!link->device->status.enabled) + printk(KERN_CONT ", disabled."); - printk("\n"); + printk(KERN_CONT "\n"); - /* TBD: Acquire/release lock */ - list_add_tail(&link->node, &acpi_link.entries); - acpi_link.count++; + list_add_tail(&link->list, &acpi_link_list); -end: + end: /* disable all links -- to be activated on use */ - acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL); - up(&acpi_link_lock); + acpi_evaluate_object(device->handle, "_DIS", NULL, NULL); + mutex_unlock(&acpi_link_lock); if (result) kfree(link); - return_VALUE(result); + return result < 0 ? result : 1; } -static int -acpi_pci_link_resume( - struct acpi_pci_link *link) +static int acpi_pci_link_resume(struct acpi_pci_link *link) { - ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); - if (link->refcnt && link->irq.active && link->irq.initialized) - return_VALUE(acpi_pci_link_set(link, link->irq.active)); - else - return_VALUE(0); + return (acpi_pci_link_set(link, link->irq.active)); + + return 0; } -/* - * FIXME: this is a workaround to avoid nasty warning. It will be removed - * after every device calls pci_disable_device in .resume. - */ -int acpi_in_resume; -static int -irqrouter_resume( - struct sys_device *dev) +static void irqrouter_resume(void) { - struct list_head *node = NULL; - struct acpi_pci_link *link = NULL; - - ACPI_FUNCTION_TRACE("irqrouter_resume"); + struct acpi_pci_link *link; - acpi_in_resume = 1; - list_for_each(node, &acpi_link.entries) { - link = list_entry(node, struct acpi_pci_link, node); - if (!link) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Invalid link context\n")); - continue; - } + list_for_each_entry(link, &acpi_link_list, list) { acpi_pci_link_resume(link); } - acpi_in_resume = 0; - return_VALUE(0); } - -static int -acpi_pci_link_remove ( - struct acpi_device *device, - int type) +static void acpi_pci_link_remove(struct acpi_device *device) { - struct acpi_pci_link *link = NULL; + struct acpi_pci_link *link; - ACPI_FUNCTION_TRACE("acpi_pci_link_remove"); + link = acpi_driver_data(device); - if (!device || !acpi_driver_data(device)) - return_VALUE(-EINVAL); - - link = (struct acpi_pci_link *) acpi_driver_data(device); - - down(&acpi_link_lock); - list_del(&link->node); - up(&acpi_link_lock); + mutex_lock(&acpi_link_lock); + list_del(&link->list); + mutex_unlock(&acpi_link_lock); kfree(link); - - return_VALUE(0); } /* @@ -861,15 +786,15 @@ static int __init acpi_irq_penalty_update(char *str, int used) int retval; int irq; - retval = get_option(&str,&irq); + retval = get_option(&str, &irq); if (!retval) break; /* no number found */ if (irq < 0) continue; - - if (irq >= ACPI_MAX_IRQS) + + if (irq >= ARRAY_SIZE(acpi_irq_penalty)) continue; if (used) @@ -892,10 +817,12 @@ static int __init acpi_irq_penalty_update(char *str, int used) */ void acpi_penalize_isa_irq(int irq, int active) { - 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_irq_penalty)) { + if (active) + acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; + else + acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; + } } /* @@ -907,6 +834,7 @@ static int __init acpi_irq_isa(char *str) { return acpi_irq_penalty_update(str, 1); } + __setup("acpi_irq_isa=", acpi_irq_isa); /* @@ -918,6 +846,7 @@ static int __init acpi_irq_pci(char *str) { return acpi_irq_penalty_update(str, 0); } + __setup("acpi_irq_pci=", acpi_irq_pci); static int __init acpi_irq_nobalance_set(char *str) @@ -925,62 +854,33 @@ static int __init acpi_irq_nobalance_set(char *str) acpi_irq_balance = 0; return 1; } + __setup("acpi_irq_nobalance", acpi_irq_nobalance_set); -int __init acpi_irq_balance_set(char *str) +static int __init acpi_irq_balance_set(char *str) { acpi_irq_balance = 1; return 1; } -__setup("acpi_irq_balance", acpi_irq_balance_set); - - -/* FIXME: we will remove this interface after all drivers call pci_disable_device */ -static struct sysdev_class irqrouter_sysdev_class = { - set_kset_name("irqrouter"), - .resume = irqrouter_resume, -}; +__setup("acpi_irq_balance", acpi_irq_balance_set); -static struct sys_device device_irqrouter = { - .id = 0, - .cls = &irqrouter_sysdev_class, +static struct syscore_ops irqrouter_syscore_ops = { + .resume = irqrouter_resume, }; - -static int __init irqrouter_init_sysfs(void) +void __init acpi_pci_link_init(void) { - int error; - - ACPI_FUNCTION_TRACE("irqrouter_init_sysfs"); - - if (acpi_disabled || acpi_noirq) - return_VALUE(0); - - error = sysdev_class_register(&irqrouter_sysdev_class); - if (!error) - error = sysdev_register(&device_irqrouter); - - return_VALUE(error); -} - -device_initcall(irqrouter_init_sysfs); - - -static int __init acpi_pci_link_init (void) -{ - ACPI_FUNCTION_TRACE("acpi_pci_link_init"); - if (acpi_noirq) - return_VALUE(0); - - acpi_link.count = 0; - INIT_LIST_HEAD(&acpi_link.entries); - - if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0) - return_VALUE(-ENODEV); + return; - return_VALUE(0); + if (acpi_irq_balance == -1) { + /* no command line switch: enable balancing in IOAPIC mode */ + if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) + acpi_irq_balance = 1; + else + acpi_irq_balance = 0; + } + register_syscore_ops(&irqrouter_syscore_ops); + acpi_scan_add_handler(&pci_link_handler); } - -subsys_initcall(acpi_pci_link_init); |
