From 7d09d525cf98f59f8b636a0bf5b4fc983514ef8c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 8 Feb 2015 10:28:23 +0800 Subject: [PATCH] 3.10-stable patches added patches: alsa-ak411x-fix-stall-in-work-callback.patch asoc-atmel_ssc_dai-fix-start-event-for-i2s-mode.patch asoc-sgtl5000-add-delay-before-first-i2c-access.patch asoc-wm8731-init-mutex-in-i2c-init-path.patch smpboot-add-missing-get_online_cpus-in-smpboot_register_percpu_thread.patch --- ...sa-ak411x-fix-stall-in-work-callback.patch | 151 ++++++++++++++++++ ...ssc_dai-fix-start-event-for-i2s-mode.patch | 80 ++++++++++ ...00-add-delay-before-first-i2c-access.patch | 38 +++++ ...c-wm8731-init-mutex-in-i2c-init-path.patch | 31 ++++ queue-3.10/series | 5 + ...us-in-smpboot_register_percpu_thread.patch | 62 +++++++ 6 files changed, 367 insertions(+) create mode 100644 queue-3.10/alsa-ak411x-fix-stall-in-work-callback.patch create mode 100644 queue-3.10/asoc-atmel_ssc_dai-fix-start-event-for-i2s-mode.patch create mode 100644 queue-3.10/asoc-sgtl5000-add-delay-before-first-i2c-access.patch create mode 100644 queue-3.10/asoc-wm8731-init-mutex-in-i2c-init-path.patch create mode 100644 queue-3.10/smpboot-add-missing-get_online_cpus-in-smpboot_register_percpu_thread.patch diff --git a/queue-3.10/alsa-ak411x-fix-stall-in-work-callback.patch b/queue-3.10/alsa-ak411x-fix-stall-in-work-callback.patch new file mode 100644 index 00000000000..f5050018baa --- /dev/null +++ b/queue-3.10/alsa-ak411x-fix-stall-in-work-callback.patch @@ -0,0 +1,151 @@ +From 4161b4505f1690358ac0a9ee59845a7887336b21 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 13 Jan 2015 10:53:20 +0100 +Subject: ALSA: ak411x: Fix stall in work callback + +From: Takashi Iwai + +commit 4161b4505f1690358ac0a9ee59845a7887336b21 upstream. + +When ak4114 work calls its callback and the callback invokes +ak4114_reinit(), it stalls due to flush_delayed_work(). For avoiding +this, control the reentrance by introducing a refcount. Also +flush_delayed_work() is replaced with cancel_delayed_work_sync(). + +The exactly same bug is present in ak4113.c and fixed as well. + +Reported-by: Pavel Hofman +Acked-by: Jaroslav Kysela +Tested-by: Pavel Hofman +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + include/sound/ak4113.h | 2 +- + include/sound/ak4114.h | 2 +- + sound/i2c/other/ak4113.c | 17 ++++++++--------- + sound/i2c/other/ak4114.c | 18 ++++++++---------- + 4 files changed, 18 insertions(+), 21 deletions(-) + +--- a/include/sound/ak4113.h ++++ b/include/sound/ak4113.h +@@ -286,7 +286,7 @@ struct ak4113 { + ak4113_write_t *write; + ak4113_read_t *read; + void *private_data; +- unsigned int init:1; ++ atomic_t wq_processing; + spinlock_t lock; + unsigned char regmap[AK4113_WRITABLE_REGS]; + struct snd_kcontrol *kctls[AK4113_CONTROLS]; +--- a/include/sound/ak4114.h ++++ b/include/sound/ak4114.h +@@ -168,7 +168,7 @@ struct ak4114 { + ak4114_write_t * write; + ak4114_read_t * read; + void * private_data; +- unsigned int init: 1; ++ atomic_t wq_processing; + spinlock_t lock; + unsigned char regmap[7]; + unsigned char txcsb[5]; +--- a/sound/i2c/other/ak4113.c ++++ b/sound/i2c/other/ak4113.c +@@ -56,8 +56,7 @@ static inline unsigned char reg_read(str + + static void snd_ak4113_free(struct ak4113 *chip) + { +- chip->init = 1; /* don't schedule new work */ +- mb(); ++ atomic_inc(&chip->wq_processing); /* don't schedule new work */ + cancel_delayed_work_sync(&chip->work); + kfree(chip); + } +@@ -89,6 +88,7 @@ int snd_ak4113_create(struct snd_card *c + chip->write = write; + chip->private_data = private_data; + INIT_DELAYED_WORK(&chip->work, ak4113_stats); ++ atomic_set(&chip->wq_processing, 0); + + for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) + chip->regmap[reg] = pgm[reg]; +@@ -139,13 +139,11 @@ static void ak4113_init_regs(struct ak41 + + void snd_ak4113_reinit(struct ak4113 *chip) + { +- chip->init = 1; +- mb(); +- flush_delayed_work(&chip->work); ++ if (atomic_inc_return(&chip->wq_processing) == 1) ++ cancel_delayed_work_sync(&chip->work); + ak4113_init_regs(chip); + /* bring up statistics / event queing */ +- chip->init = 0; +- if (chip->kctls[0]) ++ if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); + } + EXPORT_SYMBOL_GPL(snd_ak4113_reinit); +@@ -632,8 +630,9 @@ static void ak4113_stats(struct work_str + { + struct ak4113 *chip = container_of(work, struct ak4113, work.work); + +- if (!chip->init) ++ if (atomic_inc_return(&chip->wq_processing) == 1) + snd_ak4113_check_rate_and_errors(chip, chip->check_flags); + +- schedule_delayed_work(&chip->work, HZ / 10); ++ if (atomic_dec_and_test(&chip->wq_processing)) ++ schedule_delayed_work(&chip->work, HZ / 10); + } +--- a/sound/i2c/other/ak4114.c ++++ b/sound/i2c/other/ak4114.c +@@ -66,8 +66,7 @@ static void reg_dump(struct ak4114 *ak41 + + static void snd_ak4114_free(struct ak4114 *chip) + { +- chip->init = 1; /* don't schedule new work */ +- mb(); ++ atomic_inc(&chip->wq_processing); /* don't schedule new work */ + cancel_delayed_work_sync(&chip->work); + kfree(chip); + } +@@ -100,6 +99,7 @@ int snd_ak4114_create(struct snd_card *c + chip->write = write; + chip->private_data = private_data; + INIT_DELAYED_WORK(&chip->work, ak4114_stats); ++ atomic_set(&chip->wq_processing, 0); + + for (reg = 0; reg < 7; reg++) + chip->regmap[reg] = pgm[reg]; +@@ -152,13 +152,11 @@ static void ak4114_init_regs(struct ak41 + + void snd_ak4114_reinit(struct ak4114 *chip) + { +- chip->init = 1; +- mb(); +- flush_delayed_work(&chip->work); ++ if (atomic_inc_return(&chip->wq_processing) == 1) ++ cancel_delayed_work_sync(&chip->work); + ak4114_init_regs(chip); + /* bring up statistics / event queing */ +- chip->init = 0; +- if (chip->kctls[0]) ++ if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); + } + +@@ -612,10 +610,10 @@ static void ak4114_stats(struct work_str + { + struct ak4114 *chip = container_of(work, struct ak4114, work.work); + +- if (!chip->init) ++ if (atomic_inc_return(&chip->wq_processing) == 1) + snd_ak4114_check_rate_and_errors(chip, chip->check_flags); +- +- schedule_delayed_work(&chip->work, HZ / 10); ++ if (atomic_dec_and_test(&chip->wq_processing)) ++ schedule_delayed_work(&chip->work, HZ / 10); + } + + EXPORT_SYMBOL(snd_ak4114_create); diff --git a/queue-3.10/asoc-atmel_ssc_dai-fix-start-event-for-i2s-mode.patch b/queue-3.10/asoc-atmel_ssc_dai-fix-start-event-for-i2s-mode.patch new file mode 100644 index 00000000000..66a0aad1698 --- /dev/null +++ b/queue-3.10/asoc-atmel_ssc_dai-fix-start-event-for-i2s-mode.patch @@ -0,0 +1,80 @@ +From a43bd7e125143b875caae6d4f9938855b440faaf Mon Sep 17 00:00:00 2001 +From: Bo Shen +Date: Tue, 20 Jan 2015 15:43:16 +0800 +Subject: ASoC: atmel_ssc_dai: fix start event for I2S mode + +From: Bo Shen + +commit a43bd7e125143b875caae6d4f9938855b440faaf upstream. + +According to the I2S specification information as following: + - WS = 0, channel 1 (left) + - WS = 1, channel 2 (right) +So, the start event should be TF/RF falling edge. + +Reported-by: Songjun Wu +Signed-off-by: Bo Shen +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/atmel/atmel_ssc_dai.c | 18 ++++-------------- + 1 file changed, 4 insertions(+), 14 deletions(-) + +--- a/sound/soc/atmel/atmel_ssc_dai.c ++++ b/sound/soc/atmel/atmel_ssc_dai.c +@@ -331,7 +331,6 @@ static int atmel_ssc_hw_params(struct sn + struct atmel_pcm_dma_params *dma_params; + int dir, channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; +- int start_event; + int ret; + + /* +@@ -450,19 +449,10 @@ static int atmel_ssc_hw_params(struct sn + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is + * generated from the transmit clock. +- * +- * For single channel data, one sample is transferred +- * on the falling edge of the LRC clock. +- * For two channel data, one sample is +- * transferred on both edges of the LRC clock. + */ +- start_event = ((channels == 1) +- ? SSC_START_FALLING_RF +- : SSC_START_EDGE_RF); +- + rcmr = SSC_BF(RCMR_PERIOD, 0) + | SSC_BF(RCMR_STTDLY, START_DELAY) +- | SSC_BF(RCMR_START, start_event) ++ | SSC_BF(RCMR_START, SSC_START_FALLING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); +@@ -470,14 +460,14 @@ static int atmel_ssc_hw_params(struct sn + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(RFMR_FSLEN, 0) +- | SSC_BF(RFMR_DATNB, 0) ++ | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, 0) + | SSC_BF(TCMR_STTDLY, START_DELAY) +- | SSC_BF(TCMR_START, start_event) ++ | SSC_BF(TCMR_START, SSC_START_FALLING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE) + | SSC_BF(TCMR_CKS, SSC_CKS_PIN); +@@ -486,7 +476,7 @@ static int atmel_ssc_hw_params(struct sn + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(TFMR_FSLEN, 0) +- | SSC_BF(TFMR_DATNB, 0) ++ | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); diff --git a/queue-3.10/asoc-sgtl5000-add-delay-before-first-i2c-access.patch b/queue-3.10/asoc-sgtl5000-add-delay-before-first-i2c-access.patch new file mode 100644 index 00000000000..f252a07ab64 --- /dev/null +++ b/queue-3.10/asoc-sgtl5000-add-delay-before-first-i2c-access.patch @@ -0,0 +1,38 @@ +From 58cc9c9a175885bbf6bae3acf18233d0a8229a84 Mon Sep 17 00:00:00 2001 +From: Eric Nelson +Date: Fri, 30 Jan 2015 14:07:55 -0700 +Subject: ASoC: sgtl5000: add delay before first I2C access + +From: Eric Nelson + +commit 58cc9c9a175885bbf6bae3acf18233d0a8229a84 upstream. + +To quote from section 1.3.1 of the data sheet: + The SGTL5000 has an internal reset that is deasserted + 8 SYS_MCLK cycles after all power rails have been brought + up. After this time, communication can start + + ... + 1.0us represents 8 SYS_MCLK cycles at the minimum 8.0 MHz SYS_MCLK. + +Signed-off-by: Eric Nelson +Reviewed-by: Fabio Estevam +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/codecs/sgtl5000.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sound/soc/codecs/sgtl5000.c ++++ b/sound/soc/codecs/sgtl5000.c +@@ -1242,6 +1242,9 @@ static int sgtl5000_enable_regulators(st + /* wait for all power rails bring up */ + udelay(10); + ++ /* Need 8 clocks before I2C accesses */ ++ udelay(1); ++ + /* read chip information */ + reg = snd_soc_read(codec, SGTL5000_CHIP_ID); + if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) != diff --git a/queue-3.10/asoc-wm8731-init-mutex-in-i2c-init-path.patch b/queue-3.10/asoc-wm8731-init-mutex-in-i2c-init-path.patch new file mode 100644 index 00000000000..e76ea26dbbb --- /dev/null +++ b/queue-3.10/asoc-wm8731-init-mutex-in-i2c-init-path.patch @@ -0,0 +1,31 @@ +From 8a6cf30bf93df2c0f2637156e4a5070594bddebf Mon Sep 17 00:00:00 2001 +From: Manuel Lauss +Date: Mon, 19 Jan 2015 08:23:43 +0100 +Subject: ASoC: wm8731: init mutex in i2c init path + +From: Manuel Lauss + +commit 8a6cf30bf93df2c0f2637156e4a5070594bddebf upstream. + +The I2C init path forgot to init the mutex, leading to an oops when +controls are accessed. + +Signed-off-by: Manuel Lauss +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/codecs/wm8731.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/soc/codecs/wm8731.c ++++ b/sound/soc/codecs/wm8731.c +@@ -690,6 +690,8 @@ static int wm8731_i2c_probe(struct i2c_c + if (wm8731 == NULL) + return -ENOMEM; + ++ mutex_init(&wm8731->lock); ++ + wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); + if (IS_ERR(wm8731->regmap)) { + ret = PTR_ERR(wm8731->regmap); diff --git a/queue-3.10/series b/queue-3.10/series index 2bac19b7e97..24da9d5d74a 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -9,3 +9,8 @@ nilfs2-fix-deadlock-of-segment-constructor-over-i_sync-flag.patch arm64-fix-up-proc-cpuinfo.patch ext4-prevent-bugon-on-race-between-write-fcntl.patch lib-checksum.c-fix-build-for-generic-csum_tcpudp_nofold.patch +asoc-wm8731-init-mutex-in-i2c-init-path.patch +asoc-atmel_ssc_dai-fix-start-event-for-i2s-mode.patch +asoc-sgtl5000-add-delay-before-first-i2c-access.patch +alsa-ak411x-fix-stall-in-work-callback.patch +smpboot-add-missing-get_online_cpus-in-smpboot_register_percpu_thread.patch diff --git a/queue-3.10/smpboot-add-missing-get_online_cpus-in-smpboot_register_percpu_thread.patch b/queue-3.10/smpboot-add-missing-get_online_cpus-in-smpboot_register_percpu_thread.patch new file mode 100644 index 00000000000..0d37a38ff49 --- /dev/null +++ b/queue-3.10/smpboot-add-missing-get_online_cpus-in-smpboot_register_percpu_thread.patch @@ -0,0 +1,62 @@ +From 4bee96860a65c3a62d332edac331b3cf936ba3ad Mon Sep 17 00:00:00 2001 +From: Lai Jiangshan +Date: Thu, 31 Jul 2014 11:30:17 +0800 +Subject: smpboot: Add missing get_online_cpus() in smpboot_register_percpu_thread() + +From: Lai Jiangshan + +commit 4bee96860a65c3a62d332edac331b3cf936ba3ad upstream. + +The following race exists in the smpboot percpu threads management: + +CPU0 CPU1 +cpu_up(2) + get_online_cpus(); + smpboot_create_threads(2); + smpboot_register_percpu_thread(); + for_each_online_cpu(); + __smpboot_create_thread(); + __cpu_up(2); + +This results in a missing per cpu thread for the newly onlined cpu2 and +in a NULL pointer dereference on a consecutive offline of that cpu. + +Proctect smpboot_register_percpu_thread() with get_online_cpus() to +prevent that. + +[ tglx: Massaged changelog and removed the change in + smpboot_unregister_percpu_thread() because that's an + optimization and therefor not stable material. ] + +Signed-off-by: Lai Jiangshan +Cc: Thomas Gleixner +Cc: Rusty Russell +Cc: Peter Zijlstra +Cc: Srivatsa S. Bhat +Cc: David Rientjes +Link: http://lkml.kernel.org/r/1406777421-12830-1-git-send-email-laijs@cn.fujitsu.com +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/smpboot.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/kernel/smpboot.c ++++ b/kernel/smpboot.c +@@ -279,6 +279,7 @@ int smpboot_register_percpu_thread(struc + unsigned int cpu; + int ret = 0; + ++ get_online_cpus(); + mutex_lock(&smpboot_threads_lock); + for_each_online_cpu(cpu) { + ret = __smpboot_create_thread(plug_thread, cpu); +@@ -291,6 +292,7 @@ int smpboot_register_percpu_thread(struc + list_add(&plug_thread->list, &hotplug_threads); + out: + mutex_unlock(&smpboot_threads_lock); ++ put_online_cpus(); + return ret; + } + EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread); -- 2.47.3