diff mbox

ESI Juli@ crash with external clock switch - patch

Message ID s5hwq4sm2bs.wl-tiwai@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Takashi Iwai Jan. 12, 2015, 3:43 p.m. UTC
At Mon, 12 Jan 2015 09:34:52 +0100,
Pavel Hofman wrote:
> 
> On 12.1.2015 09:21, Takashi Iwai wrote:
> > Yeah, restart is necessary only in a certain situation, and is a bug
> > that is done through work itself.  This was the cause.  I'll prepare
> > fix patches later.
> 
> I wish I could help but unfortunately my practical knowledge of kernel
> workqueues is close to zero :-( Of course I will test the patches and
> will extend them for quartet with testing too.

How about the patch below?  This is a quick fix for 3.19 (and
stable).  More better fixes will follow later once after it's
confirmed to work.

> > The HZ/10 isn't that bad, but the problem is that it's unconditionally
> > running even if user doesn't need/want.
> 
> It is useful only for the external clock mode. In fact the detection of
> incoming SPDIF rate is not reliable for internal clock in Juli (while it
> works just fine in Quartet, its FPGA pins configure the SPDIF receiver
> differently). IMO the thread could be running only when clock is
> switched to external.

Yeah, we can do some smart task change in addition to manual on/off.
Maybe it's good to have an enum control for that.


Takashi

--
diff mbox

Patch

diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h
index 52f02a60dba7..796834b7790c 100644
--- a/include/sound/ak4114.h
+++ b/include/sound/ak4114.h
@@ -169,6 +169,7 @@  struct ak4114 {
 	ak4114_read_t * read;
 	void * private_data;
 	unsigned int init: 1;
+	bool in_workq;
 	spinlock_t lock;
 	unsigned char regmap[6];
 	unsigned char txcsb[5];
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index c7f56339415d..0f923809522c 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -152,9 +152,11 @@  static void ak4114_init_regs(struct ak4114 *chip)
 
 void snd_ak4114_reinit(struct ak4114 *chip)
 {
+	if (chip->in_workq)
+		return;
 	chip->init = 1;
 	mb();
-	flush_delayed_work(&chip->work);
+	cancel_delayed_work_sync(&chip->work);
 	ak4114_init_regs(chip);
 	/* bring up statistics / event queing */
 	chip->init = 0;
@@ -612,10 +614,12 @@  static void ak4114_stats(struct work_struct *work)
 {
 	struct ak4114 *chip = container_of(work, struct ak4114, work.work);
 
-	if (!chip->init)
+	chip->in_workq = true;
+	if (!chip->init) {
 		snd_ak4114_check_rate_and_errors(chip, chip->check_flags);
-
-	schedule_delayed_work(&chip->work, HZ / 10);
+		schedule_delayed_work(&chip->work, HZ / 10);
+	}
+	chip->in_workq = false;
 }
 
 EXPORT_SYMBOL(snd_ak4114_create);