diff --git a/drivers/mfd/rp1.c b/drivers/mfd/rp1.c index 0f85981da8e5ef..5de7270b12c738 100644 --- a/drivers/mfd/rp1.c +++ b/drivers/mfd/rp1.c @@ -145,8 +145,14 @@ static int rp1_irq_set_affinity(struct irq_data *irqd, const struct cpumask *des { struct rp1_dev *rp1 = irqd->domain->host_data; struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq]; + int ret; - return msi_domain_set_affinity(pcie_irqd, dest, force); + ret = msi_domain_set_affinity(pcie_irqd, dest, force); + if (ret >= 0) { + irq_data_update_effective_affinity(irqd, dest); + return IRQ_SET_MASK_OK_DONE; + } + return ret; } static struct irq_chip rp1_irq_chip = { diff --git a/drivers/pinctrl/pinctrl-rp1.c b/drivers/pinctrl/pinctrl-rp1.c index 158cea41d9b943..f87b62c99cfcbb 100644 --- a/drivers/pinctrl/pinctrl-rp1.c +++ b/drivers/pinctrl/pinctrl-rp1.c @@ -958,8 +958,14 @@ static int rp1_gpio_irq_set_affinity(struct irq_data *data, const struct cpumask } } - if (parent_data && parent_data->chip->irq_set_affinity) - return parent_data->chip->irq_set_affinity(parent_data, dest, force); + if (parent_data && parent_data->chip->irq_set_affinity) { + int ret = parent_data->chip->irq_set_affinity(parent_data, dest, force); + if (ret >= 0) { + irq_data_update_effective_affinity(data, dest); + return IRQ_SET_MASK_OK_DONE; + } + return ret; + } return -EINVAL; } diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 65d17781ddb7d3..602c6eb579d66d 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -35,33 +35,44 @@ struct pps_gpio_device_data { bool capture_clear; unsigned int echo_active_ms; /* PPS echo active duration */ unsigned long echo_timeout; /* timer timeout value in jiffies */ + struct pps_event_time ts; /* timestamp captured in hardirq */ }; /* * Report the PPS event */ -static irqreturn_t pps_gpio_irq_handler(int irq, void *data) +/* + * Primary hardirq handler — runs in hardirq context even on PREEMPT_RT. + * Only captures the timestamp; all other work is deferred to the thread. + */ +static irqreturn_t pps_gpio_irq_hardirq(int irq, void *data) { - const struct pps_gpio_device_data *info; - struct pps_event_time ts; - int rising_edge; + struct pps_gpio_device_data *info = data; + + pps_get_ts(&info->ts); - /* Get the time stamp first */ - pps_get_ts(&ts); + return IRQ_WAKE_THREAD; +} - info = data; +/* + * Threaded handler — processes the PPS event using the timestamp + * captured in hardirq context above. + */ +static irqreturn_t pps_gpio_irq_thread(int irq, void *data) +{ + struct pps_gpio_device_data *info = data; + int rising_edge; - /* Small trick to bypass the check on edge's direction when capture_clear is unset */ rising_edge = info->capture_clear ? gpiod_get_value(info->gpio_pin) : !info->assert_falling_edge; if ((rising_edge && !info->assert_falling_edge) || (!rising_edge && info->assert_falling_edge)) - pps_event(info->pps, &ts, PPS_CAPTUREASSERT, data); + pps_event(info->pps, &info->ts, PPS_CAPTUREASSERT, data); else if (info->capture_clear && ((rising_edge && info->assert_falling_edge) || (!rising_edge && !info->assert_falling_edge))) - pps_event(info->pps, &ts, PPS_CAPTURECLEAR, data); + pps_event(info->pps, &info->ts, PPS_CAPTURECLEAR, data); else dev_warn_ratelimited(&info->pps->dev, "IRQ did not trigger any PPS event\n"); @@ -213,8 +224,12 @@ static int pps_gpio_probe(struct platform_device *pdev) } /* register IRQ interrupt handler */ - ret = request_irq(data->irq, pps_gpio_irq_handler, - get_irqf_trigger_flags(data), data->info.name, data); + + ret = request_threaded_irq(data->irq, + pps_gpio_irq_hardirq, pps_gpio_irq_thread, + get_irqf_trigger_flags(data) | IRQF_ONESHOT, + data->info.name, data); + if (ret) { pps_unregister_source(data->pps); dev_err(dev, "failed to acquire IRQ %d\n", data->irq); diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 1bf0335a1b4198..dc7fac75ec2738 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -102,7 +102,7 @@ struct pps_device *pps_register_source(struct pps_source_info *info, pps->info.echo = pps_echo_client_default; init_waitqueue_head(&pps->queue); - spin_lock_init(&pps->lock); + raw_spin_lock_init(&pps->lock); /* Create the char device */ err = pps_register_cdev(pps); @@ -167,7 +167,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, timespec_to_pps_ktime(&ts_real, ts->ts_real); - spin_lock_irqsave(&pps->lock, flags); + raw_spin_lock_irqsave(&pps->lock, flags); /* Must call the echo function? */ if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) @@ -214,6 +214,6 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, kill_fasync(&pps->async_queue, SIGIO, POLL_IN); } - spin_unlock_irqrestore(&pps->lock, flags); + raw_spin_unlock_irqrestore(&pps->lock, flags); } EXPORT_SYMBOL(pps_event); diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c index fbd23295afd7d9..9c6c024d5083ff 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,17 +36,17 @@ 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); + raw_spin_lock_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); + raw_spin_unlock_irq(&pps_kc_hardpps_lock); dev_info(&pps->dev, "unbound kernel" " consumer\n"); } else { - spin_unlock_irq(&pps_kc_hardpps_lock); + raw_spin_unlock_irq(&pps_kc_hardpps_lock); dev_err(&pps->dev, "selected kernel consumer" " is not bound\n"); return -EINVAL; @@ -56,11 +56,11 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args) pps_kc_hardpps_dev == pps) { pps_kc_hardpps_mode = bind_args->edge; pps_kc_hardpps_dev = pps; - spin_unlock_irq(&pps_kc_hardpps_lock); + raw_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); + raw_spin_unlock_irq(&pps_kc_hardpps_lock); dev_err(&pps->dev, "another kernel consumer" " is already bound\n"); return -EINVAL; @@ -78,15 +78,15 @@ 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); + raw_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); + raw_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); + raw_spin_unlock_irq(&pps_kc_hardpps_lock); } /* pps_kc_event - call hardpps() on PPS event @@ -102,8 +102,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); } diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 442d7e8f6fb957..495f6dc438d849 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -103,12 +103,12 @@ static long pps_cdev_ioctl(struct file *file, case PPS_GETPARAMS: dev_dbg(&pps->dev, "PPS_GETPARAMS\n"); - spin_lock_irq(&pps->lock); + raw_spin_lock_irq(&pps->lock); /* Get the current parameters */ params = pps->params; - spin_unlock_irq(&pps->lock); + raw_spin_unlock_irq(&pps->lock); err = copy_to_user(uarg, ¶ms, sizeof(struct pps_kparams)); if (err) @@ -139,7 +139,7 @@ static long pps_cdev_ioctl(struct file *file, return -EINVAL; } - spin_lock_irq(&pps->lock); + raw_spin_lock_irq(&pps->lock); /* Save the new parameters */ pps->params = params; @@ -163,7 +163,7 @@ static long pps_cdev_ioctl(struct file *file, pps->params.assert_off_tu.flags = 0; pps->params.clear_off_tu.flags = 0; - spin_unlock_irq(&pps->lock); + raw_spin_unlock_irq(&pps->lock); break; @@ -190,7 +190,7 @@ static long pps_cdev_ioctl(struct file *file, return err; /* Return the fetched timestamp and save last fetched event */ - spin_lock_irq(&pps->lock); + raw_spin_lock_irq(&pps->lock); pps->last_fetched_ev = pps->last_ev; @@ -200,7 +200,7 @@ static long pps_cdev_ioctl(struct file *file, fdata.info.clear_tu = pps->clear_tu; fdata.info.current_mode = pps->current_mode; - spin_unlock_irq(&pps->lock); + raw_spin_unlock_irq(&pps->lock); err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata)); if (err) @@ -279,7 +279,7 @@ static long pps_cdev_compat_ioctl(struct file *file, return err; /* Return the fetched timestamp and save last fetched event */ - spin_lock_irq(&pps->lock); + raw_spin_lock_irq(&pps->lock); pps->last_fetched_ev = pps->last_ev; @@ -292,7 +292,7 @@ static long pps_cdev_compat_ioctl(struct file *file, memcpy(&compat.info.clear_tu, &pps->clear_tu, sizeof(struct pps_ktime_compat)); - spin_unlock_irq(&pps->lock); + raw_spin_unlock_irq(&pps->lock); return copy_to_user(uarg, &compat, sizeof(struct pps_fdata_compat)) ? -EFAULT : 0; diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index aab0aebb529e02..f2fe504071edd8 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -59,7 +59,7 @@ struct pps_device { void const *lookup_cookie; /* For pps_lookup_dev() only */ struct device dev; struct fasync_struct *async_queue; /* fasync method */ - spinlock_t lock; + raw_spinlock_t lock; }; /*