[PATCH v6 2/3] pps: kc: convert pps_kc_hardpps_lock to raw_spinlock_t
From: Calvin Owens
Date: Mon May 25 2026 - 15:51:57 EST
From: Michael Byczkowski <by@xxxxxxxxxxxx>
pps_kc_hardpps_lock is held in pps_kc_event(), which calls
hardpps(). hardpps() takes tk_core.lock, which is already a
raw_spinlock_t -- and nesting a sleeping lock (PREEMPT_RT's
spinlock_t) over a raw_spinlock_t is invalid.
Convert pps_kc_hardpps_lock and its call sites in kc.c to
raw_spinlock_t to make the nesting valid on PREEMPT_RT.
While here, refactor pps_kc_bind() and pps_kc_remove() to use
guard(raw_spinlock_irq) for scope-based lock release. This
eliminates four duplicated unlock call sites in pps_kc_bind()
and the ambiguous bracket structure that resulted from them.
Behavior is unchanged.
No functional change on non-RT kernels.
Tested-by: Michael Byczkowski <by@xxxxxxxxxxxx>
Tested-by: Calvin Owens <calvin@xxxxxxxxxx>
Acked-by: Rodolfo Giometti <giometti@xxxxxxxxxxxx>
Signed-off-by: Michael Byczkowski <by@xxxxxxxxxxxx>
Signed-off-by: Calvin Owens <calvin@xxxxxxxxxx>
---
drivers/pps/kc.c | 67 ++++++++++++++++++++++--------------------------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c
index fbd23295afd7..715b775e9679 100644
--- a/drivers/pps/kc.c
+++ b/drivers/pps/kc.c
@@ -21,7 +21,7 @@
*/
/* state variables to bind kernel consumer */
-static DEFINE_SPINLOCK(pps_kc_hardpps_lock);
+static DEFINE_RAW_SPINLOCK(pps_kc_hardpps_lock);
/* PPS API (RFC 2783): current source and mode for kernel consumer */
static struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */
static int pps_kc_hardpps_mode; /* mode bits for kernel consumer */
@@ -36,35 +36,31 @@ static int pps_kc_hardpps_mode; /* mode bits for kernel consumer */
int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
{
/* Check if another consumer is already bound */
- spin_lock_irq(&pps_kc_hardpps_lock);
+ guard(raw_spinlock_irq)(&pps_kc_hardpps_lock);
- if (bind_args->edge == 0)
- if (pps_kc_hardpps_dev == pps) {
- pps_kc_hardpps_mode = 0;
- pps_kc_hardpps_dev = NULL;
- spin_unlock_irq(&pps_kc_hardpps_lock);
- dev_info(&pps->dev, "unbound kernel"
- " consumer\n");
- } else {
- spin_unlock_irq(&pps_kc_hardpps_lock);
- dev_err(&pps->dev, "selected kernel consumer"
- " is not bound\n");
+ if (bind_args->edge == 0) {
+ /* Unbind request */
+ if (pps_kc_hardpps_dev != pps) {
+ dev_err(&pps->dev,
+ "selected kernel consumer is not bound\n");
return -EINVAL;
}
- else
- if (pps_kc_hardpps_dev == NULL ||
- pps_kc_hardpps_dev == pps) {
- pps_kc_hardpps_mode = bind_args->edge;
- pps_kc_hardpps_dev = pps;
- spin_unlock_irq(&pps_kc_hardpps_lock);
- dev_info(&pps->dev, "bound kernel consumer: "
- "edge=0x%x\n", bind_args->edge);
- } else {
- spin_unlock_irq(&pps_kc_hardpps_lock);
- dev_err(&pps->dev, "another kernel consumer"
- " is already bound\n");
+ pps_kc_hardpps_mode = 0;
+ pps_kc_hardpps_dev = NULL;
+ dev_info(&pps->dev, "unbound kernel consumer\n");
+ } else {
+ /* Bind request */
+ if (pps_kc_hardpps_dev && pps_kc_hardpps_dev != pps) {
+ dev_err(&pps->dev,
+ "another kernel consumer is already bound\n");
return -EINVAL;
}
+ pps_kc_hardpps_mode = bind_args->edge;
+ pps_kc_hardpps_dev = pps;
+ dev_info(&pps->dev,
+ "bound kernel consumer: edge=0x%x\n",
+ bind_args->edge);
+ }
return 0;
}
@@ -78,15 +74,14 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
*/
void pps_kc_remove(struct pps_device *pps)
{
- spin_lock_irq(&pps_kc_hardpps_lock);
- if (pps == pps_kc_hardpps_dev) {
- pps_kc_hardpps_mode = 0;
- pps_kc_hardpps_dev = NULL;
- spin_unlock_irq(&pps_kc_hardpps_lock);
- dev_info(&pps->dev, "unbound kernel consumer"
- " on device removal\n");
- } else
- spin_unlock_irq(&pps_kc_hardpps_lock);
+ guard(raw_spinlock_irq)(&pps_kc_hardpps_lock);
+
+ if (pps != pps_kc_hardpps_dev)
+ return;
+
+ pps_kc_hardpps_mode = 0;
+ pps_kc_hardpps_dev = NULL;
+ dev_info(&pps->dev, "unbound kernel consumer on device removal\n");
}
/* pps_kc_event - call hardpps() on PPS event
@@ -102,8 +97,8 @@ void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,
unsigned long flags;
/* Pass some events to kernel consumer if activated */
- spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
+ raw_spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode)
hardpps(&ts->ts_real, &ts->ts_raw);
- spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
+ raw_spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
}
--
2.47.3