[PATCH 0/6] ALSA: emu10k1: Various improvements related to locking
---
This patch series needs to be applied on top of the patch titled "ALSA: emu10k1: use more existing defines instead of open-coded numbers".
Oswald Buddenhagen (6): ALSA: emu10k1: remove pointless locks from timer code ALSA: emu10k1: remove pointless locks from /proc code ALSA: emu10k1: use the right lock in snd_emu10k1_shared_spdif_put() ALSA: emu10k1: fix locking in snd_emu1010_fpga_link_dst_src_write() ALSA: core: update comment on snd_card.controls_rwsem ALSA: emu10k1: remove now superfluous mixer locking
include/sound/core.h | 2 +- sound/pci/emu10k1/emufx.c | 7 ------- sound/pci/emu10k1/emumixer.c | 32 ++------------------------------ sound/pci/emu10k1/emupcm.c | 2 -- sound/pci/emu10k1/emuproc.c | 6 ------ sound/pci/emu10k1/io.c | 25 +++++++++++++++++-------- sound/pci/emu10k1/timer.c | 6 ------ 7 files changed, 20 insertions(+), 60 deletions(-)
Contrary to its name, reg_lock locks the emu data structure, not the registers. As the functions access only data which is set once at card initialization, there is no point in locking it.
Actually locking the registers would be pointless as well, as snd_emu10k1_intr_{en,dis}able() does its own locking, and TIMER is accessed only in this one place.
Locking snd_emu10k1_timer_{start,stop}() against each other also wouldn't buy us anything; the functions interleaving their I/O accesses wouldn't introduce new problems.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/timer.c | 6 ------ 1 file changed, 6 deletions(-)
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 2435d3ba68f7..993663fef885 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -18,29 +18,23 @@ static int snd_emu10k1_timer_start(struct snd_timer *timer) { struct snd_emu10k1 *emu; - unsigned long flags; unsigned int delay;
emu = snd_timer_chip(timer); delay = timer->sticks - 1; if (delay < 5 ) /* minimum time is 5 ticks */ delay = 5; - spin_lock_irqsave(&emu->reg_lock, flags); snd_emu10k1_intr_enable(emu, INTE_INTERVALTIMERENB); outw(delay & TIMER_RATE_MASK, emu->port + TIMER); - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
static int snd_emu10k1_timer_stop(struct snd_timer *timer) { struct snd_emu10k1 *emu; - unsigned long flags;
emu = snd_timer_chip(timer); - spin_lock_irqsave(&emu->reg_lock, flags); snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
emu_lock locks the card's registers, but that's necessary only for multi-register access, incl. read-modify-write cycles.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emuproc.c | 6 ------ 1 file changed, 6 deletions(-)
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index bec72dc60a41..c92253de881e 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -399,31 +399,25 @@ static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, { struct snd_emu10k1 *emu = entry->private_data; unsigned long value; - unsigned long flags; int i; snd_iprintf(buffer, "IO Registers:\n\n"); for(i = 0; i < 0x40; i+=4) { - spin_lock_irqsave(&emu->emu_lock, flags); value = inl(emu->port + i); - spin_unlock_irqrestore(&emu->emu_lock, flags); snd_iprintf(buffer, "%02X: %08lX\n", i, value); } }
static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_emu10k1 *emu = entry->private_data; - unsigned long flags; char line[64]; u32 reg, val; while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; if (reg < 0x40 && val <= 0xffffffff) { - spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); - spin_unlock_irqrestore(&emu->emu_lock, flags); } } }
The function does read-modify-write cycles on the card's registers, and doesn't access mutable members of the emu data structure.
I suppose this might have been a mixup due to the lock names being logically swapped.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emumixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 3ebc7c36a444..24052f17d81c 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1654,7 +1654,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, sw = ucontrol->value.integer.value[0]; if (emu->card_capabilities->invert_shared_spdif) sw = !sw; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irqsave(&emu->emu_lock, flags); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { @@ -1675,7 +1675,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, reg |= val; outl(reg | val, emu->port + HCFG); } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irqrestore(&emu->emu_lock, flags); return change; }
This is a multi-register operation, which must be locked in its entirety.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/io.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index cfb96a67aa35..aee84c3f9f37 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -233,23 +233,28 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, return err; }
-void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) +static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 value) { - unsigned long flags; - if (snd_BUG_ON(reg > 0x3f)) return; reg += 0x40; /* 0x40 upwards are registers. */ if (snd_BUG_ON(value > 0x3f)) /* 0 to 0x3f are values */ return; - spin_lock_irqsave(&emu->emu_lock, flags); outw(reg, emu->port + A_GPIO); udelay(10); outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ udelay(10); outw(value, emu->port + A_GPIO); udelay(10); outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ +} + +void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_write_locked(emu, reg, value); spin_unlock_irqrestore(&emu->emu_lock, flags); }
@@ -276,14 +281,18 @@ void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) */ void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src) { + unsigned long flags; + if (snd_BUG_ON(dst & ~0x71f)) return; if (snd_BUG_ON(src & ~0x71f)) return; - snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8); - snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f); - snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8); - snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f); + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, src >> 8); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, src & 0x1f); + spin_unlock_irqrestore(&emu->emu_lock, flags); }
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
Since commit 5bbb1ab5bd ("control: use counting semaphore as write lock for ELEM_WRITE operation"), this has been locking the controls including their values, not just the list of controls.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- include/sound/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/sound/core.h b/include/sound/core.h index 3edc4ab08774..4ea5f66b59d7 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -98,7 +98,7 @@ struct snd_card {
struct device ctl_dev; /* control device */ unsigned int last_numid; /* last used numeric ID */ - struct rw_semaphore controls_rwsem; /* controls list lock */ + struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ rwlock_t ctl_files_rwlock; /* ctl_files list lock */ int controls_count; /* count of all controls */ size_t user_ctl_alloc_size; // current memory allocation by user controls.
Since commit 5bbb1ab5bd ("control: use counting semaphore as write lock for ELEM_WRITE operation"), mixer values have been fully read-write locked. This means that it is now unnecessary to apply any additional locks to values that are accessed solely by mixer callbacks. Values that are read outside mixer callbacks still need write locking. There are no cases of mixer values being written outside mixer callbacks, so no read locks remain in mixer callbacks.
Note that the removed locks refer only to the emu data structure, not the card's registers as the lock's name suggests.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emufx.c | 7 ------- sound/pci/emu10k1/emumixer.c | 28 ---------------------------- sound/pci/emu10k1/emupcm.c | 2 -- 3 files changed, 37 deletions(-)
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 3f64ccab0e63..98785110ef63 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -318,30 +318,24 @@ static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_fx8010_ctl *ctl = (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value; - unsigned long flags; unsigned int i; - spin_lock_irqsave(&emu->reg_lock, flags); for (i = 0; i < ctl->vcount; i++) ucontrol->value.integer.value[i] = ctl->value[i]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_fx8010_ctl *ctl = (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value; - unsigned long flags; unsigned int nval, val; unsigned int i, j; int change = 0; - spin_lock_irqsave(&emu->reg_lock, flags); for (i = 0; i < ctl->vcount; i++) { nval = ucontrol->value.integer.value[i]; if (nval < ctl->min) @@ -380,7 +374,6 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl } } __error: - spin_unlock_irqrestore(&emu->reg_lock, flags); return change; }
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 24052f17d81c..ab04f8be25bd 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -41,17 +41,14 @@ static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned long flags;
/* Limit: emu->spdif_bits */ if (idx >= 3) return -EINVAL; - spin_lock_irqsave(&emu->reg_lock, flags); ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1070,10 +1067,7 @@ static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int tmp; - unsigned long flags; -
- spin_lock_irqsave(&emu->reg_lock, flags); tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); switch (tmp & A_SPDIF_RATE_MASK) { case A_SPDIF_44100: @@ -1088,7 +1082,6 @@ static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, default: ucontrol->value.enumerated.item[0] = 1; } - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1146,22 +1139,19 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); int change; unsigned int val; - unsigned long flags;
/* Limit: emu->spdif_bits */ if (idx >= 3) return -EINVAL; val = (ucontrol->value.iec958.status[0] << 0) | (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); - spin_lock_irqsave(&emu->reg_lock, flags); change = val != emu->spdif_bits[idx]; if (change) { snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); emu->spdif_bits[idx] = val; } - spin_unlock_irqrestore(&emu->reg_lock, flags); return change; }
@@ -1229,20 +1219,17 @@ static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct s static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int voice, idx; int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f;
- spin_lock_irqsave(&emu->reg_lock, flags); for (voice = 0; voice < 3; voice++) for (idx = 0; idx < num_efx; idx++) ucontrol->value.integer.value[(voice * num_efx) + idx] = mix->send_routing[voice][idx] & mask; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1305,17 +1292,14 @@ static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct sn static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int idx; int num_efx = emu->audigy ? 8 : 4;
- spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < 3*num_efx; idx++) ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1378,13 +1362,10 @@ static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; - unsigned long flags; int idx;
- spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < 3; idx++) ucontrol->value.integer.value[idx] = mix->attn[idx]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1443,19 +1424,16 @@ static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, stru static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int idx; int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f;
- spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < num_efx; idx++) ucontrol->value.integer.value[idx] = mix->send_routing[0][idx] & mask; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1513,17 +1491,14 @@ static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struc static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int idx; int num_efx = emu->audigy ? 8 : 4;
- spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < num_efx; idx++) ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
@@ -1582,11 +1557,8 @@ static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; - unsigned long flags;
- spin_lock_irqsave(&emu->reg_lock, flags); ucontrol->value.integer.value[0] = mix->attn[0]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index e8d2f0f6fbb3..5ed404e8ed39 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1433,10 +1433,8 @@ static int snd_emu10k1_pcm_efx_voices_mask_get(struct snd_kcontrol *kcontrol, st int nefx = emu->audigy ? 64 : 32; int idx; - spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < nefx; idx++) ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0; - spin_unlock_irq(&emu->reg_lock); return 0; }
On Fri, 28 Apr 2023 11:59:35 +0200, Oswald Buddenhagen wrote:
This patch series needs to be applied on top of the patch titled "ALSA: emu10k1: use more existing defines instead of open-coded numbers".
Oswald Buddenhagen (6): ALSA: emu10k1: remove pointless locks from timer code ALSA: emu10k1: remove pointless locks from /proc code ALSA: emu10k1: use the right lock in snd_emu10k1_shared_spdif_put() ALSA: emu10k1: fix locking in snd_emu1010_fpga_link_dst_src_write() ALSA: core: update comment on snd_card.controls_rwsem ALSA: emu10k1: remove now superfluous mixer locking
Applied all six patches now.
thanks,
Takashi
participants (2)
-
Oswald Buddenhagen
-
Takashi Iwai