From 4a6e68bf96c1fa293717d2f00a68a68c92fa4150 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 29 Jun 2016 04:27:35 -0400 Subject: ACPI,PCI,IRQ: factor in PCI possible The change introduced in commit 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) omitted the initially applied PCI_POSSIBLE penalty when the IRQ is active. Incorrect calculation of the penalty leads the ACPI code to assigning a wrong interrupt number to a PCI INTx interrupt. This would not be as bad as it sounds in theory. It would just cause the interrupts to be shared and result in performance penalty. However, some drivers (like the parallel port driver) don't like interrupt sharing and in the above case they will causes all of the PCI drivers wanting to share the interrupt to be unable to request it. The issue has not been caught in testing because the behavior is platform-specific and depends on the peripherals ending up sharing the IRQ and their drivers. Before the above commit the code would add the PCI_POSSIBLE value divided by the number of possible IRQ users to the IRQ penalty during initialization. Later in that code path, if the IRQ is chosen as the active IRQ or if it is used by ISA; additional penalties are added. Fixes: 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) Signed-off-by: Sinan Kaya Tested-by: Wim Osterholt [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 4ed4061..db7be62 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -470,6 +470,7 @@ 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) { /* @@ -478,18 +479,14 @@ static int acpi_irq_pci_sharing_penalty(int irq) */ if (link->irq.active && link->irq.active == irq) penalty += PIRQ_PENALTY_PCI_USING; - else { - int i; - - /* - * If a link is inactive, penalize the IRQs it - * 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; - } + + /* + * 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; -- cgit v0.10.2 From 487cf917ed0d12afaf403d9d77684bf44b8c13be Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 29 Jun 2016 04:27:36 -0400 Subject: Revert "ACPI, PCI, IRQ: remove redundant code in acpi_irq_penalty_init()" Trying to make the ISA and PCI init functionality common turned out to be a bad idea, because the ISA path depends on external functionality. Restore the previous behavior and limit the refactoring to PCI interrupts only. Fixes: 1fcb6a813c4f "ACPI,PCI,IRQ: remove redundant code in acpi_irq_penalty_init()" Signed-off-by: Sinan Kaya Tested-by: Wim Osterholt Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index b2a4e2a..3cd6983 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -396,6 +396,7 @@ int __init pci_acpi_init(void) return -ENODEV; printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); + acpi_irq_penalty_init(); pcibios_enable_irq = acpi_pci_irq_enable; pcibios_disable_irq = acpi_pci_irq_disable; x86_init.pci.init_irq = x86_init_noop; diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index db7be62..606083b 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -517,6 +517,42 @@ static int acpi_irq_get_penalty(int irq) return penalty; } +int __init acpi_irq_penalty_init(void) +{ + struct acpi_pci_link *link; + int i; + + /* + * Update penalties to facilitate IRQ balancing. + */ + 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; + + for (i = 0; i < link->irq.possible_count; i++) { + if (link->irq.possible[i] < ACPI_MAX_ISA_IRQS) + acpi_isa_irq_penalty[link->irq. + possible[i]] += + penalty; + } + + } else if (link->irq.active && + (link->irq.active < ACPI_MAX_ISA_IRQS)) { + acpi_isa_irq_penalty[link->irq.active] += + PIRQ_PENALTY_PCI_POSSIBLE; + } + } + + return 0; +} + static int acpi_irq_balance = -1; /* 0: static, 1: balance */ static int acpi_pci_link_allocate(struct acpi_pci_link *link) diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 797ae2e..29c6912 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -78,6 +78,7 @@ /* ACPI PCI Interrupt Link (pci_link.c) */ +int acpi_irq_penalty_init(void); int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, int *polarity, char **name); int acpi_pci_link_free_irq(acpi_handle handle); -- cgit v0.10.2 From f7eca374f000bd8bd6aacc2619475fdba0b7ecca Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 29 Jun 2016 04:27:37 -0400 Subject: ACPI,PCI,IRQ: separate ISA penalty calculation Since commit 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) the penalty values are calculated on the fly rather than at boot time. This works fine for PCI interrupts but not so well for ISA interrupts. The information on whether or not an ISA interrupt is in use is not available to the pci_link.c code directly. That information is obtained from the outside via acpi_penalize_isa_irq(). [If its "active" argument is true, then the IRQ is in use by ISA.] Since the current code relies on PCI Link objects for determination of penalties, we are factoring in the PCI penalty twice after acpi_penalize_isa_irq() function is called. To avoid that, limit the newly added functionality to just PCI interrupts so that old behavior is still maintained. Fixes: 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) Signed-off-by: Sinan Kaya Tested-by: Wim Osterholt Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 606083b..c983bf7 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -496,9 +496,6 @@ static int acpi_irq_get_penalty(int irq) { int penalty = 0; - if (irq < ACPI_MAX_ISA_IRQS) - penalty += acpi_isa_irq_penalty[irq]; - /* * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict * with PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be @@ -513,6 +510,9 @@ static int acpi_irq_get_penalty(int irq) penalty += PIRQ_PENALTY_PCI_USING; } + if (irq < ACPI_MAX_ISA_IRQS) + return penalty + acpi_isa_irq_penalty[irq]; + penalty += acpi_irq_pci_sharing_penalty(irq); return penalty; } -- cgit v0.10.2 From 45209046c47b93fadf26dc59a9da724f387b9cf2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 5 Jul 2016 13:53:12 +0800 Subject: ACPICA: Namespace: Fix namespace/interpreter lock ordering There is a lock order issue in acpi_load_tables(). The namespace lock is held before holding the interpreter lock. With ACPI_MUTEX_DEBUG enabled in the kernel, this is printed to the log during boot: [ 0.885699] ACPI Error: Invalid acquire order: Thread 405884224 owns [ACPI_MTX_Namespace], wants [ACPI_MTX_Interpreter] (20160422/utmutex-263) [ 0.885881] ACPI Error: Could not acquire AML Interpreter mutex (20160422/exutils-95) [ 0.893846] ACPI Error: Mutex [0x0] is not acquired, cannot release (20160422/utmutex-326) [ 0.894019] ACPI Error: Could not release AML Interpreter mutex (20160422/exutils-133) The issue has been introduced by the following commit: Commit: 2f38b1b16d9280689e5cfa47a4c50956bf437f0d ACPICA Commit: bfe03ffcde8ed56a7eae38ea0b188aeb12f9c52e Subject: ACPICA: Namespace: Fix a regression that MLC support triggers dead lock in dynamic table loading Which fixed a deadlock issue for acpi_ns_load_table() in acpi_ex_add_table() but didn't take care of the lock order in acpi_ns_load_table() correctly. Originally (before the above commit), ACPICA used the namespace/interpreter locks in the following 2 key code paths: 1. Table loading: acpi_ns_load_table L(Namespace) acpi_ns_parse_table acpi_ns_one_complete_parse U(Namespace) 2. Object evaluation: acpi_ns_evaluate L(Interpreter) acpi_ps_execute_method U(Interpreter) acpi_ns_load_table L(Namespace) U(Namespace) acpi_ev_initialize_region L(Namespace) U(Namespace) address_space.setup L(Namespace) U(Namespace) address_space.handler L(Namespace) U(Namespace) acpi_os_wait_semaphore acpi_os_acquire_mutex acpi_os_sleep L(Interpreter) U(Interpreter) During runtime, while acpi_ns_evaluate is called, the lock order is always Interpreter -> Namespace. In turn, the problematic commit acquires the locks in the following order: 3. Table loading: acpi_ns_load_table L(Namespace) acpi_ns_parse_table L(Interpreter) acpi_ns_one_complete_parse U(Interpreter) U(Namespace) To fix the lock order issue, move the interpreter lock to acpi_ns_load_table() to ensure the lock order correctness: 4. Table loading: acpi_ns_load_table L(Interpreter) L(Namespace) acpi_ns_parse_table acpi_ns_one_complete_parse U(Namespace) U(Interpreter) However, this doesn't fix the current design issues related to the namespace lock. For example, we can notice that in acpi_ns_evaluate(), outside of acpi_ns_load_table(), the namespace objects may be created by the named object creation control methods. And the creation of the method-owned namespace objects are not locked by the namespace lock. This patch doesn't try to fix such kind of existing issues. Fixes: 2f38b1b16d92 (ACPICA: Namespace: Fix a regression that MLC support triggers dead lock in dynamic table loading) Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index b5e2b0a..297f6aa 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -46,6 +46,7 @@ #include "acnamesp.h" #include "acdispat.h" #include "actables.h" +#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") @@ -78,6 +79,8 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) ACPI_FUNCTION_TRACE(ns_load_table); + acpi_ex_enter_interpreter(); + /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed @@ -89,7 +92,7 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto unlock_interp; } /* If table already loaded into namespace, just return */ @@ -130,6 +133,8 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); +unlock_interp: + (void)acpi_ex_exit_interpreter(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 1783cd7..f631a47 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -47,7 +47,6 @@ #include "acparser.h" #include "acdispat.h" #include "actables.h" -#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") @@ -171,8 +170,6 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) ACPI_FUNCTION_TRACE(ns_parse_table); - acpi_ex_enter_interpreter(); - /* * AML Parse, pass 1 * @@ -188,7 +185,7 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index, start_node); if (ACPI_FAILURE(status)) { - goto error_exit; + return_ACPI_STATUS(status); } /* @@ -204,10 +201,8 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index, start_node); if (ACPI_FAILURE(status)) { - goto error_exit; + return_ACPI_STATUS(status); } -error_exit: - acpi_ex_exit_interpreter(); return_ACPI_STATUS(status); } -- cgit v0.10.2 From 7e3fd813717693597daaa95dee875f4cb2d911ef Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 5 Jul 2016 19:18:07 +0800 Subject: ACPI / debugger: Fix regression introduced by IS_ERR_VALUE() removal The FIFO unlocking mechanism in acpi_dbg has been broken by the following commit: Commit: 287980e49ffc0f6d911601e7e352a812ed27768e Subject: remove lots of IS_ERR_VALUE abuses It converted !IS_ERR_VALUE(ret) into !ret which was not entirely correct. Fix the regression by taking ret > 0 into account too as appropriate. Fixes: 287980e49ffc (remove lots of IS_ERR_VALUE abuses) Signed-off-by: Lv Zheng [ rjw: Simplifications, changelog & subject massage ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index 1f41284..dee8692 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -602,7 +602,7 @@ static int acpi_aml_read_user(char __user *buf, int len) crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: - acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !ret); + acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, ret >= 0); return ret; } @@ -672,7 +672,7 @@ static int acpi_aml_write_user(const char __user *buf, int len) crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: - acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !ret); + acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0); return n; } -- cgit v0.10.2