summaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-07-23 14:04:37 -0700
committerJakub Kicinski <kuba@kernel.org>2026-07-23 14:07:40 -0700
commit89d8006259b81dd25c962f6cc8d7ab268d6ea426 (patch)
tree6fb362a45540a3531072b20907d19e11e8f8b7b3 /sound/core
parented6dc972c19ff9ffca504f5739848da4275219e3 (diff)
parentd326f83e819c53aa05c40d64f5805d6237b6aa1b (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.2-rc5). Conflicts: drivers/net/amt.c 3656a79f94c47 ("amt: re-read skb header pointers after every pull") 586c4dcf28eb6 ("amt: no longer rely on RTNL in amt_fill_info()") https://lore.kernel.org/amIaJr3aOQNS_Fvl@sirena.org.uk Adjacent changes: drivers/net/geneve.c 8efb8f8bbb35 ("geneve: require CAP_NET_ADMIN in the device netns for changelink") 0ba269933f73 ("geneve: convert config to RCU-protected pointer") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/seq/seq_timer.c13
-rw-r--r--sound/core/timer.c21
2 files changed, 29 insertions, 5 deletions
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 4cd7211ccf48..419288eec4bb 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -61,12 +61,23 @@ struct snd_seq_timer *snd_seq_timer_new(void)
void snd_seq_timer_delete(struct snd_seq_timer **tmr)
{
struct snd_seq_timer *t = *tmr;
- *tmr = NULL;
+ struct snd_timer_instance *ti;
if (t == NULL) {
pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
return;
}
+
+ scoped_guard(spinlock_irq, &t->lock) {
+ ti = t->timeri;
+ t->timeri = NULL;
+ }
+ if (ti) {
+ snd_timer_close(ti);
+ snd_timer_instance_free(ti);
+ }
+
+ *tmr = NULL;
t->running = 0;
/* reset time */
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 51c6ac4df9f4..07ef127b29e1 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -489,10 +489,20 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
snd_timer_stop(timeri);
if (timer) {
+ struct snd_timer_instance *slave;
+ bool busy;
+
timer->num_instances--;
- /* wait, until the active callback is finished */
+ /* unqueue then drain the slaves' callbacks before remove_slave_links() severs them */
spin_lock_irq(&timer->lock);
- while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
+ list_for_each_entry(slave, &timeri->slave_list_head, open_list)
+ list_del_init(&slave->ack_list);
+ for (;;) {
+ busy = timeri->flags & SNDRV_TIMER_IFLG_CALLBACK;
+ list_for_each_entry(slave, &timeri->slave_list_head, open_list)
+ busy |= slave->flags & SNDRV_TIMER_IFLG_CALLBACK;
+ if (!busy)
+ break;
spin_unlock_irq(&timer->lock);
udelay(10);
spin_lock_irq(&timer->lock);
@@ -927,12 +937,15 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
ack_list_head = &timer->ack_list_head;
else
ack_list_head = &timer->sack_list_head;
- if (list_empty(&ti->ack_list))
+ /* don't requeue an instance whose callback is still running */
+ if (list_empty(&ti->ack_list) &&
+ !(ti->flags & SNDRV_TIMER_IFLG_CALLBACK))
list_add_tail(&ti->ack_list, ack_list_head);
list_for_each_entry(ts, &ti->slave_active_head, active_list) {
ts->pticks = ti->pticks;
ts->resolution = resolution;
- if (list_empty(&ts->ack_list))
+ if (list_empty(&ts->ack_list) &&
+ !(ts->flags & SNDRV_TIMER_IFLG_CALLBACK))
list_add_tail(&ts->ack_list, ack_list_head);
}
}