* [PATCH 01/10] ALSA: emu10k1: fix E-MU card dock presence monitoring
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
@ 2024-04-21 20:46 ` Oswald Buddenhagen
2024-04-21 20:46 ` [PATCH 02/10] ALSA: emu10k1: factor out snd_emu1010_load_dock_firmware() Oswald Buddenhagen
` (9 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:46 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
While there are two separate IRQ status bits for dock attach and detach,
the hardware appears to mix them up more or less randomly, making them
useless for tracking what actually happened. It is much safer to check
the dock status separately and proceed based on that, as the old polling
code did.
Note that the code assumes that only the dock can be hot-plugged - if
other option card bits changed, the logic would break.
Fixes: fbb64eedf5a3 (ALSA: emu10k1: make E-MU dock monitoring interrupt-driven)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218584
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index de5c41e578e1..85f70368a27d 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -778,6 +778,11 @@ static void emu1010_firmware_work(struct work_struct *work)
msleep(10);
/* Unmute all. Default is muted after a firmware load */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
+ } else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
+ /* Audio Dock removed */
+ dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
+ /* The hardware auto-mutes all, so we unmute again */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
}
}
@@ -810,14 +815,12 @@ static void emu1010_interrupt(struct snd_emu10k1 *emu)
u32 sts;
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
- if (sts & EMU_HANA_IRQ_DOCK_LOST) {
- /* Audio Dock removed */
- dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
- /* The hardware auto-mutes all, so we unmute again */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
- } else if (sts & EMU_HANA_IRQ_DOCK) {
+
+ // The distinction of the IRQ status bits is unreliable,
+ // so we dispatch later based on option card status.
+ if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
schedule_work(&emu->emu1010.firmware_work);
- }
+
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
schedule_work(&emu->emu1010.clock_work);
}
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 02/10] ALSA: emu10k1: factor out snd_emu1010_load_dock_firmware()
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
2024-04-21 20:46 ` [PATCH 01/10] ALSA: emu10k1: fix E-MU card dock presence monitoring Oswald Buddenhagen
@ 2024-04-21 20:46 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 03/10] ALSA: emu10k1: move the whole GPIO event handling to the workqueue Oswald Buddenhagen
` (8 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:46 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
Pulled out of the next patch to improve its legibility.
As the function is now available, call it directly from
snd_emu10k1_emu1010_init(), thus making the MicroDock firmware loading
synchronous - there isn't really a reason not to. Note that this does
not affect the AudioDocks of rev1 cards, as these have no independent
power supplies, and thus come up only a while after the main card is
initialized.
As a drive-by, adjust the priorities of two messages to better reflect
their impact.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 66 +++++++++++++++++---------------
1 file changed, 36 insertions(+), 30 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 85f70368a27d..6265fc9ae260 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -732,11 +732,43 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
return snd_emu1010_load_firmware_entry(emu, *fw);
}
+static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
+{
+ u32 tmp, tmp2;
+ int err;
+
+ dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
+ /* Return to Audio Dock programming mode */
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ EMU_HANA_FPGA_CONFIG_AUDIODOCK);
+ err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
+ if (err < 0)
+ return;
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
+ dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
+ if ((tmp & 0x1f) != 0x15) {
+ /* FPGA failed to be programmed */
+ dev_err(emu->card->dev,
+ "emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
+ tmp);
+ return;
+ }
+ dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");
+
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
+ dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
+
+ /* Allow DLL to settle, to sync clocking between 1010 and Dock */
+ msleep(10);
+}
+
static void emu1010_firmware_work(struct work_struct *work)
{
struct snd_emu10k1 *emu;
- u32 tmp, tmp2, reg;
- int err;
+ u32 reg;
emu = container_of(work, struct snd_emu10k1,
emu1010.firmware_work);
@@ -749,33 +781,7 @@ static void emu1010_firmware_work(struct work_struct *work)
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
- /* Return to Audio Dock programming mode */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware\n");
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
- EMU_HANA_FPGA_CONFIG_AUDIODOCK);
- err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
- if (err < 0)
- return;
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
- dev_info(emu->card->dev,
- "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
- if ((tmp & 0x1f) != 0x15) {
- /* FPGA failed to be programmed */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
- tmp);
- return;
- }
- dev_info(emu->card->dev,
- "emu1010: Audio Dock Firmware loaded\n");
- snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
- snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
- dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
- /* Sync clocking between 1010 and Dock */
- /* Allow DLL to settle */
- msleep(10);
+ snd_emu1010_load_dock_firmware(emu);
/* Unmute all. Default is muted after a firmware load */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
} else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
@@ -892,7 +898,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®);
dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
- schedule_work(&emu->emu1010.firmware_work);
+ snd_emu1010_load_dock_firmware(emu);
if (emu->card_capabilities->no_adat) {
emu->emu1010.optical_in = 0; /* IN_SPDIF */
emu->emu1010.optical_out = 0; /* OUT_SPDIF */
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 03/10] ALSA: emu10k1: move the whole GPIO event handling to the workqueue
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
2024-04-21 20:46 ` [PATCH 01/10] ALSA: emu10k1: fix E-MU card dock presence monitoring Oswald Buddenhagen
2024-04-21 20:46 ` [PATCH 02/10] ALSA: emu10k1: factor out snd_emu1010_load_dock_firmware() Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 04/10] ALSA: emu10k1: use mutex for E-MU FPGA access locking Oswald Buddenhagen
` (7 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
The actual event processing was already done by workqueue items. We can
move the event dispatching there as well, rather than doing it already
in the interrupt handler callback.
This change has a rather profound "side effect" on the reliability of
the FPGA programming: once we enter programming mode, we must not issue
any snd_emu1010_fpga_{read,write}() calls until we're done, as these
would badly mess up the programming protocol. But exactly that would
happen when trying to program the dock, as that triggers GPIO interrupts
as a side effect. This is mitigated by deferring the actual interrupt
handling, as workqueue items are not re-entrant.
To avoid scheduling the dispatcher on non-events, we now explicitly
ignore GPIO IRQs triggered by "uninteresting" pins, which happens a lot
as a side effect of calling snd_emu1010_fpga_{read,write}().
Fixes: fbb64eedf5a3 (ALSA: emu10k1: make E-MU dock monitoring interrupt-driven)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218584
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
include/sound/emu10k1.h | 3 +-
sound/pci/emu10k1/emu10k1.c | 3 +-
sound/pci/emu10k1/emu10k1_main.c | 56 ++++++++++++++++----------------
3 files changed, 30 insertions(+), 32 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 1af9e6819392..9cc10fab01a8 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1684,8 +1684,7 @@ struct snd_emu1010 {
unsigned int clock_fallback;
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
- struct work_struct firmware_work;
- struct work_struct clock_work;
+ struct work_struct work;
};
struct snd_emu10k1 {
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index fe72e7d77241..dadeda7758ce 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -189,8 +189,7 @@ static int snd_emu10k1_suspend(struct device *dev)
emu->suspend = 1;
- cancel_work_sync(&emu->emu1010.firmware_work);
- cancel_work_sync(&emu->emu1010.clock_work);
+ cancel_work_sync(&emu->emu1010.work);
snd_ac97_suspend(emu->ac97);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 6265fc9ae260..86eaf5963502 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -765,19 +765,10 @@ static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
msleep(10);
}
-static void emu1010_firmware_work(struct work_struct *work)
+static void emu1010_dock_event(struct snd_emu10k1 *emu)
{
- struct snd_emu10k1 *emu;
u32 reg;
- emu = container_of(work, struct snd_emu10k1,
- emu1010.firmware_work);
- if (emu->card->shutdown)
- return;
-#ifdef CONFIG_PM_SLEEP
- if (emu->suspend)
- return;
-#endif
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
@@ -792,43 +783,54 @@ static void emu1010_firmware_work(struct work_struct *work)
}
}
-static void emu1010_clock_work(struct work_struct *work)
+static void emu1010_clock_event(struct snd_emu10k1 *emu)
{
- struct snd_emu10k1 *emu;
struct snd_ctl_elem_id id;
- emu = container_of(work, struct snd_emu10k1,
- emu1010.clock_work);
- if (emu->card->shutdown)
- return;
-#ifdef CONFIG_PM_SLEEP
- if (emu->suspend)
- return;
-#endif
-
spin_lock_irq(&emu->reg_lock);
// This is the only thing that can actually happen.
emu->emu1010.clock_source = emu->emu1010.clock_fallback;
emu->emu1010.wclock = 1 - emu->emu1010.clock_source;
snd_emu1010_update_clock(emu);
spin_unlock_irq(&emu->reg_lock);
snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0);
snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
}
-static void emu1010_interrupt(struct snd_emu10k1 *emu)
+static void emu1010_work(struct work_struct *work)
{
+ struct snd_emu10k1 *emu;
u32 sts;
+ emu = container_of(work, struct snd_emu10k1, emu1010.work);
+ if (emu->card->shutdown)
+ return;
+#ifdef CONFIG_PM_SLEEP
+ if (emu->suspend)
+ return;
+#endif
+
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
// The distinction of the IRQ status bits is unreliable,
// so we dispatch later based on option card status.
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
- schedule_work(&emu->emu1010.firmware_work);
+ emu1010_dock_event(emu);
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
- schedule_work(&emu->emu1010.clock_work);
+ emu1010_clock_event(emu);
+}
+
+static void emu1010_interrupt(struct snd_emu10k1 *emu)
+{
+ // We get an interrupt on each GPIO input pin change, but we
+ // care only about the ones triggered by the dedicated pin.
+ u16 sts = inw(emu->port + A_GPIO);
+ u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
+ if (!(sts & bit))
+ return;
+
+ schedule_work(&emu->emu1010.work);
}
/*
@@ -969,8 +971,7 @@ static void snd_emu10k1_free(struct snd_card *card)
/* Disable 48Volt power to Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
}
- cancel_work_sync(&emu->emu1010.firmware_work);
- cancel_work_sync(&emu->emu1010.clock_work);
+ cancel_work_sync(&emu->emu1010.work);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
snd_util_memhdr_free(emu->memhdr);
@@ -1549,8 +1550,7 @@ int snd_emu10k1_create(struct snd_card *card,
emu->irq = -1;
emu->synth = NULL;
emu->get_synth_voice = NULL;
- INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
- INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work);
+ INIT_WORK(&emu->emu1010.work, emu1010_work);
/* read revision & serial */
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 04/10] ALSA: emu10k1: use mutex for E-MU FPGA access locking
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (2 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 03/10] ALSA: emu10k1: move the whole GPIO event handling to the workqueue Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 05/10] ALSA: emu10k1: fix E-MU dock initialization Oswald Buddenhagen
` (6 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
The FPGA access through the GPIO port does not interfere with other
sound processor register access, so there is no need to subject it to
emu_lock. And after moving all FPGA access out of the interrupt handler,
it does not need to be IRQ-safe, either.
What's more, attaching the dock causes a firmware upload, which takes
several seconds. We really don't want to disable IRQs for this long, and
even less also have someone else spin with IRQs disabled waiting for us.
Therefore, use a mutex for FPGA access locking.
This makes the code somewhat more noisy, as we need to wrap bigger
sections into the mutex, as it needs to enclose the spinlocks.
The latter has the "side effect" of fixing dock FPGA programming in a
corner case: a really badly timed mixer access right between entering
FPGA programming mode and uploading the netlist would mess up the
protocol.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
include/sound/emu10k1.h | 4 +++
sound/pci/emu10k1/emu10k1_main.c | 19 +++++++++---
sound/pci/emu10k1/emumixer.c | 18 ++++++++----
sound/pci/emu10k1/emuproc.c | 9 ++++++
sound/pci/emu10k1/io.c | 50 ++++++++++++++------------------
5 files changed, 62 insertions(+), 38 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 9cc10fab01a8..234b5baea69c 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1685,6 +1685,7 @@ struct snd_emu1010 {
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
struct work_struct work;
+ struct mutex lock;
};
struct snd_emu10k1 {
@@ -1833,6 +1834,9 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg,
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
+static inline void snd_emu1010_fpga_lock(struct snd_emu10k1 *emu) { mutex_lock(&emu->emu1010.lock); };
+static inline void snd_emu1010_fpga_unlock(struct snd_emu10k1 *emu) { mutex_unlock(&emu->emu1010.lock); };
+void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value);
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
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);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 86eaf5963502..1a2905e8672b 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -810,15 +810,19 @@ static void emu1010_work(struct work_struct *work)
return;
#endif
+ snd_emu1010_fpga_lock(emu);
+
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
// The distinction of the IRQ status bits is unreliable,
// so we dispatch later based on option card status.
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
emu1010_dock_event(emu);
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
emu1010_clock_event(emu);
+
+ snd_emu1010_fpga_unlock(emu);
}
static void emu1010_interrupt(struct snd_emu10k1 *emu)
@@ -852,6 +856,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
* Proper init follows in snd_emu10k1_init(). */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
+ snd_emu1010_fpga_lock(emu);
+
/* Disable 48Volt power to Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
@@ -877,17 +883,18 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
if (err < 0) {
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
- return err;
+ goto fail;
}
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®);
if ((reg & 0x3f) != 0x15) {
/* FPGA failed to be programmed */
dev_info(emu->card->dev,
"emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
reg);
- return -ENODEV;
+ err = -ENODEV;
+ goto fail;
}
dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
@@ -947,7 +954,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
// so it is safe to simply enable the outputs.
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
- return 0;
+fail:
+ snd_emu1010_fpga_unlock(emu);
+ return err;
}
/*
* Create the EMU10K1 instance
@@ -969,9 +978,10 @@ static void snd_emu10k1_free(struct snd_card *card)
}
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
/* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0);
}
cancel_work_sync(&emu->emu1010.work);
+ mutex_destroy(&emu->emu1010.lock);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
snd_util_memhdr_free(emu->memhdr);
@@ -1551,6 +1561,7 @@ int snd_emu10k1_create(struct snd_card *card,
emu->synth = NULL;
emu->get_synth_voice = NULL;
INIT_WORK(&emu->emu1010.work, emu1010_work);
+ mutex_init(&emu->emu1010.lock);
/* read revision & serial */
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 0a32ea53d8c6..05b98d9b547b 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -661,7 +661,9 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
change = (emu->emu1010.output_source[channel] != val);
if (change) {
emu->emu1010.output_source[channel] = val;
+ snd_emu1010_fpga_lock(emu);
snd_emu1010_output_source_apply(emu, channel, val);
+ snd_emu1010_fpga_unlock(emu);
}
return change;
}
@@ -705,7 +707,9 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
change = (emu->emu1010.input_source[channel] != val);
if (change) {
emu->emu1010.input_source[channel] = val;
+ snd_emu1010_fpga_lock(emu);
snd_emu1010_input_source_apply(emu, channel, val);
+ snd_emu1010_fpga_unlock(emu);
}
return change;
}
@@ -774,7 +778,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
cache = cache & ~mask;
change = (cache != emu->emu1010.adc_pads);
if (change) {
- snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache );
emu->emu1010.adc_pads = cache;
}
@@ -832,7 +836,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
cache = cache & ~mask;
change = (cache != emu->emu1010.dac_pads);
if (change) {
- snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache );
emu->emu1010.dac_pads = cache;
}
@@ -980,6 +984,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
val = ucontrol->value.enumerated.item[0] ;
if (val >= emu_ci->num)
return -EINVAL;
+ snd_emu1010_fpga_lock(emu);
spin_lock_irq(&emu->reg_lock);
change = (emu->emu1010.clock_source != val);
if (change) {
@@ -996,6 +1001,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
} else {
spin_unlock_irq(&emu->reg_lock);
}
+ snd_emu1010_fpga_unlock(emu);
return change;
}
@@ -1041,7 +1047,7 @@ static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
change = (emu->emu1010.clock_fallback != val);
if (change) {
emu->emu1010.clock_fallback = val;
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val);
}
return change;
}
@@ -1093,7 +1099,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
emu->emu1010.optical_out = val;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
}
return change;
}
@@ -1144,7 +1150,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
emu->emu1010.optical_in = val;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
}
return change;
}
@@ -2323,7 +2329,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
for (i = 0; i < emu_ri->n_outs; i++)
emu->emu1010.output_source[i] =
emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
+ snd_emu1010_fpga_lock(emu);
snd_emu1010_apply_sources(emu);
+ snd_emu1010_fpga_unlock(emu);
kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
err = snd_ctl_add(card, kctl);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index 2f80fd91017c..737c28d31b41 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -165,6 +165,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
u32 value2;
if (emu->card_capabilities->emu_model) {
+ snd_emu1010_fpga_lock(emu);
+
// This represents the S/PDIF lock status on 0404b, which is
// kinda weird and unhelpful, because monitoring it via IRQ is
// impractical (one gets an IRQ flood as long as it is desynced).
@@ -197,6 +199,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n",
value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer",
value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : "");
+
+ snd_emu1010_fpga_unlock(emu);
} else {
snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS);
snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
@@ -458,6 +462,9 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
struct snd_emu10k1 *emu = entry->private_data;
u32 value;
int i;
+
+ snd_emu1010_fpga_lock(emu);
+
snd_iprintf(buffer, "EMU1010 Registers:\n\n");
for(i = 0; i < 0x40; i+=1) {
@@ -496,6 +503,8 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
snd_emu_proc_emu1010_link_read(emu, buffer, 0x701);
}
}
+
+ snd_emu1010_fpga_unlock(emu);
}
static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 74df2330015f..f3260a81e47b 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -289,71 +289,63 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
+ if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
+ return;
snd_emu1010_fpga_write_locked(emu, reg, value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
-static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *value)
+void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value)
+{
+ snd_emu1010_fpga_lock(emu);
+ snd_emu1010_fpga_write_locked(emu, reg, value);
+ snd_emu1010_fpga_unlock(emu);
+}
+
+void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
{
// The higest input pin is used as the designated interrupt trigger,
// so it needs to be masked out.
// But note that any other input pin change will also cause an IRQ,
// so using this function often causes an IRQ as a side effect.
u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f;
+
+ if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
+ return;
if (snd_BUG_ON(reg > 0x3f))
return;
reg += 0x40; /* 0x40 upwards are registers. */
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);
*value = ((inw(emu->port + A_GPIO) >> 8) & mask);
}
-void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
- snd_emu1010_fpga_read_locked(emu, reg, value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
-}
-
/* Each Destination has one and only one Source,
* but one Source can feed any number of Destinations simultaneously.
*/
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;
- 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);
+ 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);
}
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst)
{
- unsigned long flags;
u32 hi, lo;
if (snd_BUG_ON(dst & ~0x71f))
return 0;
- 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_read_locked(emu, EMU_HANA_SRCHI, &hi);
- snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, &lo);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SRCHI, &hi);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SRCLO, &lo);
return (hi << 8) | lo;
}
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 05/10] ALSA: emu10k1: fix E-MU dock initialization
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (3 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 04/10] ALSA: emu10k1: use mutex for E-MU FPGA access locking Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 06/10] ALSA: emu10k1: simplify E-MU card FPGA reset sequence Oswald Buddenhagen
` (5 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
A side effect of making the dock monitoring interrupt-driven was that
we'd be very quick to program a freshly connected dock. However, for
unclear reasons, the dock does not work when we do that - despite the
FPGA netlist upload going just fine. We work around this by adding a
delay before programming the dock; for safety, the value is several
times as much as was determined empirically.
Note that a badly timed dock hot-plug would have triggered the problem
even before the referenced commit - but now it would happen 100% instead
of about 3% of the time, thus making it impossible to work around by
re-plugging.
Fixes: fbb64eedf5a3 (ALSA: emu10k1: make E-MU dock monitoring interrupt-driven)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218584
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 1a2905e8672b..8ccc0178360c 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -737,6 +737,12 @@ static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
u32 tmp, tmp2;
int err;
+ // The docking events clearly arrive prematurely - while the
+ // Dock's FPGA seems to be successfully programmed, the Dock
+ // fails to initialize subsequently if we don't give it some
+ // time to "warm up" here.
+ msleep(200);
+
dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
/* Return to Audio Dock programming mode */
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 06/10] ALSA: emu10k1: simplify E-MU card FPGA reset sequence
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (4 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 05/10] ALSA: emu10k1: fix E-MU dock initialization Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 07/10] ALSA: emu10k1: make snd_emu1010_load_firmware_entry() void Oswald Buddenhagen
` (4 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
Firstly, it is pointless to explicitly disable the power to the dock
prior to resetting the FPGA, as the latter will do the former anyway.
Secondly, it doesn't make much sense to check whether the FPGA is
already programmed. It's much simpler to just presume it is, and issue
the self-reset command. If it isn't, the effect isn't worse than the
checks themselves. As a side effect, we lose the info if the reset
fails, but there is no plausible way how that could happen unless the
card burns out while operating, and in that case we'll detect a firmware
upload failure a bit later anyway.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 25 +++----------------------
1 file changed, 3 insertions(+), 22 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 8ccc0178360c..353dd3b61c61 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -864,28 +864,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_lock(emu);
- /* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
-
- /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®);
- dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg);
- if ((reg & 0x3f) == 0x15) {
- /* FPGA netlist already present so clear it */
- /* Return to programming mode */
-
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_HANA);
- }
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®);
- dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg);
- if ((reg & 0x3f) == 0x15) {
- /* FPGA failed to return to programming mode */
- dev_info(emu->card->dev,
- "emu1010: FPGA failed to return to programming mode\n");
- return -ENODEV;
- }
- dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg);
-
+ dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n");
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ EMU_HANA_FPGA_CONFIG_HANA);
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
if (err < 0) {
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 07/10] ALSA: emu10k1: make snd_emu1010_load_firmware_entry() void
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (5 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 06/10] ALSA: emu10k1: simplify E-MU card FPGA reset sequence Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 08/10] ALSA: emu10k1: move entering E-MU card FPGA programming mode Oswald Buddenhagen
` (3 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
There is only one call site, and there we already know that we actually
have a firmware.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 353dd3b61c61..ec010971a220 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -652,17 +652,14 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
return 0;
}
-static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
+static void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
const struct firmware *fw_entry)
{
int n, i;
u16 reg;
u8 value;
__always_unused u16 write_post;
- if (!fw_entry)
- return -EIO;
-
/* The FPGA is a Xilinx Spartan IIE XC2S50E */
/* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */
/* GPIO7 -> FPGA PGMN
@@ -694,8 +691,6 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
outw(0x10, emu->port + A_GPIO);
write_post = inw(emu->port + A_GPIO);
spin_unlock_irq(&emu->emu_lock);
-
- return 0;
}
/* firmware file names, per model, init-fw and dock-fw (optional) */
@@ -729,7 +724,8 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
return err;
}
- return snd_emu1010_load_firmware_entry(emu, *fw);
+ snd_emu1010_load_firmware_entry(emu, *fw);
+ return 0;
}
static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 08/10] ALSA: emu10k1: move entering E-MU card FPGA programming mode
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (6 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 07/10] ALSA: emu10k1: make snd_emu1010_load_firmware_entry() void Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 09/10] ALSA: emu10k1: move snd_emu1010_load_firmware_entry() to io.c Oswald Buddenhagen
` (2 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
... into snd_emu1010_load_firmware_entry(). This makes it clearer that
these steps belong together tightly, as explained in a prior commit.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/emu10k1_main.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index ec010971a220..d0f35d346765 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -652,14 +652,19 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
return 0;
}
-static void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
+static void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock,
const struct firmware *fw_entry)
{
int n, i;
u16 reg;
u8 value;
__always_unused u16 write_post;
+ // If the FPGA is already programmed, return it to programming mode
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ dock ? EMU_HANA_FPGA_CONFIG_AUDIODOCK :
+ EMU_HANA_FPGA_CONFIG_HANA);
+
/* The FPGA is a Xilinx Spartan IIE XC2S50E */
/* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */
/* GPIO7 -> FPGA PGMN
@@ -724,7 +729,7 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
return err;
}
- snd_emu1010_load_firmware_entry(emu, *fw);
+ snd_emu1010_load_firmware_entry(emu, dock, *fw);
return 0;
}
@@ -740,9 +745,6 @@ static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
msleep(200);
dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
- /* Return to Audio Dock programming mode */
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
- EMU_HANA_FPGA_CONFIG_AUDIODOCK);
err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
if (err < 0)
return;
@@ -861,8 +863,6 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_lock(emu);
dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n");
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
- EMU_HANA_FPGA_CONFIG_HANA);
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
if (err < 0) {
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 09/10] ALSA: emu10k1: move snd_emu1010_load_firmware_entry() to io.c
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (7 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 08/10] ALSA: emu10k1: move entering E-MU card FPGA programming mode Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-21 20:47 ` [PATCH 10/10] ALSA: emu10k1: make E-MU FPGA writes potentially more reliable Oswald Buddenhagen
2024-04-22 19:29 ` [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Takashi Iwai
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
It is a low-level I/O access function, so io.c is the natural place for
it.
While we're moving the code, reduce the scope of some variables, use
compound assignment operators, and add/adjust some comments.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
include/sound/emu10k1.h | 1 +
sound/pci/emu10k1/emu10k1_main.c | 46 ---------------------------
sound/pci/emu10k1/io.c | 53 ++++++++++++++++++++++++++++++++
3 files changed, 54 insertions(+), 46 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 234b5baea69c..b83862259eec 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1843,6 +1843,7 @@ void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 s
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst);
int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src);
void snd_emu1010_update_clock(struct snd_emu10k1 *emu);
+void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock, const struct firmware *fw_entry);
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index d0f35d346765..5b8a5ba825bd 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -652,52 +652,6 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
return 0;
}
-static void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock,
- const struct firmware *fw_entry)
-{
- int n, i;
- u16 reg;
- u8 value;
- __always_unused u16 write_post;
-
- // If the FPGA is already programmed, return it to programming mode
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
- dock ? EMU_HANA_FPGA_CONFIG_AUDIODOCK :
- EMU_HANA_FPGA_CONFIG_HANA);
-
- /* The FPGA is a Xilinx Spartan IIE XC2S50E */
- /* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */
- /* GPIO7 -> FPGA PGMN
- * GPIO6 -> FPGA CCLK
- * GPIO5 -> FPGA DIN
- * FPGA CONFIG OFF -> FPGA PGMN
- */
- spin_lock_irq(&emu->emu_lock);
- outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */
- write_post = inw(emu->port + A_GPIO);
- udelay(100);
- outw(0x80, emu->port + A_GPIO); /* Leave bit 7 set during netlist setup. */
- write_post = inw(emu->port + A_GPIO);
- udelay(100); /* Allow FPGA memory to clean */
- for (n = 0; n < fw_entry->size; n++) {
- value = fw_entry->data[n];
- for (i = 0; i < 8; i++) {
- reg = 0x80;
- if (value & 0x1)
- reg = reg | 0x20;
- value = value >> 1;
- outw(reg, emu->port + A_GPIO);
- write_post = inw(emu->port + A_GPIO);
- outw(reg | 0x40, emu->port + A_GPIO);
- write_post = inw(emu->port + A_GPIO);
- }
- }
- /* After programming, set GPIO bit 4 high again. */
- outw(0x10, emu->port + A_GPIO);
- write_post = inw(emu->port + A_GPIO);
- spin_unlock_irq(&emu->emu_lock);
-}
-
/* firmware file names, per model, init-fw and dock-fw (optional) */
static const char * const firmware_names[5][2] = {
[EMU_MODEL_EMU1010] = {
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index f3260a81e47b..9b1b25d5ba74 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -421,6 +421,59 @@ void snd_emu1010_update_clock(struct snd_emu10k1 *emu)
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, leds);
}
+void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock,
+ const struct firmware *fw_entry)
+{
+ __always_unused u16 write_post;
+
+ // On E-MU 1010 rev1 the FPGA is a Xilinx Spartan IIE XC2S50E.
+ // On E-MU 0404b it is a Xilinx Spartan III XC3S50.
+ // The wiring is as follows:
+ // GPO7 -> FPGA input & 1K resistor -> FPGA /PGMN <- FPGA output
+ // In normal operation, the active low reset line is held up by
+ // an FPGA output, while the GPO pin performs its duty as control
+ // register access strobe signal. Writing the respective bit to
+ // EMU_HANA_FPGA_CONFIG puts the FPGA output into high-Z mode, at
+ // which point the GPO pin can control the reset line through the
+ // resistor.
+ // GPO6 -> FPGA CCLK & FPGA input
+ // GPO5 -> FPGA DIN (dual function)
+
+ // If the FPGA is already programmed, return it to programming mode
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ dock ? EMU_HANA_FPGA_CONFIG_AUDIODOCK :
+ EMU_HANA_FPGA_CONFIG_HANA);
+
+ // Assert reset line for 100uS
+ outw(0x00, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ udelay(100);
+ outw(0x80, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ udelay(100); // Allow FPGA memory to clean
+
+ // Upload the netlist. Keep reset line high!
+ for (int n = 0; n < fw_entry->size; n++) {
+ u8 value = fw_entry->data[n];
+ for (int i = 0; i < 8; i++) {
+ u16 reg = 0x80;
+ if (value & 1)
+ reg |= 0x20;
+ value >>= 1;
+ outw(reg, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ outw(reg | 0x40, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ }
+ }
+
+ // After programming, set GPIO bit 4 high again.
+ // This appears to be a config word that the rev1 Hana
+ // firmware reads; weird things happen without this.
+ outw(0x10, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+}
+
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
unsigned long flags;
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 10/10] ALSA: emu10k1: make E-MU FPGA writes potentially more reliable
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (8 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 09/10] ALSA: emu10k1: move snd_emu1010_load_firmware_entry() to io.c Oswald Buddenhagen
@ 2024-04-21 20:47 ` Oswald Buddenhagen
2024-04-22 19:29 ` [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Takashi Iwai
10 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-21 20:47 UTC (permalink / raw)
To: linux-sound; +Cc: Takashi Iwai, Jaroslav Kysela, Pietro Caruso
We did not delay after the second strobe signal, so another immediately
following access could potentially corrupt the written value.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/pci/emu10k1/io.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 9b1b25d5ba74..b60ab5671e00 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -285,6 +285,7 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32
outw(value, emu->port + A_GPIO);
udelay(10);
outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */
+ udelay(10);
}
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
--
2.44.0.701.g2cf7baacf3.dirty
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock
2024-04-21 20:46 [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Oswald Buddenhagen
` (9 preceding siblings ...)
2024-04-21 20:47 ` [PATCH 10/10] ALSA: emu10k1: make E-MU FPGA writes potentially more reliable Oswald Buddenhagen
@ 2024-04-22 19:29 ` Takashi Iwai
2024-04-23 7:21 ` Oswald Buddenhagen
10 siblings, 1 reply; 13+ messages in thread
From: Takashi Iwai @ 2024-04-22 19:29 UTC (permalink / raw)
To: Oswald Buddenhagen
Cc: linux-sound, Takashi Iwai, Jaroslav Kysela, Pietro Caruso
On Sun, 21 Apr 2024 22:46:57 +0200,
Oswald Buddenhagen wrote:
>
> patches 1-3 & 5 fix the regression(s), patch 4 fixes a related pre-existing
> problem, while patches 6-10 are "only" improvements.
>
> i don't think it really makes sense to revert fbb64eedf5a3 (ALSA: emu10k1: make
> E-MU dock monitoring interrupt-driven) and re-do things from scratch, as we'd
> also need to revert the unrelated c960b012ec47 (ALSA: emu10k1: track loss of
> external clock on E-MU cards) first.
>
> so i'd just go with the series as-is, and cherry-pick the four (or preferably
> five) patches to stable.
If a few of the series are rather regression fixes that should be
merged to Linus tree sooner, please separate them and send two patch
sets instead. I don't see Fixes tag in the patch 2, for example, so
I'm not sure whether I should pick up.
Also, your Fixes tag usage is incorrect. It should be
Fixes: $ID ("subject...")
while yours missing the quotes. Some people are picky about those
formats, so let's be strict.
Could you resubmit two patch sets with those corrections?
thanks,
Takashi
>
> ---
>
> the series (and a bunch of failed experiments) is fully tested by pietro with
> both rev1 and rev2 1010 cards, a 0202 cardbus card, and their respective docks.
> he'll get permanent testing credits in the card capability table later on (if
> he so wishes), so i didn't bother adding a tested-by footer to each patch.
>
> Oswald Buddenhagen (10):
> ALSA: emu10k1: fix E-MU card dock presence monitoring
> ALSA: emu10k1: factor out snd_emu1010_load_dock_firmware()
> ALSA: emu10k1: move the whole GPIO event handling to the workqueue
> ALSA: emu10k1: use mutex for E-MU FPGA access locking
> ALSA: emu10k1: fix E-MU dock initialization
> ALSA: emu10k1: simplify E-MU card FPGA reset sequence
> ALSA: emu10k1: make snd_emu1010_load_firmware_entry() void
> ALSA: emu10k1: move entering E-MU card FPGA programming mode
> ALSA: emu10k1: move snd_emu1010_load_firmware_entry() to io.c
> ALSA: emu10k1: make E-MU FPGA writes potentially more reliable
>
> include/sound/emu10k1.h | 8 +-
> sound/pci/emu10k1/emu10k1.c | 3 +-
> sound/pci/emu10k1/emu10k1_main.c | 225 +++++++++++++------------------
> sound/pci/emu10k1/emumixer.c | 18 ++-
> sound/pci/emu10k1/emuproc.c | 9 ++
> sound/pci/emu10k1/io.c | 104 ++++++++++----
> 6 files changed, 195 insertions(+), 172 deletions(-)
>
> --
> 2.44.0.701.g2cf7baacf3.dirty
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock
2024-04-22 19:29 ` [PATCH 00/10] ALSA: emu10k1: fixes related to uploading firmware to the E-MU dock Takashi Iwai
@ 2024-04-23 7:21 ` Oswald Buddenhagen
0 siblings, 0 replies; 13+ messages in thread
From: Oswald Buddenhagen @ 2024-04-23 7:21 UTC (permalink / raw)
To: Takashi Iwai; +Cc: linux-sound, Jaroslav Kysela, Pietro Caruso
On Mon, Apr 22, 2024 at 09:29:27PM +0200, Takashi Iwai wrote:
>On Sun, 21 Apr 2024 22:46:57 +0200,
>Oswald Buddenhagen wrote:
>>
>> patches 1-3 & 5 fix the regression(s), patch 4 fixes a related pre-existing
>> problem, while patches 6-10 are "only" improvements.
>>
>If a few of the series are rather regression fixes that should be
>merged to Linus tree sooner, please separate them and send two patch
>sets instead.
>
i can't give more precise instructions than above; it's a judgment call
whether you consider patch 4 urgent enough (it's a fix, but not for a
recently introduced regression; nonetheless, i've seen less important
patches from me be picked to stable). i'd just split the series in half.
>I don't see Fixes tag in the patch 2, for example, so
>I'm not sure whether I should pick up.
>
as the commit message says, it's preparatory refactoring for patch 3, so
it's not a fix, but a mandatory dependency for one.
>Also, your Fixes tag usage is incorrect. It should be
> Fixes: $ID ("subject...")
>while yours missing the quotes. Some people are picky about those
>formats, so let's be strict.
>
fair enough.
^ permalink raw reply [flat|nested] 13+ messages in thread