* [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts
@ 2023-12-15 11:23 Rafael J. Wysocki
2023-12-15 11:25 ` [PATCH v1 1/3] ACPI: OSL: " Rafael J. Wysocki
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2023-12-15 11:23 UTC (permalink / raw)
To: Linux ACPI
Cc: LKML, Zhang Rui, Srinivas Pandruvada, Michal Wilczynski,
Hans de Goede, Andy Shevchenko, Mika Westerberg, Heikki Krogerus,
Mario Limonciello, Daniel Drake
Hi Everyone,
After
https://patchwork.kernel.org/project/linux-acpi/patch/5745568.DvuYhMxLoT@kreacher/
the SCI interrupt handler is threaded, so ACPICA spin locks can be used without
disabling interrupts, because they cannot be acquired from a hardirq handler
running on the same CPU as any code already holding the spin lock. This patch
[1/3] removes disabling interrupts from acpi_os_acquire_lock() and updates
acpi_os_release_lock() accordingly.
Patch [2/2] uses the observation that if acpi_handle_interrupt() can run
in a threaded interrupt handler in the GPE case, it can also run in a threaded
interrupt handler in the dedicated IRQ case, so it makes the EC driver use a
threaded handler for the dedicated EC interrupt.
Patch [3/3], in analogy with patch [1/3], uses the observation that after patch
[2/2] all of the EC code runs in thread context, so it need not disable
interrupts on the local CPU before acquiring a spin lock, so the EC driver is
updated to operate its spin lock without disabling interrupts.
Thanks!
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 1/3] ACPI: OSL: Use spin locks without disabling interrupts
2023-12-15 11:23 [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
@ 2023-12-15 11:25 ` Rafael J. Wysocki
2023-12-15 11:26 ` [PATCH v1 2/3] ACPI: EC: Use a threaded handler for dedicated IRQ Rafael J. Wysocki
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2023-12-15 11:25 UTC (permalink / raw)
To: Linux ACPI
Cc: LKML, Zhang Rui, Srinivas Pandruvada, Michal Wilczynski,
Hans de Goede, Andy Shevchenko, Mika Westerberg, Heikki Krogerus,
Mario Limonciello, Daniel Drake
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
After commit 7a36b901a6eb ("ACPI: OSL: Use a threaded interrupt handler
for SCI") any ACPICA code never runs in a hardirq handler, so it need
not dissable interrupts on the local CPU when acquiring a spin lock.
Make it use spin locks without disabling interrupts.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/osl.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
Index: linux-pm/drivers/acpi/osl.c
===================================================================
--- linux-pm.orig/drivers/acpi/osl.c
+++ linux-pm/drivers/acpi/osl.c
@@ -1515,20 +1515,18 @@ void acpi_os_delete_lock(acpi_spinlock h
acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
__acquires(lockp)
{
- acpi_cpu_flags flags;
-
- spin_lock_irqsave(lockp, flags);
- return flags;
+ spin_lock(lockp);
+ return 0;
}
/*
* Release a spinlock. See above.
*/
-void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
+void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags not_used)
__releases(lockp)
{
- spin_unlock_irqrestore(lockp, flags);
+ spin_unlock(lockp);
}
#ifndef ACPI_USE_LOCAL_CACHE
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 2/3] ACPI: EC: Use a threaded handler for dedicated IRQ
2023-12-15 11:23 [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
2023-12-15 11:25 ` [PATCH v1 1/3] ACPI: OSL: " Rafael J. Wysocki
@ 2023-12-15 11:26 ` Rafael J. Wysocki
2023-12-15 11:27 ` [PATCH v1 3/3] ACPI: EC: Use a spin lock without disabing interrupts Rafael J. Wysocki
2023-12-28 13:18 ` [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2023-12-15 11:26 UTC (permalink / raw)
To: Linux ACPI
Cc: LKML, Zhang Rui, Srinivas Pandruvada, Michal Wilczynski,
Hans de Goede, Andy Shevchenko, Mika Westerberg, Heikki Krogerus,
Mario Limonciello, Daniel Drake
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
After commit 7a36b901a6eb ("ACPI: OSL: Use a threaded interrupt handler
for SCI") all of the EC code runs in thread context on all systems where
EC events are signaled through a GPE.
It may as well run in thread context on systems using a dedicated IRQ
for EC events signaling, so make it use a threaded handler for that IRQ.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/ec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Index: linux-pm/drivers/acpi/ec.c
===================================================================
--- linux-pm.orig/drivers/acpi/ec.c
+++ linux-pm/drivers/acpi/ec.c
@@ -1458,8 +1458,8 @@ static bool install_gpe_event_handler(st
static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
{
- return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED,
- "ACPI EC", ec) >= 0;
+ return request_threaded_irq(ec->irq, NULL, acpi_ec_irq_handler,
+ IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0;
}
/**
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 3/3] ACPI: EC: Use a spin lock without disabing interrupts
2023-12-15 11:23 [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
2023-12-15 11:25 ` [PATCH v1 1/3] ACPI: OSL: " Rafael J. Wysocki
2023-12-15 11:26 ` [PATCH v1 2/3] ACPI: EC: Use a threaded handler for dedicated IRQ Rafael J. Wysocki
@ 2023-12-15 11:27 ` Rafael J. Wysocki
2023-12-28 13:18 ` [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2023-12-15 11:27 UTC (permalink / raw)
To: Linux ACPI
Cc: LKML, Zhang Rui, Srinivas Pandruvada, Michal Wilczynski,
Hans de Goede, Andy Shevchenko, Mika Westerberg, Heikki Krogerus,
Mario Limonciello, Daniel Drake
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Since all of the ACPI EC driver code runs in thread context after recent
changes, it does not need to disable interrupts on the local CPU when
acquiring a spin lock.
Make it use the spin lock without disabling interrupts.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/ec.c | 112 ++++++++++++++++++++++--------------------------------
1 file changed, 46 insertions(+), 66 deletions(-)
Index: linux-pm/drivers/acpi/ec.c
===================================================================
--- linux-pm.orig/drivers/acpi/ec.c
+++ linux-pm/drivers/acpi/ec.c
@@ -525,12 +525,10 @@ static void acpi_ec_clear(struct acpi_ec
static void acpi_ec_enable_event(struct acpi_ec *ec)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
if (acpi_ec_started(ec))
__acpi_ec_enable_event(ec);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
/* Drain additional events if hardware requires that */
if (EC_FLAGS_CLEAR_ON_RESUME)
@@ -546,11 +544,9 @@ static void __acpi_ec_flush_work(void)
static void acpi_ec_disable_event(struct acpi_ec *ec)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
__acpi_ec_disable_event(ec);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
/*
* When ec_freeze_events is true, we need to flush events in
@@ -571,10 +567,9 @@ void acpi_ec_flush_work(void)
static bool acpi_ec_guard_event(struct acpi_ec *ec)
{
- unsigned long flags;
bool guarded;
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
/*
* If firmware SCI_EVT clearing timing is "event", we actually
* don't know when the SCI_EVT will be cleared by firmware after
@@ -590,31 +585,29 @@ static bool acpi_ec_guard_event(struct a
guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
ec->event_state != EC_EVENT_READY &&
(!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
return guarded;
}
static int ec_transaction_polled(struct acpi_ec *ec)
{
- unsigned long flags;
int ret = 0;
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL))
ret = 1;
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
return ret;
}
static int ec_transaction_completed(struct acpi_ec *ec)
{
- unsigned long flags;
int ret = 0;
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
ret = 1;
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
return ret;
}
@@ -756,7 +749,6 @@ static int ec_guard(struct acpi_ec *ec)
static int ec_poll(struct acpi_ec *ec)
{
- unsigned long flags;
int repeat = 5; /* number of command restarts */
while (repeat--) {
@@ -765,14 +757,14 @@ static int ec_poll(struct acpi_ec *ec)
do {
if (!ec_guard(ec))
return 0;
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
advance_transaction(ec, false);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
} while (time_before(jiffies, delay));
pr_debug("controller reset, restart transaction\n");
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
start_transaction(ec);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
}
return -ETIME;
}
@@ -780,11 +772,10 @@ static int ec_poll(struct acpi_ec *ec)
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
struct transaction *t)
{
- unsigned long tmp;
int ret = 0;
/* start transaction */
- spin_lock_irqsave(&ec->lock, tmp);
+ spin_lock(&ec->lock);
/* Enable GPE for command processing (IBF=0/OBF=1) */
if (!acpi_ec_submit_flushable_request(ec)) {
ret = -EINVAL;
@@ -795,11 +786,11 @@ static int acpi_ec_transaction_unlocked(
ec->curr = t;
ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
start_transaction(ec);
- spin_unlock_irqrestore(&ec->lock, tmp);
+ spin_unlock(&ec->lock);
ret = ec_poll(ec);
- spin_lock_irqsave(&ec->lock, tmp);
+ spin_lock(&ec->lock);
if (t->irq_count == ec_storm_threshold)
acpi_ec_unmask_events(ec);
ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
@@ -808,7 +799,7 @@ static int acpi_ec_transaction_unlocked(
acpi_ec_complete_request(ec);
ec_dbg_ref(ec, "Decrease command");
unlock:
- spin_unlock_irqrestore(&ec->lock, tmp);
+ spin_unlock(&ec->lock);
return ret;
}
@@ -936,9 +927,7 @@ EXPORT_SYMBOL(ec_get_handle);
static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
ec_dbg_drv("Starting EC");
/* Enable GPE for event processing (SCI_EVT=1) */
@@ -948,31 +937,28 @@ static void acpi_ec_start(struct acpi_ec
}
ec_log_drv("EC started");
}
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
}
static bool acpi_ec_stopped(struct acpi_ec *ec)
{
- unsigned long flags;
bool flushed;
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
flushed = acpi_ec_flushed(ec);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
return flushed;
}
static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
if (acpi_ec_started(ec)) {
ec_dbg_drv("Stopping EC");
set_bit(EC_FLAGS_STOPPED, &ec->flags);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
wait_event(ec->wait, acpi_ec_stopped(ec));
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
/* Disable GPE for event processing (SCI_EVT=1) */
if (!suspending) {
acpi_ec_complete_request(ec);
@@ -983,29 +969,25 @@ static void acpi_ec_stop(struct acpi_ec
clear_bit(EC_FLAGS_STOPPED, &ec->flags);
ec_log_drv("EC stopped");
}
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
}
static void acpi_ec_enter_noirq(struct acpi_ec *ec)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
ec->busy_polling = true;
ec->polling_guard = 0;
ec_log_drv("interrupt blocked");
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
}
static void acpi_ec_leave_noirq(struct acpi_ec *ec)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
ec->busy_polling = ec_busy_polling;
ec->polling_guard = ec_polling_guard;
ec_log_drv("interrupt unblocked");
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
}
void acpi_ec_block_transactions(void)
@@ -1137,9 +1119,9 @@ static void acpi_ec_event_processor(stru
ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
- spin_lock_irq(&ec->lock);
+ spin_lock(&ec->lock);
ec->queries_in_progress--;
- spin_unlock_irq(&ec->lock);
+ spin_unlock(&ec->lock);
acpi_ec_put_query_handler(handler);
kfree(q);
@@ -1202,12 +1184,12 @@ static int acpi_ec_submit_query(struct a
*/
ec_dbg_evt("Query(0x%02x) scheduled", value);
- spin_lock_irq(&ec->lock);
+ spin_lock(&ec->lock);
ec->queries_in_progress++;
queue_work(ec_query_wq, &q->work);
- spin_unlock_irq(&ec->lock);
+ spin_unlock(&ec->lock);
return 0;
@@ -1223,14 +1205,14 @@ static void acpi_ec_event_handler(struct
ec_dbg_evt("Event started");
- spin_lock_irq(&ec->lock);
+ spin_lock(&ec->lock);
while (ec->events_to_process) {
- spin_unlock_irq(&ec->lock);
+ spin_unlock(&ec->lock);
acpi_ec_submit_query(ec);
- spin_lock_irq(&ec->lock);
+ spin_lock(&ec->lock);
ec->events_to_process--;
}
@@ -1247,11 +1229,11 @@ static void acpi_ec_event_handler(struct
ec_dbg_evt("Event stopped");
- spin_unlock_irq(&ec->lock);
+ spin_unlock(&ec->lock);
guard_timeout = !!ec_guard(ec);
- spin_lock_irq(&ec->lock);
+ spin_lock(&ec->lock);
/* Take care of SCI_EVT unless someone else is doing that. */
if (guard_timeout && !ec->curr)
@@ -1264,7 +1246,7 @@ static void acpi_ec_event_handler(struct
ec->events_in_progress--;
- spin_unlock_irq(&ec->lock);
+ spin_unlock(&ec->lock);
}
static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt)
@@ -1289,13 +1271,11 @@ static void clear_gpe_and_advance_transa
static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
+ spin_lock(&ec->lock);
clear_gpe_and_advance_transaction(ec, true);
- spin_unlock_irqrestore(&ec->lock, flags);
+ spin_unlock(&ec->lock);
}
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -2105,7 +2085,7 @@ bool acpi_ec_dispatch_gpe(void)
* Dispatch the EC GPE in-band, but do not report wakeup in any case
* to allow the caller to process events properly after that.
*/
- spin_lock_irq(&first_ec->lock);
+ spin_lock(&first_ec->lock);
if (acpi_ec_gpe_status_set(first_ec)) {
pm_pr_dbg("ACPI EC GPE status set\n");
@@ -2114,7 +2094,7 @@ bool acpi_ec_dispatch_gpe(void)
work_in_progress = acpi_ec_work_in_progress(first_ec);
}
- spin_unlock_irq(&first_ec->lock);
+ spin_unlock(&first_ec->lock);
if (!work_in_progress)
return false;
@@ -2127,11 +2107,11 @@ bool acpi_ec_dispatch_gpe(void)
pm_pr_dbg("ACPI EC work flushed\n");
- spin_lock_irq(&first_ec->lock);
+ spin_lock(&first_ec->lock);
work_in_progress = acpi_ec_work_in_progress(first_ec);
- spin_unlock_irq(&first_ec->lock);
+ spin_unlock(&first_ec->lock);
} while (work_in_progress && !pm_wakeup_pending());
return false;
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts
2023-12-15 11:23 [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
` (2 preceding siblings ...)
2023-12-15 11:27 ` [PATCH v1 3/3] ACPI: EC: Use a spin lock without disabing interrupts Rafael J. Wysocki
@ 2023-12-28 13:18 ` Rafael J. Wysocki
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2023-12-28 13:18 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Linux ACPI, LKML, Zhang Rui, Srinivas Pandruvada,
Michal Wilczynski, Hans de Goede, Andy Shevchenko,
Mika Westerberg, Heikki Krogerus, Mario Limonciello, Daniel Drake
On Fri, Dec 15, 2023 at 12:34 PM Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
>
> Hi Everyone,
>
> After
>
> https://patchwork.kernel.org/project/linux-acpi/patch/5745568.DvuYhMxLoT@kreacher/
>
> the SCI interrupt handler is threaded, so ACPICA spin locks can be used without
> disabling interrupts, because they cannot be acquired from a hardirq handler
> running on the same CPU as any code already holding the spin lock. This patch
> [1/3] removes disabling interrupts from acpi_os_acquire_lock() and updates
> acpi_os_release_lock() accordingly.
>
> Patch [2/2] uses the observation that if acpi_handle_interrupt() can run
> in a threaded interrupt handler in the GPE case, it can also run in a threaded
> interrupt handler in the dedicated IRQ case, so it makes the EC driver use a
> threaded handler for the dedicated EC interrupt.
>
> Patch [3/3], in analogy with patch [1/3], uses the observation that after patch
> [2/2] all of the EC code runs in thread context, so it need not disable
> interrupts on the local CPU before acquiring a spin lock, so the EC driver is
> updated to operate its spin lock without disabling interrupts.
I don't see any objections to these patches, so queuing them up for 6.8.
Thanks!
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-12-28 13:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-15 11:23 [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
2023-12-15 11:25 ` [PATCH v1 1/3] ACPI: OSL: " Rafael J. Wysocki
2023-12-15 11:26 ` [PATCH v1 2/3] ACPI: EC: Use a threaded handler for dedicated IRQ Rafael J. Wysocki
2023-12-15 11:27 ` [PATCH v1 3/3] ACPI: EC: Use a spin lock without disabing interrupts Rafael J. Wysocki
2023-12-28 13:18 ` [PATCH v1 0/3] ACPI: OSL/EC: Use spin locks without disabling interrupts Rafael J. Wysocki
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.