]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.10.69/alsa-ak411x-fix-stall-in-work-callback.patch
Linux 4.14.121
[thirdparty/kernel/stable-queue.git] / releases / 3.10.69 / alsa-ak411x-fix-stall-in-work-callback.patch
CommitLineData
7d09d525
GKH
1From 4161b4505f1690358ac0a9ee59845a7887336b21 Mon Sep 17 00:00:00 2001
2From: Takashi Iwai <tiwai@suse.de>
3Date: Tue, 13 Jan 2015 10:53:20 +0100
4Subject: ALSA: ak411x: Fix stall in work callback
5
6From: Takashi Iwai <tiwai@suse.de>
7
8commit 4161b4505f1690358ac0a9ee59845a7887336b21 upstream.
9
10When ak4114 work calls its callback and the callback invokes
11ak4114_reinit(), it stalls due to flush_delayed_work(). For avoiding
12this, control the reentrance by introducing a refcount. Also
13flush_delayed_work() is replaced with cancel_delayed_work_sync().
14
15The exactly same bug is present in ak4113.c and fixed as well.
16
17Reported-by: Pavel Hofman <pavel.hofman@ivitera.com>
18Acked-by: Jaroslav Kysela <perex@perex.cz>
19Tested-by: Pavel Hofman <pavel.hofman@ivitera.com>
20Signed-off-by: Takashi Iwai <tiwai@suse.de>
21Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
22
23---
24 include/sound/ak4113.h | 2 +-
25 include/sound/ak4114.h | 2 +-
26 sound/i2c/other/ak4113.c | 17 ++++++++---------
27 sound/i2c/other/ak4114.c | 18 ++++++++----------
28 4 files changed, 18 insertions(+), 21 deletions(-)
29
30--- a/include/sound/ak4113.h
31+++ b/include/sound/ak4113.h
32@@ -286,7 +286,7 @@ struct ak4113 {
33 ak4113_write_t *write;
34 ak4113_read_t *read;
35 void *private_data;
36- unsigned int init:1;
37+ atomic_t wq_processing;
38 spinlock_t lock;
39 unsigned char regmap[AK4113_WRITABLE_REGS];
40 struct snd_kcontrol *kctls[AK4113_CONTROLS];
41--- a/include/sound/ak4114.h
42+++ b/include/sound/ak4114.h
43@@ -168,7 +168,7 @@ struct ak4114 {
44 ak4114_write_t * write;
45 ak4114_read_t * read;
46 void * private_data;
47- unsigned int init: 1;
48+ atomic_t wq_processing;
49 spinlock_t lock;
50 unsigned char regmap[7];
51 unsigned char txcsb[5];
52--- a/sound/i2c/other/ak4113.c
53+++ b/sound/i2c/other/ak4113.c
54@@ -56,8 +56,7 @@ static inline unsigned char reg_read(str
55
56 static void snd_ak4113_free(struct ak4113 *chip)
57 {
58- chip->init = 1; /* don't schedule new work */
59- mb();
60+ atomic_inc(&chip->wq_processing); /* don't schedule new work */
61 cancel_delayed_work_sync(&chip->work);
62 kfree(chip);
63 }
64@@ -89,6 +88,7 @@ int snd_ak4113_create(struct snd_card *c
65 chip->write = write;
66 chip->private_data = private_data;
67 INIT_DELAYED_WORK(&chip->work, ak4113_stats);
68+ atomic_set(&chip->wq_processing, 0);
69
70 for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++)
71 chip->regmap[reg] = pgm[reg];
72@@ -139,13 +139,11 @@ static void ak4113_init_regs(struct ak41
73
74 void snd_ak4113_reinit(struct ak4113 *chip)
75 {
76- chip->init = 1;
77- mb();
78- flush_delayed_work(&chip->work);
79+ if (atomic_inc_return(&chip->wq_processing) == 1)
80+ cancel_delayed_work_sync(&chip->work);
81 ak4113_init_regs(chip);
82 /* bring up statistics / event queing */
83- chip->init = 0;
84- if (chip->kctls[0])
85+ if (atomic_dec_and_test(&chip->wq_processing))
86 schedule_delayed_work(&chip->work, HZ / 10);
87 }
88 EXPORT_SYMBOL_GPL(snd_ak4113_reinit);
89@@ -632,8 +630,9 @@ static void ak4113_stats(struct work_str
90 {
91 struct ak4113 *chip = container_of(work, struct ak4113, work.work);
92
93- if (!chip->init)
94+ if (atomic_inc_return(&chip->wq_processing) == 1)
95 snd_ak4113_check_rate_and_errors(chip, chip->check_flags);
96
97- schedule_delayed_work(&chip->work, HZ / 10);
98+ if (atomic_dec_and_test(&chip->wq_processing))
99+ schedule_delayed_work(&chip->work, HZ / 10);
100 }
101--- a/sound/i2c/other/ak4114.c
102+++ b/sound/i2c/other/ak4114.c
103@@ -66,8 +66,7 @@ static void reg_dump(struct ak4114 *ak41
104
105 static void snd_ak4114_free(struct ak4114 *chip)
106 {
107- chip->init = 1; /* don't schedule new work */
108- mb();
109+ atomic_inc(&chip->wq_processing); /* don't schedule new work */
110 cancel_delayed_work_sync(&chip->work);
111 kfree(chip);
112 }
113@@ -100,6 +99,7 @@ int snd_ak4114_create(struct snd_card *c
114 chip->write = write;
115 chip->private_data = private_data;
116 INIT_DELAYED_WORK(&chip->work, ak4114_stats);
117+ atomic_set(&chip->wq_processing, 0);
118
119 for (reg = 0; reg < 7; reg++)
120 chip->regmap[reg] = pgm[reg];
121@@ -152,13 +152,11 @@ static void ak4114_init_regs(struct ak41
122
123 void snd_ak4114_reinit(struct ak4114 *chip)
124 {
125- chip->init = 1;
126- mb();
127- flush_delayed_work(&chip->work);
128+ if (atomic_inc_return(&chip->wq_processing) == 1)
129+ cancel_delayed_work_sync(&chip->work);
130 ak4114_init_regs(chip);
131 /* bring up statistics / event queing */
132- chip->init = 0;
133- if (chip->kctls[0])
134+ if (atomic_dec_and_test(&chip->wq_processing))
135 schedule_delayed_work(&chip->work, HZ / 10);
136 }
137
138@@ -612,10 +610,10 @@ static void ak4114_stats(struct work_str
139 {
140 struct ak4114 *chip = container_of(work, struct ak4114, work.work);
141
142- if (!chip->init)
143+ if (atomic_inc_return(&chip->wq_processing) == 1)
144 snd_ak4114_check_rate_and_errors(chip, chip->check_flags);
145-
146- schedule_delayed_work(&chip->work, HZ / 10);
147+ if (atomic_dec_and_test(&chip->wq_processing))
148+ schedule_delayed_work(&chip->work, HZ / 10);
149 }
150
151 EXPORT_SYMBOL(snd_ak4114_create);